mirror of
https://github.com/ProvableHQ/leo.git
synced 2024-12-23 18:21:38 +03:00
added dependency management
- recursively add deps - prevent recursion in dep tree - pretty print recursion error - fix logging for leo install cmd - add test for leo install and dep section
This commit is contained in:
parent
f71648c6a6
commit
e5be6e2c57
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -1216,6 +1216,7 @@ dependencies = [
|
||||
"console",
|
||||
"dirs",
|
||||
"from-pest",
|
||||
"indexmap",
|
||||
"lazy_static",
|
||||
"leo-ast",
|
||||
"leo-compiler",
|
||||
|
@ -108,6 +108,9 @@ version = "0.14.0"
|
||||
[dependencies.from-pest]
|
||||
version = "0.3.1"
|
||||
|
||||
[dependencies.indexmap]
|
||||
version = "1.7"
|
||||
|
||||
[dependencies.lazy_static]
|
||||
version = "1.4.0"
|
||||
|
||||
|
@ -21,6 +21,7 @@ use anyhow::{anyhow, Result};
|
||||
use std::{
|
||||
fs::{create_dir_all, File},
|
||||
io::{Read, Write},
|
||||
path::PathBuf,
|
||||
};
|
||||
use structopt::StructOpt;
|
||||
use tracing::Span;
|
||||
@ -80,7 +81,7 @@ impl Add {
|
||||
|
||||
impl Command for Add {
|
||||
type Input = ();
|
||||
type Output = ();
|
||||
type Output = PathBuf;
|
||||
|
||||
fn log_span(&self) -> Span {
|
||||
tracing::span!(tracing::Level::INFO, "Adding")
|
||||
@ -98,6 +99,8 @@ impl Command for Add {
|
||||
|
||||
let (author, package_name) = self.try_read_arguments()?;
|
||||
|
||||
tracing::info!("Package: {}/{}", &author, &package_name);
|
||||
|
||||
// Attempt to fetch the package.
|
||||
let reader = {
|
||||
let fetch = Fetch {
|
||||
@ -118,9 +121,9 @@ impl Command for Add {
|
||||
// Dumb compatibility hack.
|
||||
// TODO: Remove once `leo add` functionality is discussed.
|
||||
if self.version.is_some() {
|
||||
path.push(format!("{}-{}@{}", author, package_name, self.version.unwrap()));
|
||||
path.push(format!("{}-{}@{}", author.clone(), package_name, self.version.unwrap()));
|
||||
} else {
|
||||
path.push(package_name);
|
||||
path.push(package_name.clone());
|
||||
}
|
||||
create_dir_all(&path)?;
|
||||
};
|
||||
@ -152,8 +155,8 @@ impl Command for Add {
|
||||
}
|
||||
}
|
||||
|
||||
tracing::info!("Successfully added a package");
|
||||
tracing::info!("Successfully added package {}/{}", author, package_name);
|
||||
|
||||
Ok(())
|
||||
Ok(path)
|
||||
}
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ use crate::{
|
||||
};
|
||||
|
||||
use anyhow::{anyhow, Result};
|
||||
use indexmap::set::IndexSet;
|
||||
use structopt::StructOpt;
|
||||
use tracing::span::Span;
|
||||
|
||||
@ -29,31 +30,65 @@ use tracing::span::Span;
|
||||
pub struct Install {}
|
||||
|
||||
impl Command for Install {
|
||||
type Input = ();
|
||||
/// Names of dependencies in the current branch of a dependency tree.
|
||||
type Input = IndexSet<String>;
|
||||
type Output = ();
|
||||
|
||||
fn log_span(&self) -> Span {
|
||||
tracing::span!(tracing::Level::INFO, "Installing")
|
||||
}
|
||||
|
||||
fn prelude(&self, _: Context) -> Result<Self::Input> {
|
||||
Ok(())
|
||||
fn prelude(&self, context: Context) -> Result<Self::Input> {
|
||||
let package_name = context.manifest()?.get_package_name();
|
||||
|
||||
let mut set = IndexSet::new();
|
||||
set.insert(package_name);
|
||||
|
||||
Ok(set)
|
||||
}
|
||||
|
||||
fn apply(self, context: Context, _: Self::Input) -> Result<Self::Output> {
|
||||
let deps = context
|
||||
.manifest()?
|
||||
.get_package_dependencies()
|
||||
.ok_or_else(|| anyhow!("Package has no dependencies"))?;
|
||||
fn apply(self, context: Context, mut tree: Self::Input) -> Result<Self::Output> {
|
||||
let dependencies = context
|
||||
.manifest()
|
||||
.map_err(|_| anyhow!("Package Manifest not found"))?
|
||||
.get_package_dependencies();
|
||||
|
||||
for (_name, dep) in deps.iter() {
|
||||
Add::new(
|
||||
let dependencies = match dependencies {
|
||||
Some(value) => value,
|
||||
None => return Ok(()),
|
||||
};
|
||||
|
||||
// Go through each dependency in Leo.toml and add it to the imports.
|
||||
// While adding, pull dependencies of this package as well and check for recursion.
|
||||
for (_name, dependency) in dependencies.iter() {
|
||||
let package_name = dependency.package.clone();
|
||||
let path = Add::new(
|
||||
None,
|
||||
Some(dep.author.clone()),
|
||||
Some(dep.package.clone()),
|
||||
Some(dep.version.clone()),
|
||||
Some(dependency.author.clone()),
|
||||
Some(package_name.clone()),
|
||||
Some(dependency.version.clone()),
|
||||
)
|
||||
.execute(context.clone())?;
|
||||
.apply(context.clone(), ())?;
|
||||
|
||||
// Try inserting a new dependency to the branch. If not inserted,
|
||||
// then fail because this dependency was added on a higher level.
|
||||
if !tree.insert(package_name.clone()) {
|
||||
// Pretty format for the message - show dependency structure.
|
||||
let mut message: Vec<String> = tree
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.map(|(i, val)| format!("{}└─{}", " ".repeat(i * 2), val))
|
||||
.collect();
|
||||
|
||||
message.push(format!("{}└─{} (FAILURE)", " ".repeat(message.len() * 2), package_name));
|
||||
|
||||
return Err(anyhow!("recursive dependency found \n{}", message.join("\n")));
|
||||
}
|
||||
|
||||
// Run the same command for installed dependency.
|
||||
let mut new_context = context.clone();
|
||||
new_context.path = Some(path);
|
||||
(Install {}).apply(new_context, tree.clone())?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
29
leo/main.rs
29
leo/main.rs
@ -247,6 +247,7 @@ mod cli_tests {
|
||||
use crate::{run_with_args, Opt};
|
||||
|
||||
use anyhow::Error;
|
||||
use snarkvm_utilities::Write;
|
||||
use std::path::PathBuf;
|
||||
use structopt::StructOpt;
|
||||
use test_dir::{DirBuilder, FileType, TestDir};
|
||||
@ -366,6 +367,7 @@ mod cli_tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn test_import() {
|
||||
let dir = testdir("test");
|
||||
let path = dir.path("test");
|
||||
@ -407,4 +409,31 @@ mod cli_tests {
|
||||
assert!(run_cmd("leo test -f examples/silly-sudoku/src/lib.leo", path).is_ok());
|
||||
assert!(run_cmd("leo test -f examples/silly-sudoku/src/main.leo", path).is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_install() {
|
||||
let dir = testdir("test");
|
||||
let path = dir.path("test");
|
||||
|
||||
assert!(run_cmd("leo new install", &Some(path.clone())).is_ok());
|
||||
|
||||
let install_path = &Some(path.join("install"));
|
||||
|
||||
let mut file = std::fs::OpenOptions::new()
|
||||
.write(true)
|
||||
.append(true)
|
||||
.open(path.join("install/Leo.toml"))
|
||||
.unwrap();
|
||||
|
||||
assert!(
|
||||
file.write_all(
|
||||
br#"
|
||||
sudoku = {author = "justice-league", package = "u8u32", version = "0.1.0"}
|
||||
"#
|
||||
)
|
||||
.is_ok()
|
||||
);
|
||||
|
||||
assert!(run_cmd("leo install", install_path).is_ok());
|
||||
}
|
||||
}
|
||||
|
@ -156,10 +156,8 @@ impl ZipFile {
|
||||
|
||||
/// Check if the file path should be included in the package zip file.
|
||||
fn is_included(path: &Path) -> bool {
|
||||
// excluded directories: `output`, `imports`
|
||||
if path.ends_with(OUTPUTS_DIRECTORY_NAME.trim_end_matches('/'))
|
||||
| path.ends_with(IMPORTS_DIRECTORY_NAME.trim_end_matches('/'))
|
||||
{
|
||||
// DO NOT include `imports` and `outputs` directories.
|
||||
if path.starts_with(IMPORTS_DIRECTORY_NAME) || path.starts_with(OUTPUTS_DIRECTORY_NAME) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user