diff --git a/.github/workflows/crates-release.yml b/.github/workflows/crates-release.yml index 558af5a9f..916f69cbb 100644 --- a/.github/workflows/crates-release.yml +++ b/.github/workflows/crates-release.yml @@ -2,7 +2,8 @@ name: Publish to crates.io on: push: - tags: ['v*'] # Triggers when pushing tags starting with 'v' + tags: ['v*'] + workflow_dispatch: {} jobs: publish: runs-on: ubuntu-24.04 @@ -13,10 +14,19 @@ jobs: - uses: rust-lang/crates-io-auth-action@v1 id: auth - run: | - for crate in bootc-internal-utils bootc-internal-blockdev; do - echo "Publishing $crate..." - cargo publish -p "$crate" - echo "Successfully published $crate" + # Publish crates if their current version is not already on crates.io. + # Order matters: dependencies must be published first. + CRATES="bootc-internal-utils bootc-internal-mount bootc-internal-blockdev" + + for crate in $CRATES; do + VERSION=$(cargo read-manifest -p "$crate" | jq -r '.version') + if cargo info "$crate@$VERSION" > /dev/null 2>&1; then + echo "$crate@$VERSION is already published, skipping" + else + echo "Publishing $crate@$VERSION..." + cargo publish -p "$crate" + echo "Successfully published $crate@$VERSION" + fi done env: CARGO_REGISTRY_TOKEN: ${{ steps.auth.outputs.token }} diff --git a/.github/workflows/scheduled-release.yml b/.github/workflows/scheduled-release.yml index 1a9cdb448..11fd5551c 100644 --- a/.github/workflows/scheduled-release.yml +++ b/.github/workflows/scheduled-release.yml @@ -92,6 +92,11 @@ jobs: cargo set-version --manifest-path crates/lib/Cargo.toml --package bootc-lib --bump ${INPUT_VERSION:-minor} VERSION=$(cargo read-manifest --manifest-path crates/lib/Cargo.toml | jq -r '.version') + # Set internal crate versions to match the bootc release version + cargo set-version --manifest-path crates/utils/Cargo.toml --package bootc-internal-utils "$VERSION" + cargo set-version --manifest-path crates/mount/Cargo.toml --package bootc-internal-mount "$VERSION" + cargo set-version --manifest-path crates/blockdev/Cargo.toml --package bootc-internal-blockdev "$VERSION" + cargo update --workspace cargo xtask update-generated echo "VERSION=$VERSION" >> $GITHUB_OUTPUT diff --git a/Cargo.lock b/Cargo.lock index 958396b17..df75abecd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -238,8 +238,8 @@ name = "bootc-internal-blockdev" version = "0.2.0" dependencies = [ "anyhow", + "bootc-internal-mount", "bootc-internal-utils", - "bootc-mount", "camino", "cap-std-ext 5.1.1", "fn-error-context", @@ -253,6 +253,23 @@ dependencies = [ "tracing", ] +[[package]] +name = "bootc-internal-mount" +version = "0.1.0" +dependencies = [ + "anyhow", + "bootc-internal-utils", + "camino", + "cap-std-ext 5.1.1", + "fn-error-context", + "indoc", + "libc", + "rustix", + "serde", + "tempfile", + "tracing", +] + [[package]] name = "bootc-internal-utils" version = "0.1.0" @@ -294,9 +311,9 @@ dependencies = [ "anyhow", "bootc-initramfs-setup", "bootc-internal-blockdev", + "bootc-internal-mount", "bootc-internal-utils", "bootc-kernel-cmdline", - "bootc-mount", "bootc-sysusers", "bootc-tmpfiles", "camino", @@ -345,23 +362,6 @@ dependencies = [ "xshell", ] -[[package]] -name = "bootc-mount" -version = "0.0.0" -dependencies = [ - "anyhow", - "bootc-internal-utils", - "camino", - "cap-std-ext 5.1.1", - "fn-error-context", - "indoc", - "libc", - "rustix", - "serde", - "tempfile", - "tracing", -] - [[package]] name = "bootc-sysusers" version = "0.1.0" @@ -2935,8 +2935,8 @@ version = "0.1.9" dependencies = [ "anstream 1.0.0", "anyhow", + "bootc-internal-mount", "bootc-internal-utils", - "bootc-mount", "clap", "crossterm", "dialoguer", diff --git a/crates/blockdev/Cargo.toml b/crates/blockdev/Cargo.toml index 87d5ba74a..83c79a9a9 100644 --- a/crates/blockdev/Cargo.toml +++ b/crates/blockdev/Cargo.toml @@ -9,7 +9,7 @@ version = "0.2.0" [dependencies] # Internal crates bootc-utils = { package = "bootc-internal-utils", path = "../utils", version = "0.1.0" } -bootc-mount = { path = "../mount" } +bootc-mount = { package = "bootc-internal-mount", path = "../mount", version = "0.1.0" } # Workspace dependencies anyhow = { workspace = true } diff --git a/crates/lib/Cargo.toml b/crates/lib/Cargo.toml index 1b0a30437..d2f6af9d0 100644 --- a/crates/lib/Cargo.toml +++ b/crates/lib/Cargo.toml @@ -16,7 +16,7 @@ include = ["/src", "LICENSE-APACHE", "LICENSE-MIT"] # Internal crates bootc-blockdev = { package = "bootc-internal-blockdev", path = "../blockdev", version = "0.2.0" } bootc-kernel-cmdline = { path = "../kernel_cmdline", version = "0.0.0" } -bootc-mount = { path = "../mount" } +bootc-mount = { package = "bootc-internal-mount", path = "../mount", version = "0.1.0" } bootc-sysusers = { path = "../sysusers" } bootc-tmpfiles = { path = "../tmpfiles" } bootc-utils = { package = "bootc-internal-utils", path = "../utils", version = "0.1.0" } diff --git a/crates/lib/src/lib.rs b/crates/lib/src/lib.rs index a40bc58eb..558ca8718 100644 --- a/crates/lib/src/lib.rs +++ b/crates/lib/src/lib.rs @@ -59,7 +59,7 @@ //! # Related Crates //! //! - [`ostree-ext`](../ostree_ext/index.html) - OCI/ostree bridging -//! - [`bootc-mount`](../bootc_mount/index.html) - Mount utilities +//! - [`bootc-internal-mount`](../bootc_mount/index.html) - Mount utilities //! - [`bootc-kernel-cmdline`](../bootc_kernel_cmdline/index.html) - Cmdline parsing //! - [`etc-merge`](../etc_merge/index.html) - `/etc` three-way merge diff --git a/crates/mount/Cargo.toml b/crates/mount/Cargo.toml index d90b0bf0c..e7f1a698c 100644 --- a/crates/mount/Cargo.toml +++ b/crates/mount/Cargo.toml @@ -1,12 +1,10 @@ [package] -description = "Internal mount code" -# Should never be published to crates.io -publish = false +description = "Internal implementation component of bootc; do not use" edition = "2024" license = "MIT OR Apache-2.0" -name = "bootc-mount" +name = "bootc-internal-mount" repository = "https://github.com/bootc-dev/bootc" -version = "0.0.0" +version = "0.1.0" [dependencies] # Internal crates @@ -28,3 +26,6 @@ indoc = { workspace = true } [lib] path = "src/mount.rs" + +[lints] +workspace = true diff --git a/crates/mount/src/mount.rs b/crates/mount/src/mount.rs index 20f80e292..67eba4a68 100644 --- a/crates/mount/src/mount.rs +++ b/crates/mount/src/mount.rs @@ -23,6 +23,7 @@ use rustix::{ }; use serde::Deserialize; +/// Temporary mount management with automatic cleanup. pub mod tempmount; /// Well known identifier for pid 1 @@ -33,26 +34,37 @@ pub const PID1: Pid = const { } }; +/// Deserialized information about a mounted filesystem from `findmnt`. #[derive(Deserialize, Debug)] #[serde(rename_all = "kebab-case")] #[allow(dead_code)] pub struct Filesystem { // Note if you add an entry to this list, you need to change the --output invocation below too + /// The source device or path. pub source: String, + /// The mount target path. pub target: String, + /// Major:minor device numbers. #[serde(rename = "maj:min")] pub maj_min: String, + /// The filesystem type (e.g. ext4, xfs). pub fstype: String, + /// Mount options. pub options: String, + /// The filesystem UUID, if available. pub uuid: Option, + /// Child filesystems, if any. pub children: Option>, } +/// Deserialized output of `findmnt --json`. #[derive(Deserialize, Debug, Default)] pub struct Findmnt { + /// The list of mounted filesystems. pub filesystems: Vec, } +/// Run `findmnt` with JSON output and parse the result. pub fn run_findmnt(args: &[&str], cwd: Option<&Dir>, path: Option<&str>) -> Result { let mut cmd = Command::new("findmnt"); if let Some(cwd) = cwd { @@ -99,8 +111,8 @@ pub fn inspect_filesystem_by_uuid(uuid: &str) -> Result { findmnt_filesystem(&["--source"], None, &(format!("UUID={uuid}"))) } -// Check if a specified device contains an already mounted filesystem -// in the root mount namespace +/// Check if a specified device contains an already mounted filesystem +/// in the root mount namespace. pub fn is_mounted_in_pid1_mountns(path: &str) -> Result { let o = run_findmnt(&["-N"], None, Some("1"))?; @@ -109,7 +121,7 @@ pub fn is_mounted_in_pid1_mountns(path: &str) -> Result { Ok(mounted) } -// Recursively check a given filesystem to see if it contains an already mounted source +/// Recursively check a given filesystem to see if it contains an already mounted source. pub fn is_source_mounted(path: &str, mounted_fs: &Filesystem) -> bool { if mounted_fs.source.contains(path) { return true; @@ -281,8 +293,8 @@ pub fn bind_mount_from_pidns( Ok(()) } -// If the target path is not already mirrored from the host (e.g. via -v /dev:/dev) -// then recursively mount it. +/// If the target path is not already mirrored from the host (e.g. via `-v /dev:/dev`) +/// then recursively mount it. pub fn ensure_mirrored_host_mount(path: impl AsRef) -> Result<()> { let path = path.as_ref(); // If we didn't have this in our filesystem already (e.g. for /var/lib/containers) diff --git a/crates/mount/src/tempmount.rs b/crates/mount/src/tempmount.rs index 702f5a8e3..a72571ad4 100644 --- a/crates/mount/src/tempmount.rs +++ b/crates/mount/src/tempmount.rs @@ -7,8 +7,12 @@ use cap_std_ext::cap_std::{ambient_authority, fs::Dir}; use fn_error_context::context; use rustix::mount::{MountFlags, MoveMountFlags, UnmountFlags, move_mount, unmount}; +/// RAII wrapper for a temporary mount that is automatically unmounted on drop. +#[derive(Debug)] pub struct TempMount { + /// The backing temporary directory. pub dir: tempfile::TempDir, + /// An open handle to the mounted directory. pub fd: Dir, } diff --git a/crates/system-reinstall-bootc/Cargo.toml b/crates/system-reinstall-bootc/Cargo.toml index 417ead91a..921698e54 100644 --- a/crates/system-reinstall-bootc/Cargo.toml +++ b/crates/system-reinstall-bootc/Cargo.toml @@ -15,7 +15,7 @@ platforms = ["*-unknown-linux-gnu"] [dependencies] # Internal crates -bootc-mount = { path = "../mount" } +bootc-mount = { package = "bootc-internal-mount", path = "../mount", version = "0.1.0" } bootc-utils = { package = "bootc-internal-utils", path = "../utils", version = "0.1.0" } # Workspace dependencies