mirror of
https://github.com/ProvableHQ/leo.git
synced 2024-09-11 13:56:58 +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",
|
"console",
|
||||||
"dirs",
|
"dirs",
|
||||||
"from-pest",
|
"from-pest",
|
||||||
|
"indexmap",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"leo-ast",
|
"leo-ast",
|
||||||
"leo-compiler",
|
"leo-compiler",
|
||||||
|
@ -108,6 +108,9 @@ version = "0.14.0"
|
|||||||
[dependencies.from-pest]
|
[dependencies.from-pest]
|
||||||
version = "0.3.1"
|
version = "0.3.1"
|
||||||
|
|
||||||
|
[dependencies.indexmap]
|
||||||
|
version = "1.7"
|
||||||
|
|
||||||
[dependencies.lazy_static]
|
[dependencies.lazy_static]
|
||||||
version = "1.4.0"
|
version = "1.4.0"
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@ use anyhow::{anyhow, Result};
|
|||||||
use std::{
|
use std::{
|
||||||
fs::{create_dir_all, File},
|
fs::{create_dir_all, File},
|
||||||
io::{Read, Write},
|
io::{Read, Write},
|
||||||
|
path::PathBuf,
|
||||||
};
|
};
|
||||||
use structopt::StructOpt;
|
use structopt::StructOpt;
|
||||||
use tracing::Span;
|
use tracing::Span;
|
||||||
@ -80,7 +81,7 @@ impl Add {
|
|||||||
|
|
||||||
impl Command for Add {
|
impl Command for Add {
|
||||||
type Input = ();
|
type Input = ();
|
||||||
type Output = ();
|
type Output = PathBuf;
|
||||||
|
|
||||||
fn log_span(&self) -> Span {
|
fn log_span(&self) -> Span {
|
||||||
tracing::span!(tracing::Level::INFO, "Adding")
|
tracing::span!(tracing::Level::INFO, "Adding")
|
||||||
@ -98,6 +99,8 @@ impl Command for Add {
|
|||||||
|
|
||||||
let (author, package_name) = self.try_read_arguments()?;
|
let (author, package_name) = self.try_read_arguments()?;
|
||||||
|
|
||||||
|
tracing::info!("Package: {}/{}", &author, &package_name);
|
||||||
|
|
||||||
// Attempt to fetch the package.
|
// Attempt to fetch the package.
|
||||||
let reader = {
|
let reader = {
|
||||||
let fetch = Fetch {
|
let fetch = Fetch {
|
||||||
@ -118,9 +121,9 @@ impl Command for Add {
|
|||||||
// Dumb compatibility hack.
|
// Dumb compatibility hack.
|
||||||
// TODO: Remove once `leo add` functionality is discussed.
|
// TODO: Remove once `leo add` functionality is discussed.
|
||||||
if self.version.is_some() {
|
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 {
|
} else {
|
||||||
path.push(package_name);
|
path.push(package_name.clone());
|
||||||
}
|
}
|
||||||
create_dir_all(&path)?;
|
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 anyhow::{anyhow, Result};
|
||||||
|
use indexmap::set::IndexSet;
|
||||||
use structopt::StructOpt;
|
use structopt::StructOpt;
|
||||||
use tracing::span::Span;
|
use tracing::span::Span;
|
||||||
|
|
||||||
@ -29,31 +30,65 @@ use tracing::span::Span;
|
|||||||
pub struct Install {}
|
pub struct Install {}
|
||||||
|
|
||||||
impl Command for Install {
|
impl Command for Install {
|
||||||
type Input = ();
|
/// Names of dependencies in the current branch of a dependency tree.
|
||||||
|
type Input = IndexSet<String>;
|
||||||
type Output = ();
|
type Output = ();
|
||||||
|
|
||||||
fn log_span(&self) -> Span {
|
fn log_span(&self) -> Span {
|
||||||
tracing::span!(tracing::Level::INFO, "Installing")
|
tracing::span!(tracing::Level::INFO, "Installing")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prelude(&self, _: Context) -> Result<Self::Input> {
|
fn prelude(&self, context: Context) -> Result<Self::Input> {
|
||||||
Ok(())
|
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> {
|
fn apply(self, context: Context, mut tree: Self::Input) -> Result<Self::Output> {
|
||||||
let deps = context
|
let dependencies = context
|
||||||
.manifest()?
|
.manifest()
|
||||||
.get_package_dependencies()
|
.map_err(|_| anyhow!("Package Manifest not found"))?
|
||||||
.ok_or_else(|| anyhow!("Package has no dependencies"))?;
|
.get_package_dependencies();
|
||||||
|
|
||||||
for (_name, dep) in deps.iter() {
|
let dependencies = match dependencies {
|
||||||
Add::new(
|
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,
|
None,
|
||||||
Some(dep.author.clone()),
|
Some(dependency.author.clone()),
|
||||||
Some(dep.package.clone()),
|
Some(package_name.clone()),
|
||||||
Some(dep.version.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(())
|
Ok(())
|
||||||
|
29
leo/main.rs
29
leo/main.rs
@ -247,6 +247,7 @@ mod cli_tests {
|
|||||||
use crate::{run_with_args, Opt};
|
use crate::{run_with_args, Opt};
|
||||||
|
|
||||||
use anyhow::Error;
|
use anyhow::Error;
|
||||||
|
use snarkvm_utilities::Write;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use structopt::StructOpt;
|
use structopt::StructOpt;
|
||||||
use test_dir::{DirBuilder, FileType, TestDir};
|
use test_dir::{DirBuilder, FileType, TestDir};
|
||||||
@ -366,6 +367,7 @@ mod cli_tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[ignore]
|
||||||
fn test_import() {
|
fn test_import() {
|
||||||
let dir = testdir("test");
|
let dir = testdir("test");
|
||||||
let path = dir.path("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/lib.leo", path).is_ok());
|
||||||
assert!(run_cmd("leo test -f examples/silly-sudoku/src/main.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.
|
/// Check if the file path should be included in the package zip file.
|
||||||
fn is_included(path: &Path) -> bool {
|
fn is_included(path: &Path) -> bool {
|
||||||
// excluded directories: `output`, `imports`
|
// DO NOT include `imports` and `outputs` directories.
|
||||||
if path.ends_with(OUTPUTS_DIRECTORY_NAME.trim_end_matches('/'))
|
if path.starts_with(IMPORTS_DIRECTORY_NAME) || path.starts_with(OUTPUTS_DIRECTORY_NAME) {
|
||||||
| path.ends_with(IMPORTS_DIRECTORY_NAME.trim_end_matches('/'))
|
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user