Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Walk git dependency repo to discover nested forc dependencies #978

Merged
merged 3 commits into from
Mar 28, 2022
Merged
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
21 changes: 21 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions forc-pkg/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,4 @@ sway-types = { version = "0.8.0", path = "../sway-types" }
sway-utils = { version = "0.8.0", path = "../sway-utils" }
toml = "0.5"
url = { version = "2.2", features = ["serde"] }
walkdir = "2"
74 changes: 54 additions & 20 deletions forc-pkg/src/pkg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ use sway_core::{
NamespaceWrapper, TreeType, TypedParseTree,
};
use sway_types::JsonABI;
use sway_utils::constants;
use url::Url;

type GraphIx = u32;
Expand Down Expand Up @@ -513,7 +514,18 @@ pub fn graph_to_path_map(
let dep = &graph[dep_node];
let dep_path = match &dep.source {
SourcePinned::Git(git) => {
git_commit_path(&dep.name, &git.source.repo, &git.commit_hash)
let repo_path = git_commit_path(&dep.name, &git.source.repo, &git.commit_hash);
if !repo_path.exists() {
println!(" Fetching {}", git.to_string());
fetch_git(fetch_id, &dep.name, git)?;
}
find_dir_within(&repo_path, &dep.name).ok_or_else(|| {
anyhow!(
"failed to find package `{}` in {}",
dep.name,
git.to_string()
)
})?
}
SourcePinned::Path => {
let parent_node = graph
Expand All @@ -536,26 +548,16 @@ pub fn graph_to_path_map(
.path
.as_ref()
.ok_or_else(|| anyhow!("missing path info for dependency: {}", dep.name))?;
parent_path.join(rel_dep_path)
let path = parent_path.join(rel_dep_path);
if !path.exists() {
bail!("pinned `path` dependency \"{}\" source missing", dep.name);
}
path
}
SourcePinned::Registry(_reg) => {
bail!("registry dependencies are not yet supported");
}
};
if !dep_path.exists() {
match &dep.source {
SourcePinned::Path => {
bail!("pinned `path` dependency \"{}\" source missing", dep.name);
}
SourcePinned::Git(git) => {
println!(" Fetching {}", git.to_string());
fetch_git(fetch_id, &dep.name, git)?;
}
SourcePinned::Registry(_reg) => {
bail!("registry dependencies are not yet supported");
}
}
}
path_map.insert(dep.id(), dep_path);
}

Expand Down Expand Up @@ -795,9 +797,10 @@ fn pin_pkg(fetch_id: u64, pkg: &Pkg, path_map: &mut PathMap) -> Result<Pinned> {
path_map.insert(id, path.clone());
pinned
}
Source::Git(ref source) => {
let pinned_git = pin_git(fetch_id, &name, source.clone())?;
let path = git_commit_path(&name, &pinned_git.source.repo, &pinned_git.commit_hash);
Source::Git(ref git_source) => {
let pinned_git = pin_git(fetch_id, &name, git_source.clone())?;
let repo_path =
git_commit_path(&name, &pinned_git.source.repo, &pinned_git.commit_hash);
let source = SourcePinned::Git(pinned_git.clone());
let pinned = Pinned { name, source };
let id = pinned.id();
Expand All @@ -807,10 +810,17 @@ fn pin_pkg(fetch_id: u64, pkg: &Pkg, path_map: &mut PathMap) -> Result<Pinned> {
// cases as users should never be touching these directories, however we should add some code
// to validate this. E.g. can we recreate the git hash by hashing the directory or something
// along these lines using git?
if !path.exists() {
if !repo_path.exists() {
println!(" Fetching {}", pinned_git.to_string());
fetch_git(fetch_id, &pinned.name, &pinned_git)?;
}
let path = find_dir_within(&repo_path, &pinned.name).ok_or_else(|| {
anyhow!(
"failed to find package `{}` in {}",
pinned.name,
pinned_git.to_string()
)
})?;
entry.insert(path);
}
pinned
Expand Down Expand Up @@ -1071,6 +1081,30 @@ pub fn build(plan: &BuildPlan, conf: &BuildConfig) -> anyhow::Result<(Compiled,
Ok((compiled, source_map))
}

/// Attempt to find a `Forc.toml` with the given project name within the given directory.
///
/// Returns the path to the package on success, or `None` in the case it could not be found.
pub fn find_within(dir: &Path, pkg_name: &str) -> Option<PathBuf> {
walkdir::WalkDir::new(dir)
.into_iter()
.filter_map(Result::ok)
.filter(|entry| entry.path().ends_with(constants::MANIFEST_FILE_NAME))
.find_map(|entry| {
let path = entry.path();
let manifest = Manifest::from_file(path).ok()?;
if manifest.project.name == pkg_name {
Some(path.to_path_buf())
} else {
None
}
})
}

/// The same as [find_within], but returns the package's project directory.
pub fn find_dir_within(dir: &Path, pkg_name: &str) -> Option<PathBuf> {
find_within(dir, pkg_name).and_then(|path| path.parent().map(Path::to_path_buf))
}

// TODO: Update this to match behaviour described in the `compile` doc comment above.
fn generate_json_abi(ast: &TypedParseTree) -> JsonABI {
match ast {
Expand Down