From 6662b6261ffa89cedebb4032b7e8f22df333d981 Mon Sep 17 00:00:00 2001 From: collin Date: Fri, 26 Jun 2020 00:19:40 -0700 Subject: [PATCH 01/26] impl leo publish to zip file --- Cargo.lock | 105 ++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 2 + leo/commands/publish.rs | 103 +++++++++++++++++++++++++++++++++++++-- leo/errors/cli.rs | 23 +++++++++ 4 files changed, 228 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 166257d9f8..740aaa9efe 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -149,6 +149,33 @@ version = "1.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" +[[package]] +name = "bzip2" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42b7c3cbf0fa9c1b82308d57191728ca0256cb821220f4e2fd410a72ade26e3b" +dependencies = [ + "bzip2-sys", + "libc", +] + +[[package]] +name = "bzip2-sys" +version = "0.1.9+1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad3b39a260062fca31f7b0b12f207e8f2590a67d32ec7d59c20484b07ea7285e" +dependencies = [ + "cc", + "libc", + "pkg-config", +] + +[[package]] +name = "cc" +version = "1.0.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1be3409f94d7bdceeb5f5fac551039d9b3f00e25da7a74fc4d33400a0d96368" + [[package]] name = "cfg-if" version = "0.1.10" @@ -190,6 +217,15 @@ dependencies = [ "winapi", ] +[[package]] +name = "crc32fast" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1" +dependencies = [ + "cfg-if", +] + [[package]] name = "crossbeam-deque" version = "0.7.3" @@ -334,6 +370,18 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" +[[package]] +name = "flate2" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2cfff41391129e0a856d6d822600b8d71179d46879e310417eb9c762eb178b42" +dependencies = [ + "cfg-if", + "crc32fast", + "libc", + "miniz_oxide", +] + [[package]] name = "from-pest" version = "0.3.1" @@ -492,6 +540,8 @@ dependencies = [ "snarkos-utilities", "thiserror", "toml", + "walkdir", + "zip", ] [[package]] @@ -692,6 +742,18 @@ dependencies = [ "sha-1", ] +[[package]] +name = "pkg-config" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05da548ad6865900e60eaba7f589cc0783590a92e940c26953ff81ddbab2d677" + +[[package]] +name = "podio" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b18befed8bc2b61abc79a457295e7e838417326da1586050b919414073977f19" + [[package]] name = "ppv-lite86" version = "0.2.8" @@ -857,6 +919,15 @@ version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + [[package]] name = "scopeguard" version = "1.1.0" @@ -1131,6 +1202,16 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "time" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "toml" version = "0.5.6" @@ -1188,6 +1269,17 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" +[[package]] +name = "walkdir" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "777182bc735b6424e1a57516d35ed72cb8019d85c8c9bf536dccb3445c1a2f7d" +dependencies = [ + "same-file", + "winapi", + "winapi-util", +] + [[package]] name = "wasi" version = "0.9.0+wasi-snapshot-preview1" @@ -1224,3 +1316,16 @@ name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "zip" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58287c28d78507f5f91f2a4cf1e8310e2c76fd4c6932f93ac60fd1ceb402db7d" +dependencies = [ + "bzip2", + "crc32fast", + "flate2", + "podio", + "time", +] diff --git a/Cargo.toml b/Cargo.toml index 076c80b80b..0b033a2fc8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -37,6 +37,8 @@ serde = { version = "1.0", features = ["derive"] } serde_json = { version = "1.0" } toml = { version = "0.5" } thiserror = { version = "1.0" } +walkdir = { version = "2" } +zip = { version = "0.5" } [dev-dependencies] rusty-hook = { version = "0.11.1" } diff --git a/leo/commands/publish.rs b/leo/commands/publish.rs index e1755457db..afcd77136c 100644 --- a/leo/commands/publish.rs +++ b/leo/commands/publish.rs @@ -1,7 +1,30 @@ -use crate::{cli::*, cli_types::*, commands::BuildCommand, errors::CLIError, files::Manifest}; +use crate::{ + cli::*, + cli_types::*, + commands::BuildCommand, + directories::{INPUTS_DIRECTORY_NAME, OUTPUTS_DIRECTORY_NAME}, + errors::CLIError, + files::{ + Manifest, + BYTES_FILE_EXTENSION, + CHECKSUM_FILE_EXTENSION, + INPUTS_FILE_EXTENSION, + PROOF_FILE_EXTENSION, + PROVING_KEY_FILE_EXTENSION, + VERIFICATION_KEY_FILE_EXTENSION, + }, +}; use clap::ArgMatches; -use std::{convert::TryFrom, env::current_dir}; +use std::{ + convert::TryFrom, + env::current_dir, + fs::File, + io::{Read, Write}, + path::{Path, PathBuf}, +}; +use walkdir::WalkDir; +use zip::write::{FileOptions, ZipWriter}; #[derive(Debug)] pub struct PublishCommand; @@ -27,11 +50,81 @@ impl CLI for PublishCommand { let (_program, _checksum_differs) = BuildCommand::output(options)?; // Get the package name - let path = current_dir()?; - let _package_name = Manifest::try_from(&path)?.get_package_name(); + let src_dir = current_dir()?; - log::info!("Unimplemented - `leo publish`"); + // Build walkdir iterator from current package + let walkdir = WalkDir::new(src_dir.clone()); + + // Create zip file + let package_name = Manifest::try_from(&src_dir)?.get_package_name(); + let mut zip_file = src_dir.clone(); + zip_file.push(PathBuf::from(format!("{}{}", package_name, ".zip".to_string()))); + + let file = &mut File::create(zip_file)?; + let mut zip = ZipWriter::new(file); + let zip_options = FileOptions::default() + .compression_method(zip::CompressionMethod::Stored) + .unix_permissions(0o755); + + // Walk through files in directory and write desired ones to the zip file + let mut buffer = Vec::new(); + for entry in walkdir.into_iter().filter_map(|e| e.ok()) { + let path = entry.path(); + let name = path.strip_prefix(src_dir.as_path()).unwrap(); + + // filter excluded paths + if is_excluded(name) { + continue; + } + + // write file or directory + if path.is_file() { + log::info!("adding file {:?} as {:?}", path, name); + zip.start_file_from_path(name, zip_options)?; + let mut f = File::open(path)?; + + f.read_to_end(&mut buffer)?; + zip.write_all(&*buffer)?; + buffer.clear(); + } else if name.as_os_str().len() != 0 { + // Only if not root Avoids path spec / warning + // and mapname conversion failed error on unzip + log::info!("adding dir {:?} as {:?}", path, name); + zip.add_directory_from_path(name, zip_options)?; + } + } + + zip.finish()?; + + log::info!("zip file created"); Ok(()) } } + +fn is_excluded(path: &Path) -> bool { + // excluded directories: `/inputs`, `/outputs` + if path.ends_with(INPUTS_DIRECTORY_NAME.trim_end_matches("/")) + | path.ends_with(OUTPUTS_DIRECTORY_NAME.trim_end_matches("/")) + { + return true; + } + + // excluded extensions: `.in`, `.bytes`, `lpk`, `lvk`, `.proof`, `.sum` + path.extension() + .map(|ext| { + if ext.eq(INPUTS_FILE_EXTENSION.trim_start_matches(".")) + | ext.eq(BYTES_FILE_EXTENSION.trim_start_matches(".")) + | ext.eq(PROVING_KEY_FILE_EXTENSION.trim_start_matches(".")) + | ext.eq(VERIFICATION_KEY_FILE_EXTENSION.trim_start_matches(".")) + | ext.eq(PROOF_FILE_EXTENSION.trim_start_matches(".")) + | ext.eq(CHECKSUM_FILE_EXTENSION.trim_start_matches(".")) + | ext.eq("zip") + { + true + } else { + false + } + }) + .unwrap_or(false) +} diff --git a/leo/errors/cli.rs b/leo/errors/cli.rs index 80dbe4ce5d..95d81d5e61 100644 --- a/leo/errors/cli.rs +++ b/leo/errors/cli.rs @@ -1,5 +1,8 @@ use crate::errors::*; +use walkdir::Error as WalkDirError; +use zip::result::ZipError; + #[derive(Debug, Error)] pub enum CLIError { #[error("{}", _0)] @@ -55,6 +58,12 @@ pub enum CLIError { #[error("{}", _0)] VerificationKeyFileError(VerificationKeyFileError), + + #[error("{}", _0)] + WalkDirError(WalkDirError), + + #[error("{}", _0)] + ZipError(ZipError), } impl From for CLIError { @@ -176,6 +185,20 @@ impl From for CLIError { } } +impl From for CLIError { + fn from(error: WalkDirError) -> Self { + log::error!("{}\n", error); + CLIError::WalkDirError(error) + } +} + +impl From for CLIError { + fn from(error: ZipError) -> Self { + log::error!("{}\n", error); + CLIError::ZipError(error) + } +} + impl From for CLIError { fn from(error: leo_compiler::errors::CompilerError) -> Self { log::error!("{}\n", error); From d9b5c15d73d3dfe9b9f91b28be64ffda43719fd0 Mon Sep 17 00:00:00 2001 From: collin Date: Fri, 26 Jun 2020 00:57:46 -0700 Subject: [PATCH 02/26] impl zip file struct --- leo/commands/build.rs | 27 +---- leo/commands/publish.rs | 99 ++----------------- leo/errors/cli.rs | 29 +----- leo/errors/files/mod.rs | 4 +- leo/errors/files/{bytes.rs => zip.rs} | 14 ++- leo/files/bytes.rs | 60 ------------ leo/files/mod.rs | 4 +- leo/files/zip.rs | 136 ++++++++++++++++++++++++++ 8 files changed, 165 insertions(+), 208 deletions(-) rename leo/errors/files/{bytes.rs => zip.rs} (55%) delete mode 100644 leo/files/bytes.rs create mode 100644 leo/files/zip.rs diff --git a/leo/commands/build.rs b/leo/commands/build.rs index 727437510b..ffba966a56 100644 --- a/leo/commands/build.rs +++ b/leo/commands/build.rs @@ -10,7 +10,6 @@ use leo_compiler::{compiler::Compiler, group::edwards_bls12::EdwardsGroupType}; use snarkos_algorithms::snark::KeypairAssembly; use snarkos_curves::{bls12_377::Bls12_377, edwards_bls12::Fq}; -use crate::files::BytesFile; use clap::ArgMatches; use std::{convert::TryFrom, env::current_dir}; @@ -60,30 +59,8 @@ impl CLI for BuildCommand { main_file_path.push(SOURCE_DIRECTORY_NAME); main_file_path.push(MAIN_FILE_NAME); - // Check if the program bytes exist - let existing_bytes = BytesFile::new(&package_name).exists_at(&path); - - let program = if existing_bytes { - // Load the program ast from stored bytes - let bytes = BytesFile::new(&package_name).read_from(&path)?; - - let mut program = Compiler::::from_bytes(bytes.as_slice())?; - - program.set_path(main_file_path.clone()); - - program - } else { - // Load the program at `main_file_path` - let program = - Compiler::::new_from_path(package_name.clone(), main_file_path.clone())?; - - // Store the program ast as bytes - let bytes = program.to_bytes()?; - - BytesFile::new(&package_name).write_to(&path, bytes)?; - - program - }; + // Load the program at `main_file_path` + let program = Compiler::::new_from_path(package_name.clone(), main_file_path.clone())?; // Compute the current program checksum let program_checksum = program.checksum()?; diff --git a/leo/commands/publish.rs b/leo/commands/publish.rs index afcd77136c..073221904d 100644 --- a/leo/commands/publish.rs +++ b/leo/commands/publish.rs @@ -2,29 +2,12 @@ use crate::{ cli::*, cli_types::*, commands::BuildCommand, - directories::{INPUTS_DIRECTORY_NAME, OUTPUTS_DIRECTORY_NAME}, errors::CLIError, - files::{ - Manifest, - BYTES_FILE_EXTENSION, - CHECKSUM_FILE_EXTENSION, - INPUTS_FILE_EXTENSION, - PROOF_FILE_EXTENSION, - PROVING_KEY_FILE_EXTENSION, - VERIFICATION_KEY_FILE_EXTENSION, - }, + files::{Manifest, ZipFile}, }; use clap::ArgMatches; -use std::{ - convert::TryFrom, - env::current_dir, - fs::File, - io::{Read, Write}, - path::{Path, PathBuf}, -}; -use walkdir::WalkDir; -use zip::write::{FileOptions, ZipWriter}; +use std::{convert::TryFrom, env::current_dir}; #[derive(Debug)] pub struct PublishCommand; @@ -50,81 +33,17 @@ impl CLI for PublishCommand { let (_program, _checksum_differs) = BuildCommand::output(options)?; // Get the package name - let src_dir = current_dir()?; - - // Build walkdir iterator from current package - let walkdir = WalkDir::new(src_dir.clone()); + let path = current_dir()?; + let package_name = Manifest::try_from(&path)?.get_package_name(); // Create zip file - let package_name = Manifest::try_from(&src_dir)?.get_package_name(); - let mut zip_file = src_dir.clone(); - zip_file.push(PathBuf::from(format!("{}{}", package_name, ".zip".to_string()))); - - let file = &mut File::create(zip_file)?; - let mut zip = ZipWriter::new(file); - let zip_options = FileOptions::default() - .compression_method(zip::CompressionMethod::Stored) - .unix_permissions(0o755); - - // Walk through files in directory and write desired ones to the zip file - let mut buffer = Vec::new(); - for entry in walkdir.into_iter().filter_map(|e| e.ok()) { - let path = entry.path(); - let name = path.strip_prefix(src_dir.as_path()).unwrap(); - - // filter excluded paths - if is_excluded(name) { - continue; - } - - // write file or directory - if path.is_file() { - log::info!("adding file {:?} as {:?}", path, name); - zip.start_file_from_path(name, zip_options)?; - let mut f = File::open(path)?; - - f.read_to_end(&mut buffer)?; - zip.write_all(&*buffer)?; - buffer.clear(); - } else if name.as_os_str().len() != 0 { - // Only if not root Avoids path spec / warning - // and mapname conversion failed error on unzip - log::info!("adding dir {:?} as {:?}", path, name); - zip.add_directory_from_path(name, zip_options)?; - } + let zip_file = ZipFile::new(&package_name); + if zip_file.exists_at(&path) { + log::info!("Existing package zip file found. Skipping compression.") + } else { + zip_file.write(&path)?; } - zip.finish()?; - - log::info!("zip file created"); - Ok(()) } } - -fn is_excluded(path: &Path) -> bool { - // excluded directories: `/inputs`, `/outputs` - if path.ends_with(INPUTS_DIRECTORY_NAME.trim_end_matches("/")) - | path.ends_with(OUTPUTS_DIRECTORY_NAME.trim_end_matches("/")) - { - return true; - } - - // excluded extensions: `.in`, `.bytes`, `lpk`, `lvk`, `.proof`, `.sum` - path.extension() - .map(|ext| { - if ext.eq(INPUTS_FILE_EXTENSION.trim_start_matches(".")) - | ext.eq(BYTES_FILE_EXTENSION.trim_start_matches(".")) - | ext.eq(PROVING_KEY_FILE_EXTENSION.trim_start_matches(".")) - | ext.eq(VERIFICATION_KEY_FILE_EXTENSION.trim_start_matches(".")) - | ext.eq(PROOF_FILE_EXTENSION.trim_start_matches(".")) - | ext.eq(CHECKSUM_FILE_EXTENSION.trim_start_matches(".")) - | ext.eq("zip") - { - true - } else { - false - } - }) - .unwrap_or(false) -} diff --git a/leo/errors/cli.rs b/leo/errors/cli.rs index 95d81d5e61..a11c2bcb18 100644 --- a/leo/errors/cli.rs +++ b/leo/errors/cli.rs @@ -1,15 +1,12 @@ use crate::errors::*; -use walkdir::Error as WalkDirError; -use zip::result::ZipError; - #[derive(Debug, Error)] pub enum CLIError { #[error("{}", _0)] BuildError(BuildError), #[error("{}", _0)] - BytesFileError(BytesFileError), + BytesFileError(ZipFileError), #[error("{}: {}", _0, _1)] Crate(&'static str, String), @@ -58,16 +55,10 @@ pub enum CLIError { #[error("{}", _0)] VerificationKeyFileError(VerificationKeyFileError), - - #[error("{}", _0)] - WalkDirError(WalkDirError), - - #[error("{}", _0)] - ZipError(ZipError), } -impl From for CLIError { - fn from(error: BytesFileError) -> Self { +impl From for CLIError { + fn from(error: ZipFileError) -> Self { log::error!("{}\n", error); CLIError::BytesFileError(error) } @@ -185,20 +176,6 @@ impl From for CLIError { } } -impl From for CLIError { - fn from(error: WalkDirError) -> Self { - log::error!("{}\n", error); - CLIError::WalkDirError(error) - } -} - -impl From for CLIError { - fn from(error: ZipError) -> Self { - log::error!("{}\n", error); - CLIError::ZipError(error) - } -} - impl From for CLIError { fn from(error: leo_compiler::errors::CompilerError) -> Self { log::error!("{}\n", error); diff --git a/leo/errors/files/mod.rs b/leo/errors/files/mod.rs index 6300c96a14..d7f66d149d 100644 --- a/leo/errors/files/mod.rs +++ b/leo/errors/files/mod.rs @@ -1,5 +1,5 @@ -pub mod bytes; -pub use self::bytes::*; +pub mod zip; +pub use self::zip::*; pub mod checksum; pub use self::checksum::*; diff --git a/leo/errors/files/bytes.rs b/leo/errors/files/zip.rs similarity index 55% rename from leo/errors/files/bytes.rs rename to leo/errors/files/zip.rs index 11d90369e9..ca477d8167 100644 --- a/leo/errors/files/bytes.rs +++ b/leo/errors/files/zip.rs @@ -1,7 +1,9 @@ use std::{io, path::PathBuf}; +use walkdir::Error as WalkDirError; +use zip::result::ZipError; #[derive(Debug, Error)] -pub enum BytesFileError { +pub enum ZipFileError { #[error("{}: {}", _0, _1)] Crate(&'static str, String), @@ -13,10 +15,16 @@ pub enum BytesFileError { #[error("writing: {}", _0)] Writing(io::Error), + + #[error("{}", _0)] + WalkDirError(#[from] WalkDirError), + + #[error("{}", _0)] + ZipError(#[from] ZipError), } -impl From for BytesFileError { +impl From for ZipFileError { fn from(error: std::io::Error) -> Self { - BytesFileError::Crate("std::io", format!("{}", error)) + ZipFileError::Crate("std::io", format!("{}", error)) } } diff --git a/leo/files/bytes.rs b/leo/files/bytes.rs deleted file mode 100644 index 3a486ba1bc..0000000000 --- a/leo/files/bytes.rs +++ /dev/null @@ -1,60 +0,0 @@ -//! The program bytes file. - -use crate::{directories::outputs::OUTPUTS_DIRECTORY_NAME, errors::BytesFileError}; - -use serde::Deserialize; -use std::{ - fs::{self, File}, - io::Write, - path::PathBuf, -}; - -pub static BYTES_FILE_EXTENSION: &str = ".bytes"; - -#[derive(Deserialize)] -pub struct BytesFile { - pub package_name: String, -} - -impl BytesFile { - pub fn new(package_name: &str) -> Self { - Self { - package_name: package_name.to_string(), - } - } - - pub fn exists_at(&self, path: &PathBuf) -> bool { - let path = self.setup_file_path(path); - path.exists() - } - - /// Reads the program bytes from the given file path if it exists. - pub fn read_from(&self, path: &PathBuf) -> Result, BytesFileError> { - let path = self.setup_file_path(path); - - Ok(fs::read(&path).map_err(|_| BytesFileError::FileReadError(path.clone()))?) - } - - /// Writes the given program bytes to a file. - pub fn write_to(&self, path: &PathBuf, bytes: Vec) -> Result<(), BytesFileError> { - let path = self.setup_file_path(path); - - let mut file = File::create(&path)?; - file.write_all(bytes.as_slice())?; - - log::info!("program bytes stored to {:?}", path); - - Ok(()) - } - - fn setup_file_path(&self, path: &PathBuf) -> PathBuf { - let mut path = path.to_owned(); - if path.is_dir() { - if !path.ends_with(OUTPUTS_DIRECTORY_NAME) { - path.push(PathBuf::from(OUTPUTS_DIRECTORY_NAME)); - } - path.push(PathBuf::from(format!("{}{}", self.package_name, BYTES_FILE_EXTENSION))); - } - path - } -} diff --git a/leo/files/mod.rs b/leo/files/mod.rs index bd2fae1ed4..472330e132 100644 --- a/leo/files/mod.rs +++ b/leo/files/mod.rs @@ -1,5 +1,5 @@ -pub mod bytes; -pub use self::bytes::*; +pub mod zip; +pub use self::zip::*; pub mod checksum; pub use self::checksum::*; diff --git a/leo/files/zip.rs b/leo/files/zip.rs new file mode 100644 index 0000000000..d536c00838 --- /dev/null +++ b/leo/files/zip.rs @@ -0,0 +1,136 @@ +//! The program package zip file. + +use crate::{ + directories::{INPUTS_DIRECTORY_NAME, OUTPUTS_DIRECTORY_NAME}, + errors::ZipFileError, + files::{ + CHECKSUM_FILE_EXTENSION, + INPUTS_FILE_EXTENSION, + PROOF_FILE_EXTENSION, + PROVING_KEY_FILE_EXTENSION, + VERIFICATION_KEY_FILE_EXTENSION, + }, +}; + +use serde::Deserialize; +use std::{ + fs::File, + io::{Read, Write}, + path::{Path, PathBuf}, +}; +use walkdir::WalkDir; +use zip::write::{FileOptions, ZipWriter}; + +pub static ZIP_FILE_EXTENSION: &str = ".zip"; + +#[derive(Deserialize)] +pub struct ZipFile { + pub package_name: String, +} + +impl ZipFile { + pub fn new(package_name: &str) -> Self { + Self { + package_name: package_name.to_string(), + } + } + + pub fn exists_at(&self, path: &PathBuf) -> bool { + let path = self.setup_file_path(path); + path.exists() + } + + // /// Reads the program bytes from the given file path if it exists. + // pub fn read_from(&self, path: &PathBuf) -> Result, ZipFileError> { + // let path = self.setup_file_path(path); + // + // Ok(fs::read(&path).map_err(|_| ZipFileError::FileReadError(path.clone()))?) + // } + + /// Writes the current package contents to a zip file. + pub fn write(&self, src_dir: &PathBuf) -> Result<(), ZipFileError> { + // Build walkdir iterator from current package + let walkdir = WalkDir::new(src_dir.clone()); + + // Create zip file + let path = self.setup_file_path(src_dir); + + let file = &mut File::create(&path)?; + let mut zip = ZipWriter::new(file); + let options = FileOptions::default() + .compression_method(zip::CompressionMethod::Stored) + .unix_permissions(0o755); + + // Walk through files in directory and write desired ones to the zip file + let mut buffer = Vec::new(); + for entry in walkdir.into_iter().filter_map(|e| e.ok()) { + let path = entry.path(); + let name = path.strip_prefix(src_dir.as_path()).unwrap(); + + // filter excluded paths + if is_excluded(name) { + continue; + } + + // write file or directory + if path.is_file() { + log::info!("\tadding file {:?} as {:?}", path, name); + zip.start_file_from_path(name, options)?; + let mut f = File::open(path)?; + + f.read_to_end(&mut buffer)?; + zip.write_all(&*buffer)?; + buffer.clear(); + } else if name.as_os_str().len() != 0 { + // Only if not root Avoids path spec / warning + // and mapname conversion failed error on unzip + log::info!("\tadding dir {:?} as {:?}", path, name); + zip.add_directory_from_path(name, options)?; + } + } + + zip.finish()?; + + log::info!("Package zip file created successfully {:?}", path); + + Ok(()) + } + + fn setup_file_path(&self, path: &PathBuf) -> PathBuf { + let mut path = path.to_owned(); + if path.is_dir() { + if !path.ends_with(OUTPUTS_DIRECTORY_NAME) { + path.push(PathBuf::from(OUTPUTS_DIRECTORY_NAME)); + } + path.push(PathBuf::from(format!("{}{}", self.package_name, ZIP_FILE_EXTENSION))); + } + path + } +} + +fn is_excluded(path: &Path) -> bool { + // excluded directories: `/inputs`, `/outputs` + if path.ends_with(INPUTS_DIRECTORY_NAME.trim_end_matches("/")) + | path.ends_with(OUTPUTS_DIRECTORY_NAME.trim_end_matches("/")) + { + return true; + } + + // excluded extensions: `.in`, `.bytes`, `lpk`, `lvk`, `.proof`, `.sum` + path.extension() + .map(|ext| { + if ext.eq(INPUTS_FILE_EXTENSION.trim_start_matches(".")) + | ext.eq(ZIP_FILE_EXTENSION.trim_start_matches(".")) + | ext.eq(PROVING_KEY_FILE_EXTENSION.trim_start_matches(".")) + | ext.eq(VERIFICATION_KEY_FILE_EXTENSION.trim_start_matches(".")) + | ext.eq(PROOF_FILE_EXTENSION.trim_start_matches(".")) + | ext.eq(CHECKSUM_FILE_EXTENSION.trim_start_matches(".")) + | ext.eq(ZIP_FILE_EXTENSION.trim_start_matches(".")) + { + true + } else { + false + } + }) + .unwrap_or(false) +} From b5d90b857bce1d5c7212f1ef37472f701bf0a2c9 Mon Sep 17 00:00:00 2001 From: collin Date: Fri, 26 Jun 2020 14:18:05 -0700 Subject: [PATCH 03/26] impl import package syntax for ast and types --- ast/src/imports/import.rs | 9 +- ast/src/imports/import_source.rs | 13 --- ast/src/imports/mod.rs | 12 +- ast/src/imports/package.rs | 13 +++ ast/src/imports/package_access.rs | 15 +++ ast/src/imports/star.rs | 7 ++ ast/src/leo.pest | 19 +++- compiler/src/constraints/import.rs | 165 +++++++++++++++------------- types/src/imports/import.rs | 31 ++---- types/src/imports/mod.rs | 6 + types/src/imports/package.rs | 40 +++++++ types/src/imports/package_access.rs | 58 ++++++++++ 12 files changed, 261 insertions(+), 127 deletions(-) delete mode 100644 ast/src/imports/import_source.rs create mode 100644 ast/src/imports/package.rs create mode 100644 ast/src/imports/package_access.rs create mode 100644 ast/src/imports/star.rs create mode 100644 types/src/imports/package.rs create mode 100644 types/src/imports/package_access.rs diff --git a/ast/src/imports/import.rs b/ast/src/imports/import.rs index 269b04b005..dbecc1b8fc 100644 --- a/ast/src/imports/import.rs +++ b/ast/src/imports/import.rs @@ -1,8 +1,4 @@ -use crate::{ - ast::Rule, - common::LineEnd, - imports::{ImportSource, ImportSymbol}, -}; +use crate::{ast::Rule, common::LineEnd, imports::Package}; use pest::Span; use pest_ast::FromPest; @@ -10,8 +6,7 @@ use pest_ast::FromPest; #[derive(Clone, Debug, FromPest, PartialEq)] #[pest_ast(rule(Rule::import))] pub struct Import<'ast> { - pub source: ImportSource<'ast>, - pub symbols: Vec>, + pub package: Package<'ast>, pub line_end: LineEnd, #[pest_ast(outer())] pub span: Span<'ast>, diff --git a/ast/src/imports/import_source.rs b/ast/src/imports/import_source.rs deleted file mode 100644 index 221fb1022c..0000000000 --- a/ast/src/imports/import_source.rs +++ /dev/null @@ -1,13 +0,0 @@ -use crate::ast::{span_into_string, Rule}; - -use pest::Span; -use pest_ast::FromPest; - -#[derive(Clone, Debug, FromPest, PartialEq)] -#[pest_ast(rule(Rule::import_source))] -pub struct ImportSource<'ast> { - #[pest_ast(outer(with(span_into_string)))] - pub value: String, - #[pest_ast(outer())] - pub span: Span<'ast>, -} diff --git a/ast/src/imports/mod.rs b/ast/src/imports/mod.rs index 20a794eeda..c2b4b01765 100644 --- a/ast/src/imports/mod.rs +++ b/ast/src/imports/mod.rs @@ -1,8 +1,14 @@ pub mod import; pub use import::*; -pub mod import_source; -pub use import_source::*; - pub mod import_symbol; pub use import_symbol::*; + +pub mod package; +pub use package::*; + +pub mod package_access; +pub use package_access::*; + +pub mod star; +pub use star::*; diff --git a/ast/src/imports/package.rs b/ast/src/imports/package.rs new file mode 100644 index 0000000000..42ac528961 --- /dev/null +++ b/ast/src/imports/package.rs @@ -0,0 +1,13 @@ +use crate::{ast::Rule, common::Identifier, imports::PackageAccess}; + +use pest::Span; +use pest_ast::FromPest; + +#[derive(Clone, Debug, FromPest, PartialEq)] +#[pest_ast(rule(Rule::package))] +pub struct Package<'ast> { + pub name: Identifier<'ast>, + pub access: PackageAccess<'ast>, + #[pest_ast(outer())] + pub span: Span<'ast>, +} diff --git a/ast/src/imports/package_access.rs b/ast/src/imports/package_access.rs new file mode 100644 index 0000000000..2581e74ee9 --- /dev/null +++ b/ast/src/imports/package_access.rs @@ -0,0 +1,15 @@ +use crate::{ + ast::Rule, + imports::{ImportSymbol, Package, Star}, +}; + +use pest_ast::FromPest; + +#[derive(Clone, Debug, FromPest, PartialEq)] +#[pest_ast(rule(Rule::package_access))] +pub enum PackageAccess<'ast> { + Star(Star), + SubPackage(Box>), + Multiple(Vec>), + Symbol(ImportSymbol<'ast>), +} diff --git a/ast/src/imports/star.rs b/ast/src/imports/star.rs new file mode 100644 index 0000000000..7cf489a418 --- /dev/null +++ b/ast/src/imports/star.rs @@ -0,0 +1,7 @@ +use crate::ast::Rule; + +use pest_ast::FromPest; + +#[derive(Clone, Debug, FromPest, PartialEq)] +#[pest_ast(rule(Rule::star))] +pub struct Star {} diff --git a/ast/src/leo.pest b/ast/src/leo.pest index 52e7f3211c..af782fe03f 100644 --- a/ast/src/leo.pest +++ b/ast/src/leo.pest @@ -286,14 +286,25 @@ test_function = { "test" ~ function_definition } /// Imports // Declared in imports/import.rs -import = { "from" ~ "\"" ~ import_source ~ "\"" ~ "import" ~ ("*" | ("{" ~ NEWLINE* ~ import_symbol_tuple ~ NEWLINE* ~ "}") | import_symbol) ~ LINE_END} +import = { "import" ~ package ~ LINE_END} -// Declared in imports/import_source.rs -import_source = @{ (!"\"" ~ ANY)* } +// Declared in imports/package.rs +package = { identifier ~ "." ~ package_access } +package_tuple = _{ "(" ~ package ~ ("," ~ NEWLINE* ~ package)* ~ ")" } + +// Declared in imports/package_access +package_access = { + star + | package // subpackage + | package_tuple + | import_symbol +} + +// Declared in imports/star.rs +star = {"*"} // Declared in imports/import_symbol.rs import_symbol = { identifier ~ ("as" ~ identifier)? } -import_symbol_tuple = _{ import_symbol ~ ("," ~ NEWLINE* ~ import_symbol)* } /// Utilities diff --git a/compiler/src/constraints/import.rs b/compiler/src/constraints/import.rs index 0c351a64d5..516d76fd1e 100644 --- a/compiler/src/constraints/import.rs +++ b/compiler/src/constraints/import.rs @@ -5,87 +5,100 @@ use crate::{ GroupType, }; use leo_ast::LeoParser; -use leo_types::{Import, Program}; +use leo_types::{Import, Package, Program}; use snarkos_models::curves::{Field, PrimeField}; use std::env::current_dir; impl> ConstrainedProgram { + // pub fn enforce_package(&mut self, scope: String, package: Package) -> Result<(), ImportError> { + // let path = current_dir().map_err(|error| ImportError::directory_error(error, import.span.clone()))?; + // + // // Sanitize the package path to the imports directory + // let mut package_path = path.clone(); + // if package_path.is_file() { + // package_path.pop(); + // } + // + // Ok(()) + // } + pub fn enforce_import(&mut self, scope: String, import: Import) -> Result<(), ImportError> { - let path = current_dir().map_err(|error| ImportError::directory_error(error, import.span.clone()))?; - - // Sanitize the package path to the imports directory - let mut package_path = path.clone(); - if package_path.is_file() { - package_path.pop(); - } - - // Construct the path to the import file in the import directory - let mut main_file_path = package_path.clone(); - main_file_path.push(import.path_string_full()); - - println!("Compiling import - {:?}", main_file_path); - - // Build the abstract syntax tree - let file_path = &main_file_path; - let input_file = &LeoParser::load_file(file_path)?; - let syntax_tree = LeoParser::parse_file(file_path, input_file)?; - - // Generate aleo program from file - let mut program = Program::from(syntax_tree, import.path_string.clone()); - - // Use same namespace as calling function for imported symbols - program = program.name(scope); - - // * -> import all imports, circuits, functions in the current scope - if import.is_star() { - // recursively evaluate program statements - self.resolve_definitions(program) - } else { - let program_name = program.name.clone(); - - // match each import symbol to a symbol in the imported file - for symbol in import.symbols.into_iter() { - // see if the imported symbol is a circuit - let matched_circuit = program - .circuits - .clone() - .into_iter() - .find(|(circuit_name, _circuit_def)| symbol.symbol == *circuit_name); - - let value = match matched_circuit { - Some((_circuit_name, circuit_def)) => ConstrainedValue::CircuitDefinition(circuit_def), - None => { - // see if the imported symbol is a function - let matched_function = program - .functions - .clone() - .into_iter() - .find(|(function_name, _function)| symbol.symbol.name == *function_name.name); - - match matched_function { - Some((_function_name, function)) => ConstrainedValue::Function(None, function), - None => return Err(ImportError::unknown_symbol(symbol, program_name, file_path)), - } - } - }; - - // take the alias if it is present - let resolved_name = symbol.alias.unwrap_or(symbol.symbol); - let resolved_circuit_name = new_scope(program_name.clone(), resolved_name.to_string()); - - // store imported circuit under resolved name - self.store(resolved_circuit_name, value); - } - - // evaluate all import statements in imported file - program - .imports - .into_iter() - .map(|nested_import| self.enforce_import(program_name.clone(), nested_import)) - .collect::, ImportError>>()?; - - Ok(()) - } + // let path = current_dir().map_err(|error| ImportError::directory_error(error, import.span.clone()))?; + // + // // Sanitize the package path to the imports directory + // let mut package_path = path.clone(); + // if package_path.is_file() { + // package_path.pop(); + // } + // + // // Construct the path to the import file in the import directory + // let mut main_file_path = package_path.clone(); + // main_file_path.push(import.path_string_full()); + // + // println!("Compiling import - {:?}", main_file_path); + // + // // Build the abstract syntax tree + // let file_path = &main_file_path; + // let input_file = &LeoParser::load_file(file_path)?; + // let syntax_tree = LeoParser::parse_file(file_path, input_file)?; + // + // // Generate aleo program from file + // let mut program = Program::from(syntax_tree, import.path_string.clone()); + // + // // Use same namespace as calling function for imported symbols + // program = program.name(scope); + // + // // * -> import all imports, circuits, functions in the current scope + // if import.is_star() { + // // recursively evaluate program statements + // self.resolve_definitions(program) + // } else { + // let program_name = program.name.clone(); + // + // // match each import symbol to a symbol in the imported file + // for symbol in import.symbols.into_iter() { + // // see if the imported symbol is a circuit + // let matched_circuit = program + // .circuits + // .clone() + // .into_iter() + // .find(|(circuit_name, _circuit_def)| symbol.symbol == *circuit_name); + // + // let value = match matched_circuit { + // Some((_circuit_name, circuit_def)) => ConstrainedValue::CircuitDefinition(circuit_def), + // None => { + // // see if the imported symbol is a function + // let matched_function = program + // .functions + // .clone() + // .into_iter() + // .find(|(function_name, _function)| symbol.symbol.name == *function_name.name); + // + // match matched_function { + // Some((_function_name, function)) => ConstrainedValue::Function(None, function), + // None => return Err(ImportError::unknown_symbol(symbol, program_name, file_path)), + // } + // } + // }; + // + // // take the alias if it is present + // let resolved_name = symbol.alias.unwrap_or(symbol.symbol); + // let resolved_circuit_name = new_scope(program_name.clone(), resolved_name.to_string()); + // + // // store imported circuit under resolved name + // self.store(resolved_circuit_name, value); + // } + // + // // evaluate all import statements in imported file + // program + // .imports + // .into_iter() + // .map(|nested_import| self.enforce_import(program_name.clone(), nested_import)) + // .collect::, ImportError>>()?; + // + // Ok(()) + // } + unimplemented!() } } diff --git a/types/src/imports/import.rs b/types/src/imports/import.rs index dc800efd7b..79fd6f53c6 100644 --- a/types/src/imports/import.rs +++ b/types/src/imports/import.rs @@ -1,6 +1,6 @@ //! The import type for a Leo program. -use crate::{ImportSymbol, Span}; +use crate::{ImportSymbol, Package, Span}; use leo_ast::imports::Import as AstImport; use serde::{Deserialize, Serialize}; @@ -8,20 +8,14 @@ use std::fmt; #[derive(Clone, Serialize, Deserialize)] pub struct Import { - pub path_string: String, - pub symbols: Vec, + pub package: Package, pub span: Span, } impl<'ast> From> for Import { fn from(import: AstImport<'ast>) -> Self { Import { - path_string: import.source.value, - symbols: import - .symbols - .into_iter() - .map(|symbol| ImportSymbol::from(symbol)) - .collect(), + package: Package::from(import.package), span: Span::from(import.span), } } @@ -29,28 +23,17 @@ impl<'ast> From> for Import { impl Import { pub fn path_string_full(&self) -> String { - format!("{}.leo", self.path_string) + format!("{}.leo", self.package.name) } // from "./import" import *; pub fn is_star(&self) -> bool { - self.symbols.is_empty() + // self.symbols.is_empty() + false } fn format(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "from {} import ", self.path_string)?; - if self.symbols.is_empty() { - write!(f, "*") - } else { - write!(f, "{{\n")?; - for (i, symbol) in self.symbols.iter().enumerate() { - write!(f, "{}", symbol)?; - if i < self.symbols.len() - 1 { - write!(f, ",\n")?; - } - } - write!(f, "\n}}") - } + write!(f, "import {};", self.package) } } diff --git a/types/src/imports/mod.rs b/types/src/imports/mod.rs index 78250a4179..09c4d143f2 100644 --- a/types/src/imports/mod.rs +++ b/types/src/imports/mod.rs @@ -3,3 +3,9 @@ pub use import::*; pub mod import_symbol; pub use import_symbol::*; + +pub mod package; +pub use package::*; + +pub mod package_access; +pub use package_access::*; diff --git a/types/src/imports/package.rs b/types/src/imports/package.rs new file mode 100644 index 0000000000..666f92e5b9 --- /dev/null +++ b/types/src/imports/package.rs @@ -0,0 +1,40 @@ +use crate::{common::Identifier, PackageAccess, Span}; +use leo_ast::imports::Package as AstPackage; + +use serde::{Deserialize, Serialize}; +use std::fmt; + +#[derive(Clone, Serialize, Deserialize)] +pub struct Package { + pub name: Identifier, + pub access: PackageAccess, + pub span: Span, +} + +impl<'ast> From> for Package { + fn from(package: AstPackage<'ast>) -> Self { + Package { + name: Identifier::from(package.name), + access: PackageAccess::from(package.access), + span: Span::from(package.span), + } + } +} + +impl Package { + fn format(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}.{}", self.name, self.access) + } +} + +impl fmt::Display for Package { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.format(f) + } +} + +impl fmt::Debug for Package { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.format(f) + } +} diff --git a/types/src/imports/package_access.rs b/types/src/imports/package_access.rs new file mode 100644 index 0000000000..0ff7da7215 --- /dev/null +++ b/types/src/imports/package_access.rs @@ -0,0 +1,58 @@ +use crate::{ImportSymbol, Package}; +use leo_ast::imports::PackageAccess as AstPackageAccess; + +use serde::{Deserialize, Serialize}; +use std::fmt; + +#[derive(Clone, Serialize, Deserialize)] +pub enum PackageAccess { + Star, + SubPackage(Box), + Multiple(Vec), + Symbol(ImportSymbol), +} + +impl<'ast> From> for PackageAccess { + fn from(access: AstPackageAccess<'ast>) -> Self { + match access { + AstPackageAccess::Star(_) => PackageAccess::Star, + AstPackageAccess::SubPackage(package) => PackageAccess::SubPackage(Box::new(Package::from(*package))), + AstPackageAccess::Multiple(packages) => { + PackageAccess::Multiple(packages.into_iter().map(|package| Package::from(package)).collect()) + } + AstPackageAccess::Symbol(symbol) => PackageAccess::Symbol(ImportSymbol::from(symbol)), + } + } +} + +impl PackageAccess { + fn format(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + PackageAccess::Star => write!(f, ".*"), + PackageAccess::SubPackage(ref package) => write!(f, ".{}", package), + PackageAccess::Multiple(ref packages) => { + write!(f, ".(")?; + for (i, package) in packages.iter().enumerate() { + write!(f, "{}", package)?; + if i < packages.len() - 1 { + write!(f, ", ")?; + } + } + write!(f, ")") + } + PackageAccess::Symbol(ref symbol) => write!(f, ".{}", symbol), + } + } +} + +impl fmt::Debug for PackageAccess { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.format(f) + } +} + +impl fmt::Display for PackageAccess { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.format(f) + } +} From 5900923d9dbf39c86eb9e301e7f73f3bbd0be297 Mon Sep 17 00:00:00 2001 From: collin Date: Fri, 26 Jun 2020 15:42:52 -0700 Subject: [PATCH 04/26] impl constraints for single imports --- ast/src/leo.pest | 1 + compiler/src/constraints/import.rs | 167 ++++++++++++++++++++-- compiler/src/errors/constraints/import.rs | 16 ++- 3 files changed, 167 insertions(+), 17 deletions(-) diff --git a/ast/src/leo.pest b/ast/src/leo.pest index af782fe03f..c71838fe09 100644 --- a/ast/src/leo.pest +++ b/ast/src/leo.pest @@ -305,6 +305,7 @@ star = {"*"} // Declared in imports/import_symbol.rs import_symbol = { identifier ~ ("as" ~ identifier)? } +// import_tuple = _{} /// Utilities diff --git a/compiler/src/constraints/import.rs b/compiler/src/constraints/import.rs index 516d76fd1e..bfb4c27036 100644 --- a/compiler/src/constraints/import.rs +++ b/compiler/src/constraints/import.rs @@ -5,26 +5,163 @@ use crate::{ GroupType, }; use leo_ast::LeoParser; -use leo_types::{Import, Package, Program}; +use leo_types::{Import, ImportSymbol, Package, PackageAccess, Program}; use snarkos_models::curves::{Field, PrimeField}; -use std::env::current_dir; +use std::{env::current_dir, fs, fs::DirEntry, path::PathBuf}; + +pub(crate) static SOURCE_DIRECTORY_NAME: &str = "src/"; +// pub(crate) static IMPORTS_DIRECTORY_NAME: &str = "imports/"; impl> ConstrainedProgram { - // pub fn enforce_package(&mut self, scope: String, package: Package) -> Result<(), ImportError> { - // let path = current_dir().map_err(|error| ImportError::directory_error(error, import.span.clone()))?; - // - // // Sanitize the package path to the imports directory - // let mut package_path = path.clone(); - // if package_path.is_file() { - // package_path.pop(); - // } - // - // Ok(()) - // } + pub fn enforce_import_symbol( + &mut self, + scope: String, + entry: DirEntry, + symbol: ImportSymbol, + ) -> Result<(), ImportError> { + // make sure the given entry is file + let file_type = entry + .file_type() + .map_err(|error| ImportError::directory_error(error, symbol.span.clone()))?; + let file_name = entry + .file_name() + .into_string() + .map_err(|_| ImportError::convert_os_string(symbol.span.clone()))?; + if file_type.is_dir() { + return Err(ImportError::expected_file(file_name, symbol)); + } + + // Build the abstract syntax tree + let file_path = &entry.path(); + let input_file = &LeoParser::load_file(file_path)?; + let syntax_tree = LeoParser::parse_file(file_path, input_file)?; + + // Generate aleo program from file + let mut program = Program::from(syntax_tree, file_name.clone()); + + // Use same namespace as calling function for imported symbols + program = program.name(scope); + + // * -> import all imports, circuits, functions in the current scope + // if import.is_star() { + // // recursively evaluate program statements + // self.resolve_definitions(program) + // } else { + let program_name = program.name.clone(); + + // match each import symbol to a symbol in the imported file + // for symbol in import.symbols.into_iter() { + // see if the imported symbol is a circuit + let matched_circuit = program + .circuits + .clone() + .into_iter() + .find(|(circuit_name, _circuit_def)| symbol.symbol == *circuit_name); + + let value = match matched_circuit { + Some((_circuit_name, circuit_def)) => ConstrainedValue::CircuitDefinition(circuit_def), + None => { + // see if the imported symbol is a function + let matched_function = program + .functions + .clone() + .into_iter() + .find(|(function_name, _function)| symbol.symbol == *function_name); + + match matched_function { + Some((_function_name, function)) => ConstrainedValue::Function(None, function), + None => return Err(ImportError::unknown_symbol(symbol, program_name, file_path)), + } + } + }; + + // take the alias if it is present + let name = symbol.alias.unwrap_or(symbol.symbol); + let resolved_name = new_scope(program_name.clone(), name.to_string()); + + // store imported circuit under resolved name + self.store(resolved_name, value); + // } + + // evaluate all import statements in imported file + // todo: add logic to detect import loops + program + .imports + .into_iter() + .map(|nested_import| self.enforce_import(program_name.clone(), nested_import)) + .collect::, ImportError>>()?; + + Ok(()) + } + + pub fn enforce_package_access( + &mut self, + scope: String, + entry: DirEntry, + access: PackageAccess, + ) -> Result<(), ImportError> { + // bring one or more import symbols into scope for the current constrained program + // we will recursively traverse sub packages here until we find the desired symbol + match access { + PackageAccess::Star => unimplemented!("star not impl"), + PackageAccess::Symbol(symbol) => self.enforce_import_symbol(scope, entry, symbol), + PackageAccess::SubPackage(package) => self.enforce_package(scope, entry.path(), *package), + PackageAccess::Multiple(packages) => { + for package in packages { + self.enforce_package(scope.clone(), entry.path(), package)?; + } + + Ok(()) + } + } + } + + pub fn enforce_package(&mut self, scope: String, path: PathBuf, package: Package) -> Result<(), ImportError> { + let package_name = package.name; + + // search for package name in local src directory + let mut source_directory = path.clone(); + source_directory.push(SOURCE_DIRECTORY_NAME); + + let entries = fs::read_dir(source_directory) + .map_err(|error| ImportError::directory_error(error, package_name.span.clone()))? + .into_iter() + .collect::, std::io::Error>>() + .map_err(|error| ImportError::directory_error(error, package_name.span.clone()))?; + + let matched_source_entry = entries + .into_iter() + .find(|entry| entry.file_name().into_string().unwrap().eq(&package_name.name)); + + // search for package name in imports directory + // let mut source_directory = path.clone(); + // source_directory.push(IMPORTS_DIRECTORY_NAME); + // + // let entries = fs::read_dir(source_directory) + // .map_err(|error| ImportError::directory_error(error, package_name.span.clone()))? + // .into_iter() + // .collect::, std::io::Error>>() + // .map_err(|error| ImportError::directory_error(error, package_name.span.clone()))?; + // + // let matched_import_entry = entries.into_iter().find(|entry| { + // entry.file_name().eq(&package_name.name) + // }); + + // todo: return error if package name is present in both directories + + // Enforce package access + if let Some(entry) = matched_source_entry { + self.enforce_package_access(scope, entry, package.access)?; + } + + Ok(()) + } pub fn enforce_import(&mut self, scope: String, import: Import) -> Result<(), ImportError> { - // let path = current_dir().map_err(|error| ImportError::directory_error(error, import.span.clone()))?; + let path = current_dir().map_err(|error| ImportError::directory_error(error, import.span.clone()))?; + + self.enforce_package(scope, path, import.package) // // // Sanitize the package path to the imports directory // let mut package_path = path.clone(); @@ -91,6 +228,7 @@ impl> ConstrainedProgram { // } // // // evaluate all import statements in imported file + // // todo: add logic to detect import loops // program // .imports // .into_iter() @@ -99,6 +237,5 @@ impl> ConstrainedProgram { // // Ok(()) // } - unimplemented!() } } diff --git a/compiler/src/errors/constraints/import.rs b/compiler/src/errors/constraints/import.rs index c5d3c238d9..618124812c 100644 --- a/compiler/src/errors/constraints/import.rs +++ b/compiler/src/errors/constraints/import.rs @@ -17,12 +17,24 @@ impl ImportError { ImportError::Error(FormattedError::new_from_span(message, span)) } - pub fn directory_error(error: io::Error, span: Span) -> Self { - let message = format!("attempt to access current directory failed - {:?}", error); + pub fn convert_os_string(span: Span) -> Self { + let message = format!("failed to convert file string name, maybe an illegal character?"); Self::new_from_span(message, span) } + pub fn directory_error(error: io::Error, span: Span) -> Self { + let message = format!("compilation failed due to directory error - {:?}", error); + + Self::new_from_span(message, span) + } + + pub fn expected_file(entry: String, symbol: ImportSymbol) -> Self { + let message = format!("cannot import symbol `{}` from directory `{}`", symbol, entry); + + Self::new_from_span(message, symbol.span) + } + pub fn unknown_symbol(symbol: ImportSymbol, file: String, file_path: &PathBuf) -> Self { let message = format!("cannot find imported symbol `{}` in imported file `{}`", symbol, file); let mut error = FormattedError::new_from_span(message, symbol.span); From a4a9ed05ea58dfb8eb9d867198f0cf722ec2fb24 Mon Sep 17 00:00:00 2001 From: collin Date: Fri, 26 Jun 2020 17:12:04 -0700 Subject: [PATCH 05/26] impl constraints and tests for multiple imports --- ast/src/imports/package_access.rs | 4 +- ast/src/imports/star.rs | 6 +- ast/src/leo.pest | 6 +- compiler/src/constraints/import.rs | 178 ++++++------------ compiler/src/errors/constraints/import.rs | 17 +- compiler/tests/import/alias.leo | 2 +- compiler/tests/import/basic.leo | 2 +- compiler/tests/import/mod.rs | 19 ++ compiler/tests/import/multiple.leo | 6 +- .../tests/import/{ => src}/test_import.leo | 0 compiler/tests/import/star.leo | 2 +- types/src/imports/import.rs | 2 +- types/src/imports/package_access.rs | 26 +-- 13 files changed, 122 insertions(+), 148 deletions(-) rename compiler/tests/import/{ => src}/test_import.leo (100%) diff --git a/ast/src/imports/package_access.rs b/ast/src/imports/package_access.rs index 2581e74ee9..0574dc94a4 100644 --- a/ast/src/imports/package_access.rs +++ b/ast/src/imports/package_access.rs @@ -8,8 +8,8 @@ use pest_ast::FromPest; #[derive(Clone, Debug, FromPest, PartialEq)] #[pest_ast(rule(Rule::package_access))] pub enum PackageAccess<'ast> { - Star(Star), + Star(Star<'ast>), SubPackage(Box>), - Multiple(Vec>), Symbol(ImportSymbol<'ast>), + Multiple(Vec>), } diff --git a/ast/src/imports/star.rs b/ast/src/imports/star.rs index 7cf489a418..4f4882801e 100644 --- a/ast/src/imports/star.rs +++ b/ast/src/imports/star.rs @@ -1,7 +1,11 @@ use crate::ast::Rule; +use pest::Span; use pest_ast::FromPest; #[derive(Clone, Debug, FromPest, PartialEq)] #[pest_ast(rule(Rule::star))] -pub struct Star {} +pub struct Star<'ast> { + #[pest_ast(outer())] + pub span: Span<'ast>, +} diff --git a/ast/src/leo.pest b/ast/src/leo.pest index c71838fe09..b4a93c5c65 100644 --- a/ast/src/leo.pest +++ b/ast/src/leo.pest @@ -290,22 +290,22 @@ import = { "import" ~ package ~ LINE_END} // Declared in imports/package.rs package = { identifier ~ "." ~ package_access } -package_tuple = _{ "(" ~ package ~ ("," ~ NEWLINE* ~ package)* ~ ")" } // Declared in imports/package_access package_access = { star | package // subpackage - | package_tuple + | multiple_package_access | import_symbol } +multiple_package_access = _{ "(" ~ NEWLINE* ~ package_access ~ ("," ~ NEWLINE* ~ package_access)* ~ NEWLINE* ~ ")"} + // Declared in imports/star.rs star = {"*"} // Declared in imports/import_symbol.rs import_symbol = { identifier ~ ("as" ~ identifier)? } -// import_tuple = _{} /// Utilities diff --git a/compiler/src/constraints/import.rs b/compiler/src/constraints/import.rs index bfb4c27036..e043376b6c 100644 --- a/compiler/src/constraints/import.rs +++ b/compiler/src/constraints/import.rs @@ -5,49 +5,61 @@ use crate::{ GroupType, }; use leo_ast::LeoParser; -use leo_types::{Import, ImportSymbol, Package, PackageAccess, Program}; +use leo_types::{Import, ImportSymbol, Package, PackageAccess, Program, Span}; use snarkos_models::curves::{Field, PrimeField}; use std::{env::current_dir, fs, fs::DirEntry, path::PathBuf}; -pub(crate) static SOURCE_DIRECTORY_NAME: &str = "src/"; +static SOURCE_FILE_EXTENSION: &str = ".leo"; +static SOURCE_DIRECTORY_NAME: &str = "src/"; // pub(crate) static IMPORTS_DIRECTORY_NAME: &str = "imports/"; +fn parse_import_file(entry: &DirEntry, span: &Span) -> Result { + // make sure the given entry is file + let file_type = entry + .file_type() + .map_err(|error| ImportError::directory_error(error, span.clone()))?; + let file_name = entry + .file_name() + .into_string() + .map_err(|_| ImportError::convert_os_string(span.clone()))?; + + if file_type.is_dir() { + return Err(ImportError::expected_file(file_name, span.clone())); + } + + // Build the abstract syntax tree + let file_path = &entry.path(); + let input_file = &LeoParser::load_file(file_path)?; + let syntax_tree = LeoParser::parse_file(file_path, input_file)?; + + // Generate aleo program from file + Ok(Program::from(syntax_tree, file_name.clone())) +} + impl> ConstrainedProgram { - pub fn enforce_import_symbol( - &mut self, - scope: String, - entry: DirEntry, - symbol: ImportSymbol, - ) -> Result<(), ImportError> { - // make sure the given entry is file - let file_type = entry - .file_type() - .map_err(|error| ImportError::directory_error(error, symbol.span.clone()))?; - let file_name = entry - .file_name() - .into_string() - .map_err(|_| ImportError::convert_os_string(symbol.span.clone()))?; - if file_type.is_dir() { - return Err(ImportError::expected_file(file_name, symbol)); - } - - // Build the abstract syntax tree - let file_path = &entry.path(); - let input_file = &LeoParser::load_file(file_path)?; - let syntax_tree = LeoParser::parse_file(file_path, input_file)?; - - // Generate aleo program from file - let mut program = Program::from(syntax_tree, file_name.clone()); + pub fn enforce_import_star(&mut self, scope: String, entry: &DirEntry, span: Span) -> Result<(), ImportError> { + let mut program = parse_import_file(entry, &span)?; // Use same namespace as calling function for imported symbols program = program.name(scope); // * -> import all imports, circuits, functions in the current scope - // if import.is_star() { - // // recursively evaluate program statements - // self.resolve_definitions(program) - // } else { + self.resolve_definitions(program) + } + + pub fn enforce_import_symbol( + &mut self, + scope: String, + entry: &DirEntry, + symbol: ImportSymbol, + ) -> Result<(), ImportError> { + // Generate aleo program from file + let mut program = parse_import_file(entry, &symbol.span)?; + + // Use same namespace as calling function for imported symbols + program = program.name(scope); + let program_name = program.name.clone(); // match each import symbol to a symbol in the imported file @@ -71,7 +83,7 @@ impl> ConstrainedProgram { match matched_function { Some((_function_name, function)) => ConstrainedValue::Function(None, function), - None => return Err(ImportError::unknown_symbol(symbol, program_name, file_path)), + None => return Err(ImportError::unknown_symbol(symbol, program_name, &entry.path())), } } }; @@ -98,18 +110,18 @@ impl> ConstrainedProgram { pub fn enforce_package_access( &mut self, scope: String, - entry: DirEntry, + entry: &DirEntry, access: PackageAccess, ) -> Result<(), ImportError> { // bring one or more import symbols into scope for the current constrained program // we will recursively traverse sub packages here until we find the desired symbol match access { - PackageAccess::Star => unimplemented!("star not impl"), + PackageAccess::Star(span) => self.enforce_import_star(scope, entry, span), PackageAccess::Symbol(symbol) => self.enforce_import_symbol(scope, entry, symbol), PackageAccess::SubPackage(package) => self.enforce_package(scope, entry.path(), *package), - PackageAccess::Multiple(packages) => { - for package in packages { - self.enforce_package(scope.clone(), entry.path(), package)?; + PackageAccess::Multiple(accesses) => { + for access in accesses { + self.enforce_package_access(scope.clone(), entry, access)?; } Ok(()) @@ -130,9 +142,14 @@ impl> ConstrainedProgram { .collect::, std::io::Error>>() .map_err(|error| ImportError::directory_error(error, package_name.span.clone()))?; - let matched_source_entry = entries - .into_iter() - .find(|entry| entry.file_name().into_string().unwrap().eq(&package_name.name)); + let matched_source_entry = entries.into_iter().find(|entry| { + entry + .file_name() + .into_string() + .unwrap() + .trim_end_matches(SOURCE_FILE_EXTENSION) + .eq(&package_name.name) + }); // search for package name in imports directory // let mut source_directory = path.clone(); @@ -152,90 +169,15 @@ impl> ConstrainedProgram { // Enforce package access if let Some(entry) = matched_source_entry { - self.enforce_package_access(scope, entry, package.access)?; + self.enforce_package_access(scope, &entry, package.access) + } else { + Err(ImportError::unknown_package(package_name)) } - - Ok(()) } pub fn enforce_import(&mut self, scope: String, import: Import) -> Result<(), ImportError> { let path = current_dir().map_err(|error| ImportError::directory_error(error, import.span.clone()))?; self.enforce_package(scope, path, import.package) - // - // // Sanitize the package path to the imports directory - // let mut package_path = path.clone(); - // if package_path.is_file() { - // package_path.pop(); - // } - // - // // Construct the path to the import file in the import directory - // let mut main_file_path = package_path.clone(); - // main_file_path.push(import.path_string_full()); - // - // println!("Compiling import - {:?}", main_file_path); - // - // // Build the abstract syntax tree - // let file_path = &main_file_path; - // let input_file = &LeoParser::load_file(file_path)?; - // let syntax_tree = LeoParser::parse_file(file_path, input_file)?; - // - // // Generate aleo program from file - // let mut program = Program::from(syntax_tree, import.path_string.clone()); - // - // // Use same namespace as calling function for imported symbols - // program = program.name(scope); - // - // // * -> import all imports, circuits, functions in the current scope - // if import.is_star() { - // // recursively evaluate program statements - // self.resolve_definitions(program) - // } else { - // let program_name = program.name.clone(); - // - // // match each import symbol to a symbol in the imported file - // for symbol in import.symbols.into_iter() { - // // see if the imported symbol is a circuit - // let matched_circuit = program - // .circuits - // .clone() - // .into_iter() - // .find(|(circuit_name, _circuit_def)| symbol.symbol == *circuit_name); - // - // let value = match matched_circuit { - // Some((_circuit_name, circuit_def)) => ConstrainedValue::CircuitDefinition(circuit_def), - // None => { - // // see if the imported symbol is a function - // let matched_function = program - // .functions - // .clone() - // .into_iter() - // .find(|(function_name, _function)| symbol.symbol.name == *function_name.name); - // - // match matched_function { - // Some((_function_name, function)) => ConstrainedValue::Function(None, function), - // None => return Err(ImportError::unknown_symbol(symbol, program_name, file_path)), - // } - // } - // }; - // - // // take the alias if it is present - // let resolved_name = symbol.alias.unwrap_or(symbol.symbol); - // let resolved_circuit_name = new_scope(program_name.clone(), resolved_name.to_string()); - // - // // store imported circuit under resolved name - // self.store(resolved_circuit_name, value); - // } - // - // // evaluate all import statements in imported file - // // todo: add logic to detect import loops - // program - // .imports - // .into_iter() - // .map(|nested_import| self.enforce_import(program_name.clone(), nested_import)) - // .collect::, ImportError>>()?; - // - // Ok(()) - // } } } diff --git a/compiler/src/errors/constraints/import.rs b/compiler/src/errors/constraints/import.rs index 618124812c..4b5bf200f3 100644 --- a/compiler/src/errors/constraints/import.rs +++ b/compiler/src/errors/constraints/import.rs @@ -1,5 +1,5 @@ use leo_ast::ParserError; -use leo_types::{Error as FormattedError, ImportSymbol, Span}; +use leo_types::{Error as FormattedError, Identifier, ImportSymbol, Span}; use std::{io, path::PathBuf}; @@ -29,10 +29,19 @@ impl ImportError { Self::new_from_span(message, span) } - pub fn expected_file(entry: String, symbol: ImportSymbol) -> Self { - let message = format!("cannot import symbol `{}` from directory `{}`", symbol, entry); + pub fn expected_file(entry: String, span: Span) -> Self { + let message = format!("cannot import symbol `{}` from directory `{}`", span.text, entry); - Self::new_from_span(message, symbol.span) + Self::new_from_span(message, span) + } + + pub fn unknown_package(identifier: Identifier) -> Self { + let message = format!( + "cannot find imported package `{}` in source files or import directory", + identifier.name + ); + + Self::new_from_span(message, identifier.span) } pub fn unknown_symbol(symbol: ImportSymbol, file: String, file_path: &PathBuf) -> Self { diff --git a/compiler/tests/import/alias.leo b/compiler/tests/import/alias.leo index 7584591ae3..6af2e64a8a 100644 --- a/compiler/tests/import/alias.leo +++ b/compiler/tests/import/alias.leo @@ -1,4 +1,4 @@ -from "tests/import/test_import" import foo as bar; +import test_import.foo as bar; function main() -> u32 { return bar() diff --git a/compiler/tests/import/basic.leo b/compiler/tests/import/basic.leo index f63096a4db..8166710c7a 100644 --- a/compiler/tests/import/basic.leo +++ b/compiler/tests/import/basic.leo @@ -1,4 +1,4 @@ -from "tests/import/test_import" import foo; +import test_import.foo; function main() -> u32 { return foo() diff --git a/compiler/tests/import/mod.rs b/compiler/tests/import/mod.rs index 1219dfd100..5c7ba19c0a 100644 --- a/compiler/tests/import/mod.rs +++ b/compiler/tests/import/mod.rs @@ -1,13 +1,26 @@ use crate::{integers::u32::output_one, parse_program}; +use std::env::{current_dir, set_current_dir}; + +static TEST_SOURCE_DIRECTORY: &str = "tests/import"; + // Import tests rely on knowledge of local directories. They should be run locally only. +fn set_local_dir() { + let mut local = current_dir().unwrap(); + local.push(TEST_SOURCE_DIRECTORY); + + set_current_dir(local).unwrap(); +} + #[test] #[ignore] fn test_basic() { let bytes = include_bytes!("basic.leo"); let program = parse_program(bytes).unwrap(); + set_local_dir(); + output_one(program); } @@ -17,6 +30,8 @@ fn test_multiple() { let bytes = include_bytes!("multiple.leo"); let program = parse_program(bytes).unwrap(); + set_local_dir(); + output_one(program); } @@ -26,6 +41,8 @@ fn test_star() { let bytes = include_bytes!("star.leo"); let program = parse_program(bytes).unwrap(); + set_local_dir(); + output_one(program); } @@ -35,5 +52,7 @@ fn test_alias() { let bytes = include_bytes!("alias.leo"); let program = parse_program(bytes).unwrap(); + set_local_dir(); + output_one(program); } diff --git a/compiler/tests/import/multiple.leo b/compiler/tests/import/multiple.leo index 4dd9720db1..ddf9093347 100644 --- a/compiler/tests/import/multiple.leo +++ b/compiler/tests/import/multiple.leo @@ -1,9 +1,9 @@ -from "tests/import/test_import" import { +import test_import.( Point, foo -}; +); function main() -> u32 { let p = Point { x: 1u32, y: 0u32 }; - return foo() + return p.x } \ No newline at end of file diff --git a/compiler/tests/import/test_import.leo b/compiler/tests/import/src/test_import.leo similarity index 100% rename from compiler/tests/import/test_import.leo rename to compiler/tests/import/src/test_import.leo diff --git a/compiler/tests/import/star.leo b/compiler/tests/import/star.leo index 5dca6dead2..113adc7088 100644 --- a/compiler/tests/import/star.leo +++ b/compiler/tests/import/star.leo @@ -1,4 +1,4 @@ -from "tests/import/test_import" import *; +import test_import.*; function main() -> u32 { let p = Point { x: 1u32, y: 0u32 }; diff --git a/types/src/imports/import.rs b/types/src/imports/import.rs index 79fd6f53c6..30c231f466 100644 --- a/types/src/imports/import.rs +++ b/types/src/imports/import.rs @@ -1,6 +1,6 @@ //! The import type for a Leo program. -use crate::{ImportSymbol, Package, Span}; +use crate::{Package, Span}; use leo_ast::imports::Import as AstImport; use serde::{Deserialize, Serialize}; diff --git a/types/src/imports/package_access.rs b/types/src/imports/package_access.rs index 0ff7da7215..ba92029f9f 100644 --- a/types/src/imports/package_access.rs +++ b/types/src/imports/package_access.rs @@ -1,4 +1,4 @@ -use crate::{ImportSymbol, Package}; +use crate::{ImportSymbol, Package, Span}; use leo_ast::imports::PackageAccess as AstPackageAccess; use serde::{Deserialize, Serialize}; @@ -6,21 +6,21 @@ use std::fmt; #[derive(Clone, Serialize, Deserialize)] pub enum PackageAccess { - Star, + Star(Span), SubPackage(Box), - Multiple(Vec), Symbol(ImportSymbol), + Multiple(Vec), } impl<'ast> From> for PackageAccess { fn from(access: AstPackageAccess<'ast>) -> Self { match access { - AstPackageAccess::Star(_) => PackageAccess::Star, + AstPackageAccess::Star(star) => PackageAccess::Star(Span::from(star.span)), AstPackageAccess::SubPackage(package) => PackageAccess::SubPackage(Box::new(Package::from(*package))), - AstPackageAccess::Multiple(packages) => { - PackageAccess::Multiple(packages.into_iter().map(|package| Package::from(package)).collect()) - } AstPackageAccess::Symbol(symbol) => PackageAccess::Symbol(ImportSymbol::from(symbol)), + AstPackageAccess::Multiple(accesses) => { + PackageAccess::Multiple(accesses.into_iter().map(|access| PackageAccess::from(access)).collect()) + } } } } @@ -28,19 +28,19 @@ impl<'ast> From> for PackageAccess { impl PackageAccess { fn format(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { - PackageAccess::Star => write!(f, ".*"), + PackageAccess::Star(ref _span) => write!(f, ".*"), PackageAccess::SubPackage(ref package) => write!(f, ".{}", package), - PackageAccess::Multiple(ref packages) => { + PackageAccess::Symbol(ref symbol) => write!(f, ".{}", symbol), + PackageAccess::Multiple(ref accesses) => { write!(f, ".(")?; - for (i, package) in packages.iter().enumerate() { - write!(f, "{}", package)?; - if i < packages.len() - 1 { + for (i, access) in accesses.iter().enumerate() { + write!(f, "{}", access)?; + if i < accesses.len() - 1 { write!(f, ", ")?; } } write!(f, ")") } - PackageAccess::Symbol(ref symbol) => write!(f, ".{}", symbol), } } } From f64dfcf4101d5ee36e935630ebdc88b35718817e Mon Sep 17 00:00:00 2001 From: collin Date: Fri, 26 Jun 2020 18:09:28 -0700 Subject: [PATCH 06/26] refactor import constraints into separate files --- compiler/src/constraints/import/import.rs | 13 +++ .../{import.rs => import/import_symbol.rs} | 82 +------------------ compiler/src/constraints/import/mod.rs | 8 ++ compiler/src/constraints/import/package.rs | 79 ++++++++++++++++++ 4 files changed, 102 insertions(+), 80 deletions(-) create mode 100644 compiler/src/constraints/import/import.rs rename compiler/src/constraints/{import.rs => import/import_symbol.rs} (51%) create mode 100644 compiler/src/constraints/import/mod.rs create mode 100644 compiler/src/constraints/import/package.rs diff --git a/compiler/src/constraints/import/import.rs b/compiler/src/constraints/import/import.rs new file mode 100644 index 0000000000..04f0bd4e90 --- /dev/null +++ b/compiler/src/constraints/import/import.rs @@ -0,0 +1,13 @@ +use crate::{constraints::ConstrainedProgram, errors::constraints::ImportError, GroupType}; +use leo_types::Import; + +use snarkos_models::curves::{Field, PrimeField}; +use std::env::current_dir; + +impl> ConstrainedProgram { + pub fn enforce_import(&mut self, scope: String, import: Import) -> Result<(), ImportError> { + let path = current_dir().map_err(|error| ImportError::directory_error(error, import.span.clone()))?; + + self.enforce_package(scope, path, import.package) + } +} diff --git a/compiler/src/constraints/import.rs b/compiler/src/constraints/import/import_symbol.rs similarity index 51% rename from compiler/src/constraints/import.rs rename to compiler/src/constraints/import/import_symbol.rs index e043376b6c..ba7621ca20 100644 --- a/compiler/src/constraints/import.rs +++ b/compiler/src/constraints/import/import_symbol.rs @@ -5,14 +5,10 @@ use crate::{ GroupType, }; use leo_ast::LeoParser; -use leo_types::{Import, ImportSymbol, Package, PackageAccess, Program, Span}; +use leo_types::{ImportSymbol, Program, Span}; use snarkos_models::curves::{Field, PrimeField}; -use std::{env::current_dir, fs, fs::DirEntry, path::PathBuf}; - -static SOURCE_FILE_EXTENSION: &str = ".leo"; -static SOURCE_DIRECTORY_NAME: &str = "src/"; -// pub(crate) static IMPORTS_DIRECTORY_NAME: &str = "imports/"; +use std::fs::DirEntry; fn parse_import_file(entry: &DirEntry, span: &Span) -> Result { // make sure the given entry is file @@ -106,78 +102,4 @@ impl> ConstrainedProgram { Ok(()) } - - pub fn enforce_package_access( - &mut self, - scope: String, - entry: &DirEntry, - access: PackageAccess, - ) -> Result<(), ImportError> { - // bring one or more import symbols into scope for the current constrained program - // we will recursively traverse sub packages here until we find the desired symbol - match access { - PackageAccess::Star(span) => self.enforce_import_star(scope, entry, span), - PackageAccess::Symbol(symbol) => self.enforce_import_symbol(scope, entry, symbol), - PackageAccess::SubPackage(package) => self.enforce_package(scope, entry.path(), *package), - PackageAccess::Multiple(accesses) => { - for access in accesses { - self.enforce_package_access(scope.clone(), entry, access)?; - } - - Ok(()) - } - } - } - - pub fn enforce_package(&mut self, scope: String, path: PathBuf, package: Package) -> Result<(), ImportError> { - let package_name = package.name; - - // search for package name in local src directory - let mut source_directory = path.clone(); - source_directory.push(SOURCE_DIRECTORY_NAME); - - let entries = fs::read_dir(source_directory) - .map_err(|error| ImportError::directory_error(error, package_name.span.clone()))? - .into_iter() - .collect::, std::io::Error>>() - .map_err(|error| ImportError::directory_error(error, package_name.span.clone()))?; - - let matched_source_entry = entries.into_iter().find(|entry| { - entry - .file_name() - .into_string() - .unwrap() - .trim_end_matches(SOURCE_FILE_EXTENSION) - .eq(&package_name.name) - }); - - // search for package name in imports directory - // let mut source_directory = path.clone(); - // source_directory.push(IMPORTS_DIRECTORY_NAME); - // - // let entries = fs::read_dir(source_directory) - // .map_err(|error| ImportError::directory_error(error, package_name.span.clone()))? - // .into_iter() - // .collect::, std::io::Error>>() - // .map_err(|error| ImportError::directory_error(error, package_name.span.clone()))?; - // - // let matched_import_entry = entries.into_iter().find(|entry| { - // entry.file_name().eq(&package_name.name) - // }); - - // todo: return error if package name is present in both directories - - // Enforce package access - if let Some(entry) = matched_source_entry { - self.enforce_package_access(scope, &entry, package.access) - } else { - Err(ImportError::unknown_package(package_name)) - } - } - - pub fn enforce_import(&mut self, scope: String, import: Import) -> Result<(), ImportError> { - let path = current_dir().map_err(|error| ImportError::directory_error(error, import.span.clone()))?; - - self.enforce_package(scope, path, import.package) - } } diff --git a/compiler/src/constraints/import/mod.rs b/compiler/src/constraints/import/mod.rs new file mode 100644 index 0000000000..a007859c04 --- /dev/null +++ b/compiler/src/constraints/import/mod.rs @@ -0,0 +1,8 @@ +pub mod import; +pub use import::*; + +pub mod import_symbol; +pub use import_symbol::*; + +pub mod package; +pub use package::*; diff --git a/compiler/src/constraints/import/package.rs b/compiler/src/constraints/import/package.rs new file mode 100644 index 0000000000..67dab822b3 --- /dev/null +++ b/compiler/src/constraints/import/package.rs @@ -0,0 +1,79 @@ +use crate::{constraints::ConstrainedProgram, errors::constraints::ImportError, GroupType}; +use leo_types::{Package, PackageAccess}; + +use snarkos_models::curves::{Field, PrimeField}; +use std::{fs, fs::DirEntry, path::PathBuf}; + +static SOURCE_FILE_EXTENSION: &str = ".leo"; +static SOURCE_DIRECTORY_NAME: &str = "src/"; +// pub(crate) static IMPORTS_DIRECTORY_NAME: &str = "imports/"; + +impl> ConstrainedProgram { + pub fn enforce_package_access( + &mut self, + scope: String, + entry: &DirEntry, + access: PackageAccess, + ) -> Result<(), ImportError> { + // bring one or more import symbols into scope for the current constrained program + // we will recursively traverse sub packages here until we find the desired symbol + match access { + PackageAccess::Star(span) => self.enforce_import_star(scope, entry, span), + PackageAccess::Symbol(symbol) => self.enforce_import_symbol(scope, entry, symbol), + PackageAccess::SubPackage(package) => self.enforce_package(scope, entry.path(), *package), + PackageAccess::Multiple(accesses) => { + for access in accesses { + self.enforce_package_access(scope.clone(), entry, access)?; + } + + Ok(()) + } + } + } + + pub fn enforce_package(&mut self, scope: String, path: PathBuf, package: Package) -> Result<(), ImportError> { + let package_name = package.name; + + // search for package name in local src directory + let mut source_directory = path.clone(); + source_directory.push(SOURCE_DIRECTORY_NAME); + + let entries = fs::read_dir(source_directory) + .map_err(|error| ImportError::directory_error(error, package_name.span.clone()))? + .into_iter() + .collect::, std::io::Error>>() + .map_err(|error| ImportError::directory_error(error, package_name.span.clone()))?; + + let matched_source_entry = entries.into_iter().find(|entry| { + entry + .file_name() + .into_string() + .unwrap() + .trim_end_matches(SOURCE_FILE_EXTENSION) + .eq(&package_name.name) + }); + + // search for package name in imports directory + // let mut source_directory = path.clone(); + // source_directory.push(IMPORTS_DIRECTORY_NAME); + // + // let entries = fs::read_dir(source_directory) + // .map_err(|error| ImportError::directory_error(error, package_name.span.clone()))? + // .into_iter() + // .collect::, std::io::Error>>() + // .map_err(|error| ImportError::directory_error(error, package_name.span.clone()))?; + // + // let matched_import_entry = entries.into_iter().find(|entry| { + // entry.file_name().eq(&package_name.name) + // }); + + // todo: return error if package name is present in both directories + + // Enforce package access + if let Some(entry) = matched_source_entry { + self.enforce_package_access(scope, &entry, package.access) + } else { + Err(ImportError::unknown_package(package_name)) + } + } +} From 1781bce5fd49eaafc832e88c66c540f6ff73996b Mon Sep 17 00:00:00 2001 From: howardwu Date: Fri, 26 Jun 2020 18:43:29 -0700 Subject: [PATCH 07/26] Adds ci.yml --- .github/workflows/ci.yml | 144 +++++++++++++++++++++++++++++++++++++++ Cargo.lock | 4 +- 2 files changed, 146 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000000..e13e81ce17 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,144 @@ +name: CI +on: + pull_request: + push: + branches: + - master +env: + RUST_BACKTRACE: 1 + +jobs: + style: + name: Check Style + runs-on: ubuntu-latest + steps: + + - name: Checkout + uses: actions/checkout@v1 + + - name: Fetch snarkOS + run: | + mkdir ~/.ssh + echo "${{ secrets.SNARKOS_DEPLOY_KEY }}" > ~/.ssh/id_rsa + chmod 600 ~/.ssh/id_rsa + eval $(ssh-agent -s) + ssh-add -k ~/.ssh/id_rsa + + - name: Install Rust + uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: nightly + override: true + components: rustfmt + + - name: cargo fmt --check + uses: actions-rs/cargo@v1 + env: + CARGO_NET_GIT_FETCH_WITH_CLI: true + with: + command: fmt + args: --all -- --check + + test: + name: Test + runs-on: ubuntu-latest + env: + RUSTFLAGS: -Dwarnings + strategy: + matrix: + rust: + - stable + - nightly + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name: Fetch snarkOS + run: | + mkdir ~/.ssh + echo "${{ secrets.SNARKOS_DEPLOY_KEY }}" > ~/.ssh/id_rsa + chmod 600 ~/.ssh/id_rsa + eval $(ssh-agent -s) + ssh-add -k ~/.ssh/id_rsa + + - name: Install Rust (${{ matrix.rust }}) + uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: ${{ matrix.rust }} + override: true + + - name: Check examples + uses: actions-rs/cargo@v1 + env: + CARGO_NET_GIT_FETCH_WITH_CLI: true + with: + command: check + args: --examples --all + + - name: Check examples with all features on stable + uses: actions-rs/cargo@v1 + env: + CARGO_NET_GIT_FETCH_WITH_CLI: true + with: + command: check + args: --examples --all-features --all + if: matrix.rust == 'stable' + + - name: Check benchmarks on nightly + uses: actions-rs/cargo@v1 + env: + CARGO_NET_GIT_FETCH_WITH_CLI: true + with: + command: check + args: --all-features --examples --all --benches + if: matrix.rust == 'nightly' + + - name: Test + uses: actions-rs/cargo@v1 + env: + CARGO_NET_GIT_FETCH_WITH_CLI: true + with: + command: test + args: --release + +# check_no_std: +# name: Check no_std +# runs-on: ubuntu-latest +# steps: +# - name: Checkout +# uses: actions/checkout@v2 +# +# - name: Fetch snarkOS +# run: | +# mkdir ~/.ssh +# echo "${{ secrets.SNARKOS_DEPLOY_KEY }}" > ~/.ssh/id_rsa +# chmod 600 ~/.ssh/id_rsa +# eval $(ssh-agent -s) +# ssh-add -k ~/.ssh/id_rsa +# +# - name: Install Rust (${{ matrix.rust }}) +# uses: actions-rs/toolchain@v1 +# with: +# toolchain: stable +# target: thumbv6m-none-eabi +# override: true +# +# - name: Build +# uses: actions-rs/cargo@v1 +# env: +# CARGO_NET_GIT_FETCH_WITH_CLI: true +# with: +# use-cross: true +# command: build +# args: --no-default-features --target thumbv6m-none-eabi +# +# - name: Check +# uses: actions-rs/cargo@v1 +# env: +# CARGO_NET_GIT_FETCH_WITH_CLI: true +# with: +# use-cross: true +# command: check +# args: --examples --no-default-features --target thumbv6m-none-eabi diff --git a/Cargo.lock b/Cargo.lock index 3fccd5be74..0625bc061e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -78,9 +78,9 @@ checksum = "58946044516aa9dc922182e0d6e9d124a31aafe6b421614654eb27cf90cec09c" [[package]] name = "bincode" -version = "1.2.1" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5753e2a71534719bf3f4e57006c3a4f0d2c672a4b676eec84161f763eca87dbf" +checksum = "f30d3a39baa26f9651f17b375061f3233dde33424a8b72b0dbe93a68a0bc896d" dependencies = [ "byteorder", "serde", From 8825a0741cd0f83cba9d27e0ad77192859ca3998 Mon Sep 17 00:00:00 2001 From: collin Date: Fri, 26 Jun 2020 19:06:52 -0700 Subject: [PATCH 08/26] clean up for pr --- compiler/src/constraints/import/import_symbol.rs | 3 --- compiler/src/constraints/statement.rs | 3 +-- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/compiler/src/constraints/import/import_symbol.rs b/compiler/src/constraints/import/import_symbol.rs index ba7621ca20..4011df354c 100644 --- a/compiler/src/constraints/import/import_symbol.rs +++ b/compiler/src/constraints/import/import_symbol.rs @@ -58,8 +58,6 @@ impl> ConstrainedProgram { let program_name = program.name.clone(); - // match each import symbol to a symbol in the imported file - // for symbol in import.symbols.into_iter() { // see if the imported symbol is a circuit let matched_circuit = program .circuits @@ -90,7 +88,6 @@ impl> ConstrainedProgram { // store imported circuit under resolved name self.store(resolved_name, value); - // } // evaluate all import statements in imported file // todo: add logic to detect import loops diff --git a/compiler/src/constraints/statement.rs b/compiler/src/constraints/statement.rs index 8048ac1e3e..deda3e04a5 100644 --- a/compiler/src/constraints/statement.rs +++ b/compiler/src/constraints/statement.rs @@ -2,7 +2,7 @@ use crate::{ constraints::{ConstrainedProgram, ConstrainedValue}, - errors::StatementError, + errors::{StatementError, ValueError}, new_scope, GroupType, }; @@ -21,7 +21,6 @@ use leo_types::{ Variable, }; -use crate::errors::ValueError; use snarkos_models::{ curves::{Field, PrimeField}, gadgets::{ From 9c2a0e4ec664dbca7a481487026900afb773f74c Mon Sep 17 00:00:00 2001 From: collin Date: Fri, 26 Jun 2020 20:58:43 -0700 Subject: [PATCH 09/26] add lib.leo support --- leo/commands/build.rs | 116 ++++++++++++++++------------- leo/commands/deploy.rs | 33 ++++++-- leo/commands/load.rs | 33 ++++++-- leo/commands/publish.rs | 4 +- leo/commands/setup.rs | 114 +++++++++++++++------------- leo/commands/unload.rs | 33 ++++++-- leo/errors/files/lib.rs | 19 +++++ leo/errors/files/mod.rs | 3 + leo/files/lib.rs | 56 ++++++++++++++ leo/files/mod.rs | 3 + types/src/imports/import_symbol.rs | 4 +- 11 files changed, 292 insertions(+), 126 deletions(-) create mode 100644 leo/errors/files/lib.rs create mode 100644 leo/files/lib.rs diff --git a/leo/commands/build.rs b/leo/commands/build.rs index ffba966a56..583e41b9c3 100644 --- a/leo/commands/build.rs +++ b/leo/commands/build.rs @@ -2,8 +2,8 @@ use crate::{ cli::*, cli_types::*, directories::{source::SOURCE_DIRECTORY_NAME, OutputsDirectory}, - errors::{BuildError, CLIError}, - files::{ChecksumFile, MainFile, Manifest, MAIN_FILE_NAME}, + errors::CLIError, + files::{ChecksumFile, LibFile, MainFile, Manifest, LIB_FILE_NAME, MAIN_FILE_NAME}, }; use leo_compiler::{compiler::Compiler, group::edwards_bls12::EdwardsGroupType}; @@ -18,7 +18,7 @@ pub struct BuildCommand; impl CLI for BuildCommand { type Options = (); - type Output = (Compiler, bool); + type Output = Option<(Compiler, bool)>; const ABOUT: AboutType = "Compile the current package as a program"; const ARGUMENTS: &'static [ArgumentType] = &[]; @@ -46,58 +46,72 @@ impl CLI for BuildCommand { package_path.pop(); } - // Verify the main file exists - if !MainFile::exists_at(&package_path) { - return Err(BuildError::MainFileDoesNotExist(package_path.as_os_str().to_owned()).into()); - } + // Compile the package starting with the lib.leo file + if LibFile::exists_at(&package_path) { + // Construct the path to the library file in the source directory + let mut lib_file_path = package_path.clone(); + lib_file_path.push(SOURCE_DIRECTORY_NAME); + lib_file_path.push(LIB_FILE_NAME); - // Create the outputs directory - OutputsDirectory::create(&package_path)?; - - // Construct the path to the main file in the source directory - let mut main_file_path = package_path.clone(); - main_file_path.push(SOURCE_DIRECTORY_NAME); - main_file_path.push(MAIN_FILE_NAME); - - // Load the program at `main_file_path` - let program = Compiler::::new_from_path(package_name.clone(), main_file_path.clone())?; - - // Compute the current program checksum - let program_checksum = program.checksum()?; - - // Generate the program on the constraint system and verify correctness - { - let mut cs = KeypairAssembly:: { - num_inputs: 0, - num_aux: 0, - num_constraints: 0, - at: vec![], - bt: vec![], - ct: vec![], - }; - let temporary_program = program.clone(); - let output = temporary_program.compile_constraints(&mut cs)?; - log::debug!("Compiled constraints - {:#?}", output); - } - - // If a checksum file exists, check if it differs from the new checksum - let checksum_file = ChecksumFile::new(&package_name); - let checksum_differs = if checksum_file.exists_at(&package_path) { - let previous_checksum = checksum_file.read_from(&package_path)?; - program_checksum != previous_checksum - } else { - // By default, the checksum differs if there is no checksum to compare against - true + // Compile the library file but do not output + let _program = Compiler::::new_from_path(package_name.clone(), lib_file_path)?; }; - // If checksum differs, compile the program - if checksum_differs { - // Write the new checksum to the outputs directory - checksum_file.write_to(&path, program_checksum)?; + // Compile the main.leo file along with constraints + if MainFile::exists_at(&package_path) { + // Create the outputs directory + OutputsDirectory::create(&package_path)?; + + // Construct the path to the main file in the source directory + let mut main_file_path = package_path.clone(); + main_file_path.push(SOURCE_DIRECTORY_NAME); + main_file_path.push(MAIN_FILE_NAME); + + // Load the program at `main_file_path` + let program = + Compiler::::new_from_path(package_name.clone(), main_file_path.clone())?; + + // Compute the current program checksum + let program_checksum = program.checksum()?; + + // Generate the program on the constraint system and verify correctness + { + let mut cs = KeypairAssembly:: { + num_inputs: 0, + num_aux: 0, + num_constraints: 0, + at: vec![], + bt: vec![], + ct: vec![], + }; + let temporary_program = program.clone(); + let output = temporary_program.compile_constraints(&mut cs)?; + log::debug!("Compiled constraints - {:#?}", output); + } + + // If a checksum file exists, check if it differs from the new checksum + let checksum_file = ChecksumFile::new(&package_name); + let checksum_differs = if checksum_file.exists_at(&package_path) { + let previous_checksum = checksum_file.read_from(&package_path)?; + program_checksum != previous_checksum + } else { + // By default, the checksum differs if there is no checksum to compare against + true + }; + + // If checksum differs, compile the program + if checksum_differs { + // Write the new checksum to the outputs directory + checksum_file.write_to(&path, program_checksum)?; + } + + log::info!("Compiled program in {:?}", main_file_path); + + return Ok(Some((program, checksum_differs))); } - log::info!("Compiled program in {:?}", main_file_path); - - Ok((program, checksum_differs)) + // Return None when compiling a package for publishing + // The published package does not need to have a main.leo + Ok(None) } } diff --git a/leo/commands/deploy.rs b/leo/commands/deploy.rs index cd715498f8..d0b6c7f8a6 100644 --- a/leo/commands/deploy.rs +++ b/leo/commands/deploy.rs @@ -1,4 +1,11 @@ -use crate::{cli::*, cli_types::*, commands::BuildCommand, errors::CLIError, files::Manifest}; +use crate::{ + cli::*, + cli_types::*, + commands::BuildCommand, + directories::SOURCE_DIRECTORY_NAME, + errors::{CLIError, RunError}, + files::{Manifest, MAIN_FILE_NAME}, +}; use clap::ArgMatches; use std::{convert::TryFrom, env::current_dir}; @@ -24,14 +31,26 @@ impl CLI for DeployCommand { #[cfg_attr(tarpaulin, skip)] fn output(options: Self::Options) -> Result { - let (_program, _checksum_differs) = BuildCommand::output(options)?; - - // Get the package name let path = current_dir()?; - let _package_name = Manifest::try_from(&path)?.get_package_name(); - log::info!("Unimplemented - `leo deploy`"); + match BuildCommand::output(options)? { + Some((_program, _checksum_differs)) => { + // Get the package name + let _package_name = Manifest::try_from(&path)?.get_package_name(); - Ok(()) + log::info!("Unimplemented - `leo deploy`"); + + Ok(()) + } + None => { + let mut main_file_path = path.clone(); + main_file_path.push(SOURCE_DIRECTORY_NAME); + main_file_path.push(MAIN_FILE_NAME); + + Err(CLIError::RunError(RunError::MainFileDoesNotExist( + main_file_path.into_os_string(), + ))) + } + } } } diff --git a/leo/commands/load.rs b/leo/commands/load.rs index 8cef939d0b..77c8f008b4 100644 --- a/leo/commands/load.rs +++ b/leo/commands/load.rs @@ -1,4 +1,11 @@ -use crate::{cli::*, cli_types::*, commands::BuildCommand, errors::CLIError, files::Manifest}; +use crate::{ + cli::*, + cli_types::*, + commands::BuildCommand, + directories::SOURCE_DIRECTORY_NAME, + errors::{CLIError, RunError}, + files::{Manifest, MAIN_FILE_NAME}, +}; use clap::ArgMatches; use std::{convert::TryFrom, env::current_dir}; @@ -24,14 +31,26 @@ impl CLI for LoadCommand { #[cfg_attr(tarpaulin, skip)] fn output(options: Self::Options) -> Result { - let (_program, _checksum_differs) = BuildCommand::output(options)?; - - // Get the package name let path = current_dir()?; - let _package_name = Manifest::try_from(&path)?.get_package_name(); - log::info!("Unimplemented - `leo deploy`"); + match BuildCommand::output(options)? { + Some((_program, _checksum_differs)) => { + // Get the package name + let _package_name = Manifest::try_from(&path)?.get_package_name(); - Ok(()) + log::info!("Unimplemented - `leo load`"); + + Ok(()) + } + None => { + let mut main_file_path = path.clone(); + main_file_path.push(SOURCE_DIRECTORY_NAME); + main_file_path.push(MAIN_FILE_NAME); + + Err(CLIError::RunError(RunError::MainFileDoesNotExist( + main_file_path.into_os_string(), + ))) + } + } } } diff --git a/leo/commands/publish.rs b/leo/commands/publish.rs index 073221904d..905b4c420d 100644 --- a/leo/commands/publish.rs +++ b/leo/commands/publish.rs @@ -30,7 +30,9 @@ impl CLI for PublishCommand { #[cfg_attr(tarpaulin, skip)] fn output(options: Self::Options) -> Result { - let (_program, _checksum_differs) = BuildCommand::output(options)?; + // Build all program files. + // It's okay if there's just a lib.leo file here + let _output = BuildCommand::output(options)?; // Get the package name let path = current_dir()?; diff --git a/leo/commands/setup.rs b/leo/commands/setup.rs index 8cd115bc3e..fa04f04b65 100644 --- a/leo/commands/setup.rs +++ b/leo/commands/setup.rs @@ -2,8 +2,9 @@ use crate::{ cli::*, cli_types::*, commands::BuildCommand, - errors::{CLIError, VerificationKeyFileError}, - files::{Manifest, ProvingKeyFile, VerificationKeyFile}, + directories::SOURCE_DIRECTORY_NAME, + errors::{CLIError, RunError, VerificationKeyFileError}, + files::{Manifest, ProvingKeyFile, VerificationKeyFile, MAIN_FILE_NAME}, }; use leo_compiler::{compiler::Compiler, group::edwards_bls12::EdwardsGroupType}; @@ -40,66 +41,77 @@ impl CLI for SetupCommand { #[cfg_attr(tarpaulin, skip)] fn output(options: Self::Options) -> Result { - let (program, checksum_differs) = BuildCommand::output(options)?; - // Get the package name let path = current_dir()?; let package_name = Manifest::try_from(&path)?.get_package_name(); - // Check if a proving key and verification key already exists - let keys_exist = ProvingKeyFile::new(&package_name).exists_at(&path) - && VerificationKeyFile::new(&package_name).exists_at(&path); + match BuildCommand::output(options)? { + Some((program, checksum_differs)) => { + // Check if a proving key and verification key already exists + let keys_exist = ProvingKeyFile::new(&package_name).exists_at(&path) + && VerificationKeyFile::new(&package_name).exists_at(&path); - // If keys do not exist or the checksum differs, run the program setup - if !keys_exist || checksum_differs { - // Start the timer - let start = Instant::now(); + // If keys do not exist or the checksum differs, run the program setup + if !keys_exist || checksum_differs { + // Start the timer + let start = Instant::now(); - // Run the program setup operation - let rng = &mut thread_rng(); - let parameters = generate_random_parameters::(program.clone(), rng).unwrap(); - let prepared_verifying_key = prepare_verifying_key::(¶meters.vk); + // Run the program setup operation + let rng = &mut thread_rng(); + let parameters = generate_random_parameters::(program.clone(), rng).unwrap(); + let prepared_verifying_key = prepare_verifying_key::(¶meters.vk); - // End the timer - log::info!("Setup completed in {:?} milliseconds", start.elapsed().as_millis()); + // End the timer + log::info!("Setup completed in {:?} milliseconds", start.elapsed().as_millis()); - // TODO (howardwu): Convert parameters to a 'proving key' struct for serialization. - // Write the proving key file to the outputs directory - let mut proving_key = vec![]; - parameters.write(&mut proving_key)?; - ProvingKeyFile::new(&package_name).write_to(&path, &proving_key)?; + // TODO (howardwu): Convert parameters to a 'proving key' struct for serialization. + // Write the proving key file to the outputs directory + let mut proving_key = vec![]; + parameters.write(&mut proving_key)?; + ProvingKeyFile::new(&package_name).write_to(&path, &proving_key)?; - // Write the proving key file to the outputs directory - let mut verification_key = vec![]; - prepared_verifying_key.write(&mut verification_key)?; - VerificationKeyFile::new(&package_name).write_to(&path, &verification_key)?; - } - - // Read the proving key file from the outputs directory - let proving_key = ProvingKeyFile::new(&package_name).read_from(&path)?; - let parameters = Parameters::::read(proving_key.as_slice(), true)?; - - // Read the proving key file from the outputs directory - let prepared_verifying_key = prepare_verifying_key::(¶meters.vk); - { - // Load the stored verification key from the outputs directory - let stored_vk = VerificationKeyFile::new(&package_name).read_from(&path)?; - - // Convert the prepared_verifying_key to a buffer - let mut verification_key = vec![]; - prepared_verifying_key.write(&mut verification_key)?; - - // Check that the constructed prepared verification key matches the stored verification key - let compare: Vec<(u8, u8)> = verification_key.into_iter().zip(stored_vk.into_iter()).collect(); - for (a, b) in compare { - if a != b { - return Err(VerificationKeyFileError::IncorrectVerificationKey.into()); + // Write the proving key file to the outputs directory + let mut verification_key = vec![]; + prepared_verifying_key.write(&mut verification_key)?; + VerificationKeyFile::new(&package_name).write_to(&path, &verification_key)?; } + + // Read the proving key file from the outputs directory + let proving_key = ProvingKeyFile::new(&package_name).read_from(&path)?; + let parameters = Parameters::::read(proving_key.as_slice(), true)?; + + // Read the proving key file from the outputs directory + let prepared_verifying_key = prepare_verifying_key::(¶meters.vk); + { + // Load the stored verification key from the outputs directory + let stored_vk = VerificationKeyFile::new(&package_name).read_from(&path)?; + + // Convert the prepared_verifying_key to a buffer + let mut verification_key = vec![]; + prepared_verifying_key.write(&mut verification_key)?; + + // Check that the constructed prepared verification key matches the stored verification key + let compare: Vec<(u8, u8)> = verification_key.into_iter().zip(stored_vk.into_iter()).collect(); + for (a, b) in compare { + if a != b { + return Err(VerificationKeyFileError::IncorrectVerificationKey.into()); + } + } + } + + log::info!("Completed program setup"); + + Ok((program, parameters, prepared_verifying_key)) + } + None => { + let mut main_file_path = path.clone(); + main_file_path.push(SOURCE_DIRECTORY_NAME); + main_file_path.push(MAIN_FILE_NAME); + + Err(CLIError::RunError(RunError::MainFileDoesNotExist( + main_file_path.into_os_string(), + ))) } } - - log::info!("Completed program setup"); - - Ok((program, parameters, prepared_verifying_key)) } } diff --git a/leo/commands/unload.rs b/leo/commands/unload.rs index 52fe84b2b0..614acc6428 100644 --- a/leo/commands/unload.rs +++ b/leo/commands/unload.rs @@ -1,4 +1,11 @@ -use crate::{cli::*, cli_types::*, commands::BuildCommand, errors::CLIError, files::Manifest}; +use crate::{ + cli::*, + cli_types::*, + commands::BuildCommand, + directories::SOURCE_DIRECTORY_NAME, + errors::{CLIError, RunError}, + files::{Manifest, MAIN_FILE_NAME}, +}; use clap::ArgMatches; use std::{convert::TryFrom, env::current_dir}; @@ -24,14 +31,26 @@ impl CLI for UnloadCommand { #[cfg_attr(tarpaulin, skip)] fn output(options: Self::Options) -> Result { - let (_program, _checksum_differs) = BuildCommand::output(options)?; - - // Get the package name let path = current_dir()?; - let _package_name = Manifest::try_from(&path)?.get_package_name(); - log::info!("Unimplemented - `leo deploy`"); + match BuildCommand::output(options)? { + Some((_program, _checksum_differs)) => { + // Get the package name + let _package_name = Manifest::try_from(&path)?.get_package_name(); - Ok(()) + log::info!("Unimplemented - `leo load`"); + + Ok(()) + } + None => { + let mut main_file_path = path.clone(); + main_file_path.push(SOURCE_DIRECTORY_NAME); + main_file_path.push(MAIN_FILE_NAME); + + Err(CLIError::RunError(RunError::MainFileDoesNotExist( + main_file_path.into_os_string(), + ))) + } + } } } diff --git a/leo/errors/files/lib.rs b/leo/errors/files/lib.rs new file mode 100644 index 0000000000..a95bc98075 --- /dev/null +++ b/leo/errors/files/lib.rs @@ -0,0 +1,19 @@ +use std::io; + +#[derive(Debug, Error)] +pub enum LibFileError { + #[error("{}: {}", _0, _1)] + Crate(&'static str, String), + + #[error("creating: {}", _0)] + Creating(io::Error), + + #[error("writing: {}", _0)] + Writing(io::Error), +} + +impl From for LibFileError { + fn from(error: std::io::Error) -> Self { + LibFileError::Crate("std::io", format!("{}", error)) + } +} diff --git a/leo/errors/files/mod.rs b/leo/errors/files/mod.rs index d7f66d149d..97bcc19e30 100644 --- a/leo/errors/files/mod.rs +++ b/leo/errors/files/mod.rs @@ -10,6 +10,9 @@ pub use self::gitignore::*; pub mod inputs; pub use self::inputs::*; +pub mod lib; +pub use self::lib::*; + pub mod main; pub use self::main::*; diff --git a/leo/files/lib.rs b/leo/files/lib.rs new file mode 100644 index 0000000000..2b514cc1cf --- /dev/null +++ b/leo/files/lib.rs @@ -0,0 +1,56 @@ +//! The `lib.leo` file. + +use crate::{directories::source::SOURCE_DIRECTORY_NAME, errors::LibFileError}; + +use serde::Deserialize; +use std::{fs::File, io::Write, path::PathBuf}; + +pub static LIB_FILE_NAME: &str = "lib.leo"; + +#[derive(Deserialize)] +pub struct LibFile { + pub package_name: String, +} + +impl LibFile { + pub fn new(package_name: &str) -> Self { + Self { + package_name: package_name.to_string(), + } + } + + pub fn exists_at(path: &PathBuf) -> bool { + let mut path = path.to_owned(); + if path.is_dir() { + if !path.ends_with(SOURCE_DIRECTORY_NAME) { + path.push(PathBuf::from(SOURCE_DIRECTORY_NAME)); + } + path.push(PathBuf::from(LIB_FILE_NAME)); + } + path.exists() + } + + pub fn write_to(self, path: &PathBuf) -> Result<(), LibFileError> { + let mut path = path.to_owned(); + if path.is_dir() { + if !path.ends_with(SOURCE_DIRECTORY_NAME) { + path.push(PathBuf::from(SOURCE_DIRECTORY_NAME)); + } + path.push(PathBuf::from(LIB_FILE_NAME)); + } + + let mut file = File::create(&path)?; + Ok(file.write_all(self.template().as_bytes())?) + } + + fn template(&self) -> String { + format!( + r#"// The '{}' lib function. +circuit Circ {{ + c: field +}} +"#, + self.package_name + ) + } +} diff --git a/leo/files/mod.rs b/leo/files/mod.rs index 472330e132..0e4f02c8dc 100644 --- a/leo/files/mod.rs +++ b/leo/files/mod.rs @@ -10,6 +10,9 @@ pub use self::inputs::*; pub mod gitignore; pub use self::gitignore::*; +pub mod lib; +pub use self::lib::*; + pub mod main; pub use self::main::*; diff --git a/types/src/imports/import_symbol.rs b/types/src/imports/import_symbol.rs index 5865df3324..eaef622992 100644 --- a/types/src/imports/import_symbol.rs +++ b/types/src/imports/import_symbol.rs @@ -24,9 +24,9 @@ impl<'ast> From> for ImportSymbol { impl fmt::Display for ImportSymbol { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { if self.alias.is_some() { - write!(f, "\t{} as {}", self.symbol, self.alias.as_ref().unwrap()) + write!(f, "{} as {}", self.symbol, self.alias.as_ref().unwrap()) } else { - write!(f, "\t{}", self.symbol) + write!(f, "{}", self.symbol) } } } From 878310f79365d3ec1a2fa14727c4b748f5fb23b8 Mon Sep 17 00:00:00 2001 From: collin Date: Fri, 26 Jun 2020 23:47:11 -0700 Subject: [PATCH 10/26] add import directory parsing --- .../src/constraints/import/import_symbol.rs | 14 ++++-- compiler/src/constraints/import/package.rs | 43 +++++++++++-------- compiler/src/errors/constraints/import.rs | 6 +++ 3 files changed, 41 insertions(+), 22 deletions(-) diff --git a/compiler/src/constraints/import/import_symbol.rs b/compiler/src/constraints/import/import_symbol.rs index 4011df354c..da457f59c0 100644 --- a/compiler/src/constraints/import/import_symbol.rs +++ b/compiler/src/constraints/import/import_symbol.rs @@ -10,6 +10,8 @@ use leo_types::{ImportSymbol, Program, Span}; use snarkos_models::curves::{Field, PrimeField}; use std::fs::DirEntry; +static LIBRARY_FILE: &str = "src/lib.leo"; + fn parse_import_file(entry: &DirEntry, span: &Span) -> Result { // make sure the given entry is file let file_type = entry @@ -20,14 +22,18 @@ fn parse_import_file(entry: &DirEntry, span: &Span) -> Result> ConstrainedProgram { pub fn enforce_package_access( @@ -54,26 +54,33 @@ impl> ConstrainedProgram { }); // search for package name in imports directory - // let mut source_directory = path.clone(); - // source_directory.push(IMPORTS_DIRECTORY_NAME); - // - // let entries = fs::read_dir(source_directory) - // .map_err(|error| ImportError::directory_error(error, package_name.span.clone()))? - // .into_iter() - // .collect::, std::io::Error>>() - // .map_err(|error| ImportError::directory_error(error, package_name.span.clone()))?; - // - // let matched_import_entry = entries.into_iter().find(|entry| { - // entry.file_name().eq(&package_name.name) - // }); + let mut imports_directory = path.clone(); + imports_directory.push(IMPORTS_DIRECTORY_NAME); - // todo: return error if package name is present in both directories + if imports_directory.exists() { + let entries = fs::read_dir(imports_directory) + .map_err(|error| ImportError::directory_error(error, package_name.span.clone()))? + .into_iter() + .collect::, std::io::Error>>() + .map_err(|error| ImportError::directory_error(error, package_name.span.clone()))?; - // Enforce package access - if let Some(entry) = matched_source_entry { - self.enforce_package_access(scope, &entry, package.access) + let matched_import_entry = entries + .into_iter() + .find(|entry| entry.file_name().into_string().unwrap().eq(&package_name.name)); + + // Enforce package access and potential collisions + match (matched_source_entry, matched_import_entry) { + (Some(_), Some(_)) => Err(ImportError::conflicting_imports(package_name)), + (Some(source_entry), None) => self.enforce_package_access(scope, &source_entry, package.access), + (None, Some(import_entry)) => self.enforce_package_access(scope, &import_entry, package.access), + (None, None) => Err(ImportError::unknown_package(package_name)), + } } else { - Err(ImportError::unknown_package(package_name)) + // Enforce local package access with no found imports directory + match matched_source_entry { + Some(source_entry) => self.enforce_package_access(scope, &source_entry, package.access), + None => Err(ImportError::unknown_package(package_name)), + } } } } diff --git a/compiler/src/errors/constraints/import.rs b/compiler/src/errors/constraints/import.rs index 4b5bf200f3..d9f7ed2406 100644 --- a/compiler/src/errors/constraints/import.rs +++ b/compiler/src/errors/constraints/import.rs @@ -17,6 +17,12 @@ impl ImportError { ImportError::Error(FormattedError::new_from_span(message, span)) } + pub fn conflicting_imports(identifier: Identifier) -> Self { + let message = format!("conflicting imports found for `{}`", identifier.name); + + Self::new_from_span(message, identifier.span) + } + pub fn convert_os_string(span: Span) -> Self { let message = format!("failed to convert file string name, maybe an illegal character?"); From b4cfa641673ba6d1a59cbe4b1d00e32470e9138f Mon Sep 17 00:00:00 2001 From: Howard Wu <9260812+howardwu@users.noreply.github.com> Date: Sat, 27 Jun 2020 20:16:38 -0700 Subject: [PATCH 11/26] Adds ci.yml (#77) * Adds ci.yml * Update ci script * Update Cargo.toml * Update to ubuntu-latest * Update dependencies * Update git deps with rev * Update ci script * Update ci script * Update ci script * Update code coverage * Update code coverage * Update CI * Update CI * Update CI * Update CI * Update CI * Update CI * Update CI * Update CI * Update CI * Update CI * Update CI * Update CI * Update CI * Update CI script * Update CI script --- .github/workflows/ci.yml | 158 +++++++++++++++++++++++++++++++++++++++ Cargo.lock | 12 ++- Cargo.toml | 12 +-- compiler/Cargo.toml | 10 +-- leo-inputs/Cargo.toml | 10 +-- types/Cargo.toml | 4 +- 6 files changed, 186 insertions(+), 20 deletions(-) create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000000..4a44311fba --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,158 @@ +name: CI +on: + pull_request: + push: + branches: + - master +env: + RUST_BACKTRACE: 1 + +jobs: + style: + name: Check Style + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v1 + + - name: Load snarkOS + run: | + mkdir ~/.ssh + echo "${{ secrets.SNARKOS_DEPLOY_KEY }}" > ~/.ssh/id_rsa + chmod 600 ~/.ssh/id_rsa + eval $(ssh-agent -s) + ssh-add -k ~/.ssh/id_rsa + + - name: Install Rust + uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: nightly + override: true + components: rustfmt + + - name: cargo fmt --check + uses: actions-rs/cargo@v1 + env: + CARGO_NET_GIT_FETCH_WITH_CLI: true + with: + command: fmt + args: --all -- --check + + test: + name: Test + runs-on: ubuntu-latest + env: + RUSTFLAGS: -Dwarnings + strategy: + matrix: + rust: + - stable + - nightly + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name: Load snarkOS + run: | + mkdir ~/.ssh + echo "${{ secrets.SNARKOS_DEPLOY_KEY }}" > ~/.ssh/id_rsa + chmod 600 ~/.ssh/id_rsa + eval $(ssh-agent -s) + ssh-add -k ~/.ssh/id_rsa + + - name: Install Rust (${{ matrix.rust }}) + uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: ${{ matrix.rust }} + override: true + + - name: Check examples + uses: actions-rs/cargo@v1 + env: + CARGO_NET_GIT_FETCH_WITH_CLI: true + with: + command: check + args: --examples --all + + - name: Check examples with all features on stable + uses: actions-rs/cargo@v1 +# env: +# CARGO_NET_GIT_FETCH_WITH_CLI: true + with: + command: check + args: --examples --all-features --all + if: matrix.rust == 'stable' + + - name: Check benchmarks on nightly + uses: actions-rs/cargo@v1 +# env: +# CARGO_NET_GIT_FETCH_WITH_CLI: true + with: + command: check + args: --all-features --examples --all --benches + if: matrix.rust == 'nightly' + + - name: Test + uses: actions-rs/cargo@v1 +# env: +# CARGO_NET_GIT_FETCH_WITH_CLI: true + with: + command: test + args: --release --all --no-fail-fast + + codecov: + name: Code Coverage + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v1 + + - name: Load snarkOS + run: | + mkdir ~/.ssh + echo "${{ secrets.SNARKOS_DEPLOY_KEY }}" > ~/.ssh/id_rsa + chmod 600 ~/.ssh/id_rsa + eval $(ssh-agent -s) + ssh-add -k ~/.ssh/id_rsa + + - name: Install Rust + uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: nightly + override: true + components: rustfmt + + - name: Test + uses: actions-rs/cargo@v1 + with: + command: test + args: --all + env: + CARGO_NET_GIT_FETCH_WITH_CLI: true + CARGO_INCREMENTAL: "0" + + - name: Install dependencies for code coverage + run: | + sudo apt-get update + sudo apt-get -y install binutils-dev libcurl4-openssl-dev zlib1g-dev libdw-dev libiberty-dev + + - name: Generate coverage report + run: | + wget https://github.com/SimonKagstrom/kcov/archive/master.tar.gz + tar xzf master.tar.gz + cd kcov-master + mkdir build && cd build + cmake .. && make + make install DESTDIR=../../kcov-build + cd ../.. + rm -rf kcov-master + for file in target/debug/deps/*-*; do if [[ "$file" != *\.* ]]; then mkdir -p "target/cov/$(basename $file)"; ./kcov-build/usr/local/bin/kcov --exclude-pattern=/.cargo,/usr/lib --verify "target/cov/$(basename $file)" "$file"; fi done + + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v1 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + token: ${{ secrets.CODECOV_TOKEN }} diff --git a/Cargo.lock b/Cargo.lock index 3fccd5be74..3fa513cb86 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -78,9 +78,9 @@ checksum = "58946044516aa9dc922182e0d6e9d124a31aafe6b421614654eb27cf90cec09c" [[package]] name = "bincode" -version = "1.2.1" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5753e2a71534719bf3f4e57006c3a4f0d2c672a4b676eec84161f763eca87dbf" +checksum = "f30d3a39baa26f9651f17b375061f3233dde33424a8b72b0dbe93a68a0bc896d" dependencies = [ "byteorder", "serde", @@ -946,6 +946,7 @@ checksum = "c7cb5678e1615754284ec264d9bb5b4c27d2018577fd90ac0ceb578591ed5ee4" [[package]] name = "snarkos-algorithms" version = "0.8.0" +source = "git+ssh://git@github.com/AleoHQ/snarkOS.git?rev=c7a56d9#c7a56d97a76dd6e7841aa6bb86e086f7128e5620" dependencies = [ "blake2", "derivative", @@ -964,6 +965,7 @@ dependencies = [ [[package]] name = "snarkos-curves" version = "0.8.0" +source = "git+ssh://git@github.com/AleoHQ/snarkOS.git?rev=c7a56d9#c7a56d97a76dd6e7841aa6bb86e086f7128e5620" dependencies = [ "derivative", "rand", @@ -977,6 +979,7 @@ dependencies = [ [[package]] name = "snarkos-derives" version = "0.1.0" +source = "git+ssh://git@github.com/AleoHQ/snarkOS.git?rev=c7a56d9#c7a56d97a76dd6e7841aa6bb86e086f7128e5620" dependencies = [ "proc-macro2 1.0.18", "quote 1.0.7", @@ -986,6 +989,7 @@ dependencies = [ [[package]] name = "snarkos-errors" version = "0.8.0" +source = "git+ssh://git@github.com/AleoHQ/snarkOS.git?rev=c7a56d9#c7a56d97a76dd6e7841aa6bb86e086f7128e5620" dependencies = [ "base58", "bech32", @@ -998,6 +1002,7 @@ dependencies = [ [[package]] name = "snarkos-gadgets" version = "0.8.0" +source = "git+ssh://git@github.com/AleoHQ/snarkOS.git?rev=c7a56d9#c7a56d97a76dd6e7841aa6bb86e086f7128e5620" dependencies = [ "derivative", "digest 0.8.1", @@ -1011,6 +1016,7 @@ dependencies = [ [[package]] name = "snarkos-models" version = "0.8.0" +source = "git+ssh://git@github.com/AleoHQ/snarkOS.git?rev=c7a56d9#c7a56d97a76dd6e7841aa6bb86e086f7128e5620" dependencies = [ "bincode", "derivative", @@ -1025,10 +1031,12 @@ dependencies = [ [[package]] name = "snarkos-profiler" version = "0.8.0" +source = "git+ssh://git@github.com/AleoHQ/snarkOS.git?rev=c7a56d9#c7a56d97a76dd6e7841aa6bb86e086f7128e5620" [[package]] name = "snarkos-utilities" version = "0.8.0" +source = "git+ssh://git@github.com/AleoHQ/snarkOS.git?rev=c7a56d9#c7a56d97a76dd6e7841aa6bb86e086f7128e5620" dependencies = [ "bincode", "rand", diff --git a/Cargo.toml b/Cargo.toml index 076c80b80b..17cc6e4e69 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,12 +19,12 @@ members = [ "ast", "compiler", "leo-inputs", "types" ] leo-compiler = { path = "compiler", version = "0.1.0" } leo-inputs = { path = "leo-inputs", version = "0.1.0"} -snarkos-algorithms = { path = "../snarkOS/algorithms", version = "0.8.0", default-features = false } -snarkos-curves = { path = "../snarkOS/curves", version = "0.8.0", default-features = false } -snarkos-errors = { path = "../snarkOS/errors", version = "0.8.0", default-features = false } -snarkos-gadgets = { path = "../snarkOS/gadgets", version = "0.8.0", default-features = false } -snarkos-models = { path = "../snarkOS/models", version = "0.8.0", default-features = false } -snarkos-utilities = { path = "../snarkOS/utilities", version = "0.8.0" } +snarkos-algorithms = { git = "ssh://git@github.com/AleoHQ/snarkOS.git", rev = "c7a56d9", default-features = false } +snarkos-curves = { git = "ssh://git@github.com/AleoHQ/snarkOS.git", rev = "c7a56d9", default-features = false } +snarkos-errors = { git = "ssh://git@github.com/AleoHQ/snarkOS.git", rev = "c7a56d9", default-features = false } +snarkos-gadgets = { git = "ssh://git@github.com/AleoHQ/snarkOS.git", rev = "c7a56d9", default-features = false } +snarkos-models = { git = "ssh://git@github.com/AleoHQ/snarkOS.git", rev = "c7a56d9", default-features = false } +snarkos-utilities = { git = "ssh://git@github.com/AleoHQ/snarkOS.git", rev = "c7a56d9" } clap = { version = "2.33.0" } colored = { version = "1.9" } diff --git a/compiler/Cargo.toml b/compiler/Cargo.toml index 3a528a946c..cbf4c1d846 100644 --- a/compiler/Cargo.toml +++ b/compiler/Cargo.toml @@ -9,10 +9,10 @@ leo-ast = { path = "../ast", version = "0.1.0" } leo-types = { path = "../types", version = "0.1.0" } leo-inputs = { path = "../leo-inputs", version = "0.1.0" } -snarkos-curves = { path = "../../snarkOS/curves", version = "0.8.0", default-features = false } -snarkos-errors = { path = "../../snarkOS/errors", version = "0.8.0", default-features = false } -snarkos-gadgets = { path = "../../snarkOS/gadgets", version = "0.8.0", default-features = false } -snarkos-models = { path = "../../snarkOS/models", version = "0.8.0", default-features = false } +snarkos-curves = { git = "ssh://git@github.com/AleoHQ/snarkOS.git", rev = "c7a56d9", default-features = false } +snarkos-errors = { git = "ssh://git@github.com/AleoHQ/snarkOS.git", rev = "c7a56d9", default-features = false } +snarkos-gadgets = { git = "ssh://git@github.com/AleoHQ/snarkOS.git", rev = "c7a56d9", default-features = false } +snarkos-models = { git = "ssh://git@github.com/AleoHQ/snarkOS.git", rev = "c7a56d9", default-features = false } hex = { version = "0.4.2" } log = { version = "0.4" } @@ -22,4 +22,4 @@ sha2 = { version = "0.8" } thiserror = { version = "1.0" } [dev-dependencies] -snarkos-utilities = { path = "../../snarkOS/utilities", version = "0.8.0" } +snarkos-utilities = { git = "ssh://git@github.com/AleoHQ/snarkOS.git", rev = "c7a56d9" } diff --git a/leo-inputs/Cargo.toml b/leo-inputs/Cargo.toml index 9b41c18964..8d4f212f42 100644 --- a/leo-inputs/Cargo.toml +++ b/leo-inputs/Cargo.toml @@ -5,11 +5,11 @@ authors = ["The Aleo Team "] edition = "2018" [dependencies] -snarkos-algorithms = { path = "../../snarkOS/algorithms", version = "0.8.0", default-features = false } -snarkos-curves = { path = "../../snarkOS/curves", version = "0.8.0", default-features = false } -snarkos-errors = { path = "../../snarkOS/errors", version = "0.8.0", default-features = false } -snarkos-gadgets = { path = "../../snarkOS/gadgets", version = "0.8.0", default-features = false } -snarkos-models = { path = "../../snarkOS/models", version = "0.8.0", default-features = false } +snarkos-algorithms = { git = "ssh://git@github.com/AleoHQ/snarkOS.git", rev = "c7a56d9", default-features = false } +snarkos-curves = { git = "ssh://git@github.com/AleoHQ/snarkOS.git", rev = "c7a56d9", default-features = false } +snarkos-errors = { git = "ssh://git@github.com/AleoHQ/snarkOS.git", rev = "c7a56d9", default-features = false } +snarkos-gadgets = { git = "ssh://git@github.com/AleoHQ/snarkOS.git", rev = "c7a56d9", default-features = false } +snarkos-models = { git = "ssh://git@github.com/AleoHQ/snarkOS.git", rev = "c7a56d9", default-features = false } from-pest = { version = "0.3.1" } pest = { version = "2.0" } diff --git a/types/Cargo.toml b/types/Cargo.toml index 03c2901821..4925f2a017 100644 --- a/types/Cargo.toml +++ b/types/Cargo.toml @@ -8,8 +8,8 @@ edition = "2018" leo-ast = { path = "../ast", version = "0.1.0" } leo-inputs = { path = "../leo-inputs", version = "0.1.0" } -snarkos-errors = { path = "../../snarkOS/errors", version = "0.8.0", default-features = false } -snarkos-models = { path = "../../snarkOS/models", version = "0.8.0", default-features = false } +snarkos-errors = { git = "ssh://git@github.com/AleoHQ/snarkOS.git", rev = "c7a56d9", default-features = false } +snarkos-models = { git = "ssh://git@github.com/AleoHQ/snarkOS.git", rev = "c7a56d9", default-features = false } pest = { version = "2.0" } thiserror = { version = "1.0" } From a9338a975634a43cb541d5301491c10b68444ce0 Mon Sep 17 00:00:00 2001 From: collin Date: Sat, 27 Jun 2020 23:48:55 -0700 Subject: [PATCH 12/26] add import directory file and errors --- leo/directories/imports.rs | 33 +++++++++++++++++++++++++++++++++ leo/directories/mod.rs | 3 +++ leo/errors/directory/imports.rs | 28 ++++++++++++++++++++++++++++ leo/errors/directory/mod.rs | 3 +++ leo/files/zip.rs | 6 ++++-- 5 files changed, 71 insertions(+), 2 deletions(-) create mode 100644 leo/directories/imports.rs create mode 100644 leo/errors/directory/imports.rs diff --git a/leo/directories/imports.rs b/leo/directories/imports.rs new file mode 100644 index 0000000000..2036deb835 --- /dev/null +++ b/leo/directories/imports.rs @@ -0,0 +1,33 @@ +use crate::errors::ImportsDirectoryError; + +use std::{fs, path::PathBuf}; + +pub(crate) static IMPORTS_DIRECTORY_NAME: &str = "imports/"; + +pub struct ImportsDirectory; + +impl ImportsDirectory { + /// Creates a directory at the provided path with the default directory name. + pub fn create(path: &PathBuf) -> Result<(), ImportsDirectoryError> { + let mut path = path.to_owned(); + if path.is_dir() && !path.ends_with(IMPORTS_DIRECTORY_NAME) { + path.push(PathBuf::from(IMPORTS_DIRECTORY_NAME)); + } + + fs::create_dir_all(&path).map_err(ImportsDirectoryError::Creating) + } + + /// Removes the directory at the provided path. + pub fn remove(path: &PathBuf) -> Result<(), ImportsDirectoryError> { + let mut path = path.to_owned(); + if path.is_dir() && !path.ends_with(IMPORTS_DIRECTORY_NAME) { + path.push(PathBuf::from(IMPORTS_DIRECTORY_NAME)); + } + + if path.exists() { + fs::remove_dir_all(&path).map_err(ImportsDirectoryError::Removing)?; + } + + Ok(()) + } +} diff --git a/leo/directories/mod.rs b/leo/directories/mod.rs index 31f99c6104..6a37fa8b54 100644 --- a/leo/directories/mod.rs +++ b/leo/directories/mod.rs @@ -1,3 +1,6 @@ +pub mod imports; +pub use self::imports::*; + pub mod inputs; pub use self::inputs::*; diff --git a/leo/errors/directory/imports.rs b/leo/errors/directory/imports.rs new file mode 100644 index 0000000000..7dd2114fc0 --- /dev/null +++ b/leo/errors/directory/imports.rs @@ -0,0 +1,28 @@ +use std::{ffi::OsString, fs::FileType, io}; + +#[derive(Debug, Error)] +pub enum ImportsDirectoryError { + #[error("creating: {}", _0)] + Creating(io::Error), + + #[error("file entry getting: {}", _0)] + GettingFileEntry(io::Error), + + #[error("file {:?} extension getting", _0)] + GettingFileExtension(OsString), + + #[error("file {:?} type getting: {}", _0, _1)] + GettingFileType(OsString, io::Error), + + #[error("invalid file {:?} extension: {:?}", _0, _1)] + InvalidFileExtension(OsString, OsString), + + #[error("invalid file {:?} type: {:?}", _0, _1)] + InvalidFileType(OsString, FileType), + + #[error("reading: {}", _0)] + Reading(io::Error), + + #[error("removing: {}", _0)] + Removing(io::Error), +} diff --git a/leo/errors/directory/mod.rs b/leo/errors/directory/mod.rs index 31f99c6104..6a37fa8b54 100644 --- a/leo/errors/directory/mod.rs +++ b/leo/errors/directory/mod.rs @@ -1,3 +1,6 @@ +pub mod imports; +pub use self::imports::*; + pub mod inputs; pub use self::inputs::*; diff --git a/leo/files/zip.rs b/leo/files/zip.rs index d536c00838..c817f826f1 100644 --- a/leo/files/zip.rs +++ b/leo/files/zip.rs @@ -1,7 +1,7 @@ //! The program package zip file. use crate::{ - directories::{INPUTS_DIRECTORY_NAME, OUTPUTS_DIRECTORY_NAME}, + directories::{IMPORTS_DIRECTORY_NAME, INPUTS_DIRECTORY_NAME, OUTPUTS_DIRECTORY_NAME}, errors::ZipFileError, files::{ CHECKSUM_FILE_EXTENSION, @@ -109,9 +109,11 @@ impl ZipFile { } fn is_excluded(path: &Path) -> bool { - // excluded directories: `/inputs`, `/outputs` + // excluded directories: `inputs`, `outputs`, `imports` if path.ends_with(INPUTS_DIRECTORY_NAME.trim_end_matches("/")) | path.ends_with(OUTPUTS_DIRECTORY_NAME.trim_end_matches("/")) + | path.ends_with(IMPORTS_DIRECTORY_NAME.trim_end_matches("/")) + | path { return true; } From cbe65e1c6cc45f522ea33d94d30ee4a1f1d42e8f Mon Sep 17 00:00:00 2001 From: howardwu Date: Sat, 27 Jun 2020 23:56:31 -0700 Subject: [PATCH 13/26] Cleanup CI --- .github/workflows/ci.yml | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4a44311fba..f63c0c5b21 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -73,34 +73,28 @@ jobs: env: CARGO_NET_GIT_FETCH_WITH_CLI: true with: - command: check - args: --examples --all + command: check + args: --examples --all - name: Check examples with all features on stable uses: actions-rs/cargo@v1 -# env: -# CARGO_NET_GIT_FETCH_WITH_CLI: true with: - command: check - args: --examples --all-features --all + command: check + args: --examples --all-features --all if: matrix.rust == 'stable' - name: Check benchmarks on nightly uses: actions-rs/cargo@v1 -# env: -# CARGO_NET_GIT_FETCH_WITH_CLI: true with: - command: check - args: --all-features --examples --all --benches + command: check + args: --all-features --examples --all --benches if: matrix.rust == 'nightly' - name: Test uses: actions-rs/cargo@v1 -# env: -# CARGO_NET_GIT_FETCH_WITH_CLI: true with: - command: test - args: --release --all --no-fail-fast + command: test + args: --release --all --no-fail-fast codecov: name: Code Coverage From 607685122b6837e9d193269badffd401b584999b Mon Sep 17 00:00:00 2001 From: howardwu Date: Sun, 28 Jun 2020 18:24:36 -0700 Subject: [PATCH 14/26] Update logger, add debug flag, improve CLI messages, add num_constraints --- compiler/src/compiler.rs | 2 +- examples/pedersen_hash/src/main.leo | 4 +- examples/test/.gitignore | 1 + examples/test/Leo.toml | 3 ++ examples/test/inputs/test.in | 4 ++ examples/test/src/main.leo | 5 +++ leo/cli.rs | 15 ++++++- leo/commands/build.rs | 6 ++- leo/commands/setup.rs | 15 +++++-- leo/files/checksum.rs | 2 - leo/files/proving_key.rs | 2 - leo/files/verification_key.rs | 2 - leo/logger.rs | 20 +--------- leo/main.rs | 61 ++++++++++++----------------- 14 files changed, 75 insertions(+), 67 deletions(-) create mode 100644 examples/test/.gitignore create mode 100644 examples/test/Leo.toml create mode 100644 examples/test/inputs/test.in create mode 100644 examples/test/src/main.leo diff --git a/compiler/src/compiler.rs b/compiler/src/compiler.rs index 4b5ea8be63..312ab9c3cf 100644 --- a/compiler/src/compiler.rs +++ b/compiler/src/compiler.rs @@ -127,7 +127,7 @@ impl> ConstraintSynthesizer for Compil })?; // Write results to file or something - log::info!("{}", result); + // log::info!("{}", result); Ok(()) } diff --git a/examples/pedersen_hash/src/main.leo b/examples/pedersen_hash/src/main.leo index ce7b714716..5b417f604f 100644 --- a/examples/pedersen_hash/src/main.leo +++ b/examples/pedersen_hash/src/main.leo @@ -15,8 +15,8 @@ circuit PedersenHash { // The 'pedersen_hash' main function. function main() -> u32 { - let parameters = [0u32; 512]; - let pedersen = PedersenHash::new(parameters); + const parameters = [0u32; 512]; + const pedersen = PedersenHash::new(parameters); let input: bool[512] = [true; 512]; return pedersen.hash(input) } diff --git a/examples/test/.gitignore b/examples/test/.gitignore new file mode 100644 index 0000000000..17aa483ab4 --- /dev/null +++ b/examples/test/.gitignore @@ -0,0 +1 @@ +outputs/ diff --git a/examples/test/Leo.toml b/examples/test/Leo.toml new file mode 100644 index 0000000000..f18a42ff37 --- /dev/null +++ b/examples/test/Leo.toml @@ -0,0 +1,3 @@ +[package] +name = "test" +version = "0.1.0" diff --git a/examples/test/inputs/test.in b/examples/test/inputs/test.in new file mode 100644 index 0000000000..9f7c94c12f --- /dev/null +++ b/examples/test/inputs/test.in @@ -0,0 +1,4 @@ +// The program inputs for test/src/main.leo +[main] +a: u32 = 1; +b: u32 = 2; diff --git a/examples/test/src/main.leo b/examples/test/src/main.leo new file mode 100644 index 0000000000..f5d7f2b03c --- /dev/null +++ b/examples/test/src/main.leo @@ -0,0 +1,5 @@ +// The 'test' main function. +function main(a: u32, b: u32) -> u32 { + let c: u32 = a + b; + return c +} diff --git a/leo/cli.rs b/leo/cli.rs index 2e321ec02a..ac49bfbf75 100644 --- a/leo/cli.rs +++ b/leo/cli.rs @@ -1,4 +1,4 @@ -use crate::{cli_types::*, errors::CLIError}; +use crate::{cli_types::*, errors::CLIError, logger}; use clap::{App, AppSettings, Arg, ArgMatches, SubCommand}; @@ -66,6 +66,19 @@ pub trait CLI { .subcommands(subcommands) } + #[cfg_attr(tarpaulin, skip)] + fn process(arguments: &ArgMatches) -> Result<(), CLIError> { + // Set logging environment + match arguments.is_present("debug") { + true => logger::init_logger("leo", 2), + false => logger::init_logger("leo", 1), + } + + let options = Self::parse(arguments)?; + let _output = Self::output(options)?; + Ok(()) + } + #[cfg_attr(tarpaulin, skip)] fn parse(arguments: &ArgMatches) -> Result; diff --git a/leo/commands/build.rs b/leo/commands/build.rs index 6011e13f57..2e78600a85 100644 --- a/leo/commands/build.rs +++ b/leo/commands/build.rs @@ -9,6 +9,7 @@ use leo_compiler::{compiler::Compiler, group::edwards_bls12::EdwardsGroupType}; use snarkos_algorithms::snark::KeypairAssembly; use snarkos_curves::{bls12_377::Bls12_377, edwards_bls12::Fq}; +use snarkos_models::gadgets::r1cs::ConstraintSystem; use clap::ArgMatches; use std::{convert::TryFrom, env::current_dir}; @@ -76,6 +77,7 @@ impl CLI for BuildCommand { let temporary_program = program.clone(); let output = temporary_program.compile_constraints(&mut cs)?; log::debug!("Compiled constraints - {:#?}", output); + log::debug!("Number of constraints - {:#?}", cs.num_constraints()); } // If a checksum file exists, check if it differs from the new checksum @@ -92,9 +94,11 @@ impl CLI for BuildCommand { if checksum_differs { // Write the new checksum to the outputs directory checksum_file.write_to(&path, program_checksum)?; + + log::info!("Checksum saved ({:?})", path); } - log::info!("Compiled program in {:?}", main_file_path); + log::info!("Compiled program ({:?})", main_file_path); Ok((program, checksum_differs)) } diff --git a/leo/commands/setup.rs b/leo/commands/setup.rs index 8cd115bc3e..072d18c870 100644 --- a/leo/commands/setup.rs +++ b/leo/commands/setup.rs @@ -52,6 +52,8 @@ impl CLI for SetupCommand { // If keys do not exist or the checksum differs, run the program setup if !keys_exist || checksum_differs { + log::info!("Setup starting..."); + // Start the timer let start = Instant::now(); @@ -61,18 +63,25 @@ impl CLI for SetupCommand { let prepared_verifying_key = prepare_verifying_key::(¶meters.vk); // End the timer - log::info!("Setup completed in {:?} milliseconds", start.elapsed().as_millis()); + let end = start.elapsed().as_millis(); // TODO (howardwu): Convert parameters to a 'proving key' struct for serialization. // Write the proving key file to the outputs directory let mut proving_key = vec![]; parameters.write(&mut proving_key)?; ProvingKeyFile::new(&package_name).write_to(&path, &proving_key)?; + log::info!("Saving proving key ({:?})", path); - // Write the proving key file to the outputs directory + // Write the verification key file to the outputs directory let mut verification_key = vec![]; prepared_verifying_key.write(&mut verification_key)?; VerificationKeyFile::new(&package_name).write_to(&path, &verification_key)?; + log::info!("Saving verification key ({:?})", path); + + // Output the setup time + log::info!("Setup completed in {:?} milliseconds", end); + } else { + log::info!("Setup complete"); } // Read the proving key file from the outputs directory @@ -98,7 +107,7 @@ impl CLI for SetupCommand { } } - log::info!("Completed program setup"); + log::info!("Program setup complete"); Ok((program, parameters, prepared_verifying_key)) } diff --git a/leo/files/checksum.rs b/leo/files/checksum.rs index b71c227808..d06ab14abc 100644 --- a/leo/files/checksum.rs +++ b/leo/files/checksum.rs @@ -42,8 +42,6 @@ impl ChecksumFile { let mut file = File::create(&path)?; file.write_all(checksum.as_bytes())?; - log::info!("Checksum stored to {:?}", path); - Ok(()) } diff --git a/leo/files/proving_key.rs b/leo/files/proving_key.rs index 49b42ba037..082eedd51f 100644 --- a/leo/files/proving_key.rs +++ b/leo/files/proving_key.rs @@ -42,8 +42,6 @@ impl ProvingKeyFile { let mut file = File::create(&path)?; file.write_all(proving_key)?; - log::info!("Proving key stored to {:?}", path); - Ok(()) } diff --git a/leo/files/verification_key.rs b/leo/files/verification_key.rs index 07071c8b18..a74328c82b 100644 --- a/leo/files/verification_key.rs +++ b/leo/files/verification_key.rs @@ -42,8 +42,6 @@ impl VerificationKeyFile { let mut file = File::create(&path)?; file.write_all(verification_key)?; - log::info!("Verification key stored to {:?}", path); - Ok(()) } diff --git a/leo/logger.rs b/leo/logger.rs index e4c12234f7..98c48c34d7 100644 --- a/leo/logger.rs +++ b/leo/logger.rs @@ -3,33 +3,18 @@ use std::io::Write; const LEVEL_NAME_LENGTH: usize = 10; -#[allow(dead_code)] -fn level_string(level: log::Level) -> colored::ColoredString { - match level { - log::Level::Error => "ERROR".bold().red(), - log::Level::Warn => "WARN".bold().yellow(), - log::Level::Info => "INFO".bold().blue(), - log::Level::Debug => "DEBUG".bold().magenta(), - log::Level::Trace => "TRACE".bold(), - } -} - #[allow(dead_code)] fn colored_string(level: log::Level, message: &str) -> colored::ColoredString { match level { log::Level::Error => message.bold().red(), log::Level::Warn => message.bold().yellow(), - log::Level::Info => message.bold().blue(), + log::Level::Info => message.bold().cyan(), log::Level::Debug => message.bold().magenta(), log::Level::Trace => message.bold(), } } /// Initialize logger with custom format and verbosity. -/// -/// # Arguments -/// -/// * `verbosity` - Verbosity level. 0 for `Warn`, 1 for `Info`, 2 for `Debug`, more for `Trace` pub fn init_logger(app_name: &'static str, verbosity: usize) { env_logger::builder() .filter_level(match verbosity { @@ -46,8 +31,7 @@ pub fn init_logger(app_name: &'static str, verbosity: usize) { writeln!( buf, - "{:>5}{:>5} {}", - level_string(record.level()), + "{:>5} {}", colored_string(record.level(), app_name), record.args().to_string().replace("\n", &padding) ) diff --git a/leo/main.rs b/leo/main.rs index 6b542b3f41..b6c14f883a 100644 --- a/leo/main.rs +++ b/leo/main.rs @@ -1,11 +1,9 @@ -use leo::{cli::*, commands::*, errors::CLIError, logger}; +use leo::{cli::*, commands::*, errors::CLIError}; -use clap::{App, AppSettings}; +use clap::{App, AppSettings, Arg}; #[cfg_attr(tarpaulin, skip)] fn main() -> Result<(), CLIError> { - logger::init_logger("leo", 1); - let arguments = App::new("leo") .version("v0.1.0") .about("Leo compiler and package manager") @@ -16,46 +14,39 @@ fn main() -> Result<(), CLIError> { AppSettings::DisableVersion, AppSettings::SubcommandRequiredElseHelp, ]) + .args(&[Arg::with_name("debug") + .short("d") + .long("debug") + .help("Enables debugging mode") + .global(true)]) .subcommands(vec![ NewCommand::new().display_order(0), InitCommand::new().display_order(1), BuildCommand::new().display_order(2), - LoadCommand::new().display_order(3), - UnloadCommand::new().display_order(4), - SetupCommand::new().display_order(5), - ProveCommand::new().display_order(6), - RunCommand::new().display_order(7), - PublishCommand::new().display_order(8), - DeployCommand::new().display_order(9), - TestCommand::new().display_order(10), + TestCommand::new().display_order(3), + LoadCommand::new().display_order(4), + UnloadCommand::new().display_order(5), + SetupCommand::new().display_order(6), + ProveCommand::new().display_order(7), + RunCommand::new().display_order(8), + PublishCommand::new().display_order(9), + DeployCommand::new().display_order(10), ]) .set_term_width(0) .get_matches(); match arguments.subcommand() { - ("new", Some(arguments)) => NewCommand::output(NewCommand::parse(arguments)?), - ("init", Some(arguments)) => InitCommand::output(InitCommand::parse(arguments)?), - ("build", Some(arguments)) => { - BuildCommand::output(BuildCommand::parse(arguments)?)?; - Ok(()) - } - ("load", Some(arguments)) => LoadCommand::output(LoadCommand::parse(arguments)?), - ("unload", Some(arguments)) => UnloadCommand::output(UnloadCommand::parse(arguments)?), - ("setup", Some(arguments)) => { - SetupCommand::output(SetupCommand::parse(arguments)?)?; - Ok(()) - } - ("prove", Some(arguments)) => { - ProveCommand::output(ProveCommand::parse(arguments)?)?; - Ok(()) - } - ("run", Some(arguments)) => RunCommand::output(RunCommand::parse(arguments)?), - ("publish", Some(arguments)) => PublishCommand::output(PublishCommand::parse(arguments)?), - ("deploy", Some(arguments)) => DeployCommand::output(DeployCommand::parse(arguments)?), - ("test", Some(arguments)) => { - TestCommand::output(TestCommand::parse(arguments)?)?; - Ok(()) - } + ("new", Some(arguments)) => NewCommand::process(arguments), + ("init", Some(arguments)) => InitCommand::process(arguments), + ("build", Some(arguments)) => BuildCommand::process(arguments), + ("test", Some(arguments)) => TestCommand::process(arguments), + ("load", Some(arguments)) => LoadCommand::process(arguments), + ("unload", Some(arguments)) => UnloadCommand::process(arguments), + ("setup", Some(arguments)) => SetupCommand::process(arguments), + ("prove", Some(arguments)) => ProveCommand::process(arguments), + ("run", Some(arguments)) => RunCommand::process(arguments), + ("publish", Some(arguments)) => PublishCommand::process(arguments), + ("deploy", Some(arguments)) => DeployCommand::process(arguments), _ => unreachable!(), } } From c1243a2e74c609755e1e0e1e2e3454af35b1395b Mon Sep 17 00:00:00 2001 From: howardwu Date: Sun, 28 Jun 2020 18:53:09 -0700 Subject: [PATCH 15/26] Adds the command --- compiler/src/compiler.rs | 2 +- leo/commands/clean.rs | 53 ++++++++++++++++++++++++++++ leo/commands/mod.rs | 3 ++ leo/errors/files/checksum.rs | 3 ++ leo/errors/files/proof.rs | 3 ++ leo/errors/files/proving_key.rs | 3 ++ leo/errors/files/verification_key.rs | 3 ++ leo/files/checksum.rs | 12 +++++++ leo/files/proof.rs | 12 +++++++ leo/files/proving_key.rs | 12 +++++++ leo/files/verification_key.rs | 12 +++++++ leo/main.rs | 2 ++ 12 files changed, 119 insertions(+), 1 deletion(-) create mode 100644 leo/commands/clean.rs diff --git a/compiler/src/compiler.rs b/compiler/src/compiler.rs index 312ab9c3cf..4b5ea8be63 100644 --- a/compiler/src/compiler.rs +++ b/compiler/src/compiler.rs @@ -127,7 +127,7 @@ impl> ConstraintSynthesizer for Compil })?; // Write results to file or something - // log::info!("{}", result); + log::info!("{}", result); Ok(()) } diff --git a/leo/commands/clean.rs b/leo/commands/clean.rs new file mode 100644 index 0000000000..cd0f620a6c --- /dev/null +++ b/leo/commands/clean.rs @@ -0,0 +1,53 @@ +use crate::{ + cli::*, + cli_types::*, + commands::BuildCommand, + errors::CLIError, + files::{ChecksumFile, Manifest, ProofFile, ProvingKeyFile, VerificationKeyFile}, +}; + +use clap::ArgMatches; +use std::{convert::TryFrom, env::current_dir}; + +#[derive(Debug)] +pub struct CleanCommand; + +impl CLI for CleanCommand { + type Options = (); + type Output = (); + + const ABOUT: AboutType = "Clean the outputs directory"; + const ARGUMENTS: &'static [ArgumentType] = &[]; + const FLAGS: &'static [FlagType] = &[]; + const NAME: NameType = "clean"; + const OPTIONS: &'static [OptionType] = &[]; + const SUBCOMMANDS: &'static [SubCommandType] = &[]; + + #[cfg_attr(tarpaulin, skip)] + fn parse(_arguments: &ArgMatches) -> Result { + Ok(()) + } + + #[cfg_attr(tarpaulin, skip)] + fn output(options: Self::Options) -> Result { + let (_program, _checksum_differs) = BuildCommand::output(options)?; + + // Get the package name + let path = current_dir()?; + let package_name = Manifest::try_from(&path)?.get_package_name(); + + // Remove the checksum from the outputs directory + ChecksumFile::new(&package_name).remove(&path)?; + + // Remove the proving key from the outputs directory + ProvingKeyFile::new(&package_name).remove(&path)?; + + // Remove the verification key from the outputs directory + VerificationKeyFile::new(&package_name).remove(&path)?; + + // Remove the proof from the outputs directory + ProofFile::new(&package_name).remove(&path)?; + + Ok(()) + } +} diff --git a/leo/commands/mod.rs b/leo/commands/mod.rs index 14bc6c664d..152ebb158a 100644 --- a/leo/commands/mod.rs +++ b/leo/commands/mod.rs @@ -1,6 +1,9 @@ pub mod build; pub use self::build::*; +pub mod clean; +pub use self::clean::*; + pub mod deploy; pub use self::deploy::*; diff --git a/leo/errors/files/checksum.rs b/leo/errors/files/checksum.rs index 4fed871e41..65fe78c9e6 100644 --- a/leo/errors/files/checksum.rs +++ b/leo/errors/files/checksum.rs @@ -11,6 +11,9 @@ pub enum ChecksumFileError { #[error("Cannot read from the provided file path - {:?}", _0)] FileReadError(PathBuf), + #[error("Cannot remove the provided file - {:?}", _0)] + FileRemovalError(PathBuf), + #[error("writing: {}", _0)] Writing(io::Error), } diff --git a/leo/errors/files/proof.rs b/leo/errors/files/proof.rs index fe7785cc5a..e0e8b1b022 100644 --- a/leo/errors/files/proof.rs +++ b/leo/errors/files/proof.rs @@ -11,6 +11,9 @@ pub enum ProofFileError { #[error("Cannot read from the provided file path - {:?}", _0)] FileReadError(PathBuf), + #[error("Cannot remove the provided file - {:?}", _0)] + FileRemovalError(PathBuf), + #[error("writing: {}", _0)] Writing(io::Error), } diff --git a/leo/errors/files/proving_key.rs b/leo/errors/files/proving_key.rs index e24bfc6fa8..ef9481551a 100644 --- a/leo/errors/files/proving_key.rs +++ b/leo/errors/files/proving_key.rs @@ -11,6 +11,9 @@ pub enum ProvingKeyFileError { #[error("Cannot read from the provided file path - {:?}", _0)] FileReadError(PathBuf), + #[error("Cannot remove the provided file - {:?}", _0)] + FileRemovalError(PathBuf), + #[error("writing: {}", _0)] Writing(io::Error), } diff --git a/leo/errors/files/verification_key.rs b/leo/errors/files/verification_key.rs index 1003af52ab..ffa3d34a61 100644 --- a/leo/errors/files/verification_key.rs +++ b/leo/errors/files/verification_key.rs @@ -11,6 +11,9 @@ pub enum VerificationKeyFileError { #[error("Cannot read from the provided file path - {:?}", _0)] FileReadError(PathBuf), + #[error("Cannot remove the provided file - {:?}", _0)] + FileRemovalError(PathBuf), + #[error("Verification key file was corrupted")] IncorrectVerificationKey, diff --git a/leo/files/checksum.rs b/leo/files/checksum.rs index d06ab14abc..a8d9053021 100644 --- a/leo/files/checksum.rs +++ b/leo/files/checksum.rs @@ -45,6 +45,18 @@ impl ChecksumFile { Ok(()) } + /// Removes the checksum at the given path if it exists. Returns `true` on success, + /// `false` if the file doesn't exist, and `Error` if the file system fails during operation. + pub fn remove(&self, path: &PathBuf) -> Result { + let path = self.setup_file_path(path); + if !path.exists() { + return Ok(false); + } + + fs::remove_file(&path).map_err(|_| ChecksumFileError::FileRemovalError(path.clone()))?; + Ok(true) + } + fn setup_file_path(&self, path: &PathBuf) -> PathBuf { let mut path = path.to_owned(); if path.is_dir() { diff --git a/leo/files/proof.rs b/leo/files/proof.rs index 0e6fa5578e..75e4f22680 100644 --- a/leo/files/proof.rs +++ b/leo/files/proof.rs @@ -48,6 +48,18 @@ impl ProofFile { Ok(()) } + /// Removes the proof at the given path if it exists. Returns `true` on success, + /// `false` if the file doesn't exist, and `Error` if the file system fails during operation. + pub fn remove(&self, path: &PathBuf) -> Result { + let path = self.setup_file_path(path); + if !path.exists() { + return Ok(false); + } + + fs::remove_file(&path).map_err(|_| ProofFileError::FileRemovalError(path.clone()))?; + Ok(true) + } + fn setup_file_path(&self, path: &PathBuf) -> PathBuf { let mut path = path.to_owned(); if path.is_dir() { diff --git a/leo/files/proving_key.rs b/leo/files/proving_key.rs index 082eedd51f..4c62a5cea9 100644 --- a/leo/files/proving_key.rs +++ b/leo/files/proving_key.rs @@ -45,6 +45,18 @@ impl ProvingKeyFile { Ok(()) } + /// Removes the proving key at the given path if it exists. Returns `true` on success, + /// `false` if the file doesn't exist, and `Error` if the file system fails during operation. + pub fn remove(&self, path: &PathBuf) -> Result { + let path = self.setup_file_path(path); + if !path.exists() { + return Ok(false); + } + + fs::remove_file(&path).map_err(|_| ProvingKeyFileError::FileRemovalError(path.clone()))?; + Ok(true) + } + fn setup_file_path(&self, path: &PathBuf) -> PathBuf { let mut path = path.to_owned(); if path.is_dir() { diff --git a/leo/files/verification_key.rs b/leo/files/verification_key.rs index a74328c82b..6087e2d999 100644 --- a/leo/files/verification_key.rs +++ b/leo/files/verification_key.rs @@ -45,6 +45,18 @@ impl VerificationKeyFile { Ok(()) } + /// Removes the verification key at the given path if it exists. Returns `true` on success, + /// `false` if the file doesn't exist, and `Error` if the file system fails during operation. + pub fn remove(&self, path: &PathBuf) -> Result { + let path = self.setup_file_path(path); + if !path.exists() { + return Ok(false); + } + + fs::remove_file(&path).map_err(|_| VerificationKeyFileError::FileRemovalError(path.clone()))?; + Ok(true) + } + fn setup_file_path(&self, path: &PathBuf) -> PathBuf { let mut path = path.to_owned(); if path.is_dir() { diff --git a/leo/main.rs b/leo/main.rs index b6c14f883a..f11932b0b4 100644 --- a/leo/main.rs +++ b/leo/main.rs @@ -31,6 +31,7 @@ fn main() -> Result<(), CLIError> { RunCommand::new().display_order(8), PublishCommand::new().display_order(9), DeployCommand::new().display_order(10), + CleanCommand::new().display_order(11), ]) .set_term_width(0) .get_matches(); @@ -47,6 +48,7 @@ fn main() -> Result<(), CLIError> { ("run", Some(arguments)) => RunCommand::process(arguments), ("publish", Some(arguments)) => PublishCommand::process(arguments), ("deploy", Some(arguments)) => DeployCommand::process(arguments), + ("clean", Some(arguments)) => CleanCommand::process(arguments), _ => unreachable!(), } } From a262622f605c43e2841bc8bf11753ca9fe2fae8c Mon Sep 17 00:00:00 2001 From: howardwu Date: Sun, 28 Jun 2020 18:53:40 -0700 Subject: [PATCH 16/26] Remove the test folder --- examples/test/.gitignore | 1 - examples/test/Leo.toml | 3 --- examples/test/inputs/test.in | 4 ---- examples/test/src/main.leo | 5 ----- 4 files changed, 13 deletions(-) delete mode 100644 examples/test/.gitignore delete mode 100644 examples/test/Leo.toml delete mode 100644 examples/test/inputs/test.in delete mode 100644 examples/test/src/main.leo diff --git a/examples/test/.gitignore b/examples/test/.gitignore deleted file mode 100644 index 17aa483ab4..0000000000 --- a/examples/test/.gitignore +++ /dev/null @@ -1 +0,0 @@ -outputs/ diff --git a/examples/test/Leo.toml b/examples/test/Leo.toml deleted file mode 100644 index f18a42ff37..0000000000 --- a/examples/test/Leo.toml +++ /dev/null @@ -1,3 +0,0 @@ -[package] -name = "test" -version = "0.1.0" diff --git a/examples/test/inputs/test.in b/examples/test/inputs/test.in deleted file mode 100644 index 9f7c94c12f..0000000000 --- a/examples/test/inputs/test.in +++ /dev/null @@ -1,4 +0,0 @@ -// The program inputs for test/src/main.leo -[main] -a: u32 = 1; -b: u32 = 2; diff --git a/examples/test/src/main.leo b/examples/test/src/main.leo deleted file mode 100644 index f5d7f2b03c..0000000000 --- a/examples/test/src/main.leo +++ /dev/null @@ -1,5 +0,0 @@ -// The 'test' main function. -function main(a: u32, b: u32) -> u32 { - let c: u32 = a + b; - return c -} From c622b157f59417f9b26effa7697cd07a948f770a Mon Sep 17 00:00:00 2001 From: howardwu Date: Sun, 28 Jun 2020 19:36:45 -0700 Subject: [PATCH 17/26] Cleanup --- compiler/src/constraints/mod.rs | 1 - leo/commands/build.rs | 4 +++- leo/commands/clean.rs | 5 +---- leo/commands/load.rs | 2 +- leo/commands/prove.rs | 2 ++ leo/commands/unload.rs | 2 +- leo/files/proof.rs | 2 +- 7 files changed, 9 insertions(+), 9 deletions(-) diff --git a/compiler/src/constraints/mod.rs b/compiler/src/constraints/mod.rs index 2045087aff..42a3ce22f4 100644 --- a/compiler/src/constraints/mod.rs +++ b/compiler/src/constraints/mod.rs @@ -53,7 +53,6 @@ pub fn generate_constraints, CS: Constrai match main.clone() { ConstrainedValue::Function(_circuit_identifier, function) => { let result = resolved_program.enforce_main_function(cs, program_name, function, parameters)?; - log::debug!("{}", result); Ok(result) } _ => Err(CompilerError::NoMainFunction), diff --git a/leo/commands/build.rs b/leo/commands/build.rs index 2e78600a85..4bd745c4d7 100644 --- a/leo/commands/build.rs +++ b/leo/commands/build.rs @@ -52,6 +52,8 @@ impl CLI for BuildCommand { return Err(BuildError::MainFileDoesNotExist(package_path.as_os_str().to_owned()).into()); } + log::info!("Compiling..."); + // Create the outputs directory OutputsDirectory::create(&package_path)?; @@ -95,7 +97,7 @@ impl CLI for BuildCommand { // Write the new checksum to the outputs directory checksum_file.write_to(&path, program_checksum)?; - log::info!("Checksum saved ({:?})", path); + log::debug!("Checksum saved ({:?})", path); } log::info!("Compiled program ({:?})", main_file_path); diff --git a/leo/commands/clean.rs b/leo/commands/clean.rs index cd0f620a6c..3c41690019 100644 --- a/leo/commands/clean.rs +++ b/leo/commands/clean.rs @@ -1,7 +1,6 @@ use crate::{ cli::*, cli_types::*, - commands::BuildCommand, errors::CLIError, files::{ChecksumFile, Manifest, ProofFile, ProvingKeyFile, VerificationKeyFile}, }; @@ -29,9 +28,7 @@ impl CLI for CleanCommand { } #[cfg_attr(tarpaulin, skip)] - fn output(options: Self::Options) -> Result { - let (_program, _checksum_differs) = BuildCommand::output(options)?; - + fn output(_options: Self::Options) -> Result { // Get the package name let path = current_dir()?; let package_name = Manifest::try_from(&path)?.get_package_name(); diff --git a/leo/commands/load.rs b/leo/commands/load.rs index 8cef939d0b..8129b98179 100644 --- a/leo/commands/load.rs +++ b/leo/commands/load.rs @@ -30,7 +30,7 @@ impl CLI for LoadCommand { let path = current_dir()?; let _package_name = Manifest::try_from(&path)?.get_package_name(); - log::info!("Unimplemented - `leo deploy`"); + log::info!("Unimplemented - `leo load`"); Ok(()) } diff --git a/leo/commands/prove.rs b/leo/commands/prove.rs index 14d66e450b..9fd9993e22 100644 --- a/leo/commands/prove.rs +++ b/leo/commands/prove.rs @@ -40,6 +40,8 @@ impl CLI for ProveCommand { let path = current_dir()?; let package_name = Manifest::try_from(&path)?.get_package_name(); + log::info!("Proving..."); + // Fetch program inputs here let inputs_string = InputsFile::new(&package_name).read_from(&path)?; program.parse_inputs(&inputs_string)?; diff --git a/leo/commands/unload.rs b/leo/commands/unload.rs index 52fe84b2b0..614506fe55 100644 --- a/leo/commands/unload.rs +++ b/leo/commands/unload.rs @@ -30,7 +30,7 @@ impl CLI for UnloadCommand { let path = current_dir()?; let _package_name = Manifest::try_from(&path)?.get_package_name(); - log::info!("Unimplemented - `leo deploy`"); + log::info!("Unimplemented - `leo unload`"); Ok(()) } diff --git a/leo/files/proof.rs b/leo/files/proof.rs index 75e4f22680..2353699ef8 100644 --- a/leo/files/proof.rs +++ b/leo/files/proof.rs @@ -43,7 +43,7 @@ impl ProofFile { let mut file = File::create(&path)?; file.write_all(proof)?; - log::info!("Proof stored to {:?}", path); + log::info!("Proof stored ({:?})", path); Ok(()) } From f061c8ea82d2be094fb5ff03625366bf0e6bc1f1 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 29 Jun 2020 11:09:36 +0000 Subject: [PATCH 18/26] Bump sha2 from 0.8.2 to 0.9.0 Bumps [sha2](https://github.com/RustCrypto/hashes) from 0.8.2 to 0.9.0. - [Release notes](https://github.com/RustCrypto/hashes/releases) - [Commits](https://github.com/RustCrypto/hashes/compare/sha2-v0.8.2...sha2-v0.9.0) Signed-off-by: dependabot-preview[bot] --- Cargo.lock | 16 ++-------------- compiler/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3fa513cb86..4ad998187c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -518,7 +518,7 @@ dependencies = [ "log", "pest", "rand", - "sha2 0.8.2", + "sha2", "snarkos-curves", "snarkos-errors", "snarkos-gadgets", @@ -904,18 +904,6 @@ dependencies = [ "opaque-debug", ] -[[package]] -name = "sha2" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a256f46ea78a0c0d9ff00077504903ac881a1dafdc20da66545699e7776b3e69" -dependencies = [ - "block-buffer 0.7.3", - "digest 0.8.1", - "fake-simd", - "opaque-debug", -] - [[package]] name = "sha2" version = "0.9.0" @@ -954,7 +942,7 @@ dependencies = [ "rand", "rand_chacha", "rayon", - "sha2 0.9.0", + "sha2", "smallvec", "snarkos-errors", "snarkos-models", diff --git a/compiler/Cargo.toml b/compiler/Cargo.toml index cbf4c1d846..203acd60b0 100644 --- a/compiler/Cargo.toml +++ b/compiler/Cargo.toml @@ -18,7 +18,7 @@ hex = { version = "0.4.2" } log = { version = "0.4" } pest = { version = "2.0" } rand = { version = "0.7" } -sha2 = { version = "0.8" } +sha2 = { version = "0.9" } thiserror = { version = "1.0" } [dev-dependencies] From b8292e3fd999fe07555f4dc842a79776c88c4671 Mon Sep 17 00:00:00 2001 From: collin Date: Mon, 29 Jun 2020 12:08:18 -0700 Subject: [PATCH 19/26] require spacing after keywords --- ast/src/leo.pest | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/ast/src/leo.pest b/ast/src/leo.pest index 40886ba32a..ca41f1a5b5 100644 --- a/ast/src/leo.pest +++ b/ast/src/leo.pest @@ -18,7 +18,7 @@ protected_name = { LINE_END = { ";" ~ NEWLINE* } // Declared in common/mutable.rs -mutable = { "mut" } +mutable = { "mut " } // Declared in common/range.rs range = { from_expression? ~ ".." ~ to_expression? } @@ -35,15 +35,15 @@ spread = { "..." ~ expression } spread_or_expression = { spread | expression } // Declared in common/static_.rs -static_ = { "static" } +static_ = { "static " } // Declared in common/variable.rs variable = { mutable? ~ identifier ~ (":" ~ type_)? } // Declared in common/declare.rs declare = { let_ | const_ } -const_ = { "const" } -let_ = { "let" } +const_ = { "const " } +let_ = { "let " } /// Operations @@ -177,7 +177,7 @@ access_static_member = { "::" ~ identifier } /// Circuits // Declared in circuits/circuit_definition.rs -circuit = { "circuit" ~ identifier ~ "{" ~ NEWLINE* ~ circuit_member* ~ NEWLINE* ~ "}" ~ NEWLINE* } +circuit = { "circuit " ~ identifier ~ "{" ~ NEWLINE* ~ circuit_member* ~ NEWLINE* ~ "}" ~ NEWLINE* } // Declared in circuits/circuit_field.rs circuit_field = { identifier ~ ":" ~ expression } @@ -193,7 +193,7 @@ circuit_member = { circuit_function | circuit_field_definition } /// Conditionals -expression_conditional = { "if" ~ expression ~ "?" ~ expression ~ ":" ~ expression} +expression_conditional = { "if " ~ expression ~ "? " ~ expression ~ ": " ~ expression} /// Expressions @@ -254,7 +254,7 @@ assert_eq = {"assert_eq!" ~ "(" ~ NEWLINE* ~ expression ~ "," ~ NEWLINE* ~ expre statement_assign = { assignee ~ operation_assign ~ expression ~ LINE_END } // Declared in statements/conditional_statement.rs -statement_conditional = {"if" ~ (expression | "(" ~ expression ~ ")") ~ "{" ~ NEWLINE* ~ statement+ ~ "}" ~ ("else" ~ conditional_nested_or_end_statement)?} +statement_conditional = {"if " ~ (expression | "(" ~ expression ~ ")") ~ "{" ~ NEWLINE* ~ statement+ ~ "}" ~ ("else" ~ conditional_nested_or_end_statement)?} conditional_nested_or_end_statement = { statement_conditional | "{" ~ NEWLINE* ~ statement+ ~ "}"} // Declared in statements/definition_statement.rs @@ -264,26 +264,26 @@ statement_definition = { declare ~ variable ~ "=" ~ expression ~ LINE_END} statement_expression = { expression ~ LINE_END } // Declared in statements/for_statement.rs -statement_for = { "for" ~ identifier ~ "in" ~ expression ~ ".." ~ expression ~ "{" ~ NEWLINE* ~ statement+ ~ "}"} +statement_for = { "for " ~ identifier ~ "in " ~ expression ~ ".." ~ expression ~ "{" ~ NEWLINE* ~ statement+ ~ "}"} // Declared in statements/multiple_assignment_statement.rs statement_multiple_assignment = { declare ~ "(" ~ variable_tuple ~ ")" ~ "=" ~ identifier ~ "(" ~ expression_tuple ~ ")" ~ LINE_END} variable_tuple = _{ variable ~ ("," ~ variable)* } // Declared in statements/return_statement.rs -statement_return = { "return" ~ expression_tuple } +statement_return = { "return " ~ expression_tuple } /// Functions // Declared in functions/function.rs -function_definition = { "function" ~ identifier ~ "(" ~ input_model_list ~ ")" ~ ("->" ~ (type_ | "(" ~ type_list ~ ")"))? ~ "{" ~ NEWLINE* ~ statement* ~ NEWLINE* ~ "}" ~ NEWLINE* } +function_definition = { "function " ~ identifier ~ "(" ~ input_model_list ~ ")" ~ ("->" ~ (type_ | "(" ~ type_list ~ ")"))? ~ "{" ~ NEWLINE* ~ statement* ~ NEWLINE* ~ "}" ~ NEWLINE* } // Declared in functions/function_input.rs function_input = { mutable? ~ identifier ~ ":" ~ type_ } input_model_list = _{ (function_input ~ ("," ~ function_input)*)? } // Declared in functions/test_function.rs -test_function = { "test" ~ function_definition } +test_function = { "test " ~ function_definition } /// Imports @@ -300,4 +300,4 @@ import_symbol_tuple = _{ import_symbol ~ ("," ~ NEWLINE* ~ import_symbol)* } /// Utilities COMMENT = _{ ("/*" ~ (!"*/" ~ ANY)* ~ "*/") | ("//" ~ (!NEWLINE ~ ANY)*) } -WHITESPACE = _{ " " | "\t" ~ (NEWLINE)* } +WHITESPACE = _{ " " | "\t" ~ (NEWLINE)* } // pest implicit whitespace keyword From 457a1b26bccd1ee1fb769a37f17b49c679deb10f Mon Sep 17 00:00:00 2001 From: collin Date: Mon, 29 Jun 2020 13:05:41 -0700 Subject: [PATCH 20/26] add comma to circuit member field def --- ast/src/leo.pest | 4 ++-- compiler/tests/circuits/member_field.leo | 2 +- compiler/tests/circuits/member_field_and_function.leo | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ast/src/leo.pest b/ast/src/leo.pest index ca41f1a5b5..9047f8fcb7 100644 --- a/ast/src/leo.pest +++ b/ast/src/leo.pest @@ -183,13 +183,13 @@ circuit = { "circuit " ~ identifier ~ "{" ~ NEWLINE* ~ circuit_member* ~ NEWLINE circuit_field = { identifier ~ ":" ~ expression } // Declared in circuits/circuit_field_definition.rs -circuit_field_definition = { identifier ~ ":" ~ type_ ~ NEWLINE* } +circuit_field_definition = { identifier ~ ":" ~ type_ ~ ","?} // Declared in circuits/circuit_function.rs circuit_function = { static_? ~ function_definition } // Declared in circuits/circuit_member.rs -circuit_member = { circuit_function | circuit_field_definition } +circuit_member = { circuit_function | circuit_field_definition ~ NEWLINE*} /// Conditionals diff --git a/compiler/tests/circuits/member_field.leo b/compiler/tests/circuits/member_field.leo index fe29638c0e..b9e7b7d88e 100644 --- a/compiler/tests/circuits/member_field.leo +++ b/compiler/tests/circuits/member_field.leo @@ -1,5 +1,5 @@ circuit Circ { - x: u32 + x: u32, } function main() -> u32 { diff --git a/compiler/tests/circuits/member_field_and_function.leo b/compiler/tests/circuits/member_field_and_function.leo index d020942c5c..207ae068e5 100644 --- a/compiler/tests/circuits/member_field_and_function.leo +++ b/compiler/tests/circuits/member_field_and_function.leo @@ -1,5 +1,5 @@ circuit Foo { - foo: u32 + foo: u32, static function bar() -> u32 { return 0 From 18b965583a649cf4828189b3448d0843f3901037 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 29 Jun 2020 20:12:50 +0000 Subject: [PATCH 21/26] Bump rusty-hook from 0.11.1 to 0.11.2 Bumps [rusty-hook](https://github.com/swellaby/rusty-hook) from 0.11.1 to 0.11.2. - [Release notes](https://github.com/swellaby/rusty-hook/releases) - [Commits](https://github.com/swellaby/rusty-hook/commits) Signed-off-by: dependabot-preview[bot] --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 336d80bd3d..bba5287dac 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -903,9 +903,9 @@ checksum = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783" [[package]] name = "rusty-hook" -version = "0.11.1" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27138b73a8ce63ae918707a5e3b57f9b0c0842a57b82f0e43474cf4e3aaf0ff4" +checksum = "96cee9be61be7e1cbadd851e58ed7449c29c620f00b23df937cb9cbc04ac21a3" dependencies = [ "ci_info", "getopts", diff --git a/Cargo.toml b/Cargo.toml index c41f2fb8aa..13ca606fca 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -41,7 +41,7 @@ walkdir = { version = "2" } zip = { version = "0.5" } [dev-dependencies] -rusty-hook = { version = "0.11.1" } +rusty-hook = { version = "0.11.2" } [profile.release] opt-level = 3 From 9854c8c983cc235b0b6736aa60ee18283fdb76be Mon Sep 17 00:00:00 2001 From: collin Date: Mon, 29 Jun 2020 14:11:12 -0700 Subject: [PATCH 22/26] use updated sha2 functions --- compiler/src/compiler.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/src/compiler.rs b/compiler/src/compiler.rs index 8391446535..49c2348bb1 100644 --- a/compiler/src/compiler.rs +++ b/compiler/src/compiler.rs @@ -66,8 +66,8 @@ impl> Compiler { // Hash the file contents let mut hasher = Sha256::new(); - hasher.input(unparsed_file.as_bytes()); - let hash = hasher.result(); + hasher.update(unparsed_file.as_bytes()); + let hash = hasher.finalize(); Ok(hex::encode(hash)) } From d905ffd569d8f32f8e0d634c4292d50b0e3f01a3 Mon Sep 17 00:00:00 2001 From: collin Date: Mon, 29 Jun 2020 17:47:23 -0700 Subject: [PATCH 23/26] impl importing from package lib, file, directory, and star --- ast/src/leo.pest | 2 +- .../src/constraints/import/import_symbol.rs | 42 +++++++++++++++---- compiler/src/constraints/import/package.rs | 19 +++++---- compiler/src/errors/constraints/import.rs | 7 +++- compiler/tests/import/imports/bar/.gitignore | 1 + compiler/tests/import/imports/bar/Leo.toml | 3 ++ .../tests/import/imports/bar/src/bat/bat.leo | 3 ++ compiler/tests/import/imports/bar/src/baz.leo | 3 ++ compiler/tests/import/imports/bar/src/lib.leo | 3 ++ compiler/tests/import/imports/car/.gitignore | 1 + compiler/tests/import/imports/car/Leo.toml | 3 ++ compiler/tests/import/imports/car/src/lib.leo | 3 ++ compiler/tests/import/many_import.leo | 25 +++++++++++ compiler/tests/import/many_import_star.leo | 16 +++++++ compiler/tests/import/mod.rs | 23 ++++++++++ leo/files/lib.rs | 4 +- 16 files changed, 139 insertions(+), 19 deletions(-) create mode 100755 compiler/tests/import/imports/bar/.gitignore create mode 100755 compiler/tests/import/imports/bar/Leo.toml create mode 100755 compiler/tests/import/imports/bar/src/bat/bat.leo create mode 100755 compiler/tests/import/imports/bar/src/baz.leo create mode 100755 compiler/tests/import/imports/bar/src/lib.leo create mode 100755 compiler/tests/import/imports/car/.gitignore create mode 100755 compiler/tests/import/imports/car/Leo.toml create mode 100755 compiler/tests/import/imports/car/src/lib.leo create mode 100644 compiler/tests/import/many_import.leo create mode 100644 compiler/tests/import/many_import_star.leo diff --git a/ast/src/leo.pest b/ast/src/leo.pest index 18f5ce31ca..78652c5fd8 100644 --- a/ast/src/leo.pest +++ b/ast/src/leo.pest @@ -299,7 +299,7 @@ package_access = { | import_symbol } -multiple_package_access = _{ "(" ~ NEWLINE* ~ package_access ~ ("," ~ NEWLINE* ~ package_access)* ~ NEWLINE* ~ ")"} +multiple_package_access = _{ "(" ~ NEWLINE* ~ package_access ~ ("," ~ NEWLINE* ~ package_access)* ~ ","? ~ NEWLINE* ~ ")"} // Declared in imports/star.rs star = {"*"} diff --git a/compiler/src/constraints/import/import_symbol.rs b/compiler/src/constraints/import/import_symbol.rs index da457f59c0..b7a61c11a4 100644 --- a/compiler/src/constraints/import/import_symbol.rs +++ b/compiler/src/constraints/import/import_symbol.rs @@ -8,7 +8,10 @@ use leo_ast::LeoParser; use leo_types::{ImportSymbol, Program, Span}; use snarkos_models::curves::{Field, PrimeField}; -use std::fs::DirEntry; +use std::{ + ffi::OsString, + fs::{read_dir, DirEntry}, +}; static LIBRARY_FILE: &str = "src/lib.leo"; @@ -27,7 +30,10 @@ fn parse_import_file(entry: &DirEntry, span: &Span) -> Result Result> ConstrainedProgram { pub fn enforce_import_star(&mut self, scope: String, entry: &DirEntry, span: Span) -> Result<(), ImportError> { - let mut program = parse_import_file(entry, &span)?; + // import star from a file + if entry.path().is_file() { + // only parse `.leo` files + if let Some(extension) = entry.path().extension() { + if extension.eq(&OsString::from("leo")) { + let mut program = parse_import_file(entry, &span)?; - // Use same namespace as calling function for imported symbols - program = program.name(scope); + // Use same namespace as calling function for imported symbols + program = program.name(scope); - // * -> import all imports, circuits, functions in the current scope - self.resolve_definitions(program) + // * -> import all imports, circuits, functions in the current scope + self.resolve_definitions(program) + } else { + Ok(()) + } + } else { + Ok(()) + } + } else { + // import star for every file in the directory + for entry in read_dir(entry.path()).map_err(|error| ImportError::directory_error(error, span.clone()))? { + match entry { + Ok(entry) => self.enforce_import_star(scope.clone(), &entry, span.clone())?, + Err(error) => return Err(ImportError::directory_error(error, span.clone())), + } + } + + Ok(()) + } } pub fn enforce_import_symbol( diff --git a/compiler/src/constraints/import/package.rs b/compiler/src/constraints/import/package.rs index 868b5048f2..5497bb9f0a 100644 --- a/compiler/src/constraints/import/package.rs +++ b/compiler/src/constraints/import/package.rs @@ -31,14 +31,23 @@ impl> ConstrainedProgram { } } - pub fn enforce_package(&mut self, scope: String, path: PathBuf, package: Package) -> Result<(), ImportError> { + pub fn enforce_package(&mut self, scope: String, mut path: PathBuf, package: Package) -> Result<(), ImportError> { let package_name = package.name; - // search for package name in local src directory + // search for package name in local directory let mut source_directory = path.clone(); source_directory.push(SOURCE_DIRECTORY_NAME); - let entries = fs::read_dir(source_directory) + // search for package name in `imports` directory + let mut imports_directory = path.clone(); + imports_directory.push(IMPORTS_DIRECTORY_NAME); + + // read from local `src` directory or the current path + if source_directory.exists() { + path = source_directory + } + + let entries = fs::read_dir(path) .map_err(|error| ImportError::directory_error(error, package_name.span.clone()))? .into_iter() .collect::, std::io::Error>>() @@ -53,10 +62,6 @@ impl> ConstrainedProgram { .eq(&package_name.name) }); - // search for package name in imports directory - let mut imports_directory = path.clone(); - imports_directory.push(IMPORTS_DIRECTORY_NAME); - if imports_directory.exists() { let entries = fs::read_dir(imports_directory) .map_err(|error| ImportError::directory_error(error, package_name.span.clone()))? diff --git a/compiler/src/errors/constraints/import.rs b/compiler/src/errors/constraints/import.rs index d9f7ed2406..2152bee06c 100644 --- a/compiler/src/errors/constraints/import.rs +++ b/compiler/src/errors/constraints/import.rs @@ -35,8 +35,11 @@ impl ImportError { Self::new_from_span(message, span) } - pub fn expected_file(entry: String, span: Span) -> Self { - let message = format!("cannot import symbol `{}` from directory `{}`", span.text, entry); + pub fn expected_lib_file(entry: String, span: Span) -> Self { + let message = format!( + "expected library file`{}` when looking for symbol `{}`", + entry, span.text + ); Self::new_from_span(message, span) } diff --git a/compiler/tests/import/imports/bar/.gitignore b/compiler/tests/import/imports/bar/.gitignore new file mode 100755 index 0000000000..17aa483ab4 --- /dev/null +++ b/compiler/tests/import/imports/bar/.gitignore @@ -0,0 +1 @@ +outputs/ diff --git a/compiler/tests/import/imports/bar/Leo.toml b/compiler/tests/import/imports/bar/Leo.toml new file mode 100755 index 0000000000..8e22d51a95 --- /dev/null +++ b/compiler/tests/import/imports/bar/Leo.toml @@ -0,0 +1,3 @@ +[package] +name = "bar" +version = "0.1.0" diff --git a/compiler/tests/import/imports/bar/src/bat/bat.leo b/compiler/tests/import/imports/bar/src/bat/bat.leo new file mode 100755 index 0000000000..a7d2fc83d4 --- /dev/null +++ b/compiler/tests/import/imports/bar/src/bat/bat.leo @@ -0,0 +1,3 @@ +circuit Bat { + t: u32 +} \ No newline at end of file diff --git a/compiler/tests/import/imports/bar/src/baz.leo b/compiler/tests/import/imports/bar/src/baz.leo new file mode 100755 index 0000000000..6c1df2d4b9 --- /dev/null +++ b/compiler/tests/import/imports/bar/src/baz.leo @@ -0,0 +1,3 @@ +circuit Baz { + z: u32 +} \ No newline at end of file diff --git a/compiler/tests/import/imports/bar/src/lib.leo b/compiler/tests/import/imports/bar/src/lib.leo new file mode 100755 index 0000000000..c169f5935e --- /dev/null +++ b/compiler/tests/import/imports/bar/src/lib.leo @@ -0,0 +1,3 @@ +circuit Bar { + r: u32 +} \ No newline at end of file diff --git a/compiler/tests/import/imports/car/.gitignore b/compiler/tests/import/imports/car/.gitignore new file mode 100755 index 0000000000..17aa483ab4 --- /dev/null +++ b/compiler/tests/import/imports/car/.gitignore @@ -0,0 +1 @@ +outputs/ diff --git a/compiler/tests/import/imports/car/Leo.toml b/compiler/tests/import/imports/car/Leo.toml new file mode 100755 index 0000000000..15b76f1d76 --- /dev/null +++ b/compiler/tests/import/imports/car/Leo.toml @@ -0,0 +1,3 @@ +[package] +name = "car" +version = "0.1.0" diff --git a/compiler/tests/import/imports/car/src/lib.leo b/compiler/tests/import/imports/car/src/lib.leo new file mode 100755 index 0000000000..b1e037fd38 --- /dev/null +++ b/compiler/tests/import/imports/car/src/lib.leo @@ -0,0 +1,3 @@ +circuit Car { + c: u32 +} \ No newline at end of file diff --git a/compiler/tests/import/many_import.leo b/compiler/tests/import/many_import.leo new file mode 100644 index 0000000000..d67b775cbe --- /dev/null +++ b/compiler/tests/import/many_import.leo @@ -0,0 +1,25 @@ +import test_import.( // local import + Point, + foo, +); + +import bar.( // imports directory import + Bar, + baz.Baz, + bat.bat.Bat, +); + +import car.Car; // imports directory import + +function main() -> u32 { + // const point = Point { x: 1u32, y: 1u32 }; + // const foo = foo(); + + const bar = Bar { r: 1u32 }; + const bat = Bat { t: 1u32 }; + const baz = Baz { z: 1u32 }; + + const car = Car { c: 1u32 }; + + return car.c +} \ No newline at end of file diff --git a/compiler/tests/import/many_import_star.leo b/compiler/tests/import/many_import_star.leo new file mode 100644 index 0000000000..b98e84a2f1 --- /dev/null +++ b/compiler/tests/import/many_import_star.leo @@ -0,0 +1,16 @@ +import test_import.*; // local import +import bar.*; // imports directory import +import car.*; // imports directory import + +function main() -> u32 { + const point = Point { x: 1u32, y: 1u32 }; + const foo = foo(); + + const bar = Bar { r: 1u32 }; + const bat = Bat { t: 1u32 }; + const baz = Baz { z: 1u32 }; + + const car = Car { c: 1u32 }; + + return car.c +} \ No newline at end of file diff --git a/compiler/tests/import/mod.rs b/compiler/tests/import/mod.rs index 5c7ba19c0a..30d210a055 100644 --- a/compiler/tests/import/mod.rs +++ b/compiler/tests/import/mod.rs @@ -56,3 +56,26 @@ fn test_alias() { output_one(program); } + +// more complex tests +#[test] +#[ignore] +fn test_many_import() { + let bytes = include_bytes!("many_import.leo"); + let program = parse_program(bytes).unwrap(); + + set_local_dir(); + + output_one(program); +} + +#[test] +#[ignore] +fn test_many_import_star() { + let bytes = include_bytes!("many_import_star.leo"); + let program = parse_program(bytes).unwrap(); + + set_local_dir(); + + output_one(program); +} diff --git a/leo/files/lib.rs b/leo/files/lib.rs index 2b514cc1cf..54fed26c83 100644 --- a/leo/files/lib.rs +++ b/leo/files/lib.rs @@ -46,8 +46,8 @@ impl LibFile { fn template(&self) -> String { format!( r#"// The '{}' lib function. -circuit Circ {{ - c: field +circuit Foo {{ + a: field }} "#, self.package_name From 4a41f6c6814e651cfeb2a4aa6b259c522ef221ca Mon Sep 17 00:00:00 2001 From: collin Date: Mon, 29 Jun 2020 18:37:52 -0700 Subject: [PATCH 24/26] update readme --- README.md | 117 +++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 94 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index 20cc9b6d8b..60f7c5d741 100644 --- a/README.md +++ b/README.md @@ -356,40 +356,111 @@ function main() -> Circ { ``` ## Imports -Both struct and function imports are supported. +Leo supports importing functions and circuits by name into the current file with the following syntax: -```leo -import all: `*` -import alias: `symbol as alias` +```rust +import [package].[name]; ``` -`src/simple_import.leo` +#### Import Aliases +To import a name using an alias: ```rust -circuit Point { - x: u32 - y: u32 +import [package].[name] as [alias]; +``` + +#### Import Multiple +To import multiple names from the same package: +```rust +import [package].( + [name_1], + [name_2] as [alias], +); +``` + +#### Import Star +To import all symbols from a package: +```rust +import [package].*; +``` + +### Local +You can import from a local file in the `src/` directory by using its `[file].leo` as the `[package]` name. + +```rust +import [file].[name]; +``` + +#### Example: +`src/bar.leo` +```rust +circuit Bar { + b: u32 } -function test() -> (u32, u32[2]) { - return 1, [2, 3] +function baz() -> u32 { + return 1u32 } ``` -`src/simple.leo` +`src/main.leo` ```rust -from "./simple_import" import { - Point as Foo, - test -}; +import bar.( + Bar, + baz +); -// from "./simple_import" import * +function main() { + const bar = Bar { b: 1u32}; + const z = baz(); +} +``` -function main() -> (u32[3]) { - let p = Foo { x: 1, y: 2}; +### Foreign +You can import from a foreign package in the `imports/` directory using its `[package]` name. +```rust +import [package].[name]; +``` - let (a, b) = test(); +#### Example: +`imports/bar/src/lib.leo` +```rust +circuit Bar { + b: u32 +} +``` - return [a, ...b] +`src/main.leo` +```rust +import bar.Bar; + +function main() { + const bar = Bar { b: 1u32 }; +} +``` + +### Package Paths +Leo treats directories as package names when importing. +```rust +import [package].[directory].[file].[name] +``` + +#### Example: +We wish to import the `Baz` circuit from the `baz.leo` file in the `bar` directory in the `foo` package + + +`imports/foo/src/bar/baz.leo` +```rust +circuit Baz { + b: u32 +} +``` + +`src/main.leo` +```rust +import foo.bar.baz.Baz; + +function main() { + const baz = Baz { b: 1u32 }; } ``` @@ -400,11 +471,11 @@ This will enforce that the two values are equal in the constraint system. ```rust function main() { - assert_eq(45, 45); + assert_eq!(45, 45); - assert_eq(2fe, 2fe); + assert_eq!(2fe, 2fe); - assert_eq(true, true); + assert_eq!(true, true); } ``` From 4a36a899e330926667dff8daa9b29f207b6f7413 Mon Sep 17 00:00:00 2001 From: collin Date: Mon, 29 Jun 2020 19:24:41 -0700 Subject: [PATCH 25/26] add --bin and --lib flags to new and init cli commands --- leo/commands/init.rs | 58 +++++++++++++++++++++++------------------ leo/commands/new.rs | 35 ++++++++++++++++--------- leo/commands/publish.rs | 4 +++ leo/errors/cli.rs | 10 +++++++ leo/files/lib.rs | 2 +- 5 files changed, 70 insertions(+), 39 deletions(-) diff --git a/leo/commands/init.rs b/leo/commands/init.rs index da7161312c..ea1656d8f2 100644 --- a/leo/commands/init.rs +++ b/leo/commands/init.rs @@ -3,7 +3,7 @@ use crate::{ cli_types::*, directories::{InputsDirectory, SourceDirectory}, errors::{CLIError, InitError}, - files::{Gitignore, InputsFile, MainFile, Manifest}, + files::{Gitignore, InputsFile, LibFile, MainFile, Manifest}, }; use clap::ArgMatches; @@ -13,35 +13,31 @@ use std::env::current_dir; pub struct InitCommand; impl CLI for InitCommand { - type Options = Option; + type Options = bool; type Output = (); const ABOUT: AboutType = "Create a new Leo package in an existing directory"; const ARGUMENTS: &'static [ArgumentType] = &[]; - const FLAGS: &'static [FlagType] = &[]; + const FLAGS: &'static [FlagType] = &[("--lib"), ("--bin")]; const NAME: NameType = "init"; const OPTIONS: &'static [OptionType] = &[]; const SUBCOMMANDS: &'static [SubCommandType] = &[]; #[cfg_attr(tarpaulin, skip)] - fn parse(_arguments: &ArgMatches) -> Result { - Ok(None) + fn parse(arguments: &ArgMatches) -> Result { + Ok(arguments.is_present("lib")) } #[cfg_attr(tarpaulin, skip)] fn output(options: Self::Options) -> Result { - let name = options; let path = current_dir()?; // Derive the package name - let package_name = match name { - Some(name) => name, - None => path - .file_stem() - .ok_or_else(|| InitError::ProjectNameInvalid(path.as_os_str().to_owned()))? - .to_string_lossy() - .to_string(), - }; + let package_name = path + .file_stem() + .ok_or_else(|| InitError::ProjectNameInvalid(path.as_os_str().to_owned()))? + .to_string_lossy() + .to_string(); // Verify the directory exists if !path.exists() { @@ -62,20 +58,30 @@ impl CLI for InitCommand { // Create the source directory SourceDirectory::create(&path)?; - // Create the inputs directory - InputsDirectory::create(&path)?; + // Create a new library or binary file - // Verify the inputs file does not exist - let inputs_file = InputsFile::new(&package_name); - if !inputs_file.exists_at(&path) { - // Create the inputs file in the inputs directory - inputs_file.write_to(&path)?; - } + if options { + // Verify the library file does not exist + if !LibFile::exists_at(&path) { + // Create the library file in the source directory + LibFile::new(&package_name).write_to(&path)?; + } + } else { + // Create the inputs directory + InputsDirectory::create(&path)?; - // Verify the main file does not exist - if !MainFile::exists_at(&path) { - // Create the main file in the source directory - MainFile::new(&package_name).write_to(&path)?; + // Verify the inputs file does not exist + let inputs_file = InputsFile::new(&package_name); + if !inputs_file.exists_at(&path) { + // Create the inputs file in the inputs directory + inputs_file.write_to(&path)?; + } + + // Verify the main file does not exist + if !MainFile::exists_at(&path) { + // Create the main file in the source directory + MainFile::new(&package_name).write_to(&path)?; + } } Ok(()) diff --git a/leo/commands/new.rs b/leo/commands/new.rs index da7ac0c4dd..88cdb0f3c7 100644 --- a/leo/commands/new.rs +++ b/leo/commands/new.rs @@ -3,7 +3,7 @@ use crate::{ cli_types::*, directories::{InputsDirectory, SourceDirectory}, errors::{CLIError, NewError}, - files::{Gitignore, InputsFile, MainFile, Manifest}, + files::{Gitignore, InputsFile, LibFile, MainFile, Manifest}, }; use clap::ArgMatches; @@ -13,7 +13,7 @@ use std::{env::current_dir, fs}; pub struct NewCommand; impl CLI for NewCommand { - type Options = Option; + type Options = (Option, bool); type Output = (); const ABOUT: AboutType = "Create a new Leo package in a new directory"; @@ -26,16 +26,21 @@ impl CLI for NewCommand { 1u64, ), ]; - const FLAGS: &'static [FlagType] = &[]; + const FLAGS: &'static [FlagType] = &[("--lib"), ("--bin")]; const NAME: NameType = "new"; const OPTIONS: &'static [OptionType] = &[]; const SUBCOMMANDS: &'static [SubCommandType] = &[]; #[cfg_attr(tarpaulin, skip)] fn parse(arguments: &ArgMatches) -> Result { + let mut is_lib = false; + if arguments.is_present("lib") { + is_lib = true; + } + match arguments.value_of("NAME") { - Some(name) => Ok(Some(name.to_string())), - None => Ok(None), + Some(name) => Ok((Some(name.to_string()), is_lib)), + None => Ok((None, is_lib)), } } @@ -44,7 +49,7 @@ impl CLI for NewCommand { let mut path = current_dir()?; // Derive the package name - let package_name = match options { + let package_name = match options.0 { Some(name) => name, None => path .file_stem() @@ -74,14 +79,20 @@ impl CLI for NewCommand { // Create the source directory SourceDirectory::create(&path)?; - // Create the inputs directory - InputsDirectory::create(&path)?; + // Create a new library or binary file + if options.1 { + // Create the library file in the source directory + LibFile::new(&package_name).write_to(&path)?; + } else { + // Create the inputs directory + InputsDirectory::create(&path)?; - // Create the inputs file in the inputs directory - InputsFile::new(&package_name).write_to(&path)?; + // Create the inputs file in the inputs directory + InputsFile::new(&package_name).write_to(&path)?; - // Create the main file in the source directory - MainFile::new(&package_name).write_to(&path)?; + // Create the main file in the source directory + MainFile::new(&package_name).write_to(&path)?; + } Ok(()) } diff --git a/leo/commands/publish.rs b/leo/commands/publish.rs index 905b4c420d..90acbde86f 100644 --- a/leo/commands/publish.rs +++ b/leo/commands/publish.rs @@ -2,6 +2,7 @@ use crate::{ cli::*, cli_types::*, commands::BuildCommand, + directories::outputs::OutputsDirectory, errors::CLIError, files::{Manifest, ZipFile}, }; @@ -38,6 +39,9 @@ impl CLI for PublishCommand { let path = current_dir()?; let package_name = Manifest::try_from(&path)?.get_package_name(); + // Create the outputs directory + OutputsDirectory::create(&path)?; + // Create zip file let zip_file = ZipFile::new(&package_name); if zip_file.exists_at(&path) { diff --git a/leo/errors/cli.rs b/leo/errors/cli.rs index a11c2bcb18..1beb8fc84c 100644 --- a/leo/errors/cli.rs +++ b/leo/errors/cli.rs @@ -26,6 +26,9 @@ pub enum CLIError { #[error("{}", _0)] InputsFileError(InputsFileError), + #[error("{}", _0)] + LibFileError(LibFileError), + #[error("{}", _0)] MainFileError(MainFileError), @@ -106,6 +109,13 @@ impl From for CLIError { } } +impl From for CLIError { + fn from(error: LibFileError) -> Self { + log::error!("{}\n", error); + CLIError::LibFileError(error) + } +} + impl From for CLIError { fn from(error: MainFileError) -> Self { log::error!("{}\n", error); diff --git a/leo/files/lib.rs b/leo/files/lib.rs index 54fed26c83..1b885cf832 100644 --- a/leo/files/lib.rs +++ b/leo/files/lib.rs @@ -45,7 +45,7 @@ impl LibFile { fn template(&self) -> String { format!( - r#"// The '{}' lib function. + r#"// The '{}' library circuit. circuit Foo {{ a: field }} From 26890ff09724163d0f52bb4c360d7ee210a24c6b Mon Sep 17 00:00:00 2001 From: collin Date: Mon, 29 Jun 2020 19:36:30 -0700 Subject: [PATCH 26/26] update readme --- README.md | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 60f7c5d741..8fcbe7ff56 100644 --- a/README.md +++ b/README.md @@ -561,13 +561,28 @@ This will create a new directory with a given package name. The new package will - inputs.leo # Your program inputs for main.leo - outputs # Your program outputs - src - - lib.leo # Your program library - main.leo # Your program - tests - test.leo # Your program tests - Leo.toml # Your program manifest ``` +#### Flags +```rust +leo new {$Name} --bin +``` +This will create a new directory with a given package name. The new package will have a directory structure as above. + +```rust +leo new {$Name} --lib +``` +This will create a new directory with a given package name. The new package will have a directory structure as follows: +``` +- src + - lib.leo # Your program library +- Leo.toml # Your program manifest +``` + ### `leo init` To initialize an existing directory, run: @@ -576,6 +591,16 @@ leo init ``` This will initialize the current directory with the same package directory setup. +#### Flags +`leo init` supports the same flags as `leo new` +```rust +leo init --bin +``` +```rust +leo init --lib +``` + + ### `leo build` To compile your program and verify that it builds properly, run: