Skip to content

Commit

Permalink
Parse flake references in NIX_PATH
Browse files Browse the repository at this point in the history
Now, `NIX_PATH=nixpkgs:flake:nixpkgs` won't be treated as a relative
path. Consequently, changing the current directory wouldn't invalidate
the cache.
  • Loading branch information
xzfc committed Jun 23, 2024
1 parent bb4c221 commit 0e892a2
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 10 deletions.
2 changes: 1 addition & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -387,7 +387,7 @@ fn run_from_args(args: Vec<OsString>) {
current_dir().expect("Can't get PWD")
} else if arg.as_bytes().starts_with(b"<")
&& arg.as_bytes().ends_with(b">")
|| nix_path::is_uri(arg.as_bytes())
|| nix_path::is_pseudo_url(arg.as_bytes())
{
// in: nix-shell '<foo>'
// out: cd /var/empty; nix-shell '<foo>'
Expand Down
32 changes: 23 additions & 9 deletions src/nix_path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@ fn is_relative(b: &[u8]) -> bool {
.position(|&c| c == b'=')
.map(|x| x + 1)
.unwrap_or(0);
b.get(pos) != Some(&b'/') && !is_uri(&b[pos..])
b.get(pos) != Some(&b'/') && !is_pseudo_url(&b[pos..])
}

/// Reference: https://github.com/NixOS/nix/blob/2.3.10/src/libexpr/eval.cc#L242-L277
/// Reference: https://github.com/NixOS/nix/blob/2.23.0/src/libexpr/eval-settings.cc#L9-L45
fn parse_nix_path(s: &[u8]) -> Vec<&[u8]> {
let mut res = Vec::new();
let mut p = 0;
Expand All @@ -45,7 +45,7 @@ fn parse_nix_path(s: &[u8]) -> Vec<&[u8]> {
}

if s[p] == b':' {
if is_uri(&s[start2..]) {
if is_pseudo_url(&s[start2..]) {
p += 1;
while p < s.len() && s[p] != b':' {
p += 1;
Expand All @@ -63,8 +63,8 @@ fn parse_nix_path(s: &[u8]) -> Vec<&[u8]> {
res
}

/// Reference: https://github.com/NixOS/nix/blob/2.3.10/src/libstore/download.cc#L936-L943
pub fn is_uri(s: &[u8]) -> bool {
/// Reference: https://github.com/NixOS/nix/blob/2.23.0/src/libexpr/eval-settings.cc#L79-L86
pub fn is_pseudo_url(s: &[u8]) -> bool {
let prefixes = &[
"channel:",
"http://",
Expand All @@ -74,6 +74,7 @@ pub fn is_uri(s: &[u8]) -> bool {
"git://",
"s3://",
"ssh://",
"flake:", // Not in the original code
];
prefixes
.iter()
Expand All @@ -82,28 +83,41 @@ pub fn is_uri(s: &[u8]) -> bool {

#[cfg(test)]
mod tests {
use super::{is_relative, parse_nix_path};
use super::*;

macro_rules! v {
( $($a:literal),* ) => {{
vec![ $( Vec::<u8>::from($a as &[_])),* ]
}}
}

#[test]
fn it_works() {
fn test_parse_nix_path() {
assert_eq!(parse_nix_path(b"foo:bar:baz"), v![b"foo", b"bar", b"baz"]);
assert_eq!(
parse_nix_path(b"foo:bar=something:baz"),
v![b"foo", b"bar=something", b"baz"]
);
assert_eq!(
parse_nix_path(b"foo:bar=https://something:baz"),
v![b"foo", b"bar=https://something", b"baz"]
parse_nix_path(
b"foo:bar=https://something:baz=flake:something:qux"
),
v![
b"foo",
b"bar=https://something",
b"baz=flake:something",
b"qux"
]
);
}

#[test]
fn test_is_relative() {
assert!(is_relative(b"foo"));
assert!(is_relative(b"foo=bar"));
assert!(!is_relative(b"http://foo"));
assert!(!is_relative(b"foo=/bar"));
assert!(!is_relative(b"foo=http://bar"));
assert!(!is_relative(b"foo=flake:bar"));
}
}

0 comments on commit 0e892a2

Please sign in to comment.