Skip to content

Commit

Permalink
Auto merge of #13960 - tweag:issue-13695, r=weihanglo
Browse files Browse the repository at this point in the history
Include vcs_info even if workspace is dirty

### What does this PR try to resolve?

Related to #13695.

Generates and packages the `.cargo_vcs_info.json` file even if the worktree is dirty, as long as `--allow-dirty` is passed.

Also added a `dirty` field to the file to record if the Git repository status is dirty.

Tests are included.
  • Loading branch information
bors committed Jun 24, 2024
2 parents e18afe2 + e7bfed1 commit 95d16be
Show file tree
Hide file tree
Showing 8 changed files with 162 additions and 26 deletions.
34 changes: 20 additions & 14 deletions src/cargo/ops/cargo_package.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,9 @@ struct VcsInfo {
#[derive(Serialize)]
struct GitVcsInfo {
sha1: String,
/// Indicate whether or not the Git worktree is dirty.
#[serde(skip_serializing_if = "std::ops::Not::not")]
dirty: bool,
}

/// Packages a single package in a workspace, returning the resulting tar file.
Expand Down Expand Up @@ -235,14 +238,8 @@ fn prepare_archive(
}
let src_files = src.list_files(pkg)?;

// Check (git) repository state, getting the current commit hash if not
// dirty.
let vcs_info = if !opts.allow_dirty {
// This will error if a dirty repo is found.
check_repo_state(pkg, &src_files, gctx)?
} else {
None
};
// Check (git) repository state, getting the current commit hash.
let vcs_info = check_repo_state(pkg, &src_files, gctx, &opts)?;

build_ar_list(ws, pkg, src_files, vcs_info)
}
Expand Down Expand Up @@ -559,13 +556,15 @@ fn check_metadata(pkg: &Package, gctx: &GlobalContext) -> CargoResult<()> {
}

/// Checks if the package source is in a *git* DVCS repository. If *git*, and
/// the source is *dirty* (e.g., has uncommitted changes) then `bail!` with an
/// informative message. Otherwise return the sha1 hash of the current *HEAD*
/// commit, or `None` if no repo is found.
/// the source is *dirty* (e.g., has uncommitted changes), and `--allow-dirty`
/// has not been passed, then `bail!` with an informative message. Otherwise
/// return the sha1 hash of the current *HEAD* commit, or `None` if no repo is
/// found.
fn check_repo_state(
p: &Package,
src_files: &[PathBuf],
gctx: &GlobalContext,
opts: &PackageOpts<'_>,
) -> CargoResult<Option<VcsInfo>> {
if let Ok(repo) = git2::Repository::discover(p.root()) {
if let Some(workdir) = repo.workdir() {
Expand All @@ -585,7 +584,7 @@ fn check_repo_state(
.unwrap_or("")
.replace("\\", "/");
return Ok(Some(VcsInfo {
git: git(p, src_files, &repo)?,
git: git(p, src_files, &repo, &opts)?,
path_in_vcs,
}));
}
Expand All @@ -608,7 +607,12 @@ fn check_repo_state(
// directory is dirty or not, thus we have to assume that it's clean.
return Ok(None);

fn git(p: &Package, src_files: &[PathBuf], repo: &git2::Repository) -> CargoResult<GitVcsInfo> {
fn git(
p: &Package,
src_files: &[PathBuf],
repo: &git2::Repository,
opts: &PackageOpts<'_>,
) -> CargoResult<GitVcsInfo> {
// This is a collection of any dirty or untracked files. This covers:
// - new/modified/deleted/renamed/type change (index or worktree)
// - untracked files (which are "new" worktree files)
Expand All @@ -633,10 +637,12 @@ fn check_repo_state(
.to_string()
})
.collect();
if dirty_src_files.is_empty() {
let dirty = !dirty_src_files.is_empty();
if !dirty || opts.allow_dirty {
let rev_obj = repo.revparse_single("HEAD")?;
Ok(GitVcsInfo {
sha1: rev_obj.id().to_string(),
dirty,
})
} else {
anyhow::bail!(
Expand Down
10 changes: 7 additions & 3 deletions src/doc/man/cargo-package.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ steps:
executable binary or example target. {{man "cargo-install" 1}} will use the
packaged lock file if the `--locked` flag is used.
- A `.cargo_vcs_info.json` file is included that contains information
about the current VCS checkout hash if available (not included with
`--allow-dirty`).
about the current VCS checkout hash if available, as well as a flag if the
worktree is dirty.
3. Extract the `.crate` file and build it to verify it can build.
- This will rebuild your package from scratch to ensure that it can be
built from a pristine state. The `--no-verify` flag can be used to skip
Expand All @@ -52,12 +52,16 @@ Will generate a `.cargo_vcs_info.json` in the following format
```javascript
{
"git": {
"sha1": "aac20b6e7e543e6dd4118b246c77225e3a3a1302"
"sha1": "aac20b6e7e543e6dd4118b246c77225e3a3a1302",
"dirty": true
},
"path_in_vcs": ""
}
```

`dirty` indicates that the Git worktree was dirty when the package
was built.

`path_in_vcs` will be set to a repo-relative path for packages
in subdirectories of the version control repository.

Expand Down
10 changes: 7 additions & 3 deletions src/doc/man/generated_txt/cargo-package.txt
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ DESCRIPTION
packaged lock file if the --locked flag is used.

o A .cargo_vcs_info.json file is included that contains information
about the current VCS checkout hash if available (not included
with --allow-dirty).
about the current VCS checkout hash if available, as well as a
flag if the worktree is dirty.

3. Extract the .crate file and build it to verify it can build.
o This will rebuild your package from scratch to ensure that it can
Expand All @@ -51,11 +51,15 @@ DESCRIPTION

{
"git": {
"sha1": "aac20b6e7e543e6dd4118b246c77225e3a3a1302"
"sha1": "aac20b6e7e543e6dd4118b246c77225e3a3a1302",
"dirty": true
},
"path_in_vcs": ""
}

dirty indicates that the Git worktree was dirty when the package was
built.

path_in_vcs will be set to a repo-relative path for packages in
subdirectories of the version control repository.

Expand Down
10 changes: 7 additions & 3 deletions src/doc/src/commands/cargo-package.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ steps:
executable binary or example target. [cargo-install(1)](cargo-install.html) will use the
packaged lock file if the `--locked` flag is used.
- A `.cargo_vcs_info.json` file is included that contains information
about the current VCS checkout hash if available (not included with
`--allow-dirty`).
about the current VCS checkout hash if available, as well as a flag if the
worktree is dirty.
3. Extract the `.crate` file and build it to verify it can build.
- This will rebuild your package from scratch to ensure that it can be
built from a pristine state. The `--no-verify` flag can be used to skip
Expand All @@ -47,12 +47,16 @@ Will generate a `.cargo_vcs_info.json` in the following format
```javascript
{
"git": {
"sha1": "aac20b6e7e543e6dd4118b246c77225e3a3a1302"
"sha1": "aac20b6e7e543e6dd4118b246c77225e3a3a1302",
"dirty": true
},
"path_in_vcs": ""
}
```

`dirty` indicates that the Git worktree was dirty when the package
was built.

`path_in_vcs` will be set to a repo-relative path for packages
in subdirectories of the version control repository.

Expand Down
10 changes: 7 additions & 3 deletions src/etc/man/cargo-package.1
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ packaged lock file if the \fB\-\-locked\fR flag is used.
.sp
.RS 4
\h'-04'\(bu\h'+02'A \fB\&.cargo_vcs_info.json\fR file is included that contains information
about the current VCS checkout hash if available (not included with
\fB\-\-allow\-dirty\fR).
about the current VCS checkout hash if available, as well as a flag if the
worktree is dirty.
.RE
.RE
.sp
Expand Down Expand Up @@ -74,13 +74,17 @@ Will generate a \fB\&.cargo_vcs_info.json\fR in the following format
.nf
{
"git": {
"sha1": "aac20b6e7e543e6dd4118b246c77225e3a3a1302"
"sha1": "aac20b6e7e543e6dd4118b246c77225e3a3a1302",
"dirty": true
},
"path_in_vcs": ""
}
.fi
.RE
.sp
\fBdirty\fR indicates that the Git worktree was dirty when the package
was built.
.sp
\fBpath_in_vcs\fR will be set to a repo\-relative path for packages
in subdirectories of the version control repository.
.sp
Expand Down
1 change: 1 addition & 0 deletions tests/testsuite/git.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2610,6 +2610,7 @@ fn include_overrides_gitignore() {
p.cargo("package --list --allow-dirty")
.with_stdout(
"\
.cargo_vcs_info.json
Cargo.toml
Cargo.toml.orig
ignored.txt
Expand Down
112 changes: 112 additions & 0 deletions tests/testsuite/package.rs
Original file line number Diff line number Diff line change
Expand Up @@ -703,6 +703,7 @@ fn no_duplicates_from_modified_tracked_files() {
p.cargo("package --list --allow-dirty")
.with_stdout(
"\
.cargo_vcs_info.json
Cargo.lock
Cargo.toml
Cargo.toml.orig
Expand Down Expand Up @@ -1011,6 +1012,7 @@ src/main.rs
.with_stderr("")
.with_stdout(
"\
.cargo_vcs_info.json
.gitignore
Cargo.lock
Cargo.toml
Expand Down Expand Up @@ -1171,6 +1173,111 @@ src/lib.rs
.run();
}

#[cargo_test]
fn issue_13695_allow_dirty_vcs_info() {
let p = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.1.0"
edition = "2015"
description = "foo"
license = "foo"
documentation = "foo"
"#,
)
.file("src/lib.rs", "")
.build();

let repo = git::init(&p.root());
// Initial commit, with no files added.
git::commit(&repo);

// Allowing a dirty worktree results in the vcs file still being included.
p.cargo("package --allow-dirty").run();

let f = File::open(&p.root().join("target/package/foo-0.1.0.crate")).unwrap();
validate_crate_contents(
f,
"foo-0.1.0.crate",
&[
".cargo_vcs_info.json",
"Cargo.toml",
"Cargo.toml.orig",
"src/lib.rs",
],
&[(
".cargo_vcs_info.json",
r#"{
"git": {
"sha1": "[..]",
"dirty": true
},
"path_in_vcs": ""
}"#,
)],
);

// Listing provides a consistent result.
p.cargo("package --list --allow-dirty")
.with_stderr("")
.with_stdout(
"\
.cargo_vcs_info.json
Cargo.toml
Cargo.toml.orig
src/lib.rs
",
)
.run();
}

#[cargo_test]
fn issue_13695_allowing_dirty_vcs_info_but_clean() {
let p = project().build();
let _ = git::repo(&paths::root().join("foo"))
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.1.0"
edition = "2015"
description = "foo"
license = "foo"
documentation = "foo"
"#,
)
.file("src/lib.rs", "")
.build();

// Allowing a dirty worktree despite it being clean.
p.cargo("package --allow-dirty").run();

let f = File::open(&p.root().join("target/package/foo-0.1.0.crate")).unwrap();
validate_crate_contents(
f,
"foo-0.1.0.crate",
&[
".cargo_vcs_info.json",
"Cargo.toml",
"Cargo.toml.orig",
"src/lib.rs",
],
&[(
".cargo_vcs_info.json",
r#"{
"git": {
"sha1": "[..]"
},
"path_in_vcs": ""
}"#,
)],
);
}

#[cargo_test]
fn generated_manifest() {
let registry = registry::alt_init();
Expand Down Expand Up @@ -2333,6 +2440,7 @@ fn finds_git_in_parent() {
p.cargo("package --list --allow-dirty")
.with_stdout(
"\
.cargo_vcs_info.json
Cargo.toml
Cargo.toml.orig
ignoreme
Expand All @@ -2346,6 +2454,7 @@ src/lib.rs
p.cargo("package --list --allow-dirty")
.with_stdout(
"\
.cargo_vcs_info.json
.gitignore
Cargo.toml
Cargo.toml.orig
Expand All @@ -2359,6 +2468,7 @@ src/lib.rs
p.cargo("package --list --allow-dirty")
.with_stdout(
"\
.cargo_vcs_info.json
.gitignore
Cargo.toml
Cargo.toml.orig
Expand Down Expand Up @@ -2621,6 +2731,7 @@ fn deleted_git_working_tree() {
p.cargo("package --allow-dirty --list")
.with_stdout(
"\
.cargo_vcs_info.json
Cargo.lock
Cargo.toml
Cargo.toml.orig
Expand All @@ -2635,6 +2746,7 @@ src/main.rs
p.cargo("package --allow-dirty --list")
.with_stdout(
"\
.cargo_vcs_info.json
Cargo.lock
Cargo.toml
Cargo.toml.orig
Expand Down
1 change: 1 addition & 0 deletions tests/testsuite/publish_lockfile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,7 @@ fn note_resolve_changes() {
[NOTE] package `multi v0.1.0` added to the packaged Cargo.lock file, was originally sourced from `[..]/foo/multi`
[NOTE] package `patched v1.0.0` added to the packaged Cargo.lock file, was originally sourced from `[..]/foo/patched`
[PACKAGED] [..] files, [..] ([..] compressed)
[WARNING] no (git) Cargo.toml found at `target/tmp/[..]/foo/Cargo.toml` in workdir `[..]`
",
)
.run();
Expand Down

0 comments on commit 95d16be

Please sign in to comment.