add lib.leo support

This commit is contained in:
collin 2020-06-26 20:58:43 -07:00
parent 8825a0741c
commit 9c2a0e4ec6
11 changed files with 292 additions and 126 deletions

View File

@ -2,8 +2,8 @@ use crate::{
cli::*, cli::*,
cli_types::*, cli_types::*,
directories::{source::SOURCE_DIRECTORY_NAME, OutputsDirectory}, directories::{source::SOURCE_DIRECTORY_NAME, OutputsDirectory},
errors::{BuildError, CLIError}, errors::CLIError,
files::{ChecksumFile, MainFile, Manifest, MAIN_FILE_NAME}, files::{ChecksumFile, LibFile, MainFile, Manifest, LIB_FILE_NAME, MAIN_FILE_NAME},
}; };
use leo_compiler::{compiler::Compiler, group::edwards_bls12::EdwardsGroupType}; use leo_compiler::{compiler::Compiler, group::edwards_bls12::EdwardsGroupType};
@ -18,7 +18,7 @@ pub struct BuildCommand;
impl CLI for BuildCommand { impl CLI for BuildCommand {
type Options = (); type Options = ();
type Output = (Compiler<Fq, EdwardsGroupType>, bool); type Output = Option<(Compiler<Fq, EdwardsGroupType>, bool)>;
const ABOUT: AboutType = "Compile the current package as a program"; const ABOUT: AboutType = "Compile the current package as a program";
const ARGUMENTS: &'static [ArgumentType] = &[]; const ARGUMENTS: &'static [ArgumentType] = &[];
@ -46,11 +46,19 @@ impl CLI for BuildCommand {
package_path.pop(); package_path.pop();
} }
// Verify the main file exists // Compile the package starting with the lib.leo file
if !MainFile::exists_at(&package_path) { if LibFile::exists_at(&package_path) {
return Err(BuildError::MainFileDoesNotExist(package_path.as_os_str().to_owned()).into()); // 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);
// Compile the library file but do not output
let _program = Compiler::<Fq, EdwardsGroupType>::new_from_path(package_name.clone(), lib_file_path)?;
};
// Compile the main.leo file along with constraints
if MainFile::exists_at(&package_path) {
// Create the outputs directory // Create the outputs directory
OutputsDirectory::create(&package_path)?; OutputsDirectory::create(&package_path)?;
@ -60,7 +68,8 @@ impl CLI for BuildCommand {
main_file_path.push(MAIN_FILE_NAME); main_file_path.push(MAIN_FILE_NAME);
// Load the program at `main_file_path` // Load the program at `main_file_path`
let program = Compiler::<Fq, EdwardsGroupType>::new_from_path(package_name.clone(), main_file_path.clone())?; let program =
Compiler::<Fq, EdwardsGroupType>::new_from_path(package_name.clone(), main_file_path.clone())?;
// Compute the current program checksum // Compute the current program checksum
let program_checksum = program.checksum()?; let program_checksum = program.checksum()?;
@ -98,6 +107,11 @@ impl CLI for BuildCommand {
log::info!("Compiled program in {:?}", main_file_path); log::info!("Compiled program in {:?}", main_file_path);
Ok((program, checksum_differs)) return Ok(Some((program, checksum_differs)));
}
// Return None when compiling a package for publishing
// The published package does not need to have a main.leo
Ok(None)
} }
} }

View File

@ -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 clap::ArgMatches;
use std::{convert::TryFrom, env::current_dir}; use std::{convert::TryFrom, env::current_dir};
@ -24,14 +31,26 @@ impl CLI for DeployCommand {
#[cfg_attr(tarpaulin, skip)] #[cfg_attr(tarpaulin, skip)]
fn output(options: Self::Options) -> Result<Self::Output, CLIError> { fn output(options: Self::Options) -> Result<Self::Output, CLIError> {
let (_program, _checksum_differs) = BuildCommand::output(options)?;
// Get the package name
let path = current_dir()?; let path = current_dir()?;
match BuildCommand::output(options)? {
Some((_program, _checksum_differs)) => {
// Get the package name
let _package_name = Manifest::try_from(&path)?.get_package_name(); let _package_name = Manifest::try_from(&path)?.get_package_name();
log::info!("Unimplemented - `leo deploy`"); log::info!("Unimplemented - `leo deploy`");
Ok(()) 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(),
)))
}
}
}
} }

View File

@ -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 clap::ArgMatches;
use std::{convert::TryFrom, env::current_dir}; use std::{convert::TryFrom, env::current_dir};
@ -24,14 +31,26 @@ impl CLI for LoadCommand {
#[cfg_attr(tarpaulin, skip)] #[cfg_attr(tarpaulin, skip)]
fn output(options: Self::Options) -> Result<Self::Output, CLIError> { fn output(options: Self::Options) -> Result<Self::Output, CLIError> {
let (_program, _checksum_differs) = BuildCommand::output(options)?;
// Get the package name
let path = current_dir()?; let path = current_dir()?;
match BuildCommand::output(options)? {
Some((_program, _checksum_differs)) => {
// Get the package name
let _package_name = Manifest::try_from(&path)?.get_package_name(); let _package_name = Manifest::try_from(&path)?.get_package_name();
log::info!("Unimplemented - `leo deploy`"); log::info!("Unimplemented - `leo load`");
Ok(()) 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(),
)))
}
}
}
} }

View File

@ -30,7 +30,9 @@ impl CLI for PublishCommand {
#[cfg_attr(tarpaulin, skip)] #[cfg_attr(tarpaulin, skip)]
fn output(options: Self::Options) -> Result<Self::Output, CLIError> { fn output(options: Self::Options) -> Result<Self::Output, CLIError> {
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 // Get the package name
let path = current_dir()?; let path = current_dir()?;

View File

@ -2,8 +2,9 @@ use crate::{
cli::*, cli::*,
cli_types::*, cli_types::*,
commands::BuildCommand, commands::BuildCommand,
errors::{CLIError, VerificationKeyFileError}, directories::SOURCE_DIRECTORY_NAME,
files::{Manifest, ProvingKeyFile, VerificationKeyFile}, errors::{CLIError, RunError, VerificationKeyFileError},
files::{Manifest, ProvingKeyFile, VerificationKeyFile, MAIN_FILE_NAME},
}; };
use leo_compiler::{compiler::Compiler, group::edwards_bls12::EdwardsGroupType}; use leo_compiler::{compiler::Compiler, group::edwards_bls12::EdwardsGroupType};
@ -40,12 +41,12 @@ impl CLI for SetupCommand {
#[cfg_attr(tarpaulin, skip)] #[cfg_attr(tarpaulin, skip)]
fn output(options: Self::Options) -> Result<Self::Output, CLIError> { fn output(options: Self::Options) -> Result<Self::Output, CLIError> {
let (program, checksum_differs) = BuildCommand::output(options)?;
// Get the package name // Get the package name
let path = current_dir()?; let path = current_dir()?;
let package_name = Manifest::try_from(&path)?.get_package_name(); let package_name = Manifest::try_from(&path)?.get_package_name();
match BuildCommand::output(options)? {
Some((program, checksum_differs)) => {
// Check if a proving key and verification key already exists // Check if a proving key and verification key already exists
let keys_exist = ProvingKeyFile::new(&package_name).exists_at(&path) let keys_exist = ProvingKeyFile::new(&package_name).exists_at(&path)
&& VerificationKeyFile::new(&package_name).exists_at(&path); && VerificationKeyFile::new(&package_name).exists_at(&path);
@ -102,4 +103,15 @@ impl CLI for SetupCommand {
Ok((program, parameters, prepared_verifying_key)) 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(),
)))
}
}
}
} }

View File

@ -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 clap::ArgMatches;
use std::{convert::TryFrom, env::current_dir}; use std::{convert::TryFrom, env::current_dir};
@ -24,14 +31,26 @@ impl CLI for UnloadCommand {
#[cfg_attr(tarpaulin, skip)] #[cfg_attr(tarpaulin, skip)]
fn output(options: Self::Options) -> Result<Self::Output, CLIError> { fn output(options: Self::Options) -> Result<Self::Output, CLIError> {
let (_program, _checksum_differs) = BuildCommand::output(options)?;
// Get the package name
let path = current_dir()?; let path = current_dir()?;
match BuildCommand::output(options)? {
Some((_program, _checksum_differs)) => {
// Get the package name
let _package_name = Manifest::try_from(&path)?.get_package_name(); let _package_name = Manifest::try_from(&path)?.get_package_name();
log::info!("Unimplemented - `leo deploy`"); log::info!("Unimplemented - `leo load`");
Ok(()) 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(),
)))
}
}
}
} }

19
leo/errors/files/lib.rs Normal file
View File

@ -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<std::io::Error> for LibFileError {
fn from(error: std::io::Error) -> Self {
LibFileError::Crate("std::io", format!("{}", error))
}
}

View File

@ -10,6 +10,9 @@ pub use self::gitignore::*;
pub mod inputs; pub mod inputs;
pub use self::inputs::*; pub use self::inputs::*;
pub mod lib;
pub use self::lib::*;
pub mod main; pub mod main;
pub use self::main::*; pub use self::main::*;

56
leo/files/lib.rs Normal file
View File

@ -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
)
}
}

View File

@ -10,6 +10,9 @@ pub use self::inputs::*;
pub mod gitignore; pub mod gitignore;
pub use self::gitignore::*; pub use self::gitignore::*;
pub mod lib;
pub use self::lib::*;
pub mod main; pub mod main;
pub use self::main::*; pub use self::main::*;

View File

@ -24,9 +24,9 @@ impl<'ast> From<AstImportSymbol<'ast>> for ImportSymbol {
impl fmt::Display for ImportSymbol { impl fmt::Display for ImportSymbol {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if self.alias.is_some() { 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 { } else {
write!(f, "\t{}", self.symbol) write!(f, "{}", self.symbol)
} }
} }
} }