about summary refs log tree commit diff
path: root/tvix/nix-compat
diff options
context:
space:
mode:
authorAspen Smith <root@gws.fyi>2024-02-23T15·09-0500
committerclbot <clbot@tvl.fyi>2024-03-11T02·21+0000
commitde727bccf99a1dcce2bb335e56af02f80e462dbc (patch)
tree68be9d8e56fd7efdd8383a02daae611ac4d86ded /tvix/nix-compat
parent83ad32c48162e920168657421aaec1cc9e35a1de (diff)
feat(tvix/glue): Implement builtins.fetchurl r/7678
Implement the fetchurl builtin, and lay the groundwork for implementing
the fetchTarball builtin (which works very similarly, and is implemented
using almost the same code in C++ nix).

An overview of how this works:

1. First, we check if the store path that *would* result from the
   download already exists in the store - if it does, we just return
   that
2. If we need to download the URL, TvixStoreIO has an `http_client:
   reqwest::Client` field now which we use to make the request
3. As we're downloading the blob, we hash the data incrementally into a
   SHA256 hasher
4. We compare the hash against the expected hash (if any) and bail out
   if it doesn't match
5. Finally, we put the blob in the store and return the store path

Since the logic is very similar, this commit also implements a *chunk*
of `fetchTarball` (though the actual implementation will likely include
a refactor to some of the code reuse here).

The main thing that's missing here is caching of downloaded blobs when
fetchurl is called without a hash - I've opened b/381 to track the TODO
there.

Adding the `SSL_CERT_FILE` here is necessary to teach reqwest how to
load it during tests - see 1c16dee20 (feat(tvix/store): use reqwests'
rustls-native-roots feature, 2024-03-03) for  more info.

Change-Id: I83c4abbc7c0c3bfe92461917e23d6d3430fbf137
Reviewed-on: https://cl.tvl.fyi/c/depot/+/11017
Tested-by: BuildkiteCI
Reviewed-by: flokli <flokli@flokli.de>
Autosubmit: aspen <root@gws.fyi>
Diffstat (limited to 'tvix/nix-compat')
-rw-r--r--tvix/nix-compat/src/store_path/mod.rs14
1 files changed, 10 insertions, 4 deletions
diff --git a/tvix/nix-compat/src/store_path/mod.rs b/tvix/nix-compat/src/store_path/mod.rs
index 836374b800..c744f1a46a 100644
--- a/tvix/nix-compat/src/store_path/mod.rs
+++ b/tvix/nix-compat/src/store_path/mod.rs
@@ -29,7 +29,7 @@ pub enum Error {
     #[error("Dash is missing between hash and name")]
     MissingDash,
     #[error("Hash encoding is invalid: {0}")]
-    InvalidHashEncoding(DecodeError),
+    InvalidHashEncoding(#[from] DecodeError),
     #[error("Invalid length")]
     InvalidLength,
     #[error(
@@ -67,6 +67,13 @@ impl StorePath {
     pub fn name(&self) -> &str {
         self.name.as_ref()
     }
+
+    pub fn as_ref(&self) -> StorePathRef<'_> {
+        StorePathRef {
+            digest: self.digest,
+            name: &self.name,
+        }
+    }
 }
 
 impl PartialOrd for StorePath {
@@ -176,7 +183,7 @@ impl Serialize for StorePath {
 /// Like [StorePath], but without a heap allocation for the name.
 /// Used by [StorePath] for parsing.
 ///
-#[derive(Debug, Eq, PartialEq)]
+#[derive(Debug, Eq, PartialEq, Clone, Copy)]
 pub struct StorePathRef<'a> {
     digest: [u8; DIGEST_SIZE],
     name: &'a str,
@@ -237,8 +244,7 @@ impl<'a> StorePathRef<'a> {
             Err(Error::InvalidLength)?
         }
 
-        let digest = nixbase32::decode_fixed(&s[..ENCODED_DIGEST_SIZE])
-            .map_err(Error::InvalidHashEncoding)?;
+        let digest = nixbase32::decode_fixed(&s[..ENCODED_DIGEST_SIZE])?;
 
         if s[ENCODED_DIGEST_SIZE] != b'-' {
             return Err(Error::MissingDash);