Compare commits
24 commits
Author | SHA1 | Date | |
---|---|---|---|
|
b60bbc162f | ||
|
85a6d6cc9a | ||
|
cb34302e17 | ||
|
8c271f669a | ||
|
e949478754 | ||
|
419976d275 | ||
|
6efdad5e66 | ||
|
19fa28545f | ||
|
0a7cf9f016 | ||
|
bef974eda7 | ||
|
f68cbc2f5a | ||
|
4be508a330 | ||
|
c7da345cf4 | ||
|
701c86d650 | ||
|
beef106b41 | ||
|
5922220498 | ||
|
149d353019 | ||
|
b69542d9a6 | ||
|
b05095ff35 | ||
|
0863eae4b4 | ||
|
133584c1e6 | ||
|
747e481bcb | ||
|
7db9d3a2e1 | ||
|
c7f6b2c256 |
14 changed files with 329 additions and 284 deletions
|
@ -5,7 +5,7 @@
|
|||
{
|
||||
projectRootFile = "Cargo.toml";
|
||||
programs = {
|
||||
nixpkgs-fmt.enable = true; # nix
|
||||
nixfmt.enable = true; # nix
|
||||
statix.enable = true; # nix static analysis
|
||||
deadnix.enable = true; # find dead nix code
|
||||
rustfmt.enable = true; # rust
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
#
|
||||
# SPDX-License-Identifier: EUPL-1.2
|
||||
|
||||
name: Conventional Commits
|
||||
name: conventional commits
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
|
@ -12,9 +12,9 @@ concurrency:
|
|||
group: ${{ github.workflow }}-${{ github.event_name == 'pull_request' && github.head_ref || github.sha }}
|
||||
cancel-in-progress: true
|
||||
jobs:
|
||||
build:
|
||||
name: Conventional Commits
|
||||
check:
|
||||
name: conventional commits
|
||||
runs-on: native
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: https://github.com/webiny/action-conventional-commits@v1.3.0
|
||||
- uses: actions/action-conventional-commits@v1.3.0
|
||||
|
|
|
@ -2,18 +2,16 @@
|
|||
#
|
||||
# SPDX-License-Identifier: EUPL-1.2
|
||||
|
||||
name: Security audit
|
||||
name: build
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 0 * * *'
|
||||
push:
|
||||
branches: [main]
|
||||
pull_request:
|
||||
branches: [main]
|
||||
jobs:
|
||||
security_audit:
|
||||
run:
|
||||
runs-on: native
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Scan for vulnerabilities
|
||||
run: nix develop --accept-flake-config --command cargo deny check
|
||||
- name: build flake
|
||||
run: nix build
|
17
.forgejo/workflows/nix-flake-check.yml
Normal file
17
.forgejo/workflows/nix-flake-check.yml
Normal file
|
@ -0,0 +1,17 @@
|
|||
# SPDX-FileCopyrightText: 2024 Christina Sørensen
|
||||
#
|
||||
# SPDX-License-Identifier: EUPL-1.2
|
||||
|
||||
name: check
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
pull_request:
|
||||
branches: [main]
|
||||
jobs:
|
||||
run:
|
||||
runs-on: native
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: flake checks
|
||||
run: nix flake check
|
5
.rustfmt.toml
Normal file
5
.rustfmt.toml
Normal file
|
@ -0,0 +1,5 @@
|
|||
# SPDX-FileCopyrightText: 2024 Christina Sørensen
|
||||
#
|
||||
# SPDX-License-Identifier: EUPL-1.2
|
||||
|
||||
tab_spaces = 2
|
4
Cargo.lock
generated
4
Cargo.lock
generated
|
@ -304,7 +304,7 @@ checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0"
|
|||
|
||||
[[package]]
|
||||
name = "common"
|
||||
version = "0.0.2"
|
||||
version = "0.0.4"
|
||||
dependencies = [
|
||||
"workspace-hack",
|
||||
]
|
||||
|
@ -1109,7 +1109,7 @@ checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086"
|
|||
|
||||
[[package]]
|
||||
name = "nix-weather"
|
||||
version = "0.0.2"
|
||||
version = "0.0.4"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"clap_complete",
|
||||
|
|
10
Cargo.toml
10
Cargo.toml
|
@ -8,13 +8,19 @@ members = ["crates/*", "crates/workspace-hack"]
|
|||
|
||||
[workspace.package]
|
||||
description = "Guix weather, for nix!"
|
||||
version = "0.0.2"
|
||||
version = "0.0.4"
|
||||
edition = "2021"
|
||||
rust-version = "1.81"
|
||||
license = "EUPL-1.2"
|
||||
authors = ["Christina Sørensen <christina@cafkafk.com>"]
|
||||
categories = ["command-line-utilities"]
|
||||
|
||||
# Keep this on anything that isn't EOL, we'll be nice to nixpkgs as long as
|
||||
# they don't literally actually unironically lock all our deps for us or go on
|
||||
# EOL rustc >_>
|
||||
#
|
||||
# ...also if we wanna play with bench we can probably cfg gate that :p
|
||||
rust-version = "1.80.1"
|
||||
|
||||
[workspace.metadata.crane]
|
||||
name = "nix-weather"
|
||||
|
||||
|
|
|
@ -14,30 +14,33 @@ use std::path::PathBuf;
|
|||
include!("src/cli.rs");
|
||||
|
||||
fn main() -> Result<(), Error> {
|
||||
let real_outdir = match env::var_os("OUT_DIR") {
|
||||
None => return Ok(()),
|
||||
Some(outdir) => outdir,
|
||||
};
|
||||
let real_outdir = match env::var_os("OUT_DIR") {
|
||||
None => return Ok(()),
|
||||
Some(outdir) => outdir,
|
||||
};
|
||||
|
||||
let outdir = match env::var_os("MAN_OUT") {
|
||||
None => real_outdir,
|
||||
Some(outdir) => outdir,
|
||||
};
|
||||
let outdir = match env::var_os("MAN_OUT") {
|
||||
None => real_outdir,
|
||||
Some(outdir) => outdir,
|
||||
};
|
||||
|
||||
let mut cmd = build_cli();
|
||||
for &shell in Shell::value_variants() {
|
||||
// HACK: this is gross :(
|
||||
let output = std::process::Command::new("mkdir").arg("man").output();
|
||||
let mut cmd = build_cli();
|
||||
for &shell in Shell::value_variants() {
|
||||
// HACK: this is gross :(
|
||||
std::process::Command::new("mkdir")
|
||||
.arg("man")
|
||||
.output()
|
||||
.expect("failed to make man directory");
|
||||
|
||||
generate_to(shell, &mut cmd, "nix-weather", &outdir)?;
|
||||
}
|
||||
generate_to(shell, &mut cmd, "nix-weather", &outdir)?;
|
||||
}
|
||||
|
||||
let file = PathBuf::from(&outdir).join("nix-weather.1");
|
||||
let mut file = File::create(file)?;
|
||||
let file = PathBuf::from(&outdir).join("nix-weather.1");
|
||||
let mut file = File::create(file)?;
|
||||
|
||||
Man::new(cmd).render(&mut file)?;
|
||||
Man::new(cmd).render(&mut file)?;
|
||||
|
||||
println!("cargo:warning=completion file is generated: {outdir:?}");
|
||||
println!("cargo:warning=completion file is generated: {outdir:?}");
|
||||
|
||||
Ok(())
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -3,36 +3,39 @@
|
|||
//
|
||||
// SPDX-License-Identifier: EUPL-1.2
|
||||
|
||||
use std::{cell::OnceCell, sync::OnceLock};
|
||||
|
||||
use clap::{arg, command, crate_authors, value_parser, Arg, ArgAction, Command};
|
||||
use clap::{arg, command, crate_authors, value_parser, ArgAction, Command};
|
||||
|
||||
const DEFAULT_CACHE: &str = "cache.nixos.org";
|
||||
|
||||
pub fn build_cli() -> Command {
|
||||
use std::path::PathBuf;
|
||||
|
||||
command!()
|
||||
.author(crate_authors!("\n"))
|
||||
.arg(
|
||||
arg!(--cache <CACHE> "check a specific cache")
|
||||
.required(false)
|
||||
.default_value(DEFAULT_CACHE),
|
||||
)
|
||||
.arg(
|
||||
arg!(-n --name <HOST> "Hostname of machine.")
|
||||
.required(false)
|
||||
.value_parser(value_parser!(String)),
|
||||
)
|
||||
.arg(
|
||||
arg!(-c --config <FILE> "Path to NixOS config.")
|
||||
.required(false)
|
||||
.value_parser(value_parser!(String)),
|
||||
)
|
||||
.arg(
|
||||
arg!(--timestamp "Add timestamp to log output.")
|
||||
.action(ArgAction::SetTrue)
|
||||
.required(false),
|
||||
)
|
||||
.arg(arg!(-v --verbose ... "Verbosity level."))
|
||||
command!()
|
||||
.author(crate_authors!("\n"))
|
||||
// TODO: parse multiple installables, like e.g. build does?
|
||||
.arg(arg!([installable] "A nix installable").required(false))
|
||||
.arg(
|
||||
arg!(--cache <CACHE> "Check a specific cache")
|
||||
.required(false)
|
||||
.default_value(DEFAULT_CACHE),
|
||||
)
|
||||
.arg(
|
||||
arg!(-n --name <HOST> "Hostname of machine.")
|
||||
.required(false)
|
||||
.value_parser(value_parser!(String)),
|
||||
)
|
||||
.arg(
|
||||
arg!(-c --config <FILE> "Path to NixOS config.")
|
||||
.required(false)
|
||||
.value_parser(value_parser!(String)),
|
||||
)
|
||||
.arg(
|
||||
arg!(--timestamp "Add timestamp to log output.")
|
||||
.action(ArgAction::SetTrue)
|
||||
.required(false),
|
||||
)
|
||||
.arg(arg!(-v --verbose ... "Verbosity level."))
|
||||
.arg(
|
||||
arg!(printBuildLogs: -L "Verbosity level.")
|
||||
.long("print-build-logs")
|
||||
.conflicts_with("verbose"),
|
||||
)
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
//
|
||||
// SPDX-License-Identifier: EUPL-1.2
|
||||
|
||||
use std::time::{Duration, Instant};
|
||||
use std::time::Instant;
|
||||
use std::{env, io, net::SocketAddr};
|
||||
|
||||
use dns_lookup::lookup_host;
|
||||
|
@ -11,8 +11,6 @@ use futures::future::join_all;
|
|||
use gethostname::gethostname;
|
||||
use itertools::Itertools;
|
||||
|
||||
use log;
|
||||
|
||||
use crate::nix::get_requisites;
|
||||
|
||||
mod cli;
|
||||
|
@ -27,123 +25,134 @@ const DEFAULT_CONFIG_DIR: &str = "/etc/nixos";
|
|||
|
||||
#[tokio::main(flavor = "multi_thread")]
|
||||
async fn main() -> io::Result<()> {
|
||||
let initial_time = Instant::now();
|
||||
let initial_time = Instant::now();
|
||||
|
||||
let host_name: String;
|
||||
let cache_url: String;
|
||||
let config_dir: String;
|
||||
let host_name: String;
|
||||
let cache_url: String;
|
||||
let config_dir: String;
|
||||
|
||||
let matches = cli::build_cli().get_matches();
|
||||
let matches = cli::build_cli().get_matches();
|
||||
|
||||
/// If the users inputs more -v flags than we have log levels, send them a
|
||||
/// message informing them.
|
||||
let mut very_bose = false;
|
||||
// If the users inputs more -v flags than we have log levels, send them a
|
||||
// message informing them.
|
||||
let mut very_bose = false;
|
||||
|
||||
match matches
|
||||
.get_one::<u8>("verbose")
|
||||
.expect("Counts aren't defaulted")
|
||||
{
|
||||
0 => env::set_var("RUST_LOG", "error"),
|
||||
1 => env::set_var("RUST_LOG", "warn"),
|
||||
2 => env::set_var("RUST_LOG", "info"),
|
||||
3 => env::set_var("RUST_LOG", "debug"),
|
||||
4 => env::set_var("RUST_LOG", "trace"),
|
||||
_ => {
|
||||
very_bose = true;
|
||||
env::set_var("RUST_LOG", "trace")
|
||||
}
|
||||
// The Normal verbose flag, allowing multiple levels. Conflicts with
|
||||
// printBuildLogs.
|
||||
match matches
|
||||
.get_one::<u8>("verbose")
|
||||
.expect("Counts aren't defaulted")
|
||||
{
|
||||
0 => env::set_var("RUST_LOG", "error"),
|
||||
1 => env::set_var("RUST_LOG", "warn"),
|
||||
2 => env::set_var("RUST_LOG", "info"),
|
||||
3 => env::set_var("RUST_LOG", "debug"),
|
||||
4 => env::set_var("RUST_LOG", "trace"),
|
||||
_ => {
|
||||
very_bose = true;
|
||||
env::set_var("RUST_LOG", "trace")
|
||||
}
|
||||
}
|
||||
|
||||
if matches.get_flag("timestamp") {
|
||||
pretty_env_logger::formatted_timed_builder()
|
||||
.parse_env("RUST_LOG")
|
||||
.init();
|
||||
} else {
|
||||
pretty_env_logger::formatted_builder()
|
||||
.parse_env("RUST_LOG")
|
||||
.init();
|
||||
}
|
||||
// The -L flag, to give a more nix3 feel
|
||||
if matches.get_flag("printBuildLogs") {
|
||||
env::set_var("RUST_LOG", "trace")
|
||||
}
|
||||
|
||||
if very_bose {
|
||||
log::trace!("More than four -v flags don't increase log level.");
|
||||
}
|
||||
if matches.get_flag("timestamp") {
|
||||
pretty_env_logger::formatted_timed_builder()
|
||||
.parse_env("RUST_LOG")
|
||||
.init();
|
||||
} else {
|
||||
pretty_env_logger::formatted_builder()
|
||||
.parse_env("RUST_LOG")
|
||||
.init();
|
||||
}
|
||||
|
||||
if let Some(name) = matches.get_one::<String>("name") {
|
||||
host_name = name.to_owned();
|
||||
} else {
|
||||
host_name = gethostname().into_string().unwrap();
|
||||
}
|
||||
if very_bose {
|
||||
log::trace!("More than four -v flags don't increase log level.");
|
||||
}
|
||||
|
||||
if let Some(cache) = matches.get_one::<String>("cache") {
|
||||
cache_url = cache.to_owned();
|
||||
} else {
|
||||
cache_url = DEFAULT_CACHE.to_string();
|
||||
}
|
||||
if let Some(name) = matches.get_one::<String>("name") {
|
||||
host_name = name.to_owned();
|
||||
} else {
|
||||
host_name = gethostname().into_string().unwrap();
|
||||
}
|
||||
|
||||
if let Some(config) = matches.get_one::<String>("config") {
|
||||
config_dir = config.to_owned();
|
||||
} else {
|
||||
config_dir = DEFAULT_CONFIG_DIR.to_string();
|
||||
}
|
||||
if let Some(cache) = matches.get_one::<String>("cache") {
|
||||
cache_url = cache.to_owned();
|
||||
} else {
|
||||
cache_url = DEFAULT_CACHE.to_string();
|
||||
}
|
||||
|
||||
let domain = cache_url.to_owned();
|
||||
let ips: Vec<std::net::IpAddr> = lookup_host(&domain).unwrap();
|
||||
if let Some(config) = matches.get_one::<String>("config") {
|
||||
config_dir = config.to_owned();
|
||||
} else {
|
||||
config_dir = DEFAULT_CONFIG_DIR.to_string();
|
||||
}
|
||||
|
||||
log::debug!("{:#?}", &ips);
|
||||
let domain = cache_url.to_owned();
|
||||
let ips: Vec<std::net::IpAddr> = lookup_host(&domain).unwrap();
|
||||
|
||||
let domain_addr = SocketAddr::new(ips[0], 443);
|
||||
log::debug!("{:#?}", &ips);
|
||||
|
||||
let client = reqwest::Client::builder()
|
||||
.resolve(&domain, domain_addr)
|
||||
.build()
|
||||
.unwrap();
|
||||
let domain_addr = SocketAddr::new(ips[0], 443);
|
||||
|
||||
let binding = get_requisites(&host_name, &config_dir);
|
||||
let client = reqwest::Client::builder()
|
||||
.resolve(&domain, domain_addr)
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
let get_requisites_duration = initial_time.elapsed().as_secs();
|
||||
let binding = get_requisites(
|
||||
&host_name,
|
||||
&config_dir,
|
||||
matches.get_one::<String>("installable").cloned(),
|
||||
);
|
||||
|
||||
println!(
|
||||
"Found Nix Requisites in {} seconds",
|
||||
get_requisites_duration
|
||||
);
|
||||
let get_requisites_duration = initial_time.elapsed().as_secs();
|
||||
|
||||
let network_time = Instant::now();
|
||||
println!(
|
||||
"Found Nix Requisites in {} seconds",
|
||||
get_requisites_duration
|
||||
);
|
||||
|
||||
let lines = binding
|
||||
.lines()
|
||||
.map(|line| line.to_owned())
|
||||
.collect::<Vec<_>>();
|
||||
let network_time = Instant::now();
|
||||
|
||||
let count = lines.len();
|
||||
let lines = binding
|
||||
.lines()
|
||||
.map(|line| line.to_owned())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let tasks = lines
|
||||
.into_iter()
|
||||
.map(|hash| {
|
||||
let client = client.clone();
|
||||
let domain = domain.clone();
|
||||
tokio::spawn(async move {
|
||||
log::trace!("connecting to {domain} {domain_addr:#?} for {hash}");
|
||||
net::nar_exists(client, &domain, &hash, SLIDE).await
|
||||
})
|
||||
})
|
||||
.collect_vec();
|
||||
let count = lines.len();
|
||||
|
||||
let sum: usize = join_all(tasks)
|
||||
.await
|
||||
.into_iter()
|
||||
.map(|result| result.unwrap())
|
||||
.sum();
|
||||
let tasks = lines
|
||||
.into_iter()
|
||||
.map(|hash| {
|
||||
let client = client.clone();
|
||||
let domain = domain.clone();
|
||||
tokio::spawn(async move {
|
||||
log::trace!("connecting to {domain} {domain_addr:#?} for {hash}");
|
||||
net::nar_exists(client, &domain, &hash, SLIDE).await
|
||||
})
|
||||
})
|
||||
.collect_vec();
|
||||
|
||||
println!(
|
||||
"Checked {count} packages in {} seconds",
|
||||
network_time.elapsed().as_secs()
|
||||
);
|
||||
println!(
|
||||
"Found {:#?}/{} ({:.2}%) in cache",
|
||||
sum,
|
||||
count,
|
||||
(sum as f64 / count as f64) * 100.
|
||||
);
|
||||
let sum: usize = join_all(tasks)
|
||||
.await
|
||||
.into_iter()
|
||||
.map(|result| result.unwrap())
|
||||
.sum();
|
||||
|
||||
Ok(())
|
||||
println!(
|
||||
"Checked {count} packages in {} seconds",
|
||||
network_time.elapsed().as_secs()
|
||||
);
|
||||
println!(
|
||||
"Found {:#?}/{} ({:.2}%) in cache",
|
||||
sum,
|
||||
count,
|
||||
(sum as f64 / count as f64) * 100.
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -8,33 +8,31 @@ use std::time::Duration;
|
|||
use reqwest::Client;
|
||||
use tokio::time::sleep;
|
||||
|
||||
use log;
|
||||
|
||||
const MAX_SLIDE: u64 = 1000;
|
||||
|
||||
pub async fn nar_exists(client: Client, domain: &str, hash: &str, slide: u64) -> usize {
|
||||
let response = client
|
||||
.head(format!("https://{domain}/{hash}.narinfo"))
|
||||
.send()
|
||||
.await;
|
||||
let response = client
|
||||
.head(format!("https://{domain}/{hash}.narinfo"))
|
||||
.send()
|
||||
.await;
|
||||
|
||||
match response {
|
||||
Ok(response) if response.status().as_u16() == 200 => 1,
|
||||
Ok(response) if response.status().as_u16() == 404 => 0,
|
||||
_ => {
|
||||
// We're so fast now we get rate limited.
|
||||
//
|
||||
// Writng an actual sliding window seems kinda hard,
|
||||
// so we do this instead.
|
||||
log::trace!("rate limited! {slide}");
|
||||
sleep(Duration::from_millis(slide)).await;
|
||||
Box::pin(nar_exists(
|
||||
client,
|
||||
domain,
|
||||
hash,
|
||||
std::cmp::min(slide * 2, MAX_SLIDE),
|
||||
))
|
||||
.await
|
||||
}
|
||||
match response {
|
||||
Ok(response) if response.status().as_u16() == 200 => 1,
|
||||
Ok(response) if response.status().as_u16() == 404 => 0,
|
||||
_ => {
|
||||
// We're so fast now we get rate limited.
|
||||
//
|
||||
// Writng an actual sliding window seems kinda hard,
|
||||
// so we do this instead.
|
||||
log::trace!("rate limited! {slide}");
|
||||
sleep(Duration::from_millis(slide)).await;
|
||||
Box::pin(nar_exists(
|
||||
client,
|
||||
domain,
|
||||
hash,
|
||||
std::cmp::min(slide * 2, MAX_SLIDE),
|
||||
))
|
||||
.await
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,53 +5,89 @@
|
|||
|
||||
use serde_json::Value;
|
||||
use std::{
|
||||
path::Path,
|
||||
process::{Command, Stdio},
|
||||
path::Path,
|
||||
process::{Command, Stdio},
|
||||
};
|
||||
|
||||
pub fn get_requisites(host: &str, config_dir: &str) -> String {
|
||||
let get_drv_path = Command::new("nix")
|
||||
.current_dir(Path::new(config_dir))
|
||||
.args([
|
||||
"build",
|
||||
"--impure",
|
||||
"--quiet",
|
||||
&format!(
|
||||
"./#nixosConfigurations.{}.config.system.build.toplevel",
|
||||
host
|
||||
),
|
||||
"--dry-run",
|
||||
"--json",
|
||||
"--option",
|
||||
"eval-cache",
|
||||
"true",
|
||||
])
|
||||
.output()
|
||||
.unwrap();
|
||||
|
||||
let drv_path_json: Value =
|
||||
serde_json::from_str(&String::from_utf8(get_drv_path.stdout).unwrap()).unwrap();
|
||||
let drv_path = drv_path_json[0]["drvPath"].clone();
|
||||
|
||||
log::debug!("drv_path: {}", &drv_path);
|
||||
|
||||
let get_drv_requisites = Command::new("nix-store")
|
||||
.args(["--query", "--requisites", drv_path.as_str().unwrap()])
|
||||
.stdout(Stdio::piped())
|
||||
.spawn()
|
||||
.unwrap();
|
||||
let drv_requisites_remove_base = Command::new("cut")
|
||||
.args(["-d", "/", "-f4"])
|
||||
.stdin(Stdio::from(get_drv_requisites.stdout.unwrap()))
|
||||
.stdout(Stdio::piped())
|
||||
.spawn()
|
||||
.unwrap();
|
||||
let drv_requisites_to_hash = Command::new("cut")
|
||||
.args(["-d", "-", "-f1"])
|
||||
.stdin(Stdio::from(drv_requisites_remove_base.stdout.unwrap()))
|
||||
.stdout(Stdio::piped())
|
||||
.spawn()
|
||||
.unwrap();
|
||||
|
||||
String::from_utf8(drv_requisites_to_hash.wait_with_output().unwrap().stdout).unwrap()
|
||||
/// Get nixosConfiguration derivation path
|
||||
#[inline]
|
||||
fn get_config_drv_path(host: &str, config_dir: &str) -> std::io::Result<std::process::Output> {
|
||||
Command::new("nix")
|
||||
.current_dir(Path::new(config_dir))
|
||||
.args([
|
||||
"build",
|
||||
"--quiet",
|
||||
&format!(
|
||||
"./#nixosConfigurations.{}.config.system.build.toplevel",
|
||||
host
|
||||
),
|
||||
"--dry-run",
|
||||
"--json",
|
||||
])
|
||||
.output()
|
||||
}
|
||||
|
||||
/// Get installable derivation path
|
||||
#[inline]
|
||||
fn get_installable_drv_path(installable: &str) -> std::io::Result<std::process::Output> {
|
||||
Command::new("nix")
|
||||
.args(["build", "--quiet", installable, "--dry-run", "--json"])
|
||||
.output()
|
||||
}
|
||||
|
||||
/// Takes a drv_path and gets all it's requisites from the nix store.
|
||||
#[inline]
|
||||
fn get_requisites_from_drv_path(drv_path: &str) -> std::io::Result<std::process::Child> {
|
||||
Command::new("nix-store")
|
||||
.args(["--query", "--requisites", drv_path])
|
||||
.stdout(Stdio::piped())
|
||||
.spawn()
|
||||
}
|
||||
|
||||
/// Turns requisites into hashes
|
||||
#[inline]
|
||||
fn requisites_to_hashes(
|
||||
drv_requisites: std::process::Child,
|
||||
) -> std::io::Result<std::process::Child> {
|
||||
let drv_requisites_remove_base = Command::new("cut")
|
||||
.args(["-d", "/", "-f4"])
|
||||
.stdin(Stdio::from(drv_requisites.stdout.unwrap()))
|
||||
.stdout(Stdio::piped())
|
||||
.spawn()
|
||||
.unwrap();
|
||||
Command::new("cut")
|
||||
.args(["-d", "-", "-f1"])
|
||||
.stdin(Stdio::from(drv_requisites_remove_base.stdout.unwrap()))
|
||||
.stdout(Stdio::piped())
|
||||
.spawn()
|
||||
}
|
||||
|
||||
pub fn get_requisites(host: &str, config_dir: &str, installable: Option<String>) -> String {
|
||||
// If the users specified an installable, we interpret that, instead of trying
|
||||
// to guess their config location.
|
||||
let drv_path;
|
||||
if let Some(installable) = installable {
|
||||
drv_path = get_installable_drv_path(&installable).unwrap();
|
||||
} else {
|
||||
drv_path = get_config_drv_path(host, config_dir).unwrap();
|
||||
}
|
||||
|
||||
let drv_path_json: Value =
|
||||
serde_json::from_str(&String::from_utf8(drv_path.stdout).unwrap()).unwrap();
|
||||
let drv_path = drv_path_json[0]["drvPath"].clone();
|
||||
|
||||
log::debug!("drv_path: {}", &drv_path);
|
||||
|
||||
let drv_requisites = get_requisites_from_drv_path(drv_path.as_str().unwrap()).unwrap();
|
||||
|
||||
let drv_requisite_hashes = requisites_to_hashes(drv_requisites);
|
||||
|
||||
String::from_utf8(
|
||||
drv_requisite_hashes
|
||||
.unwrap()
|
||||
.wait_with_output()
|
||||
.unwrap()
|
||||
.stdout,
|
||||
)
|
||||
.unwrap()
|
||||
}
|
||||
|
|
|
@ -7,4 +7,4 @@ multiple-versions = 'allow'
|
|||
|
||||
[licenses]
|
||||
private = { ignore = true }
|
||||
allow = ["MIT", "ISC", "MPL-2.0", "Apache-2.0", "Unicode-DFS-2016", "BSD-3-Clause"]
|
||||
allow = ["MIT", "ISC", "MPL-2.0", "Apache-2.0", "Unicode-DFS-2016", "BSD-3-Clause", "EUPL-1.2"]
|
||||
|
|
74
flake.nix
74
flake.nix
|
@ -3,7 +3,7 @@
|
|||
# SPDX-License-Identifier: EUPL-1.2
|
||||
|
||||
{
|
||||
description = "Nix Weather - Check Cache Availablility of NixOS Configurations";
|
||||
description = "Nix Weather - Check Cache Availability of NixOS Configurations";
|
||||
|
||||
inputs = {
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
|
||||
|
@ -13,10 +13,7 @@
|
|||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
|
||||
crane = {
|
||||
url = "github:ipetkov/crane";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
crane.url = "github:ipetkov/crane";
|
||||
|
||||
fenix = {
|
||||
url = "github:nix-community/fenix";
|
||||
|
@ -85,9 +82,7 @@
|
|||
let
|
||||
overlays = [ (import rust-overlay) ];
|
||||
|
||||
pkgs = (import nixpkgs) {
|
||||
inherit system overlays;
|
||||
};
|
||||
pkgs = (import nixpkgs) { inherit system overlays; };
|
||||
|
||||
inherit (pkgs) lib;
|
||||
|
||||
|
@ -101,9 +96,7 @@
|
|||
inherit src;
|
||||
strictDeps = true;
|
||||
|
||||
nativeBuildInputs = [
|
||||
pkgs.pkg-config
|
||||
];
|
||||
nativeBuildInputs = [ pkgs.pkg-config ];
|
||||
|
||||
buildInputs =
|
||||
[
|
||||
|
@ -113,6 +106,8 @@
|
|||
++ lib.optionals pkgs.stdenv.isDarwin [
|
||||
# Additional darwin specific inputs can be set here
|
||||
pkgs.libiconv
|
||||
pkgs.darwin.apple_sdk.frameworks.Security
|
||||
pkgs.darwin.apple_sdk.frameworks.SystemConfiguration
|
||||
];
|
||||
|
||||
# Additional environment variables can be set directly
|
||||
|
@ -205,27 +200,16 @@
|
|||
}
|
||||
);
|
||||
|
||||
cargo-workspace-doc = craneLib.cargoDoc (
|
||||
commonArgs
|
||||
// {
|
||||
inherit cargoArtifacts;
|
||||
}
|
||||
);
|
||||
cargo-workspace-doc = craneLib.cargoDoc (commonArgs // { inherit cargoArtifacts; });
|
||||
|
||||
# Check formatting
|
||||
cargo-workspace-fmt = craneLib.cargoFmt {
|
||||
inherit src;
|
||||
};
|
||||
cargo-workspace-fmt = craneLib.cargoFmt { inherit src; };
|
||||
|
||||
# Audit dependencies
|
||||
cargo-workspace-audit = craneLib.cargoAudit {
|
||||
inherit src advisory-db;
|
||||
};
|
||||
cargo-workspace-audit = craneLib.cargoAudit { inherit src advisory-db; };
|
||||
|
||||
# Audit licenses
|
||||
cargo-workspace-deny = craneLib.cargoDeny {
|
||||
inherit src;
|
||||
};
|
||||
cargo-workspace-deny = craneLib.cargoDeny { inherit src; };
|
||||
|
||||
# Run tests with cargo-nextest
|
||||
# Consider setting `doCheck = false` on other crate derivations
|
||||
|
@ -252,14 +236,15 @@
|
|||
cargo hakari verify
|
||||
'';
|
||||
|
||||
nativeBuildInputs = [
|
||||
pkgs.cargo-hakari
|
||||
];
|
||||
nativeBuildInputs = [ pkgs.cargo-hakari ];
|
||||
};
|
||||
pre-commit-check =
|
||||
let
|
||||
# some treefmt formatters are not supported in pre-commit-hooks we filter them out for now.
|
||||
toFilter = [ "yamlfmt" ];
|
||||
toFilter = [
|
||||
"yamlfmt"
|
||||
"nixfmt"
|
||||
];
|
||||
filterFn = n: _v: (!builtins.elem n toFilter);
|
||||
treefmtFormatters = pkgs.lib.mapAttrs (_n: v: { inherit (v) enable; }) (
|
||||
pkgs.lib.filterAttrs filterFn (import ./.config/treefmt.nix).programs
|
||||
|
@ -268,11 +253,14 @@
|
|||
pre-commit-hooks.lib.${system}.run {
|
||||
src = ./.;
|
||||
hooks = treefmtFormatters // {
|
||||
convco.enable = true; # not in treefmt
|
||||
# not in treefmt
|
||||
convco.enable = true;
|
||||
# named nixfmt in treefmt (which defaults to nixfmt-classic for pre-commit-hooks)
|
||||
nixfmt-rfc-style.enable = true;
|
||||
reuse = {
|
||||
enable = true;
|
||||
name = "reuse";
|
||||
entry = with pkgs; "${pkgs.reuse}/bin/reuse lint";
|
||||
entry = with pkgs; "${reuse}/bin/reuse lint";
|
||||
pass_filenames = false;
|
||||
};
|
||||
};
|
||||
|
@ -287,17 +275,12 @@
|
|||
}
|
||||
// lib.optionalAttrs (!pkgs.stdenv.isDarwin) {
|
||||
cargo-workspace-llvm-coverage = craneLibLLvmTools.cargoLlvmCov (
|
||||
commonArgs
|
||||
// {
|
||||
inherit cargoArtifacts;
|
||||
}
|
||||
commonArgs // { inherit cargoArtifacts; }
|
||||
);
|
||||
};
|
||||
|
||||
apps = {
|
||||
nix-weather = flake-utils.lib.mkApp {
|
||||
drv = nix-weather;
|
||||
};
|
||||
nix-weather = flake-utils.lib.mkApp { drv = nix-weather; };
|
||||
};
|
||||
|
||||
# For `nix develop`:
|
||||
|
@ -332,16 +315,3 @@
|
|||
];
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue