deps_gen/lib.rs
1#![allow(non_ascii_idents)]
2
3//!
4//! # deps-gen
5//! Allows to generate files from `Cargo.lock` and a provided template at build-time
6//! ## Example
7//! The following will build a file named `src/deps.rs`.
8//!
9//! In `Cargo.toml`, add the following line:
10//! ```toml
11//! [build-dependencies]
12//! deps-gen = "*"
13//! ```
14//! then in your `build.rs`:
15//! ```rust-notest
16//! use deps_gen::gen_deps;
17//!
18//! fn main() {
19//! gen_deps();
20//! }
21//! ```
22//! Add `src/deps.template.rs`:
23//!
24//! ```rust
25//! #[allow(dead_code)]
26//!
27//! pub struct License {
28//! pub name: &'static str,
29//! pub version: &'static str,
30//! }
31//!
32//! impl License {
33//! pub fn all() -> Vec<Self> {
34//! vec![
35//! //{}{{#each dependencies}}
36//! Self {
37//! name: "{{name}}",
38//! version: "{{version}}",
39//! },
40//! //{}{{/each}}
41//! ]
42//! }
43//! }
44//! ```
45//! See [readme](https://crates.io/crates/deps-gen) for more details
46
47#[allow(dead_code)]
48
49mod test;
50mod generator;
51mod data;
52
53use std::fs;
54use std::io::Error;
55use std::path::PathBuf;
56
57pub enum TemplateSource {
58 Text(String),
59 File(PathBuf)
60}
61
62/// `Configuration` struct
63/// - `template` can be either a `File` or `Text`
64/// - `cargo_lock_path` is the path to `Cargo.lock` (filled by default)
65/// - `target_path` if not specified is deduced for `template` (if `template is specified as `File`) by removing the `.template.` name part.
66/// - `post_template_search` / `post_template_replace` allows to perform a post template replacement (to perform cleanup)
67/// - `include_root` if the root crate (the one currently being built) has to be included
68/// - `maximum_depth` when specified allows to limit recursion (the only interest here is probably `1`)
69pub struct Configuration {
70 pub template: TemplateSource,
71 pub cargo_lock_path: PathBuf,
72 pub target_path: Option<PathBuf>,
73 pub post_template_search: Option<String>,
74 pub post_template_replace: String,
75 pub include_root: bool,
76 pub maximum_depth: Option<usize>,
77}
78
79impl Default for Configuration {
80 /// Default values for `Configuration` are
81 /// - `template`: TemplateSource::File("src/deps.template.rs".into()), read template from `src/deps.template.rs`
82 /// - `cargo_lock_path`: the `Cargo.lock` (how surprising π
)
83 /// - `target_path`: `None` (will be deduced from source path)
84 /// - `post_template_search` / `post_template_replace`: `"//{}"` / `""` (meaning `//{}` is removed)
85 /// - `include_root`: `false`
86 /// - `maximum_depth`: `None`
87 fn default() -> Self {
88 Self {
89 template: TemplateSource::File("src/deps.template.rs".into()),
90 cargo_lock_path: "Cargo.lock".into(),
91 target_path: None,
92 post_template_search: Some("//{}".into()),
93 post_template_replace: "".into(),
94 include_root: false,
95 maximum_depth: None,
96 }
97 }
98}
99
100impl Configuration {
101 pub fn target_path(&self) -> PathBuf {
102 if let Some(target_path) = &self.target_path {
103 target_path.clone()
104 } else if let TemplateSource::File(template_file) = &self.template {
105 let template_file_path = template_file.to_str().unwrap();
106 if !template_file_path.contains(".template.") {
107 panic!("When output is not specified, the input file must contain the pattern β.template.β");
108 }
109 let target_path = template_file_path.replace(".template.", ".");
110 target_path.into()
111 } else {
112 panic!("Canβt guess output file!")
113 }
114 }
115
116 pub fn template_text(&self) -> String {
117 match &self.template {
118 TemplateSource::Text(text) => text.clone(),
119 TemplateSource::File(template_file) => {
120 fs::read_to_string(template_file).expect("Problem reading template file")
121 },
122 }
123 }
124}
125
126/// For lazy people (like me π) the default configuration will take `src/deps.template.rs` to generate `src/deps.rs`
127pub fn gen_deps() -> Result<(), Error> {
128 gen_deps_with_conf(Configuration::default())
129}
130
131/// Detailed generator, allowing to customize configuration
132pub fn gen_deps_with_conf(configuration: Configuration) -> Result<(), Error> {
133 if let TemplateSource::File(source_path) = &configuration.template {
134 println!("cargo:rerun-if-changed={}", fs::canonicalize(source_path)?.to_str().unwrap());
135 }
136 generator::Generator::gen_with_configuration(configuration)
137}
138