Skip to main content

snix_glue/
fetchurl.rs

1//! This contains the code translating from a `builtin:derivation` [Derivation]
2//! to a [Fetch].
3use nix_compat::derivation::{Derivation, OutputHash, OutputName};
4use snix_build_glue::fetchers::Fetch;
5use tracing::instrument;
6use url::Url;
7
8/// Takes a derivation produced by a call to `builtin:fetchurl` and returns the
9/// synthesized [Fetch] for it, as well as the name.
10#[instrument]
11pub(crate) fn fetchurl_derivation_to_fetch(drv: &Derivation) -> Result<(String, Fetch), Error> {
12    if drv.builder != "builtin:fetchurl" {
13        return Err(Error::BuilderInvalid);
14    }
15    if !drv.arguments.is_empty() {
16        return Err(Error::ArgumentsInvalud);
17    }
18    if drv.system != "builtin" {
19        return Err(Error::SystemInvalid);
20    }
21
22    // ensure this is a fixed-output derivation
23    if drv.outputs.len() != 1 {
24        return Err(Error::NoFOD);
25    }
26    let out_output = &drv.outputs.get(&OutputName::out()).ok_or(Error::NoFOD)?;
27    let output_hash = out_output.output_hash.as_ref().ok_or(Error::NoFOD)?;
28
29    let name: String = drv
30        .environment
31        .get("name")
32        .ok_or(Error::NameMissing)?
33        .to_owned()
34        .try_into()
35        .map_err(|_| Error::NameInvalid)?;
36
37    let url: Url = std::str::from_utf8(drv.environment.get("url").ok_or(Error::URLMissing)?)
38        .map_err(|_| Error::URLInvalid)?
39        .parse()
40        .map_err(|_| Error::URLInvalid)?;
41
42    Ok(match output_hash {
43        OutputHash {
44            mode: nix_compat::derivation::OutputHashMode::Flat,
45            hash,
46        } => (
47            name,
48            Fetch::URL {
49                url,
50                exp_hash: Some(hash.to_owned()),
51            },
52        ),
53        OutputHash {
54            mode: nix_compat::derivation::OutputHashMode::Recursive,
55            hash,
56        } => {
57            if drv.environment.get("executable").map(|v| v.as_slice()) == Some(b"1") {
58                (
59                    name,
60                    Fetch::Executable {
61                        url,
62                        hash: hash.to_owned(),
63                    },
64                )
65            } else {
66                (
67                    name,
68                    Fetch::NAR {
69                        url,
70                        hash: hash.to_owned(),
71                    },
72                )
73            }
74        }
75    })
76}
77
78#[derive(Debug, thiserror::Error)]
79pub(crate) enum Error {
80    #[error("Invalid builder")]
81    BuilderInvalid,
82    #[error("invalid arguments")]
83    ArgumentsInvalud,
84    #[error("Invalid system")]
85    SystemInvalid,
86    #[error("Derivation is not fixed-output")]
87    NoFOD,
88    #[error("Missing URL")]
89    URLMissing,
90    #[error("Invalid URL")]
91    URLInvalid,
92    #[error("Missing Name")]
93    NameMissing,
94    #[error("Name invalid")]
95    NameInvalid,
96}