Skip to content

Commit a37c8b6

Browse files
Cargo.toml: switch to a workspace
Split into a few separate crates: - libraries: - composefs - composefs-oci - composefs-boot - binaries: - cfsctl - composefs-setup-root - erofs-debug Move our lint config (which only forbids missing debug impls) to the workspace level and have all crates inherit from that. Add a new workflow for testing that we can `cargo package` everything. We need a nightly cargo in order to do this with workspaces containing inter-dependent crates: rust-lang/cargo#13947 Make 'oci' an optional feature of cfsctl, but enable it by default. Adjust our rawhide bls example (which included --no-default-features) to *not* disable that. This is not a huge improvement in terms of compile speed, and it has some drawbacks (like 'cargo run' no longer defaulting to cfsctl) but it seems like the right step at this point. I want to start to add some more experimental code without making it part of the main crate. Signed-off-by: Allison Karlitskaya <[email protected]>
1 parent f925f5d commit a37c8b6

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+302
-124
lines changed

.github/workflows/publish.yml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,8 @@ jobs:
1616
uses: actions/checkout@v4
1717

1818
- name: Publish crate
19-
run: cargo publish
19+
run: cargo publish -p composefs
20+
run: cargo publish -p composefs-oci
21+
run: cargo publish -p composefs-boot
22+
run: cargo publish -p cfsctl
23+
run: cargo publish -p composefs-setup-root

.github/workflows/rust.yml

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,16 @@ env:
1010
CARGO_TERM_COLOR: always
1111

1212
jobs:
13+
nightly:
14+
runs-on: ubuntu-24.04
15+
timeout-minutes: 15
16+
steps:
17+
- uses: actions-rs/toolchain@v1
18+
with:
19+
toolchain: nightly
20+
- uses: actions/checkout@v4
21+
- run: cargo +nightly -Z package-workspace package
22+
1323
fedora:
1424
runs-on: ubuntu-24.04
1525
timeout-minutes: 5
@@ -26,4 +36,3 @@ jobs:
2636
- run: cargo fmt --check
2737
- run: cargo clippy -- -Dwarnings
2838
- run: env CFS_TEST_TMPDIR=/run/host/var/tmp cargo test --verbose
29-
- run: cargo publish --dry-run

Cargo.toml

Lines changed: 14 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,23 @@
1-
[package]
2-
name = "composefs"
3-
version = "0.2.0"
1+
[workspace]
2+
members = ["crates/*"]
3+
resolver = "2"
4+
5+
[workspace.package]
46
edition = "2021"
5-
rust-version = "1.82.0"
6-
description = "Rust library for the composefs filesystem"
7-
keywords = ["composefs"]
87
license = "MIT OR Apache-2.0"
9-
repository = "https://github.com/containers/composefs-rs"
108
readme = "README.md"
11-
default-run = "cfsctl"
12-
exclude = ["/.git*", "/examples/"]
13-
14-
[features]
15-
default = ['pre-6.15']
16-
rhel9 = ['pre-6.15']
17-
'pre-6.15' = []
9+
repository = "https://github.com/containers/composefs-rs"
10+
rust-version = "1.82.0"
11+
version = "0.2.0"
1812

19-
[dependencies]
20-
anyhow = { version = "1.0.87", default-features = false }
21-
async-compression = { version = "0.4.0", default-features = false, features = ["tokio", "zstd", "gzip"] }
22-
clap = { version = "4.0.1", default-features = false, features = ["std", "help", "usage", "derive"] }
23-
containers-image-proxy = "0.7.1"
24-
env_logger = "0.11.0"
25-
hex = "0.4.0"
26-
indicatif = { version = "0.17.0", features = ["tokio"] }
27-
log = "0.4.8"
28-
oci-spec = "0.7.0"
29-
once_cell = { version = "1.21.3", default-features = false }
30-
regex-automata = { version = "0.4.4", default-features = false }
31-
rustix = { version = "1.0.0", features = ["fs", "mount", "process"] }
32-
serde = "1.0.145"
33-
sha2 = "0.10.1"
34-
tar = { version = "0.4.38", default-features = false }
35-
tempfile = "3.8.0"
36-
thiserror = "2.0.0"
37-
tokio = { version = "1.24.2", features = ["rt-multi-thread"] }
38-
toml = "0.8.0"
39-
xxhash-rust = { version = "0.8.2", features = ["xxh32"] }
40-
zerocopy = { version = "0.8.0", features = ["derive", "std"] }
41-
zstd = "0.13.0"
13+
[workspace.lints.rust]
14+
missing_debug_implementations = "deny"
4215

43-
[dev-dependencies]
44-
insta = "1.42.2"
45-
similar-asserts = "1.7.0"
46-
test-with = { version = "0.14", default-features = false, features = ["executable", "runtime"] }
47-
tokio-test = "0.4.4"
16+
[workspace.dependencies]
17+
composefs = { version = "0.2.0", path = "crates/composefs", default-features = false }
18+
composefs-oci = { version = "0.2.0", path = "crates/composefs-oci", default-features = false }
19+
composefs-boot = { version = "0.2.0", path = "crates/composefs-boot", default-features = false }
4820

4921
[profile.dev.package.sha2]
5022
# this is *really* slow otherwise
5123
opt-level = 3
52-
53-
[lib]
54-
name = "composefs"
55-
path = "src/lib.rs"

crates/cfsctl/Cargo.toml

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
[package]
2+
name = "cfsctl"
3+
description = "Command-line utility for composefs"
4+
default-run = "cfsctl"
5+
6+
edition.workspace = true
7+
license.workspace = true
8+
readme.workspace = true
9+
repository.workspace = true
10+
rust-version.workspace = true
11+
version.workspace = true
12+
13+
[features]
14+
default = ['pre-6.15', 'oci']
15+
oci = ['composefs-oci']
16+
rhel9 = ['composefs/rhel9']
17+
'pre-6.15' = ['composefs/pre-6.15']
18+
19+
[dependencies]
20+
anyhow = { version = "1.0.87", default-features = false }
21+
clap = { version = "4.0.1", default-features = false, features = ["std", "help", "usage", "derive"] }
22+
composefs = { workspace = true }
23+
composefs-boot = { workspace = true }
24+
composefs-oci = { workspace = true, optional = true }
25+
env_logger = { version = "0.11.0", default-features = false }
26+
hex = { version = "0.4.0", default-features = false }
27+
rustix = { version = "1.0.0", default-features = false, features = ["fs", "process"] }
28+
tokio = { version = "1.24.2", default-features = false }
29+
30+
[lints]
31+
workspace = true

src/bin/cfsctl.rs renamed to crates/cfsctl/src/main.rs

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,16 @@ use std::{
44
sync::Arc,
55
};
66

7-
use anyhow::{bail, Result};
7+
use anyhow::Result;
88
use clap::{Parser, Subcommand};
99

1010
use rustix::fs::CWD;
1111

12+
use composefs_boot::{write_boot, BootOps};
13+
1214
use composefs::{
1315
fsverity::{FsVerityHashValue, Sha256HashValue},
14-
oci,
1516
repository::Repository,
16-
util::parse_sha256,
1717
};
1818

1919
/// cfsctl
@@ -31,6 +31,7 @@ pub struct App {
3131
cmd: Command,
3232
}
3333

34+
#[cfg(feature = "oci")]
3435
#[derive(Debug, Subcommand)]
3536
enum OciCommand {
3637
/// Stores a tar file as a splitstream in the repository.
@@ -102,6 +103,7 @@ enum Command {
102103
reference: String,
103104
},
104105
/// Commands for dealing with OCI layers
106+
#[cfg(feature = "oci")]
105107
Oci {
106108
#[clap(subcommand)]
107109
cmd: OciCommand,
@@ -179,25 +181,27 @@ async fn main() -> Result<()> {
179181
let image_id = repo.import_image(&reference, &mut std::io::stdin())?;
180182
println!("{}", image_id.to_id());
181183
}
184+
#[cfg(feature = "oci")]
182185
Command::Oci { cmd: oci_cmd } => match oci_cmd {
183186
OciCommand::ImportLayer { name, sha256 } => {
184-
let object_id = oci::import_layer(
187+
let object_id = composefs_oci::import_layer(
185188
&Arc::new(repo),
186-
&parse_sha256(sha256)?,
189+
&composefs::util::parse_sha256(sha256)?,
187190
name.as_deref(),
188191
&mut std::io::stdin(),
189192
)?;
190193
println!("{}", object_id.to_id());
191194
}
192195
OciCommand::LsLayer { name } => {
193-
oci::ls_layer(&repo, &name)?;
196+
composefs_oci::ls_layer(&repo, &name)?;
194197
}
195198
OciCommand::Dump {
196199
ref config_name,
197200
ref config_verity,
198201
} => {
199202
let verity = verity_opt(config_verity)?;
200-
let mut fs = oci::image::create_filesystem(&repo, config_name, verity.as_ref())?;
203+
let mut fs =
204+
composefs_oci::image::create_filesystem(&repo, config_name, verity.as_ref())?;
201205
fs.print_dumpfile()?;
202206
}
203207
OciCommand::ComputeId {
@@ -206,7 +210,8 @@ async fn main() -> Result<()> {
206210
bootable,
207211
} => {
208212
let verity = verity_opt(config_verity)?;
209-
let mut fs = oci::image::create_filesystem(&repo, config_name, verity.as_ref())?;
213+
let mut fs =
214+
composefs_oci::image::create_filesystem(&repo, config_name, verity.as_ref())?;
210215
if bootable {
211216
fs.transform_for_boot(&repo)?;
212217
}
@@ -220,15 +225,17 @@ async fn main() -> Result<()> {
220225
ref image_name,
221226
} => {
222227
let verity = verity_opt(config_verity)?;
223-
let mut fs = oci::image::create_filesystem(&repo, config_name, verity.as_ref())?;
228+
let mut fs =
229+
composefs_oci::image::create_filesystem(&repo, config_name, verity.as_ref())?;
224230
if bootable {
225231
fs.transform_for_boot(&repo)?;
226232
}
227233
let image_id = fs.commit_image(&repo, image_name.as_deref())?;
228234
println!("{}", image_id.to_id());
229235
}
230236
OciCommand::Pull { ref image, name } => {
231-
let (sha256, verity) = oci::pull(&Arc::new(repo), image, name.as_deref()).await?;
237+
let (sha256, verity) =
238+
composefs_oci::pull(&Arc::new(repo), image, name.as_deref()).await?;
232239

233240
println!("sha256 {}", hex::encode(sha256));
234241
println!("verity {}", verity.to_hex());
@@ -238,15 +245,16 @@ async fn main() -> Result<()> {
238245
ref config_verity,
239246
} => {
240247
let verity = verity_opt(config_verity)?;
241-
let (sha256, verity) = oci::seal(&Arc::new(repo), config_name, verity.as_ref())?;
248+
let (sha256, verity) =
249+
composefs_oci::seal(&Arc::new(repo), config_name, verity.as_ref())?;
242250
println!("sha256 {}", hex::encode(sha256));
243251
println!("verity {}", verity.to_id());
244252
}
245253
OciCommand::Mount {
246254
ref name,
247255
ref mountpoint,
248256
} => {
249-
oci::mount(&repo, name, mountpoint, None)?;
257+
composefs_oci::mount(&repo, name, mountpoint, None)?;
250258
}
251259
OciCommand::PrepareBoot {
252260
ref config_name,
@@ -256,16 +264,17 @@ async fn main() -> Result<()> {
256264
ref cmdline,
257265
} => {
258266
let verity = verity_opt(config_verity)?;
259-
let mut fs = oci::image::create_filesystem(&repo, config_name, verity.as_ref())?;
267+
let mut fs =
268+
composefs_oci::image::create_filesystem(&repo, config_name, verity.as_ref())?;
260269
let entries = fs.transform_for_boot(&repo)?;
261270
let id = fs.commit_image(&repo, None)?;
262271

263272
let Some(entry) = entries.into_iter().next() else {
264-
bail!("No boot entries!");
273+
anyhow::bail!("No boot entries!");
265274
};
266275

267276
let cmdline_refs: Vec<&str> = cmdline.iter().map(String::as_str).collect();
268-
composefs::write_boot::write_boot_simple(
277+
write_boot::write_boot_simple(
269278
&repo,
270279
entry,
271280
&id,

crates/composefs-boot/Cargo.toml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
[package]
2+
name = "composefs-boot"
3+
description = "Helpers for bootable composefs systems"
4+
keywords = ["composefs", "boot"]
5+
6+
edition.workspace = true
7+
license.workspace = true
8+
readme.workspace = true
9+
repository.workspace = true
10+
rust-version.workspace = true
11+
version.workspace = true
12+
13+
[dependencies]
14+
anyhow = { version = "1.0.87", default-features = false }
15+
composefs = { workspace = true }
16+
regex-automata = { version = "0.4.4", default-features = false, features=["hybrid", "std", "syntax"] }
17+
thiserror = { version = "2.0.0", default-features = false }
18+
zerocopy = { version = "0.8.0", default-features = false, features = ["derive"] }
19+
20+
[dev-dependencies]
21+
similar-asserts = "1.7.0"
22+
23+
[lints]
24+
workspace = true

src/bootloader.rs renamed to crates/composefs-boot/src/bootloader.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,14 @@ use std::{
55

66
use anyhow::{bail, ensure, Result};
77

8-
use crate::{
9-
cmdline::split_cmdline,
8+
use composefs::{
109
fsverity::FsVerityHashValue,
1110
repository::Repository,
1211
tree::{Directory, FileSystem, ImageError, Inode, LeafContent, RegularFile},
1312
};
1413

14+
use crate::cmdline::split_cmdline;
15+
1516
/// Strips the key (if it matches) plus the following whitespace from a single line in a "Type #1
1617
/// Boot Loader Specification Entry" file.
1718
///
File renamed without changes.

crates/composefs-boot/src/lib.rs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
#![deny(missing_debug_implementations)]
2+
3+
pub mod bootloader;
4+
pub mod cmdline;
5+
pub mod os_release;
6+
pub mod selabel;
7+
pub mod uki;
8+
pub mod write_boot;
9+
10+
use anyhow::Result;
11+
12+
use composefs::{fsverity::FsVerityHashValue, repository::Repository, tree::FileSystem};
13+
14+
use crate::bootloader::{get_boot_resources, BootEntry};
15+
16+
pub trait BootOps<ObjectID: FsVerityHashValue> {
17+
fn transform_for_boot(
18+
&mut self,
19+
repo: &Repository<ObjectID>,
20+
) -> Result<Vec<BootEntry<ObjectID>>>;
21+
}
22+
23+
impl<ObjectID: FsVerityHashValue> BootOps<ObjectID> for FileSystem<ObjectID> {
24+
fn transform_for_boot(
25+
&mut self,
26+
repo: &Repository<ObjectID>,
27+
) -> Result<Vec<BootEntry<ObjectID>>> {
28+
let boot_entries = get_boot_resources(self, repo)?;
29+
let boot = self.root.get_directory_mut("boot".as_ref())?;
30+
boot.stat.st_mtim_sec = 0;
31+
boot.clear();
32+
33+
selabel::selabel(self, repo)?;
34+
35+
Ok(boot_entries)
36+
}
37+
}
File renamed without changes.

0 commit comments

Comments
 (0)