Skip to content

Commit

Permalink
Merge pull request #274 from helsing-ai/vsiles/mtime
Browse files Browse the repository at this point in the history
Keeping files "last modified" time to enable change detection in build.rs
  • Loading branch information
vsiles authored Dec 10, 2024
2 parents e4c0c77 + c920bbc commit 2a14b6e
Show file tree
Hide file tree
Showing 6 changed files with 210 additions and 79 deletions.
1 change: 0 additions & 1 deletion flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
rust-overlay = {
url = "github:oxalica/rust-overlay";
inputs.nixpkgs.follows = "nixpkgs";
inputs.flake-utils.follows = "flake-utils";
};
advisory-db = {
url = "github:rustsec/advisory-db";
Expand Down
23 changes: 16 additions & 7 deletions src/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,7 @@ pub async fn package(
directory: impl AsRef<Path>,
dry_run: bool,
version: Option<Version>,
preserve_mtime: bool,
) -> miette::Result<()> {
let mut manifest = Manifest::read().await?;
let store = PackageStore::current().await?;
Expand All @@ -248,7 +249,7 @@ pub async fn package(
store.populate(pkg).await?;
}

let package = store.release(&manifest).await?;
let package = store.release(&manifest, preserve_mtime).await?;

if dry_run {
return Ok(());
Expand All @@ -275,6 +276,7 @@ pub async fn publish(
#[cfg(feature = "git")] allow_dirty: bool,
dry_run: bool,
version: Option<Version>,
preserve_mtime: bool,
) -> miette::Result<()> {
#[cfg(feature = "git")]
async fn git_statuses() -> miette::Result<Vec<String>> {
Expand Down Expand Up @@ -345,7 +347,7 @@ pub async fn publish(
store.populate(pkg).await?;
}

let package = store.release(&manifest).await?;
let package = store.release(&manifest, preserve_mtime).await?;

if dry_run {
tracing::warn!(":: aborting upload due to dry run");
Expand All @@ -356,7 +358,9 @@ pub async fn publish(
}

/// Installs dependencies
pub async fn install() -> miette::Result<()> {
///
/// if [preserve_mtime] is true, local dependencies will keep their modification time
pub async fn install(preserve_mtime: bool) -> miette::Result<()> {
let manifest = Manifest::read().await?;
let lockfile = Lockfile::read_or_default().await?;
let store = PackageStore::current().await?;
Expand All @@ -371,10 +375,15 @@ pub async fn install() -> miette::Result<()> {
tracing::info!(":: installed {}@{}", pkg.name, pkg.version);
}

let dependency_graph =
DependencyGraph::from_manifest(&manifest, &lockfile, &credentials.into(), &cache)
.await
.wrap_err(miette!("dependency resolution failed"))?;
let dependency_graph = DependencyGraph::from_manifest(
&manifest,
&lockfile,
&credentials.into(),
&cache,
preserve_mtime,
)
.await
.wrap_err(miette!("dependency resolution failed"))?;

let mut locked = Vec::new();

Expand Down
37 changes: 30 additions & 7 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,10 @@ enum Command {
/// Note: This overrides the version in the manifest.
#[clap(long)]
set_version: Option<Version>,
/// Indicate whether access time information is preserved when creating a package.
/// Default is 'true'
#[clap(long)]
preserve_mtime: Option<bool>,
},

/// Packages and uploads this api to the registry
Expand All @@ -115,10 +119,19 @@ enum Command {
/// Note: This overrides the version in the manifest.
#[clap(long)]
set_version: Option<Version>,
/// Indicate whether access time information is preserved when creating a package.
/// Default is 'true'
#[clap(long)]
preserve_mtime: Option<bool>,
},

/// Installs dependencies
Install,
Install {
/// Indicate whether access time information is preserved when installing a local.
/// Default is 'true'
#[clap(long)]
preserve_local_mtime: Option<bool>,
},
/// Uninstalls dependencies
Uninstall,

Expand Down Expand Up @@ -229,23 +242,31 @@ async fn main() -> miette::Result<()> {
output_directory,
dry_run,
set_version,
} => command::package(output_directory, dry_run, set_version)
.await
.wrap_err(miette!(
"failed to export `{package}` into the buffrs package format"
)),
preserve_mtime,
} => command::package(
output_directory,
dry_run,
set_version,
preserve_mtime.unwrap_or(true),
)
.await
.wrap_err(miette!(
"failed to export `{package}` into the buffrs package format"
)),
Command::Publish {
registry,
repository,
allow_dirty,
dry_run,
set_version,
preserve_mtime,
} => command::publish(
registry.to_owned(),
repository.to_owned(),
allow_dirty,
dry_run,
set_version,
preserve_mtime.unwrap_or(true),
)
.await
.wrap_err(miette!(
Expand All @@ -255,7 +276,9 @@ async fn main() -> miette::Result<()> {
"failed to lint protocol buffers in `{}`",
PackageStore::PROTO_PATH
)),
Command::Install => command::install()
Command::Install {
preserve_local_mtime,
} => command::install(preserve_local_mtime.unwrap_or(true))
.await
.wrap_err(miette!("failed to install dependencies for `{package}`")),
Command::Uninstall => command::uninstall()
Expand Down
26 changes: 24 additions & 2 deletions src/package/compressed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ use std::{
collections::BTreeMap,
io::{self, Cursor, Read, Write},
path::{Path, PathBuf},
time::UNIX_EPOCH,
};

use bytes::{Buf, Bytes};
Expand All @@ -32,6 +33,8 @@ use crate::{
ManagedFile,
};

use super::store::Entry;

/// An in memory representation of a `buffrs` package
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Package {
Expand All @@ -46,7 +49,11 @@ impl Package {
///
/// This intentionally uses a [`BTreeMap`] to ensure that the list of files is sorted
/// lexicographically. This ensures a reproducible output.
pub fn create(mut manifest: Manifest, files: BTreeMap<PathBuf, Bytes>) -> miette::Result<Self> {
pub fn create(
mut manifest: Manifest,
files: BTreeMap<PathBuf, Entry>,
preserve_mtime: bool,
) -> miette::Result<Self> {
if manifest.edition == Edition::Unknown {
manifest = Manifest::new(manifest.package, manifest.dependencies);
}
Expand Down Expand Up @@ -88,8 +95,23 @@ impl Package {
.into_diagnostic()
.wrap_err(miette!("failed to add manifest to release"))?;

for (name, contents) in &files {
for (name, entry) in &files {
let mut header = tar::Header::new_gnu();

let Entry { contents, metadata } = entry;

if preserve_mtime {
let mtime = metadata
.as_ref()
.and_then(|metadata| metadata.modified().ok())
.and_then(|modified| modified.duration_since(UNIX_EPOCH).ok())
.map(|duration| duration.as_secs());

if let Some(mtime) = mtime {
header.set_mtime(mtime);
}
}

header.set_mode(0o444);
header.set_size(contents.len() as u64);
archive
Expand Down
25 changes: 22 additions & 3 deletions src/package/store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ use std::{
path::{Path, PathBuf},
};

use bytes::Bytes;
use miette::{bail, ensure, miette, Context, IntoDiagnostic};
use tokio::fs;
use walkdir::WalkDir;
Expand Down Expand Up @@ -151,7 +152,11 @@ impl PackageStore {
}

/// Packages a release from the local file system state
pub async fn release(&self, manifest: &Manifest) -> miette::Result<Package> {
pub async fn release(
&self,
manifest: &Manifest,
preserve_mtime: bool,
) -> miette::Result<Package> {
for dependency in manifest.dependencies.iter() {
let resolved = self.resolve(&dependency.package).await?;

Expand All @@ -171,10 +176,17 @@ impl PackageStore {
for entry in self.collect(&pkg_path, false).await {
let path = entry.strip_prefix(&pkg_path).into_diagnostic()?;
let contents = tokio::fs::read(&entry).await.unwrap();
entries.insert(path.into(), contents.into());

entries.insert(
path.into(),
Entry {
contents: contents.into(),
metadata: tokio::fs::metadata(&entry).await.ok(),
},
);
}

let package = Package::create(manifest.clone(), entries)?;
let package = Package::create(manifest.clone(), entries, preserve_mtime)?;

tracing::info!(":: packaged {}@{}", package.name(), package.version());

Expand Down Expand Up @@ -260,6 +272,13 @@ impl PackageStore {
}
}

pub struct Entry {
/// Actual bytes of the file
pub contents: Bytes,
/// File metadata, like mtime, ...
pub metadata: Option<std::fs::Metadata>,
}

#[test]
fn can_get_proto_path() {
assert_eq!(
Expand Down
Loading

0 comments on commit 2a14b6e

Please sign in to comment.