Add group reports for flake-group check (#436)
* `nix flake {info -> metadata}` * Fix error variant for io errors * Enable backtrace support for anyhow * Improve error printing * Write error report file * Format workflow file * Use report file * Set non-zero exit status if a group fails * Do not use `local` * Apply suggestions from review * Move exit outside the loop * Fix multi line output * Fix var substitution * Different work around for multi lines
This commit is contained in:
parent
d098ad2acb
commit
33da3a4a0c
28
.github/workflows/check-flake-files.yml
vendored
28
.github/workflows/check-flake-files.yml
vendored
|
@ -4,11 +4,10 @@ on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
pull_request:
|
pull_request:
|
||||||
paths:
|
paths:
|
||||||
- 'flakes/**.toml'
|
- "flakes/**.toml"
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
automatic-custom-flakes-check:
|
automatic-custom-flakes-check:
|
||||||
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
strategy:
|
strategy:
|
||||||
|
@ -34,7 +33,30 @@ jobs:
|
||||||
- name: Try importing all custom flakes
|
- name: Try importing all custom flakes
|
||||||
run: |
|
run: |
|
||||||
shopt -s globstar
|
shopt -s globstar
|
||||||
|
|
||||||
|
had_error=0
|
||||||
|
|
||||||
for flake_group in flakes/**/*.toml
|
for flake_group in flakes/**/*.toml
|
||||||
do
|
do
|
||||||
./result/bin/flake-info group "$flake_group" "$(basename "$flake_group" .toml)"
|
echo "::group::Group \"$(basename $flake_group .toml)\""
|
||||||
|
|
||||||
|
./result/bin/flake-info group "$flake_group" "$(basename "$flake_group" .toml)" --report
|
||||||
|
|
||||||
|
if [[ -f "./report.txt" ]]
|
||||||
|
then
|
||||||
|
had_error=1
|
||||||
|
|
||||||
|
# sic.:
|
||||||
|
# Workaround for multi line output
|
||||||
|
report="$(< ./report.txt)"
|
||||||
|
report="${report//'%'/'%25'}"
|
||||||
|
report="${report//$'\n'/'%0A'}"
|
||||||
|
report="${report//$'\r'/'%0D'}"
|
||||||
|
|
||||||
|
echo "::error file=$flake_group::$report"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ::endgroup::
|
||||||
|
|
||||||
done
|
done
|
||||||
|
exit $had_error
|
||||||
|
|
48
flake-info/Cargo.lock
generated
48
flake-info/Cargo.lock
generated
|
@ -2,6 +2,15 @@
|
||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
version = 3
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "addr2line"
|
||||||
|
version = "0.17.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b"
|
||||||
|
dependencies = [
|
||||||
|
"gimli",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "adler"
|
name = "adler"
|
||||||
version = "1.0.2"
|
version = "1.0.2"
|
||||||
|
@ -31,6 +40,9 @@ name = "anyhow"
|
||||||
version = "1.0.43"
|
version = "1.0.43"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "28ae2b3dec75a406790005a200b1bd89785afc02517a00ca99ecfe093ee9e6cf"
|
checksum = "28ae2b3dec75a406790005a200b1bd89785afc02517a00ca99ecfe093ee9e6cf"
|
||||||
|
dependencies = [
|
||||||
|
"backtrace",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "async-compression"
|
name = "async-compression"
|
||||||
|
@ -62,6 +74,21 @@ version = "1.0.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
|
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "backtrace"
|
||||||
|
version = "0.3.63"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "321629d8ba6513061f26707241fa9bc89524ff1cd7a915a97ef0c62c666ce1b6"
|
||||||
|
dependencies = [
|
||||||
|
"addr2line",
|
||||||
|
"cc",
|
||||||
|
"cfg-if",
|
||||||
|
"libc",
|
||||||
|
"miniz_oxide",
|
||||||
|
"object",
|
||||||
|
"rustc-demangle",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "base64"
|
name = "base64"
|
||||||
version = "0.11.0"
|
version = "0.11.0"
|
||||||
|
@ -448,6 +475,12 @@ dependencies = [
|
||||||
"wasi",
|
"wasi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "gimli"
|
||||||
|
version = "0.26.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "h2"
|
name = "h2"
|
||||||
version = "0.3.4"
|
version = "0.3.4"
|
||||||
|
@ -766,6 +799,15 @@ dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "object"
|
||||||
|
version = "0.27.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "67ac1d3f9a1d3616fd9a60c8d74296f22406a238b6a72f5cc1e6f314df4ffbf9"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "once_cell"
|
name = "once_cell"
|
||||||
version = "1.8.0"
|
version = "1.8.0"
|
||||||
|
@ -1070,6 +1112,12 @@ dependencies = [
|
||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustc-demangle"
|
||||||
|
version = "0.1.21"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustc_version"
|
name = "rustc_version"
|
||||||
version = "0.2.3"
|
version = "0.2.3"
|
||||||
|
|
|
@ -12,7 +12,7 @@ serde = {version="1.0", features = ["derive"]}
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
serde_path_to_error = "0.1.5"
|
serde_path_to_error = "0.1.5"
|
||||||
toml = "0.5"
|
toml = "0.5"
|
||||||
anyhow = "1.0"
|
anyhow = { version= "1.0", features = ["backtrace"] }
|
||||||
thiserror = "1.0"
|
thiserror = "1.0"
|
||||||
structopt = "0.3"
|
structopt = "0.3"
|
||||||
command-run = "0.13"
|
command-run = "0.13"
|
||||||
|
|
|
@ -6,11 +6,13 @@ use flake_info::elastic::{ElasticsearchError, ExistsStrategy};
|
||||||
use flake_info::{commands, elastic};
|
use flake_info::{commands, elastic};
|
||||||
use log::{debug, error, info, warn};
|
use log::{debug, error, info, warn};
|
||||||
use sha2::Digest;
|
use sha2::Digest;
|
||||||
use std::fs;
|
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::ptr::hash;
|
use std::ptr::hash;
|
||||||
|
use std::{fs, io};
|
||||||
use structopt::{clap::ArgGroup, StructOpt};
|
use structopt::{clap::ArgGroup, StructOpt};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
use tokio::fs::File;
|
||||||
|
use tokio::io::AsyncWriteExt;
|
||||||
|
|
||||||
#[derive(StructOpt, Debug)]
|
#[derive(StructOpt, Debug)]
|
||||||
#[structopt(
|
#[structopt(
|
||||||
|
@ -74,6 +76,9 @@ enum Command {
|
||||||
|
|
||||||
#[structopt(long, help = "Whether to gc the store after info or not")]
|
#[structopt(long, help = "Whether to gc the store after info or not")]
|
||||||
gc: bool,
|
gc: bool,
|
||||||
|
|
||||||
|
#[structopt(long, help = "Whether write an error report about failed packages")]
|
||||||
|
report: bool,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -155,17 +160,6 @@ async fn main() -> Result<()> {
|
||||||
let command_result = run_command(args.command, args.kind, &args.extra).await;
|
let command_result = run_command(args.command, args.kind, &args.extra).await;
|
||||||
|
|
||||||
if let Err(error) = command_result {
|
if let Err(error) = command_result {
|
||||||
match error {
|
|
||||||
FlakeInfoError::Flake(ref e)
|
|
||||||
| FlakeInfoError::Nixpkgs(ref e)
|
|
||||||
| FlakeInfoError::IO(ref e) => {
|
|
||||||
error!("{}", e);
|
|
||||||
}
|
|
||||||
FlakeInfoError::Group(ref el) => {
|
|
||||||
el.iter().for_each(|e| error!("{}", e));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Err(error.into());
|
return Err(error.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -187,11 +181,10 @@ enum FlakeInfoError {
|
||||||
Flake(anyhow::Error),
|
Flake(anyhow::Error),
|
||||||
#[error("Getting nixpkgs info caused an error: {0:?}")]
|
#[error("Getting nixpkgs info caused an error: {0:?}")]
|
||||||
Nixpkgs(anyhow::Error),
|
Nixpkgs(anyhow::Error),
|
||||||
#[error("Getting group info caused one or more errors: {0:?}")]
|
#[error("Some members of the group '{0}' could not be processed: \n {}", .1.iter().enumerate().map(|(n, e)| format!("{}: {:?}", n+1, e)).collect::<Vec<String>>().join("\n\n"))]
|
||||||
Group(Vec<anyhow::Error>),
|
Group(String, Vec<anyhow::Error>),
|
||||||
|
|
||||||
#[error("Couldn't perform IO: {0}")]
|
#[error("Couldn't perform IO: {0}")]
|
||||||
IO(anyhow::Error),
|
IO(#[from] io::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn run_command(
|
async fn run_command(
|
||||||
|
@ -239,8 +232,14 @@ async fn run_command(
|
||||||
temp_store,
|
temp_store,
|
||||||
gc,
|
gc,
|
||||||
name,
|
name,
|
||||||
|
report,
|
||||||
} => {
|
} => {
|
||||||
let sources = Source::read_sources_file(&targets).map_err(FlakeInfoError::IO)?;
|
// if reporting is enabled delete old report
|
||||||
|
if report && tokio::fs::metadata("report.txt").await.is_ok() {
|
||||||
|
tokio::fs::remove_file("report.txt").await?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let sources = Source::read_sources_file(&targets)?;
|
||||||
let (exports_and_hashes, errors) = sources
|
let (exports_and_hashes, errors) = sources
|
||||||
.iter()
|
.iter()
|
||||||
.map(|source| match source {
|
.map(|source| match source {
|
||||||
|
@ -273,15 +272,19 @@ async fn run_command(
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
if !errors.is_empty() {
|
if !errors.is_empty() {
|
||||||
|
let error = FlakeInfoError::Group(name.clone(), errors);
|
||||||
if exports.is_empty() {
|
if exports.is_empty() {
|
||||||
return Err(FlakeInfoError::Group(errors));
|
return Err(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
warn!("=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=");
|
warn!("=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=");
|
||||||
warn!(
|
warn!("{}", error);
|
||||||
"Some group members could not be evaluated: {}",
|
|
||||||
FlakeInfoError::Group(errors)
|
|
||||||
);
|
|
||||||
warn!("=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=");
|
warn!("=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=");
|
||||||
|
|
||||||
|
if report {
|
||||||
|
let mut file = File::create("report.txt").await?;
|
||||||
|
file.write_all(format!("{}", error).as_bytes()).await?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let hash = {
|
let hash = {
|
||||||
|
|
|
@ -6,13 +6,13 @@ use std::path::PathBuf;
|
||||||
use crate::data::Flake;
|
use crate::data::Flake;
|
||||||
|
|
||||||
/// Uses `nix` to fetch the provided flake and read general information
|
/// Uses `nix` to fetch the provided flake and read general information
|
||||||
/// about it using `nix flake info`
|
/// about it using `nix flake metadata`
|
||||||
pub fn get_flake_info<T: AsRef<str> + Display>(
|
pub fn get_flake_info<T: AsRef<str> + Display>(
|
||||||
flake_ref: T,
|
flake_ref: T,
|
||||||
temp_store: bool,
|
temp_store: bool,
|
||||||
extra: &[String],
|
extra: &[String],
|
||||||
) -> Result<Flake> {
|
) -> Result<Flake> {
|
||||||
let args = ["flake", "info", "--json", "--no-write-lock-file"].iter();
|
let args = ["flake", "metadata", "--json", "--no-write-lock-file"];
|
||||||
let mut command = Command::with_args("nix", args);
|
let mut command = Command::with_args("nix", args);
|
||||||
let command = command.add_arg(flake_ref.as_ref());
|
let command = command.add_arg(flake_ref.as_ref());
|
||||||
if temp_store {
|
if temp_store {
|
||||||
|
|
|
@ -3,7 +3,7 @@ use serde::{Deserialize, Serialize};
|
||||||
use std::{
|
use std::{
|
||||||
ffi::OsStr,
|
ffi::OsStr,
|
||||||
fs::{self, File},
|
fs::{self, File},
|
||||||
io::Read,
|
io::{Read, self},
|
||||||
path::Path,
|
path::Path,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -74,8 +74,8 @@ impl Source {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read_sources_file(path: &Path) -> Result<Vec<Source>> {
|
pub fn read_sources_file(path: &Path) -> io::Result<Vec<Source>> {
|
||||||
let mut file = File::open(path).with_context(|| "Failed to open input file")?;
|
let mut file = File::open(path)?;
|
||||||
|
|
||||||
let mut buf = String::new();
|
let mut buf = String::new();
|
||||||
file.read_to_string(&mut buf)?;
|
file.read_to_string(&mut buf)?;
|
||||||
|
|
Loading…
Reference in a new issue