这是indexloc提供的服务,不要输入任何密码
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
236 changes: 236 additions & 0 deletions third_party/move/tools/move-package/src/resolution/git.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,236 @@
// Copyright (c) Aptos Foundation
// SPDX-License-Identifier: Apache-2.0

use crate::source_package::parsed_manifest::PackageName;
use anyhow::bail;
use std::process::{Command, ExitStatus, Stdio};

pub(crate) fn fetch_new_dependency(
git_url: &str,
git_path: &str,
git_rev: &str,
dep_name: PackageName,
) -> anyhow::Result<()> {
deep_clone_repo(git_url, git_path, dep_name)?;
checkout_rev(git_path, git_rev, dep_name)?;
Ok(())
}

pub(crate) fn fetch_new_dependency_shallow(
git_url: &str,
git_path: &str,
git_rev: &str,
dep_name: PackageName,
) -> anyhow::Result<()> {
shallow_clone_repo(git_url, git_path, dep_name)?;

shallow_fetch_latest_origin_rev(git_path, git_rev, dep_name)?;
switch_to_fetched_rev(git_path, git_rev, dep_name)?;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Dependency Fetch Silently Fails

The fetch_new_dependency_shallow function doesn't check the exit status of shallow_fetch_latest_origin_rev and switch_to_fetched_rev. If these git commands fail (non-zero exit code), the function returns Ok(()) instead of an error. This differs from update_dependency_shallow which properly checks the status, creating inconsistent error handling.

Fix in Cursor Fix in Web


Ok(())
}

pub(crate) fn update_dependency(
git_path: &str,
git_rev: &str,
dep_name: PackageName,
) -> anyhow::Result<()> {
let status = fetch_latest_origin_rev(git_path, dep_name)?;
if !status.success() {
return Err(anyhow::anyhow!(
"Failed to fetch to latest Git state for package '{}', to skip set --skip-fetch-latest-git-deps | Exit status: {}",
dep_name,
status
));
}
let status = Command::new("git")
.args([
"-C",
git_path,
"reset",
"--hard",
&format!("origin/{}", git_rev)
])
.stdout(Stdio::null())
.stderr(Stdio::null())
.status()
.map_err(|_| {
anyhow::anyhow!(
"Failed to reset to latest Git state '{}' for package '{}', to skip set --skip-fetch-latest-git-deps",
git_rev,
dep_name
)
})?;
if !status.success() {
return Err(anyhow::anyhow!(
"Failed to reset to latest Git state '{}' for package '{}', to skip set --skip-fetch-latest-git-deps | Exit status: {}",
git_rev,
dep_name,
status
));
}
Ok(())
}

pub(crate) fn update_dependency_shallow(
git_path: &str,
git_rev: &str,
dep_name: PackageName,
) -> anyhow::Result<()> {
// If the current folder exists, do a fetch and reset to ensure that the branch
// is up to date
// NOTE: this means that you must run the package system with a working network connection
let status = shallow_fetch_latest_origin_rev(git_path, git_rev, dep_name)?;
if !status.success() {
return Err(anyhow::anyhow!(
"Failed to fetch to latest Git state for package '{}', to skip set --skip-fetch-latest-git-deps | Exit status: {}",
dep_name,
status
));
}
let status = switch_to_fetched_rev(git_path, git_rev, dep_name)?;
if !status.success() {
return Err(anyhow::anyhow!(
"Failed to reset to latest Git state '{}' for package '{}', to skip set --skip-fetch-latest-git-deps | Exit status: {}",
git_rev,
dep_name,
status
));
}
Ok(())
}

// old version of initial git clone
fn deep_clone_repo(url: &str, repo_path: &str, dep_name: PackageName) -> anyhow::Result<()> {
Command::new("git")
.args(["clone", url, repo_path])
.output()
.map_err(|_| {
anyhow::anyhow!("Failed to clone Git repository for package '{}'", dep_name)
})?;
Ok(())
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Git Clone Errors Go Unnoticed

The deep_clone_repo function uses .output() but doesn't check if the git command succeeded via output.status.success(). If git fails (invalid URL, network error, permission denied), the function returns Ok(()) instead of propagating the error, causing silent failures during dependency cloning.

Fix in Cursor Fix in Web


fn shallow_clone_repo(url: &str, repo_path: &str, package_name: PackageName) -> anyhow::Result<()> {
Command::new("git")
.args(["clone", "--depth", "1", url, repo_path])
.output()
.map_err(|_| {
anyhow::anyhow!(
"Failed to clone Git repository for package '{}'",
package_name
)
})?;
Ok(())
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Git Commands Fail Silently

The shallow_clone_repo function uses .output() but doesn't check if the git command succeeded via output.status.success(). If git fails (invalid URL, network error, permission denied), the function returns Ok(()) instead of propagating the error, causing silent failures during shallow cloning.

Fix in Cursor Fix in Web


// old version of initial git checkout
fn checkout_rev(repo_path: &str, git_rev: &str, dep_name: PackageName) -> anyhow::Result<()> {
Command::new("git")
.args(["-C", repo_path, "checkout", git_rev])
.output()
.map_err(|_| {
anyhow::anyhow!(
"Failed to checkout Git reference '{}' for package '{}'",
git_rev,
dep_name
)
})?;
Ok(())
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Silent Failures in Git Checkout

The checkout_rev function uses .output() but doesn't check if the git command succeeded via output.status.success(). If git checkout fails (invalid ref, detached HEAD issues), the function returns Ok(()) instead of propagating the error, causing silent failures when checking out specific revisions.

Fix in Cursor Fix in Web


// old version of git fetch
fn fetch_latest_origin_rev(repo_path: &str, dep_name: PackageName) -> anyhow::Result<ExitStatus> {
let mut cmd = Command::new("git");
cmd.args(["-C", repo_path, "fetch", "origin"])
.stdout(Stdio::null())
.stderr(Stdio::null());
cmd
.status()
.map_err(|_| {
anyhow::anyhow!(
"Failed to fetch latest Git state for package '{}', to skip set --skip-fetch-latest-git-deps",
dep_name
)
})
}

fn switch_to_fetched_rev(
repo_path: &str,
git_rev: &str,
dep_name: PackageName,
) -> anyhow::Result<ExitStatus> {
let mut cmd = Command::new("git");
cmd.args(["reset", "--hard", "FETCH_HEAD"])
.current_dir(repo_path)
.stdout(Stdio::null())
.stderr(Stdio::null());
let output = cmd
.output()
.map_err(|_| {
anyhow::anyhow!(
"Failed to reset to latest Git state '{}' for package '{}', to skip set --skip-fetch-latest-git-deps",
git_rev,
dep_name
)
})?;
Ok(output.status)
}

fn shallow_fetch_latest_origin_rev(
repo_path: &str,
git_rev: &str,
dep_name: PackageName,
) -> anyhow::Result<ExitStatus> {
let status = Command::new("git")
.args(["fetch", "--depth", "1", "origin", git_rev])
.current_dir(repo_path)
.stdout(Stdio::null())
.stderr(Stdio::null())
.status()
.map_err(|_| {
anyhow::anyhow!(
"Failed to checkout Git reference '{}' for package '{}'",
git_rev,
dep_name
)
})?;
Ok(status)
}

pub(crate) fn confirm_git_available() -> anyhow::Result<()> {
match Command::new("git").arg("--version").output() {
Ok(_) => Ok(()),
Err(e) => {
if let std::io::ErrorKind::NotFound = e.kind() {
bail!(
"git was not found, confirm you have git installed and it is on your PATH. \
Alternatively, skip with --skip-fetch-latest-git-deps"
);
} else {
bail!(
"Unexpected error occurred when checking for presence of `git`: {:#}",
e
);
}
},
}
}

pub(crate) fn get_existing_rev(repo_path: &str, git_rev: &str) -> anyhow::Result<String> {
let output = Command::new("git")
.args(["rev-parse", "--verify", git_rev])
.current_dir(repo_path)
.output()?;
let stdout = String::from_utf8(output.stdout)?;
Ok(stdout.trim().to_string())
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Incorrectly parsing failed command output.

The get_existing_rev function doesn't check output.status.success() before parsing stdout. If git fails (invalid ref, not a git repo), it attempts to parse error output as a valid revision string, potentially returning empty strings or error messages instead of failing properly.

Fix in Cursor Fix in Web


pub(crate) fn get_existing_tag(repo_path: &str, git_rev: &str) -> anyhow::Result<String> {
let output = Command::new("git")
.args(["tag", "--list", git_rev])
.current_dir(repo_path)
.output()?;
let stdout = String::from_utf8(output.stdout)?;
Ok(stdout.trim().to_string())
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Confusing Git Errors for Valid Tags

The get_existing_tag function doesn't check output.status.success() before parsing stdout. If git fails (not a git repo, command error), it attempts to parse error output as a valid tag string, potentially returning empty strings or error messages instead of failing properly.

Fix in Cursor Fix in Web

1 change: 1 addition & 0 deletions third_party/move/tools/move-package/src/resolution/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@
// SPDX-License-Identifier: Apache-2.0

mod digest;
pub(crate) mod git;
pub mod resolution_graph;
Loading
Loading