Compare commits
19 commits
test-in-ci
...
main
Author | SHA1 | Date | |
---|---|---|---|
885a49701c | |||
139dcf2fe7 | |||
8ba2c6cc9b | |||
ab1fcc8207 | |||
a995716212 | |||
2b52792959 | |||
112654f448 | |||
ce0e70f95a | |||
68df59ad25 | |||
76e6c6c537 | |||
d9ca033a14 | |||
6cfe67af0e | |||
96ae0ca647 | |||
688fcd8706 | |||
d03058d125 | |||
3c40776981 | |||
9b0c6aece6 | |||
14d6e9d29e | |||
0e97d11745 |
15 changed files with 308 additions and 57 deletions
3
.editorconfig
Normal file
3
.editorconfig
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
[*.nix]
|
||||||
|
indent_size = 2
|
||||||
|
indent_stype = space
|
73
.github/workflows/build.yml
vendored
Normal file
73
.github/workflows/build.yml
vendored
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
name: build
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
push:
|
||||||
|
pull_request:
|
||||||
|
|
||||||
|
env:
|
||||||
|
TERM: ansi
|
||||||
|
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
||||||
|
AWS_SECRET_ACCESS_KEY: ${{ secrets. AWS_SECRET_ACCESS_KEY }}
|
||||||
|
AWS_ENDPOINT: https://s3.cy7.sh
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-packages:
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
os:
|
||||||
|
- ubuntu-latest
|
||||||
|
- ubuntu-24.04-arm
|
||||||
|
- macos-latest # arm64
|
||||||
|
- macos-13 # x86
|
||||||
|
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: setup binary cache key
|
||||||
|
run: echo -n "${{ secrets.NIX_CACHE_SECRET_KEY }}" | xxd -p -r > ${{ runner.temp }}/cache-priv-key.pem
|
||||||
|
|
||||||
|
- name: Install Nix
|
||||||
|
uses: cachix/install-nix-action@526118121621777ccd86f79b04685a9319637641
|
||||||
|
with:
|
||||||
|
enable_kvm: true
|
||||||
|
extra_nix_config: |
|
||||||
|
show-trace = true
|
||||||
|
experimental-features = nix-command flakes
|
||||||
|
secret-key-files = ${{ runner.temp }}/cache-priv-key.pem
|
||||||
|
extra-substituters = https://nixcache.cy7.sh
|
||||||
|
extra-trusted-public-keys = nixcache.cy7.sh:DN3d1dt0wnXfTH03oVmTee4KgmdNdB0NY3SuzA8Fwx8=
|
||||||
|
|
||||||
|
- uses: actions/checkout@85e6279cec87321a52edac9c87bce653a07cf6c2
|
||||||
|
with:
|
||||||
|
persist-credentials: false
|
||||||
|
|
||||||
|
- name: cache devshell
|
||||||
|
run: |
|
||||||
|
nix build .#devShells.$(nix eval --impure --raw --expr 'builtins.currentSystem').default
|
||||||
|
nix run \
|
||||||
|
github:cything/nixcp -- push \
|
||||||
|
--bucket nixcache \
|
||||||
|
--signing-key ${{ runner.temp }}/cache-priv-key.pem \
|
||||||
|
result
|
||||||
|
|
||||||
|
- name: build
|
||||||
|
run: nix build -L .
|
||||||
|
|
||||||
|
- name: cache
|
||||||
|
run: |
|
||||||
|
nix run \
|
||||||
|
github:cything/nixcp -- push \
|
||||||
|
--bucket nixcache \
|
||||||
|
--signing-key ${{ runner.temp }}/cache-priv-key.pem \
|
||||||
|
result
|
||||||
|
|
||||||
|
- name: prepare tarball to upload
|
||||||
|
run: nix run github:nixos/nixpkgs#gnutar hcvf result.tar result
|
||||||
|
|
||||||
|
- name: upload result
|
||||||
|
uses: actions/upload-artifact@6027e3dd177782cd8ab9af838c04fd81a07f1d47
|
||||||
|
with:
|
||||||
|
name: ${{ matrix.os }}.tar
|
||||||
|
path: result.tar
|
||||||
|
if-no-files-found: error
|
27
.github/workflows/check.yml
vendored
Normal file
27
.github/workflows/check.yml
vendored
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
name: check
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
push:
|
||||||
|
pull_request:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Install Nix
|
||||||
|
uses: cachix/install-nix-action@526118121621777ccd86f79b04685a9319637641
|
||||||
|
with:
|
||||||
|
enable_kvm: true
|
||||||
|
extra_nix_config: |
|
||||||
|
show-trace = true
|
||||||
|
experimental-features = nix-command flakes
|
||||||
|
extra-substituters = https://nixcache.cy7.sh
|
||||||
|
extra-trusted-public-keys = nixcache.cy7.sh:DN3d1dt0wnXfTH03oVmTee4KgmdNdB0NY3SuzA8Fwx8=
|
||||||
|
|
||||||
|
- uses: actions/checkout@85e6279cec87321a52edac9c87bce653a07cf6c2
|
||||||
|
with:
|
||||||
|
persist-credentials: false
|
||||||
|
|
||||||
|
- name: Run checks
|
||||||
|
run: nix flake check -L
|
30
.github/workflows/test.yml
vendored
Normal file
30
.github/workflows/test.yml
vendored
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
name: test
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
push:
|
||||||
|
pull_request:
|
||||||
|
|
||||||
|
env:
|
||||||
|
CARGO_TERM_COLOR: always
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Install Nix
|
||||||
|
uses: cachix/install-nix-action@526118121621777ccd86f79b04685a9319637641
|
||||||
|
with:
|
||||||
|
enable_kvm: true
|
||||||
|
extra_nix_config: |
|
||||||
|
show-trace = true
|
||||||
|
experimental-features = nix-command flakes
|
||||||
|
extra-substituters = https://nixcache.cy7.sh
|
||||||
|
extra-trusted-public-keys = nixcache.cy7.sh:DN3d1dt0wnXfTH03oVmTee4KgmdNdB0NY3SuzA8Fwx8=
|
||||||
|
|
||||||
|
- uses: actions/checkout@85e6279cec87321a52edac9c87bce653a07cf6c2
|
||||||
|
with:
|
||||||
|
persist-credentials: false
|
||||||
|
|
||||||
|
- name: Run tests
|
||||||
|
run: nix develop -c cargo test --verbose
|
10
Cargo.toml
10
Cargo.toml
|
@ -16,15 +16,14 @@ futures = "0.3.31"
|
||||||
nix-compat = { git = "https://github.com/tvlfyi/tvix.git", version = "0.1.0" }
|
nix-compat = { git = "https://github.com/tvlfyi/tvix.git", version = "0.1.0" }
|
||||||
regex = "1.11.1"
|
regex = "1.11.1"
|
||||||
reqwest = "0.12.15"
|
reqwest = "0.12.15"
|
||||||
serde = { version = "1.0.219", features = [ "derive" ]}
|
serde = { version = "1.0.219", features = ["derive"] }
|
||||||
serde_json = "1.0.140"
|
serde_json = "1.0.140"
|
||||||
sha2 = "0.10.8"
|
sha2 = "0.10.8"
|
||||||
tokio = { version = "1.44.1", features = [ "full", "tracing", "parking_lot" ]}
|
tokio = { version = "1.44.1", features = ["full", "tracing", "parking_lot"] }
|
||||||
tracing = "0.1.41"
|
tracing = "0.1.41"
|
||||||
url = { version = "2.5.4", features = [ "serde" ]}
|
url = { version = "2.5.4", features = ["serde"] }
|
||||||
cxx = "1.0"
|
cxx = "1.0"
|
||||||
console-subscriber = "0.4.1"
|
console-subscriber = "0.4.1"
|
||||||
tempfile = "3.19.1"
|
|
||||||
tokio-util = { version = "0.7.15", features = ["io"] }
|
tokio-util = { version = "0.7.15", features = ["io"] }
|
||||||
bytes = "1.10.1"
|
bytes = "1.10.1"
|
||||||
object_store = { version = "0.12.0", features = ["aws"] }
|
object_store = { version = "0.12.0", features = ["aws"] }
|
||||||
|
@ -35,3 +34,6 @@ humansize = "2.1.3"
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
cxx-build = "1.0"
|
cxx-build = "1.0"
|
||||||
pkg-config = "0.3.32"
|
pkg-config = "0.3.32"
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
tempfile = "3.19.1"
|
||||||
|
|
21
LICENSE
Normal file
21
LICENSE
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2025 Cy
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
19
README.md
19
README.md
|
@ -11,14 +11,13 @@ The signing key is generated with:
|
||||||
nix-store --generate-binary-cache-key nixcache.cy7.sh cache-priv-key.pem cache-pub-key.pem
|
nix-store --generate-binary-cache-key nixcache.cy7.sh cache-priv-key.pem cache-pub-key.pem
|
||||||
```
|
```
|
||||||
|
|
||||||
`AWS_ACCESS_KEY_ID` and `AWS_ENDPOINT_URL` environment variables should be set with your s3 credentials.
|
`AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` environment variables should be set with your s3 credentials.
|
||||||
|
|
||||||
```
|
```
|
||||||
Usage: nixcp [OPTIONS] --bucket <bucket name> --signing-key <SIGNING_KEY> <COMMAND>
|
Usage: nixcp push [OPTIONS] --bucket <bucket name> --signing-key <SIGNING_KEY> [PATH]...
|
||||||
|
|
||||||
Commands:
|
Arguments:
|
||||||
push
|
[PATH]... Path to upload e.g. ./result or /nix/store/y4qpcibkj767szhjb58i2sidmz8m24hb-hello-2.12.1
|
||||||
help Print this message or the help of the given subcommand(s)
|
|
||||||
|
|
||||||
Options:
|
Options:
|
||||||
--bucket <bucket name>
|
--bucket <bucket name>
|
||||||
|
@ -28,15 +27,13 @@ Options:
|
||||||
--signing-key <SIGNING_KEY>
|
--signing-key <SIGNING_KEY>
|
||||||
Path to the file containing signing key e.g. ~/cache-priv-key.pem
|
Path to the file containing signing key e.g. ~/cache-priv-key.pem
|
||||||
--region <REGION>
|
--region <REGION>
|
||||||
If unspecified, will get it form AWS_DEFAULT_REGION envar or the AWS default
|
If unspecified, will get it form AWS_DEFAULT_REGION envar or default to us-east-1
|
||||||
--endpoint <ENDPOINT>
|
--endpoint <ENDPOINT>
|
||||||
If unspecifed, will get it from AWS_ENDPOINT_URL envar or the AWS default e.g. https://s3.example.com
|
If unspecifed, will get it from AWS_ENDPOINT envar e.g. https://s3.example.com
|
||||||
--profile <PROFILE>
|
--no-default-upstream
|
||||||
AWS profile to use
|
Do not include cache.nixos.org as upstream
|
||||||
-h, --help
|
-h, --help
|
||||||
Print help
|
Print help
|
||||||
-V, --version
|
|
||||||
Print version
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Install with nix
|
## Install with nix
|
||||||
|
|
49
flake.nix
49
flake.nix
|
@ -11,8 +11,15 @@
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
outputs = inputs@{ nixpkgs, flake-utils, crane, ... }:
|
outputs =
|
||||||
flake-utils.lib.eachDefaultSystem (system:
|
inputs@{
|
||||||
|
nixpkgs,
|
||||||
|
flake-utils,
|
||||||
|
crane,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
flake-utils.lib.eachDefaultSystem (
|
||||||
|
system:
|
||||||
let
|
let
|
||||||
pkgs = import nixpkgs {
|
pkgs = import nixpkgs {
|
||||||
inherit system;
|
inherit system;
|
||||||
|
@ -21,13 +28,12 @@
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
toolchain = pkgs.rust-bin.fromRustupToolchainFile ./rust-toolchain.toml;
|
toolchain = pkgs.rust-bin.fromRustupToolchainFile ./rust-toolchain.toml;
|
||||||
craneLib = (crane.mkLib pkgs).overrideToolchain(_: toolchain);
|
craneLib = (crane.mkLib pkgs).overrideToolchain (_: toolchain);
|
||||||
lib = pkgs.lib;
|
lib = pkgs.lib;
|
||||||
|
|
||||||
# don't clean cpp files
|
# don't clean cpp files
|
||||||
cppFilter = path: _type: builtins.match ".*(cpp|hpp)$" path != null;
|
cppFilter = path: _type: builtins.match ".*(cpp|hpp)$" path != null;
|
||||||
cppOrCargo = path: type:
|
cppOrCargo = path: type: (cppFilter path type) || (craneLib.filterCargoSources path type);
|
||||||
(cppFilter path type) || (craneLib.filterCargoSources path type);
|
|
||||||
src = lib.cleanSourceWith {
|
src = lib.cleanSourceWith {
|
||||||
src = ./.;
|
src = ./.;
|
||||||
filter = cppOrCargo;
|
filter = cppOrCargo;
|
||||||
|
@ -48,14 +54,38 @@
|
||||||
];
|
];
|
||||||
# for cpp bindings to work
|
# for cpp bindings to work
|
||||||
NIX_INCLUDE_PATH = "${lib.getDev pkgs.nix}/include";
|
NIX_INCLUDE_PATH = "${lib.getDev pkgs.nix}/include";
|
||||||
|
# skip integration tests (they need a connection to the nix store)
|
||||||
|
cargoTestExtraArgs = "--bins";
|
||||||
};
|
};
|
||||||
|
|
||||||
cargoArtifacts = craneLib.buildDepsOnly commonArgs;
|
cargoArtifacts = craneLib.buildDepsOnly commonArgs;
|
||||||
nixcp = craneLib.buildPackage (commonArgs // {
|
nixcp = craneLib.buildPackage (
|
||||||
inherit cargoArtifacts;
|
commonArgs
|
||||||
});
|
// {
|
||||||
|
inherit cargoArtifacts;
|
||||||
|
}
|
||||||
|
);
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
|
checks = {
|
||||||
|
# clippy with all warnings denied
|
||||||
|
clippy = craneLib.cargoClippy (
|
||||||
|
commonArgs
|
||||||
|
// {
|
||||||
|
inherit cargoArtifacts;
|
||||||
|
cargoClippyExtraArgs = "--all-targets -- --deny warnings";
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
# check formatting
|
||||||
|
cargoFmt = craneLib.cargoFmt {
|
||||||
|
inherit src;
|
||||||
|
};
|
||||||
|
tomlFmt = craneLib.taploFmt {
|
||||||
|
src = lib.sources.sourceFilesBySuffices src [ ".toml" ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
devShells.default = craneLib.devShell {
|
devShells.default = craneLib.devShell {
|
||||||
inputsFrom = [ nixcp ];
|
inputsFrom = [ nixcp ];
|
||||||
|
|
||||||
|
@ -66,9 +96,12 @@
|
||||||
packages = with pkgs; [
|
packages = with pkgs; [
|
||||||
tokio-console
|
tokio-console
|
||||||
cargo-udeps
|
cargo-udeps
|
||||||
|
cargo-audit
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
formatter = pkgs.nixfmt-rfc-style;
|
||||||
|
|
||||||
packages.default = nixcp;
|
packages.default = nixcp;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,9 +1,4 @@
|
||||||
[toolchain]
|
[toolchain]
|
||||||
channel = "nightly"
|
channel = "nightly"
|
||||||
profile = "minimal"
|
profile = "minimal"
|
||||||
components = [
|
components = ["rust-src", "rust-analyzer", "rustfmt", "clippy"]
|
||||||
"rust-src",
|
|
||||||
"rust-analyzer",
|
|
||||||
"rustfmt",
|
|
||||||
"clippy",
|
|
||||||
]
|
|
||||||
|
|
|
@ -1,2 +0,0 @@
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,6 @@ use std::path::PathBuf;
|
||||||
use clap::{Args, Parser, Subcommand};
|
use clap::{Args, Parser, Subcommand};
|
||||||
|
|
||||||
mod bindings;
|
mod bindings;
|
||||||
mod cli;
|
|
||||||
pub mod make_nar;
|
pub mod make_nar;
|
||||||
pub mod path_info;
|
pub mod path_info;
|
||||||
pub mod push;
|
pub mod push;
|
||||||
|
@ -55,8 +54,9 @@ pub struct PushArgs {
|
||||||
#[arg(long)]
|
#[arg(long)]
|
||||||
endpoint: Option<String>,
|
endpoint: Option<String>,
|
||||||
|
|
||||||
|
/// Do not include cache.nixos.org as upstream
|
||||||
#[arg(long)]
|
#[arg(long)]
|
||||||
skip_signature_check: bool,
|
no_default_upstream: bool,
|
||||||
|
|
||||||
/// Path to upload
|
/// Path to upload
|
||||||
/// e.g. ./result or /nix/store/y4qpcibkj767szhjb58i2sidmz8m24hb-hello-2.12.1
|
/// e.g. ./result or /nix/store/y4qpcibkj767szhjb58i2sidmz8m24hb-hello-2.12.1
|
||||||
|
|
|
@ -28,6 +28,14 @@ impl PathInfo {
|
||||||
let derivation = match drv.extension() {
|
let derivation = match drv.extension() {
|
||||||
Some(ext) if ext == "drv" => drv.as_os_str().as_encoded_bytes(),
|
Some(ext) if ext == "drv" => drv.as_os_str().as_encoded_bytes(),
|
||||||
_ => {
|
_ => {
|
||||||
|
let drv = {
|
||||||
|
// resolve symlink
|
||||||
|
if drv.is_symlink() {
|
||||||
|
&drv.canonicalize()?
|
||||||
|
} else {
|
||||||
|
drv
|
||||||
|
}
|
||||||
|
};
|
||||||
&Command::new("nix")
|
&Command::new("nix")
|
||||||
.arg("path-info")
|
.arg("path-info")
|
||||||
.arg("--derivation")
|
.arg("--derivation")
|
||||||
|
|
18
src/push.rs
18
src/push.rs
|
@ -1,7 +1,6 @@
|
||||||
use std::{
|
use std::{
|
||||||
collections::HashSet,
|
collections::HashSet,
|
||||||
fs,
|
fs,
|
||||||
iter::once,
|
|
||||||
path::PathBuf,
|
path::PathBuf,
|
||||||
sync::{
|
sync::{
|
||||||
Arc,
|
Arc,
|
||||||
|
@ -39,11 +38,13 @@ pub struct Push {
|
||||||
impl Push {
|
impl Push {
|
||||||
pub async fn new(cli: &PushArgs, store: Store) -> Result<Self> {
|
pub async fn new(cli: &PushArgs, store: Store) -> Result<Self> {
|
||||||
let mut upstreams = Vec::with_capacity(cli.upstreams.len() + 1);
|
let mut upstreams = Vec::with_capacity(cli.upstreams.len() + 1);
|
||||||
for upstream in cli
|
if !cli.no_default_upstream {
|
||||||
.upstreams
|
upstreams.push(
|
||||||
.iter()
|
Url::parse("https://cache.nixos.org")
|
||||||
.chain(once(&"https://cache.nixos.org".to_string()))
|
.expect("default upstream must be a valid url"),
|
||||||
{
|
);
|
||||||
|
}
|
||||||
|
for upstream in &cli.upstreams {
|
||||||
upstreams
|
upstreams
|
||||||
.push(Url::parse(upstream).context(format!("failed to parse {upstream} as url"))?);
|
.push(Url::parse(upstream).context(format!("failed to parse {upstream} as url"))?);
|
||||||
}
|
}
|
||||||
|
@ -132,10 +133,7 @@ impl Push {
|
||||||
let inflight_permits = inflight_permits.clone();
|
let inflight_permits = inflight_permits.clone();
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
let _permit = inflight_permits.acquire().await.unwrap();
|
let _permit = inflight_permits.acquire().await.unwrap();
|
||||||
if !path
|
if !path.check_upstream_hit(&self.upstream_caches).await {
|
||||||
.check_upstream_hit(self.upstream_caches.as_slice())
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
if path.check_if_already_exists(&self.s3).await {
|
if path.check_if_already_exists(&self.s3).await {
|
||||||
debug!("skip {} (already exists)", path.absolute_path());
|
debug!("skip {} (already exists)", path.absolute_path());
|
||||||
self.already_exists_count.fetch_add(1, Ordering::Relaxed);
|
self.already_exists_count.fetch_add(1, Ordering::Relaxed);
|
||||||
|
|
|
@ -6,8 +6,10 @@ use std::sync::Arc;
|
||||||
use nixcp::store::Store;
|
use nixcp::store::Store;
|
||||||
|
|
||||||
pub const HELLO: &str = "github:nixos/nixpkgs?ref=f771eb401a46846c1aebd20552521b233dd7e18b#hello";
|
pub const HELLO: &str = "github:nixos/nixpkgs?ref=f771eb401a46846c1aebd20552521b233dd7e18b#hello";
|
||||||
pub const HELLO_DRV: &str = "iqbwkm8mjjjlmw6x6ry9rhzin2cp9372-hello-2.12.1.drv";
|
pub const HELLO_DRV: &str = "/nix/store/iqbwkm8mjjjlmw6x6ry9rhzin2cp9372-hello-2.12.1.drv";
|
||||||
pub const HELLO_PATH: &str = "/nix/store/9bwryidal9q3g91cjm6xschfn4ikd82q-hello-2.12.1";
|
pub const HELLO_PATH: &str = "/nix/store/9bwryidal9q3g91cjm6xschfn4ikd82q-hello-2.12.1";
|
||||||
|
pub const NIXCP_PKG: &str = "github:cything/nixcp?ref=6cfe67af0e8da502702b31f34a941753e64d9561";
|
||||||
|
pub const NIXCP_DRV: &str = "/nix/store/ldjvf9qjp980dyvka2hj99q4c0w6901x-nixcp-0.1.0.drv";
|
||||||
|
|
||||||
pub struct Context {
|
pub struct Context {
|
||||||
pub store: Arc<Store>,
|
pub store: Arc<Store>,
|
||||||
|
@ -16,12 +18,7 @@ pub struct Context {
|
||||||
impl Context {
|
impl Context {
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
// hello must be in the store
|
// hello must be in the store
|
||||||
Command::new("nix")
|
ensure_exists(HELLO);
|
||||||
.arg("build")
|
|
||||||
.arg("--no-link")
|
|
||||||
.arg(HELLO)
|
|
||||||
.status()
|
|
||||||
.unwrap();
|
|
||||||
let store = Arc::new(Store::connect().expect("connect to nix store"));
|
let store = Arc::new(Store::connect().expect("connect to nix store"));
|
||||||
Self { store }
|
Self { store }
|
||||||
}
|
}
|
||||||
|
@ -30,3 +27,12 @@ impl Context {
|
||||||
pub fn context() -> Context {
|
pub fn context() -> Context {
|
||||||
Context::new()
|
Context::new()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn ensure_exists(pkg: &str) {
|
||||||
|
Command::new("nix")
|
||||||
|
.arg("build")
|
||||||
|
.arg("--no-link")
|
||||||
|
.arg(pkg)
|
||||||
|
.status()
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
use nixcp::path_info::PathInfo;
|
use nixcp::path_info::PathInfo;
|
||||||
use std::path::PathBuf;
|
use std::{collections::HashSet, path::PathBuf, process::Command};
|
||||||
|
|
||||||
use crate::common::{HELLO, HELLO_DRV, HELLO_PATH};
|
use tempfile::TempDir;
|
||||||
|
|
||||||
|
use crate::common::{HELLO, HELLO_DRV, HELLO_PATH, NIXCP_DRV, NIXCP_PKG};
|
||||||
|
|
||||||
mod common;
|
mod common;
|
||||||
|
|
||||||
|
@ -12,7 +14,7 @@ async fn path_info_from_package() {
|
||||||
let path_info = PathInfo::from_derivation(&path, &ctx.store)
|
let path_info = PathInfo::from_derivation(&path, &ctx.store)
|
||||||
.await
|
.await
|
||||||
.expect("get pathinfo from package");
|
.expect("get pathinfo from package");
|
||||||
assert_eq!(path_info.path.to_string(), HELLO_DRV);
|
assert_eq!(path_info.path.to_absolute_path(), HELLO_DRV);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
@ -22,16 +24,74 @@ async fn path_info_from_path() {
|
||||||
let path_info = PathInfo::from_derivation(&path, &ctx.store)
|
let path_info = PathInfo::from_derivation(&path, &ctx.store)
|
||||||
.await
|
.await
|
||||||
.expect("get pathinfo from package");
|
.expect("get pathinfo from package");
|
||||||
assert_eq!(path_info.path.to_string(), HELLO_DRV);
|
assert_eq!(path_info.path.to_absolute_path(), HELLO_DRV);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn closure() {
|
async fn path_info_symlink() {
|
||||||
|
let ctx = common::context();
|
||||||
|
|
||||||
|
let temp_path = TempDir::new().unwrap();
|
||||||
|
let link_path = temp_path.path().join("result");
|
||||||
|
|
||||||
|
// symlink at ./result (like `nix build`)
|
||||||
|
std::os::unix::fs::symlink(HELLO_PATH, &link_path).unwrap();
|
||||||
|
|
||||||
|
// should resolve symlink
|
||||||
|
let path_info = PathInfo::from_derivation(&link_path, &ctx.store)
|
||||||
|
.await
|
||||||
|
.expect("get pathinfo from package");
|
||||||
|
assert_eq!(path_info.path.to_absolute_path(), HELLO_DRV);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn closure_includes_nix_store_requisites() {
|
||||||
let ctx = common::context();
|
let ctx = common::context();
|
||||||
let path = PathBuf::from(HELLO);
|
let path = PathBuf::from(HELLO);
|
||||||
let path_info = PathInfo::from_derivation(&path, &ctx.store)
|
let path_info = PathInfo::from_derivation(&path, &ctx.store)
|
||||||
.await
|
.await
|
||||||
.expect("get pathinfo from package");
|
.expect("get pathinfo from package");
|
||||||
let closure = path_info.get_closure(&ctx.store).await.unwrap();
|
|
||||||
assert_eq!(closure.len(), 472);
|
// get what we think is the closure
|
||||||
|
let mut closure: HashSet<String> = path_info
|
||||||
|
.get_closure(&ctx.store)
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
.iter()
|
||||||
|
.map(|x| x.path.to_absolute_path())
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
// for a somewhat more complicated case
|
||||||
|
common::ensure_exists(NIXCP_PKG);
|
||||||
|
let path = PathBuf::from(NIXCP_PKG);
|
||||||
|
let path_info = PathInfo::from_derivation(&path, &ctx.store)
|
||||||
|
.await
|
||||||
|
.expect("get pathinfo from package");
|
||||||
|
closure.extend(
|
||||||
|
path_info
|
||||||
|
.get_closure(&ctx.store)
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
.iter()
|
||||||
|
.map(|x| x.path.to_absolute_path()),
|
||||||
|
);
|
||||||
|
|
||||||
|
// get output of `nix-store --query --requisites --include-outputs`
|
||||||
|
let nix_store_out = Command::new("nix-store")
|
||||||
|
.arg("--query")
|
||||||
|
.arg("--requisites")
|
||||||
|
.arg("--include-outputs")
|
||||||
|
.arg(HELLO_DRV)
|
||||||
|
.arg(NIXCP_DRV)
|
||||||
|
.output()
|
||||||
|
.unwrap()
|
||||||
|
.stdout;
|
||||||
|
assert!(!nix_store_out.is_empty());
|
||||||
|
let ref_closure = String::from_utf8_lossy(&nix_store_out);
|
||||||
|
let ref_closure = ref_closure.split_whitespace();
|
||||||
|
|
||||||
|
// check that we didn't miss anything nix-store would catch
|
||||||
|
for path in ref_closure {
|
||||||
|
assert!(closure.contains(path));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue