Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 25 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,18 @@ publish = false
[dependencies]
anyhow = "1"
camino = { version = "1", features = ["serde1"] }
cap-std-ext = { version = "5", default-features = false, features = ["fs_utf8"] }
cap-std-ext = { version = "5", default-features = false, features = [
"fs_utf8",
] }
chrono = "0.4"
clap = { version = "4", default-features = false, features = ["derive", "std", "help", "usage", "error-context", "env"] }
clap = { version = "4", default-features = false, features = [
"derive",
"std",
"help",
"usage",
"error-context",
"env",
] }
ctrlc = "3.5.2"
flate2 = "1"
fnv = "1.0.7"
Expand All @@ -35,3 +44,17 @@ tracing-subscriber = { version = "0.3", features = ["env-filter"] }
[dev-dependencies]
fs-set-times = "0.20.3"
maplit = "1"

[lints.clippy]
cast_lossless = "deny"
manual_midpoint = "deny"
bool_to_int_with_if = "deny"
trivially_copy_pass_by_ref = "deny"
map_clone = "deny"
redundant_closure = "deny"
explicit_into_iter_loop = "deny"
unreadable_literal = "deny"
needless_raw_string_hashes = "deny"
unnecessary_wraps = "deny"
# This can have some false positives with things like `Arc` so only warning
needless_pass_by_value = "warn"
26 changes: 13 additions & 13 deletions src/cmd_build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ pub struct BuildArgs {

impl BuildArgs {
/// Apply CLI overrides to an OCI config, returning a new config.
fn apply_to_config(&self, config: oci_image::Config) -> Result<oci_image::Config> {
fn apply_to_config(&self, config: &oci_image::Config) -> Result<oci_image::Config> {
let mut builder = oci_image::ConfigBuilder::default();

// Copy over all fields from base config. Would be nice if we could
Expand Down Expand Up @@ -225,7 +225,7 @@ pub fn run(args: &BuildArgs) -> Result<()> {
let annotations = parse_key_value_pairs(&args.annotations, parsed.annotations)
.context("parsing annotations")?;

let image_config = build_image_config(args, parsed.config, created_epoch, architecture)
let image_config = build_image_config(args, &parsed.config, created_epoch, architecture)
.context("building image config")?;

let rootfs = Dir::open_ambient_dir(args.rootfs.as_std_path(), ambient_authority())
Expand Down Expand Up @@ -260,7 +260,7 @@ pub fn run(args: &BuildArgs) -> Result<()> {
}

// pack components down to max layers
let components = pack_components(args.max_layers, components).context("packing components")?;
let components = pack_components(args.max_layers, components);
tracing::info!(layers = components.len(), "packing complete");

// build the OCI image
Expand Down Expand Up @@ -319,7 +319,7 @@ pub fn run(args: &BuildArgs) -> Result<()> {

/// Parse the `--output` value into an [`OutputTarget`].
fn parse_output_target(output: Option<&Utf8Path>) -> Result<OutputTarget> {
match output.map(|o| o.as_str()) {
match output.map(Utf8Path::as_str) {
None => Ok(OutputTarget::Stdout),
Some(s) => match s.split_once(':') {
Some(("oci-archive", path)) => {
Expand Down Expand Up @@ -380,7 +380,7 @@ fn write_manifest(
file_count: component.files.len(),
size: component.files.values().map(|f| f.size).sum(),
stability: component.stability,
files: component.files.keys().map(|p| p.to_string()).collect(),
files: component.files.keys().map(Utf8PathBuf::to_string).collect(),
};
(name.clone(), entry)
})
Expand Down Expand Up @@ -475,7 +475,7 @@ fn resolve_created_epoch(source_date_epoch: Option<u64>, parsed: &ParsedConfig)
/// Build the OCI image configuration from CLI args and a parsed config.
fn build_image_config(
args: &BuildArgs,
config: oci_image::Config,
config: &oci_image::Config,
created: u64,
architecture: &str,
) -> Result<oci_image::ImageConfiguration> {
Expand Down Expand Up @@ -539,7 +539,7 @@ fn parse_key_value_pairs(
fn pack_components(
max_layers: usize,
components: HashMap<String, Component>,
) -> Result<Vec<(String, Component)>> {
) -> Vec<(String, Component)> {
let mut entries: Vec<Option<(String, Component)>> = components.into_iter().map(Some).collect();
// sort by component name for deterministic inputs to the packing algorithm
entries.sort_by(|a, b| a.as_ref().unwrap().0.cmp(&b.as_ref().unwrap().0));
Expand Down Expand Up @@ -600,7 +600,7 @@ fn pack_components(
}
}

Ok(result)
result
}

#[cfg(test)]
Expand Down Expand Up @@ -651,7 +651,7 @@ mod tests {

// parse config from fixture file
let parsed = parse_config(CONFIG_FIXTURE).unwrap();
let image_config = build_image_config(&args, parsed.config, 1, "amd64").unwrap();
let image_config = build_image_config(&args, &parsed.config, 1, "amd64").unwrap();

let rootfs = Dir::open_ambient_dir(rootfs_dir.path(), ambient_authority()).unwrap();

Expand Down Expand Up @@ -702,7 +702,7 @@ mod tests {

// verify there's no history
assert!(
image_config.history().as_ref().is_none_or(|h| h.is_empty()),
image_config.history().as_ref().is_none_or(Vec::is_empty),
"image should have no history entries"
);

Expand Down Expand Up @@ -861,7 +861,7 @@ mod tests {
..Default::default()
};

let image_config = build_image_config(&args, parsed.config, 1, "amd64").unwrap();
let image_config = build_image_config(&args, &parsed.config, 1, "amd64").unwrap();
let labels = image_config
.config()
.as_ref()
Expand Down Expand Up @@ -891,7 +891,7 @@ mod tests {
let rootfs = Dir::open_ambient_dir(tmp.path(), ambient_authority()).unwrap();

let add_component = |name: &str, size_mb: usize, interval: &str| {
rootfs.write(name, &vec![0u8; size_mb * MB]).unwrap();
rootfs.write(name, vec![0u8; size_mb * MB]).unwrap();
rootfs
.setxattr(name, XATTR_COMPONENT, name.as_bytes())
.unwrap();
Expand All @@ -907,7 +907,7 @@ mod tests {
let files = crate::scan::Scanner::new(&rootfs).scan().unwrap();
let repos = ComponentsRepos::load(&rootfs, &files, 0).unwrap();
let components = repos.into_components(&rootfs, files).unwrap();
pack_components(2, components).unwrap()
pack_components(2, components)
};

// Helper to find which packed layer contains a given file.
Expand Down
33 changes: 15 additions & 18 deletions src/components/alpm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -357,7 +357,7 @@ impl ComponentsRepo for AlpmComponentsRepo {
) -> Vec<ComponentId> {
self.path_to_components
.get(path)
.map(|components| components.to_vec())
.cloned()
.unwrap_or_default()
}

Expand Down Expand Up @@ -572,7 +572,7 @@ impl LocalAlpmDbFile {
.get(section)
.ok_or_else(|| anyhow!("section not found: {section}"))?
.iter()
.map(|line| line.as_str());
.map(String::as_str);
let first = lines
.next()
.ok_or_else(|| anyhow!("no value found for section {section}"))?;
Expand All @@ -590,7 +590,7 @@ impl LocalAlpmDbFile {
/// Note that the spec is different for `alpm-db-desc` and `alpm-db-files` (see [`Self::get_single_line_value`]).
/// If you are parsing a `alpm-db-files` file, you might need to filter additional newlines by yourself.
fn get_multi_line_value(&self, section: &str) -> Option<&[String]> {
self.0.get(section).map(|value| value.as_slice())
self.0.get(section).map(Vec::as_slice)
}

/// Checks that the given line is a well-formed header line and returns the section name if it is
Expand Down Expand Up @@ -782,8 +782,8 @@ mod tests {

// Multiple packages in base have gcc as their basename, so in terms of component names, they will be seen multiple times
let mut expected_components = IMPORTANT_ARCH_LINUX_PACKAGES_IN_BASE
.into_iter()
.map(|pkg| *pkg)
.iter()
.copied()
.collect::<BTreeSet<_>>();
let component_info = claims.iter().map(|claim| alpm.component_info(*claim));
for component in component_info {
Expand Down Expand Up @@ -848,7 +848,7 @@ mod tests {

#[test]
fn test_parse_desc() {
const DESC_CONTENTS: &str = r#"%NAME%
const DESC_CONTENTS: &str = r"%NAME%
filesystem

%VERSION%
Expand Down Expand Up @@ -889,7 +889,7 @@ iana-etc

%XDATA%
pkgtype=pkg
"#;
";
let parsed_desc = DESC_CONTENTS.parse::<LocalAlpmDbFile>().unwrap();
assert_eq!(
parsed_desc.get_single_line_value("NAME").unwrap(),
Expand All @@ -900,12 +900,12 @@ pkgtype=pkg
assert_eq!(parsed_desc.base().unwrap(), "filesystem");
// This is the builddate at the time of writing the test.
// Package will probably be newer if the fixture contents are regenerated at a later point in time
assert!(parsed_desc.builddate().unwrap() >= 1760286101);
assert!(parsed_desc.builddate().unwrap() >= 1_760_286_101);
}

#[test]
fn test_parse_files() {
const FILES_CONTENT: &str = r#"%FILES%
const FILES_CONTENT: &str = r"%FILES%
etc/
etc/protocols
etc/services
Expand All @@ -921,7 +921,7 @@ usr/share/licenses/iana-etc/LICENSE
%BACKUP%
etc/protocols b9833a5373ef2f5df416f4f71ccb42eb
etc/services b80b33810d79289b09bac307a99b4b54
"#;
";
const EXPECTED_PATHS: &[&str] = &[
"etc/",
"etc/protocols",
Expand All @@ -937,16 +937,13 @@ etc/services b80b33810d79289b09bac307a99b4b54
];
let mut expected_paths_set = EXPECTED_PATHS
.iter()
.map(|path| Utf8Path::new(path))
.map(Utf8Path::new)
.collect::<BTreeSet<_>>();

let parsed_files = FILES_CONTENT.parse::<LocalAlpmDbFile>().unwrap();

// Test that the generic parser can parse other sections, such as BACKUP
let mut other_section = parsed_files
.get_multi_line_value("BACKUP")
.unwrap()
.into_iter();
let mut other_section = parsed_files.get_multi_line_value("BACKUP").unwrap().iter();
assert_eq!(
other_section.next().unwrap(),
"etc/protocols\tb9833a5373ef2f5df416f4f71ccb42eb"
Expand All @@ -958,7 +955,7 @@ etc/services b80b33810d79289b09bac307a99b4b54
assert_eq!(other_section.next(), None);

let parsed_files = LocalAlpmDbFilesFile(parsed_files);
for path_from_files in parsed_files.files().into_iter() {
for path_from_files in parsed_files.files() {
assert!(
expected_paths_set.remove(path_from_files),
"path from files must be expected"
Expand Down Expand Up @@ -1026,14 +1023,14 @@ DBPathInvalid = /invalid
#[test]
fn pacman_conf_last_with_inline_comment() {
/// A pacman.conf file that is valid, but contains comments in the same line
pub const PACMAN_CONF_MULTIPLE_WITH_INLINE_COMMENT_AND_RELATIVE: &str = r#"
pub const PACMAN_CONF_MULTIPLE_WITH_INLINE_COMMENT_AND_RELATIVE: &str = r"
[options]
DBPath = /invalid # This is an inline comment
[invalid]
invalid_option = false
[options]
DBPath = var/lib/pacman # Last path should win. Test relative paths are working as well.
"#;
";
let dbpath = AlpmComponentsRepo::parse_pacman_conf_dbpath(
PACMAN_CONF_MULTIPLE_WITH_INLINE_COMMENT_AND_RELATIVE,
);
Expand Down
2 changes: 1 addition & 1 deletion src/components/bigfiles.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ impl BigfilesRepo {

let filename = path
.file_name()
.map(|s| s.to_string())
.map(str::to_string)
.expect("filename has no basename");

// derive component name from filename
Expand Down
6 changes: 3 additions & 3 deletions src/components/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ impl FileType {
/// Try to convert from cap_std file type.
///
/// Returns `None` for unsupported types (sockets, FIFOs, block/char devices).
pub fn from_cap_std(file_type: &CapFileType) -> Option<Self> {
pub fn from_cap_std(file_type: CapFileType) -> Option<Self> {
if file_type.is_dir() {
Some(FileType::Directory)
} else if file_type.is_file() {
Expand Down Expand Up @@ -253,7 +253,7 @@ impl ComponentsRepos {
}

/// Whether to use strong or weak claims in a claiming pass.
#[derive(Debug)]
#[derive(Debug, Clone, Copy)]
enum ClaimStrength {
Strong,
Weak,
Expand Down Expand Up @@ -426,7 +426,7 @@ mod tests {
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_secs();
let rpm_repo = rpm::RpmRepo::load_from_packages(packages, now).unwrap();
let rpm_repo = rpm::RpmRepo::load_from_packages(packages, now);

let repos: Vec<Box<dyn ComponentsRepo>> = vec![Box::new(rpm_repo), Box::new(xattr_repo)];
let loaded = ComponentsRepos {
Expand Down
Loading
Loading