Squashed 'third_party/autocxx/' content from commit 629e8fa53
git-subtree-dir: third_party/autocxx
git-subtree-split: 629e8fa531a633164c0b52e2a3cab536d4cd0849
Signed-off-by: Brian Silverman <bsilver16384@gmail.com>
Change-Id: I62a03b0049f49adf029e0204639cdb5468dde1a1
diff --git a/gen/cmd/src/depfile.rs b/gen/cmd/src/depfile.rs
new file mode 100644
index 0000000..5bb7a66
--- /dev/null
+++ b/gen/cmd/src/depfile.rs
@@ -0,0 +1,102 @@
+// Copyright 2022 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::{
+ fs::File,
+ io::Write,
+ path::{Path, PathBuf},
+};
+
+/// Type which knows how to write a .d file. All outputs depend on all
+/// dependencies.
+pub(crate) struct Depfile {
+ file: File,
+ outputs: Vec<String>,
+ dependencies: Vec<String>,
+ depfile_dir: PathBuf,
+}
+
+impl Depfile {
+ pub(crate) fn new(depfile: &Path) -> std::io::Result<Self> {
+ let file = File::create(depfile)?;
+ Ok(Self {
+ file,
+ outputs: Vec::new(),
+ dependencies: Vec::new(),
+ depfile_dir: depfile.parent().unwrap().to_path_buf(),
+ })
+ }
+
+ pub(crate) fn add_dependency(&mut self, dependency: &Path) {
+ self.dependencies.push(self.relativize(dependency))
+ }
+
+ pub(crate) fn add_output(&mut self, output: &Path) {
+ self.outputs.push(self.relativize(output))
+ }
+
+ pub(crate) fn write(&mut self) -> std::io::Result<()> {
+ let dependency_list = self.dependencies.join(" \\\n ");
+ for output in &self.outputs {
+ self.file
+ .write_all(format!("{}: {}\n\n", output, dependency_list).as_bytes())?
+ }
+ Ok(())
+ }
+
+ /// Return a string giving a relative path from the depfile.
+ fn relativize(&self, path: &Path) -> String {
+ pathdiff::diff_paths(path, &self.depfile_dir)
+ .expect("Unable to make a relative path from the depfile's directory to the dependency")
+ .to_str()
+ .expect("Unable to represent the file path in a UTF8 encoding")
+ .into()
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use std::{fs::File, io::Read};
+
+ use tempdir::TempDir;
+
+ use super::Depfile;
+
+ #[test]
+ fn test_simple_depfile() {
+ let tmp_dir = TempDir::new("depfile-test").unwrap();
+ let f = tmp_dir.path().join("depfile.d");
+ let mut df = Depfile::new(&f).unwrap();
+ df.add_output(&tmp_dir.path().join("a/b"));
+ df.add_dependency(&tmp_dir.path().join("c/d"));
+ df.add_dependency(&tmp_dir.path().join("e/f"));
+ df.write().unwrap();
+
+ let mut f = File::open(&f).unwrap();
+ let mut contents = String::new();
+ f.read_to_string(&mut contents).unwrap();
+ assert_eq!(contents, "a/b: c/d \\\n e/f\n\n");
+ }
+
+ #[test]
+ fn test_multiple_outputs() {
+ let tmp_dir = TempDir::new("depfile-test").unwrap();
+ let f = tmp_dir.path().join("depfile.d");
+ let mut df = Depfile::new(&f).unwrap();
+ df.add_output(&tmp_dir.path().join("a/b"));
+ df.add_output(&tmp_dir.path().join("z"));
+ df.add_dependency(&tmp_dir.path().join("c/d"));
+ df.add_dependency(&tmp_dir.path().join("e/f"));
+ df.write().unwrap();
+
+ let mut f = File::open(&f).unwrap();
+ let mut contents = String::new();
+ f.read_to_string(&mut contents).unwrap();
+ assert_eq!(contents, "a/b: c/d \\\n e/f\n\nz: c/d \\\n e/f\n\n");
+ }
+}