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:
|
||||
pull_request:
|
||||
paths:
|
||||
- 'flakes/**.toml'
|
||||
- "flakes/**.toml"
|
||||
|
||||
jobs:
|
||||
automatic-custom-flakes-check:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
|
@ -34,7 +33,30 @@ jobs:
|
|||
- name: Try importing all custom flakes
|
||||
run: |
|
||||
shopt -s globstar
|
||||
|
||||
had_error=0
|
||||
|
||||
for flake_group in flakes/**/*.toml
|
||||
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
|
||||
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.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "addr2line"
|
||||
version = "0.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b"
|
||||
dependencies = [
|
||||
"gimli",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "adler"
|
||||
version = "1.0.2"
|
||||
|
@ -31,6 +40,9 @@ name = "anyhow"
|
|||
version = "1.0.43"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "28ae2b3dec75a406790005a200b1bd89785afc02517a00ca99ecfe093ee9e6cf"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-compression"
|
||||
|
@ -62,6 +74,21 @@ version = "1.0.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
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]]
|
||||
name = "base64"
|
||||
version = "0.11.0"
|
||||
|
@ -448,6 +475,12 @@ dependencies = [
|
|||
"wasi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gimli"
|
||||
version = "0.26.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4"
|
||||
|
||||
[[package]]
|
||||
name = "h2"
|
||||
version = "0.3.4"
|
||||
|
@ -766,6 +799,15 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "object"
|
||||
version = "0.27.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "67ac1d3f9a1d3616fd9a60c8d74296f22406a238b6a72f5cc1e6f314df4ffbf9"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.8.0"
|
||||
|
@ -1070,6 +1112,12 @@ dependencies = [
|
|||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-demangle"
|
||||
version = "0.1.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342"
|
||||
|
||||
[[package]]
|
||||
name = "rustc_version"
|
||||
version = "0.2.3"
|
||||
|
|
|
@ -12,7 +12,7 @@ serde = {version="1.0", features = ["derive"]}
|
|||
serde_json = "1.0"
|
||||
serde_path_to_error = "0.1.5"
|
||||
toml = "0.5"
|
||||
anyhow = "1.0"
|
||||
anyhow = { version= "1.0", features = ["backtrace"] }
|
||||
thiserror = "1.0"
|
||||
structopt = "0.3"
|
||||
command-run = "0.13"
|
||||
|
|
|
@ -6,11 +6,13 @@ use flake_info::elastic::{ElasticsearchError, ExistsStrategy};
|
|||
use flake_info::{commands, elastic};
|
||||
use log::{debug, error, info, warn};
|
||||
use sha2::Digest;
|
||||
use std::fs;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::ptr::hash;
|
||||
use std::{fs, io};
|
||||
use structopt::{clap::ArgGroup, StructOpt};
|
||||
use thiserror::Error;
|
||||
use tokio::fs::File;
|
||||
use tokio::io::AsyncWriteExt;
|
||||
|
||||
#[derive(StructOpt, Debug)]
|
||||
#[structopt(
|
||||
|
@ -74,6 +76,9 @@ enum Command {
|
|||
|
||||
#[structopt(long, help = "Whether to gc the store after info or not")]
|
||||
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;
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
|
@ -187,11 +181,10 @@ enum FlakeInfoError {
|
|||
Flake(anyhow::Error),
|
||||
#[error("Getting nixpkgs info caused an error: {0:?}")]
|
||||
Nixpkgs(anyhow::Error),
|
||||
#[error("Getting group info caused one or more errors: {0:?}")]
|
||||
Group(Vec<anyhow::Error>),
|
||||
|
||||
#[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(String, Vec<anyhow::Error>),
|
||||
#[error("Couldn't perform IO: {0}")]
|
||||
IO(anyhow::Error),
|
||||
IO(#[from] io::Error),
|
||||
}
|
||||
|
||||
async fn run_command(
|
||||
|
@ -239,8 +232,14 @@ async fn run_command(
|
|||
temp_store,
|
||||
gc,
|
||||
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
|
||||
.iter()
|
||||
.map(|source| match source {
|
||||
|
@ -273,15 +272,19 @@ async fn run_command(
|
|||
.collect::<Vec<_>>();
|
||||
|
||||
if !errors.is_empty() {
|
||||
let error = FlakeInfoError::Group(name.clone(), errors);
|
||||
if exports.is_empty() {
|
||||
return Err(FlakeInfoError::Group(errors));
|
||||
return Err(error);
|
||||
}
|
||||
|
||||
warn!("=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=");
|
||||
warn!(
|
||||
"Some group members could not be evaluated: {}",
|
||||
FlakeInfoError::Group(errors)
|
||||
);
|
||||
warn!("{}", error);
|
||||
warn!("=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=");
|
||||
|
||||
if report {
|
||||
let mut file = File::create("report.txt").await?;
|
||||
file.write_all(format!("{}", error).as_bytes()).await?;
|
||||
}
|
||||
}
|
||||
|
||||
let hash = {
|
||||
|
|
|
@ -6,13 +6,13 @@ use std::path::PathBuf;
|
|||
use crate::data::Flake;
|
||||
|
||||
/// 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>(
|
||||
flake_ref: T,
|
||||
temp_store: bool,
|
||||
extra: &[String],
|
||||
) -> 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 command = command.add_arg(flake_ref.as_ref());
|
||||
if temp_store {
|
||||
|
|
|
@ -3,7 +3,7 @@ use serde::{Deserialize, Serialize};
|
|||
use std::{
|
||||
ffi::OsStr,
|
||||
fs::{self, File},
|
||||
io::Read,
|
||||
io::{Read, self},
|
||||
path::Path,
|
||||
};
|
||||
|
||||
|
@ -74,8 +74,8 @@ impl Source {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn read_sources_file(path: &Path) -> Result<Vec<Source>> {
|
||||
let mut file = File::open(path).with_context(|| "Failed to open input file")?;
|
||||
pub fn read_sources_file(path: &Path) -> io::Result<Vec<Source>> {
|
||||
let mut file = File::open(path)?;
|
||||
|
||||
let mut buf = String::new();
|
||||
file.read_to_string(&mut buf)?;
|
||||
|
|
Loading…
Reference in a new issue