summary refs log tree commit diff
path: root/src/main.rs
blob: dd4a56ce665f297225ff7bb0c274d31f89badc1f (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
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")
    );
}