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}