From 238e02fc67c6702b9db7a9ee5f7279d60b3746dc Mon Sep 17 00:00:00 2001 From: Mario Date: Sat, 17 Aug 2024 03:02:12 -0400 Subject: [PATCH 1/6] Using git branch, tag to pull dependencies --- src/commands.rs | 14 +- src/config.rs | 341 ++++++++++++++++++++++++++++------- src/dependency_downloader.rs | 90 +++++---- src/lib.rs | 194 ++++++++++++++++++++ test/emptyfile | 1 + test/emptyfile2 | 0 tests/ci/foundry.rs | 2 + 7 files changed, 545 insertions(+), 97 deletions(-) delete mode 100644 test/emptyfile2 diff --git a/src/commands.rs b/src/commands.rs index a859c9a..2a8ea53 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -50,7 +50,11 @@ You can install a dependency from the Soldeer repository, a custom URL pointing - **Example from Git:** soldeer install @openzeppelin-contracts~2.3.0 git@github.com:OpenZeppelin/openzeppelin-contracts.git - **Example from Git with a specified commit:** - soldeer install @openzeppelin-contracts~2.3.0 git@github.com:OpenZeppelin/openzeppelin-contracts.git --rev 05f218fb6617932e56bf5388c3b389c3028a7b73", + soldeer install @openzeppelin-contracts~2.3.0 git@github.com:OpenZeppelin/openzeppelin-contracts.git --rev 05f218fb6617932e56bf5388c3b389c3028a7b73 + - **Example from Git with a specified tag:** + soldeer install @openzeppelin-contracts~2.3.0 git@github.com:OpenZeppelin/openzeppelin-contracts.git --tag my-tag + - **Example from Git with a specified branch:** + soldeer install @openzeppelin-contracts~2.3.0 git@github.com:OpenZeppelin/openzeppelin-contracts.git --branch my-branch", after_help = "For more information, read the README.md" )] pub struct Install { @@ -70,6 +74,14 @@ pub struct Install { #[arg(long)] pub rev: Option, + /// The tag of the dependency, if from Git + #[arg(long)] + pub tag: Option, + + /// The branch of the dependency, if from Git + #[arg(long)] + pub branch: Option, + /// If set, this command will delete the existing remappings and re-create them #[arg(short = 'g', long, default_value_t = false)] pub regenerate_remappings: bool, diff --git a/src/config.rs b/src/config.rs index f7133c3..c41215e 100644 --- a/src/config.rs +++ b/src/config.rs @@ -70,6 +70,8 @@ pub struct GitDependency { pub version: String, pub git: String, pub rev: Option, + pub tag: Option, + pub branch: Option, } impl core::fmt::Display for GitDependency { @@ -144,48 +146,49 @@ impl Dependency { None => value(&dep.version), }, ), - Dependency::Git(dep) => ( - dep.name.clone(), - match &dep.rev { - Some(rev) => { - let mut table = InlineTable::new(); + Dependency::Git(dep) => { + let mut table = InlineTable::new(); + table.insert( + "version", + value(&dep.version).into_value().expect("version should be a valid toml value"), + ); + table.insert( + "git", + value(&dep.git).into_value().expect("git URL should be a valid toml value"), + ); + + match &dep.tag { + Some(tag) => { table.insert( - "version", - value(&dep.version) - .into_value() - .expect("version should be a valid toml value"), + "tag", + value(tag).into_value().expect("tag should be a valid toml value"), ); - table.insert( - "git", - value(&dep.git) - .into_value() - .expect("git URL should be a valid toml value"), - ); - table.insert( - "rev", - value(rev).into_value().expect("rev should be a valid toml value"), - ); - value(table) } - None => { - let mut table = InlineTable::new(); - table.insert( - "version", - value(&dep.version) - .into_value() - .expect("version should be a valid toml value"), - ); - table.insert( - "git", - value(&dep.git) - .into_value() - .expect("git URL should be a valid toml value"), - ); - - value(table) - } - }, - ), + None => match &dep.branch { + Some(branch) => { + table.insert( + "branch", + value(branch) + .into_value() + .expect("branch should be a valid toml value"), + ); + } + None => match &dep.rev { + Some(rev) => { + table.insert( + "rev", + value(rev) + .into_value() + .expect("rev should be a valid toml value"), + ); + } + None => {} + }, + }, + }; + + (dep.name.clone(), value(table)) + } } } @@ -454,29 +457,6 @@ fn parse_dependency(name: impl Into, value: &Item) -> Result ); } - // else if value.is_inline_table() && // TODO: Hacky way of doing this, might need rewritten - // !value.as_inline_table().unwrap().contains_key("url") && - // !value.as_inline_table().unwrap().contains_key("git") - // { - // // this function does not retrieve the url, only version - // return Ok(HttpDependency { - // name: name.clone(), - // version: match value.as_inline_table() { - // // we normalize to inline table - // Some(table) => { - // let version = table.get("version").unwrap().to_string(); - // version.replace("\"", "").trim().to_string() - // } - // None => { - // return Err(ConfigError::InvalidDependency(name)); - // } - // }, - // url: None, - // checksum: None, - // } - // .into()); - // } - // we should have a table or inline table let table = { match value.as_inline_table() { @@ -516,11 +496,32 @@ fn parse_dependency(name: impl Into, value: &Item) -> Result } None => None, }; + + let tag = match table.get("tag").map(|v| v.as_str()) { + Some(Some(tag)) => Some(tag.to_string()), + Some(None) => { + return Err(ConfigError::InvalidField { field: "tag".to_string(), dep: name }); + } + None => None, + }; + + let branch = match table.get("branch").map(|v| v.as_str()) { + Some(Some(tag)) => Some(tag.to_string()), + Some(None) => { + return Err(ConfigError::InvalidField { + field: "branch".to_string(), + dep: name, + }); + } + None => None, + }; return Ok(Dependency::Git(GitDependency { name: name.to_string(), git: git.to_string(), version, rev, + tag, + branch, })); } None => {} @@ -1442,6 +1443,8 @@ gas_reports = ['*'] version: "1.0.0".to_string(), git: "git@github.com:foundry-rs/forge-std.git".to_string(), rev: Some("07263d193d621c4b2b0ce8b4d54af58f6957d97d".to_string()), + tag: None, + branch: None, }); add_to_config(&dependency, &target_config).unwrap(); @@ -1459,6 +1462,218 @@ gas_reports = ['*'] [dependencies] dep1 = { version = "1.0.0", git = "git@github.com:foundry-rs/forge-std.git", rev = "07263d193d621c4b2b0ce8b4d54af58f6957d97d" } +# we don't have [dependencies] declared +"#; + + assert_eq!(read_file_to_string(&target_config), content); + + let _ = remove_file(target_config); + Ok(()) + } + + #[test] + fn add_to_config_foundry_github_with_tag() -> Result<()> { + let mut content = r#" +# Full reference https://github.com/foundry-rs/foundry/tree/master/crates/config + +[profile.default] +script = "script" +solc = "0.8.26" +src = "src" +test = "test" +libs = ["dependencies"] +gas_reports = ['*'] + +# we don't have [dependencies] declared +"#; + + let target_config = define_config(true); + + write_to_config(&target_config, content); + + let dependency = Dependency::Git(GitDependency { + name: "dep1".to_string(), + version: "1.0.0".to_string(), + git: "https://gitlab.com/mario4582928/Mario.git".to_string(), + rev: None, + tag: Some("custom-tag".to_string()), + branch: None, + }); + + add_to_config(&dependency, &target_config).unwrap(); + content = r#" +# Full reference https://github.com/foundry-rs/foundry/tree/master/crates/config + +[profile.default] +script = "script" +solc = "0.8.26" +src = "src" +test = "test" +libs = ["dependencies"] +gas_reports = ['*'] + +[dependencies] +dep1 = { version = "1.0.0", git = "https://gitlab.com/mario4582928/Mario.git", tag = "custom-tag" } + +# we don't have [dependencies] declared +"#; + + assert_eq!(read_file_to_string(&target_config), content); + + let _ = remove_file(target_config); + Ok(()) + } + + #[test] + fn add_to_config_foundry_github_with_tag_when_revision_present() -> Result<()> { + let mut content = r#" +# Full reference https://github.com/foundry-rs/foundry/tree/master/crates/config + +[profile.default] +script = "script" +solc = "0.8.26" +src = "src" +test = "test" +libs = ["dependencies"] +gas_reports = ['*'] + +# we don't have [dependencies] declared +"#; + + let target_config = define_config(true); + + write_to_config(&target_config, content); + + let dependency = Dependency::Git(GitDependency { + name: "dep1".to_string(), + version: "1.0.0".to_string(), + git: "https://gitlab.com/mario4582928/Mario.git".to_string(), + rev: Some("22868f426bd4dd0e682b5ec5f9bd55507664240c".to_string()), + tag: Some("custom-tag".to_string()), + branch: None, + }); + + add_to_config(&dependency, &target_config).unwrap(); + content = r#" +# Full reference https://github.com/foundry-rs/foundry/tree/master/crates/config + +[profile.default] +script = "script" +solc = "0.8.26" +src = "src" +test = "test" +libs = ["dependencies"] +gas_reports = ['*'] + +[dependencies] +dep1 = { version = "1.0.0", git = "https://gitlab.com/mario4582928/Mario.git", tag = "custom-tag" } + +# we don't have [dependencies] declared +"#; + + assert_eq!(read_file_to_string(&target_config), content); + + let _ = remove_file(target_config); + Ok(()) + } + + #[test] + fn add_to_config_foundry_github_with_branch() -> Result<()> { + let mut content = r#" +# Full reference https://github.com/foundry-rs/foundry/tree/master/crates/config + +[profile.default] +script = "script" +solc = "0.8.26" +src = "src" +test = "test" +libs = ["dependencies"] +gas_reports = ['*'] + +# we don't have [dependencies] declared +"#; + + let target_config = define_config(true); + + write_to_config(&target_config, content); + + let dependency = Dependency::Git(GitDependency { + name: "dep1".to_string(), + version: "1.0.0".to_string(), + git: "https://gitlab.com/mario4582928/Mario.git".to_string(), + rev: None, + tag: None, + branch: Some("custom-branch".to_string()), + }); + + add_to_config(&dependency, &target_config).unwrap(); + content = r#" +# Full reference https://github.com/foundry-rs/foundry/tree/master/crates/config + +[profile.default] +script = "script" +solc = "0.8.26" +src = "src" +test = "test" +libs = ["dependencies"] +gas_reports = ['*'] + +[dependencies] +dep1 = { version = "1.0.0", git = "https://gitlab.com/mario4582928/Mario.git", branch = "custom-branch" } + +# we don't have [dependencies] declared +"#; + + assert_eq!(read_file_to_string(&target_config), content); + + let _ = remove_file(target_config); + Ok(()) + } + + #[test] + fn add_to_config_foundry_github_with_rev_tag_branch() -> Result<()> { + let mut content = r#" +# Full reference https://github.com/foundry-rs/foundry/tree/master/crates/config + +[profile.default] +script = "script" +solc = "0.8.26" +src = "src" +test = "test" +libs = ["dependencies"] +gas_reports = ['*'] + +# we don't have [dependencies] declared +"#; + + let target_config = define_config(true); + + write_to_config(&target_config, content); + + let dependency = Dependency::Git(GitDependency { + name: "dep1".to_string(), + version: "1.0.0".to_string(), + git: "https://gitlab.com/mario4582928/Mario.git".to_string(), + rev: Some("custom-rev".to_string()), + tag: Some("custom-tag".to_string()), + branch: Some("custom-branch".to_string()), + }); + + add_to_config(&dependency, &target_config).unwrap(); + content = r#" +# Full reference https://github.com/foundry-rs/foundry/tree/master/crates/config + +[profile.default] +script = "script" +solc = "0.8.26" +src = "src" +test = "test" +libs = ["dependencies"] +gas_reports = ['*'] + +[dependencies] +dep1 = { version = "1.0.0", git = "https://gitlab.com/mario4582928/Mario.git", tag = "custom-tag" } + # we don't have [dependencies] declared "#; @@ -1496,6 +1711,8 @@ dep1 = { version = "1.0.0", git = "git@github.com:foundry-rs/forge-std.git" } version: "1.0.0".to_string(), git: "git@github.com:foundry-rs/forge-std.git".to_string(), rev: Some("07263d193d621c4b2b0ce8b4d54af58f6957d97d".to_string()), + tag: None, + branch: None, }); add_to_config(&dependency, &target_config).unwrap(); diff --git a/src/dependency_downloader.rs b/src/dependency_downloader.rs index 04cf751..c07271d 100644 --- a/src/dependency_downloader.rs +++ b/src/dependency_downloader.rs @@ -195,60 +195,70 @@ async fn download_via_git( )); } - let rev = match dependency.rev.clone() { - Some(rev) => { - let mut git_get_commit = Command::new("git"); - let result = git_get_commit - .args(["checkout".to_string(), rev.to_string()]) - .env("GIT_TERMINAL_PROMPT", "0") - .current_dir(&path) - .stdout(Stdio::piped()) - .stderr(Stdio::piped()); - - let out = result.output().expect("Checkout to revision status failed"); - let status = result.status().expect("Checkout to revision getting output failed"); + let checkout_target = match dependency.rev.clone() { + Some(rev) => Some(rev), + None => match dependency.tag.clone() { + Some(tag) => Some(tag), + None => match dependency.branch.clone() { + Some(branch) => Some(branch), + None => None, + }, + }, + }; - if !status.success() { - let _ = fs::remove_dir_all(&path); - return Err(DownloadError::GitError( - str::from_utf8(&out.stderr).unwrap().trim().to_string(), - )); - } - rev - } - None => { + match checkout_target.clone() { + Some(target) => { let mut git_checkout = Command::new("git"); - let result = git_checkout - .args(["rev-parse".to_string(), "--verify".to_string(), "HEAD".to_string()]) + .args(["checkout".to_string(), target.to_string()]) .env("GIT_TERMINAL_PROMPT", "0") .current_dir(&path) .stdout(Stdio::piped()) .stderr(Stdio::piped()); - let out = result.output().expect("Getting revision status failed"); - let status = result.status().expect("Getting revision output failed"); + let out = result.output().expect("Checkout status failed"); + let status = result.status().expect("Checkout getting output failed"); + if !status.success() { let _ = fs::remove_dir_all(&path); return Err(DownloadError::GitError( str::from_utf8(&out.stderr).unwrap().trim().to_string(), )); } - - let hash = str::from_utf8(&out.stdout).unwrap().trim().to_string(); - // check the commit hash - if !hash.is_empty() && hash.len() != 40 { - let _ = fs::remove_dir_all(&path); - return Err(DownloadError::GitError(format!("invalid revision hash: {hash}"))); - } - hash } + None => {} }; + + let mut git_checkout = Command::new("git"); + + let result = git_checkout + .args(["rev-parse".to_string(), "--verify".to_string(), "HEAD".to_string()]) + .env("GIT_TERMINAL_PROMPT", "0") + .current_dir(&path) + .stdout(Stdio::piped()) + .stderr(Stdio::piped()); + + let out = result.output().expect("Getting revision status failed"); + let status = result.status().expect("Getting revision output failed"); + if !status.success() { + let _ = fs::remove_dir_all(&path); + return Err(DownloadError::GitError( + str::from_utf8(&out.stderr).unwrap().trim().to_string(), + )); + } + + let hash = str::from_utf8(&out.stdout).unwrap().trim().to_string(); + // check the commit hash + if !hash.is_empty() && hash.len() != 40 { + let _ = fs::remove_dir_all(&path); + return Err(DownloadError::GitError(format!("invalid revision hash: {hash}"))); + } + println!( "{}", format!("Successfully downloaded {} the dependency via git", dependency,).green() ); - Ok(rev) + Ok(hash) } async fn download_via_http( @@ -372,6 +382,8 @@ mod tests { version: "2.3.0".to_string(), git: "https://gitlab.com/mario4582928/Mario.git".to_string(), rev: Some("7a0663eaf7488732f39550be655bad6694974cb3".to_string()), + tag: None, + branch: None, }); dependencies.push(dependency.clone()); let results = download_dependencies(&dependencies, false).await.unwrap(); @@ -401,6 +413,8 @@ mod tests { version: "2.3.0".to_string(), git: "https://gitlab.com/mario4582928/Mario.git".to_string(), rev: None, + tag: None, + branch: None, }); dependencies.push(dependency.clone()); let results = download_dependencies(&dependencies, false).await.unwrap(); @@ -462,6 +476,8 @@ mod tests { version: "2.3.0".to_string(), git: "https://github.com/transmissions11/solmate.git".to_string(), rev: None, + tag: None, + branch: None, }); dependencies.push(dependency_one.clone()); @@ -470,6 +486,8 @@ mod tests { version: "1.0.0-beta.4".to_string(), git: "https://gitlab.com/mario4582928/Mario.git".to_string(), rev: None, + tag: None, + branch: None, }); dependencies.push(dependency_two.clone()); @@ -619,6 +637,8 @@ mod tests { version: "2.3.0".to_string(), git: "git@github.com:transmissions11/solmate-wrong.git".to_string(), rev: None, + tag: None, + branch: None, }); dependencies.push(dependency.clone()); @@ -738,6 +758,8 @@ mod tests { version: "2.3.0".to_string(), git: "https://github.com/transmissions11/solmate.git".to_string(), rev: None, + tag: None, + branch: None, }); dependencies.push(dependency.clone()); diff --git a/src/lib.rs b/src/lib.rs index ec2cb60..1852639 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -82,6 +82,8 @@ pub async fn run(command: Subcommands) -> Result<(), SoldeerError> { version: dependency_version.to_string(), git: url, rev: install.rev, + tag: install.tag, + branch: install.branch, }), UrlType::Http => Dependency::Http(HttpDependency { name: dependency_name.to_string(), @@ -384,6 +386,8 @@ libs = ["dependencies"] dependency: None, remote_url: None, rev: None, + tag: None, + branch: None, regenerate_remappings: false, recursive_deps: false, }); @@ -436,6 +440,8 @@ libs = ["dependencies"] dependency: Some("test~1".to_string()), remote_url: Some("https://gitlab.com/mario4582928/Mario.git".to_string()), rev: None, + tag: None, + branch: None, regenerate_remappings: false, recursive_deps: false, }); @@ -501,6 +507,8 @@ libs = ["dependencies"] dependency: Some("test~1".to_string()), remote_url: Some("https://gitlab.com/mario4582928/Mario.git".to_string()), rev: Some("2fd642069600f0b8da3e1897fad42b2c53c6e927".to_string()), + tag: None, + branch: None, regenerate_remappings: false, recursive_deps: false, }); @@ -567,6 +575,8 @@ libs = ["dependencies"] dependency: None, remote_url: None, rev: None, + tag: None, + branch: None, regenerate_remappings: false, recursive_deps: false, }); @@ -606,6 +616,9 @@ libs = ["dependencies"] forge-std = { version = "1.8.1" } solmate = "6.7.0" mario = { version = "1.0", git = "https://gitlab.com/mario4582928/Mario.git", rev = "22868f426bd4dd0e682b5ec5f9bd55507664240c" } +mario-custom-tag = { version = "1.0", git = "https://gitlab.com/mario4582928/Mario.git", tag = "custom-tag" } +mario-custom-branch = { version = "1.0", git = "https://gitlab.com/mario4582928/Mario.git", tag = "custom-branch" } + "#; let target_config = define_config(true); @@ -803,6 +816,8 @@ libs = ["dependencies"] dependency: None, remote_url: None, rev: None, + tag: None, + branch: None, regenerate_remappings: false, recursive_deps: false, }); @@ -995,6 +1010,8 @@ libs = ["dependencies"] dependency: Some("forge-std~1.9.1".to_string()), remote_url: Option::None, rev: None, + tag: None, + branch: None, regenerate_remappings: false, recursive_deps: false, }); @@ -1051,6 +1068,8 @@ libs = ["dependencies"] dependency: Some("forge-std~1.9.1".to_string()), remote_url: Some("https://soldeer-revisions.s3.amazonaws.com/forge-std/v1_9_0_03-07-2024_14:44:57_forge-std-v1.9.0.zip".to_string()), rev: None, + tag: None, +branch: None, regenerate_remappings: false, recursive_deps: false }); @@ -1107,6 +1126,8 @@ libs = ["dependencies"] dependency: Some("forge-std~1.9.1".to_string()), remote_url: Some("https://github.com/foundry-rs/forge-std.git".to_string()), rev: None, + tag: None, + branch: None, regenerate_remappings: false, recursive_deps: false, }); @@ -1163,6 +1184,8 @@ libs = ["dependencies"] dependency: Some("forge-std~1.9.1".to_string()), remote_url: Some("https://github.com/foundry-rs/forge-std.git".to_string()), rev: None, + tag: None, + branch: None, regenerate_remappings: false, recursive_deps: false, }); @@ -1219,6 +1242,8 @@ libs = ["dependencies"] dependency: Some("forge-std~1.9.1".to_string()), remote_url: Some("https://github.com/foundry-rs/forge-std.git".to_string()), rev: Some("3778c3cb8e4244cb5a1c3ef3ce1c71a3683e324a".to_string()), + tag: None, + branch: None, regenerate_remappings: false, recursive_deps: false, }); @@ -1237,6 +1262,167 @@ libs = ["dependencies"] assert!(!path_dependency.exists()); // this should not exists at that commit path_dependency = DEPENDENCY_DIR.join("forge-std-1.9.1").join("src").join("Test.sol"); assert!(path_dependency.exists()); // this should exists at that commit + + let content = r#" +# Full reference https://github.com/foundry-rs/foundry/tree/master/crates/config + +[profile.default] +script = "script" +solc = "0.8.26" +src = "src" +test = "test" +libs = ["dependencies"] + +[dependencies] +forge-std = { version = "1.9.1", git = "https://github.com/foundry-rs/forge-std.git", rev = "3778c3cb8e4244cb5a1c3ef3ce1c71a3683e324a" } +"#; + assert_eq!(read_file_to_string(&target_config), content); + clean_test_env(target_config); + } + + #[test] + #[serial] + fn install_dependency_custom_git_giturl_custom_tag() { + let _ = remove_dir_all(DEPENDENCY_DIR.clone()); + let _ = remove_file(LOCK_FILE.clone()); + let test_dir = env::current_dir().unwrap().join("test").join("install_http"); + + // Create test directory + if !test_dir.exists() { + std::fs::create_dir(&test_dir).unwrap(); + } + + let content = r#" +# Full reference https://github.com/foundry-rs/foundry/tree/master/crates/config + +[profile.default] +script = "script" +solc = "0.8.26" +src = "src" +test = "test" +libs = ["dependencies"] + +[dependencies] +"#; + + let target_config = define_config(true); + + write_to_config(&target_config, content); + + unsafe { + // became unsafe in Rust 1.80 + env::set_var("base_url", "https://api.soldeer.xyz"); + } + + let command = Subcommands::Install(Install { + dependency: Some("dep~1".to_string()), + remote_url: Some("https://gitlab.com/mario4582928/Mario.git".to_string()), + rev: None, + tag: Some("custom-tag".to_string()), + branch: None, + regenerate_remappings: false, + recursive_deps: false, + }); + + match run(command) { + Ok(_) => {} + Err(err) => { + println!("Error occurred {:?}", err); + clean_test_env(target_config.clone()); + assert_eq!("Invalid State", "") + } + } + + let path_dependency = DEPENDENCY_DIR.join("dep-1").join("CustomTagFileBranch"); + assert!(path_dependency.exists()); // this should exists at that tag + + let content = r#" +# Full reference https://github.com/foundry-rs/foundry/tree/master/crates/config + +[profile.default] +script = "script" +solc = "0.8.26" +src = "src" +test = "test" +libs = ["dependencies"] + +[dependencies] +dep = { version = "1", git = "https://gitlab.com/mario4582928/Mario.git", tag = "custom-tag" } +"#; + assert_eq!(read_file_to_string(&target_config), content); + clean_test_env(target_config); + } + + #[test] + #[serial] + fn install_dependency_custom_git_giturl_custom_branch() { + let _ = remove_dir_all(DEPENDENCY_DIR.clone()); + let _ = remove_file(LOCK_FILE.clone()); + let test_dir = env::current_dir().unwrap().join("test").join("install_http"); + + // Create test directory + if !test_dir.exists() { + std::fs::create_dir(&test_dir).unwrap(); + } + + let content = r#" +# Full reference https://github.com/foundry-rs/foundry/tree/master/crates/config + +[profile.default] +script = "script" +solc = "0.8.26" +src = "src" +test = "test" +libs = ["dependencies"] + +[dependencies] +"#; + + let target_config = define_config(true); + + write_to_config(&target_config, content); + + unsafe { + // became unsafe in Rust 1.80 + env::set_var("base_url", "https://api.soldeer.xyz"); + } + + let command = Subcommands::Install(Install { + dependency: Some("dep~1".to_string()), + remote_url: Some("https://gitlab.com/mario4582928/Mario.git".to_string()), + rev: None, + tag: None, + branch: Some("custom-branch".to_string()), + regenerate_remappings: false, + recursive_deps: false, + }); + + match run(command) { + Ok(_) => {} + Err(err) => { + println!("Error occurred {:?}", err); + clean_test_env(target_config.clone()); + assert_eq!("Invalid State", "") + } + } + + let path_dependency = DEPENDENCY_DIR.join("dep-1").join("CustomFileBranch"); + assert!(path_dependency.exists()); // this should exists at that branch + + let content = r#" +# Full reference https://github.com/foundry-rs/foundry/tree/master/crates/config + +[profile.default] +script = "script" +solc = "0.8.26" +src = "src" +test = "test" +libs = ["dependencies"] + +[dependencies] +dep = { version = "1", git = "https://gitlab.com/mario4582928/Mario.git", branch = "custom-branch" } +"#; + assert_eq!(read_file_to_string(&target_config), content); clean_test_env(target_config); } @@ -1352,6 +1538,8 @@ libs = ["dependencies"] "https://gitlab.com/mario4582928/mario-soldeer-dependency.git".to_string(), ), rev: None, + tag: None, + branch: None, regenerate_remappings: false, recursive_deps: true, }); @@ -1412,6 +1600,8 @@ recursive_deps = true "https://gitlab.com/mario4582928/mario-soldeer-dependency.git".to_string(), ), rev: None, + tag: None, + branch: None, regenerate_remappings: false, recursive_deps: false, }); @@ -1467,6 +1657,8 @@ libs = ["dependencies"] dependency: Some("dep1~1.0".to_string()), remote_url: Some("https://gitlab.com/mario4582928/mario-git-submodule.git".to_string()), rev: None, + tag: None, + branch: None, regenerate_remappings: false, recursive_deps: true, }); @@ -1522,6 +1714,8 @@ recursive_deps = true dependency: Some("dep1~1.0".to_string()), remote_url: Some("https://gitlab.com/mario4582928/mario-git-submodule.git".to_string()), rev: None, + tag: None, + branch: None, regenerate_remappings: false, recursive_deps: false, }); diff --git a/test/emptyfile b/test/emptyfile index e69de29..5337cd5 100644 --- a/test/emptyfile +++ b/test/emptyfile @@ -0,0 +1 @@ +File kept just to have the test directory present on git. This directory is used for the tests to write artifacts \ No newline at end of file diff --git a/test/emptyfile2 b/test/emptyfile2 deleted file mode 100644 index e69de29..0000000 diff --git a/tests/ci/foundry.rs b/tests/ci/foundry.rs index f8afa22..558c1bc 100644 --- a/tests/ci/foundry.rs +++ b/tests/ci/foundry.rs @@ -24,6 +24,8 @@ fn soldeer_install_valid_dependency() { dependency: Some("forge-std~1.8.2".to_string()), remote_url: None, rev: None, + tag: None, + branch: None, regenerate_remappings: false, recursive_deps: false, }); From a6bd9c4d17d20dcca75c72b8beaf18da238830fe Mon Sep 17 00:00:00 2001 From: Mario Date: Fri, 23 Aug 2024 02:01:30 -0400 Subject: [PATCH 2/6] clippy --- src/dependency_downloader.rs | 42 ++++++++++++++++-------------------- 1 file changed, 18 insertions(+), 24 deletions(-) diff --git a/src/dependency_downloader.rs b/src/dependency_downloader.rs index c07271d..765254e 100644 --- a/src/dependency_downloader.rs +++ b/src/dependency_downloader.rs @@ -199,34 +199,28 @@ async fn download_via_git( Some(rev) => Some(rev), None => match dependency.tag.clone() { Some(tag) => Some(tag), - None => match dependency.branch.clone() { - Some(branch) => Some(branch), - None => None, - }, + None => dependency.branch.clone(), }, }; - match checkout_target.clone() { - Some(target) => { - let mut git_checkout = Command::new("git"); - let result = git_checkout - .args(["checkout".to_string(), target.to_string()]) - .env("GIT_TERMINAL_PROMPT", "0") - .current_dir(&path) - .stdout(Stdio::piped()) - .stderr(Stdio::piped()); - - let out = result.output().expect("Checkout status failed"); - let status = result.status().expect("Checkout getting output failed"); - - if !status.success() { - let _ = fs::remove_dir_all(&path); - return Err(DownloadError::GitError( - str::from_utf8(&out.stderr).unwrap().trim().to_string(), - )); - } + if let Some(target) = checkout_target.clone() { + let mut git_checkout = Command::new("git"); + let result = git_checkout + .args(["checkout".to_string(), target.to_string()]) + .env("GIT_TERMINAL_PROMPT", "0") + .current_dir(&path) + .stdout(Stdio::piped()) + .stderr(Stdio::piped()); + + let out = result.output().expect("Checkout status failed"); + let status = result.status().expect("Checkout getting output failed"); + + if !status.success() { + let _ = fs::remove_dir_all(&path); + return Err(DownloadError::GitError( + str::from_utf8(&out.stderr).unwrap().trim().to_string(), + )); } - None => {} }; let mut git_checkout = Command::new("git"); From 3ed6dc6fc14782ed35a1e63a58a0a8fe6c55a5e6 Mon Sep 17 00:00:00 2001 From: Mario Date: Sat, 24 Aug 2024 02:35:29 -0400 Subject: [PATCH 3/6] fixed bug on showing wrong error if config was incorrect --- src/janitor.rs | 6 ++++-- src/lib.rs | 11 ++++++----- src/lock.rs | 4 ++++ 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/janitor.rs b/src/janitor.rs index 09445d3..f83ca90 100644 --- a/src/janitor.rs +++ b/src/janitor.rs @@ -33,13 +33,15 @@ pub fn cleanup_dependency(dependency: &Dependency, full: bool) -> Result<()> { sanitize_dependency_name(&format!("{}-{}", dependency.name(), dependency.version())); let new_path = DEPENDENCY_DIR.clone().join(format!("{sanitized_name}.zip")); - if let Dependency::Http(_) = dependency { + if new_path.exists() { fs::remove_file(&new_path) .map_err(|e| JanitorError::IOError { path: new_path, source: e })?; } if full { let dir = DEPENDENCY_DIR.join(sanitized_name); - fs::remove_dir_all(&dir).map_err(|e| JanitorError::IOError { path: dir, source: e })?; + if dir.exists() { + fs::remove_dir_all(&dir).map_err(|e| JanitorError::IOError { path: dir, source: e })?; + } remove_lock(dependency).map_err(JanitorError::LockError)?; } Ok(()) diff --git a/src/lib.rs b/src/lib.rs index 1852639..b695759 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -64,11 +64,12 @@ pub async fn run(command: Subcommands) -> Result<(), SoldeerError> { Subcommands::Install(install) => { let regenerate_remappings = install.regenerate_remappings; let Some(dependency) = install.dependency else { - return update(regenerate_remappings, install.recursive_deps).await; // TODO: instead, check which - // dependencies - // do - // not match the - // integrity checksum and install those + return update(regenerate_remappings, install.recursive_deps).await; + // TODO: instead, check which + // dependencies + // do + // not match the + // integrity checksum and install those }; println!("{}", "🦌 Running Soldeer install 🦌".green()); diff --git a/src/lock.rs b/src/lock.rs index 94df8a8..6be7df7 100644 --- a/src/lock.rs +++ b/src/lock.rs @@ -139,6 +139,10 @@ pub fn remove_lock(dependency: &Dependency) -> Result<()> { } else { LOCK_FILE.clone() }; + // check if the lock exists, if does not we don't have what to delete + if !lock_file.exists() { + return Ok(()); + } let entries: Vec<_> = read_lock()? .into_iter() From 1e72f8d9052f285c7455be6b6604704e39ba9dac Mon Sep 17 00:00:00 2001 From: Mario Date: Sat, 24 Aug 2024 02:45:51 -0400 Subject: [PATCH 4/6] fixed janitor tests --- src/janitor.rs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/janitor.rs b/src/janitor.rs index f83ca90..e6bee11 100644 --- a/src/janitor.rs +++ b/src/janitor.rs @@ -120,7 +120,13 @@ mod tests { version: "v-cleanup-nonexisting".to_string(), url: Some("https://github.com/mario-eth/soldeer-versions/raw/main/all_versions/@openzeppelin-contracts~2.3.0.zip".to_string()), checksum: None})); - cleanup_dependency(&dependencies[0], false).unwrap_err(); + match cleanup_dependency(&dependencies[0], false) { + Ok(_) => {} + Err(error) => { + println!("Error {:?}", error); + assert_eq!("Invalid State", ""); + } + }; } #[tokio::test] @@ -167,12 +173,10 @@ mod tests { url: Some("https://github.com/mario-eth/soldeer-versions/raw/main/all_versions/@openzeppelin-contracts~2.4.0.zip".to_string()), checksum: None})); match cleanup_after(&dependencies) { - Ok(_) => { - assert_eq!("Invalid State", ""); - } + Ok(_) => {} Err(error) => { - println!("{error}"); - assert!(matches!(error, JanitorError::IOError { path: _, source: _ })); + println!("Error {:?}", error); + assert_eq!("Invalid State", ""); } } } From 11b7e4f9e3bf0223534706e2465ee9eb438c5a3b Mon Sep 17 00:00:00 2001 From: "Valentin B." <703631+beeb@users.noreply.github.com> Date: Tue, 27 Aug 2024 06:46:34 +0200 Subject: [PATCH 5/6] refactor: git branches and tags (#162) * fix: rev in git dependency * fix: behavior with no rev --- src/commands.rs | 18 +-- src/config.rs | 236 ++++++++++++----------------------- src/dependency_downloader.rs | 35 ++---- src/errors.rs | 3 + src/lib.rs | 35 ++++-- src/lock.rs | 10 +- 6 files changed, 128 insertions(+), 209 deletions(-) diff --git a/src/commands.rs b/src/commands.rs index 2a8ea53..2034cab 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -51,9 +51,9 @@ You can install a dependency from the Soldeer repository, a custom URL pointing soldeer install @openzeppelin-contracts~2.3.0 git@github.com:OpenZeppelin/openzeppelin-contracts.git - **Example from Git with a specified commit:** soldeer install @openzeppelin-contracts~2.3.0 git@github.com:OpenZeppelin/openzeppelin-contracts.git --rev 05f218fb6617932e56bf5388c3b389c3028a7b73 - - **Example from Git with a specified tag:** +- **Example from Git with a specified tag:** soldeer install @openzeppelin-contracts~2.3.0 git@github.com:OpenZeppelin/openzeppelin-contracts.git --tag my-tag - - **Example from Git with a specified branch:** +- **Example from Git with a specified branch:** soldeer install @openzeppelin-contracts~2.3.0 git@github.com:OpenZeppelin/openzeppelin-contracts.git --branch my-branch", after_help = "For more information, read the README.md" )] @@ -67,19 +67,19 @@ pub struct Install { /// The URL to the dependency zip file, if not from the Soldeer repository /// /// Example: https://my-domain/dep.zip - #[arg(value_name = "URL")] + #[arg(value_name = "URL", requires = "dependency")] pub remote_url: Option, - /// The revision of the dependency, if from Git - #[arg(long)] + /// A Git revision + #[arg(long, group = "identifier", requires = "remote_url")] pub rev: Option, - /// The tag of the dependency, if from Git - #[arg(long)] + /// A Git tag + #[arg(long, group = "identifier", requires = "remote_url")] pub tag: Option, - /// The branch of the dependency, if from Git - #[arg(long)] + /// A Git branch + #[arg(long, group = "identifier", requires = "remote_url")] pub branch: Option, /// If set, this command will delete the existing remappings and re-create them diff --git a/src/config.rs b/src/config.rs index c41215e..7f43eb2 100644 --- a/src/config.rs +++ b/src/config.rs @@ -5,7 +5,7 @@ use crate::{ }; use serde::{Deserialize, Serialize}; use std::{ - env, + env, fmt, fs::{self, remove_dir_all, remove_file, File}, io::{self, Write}, path::{Path, PathBuf}, @@ -64,14 +64,47 @@ impl Default for SoldeerConfig { } } +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] +pub enum GitIdentifier { + Rev(String), + Branch(String), + Tag(String), +} + +impl GitIdentifier { + pub fn from_rev(rev: impl Into) -> Self { + let rev: String = rev.into(); + GitIdentifier::Rev(rev) + } + + pub fn from_branch(branch: impl Into) -> Self { + let branch: String = branch.into(); + GitIdentifier::Branch(branch) + } + + pub fn from_tag(tag: impl Into) -> Self { + let tag: String = tag.into(); + GitIdentifier::Tag(tag) + } +} + +impl fmt::Display for GitIdentifier { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let val = match self { + GitIdentifier::Rev(rev) => rev, + GitIdentifier::Branch(branch) => branch, + GitIdentifier::Tag(tag) => tag, + }; + write!(f, "{val}") + } +} + #[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] pub struct GitDependency { pub name: String, pub version: String, pub git: String, - pub rev: Option, - pub tag: Option, - pub branch: Option, + pub identifier: Option, } impl core::fmt::Display for GitDependency { @@ -157,35 +190,29 @@ impl Dependency { value(&dep.git).into_value().expect("git URL should be a valid toml value"), ); - match &dep.tag { - Some(tag) => { + match &dep.identifier { + Some(GitIdentifier::Rev(rev)) => { + table.insert( + "rev", + value(rev).into_value().expect("rev should be a valid toml value"), + ); + } + Some(GitIdentifier::Branch(branch)) => { + table.insert( + "branch", + value(branch) + .into_value() + .expect("branch should be a valid toml value"), + ); + } + Some(GitIdentifier::Tag(tag)) => { table.insert( "tag", value(tag).into_value().expect("tag should be a valid toml value"), ); } - None => match &dep.branch { - Some(branch) => { - table.insert( - "branch", - value(branch) - .into_value() - .expect("branch should be a valid toml value"), - ); - } - None => match &dep.rev { - Some(rev) => { - table.insert( - "rev", - value(rev) - .into_value() - .expect("rev should be a valid toml value"), - ); - } - None => {} - }, - }, - }; + None => {} + } (dep.name.clone(), value(table)) } @@ -488,7 +515,7 @@ fn parse_dependency(name: impl Into, value: &Item) -> Result return Err(ConfigError::InvalidField { field: "git".to_string(), dep: name }); } Some(Some(git)) => { - // rev field is optional but needs to be a string if present + // rev/branch/tag fields are optional but need to be a string if present let rev = match table.get("rev").map(|v| v.as_str()) { Some(Some(rev)) => Some(rev.to_string()), Some(None) => { @@ -496,15 +523,6 @@ fn parse_dependency(name: impl Into, value: &Item) -> Result } None => None, }; - - let tag = match table.get("tag").map(|v| v.as_str()) { - Some(Some(tag)) => Some(tag.to_string()), - Some(None) => { - return Err(ConfigError::InvalidField { field: "tag".to_string(), dep: name }); - } - None => None, - }; - let branch = match table.get("branch").map(|v| v.as_str()) { Some(Some(tag)) => Some(tag.to_string()), Some(None) => { @@ -515,13 +533,27 @@ fn parse_dependency(name: impl Into, value: &Item) -> Result } None => None, }; + let tag = match table.get("tag").map(|v| v.as_str()) { + Some(Some(tag)) => Some(tag.to_string()), + Some(None) => { + return Err(ConfigError::InvalidField { field: "tag".to_string(), dep: name }); + } + None => None, + }; + let identifier = match (rev, branch, tag) { + (Some(rev), None, None) => Some(GitIdentifier::from_rev(rev)), + (None, Some(branch), None) => Some(GitIdentifier::from_branch(branch)), + (None, None, Some(tag)) => Some(GitIdentifier::from_tag(tag)), + (None, None, None) => None, + _ => { + return Err(ConfigError::GitIdentifierConflict(name)); + } + }; return Ok(Dependency::Git(GitDependency { name: name.to_string(), git: git.to_string(), version, - rev, - tag, - branch, + identifier, })); } None => {} @@ -1442,9 +1474,7 @@ gas_reports = ['*'] name: "dep1".to_string(), version: "1.0.0".to_string(), git: "git@github.com:foundry-rs/forge-std.git".to_string(), - rev: Some("07263d193d621c4b2b0ce8b4d54af58f6957d97d".to_string()), - tag: None, - branch: None, + identifier: Some(GitIdentifier::from_rev("07263d193d621c4b2b0ce8b4d54af58f6957d97d")), }); add_to_config(&dependency, &target_config).unwrap(); @@ -1495,62 +1525,7 @@ gas_reports = ['*'] name: "dep1".to_string(), version: "1.0.0".to_string(), git: "https://gitlab.com/mario4582928/Mario.git".to_string(), - rev: None, - tag: Some("custom-tag".to_string()), - branch: None, - }); - - add_to_config(&dependency, &target_config).unwrap(); - content = r#" -# Full reference https://github.com/foundry-rs/foundry/tree/master/crates/config - -[profile.default] -script = "script" -solc = "0.8.26" -src = "src" -test = "test" -libs = ["dependencies"] -gas_reports = ['*'] - -[dependencies] -dep1 = { version = "1.0.0", git = "https://gitlab.com/mario4582928/Mario.git", tag = "custom-tag" } - -# we don't have [dependencies] declared -"#; - - assert_eq!(read_file_to_string(&target_config), content); - - let _ = remove_file(target_config); - Ok(()) - } - - #[test] - fn add_to_config_foundry_github_with_tag_when_revision_present() -> Result<()> { - let mut content = r#" -# Full reference https://github.com/foundry-rs/foundry/tree/master/crates/config - -[profile.default] -script = "script" -solc = "0.8.26" -src = "src" -test = "test" -libs = ["dependencies"] -gas_reports = ['*'] - -# we don't have [dependencies] declared -"#; - - let target_config = define_config(true); - - write_to_config(&target_config, content); - - let dependency = Dependency::Git(GitDependency { - name: "dep1".to_string(), - version: "1.0.0".to_string(), - git: "https://gitlab.com/mario4582928/Mario.git".to_string(), - rev: Some("22868f426bd4dd0e682b5ec5f9bd55507664240c".to_string()), - tag: Some("custom-tag".to_string()), - branch: None, + identifier: Some(GitIdentifier::from_tag("custom-tag")), }); add_to_config(&dependency, &target_config).unwrap(); @@ -1601,9 +1576,7 @@ gas_reports = ['*'] name: "dep1".to_string(), version: "1.0.0".to_string(), git: "https://gitlab.com/mario4582928/Mario.git".to_string(), - rev: None, - tag: None, - branch: Some("custom-branch".to_string()), + identifier: Some(GitIdentifier::from_branch("custom-branch")), }); add_to_config(&dependency, &target_config).unwrap(); @@ -1621,59 +1594,6 @@ gas_reports = ['*'] [dependencies] dep1 = { version = "1.0.0", git = "https://gitlab.com/mario4582928/Mario.git", branch = "custom-branch" } -# we don't have [dependencies] declared -"#; - - assert_eq!(read_file_to_string(&target_config), content); - - let _ = remove_file(target_config); - Ok(()) - } - - #[test] - fn add_to_config_foundry_github_with_rev_tag_branch() -> Result<()> { - let mut content = r#" -# Full reference https://github.com/foundry-rs/foundry/tree/master/crates/config - -[profile.default] -script = "script" -solc = "0.8.26" -src = "src" -test = "test" -libs = ["dependencies"] -gas_reports = ['*'] - -# we don't have [dependencies] declared -"#; - - let target_config = define_config(true); - - write_to_config(&target_config, content); - - let dependency = Dependency::Git(GitDependency { - name: "dep1".to_string(), - version: "1.0.0".to_string(), - git: "https://gitlab.com/mario4582928/Mario.git".to_string(), - rev: Some("custom-rev".to_string()), - tag: Some("custom-tag".to_string()), - branch: Some("custom-branch".to_string()), - }); - - add_to_config(&dependency, &target_config).unwrap(); - content = r#" -# Full reference https://github.com/foundry-rs/foundry/tree/master/crates/config - -[profile.default] -script = "script" -solc = "0.8.26" -src = "src" -test = "test" -libs = ["dependencies"] -gas_reports = ['*'] - -[dependencies] -dep1 = { version = "1.0.0", git = "https://gitlab.com/mario4582928/Mario.git", tag = "custom-tag" } - # we don't have [dependencies] declared "#; @@ -1710,9 +1630,7 @@ dep1 = { version = "1.0.0", git = "git@github.com:foundry-rs/forge-std.git" } name: "dep1".to_string(), version: "1.0.0".to_string(), git: "git@github.com:foundry-rs/forge-std.git".to_string(), - rev: Some("07263d193d621c4b2b0ce8b4d54af58f6957d97d".to_string()), - tag: None, - branch: None, + identifier: Some(GitIdentifier::from_rev("07263d193d621c4b2b0ce8b4d54af58f6957d97d")), }); add_to_config(&dependency, &target_config).unwrap(); diff --git a/src/dependency_downloader.rs b/src/dependency_downloader.rs index 765254e..ebf8352 100644 --- a/src/dependency_downloader.rs +++ b/src/dependency_downloader.rs @@ -195,15 +195,7 @@ async fn download_via_git( )); } - let checkout_target = match dependency.rev.clone() { - Some(rev) => Some(rev), - None => match dependency.tag.clone() { - Some(tag) => Some(tag), - None => dependency.branch.clone(), - }, - }; - - if let Some(target) = checkout_target.clone() { + if let Some(target) = &dependency.identifier { let mut git_checkout = Command::new("git"); let result = git_checkout .args(["checkout".to_string(), target.to_string()]) @@ -340,6 +332,7 @@ pub fn install_subdependencies(dependency: &Dependency) -> Result<()> { mod tests { use super::*; use crate::{ + config::GitIdentifier, janitor::healthcheck_dependency, utils::{get_url_type, UrlType}, }; @@ -375,9 +368,7 @@ mod tests { name: "@openzeppelin-contracts".to_string(), version: "2.3.0".to_string(), git: "https://gitlab.com/mario4582928/Mario.git".to_string(), - rev: Some("7a0663eaf7488732f39550be655bad6694974cb3".to_string()), - tag: None, - branch: None, + identifier: Some(GitIdentifier::from_rev("7a0663eaf7488732f39550be655bad6694974cb3")), }); dependencies.push(dependency.clone()); let results = download_dependencies(&dependencies, false).await.unwrap(); @@ -406,9 +397,7 @@ mod tests { name: "@openzeppelin-contracts".to_string(), version: "2.3.0".to_string(), git: "https://gitlab.com/mario4582928/Mario.git".to_string(), - rev: None, - tag: None, - branch: None, + identifier: None, }); dependencies.push(dependency.clone()); let results = download_dependencies(&dependencies, false).await.unwrap(); @@ -469,9 +458,7 @@ mod tests { name: "@openzeppelin-contracts".to_string(), version: "2.3.0".to_string(), git: "https://github.com/transmissions11/solmate.git".to_string(), - rev: None, - tag: None, - branch: None, + identifier: None, }); dependencies.push(dependency_one.clone()); @@ -479,9 +466,7 @@ mod tests { name: "@uniswap-v2-core".to_string(), version: "1.0.0-beta.4".to_string(), git: "https://gitlab.com/mario4582928/Mario.git".to_string(), - rev: None, - tag: None, - branch: None, + identifier: None, }); dependencies.push(dependency_two.clone()); @@ -630,9 +615,7 @@ mod tests { name: "@openzeppelin-contracts".to_string(), version: "2.3.0".to_string(), git: "git@github.com:transmissions11/solmate-wrong.git".to_string(), - rev: None, - tag: None, - branch: None, + identifier: None, }); dependencies.push(dependency.clone()); @@ -751,9 +734,7 @@ mod tests { name: "@openzeppelin-contracts".to_string(), version: "2.3.0".to_string(), git: "https://github.com/transmissions11/solmate.git".to_string(), - rev: None, - tag: None, - branch: None, + identifier: None, }); dependencies.push(dependency.clone()); diff --git a/src/errors.rs b/src/errors.rs index c0080dd..8d906ae 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -72,6 +72,9 @@ pub enum ConfigError { #[error("invalid `{field}` field in {dep}")] InvalidField { field: String, dep: String }, + #[error("only one of `git`, `branch` and `rev` can be specified for dependency {0}")] + GitIdentifierConflict(String), + #[error("dependency {0} is not valid")] InvalidDependency(String), diff --git a/src/lib.rs b/src/lib.rs index b695759..2120a43 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -14,7 +14,7 @@ use crate::{ pub use crate::{commands::Subcommands, errors::SoldeerError}; use config::{ add_to_config, get_config_path, read_soldeer_config, remappings_foundry, GitDependency, - HttpDependency, RemappingsAction, RemappingsLocation, + GitIdentifier, HttpDependency, RemappingsAction, RemappingsLocation, }; use dependency_downloader::download_dependency; use janitor::cleanup_dependency; @@ -78,14 +78,23 @@ pub async fn run(command: Subcommands) -> Result<(), SoldeerError> { let dep = match install.remote_url { Some(url) => match get_url_type(&url) { - UrlType::Git => Dependency::Git(GitDependency { - name: dependency_name.to_string(), - version: dependency_version.to_string(), - git: url, - rev: install.rev, - tag: install.tag, - branch: install.branch, - }), + UrlType::Git => { + let identifier = match (install.rev, install.branch, install.tag) { + (Some(rev), None, None) => Some(GitIdentifier::from_rev(rev)), + (None, Some(branch), None) => Some(GitIdentifier::from_branch(branch)), + (None, None, Some(tag)) => Some(GitIdentifier::from_tag(tag)), + (None, None, None) => None, + _ => { + unreachable!("clap validation should prevent this from happening") + } + }; + Dependency::Git(GitDependency { + name: dependency_name.to_string(), + version: dependency_version.to_string(), + git: url, + identifier, + }) + } UrlType::Http => Dependency::Http(HttpDependency { name: dependency_name.to_string(), version: dependency_version.to_string(), @@ -235,7 +244,9 @@ async fn install_dependency( dep.url = Some(result.url); } Dependency::Git(ref mut dep) => { - dep.rev = Some(result.hash); + if dep.identifier.is_none() { + dep.identifier = Some(GitIdentifier::from_rev(result.hash)); + } add_to_config(&dependency, &config_path)?; } } @@ -308,7 +319,9 @@ async fn update(regenerate_remappings: bool, recursive_deps: bool) -> Result<(), dep.checksum = Some(result.hash); dep.url = Some(result.url); } - Dependency::Git(ref mut dep) => dep.rev = Some(result.hash), + Dependency::Git(ref mut dep) => { + dep.identifier = Some(GitIdentifier::from_rev(result.hash)) + } } }); diff --git a/src/lock.rs b/src/lock.rs index 6be7df7..1f87600 100644 --- a/src/lock.rs +++ b/src/lock.rs @@ -97,9 +97,13 @@ pub fn write_lock( dep.checksum.as_ref().unwrap(), integrity.clone().map(|c| c.to_string()), ), - Dependency::Git(dep) => { - LockEntry::new(&dep.name, &dep.version, &dep.git, dep.rev.as_ref().unwrap(), None) - } + Dependency::Git(dep) => LockEntry::new( + &dep.name, + &dep.version, + &dep.git, + dep.identifier.as_ref().unwrap().to_string(), + None, + ), }; // check for entry already existing match entries.iter().position(|e| e.name == entry.name && e.version == entry.version) { From c42de38e9b541696ee20020a97bc1237404f976d Mon Sep 17 00:00:00 2001 From: Mario Date: Tue, 27 Aug 2024 00:55:06 -0400 Subject: [PATCH 6/6] fixed clippy --- src/config.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/config.rs b/src/config.rs index 35020f4..ee2af7a 100644 --- a/src/config.rs +++ b/src/config.rs @@ -550,7 +550,7 @@ fn parse_dependency(name: impl Into, value: &Item) -> Result } }; return Ok(Dependency::Git(GitDependency { - name: name.to_string(), + name, git: git.to_string(), version, identifier,