build_deps/lib.rs
1// Copyright (C) 2019 Frank Rehberger
2//
3// Licensed under the Apache License, Version 2.0 or MIT License
4
5//! # Rust build-script dependencies generator
6//!
7//! Rust build-script dependencies generator is intended for the build-script `build.rs'. All files
8//! matching the user defined GLOB pattern will be added to Cargo's dependency-checker. In case
9//! those files have been modified since last build-process, the build process is re-ran.
10//!
11//! Expanding the pattern the set _must_ not contain directories. Cargo only supports files
12//! for dependency checking. If the expanded set contains a directory the function will continue
13//! with next element in the list but returning with error Error::ExpandedPathExpectedFile(String)
14//!
15//! This way the calling build-script `build.rs` may interrupt the build-process or ignore
16//! the presents of a directory along the GLOB-expansion.
17//!
18//! For further reading see chapter [Cargo Build-Script Output](https://doc.rust-lang.org/cargo/reference/build-scripts.html#outputs-of-the-build-script)
19//!
20//! Note: The cargo application ist storing the build-script-output in the build directory,
21//! for example: `target/debug/build/*/output`.
22extern crate glob;
23use std::path::{Path};
24
25use self::glob::{glob, Paths};
26
27/// Error cases
28#[derive(Clone, Debug)]
29pub enum Error {
30 /// Invalid GLOB pattern
31 InvalidGlobPattern(String),
32
33 /// The pattern contains invalid characters
34 InvalidOsString(std::ffi::OsString),
35
36 /// Expanded pattern contains a path that is no file
37 ExpandedPathExpectedFile(String),
38}
39
40/// Specify a file or directory which, if changed, should trigger a rebuild.
41///
42/// Reference: This function stems from crate 'build-helper'
43fn rerun_if_changed<P: AsRef<Path>>(path: P) {
44 println!("cargo:rerun-if-changed={}", path.as_ref().display());
45}
46
47/// Exapanding the GLOB pattern and adding dependency to Cargo-build-process
48///
49/// For example:
50/// `"data/*"` will enumerate all files/directories in directory "data/" and watchin changes
51///
52/// `"data/"` - will add the directory itself to the watch-list, triggering a rerun in case new entities are added.
53///
54/// `"data/**/*.protobuf"` will traverse all sub-directories enumerating all protobuf files.
55///
56/// `"data/**"` will traverse all sub-directories enumerating all directories
57///
58/// **Rule of thumb**
59/// Add files, if changes to files shall be detected.
60///
61/// Add directories, if the build-process shall be rerun in case of _new_/_removed_ files.
62///
63/// ```
64/// // declared in Cargo.toml as "[build-dependencies]"
65/// extern crate build_deps;
66///
67/// fn main() {
68/// // Enumerate files in sub-folder "data/*", being relevant for the test-generation (as example)
69/// // If function returns with error, exit with error message.
70/// build_deps::rerun_if_changed_paths( "data/*" ).unwrap();
71///
72/// // Adding the parent directory "data" to the watch-list will capture new-files being added
73/// build_deps::rerun_if_changed_paths( "data" ).unwrap();
74/// }
75/// ```
76///
77pub fn rerun_if_changed_paths(pattern: &str) -> Result<(), Error> {
78 let paths: Paths = glob(&pattern).map_err(|err| Error::InvalidGlobPattern(err.to_string()))?;
79
80 for entry in paths {
81 match entry {
82 Ok(path) => rerun_if_changed(&path),
83 Err(e) => return Err(Error::InvalidGlobPattern(e.to_string())),
84 }
85 }
86
87 Ok(())
88}