summary refs log tree commit diff
path: root/src/main.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/main.rs')
-rw-r--r--src/main.rs89
1 files changed, 89 insertions, 0 deletions
diff --git a/src/main.rs b/src/main.rs
new file mode 100644
index 0000000..dd4a56c
--- /dev/null
+++ b/src/main.rs
@@ -0,0 +1,89 @@
+use std::collections::BTreeSet;
+use std::env::args_os;
+use std::fs::File;
+use std::io::Read;
+use std::os::unix::prelude::*;
+use std::process::{Command, Stdio};
+
+use cargo::core::SourceId;
+use serde::{Deserialize, Serialize};
+use serde_json;
+use toml::value::Table as TomlTable;
+
+#[derive(Debug, Serialize)]
+struct Output {
+    git: BTreeSet<PrefetchGit>,
+}
+
+#[derive(Debug, Serialize, Deserialize, Ord, PartialOrd, Eq, PartialEq)]
+struct PrefetchGit {
+    url: String,
+    rev: String,
+    sha256: String,
+    #[serde(rename = "fetchSubmodules")]
+    fetch_submodules: bool,
+    #[serde(rename = "deepClone")]
+    deep_clone: bool,
+    #[serde(rename = "leaveDotGit")]
+    leave_dot_git: bool,
+}
+
+fn main() {
+    let lockfile_path = args_os().skip(1).next().expect("missing lockfile path");
+
+    let mut lockfile_bytes = vec![];
+    let mut lockfile_fd = File::open(lockfile_path).expect("lockfile does not exist");
+    lockfile_fd
+        .read_to_end(&mut lockfile_bytes)
+        .expect("failed to read lockfile");
+
+    let lockfile: TomlTable = toml::from_slice(&lockfile_bytes).expect("can't parse lockfile");
+    let packages = lockfile
+        .get("package")
+        .expect("missing 'package' key")
+        .as_array()
+        .expect("package is not array");
+
+    let sources: BTreeSet<_> = packages
+        .into_iter()
+        .flat_map(|package| package.get("source"))
+        .map(|source| {
+            SourceId::from_url(source.as_str().expect("source not string"))
+                .expect("source not string")
+        })
+        .filter(|source| source.is_git())
+        .collect();
+
+    let output: BTreeSet<PrefetchGit> = sources
+        .into_iter()
+        .map(|source| {
+            let output = Command::new("nix-prefetch-git")
+                .arg("--fetch-submodules")
+                .arg(source.url().as_str())
+                .arg(source.precise().expect("missing precise in source URL"))
+                .stderr(Stdio::inherit())
+                .output()
+                .expect("failed to spawn nix-prefetch-git");
+            if !output.status.success() {
+                if let Some(code) = output.status.code() {
+                    panic!("nix-prefetch-git exited with status {}", code);
+                } else {
+                    panic!(
+                        "nix-prefetch-git exited with signal {}",
+                        output.status.signal().unwrap()
+                    );
+                }
+            }
+
+            // FIXME: no need to read stdout into a buffer.
+
+            serde_json::from_slice(&output.stdout).expect("failed to parse nix-prefetch-git output")
+        })
+        .collect();
+
+    println!(
+        "{}",
+        toml::ser::to_string_pretty(&Output { git: output })
+            .expect("failed to serialize nix-prefetch-git output as TOML")
+    );
+}