Merge pull request #320 from AleoHQ/refactor/packages

Refactor file system operations into `leo-package`
This commit is contained in:
Howard Wu 2020-09-02 20:32:17 -07:00 committed by GitHub
commit b0c088d978
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 568 additions and 176 deletions

View File

@ -1,4 +1,4 @@
name: Leo Programs
name: Leo Release Tests
on:
pull_request:
push:
@ -9,7 +9,7 @@ env:
jobs:
new:
name: Hello Leo (from 'leo new')
name: Hello Leo ('leo new hello-world')
runs-on: ubuntu-latest
steps:
- name: Checkout
@ -39,16 +39,16 @@ jobs:
command: install
args: --path .
- name: 'leo new'
- name: 'leo new hello-world'
run: |
cd ..
leo new hello_world
leo new hello-world
ls -la
cd hello_world && ls -la
cd hello-world && ls -la
leo run
init:
name: Hello Leo (from 'leo init')
name: Hello Leo ('leo init')
runs-on: ubuntu-latest
steps:
- name: Checkout
@ -80,7 +80,7 @@ jobs:
- name: 'leo init'
run: |
cd .. && mkdir hello_world && cd hello_world
cd .. && mkdir hello-world && cd hello-world
leo init
ls -la
leo run

1
Cargo.lock generated
View File

@ -1326,6 +1326,7 @@ version = "1.0.2"
name = "leo-package"
version = "1.0.2"
dependencies = [
"lazy_static",
"serde",
"serde_json",
"thiserror",

View File

@ -25,7 +25,7 @@ use leo_package::{
inputs::*,
outputs::{ChecksumFile, CircuitFile, OutputsDirectory, OUTPUTS_DIRECTORY_NAME},
root::Manifest,
source::{LibFile, MainFile, LIB_FILE_NAME, MAIN_FILE_NAME, SOURCE_DIRECTORY_NAME},
source::{LibraryFile, MainFile, LIBRARY_FILENAME, MAIN_FILENAME, SOURCE_DIRECTORY_NAME},
};
use snarkos_curves::{bls12_377::Bls12_377, edwards_bls12::Fq};
@ -81,11 +81,11 @@ impl CLI for BuildCommand {
let start = Instant::now();
// Compile the package starting with the lib.leo file
if LibFile::exists_at(&package_path) {
if LibraryFile::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);
lib_file_path.push(LIBRARY_FILENAME);
// Log compilation of library file to console
tracing::info!("Compiling library... ({:?})", lib_file_path);
@ -107,7 +107,7 @@ impl CLI for BuildCommand {
// 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);
main_file_path.push(MAIN_FILENAME);
// Load the input file at `package_name.in`
let input_string = InputFile::new(&package_name).read_from(&path)?;

View File

@ -22,7 +22,7 @@ use crate::{
};
use leo_package::{
root::Manifest,
source::{MAIN_FILE_NAME, SOURCE_DIRECTORY_NAME},
source::{MAIN_FILENAME, SOURCE_DIRECTORY_NAME},
};
use clap::ArgMatches;
@ -67,7 +67,7 @@ impl CLI for DeployCommand {
None => {
let mut main_file_path = path.clone();
main_file_path.push(SOURCE_DIRECTORY_NAME);
main_file_path.push(MAIN_FILE_NAME);
main_file_path.push(MAIN_FILENAME);
Err(CLIError::RunError(RunError::MainFileDoesNotExist(
main_file_path.into_os_string(),

View File

@ -19,11 +19,7 @@ use crate::{
cli_types::*,
errors::{CLIError, InitError},
};
use leo_package::{
inputs::*,
root::{Gitignore, Manifest, README},
source::{LibFile, MainFile, SourceDirectory},
};
use leo_package::LeoPackage;
use clap::ArgMatches;
use std::env::current_dir;
@ -62,60 +58,12 @@ impl CLI for InitCommand {
.to_string_lossy()
.to_string();
// Verify the directory exists
// Verify the directory does not exist
if !path.exists() {
return Err(InitError::DirectoryDoesNotExist(path.as_os_str().to_owned()).into());
}
// Verify a manifest file does not already exist
if Manifest::exists_at(&path) {
return Err(InitError::PackageAlreadyExists(path.as_os_str().to_owned()).into());
}
// Create the manifest file
Manifest::new(&package_name).write_to(&path)?;
// Create the .gitignore file
Gitignore::new().write_to(&path)?;
// Create the README.md file
README::new(&package_name).write_to(&path)?;
// Create the source directory
SourceDirectory::create(&path)?;
// Create a new library or binary file
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 input directory
InputsDirectory::create(&path)?;
// Verify the input file does not exist
let input_file = InputFile::new(&package_name);
if !input_file.exists_at(&path) {
// Create the input file in the inputs directory
input_file.write_to(&path)?;
}
// Verify the state file does not exist
let state_file = StateFile::new(&package_name);
if !state_file.exists_at(&path) {
// Create the state file in the inputs directory
state_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)?;
}
}
LeoPackage::initialize(&package_name, options, &path)?;
tracing::info!("Successfully initialized package \"{}\"\n", package_name);

View File

@ -22,7 +22,7 @@ use crate::{
};
use leo_package::{
root::Manifest,
source::{MAIN_FILE_NAME, SOURCE_DIRECTORY_NAME},
source::{MAIN_FILENAME, SOURCE_DIRECTORY_NAME},
};
use clap::ArgMatches;
@ -67,7 +67,7 @@ impl CLI for LintCommand {
None => {
let mut main_file_path = path.clone();
main_file_path.push(SOURCE_DIRECTORY_NAME);
main_file_path.push(MAIN_FILE_NAME);
main_file_path.push(MAIN_FILENAME);
Err(CLIError::RunError(RunError::MainFileDoesNotExist(
main_file_path.into_os_string(),

View File

@ -19,11 +19,7 @@ use crate::{
cli_types::*,
errors::{CLIError, NewError},
};
use leo_package::{
inputs::*,
root::{Gitignore, Manifest, README},
source::{LibFile, MainFile, SourceDirectory},
};
use leo_package::LeoPackage;
use clap::ArgMatches;
use std::{env::current_dir, fs};
@ -89,35 +85,7 @@ impl CLI for NewCommand {
fs::create_dir_all(&path)
.map_err(|error| NewError::CreatingRootDirectory(path.as_os_str().to_owned(), error))?;
// Create the manifest file
Manifest::new(&package_name).write_to(&path)?;
// Create the .gitignore file
Gitignore::new().write_to(&path)?;
// Create the README.md file
README::new(&package_name).write_to(&path)?;
// Create the source directory
SourceDirectory::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 input directory
InputsDirectory::create(&path)?;
// Create the input file in the inputs directory
InputFile::new(&package_name).write_to(&path)?;
// Create the state file in the inputs directory
StateFile::new(&package_name).write_to(&path)?;
// Create the main file in the source directory
MainFile::new(&package_name).write_to(&path)?;
}
LeoPackage::initialize(&package_name, options.1, &path)?;
tracing::info!("Successfully initialized package \"{}\"\n", package_name);

View File

@ -22,7 +22,7 @@ use crate::{
};
use leo_package::{
root::Manifest,
source::{MAIN_FILE_NAME, SOURCE_DIRECTORY_NAME},
source::{MAIN_FILENAME, SOURCE_DIRECTORY_NAME},
};
use clap::ArgMatches;
@ -67,7 +67,7 @@ impl CLI for RemoveCommand {
None => {
let mut main_file_path = path.clone();
main_file_path.push(SOURCE_DIRECTORY_NAME);
main_file_path.push(MAIN_FILE_NAME);
main_file_path.push(MAIN_FILENAME);
Err(CLIError::RunError(RunError::MainFileDoesNotExist(
main_file_path.into_os_string(),

View File

@ -24,7 +24,7 @@ use leo_compiler::{compiler::Compiler, group::targets::edwards_bls12::EdwardsGro
use leo_package::{
outputs::{ProvingKeyFile, VerificationKeyFile},
root::Manifest,
source::{MAIN_FILE_NAME, SOURCE_DIRECTORY_NAME},
source::{MAIN_FILENAME, SOURCE_DIRECTORY_NAME},
};
use snarkos_algorithms::snark::groth16::{Groth16, Parameters, PreparedVerifyingKey, VerifyingKey};
@ -148,7 +148,7 @@ impl CLI for SetupCommand {
None => {
let mut main_file_path = path.clone();
main_file_path.push(SOURCE_DIRECTORY_NAME);
main_file_path.push(MAIN_FILE_NAME);
main_file_path.push(MAIN_FILENAME);
Err(CLIError::RunError(RunError::MainFileDoesNotExist(
main_file_path.into_os_string(),

View File

@ -24,7 +24,7 @@ use leo_package::{
inputs::*,
outputs::{OutputsDirectory, OUTPUTS_DIRECTORY_NAME},
root::Manifest,
source::{LibFile, MainFile, LIB_FILE_NAME, MAIN_FILE_NAME, SOURCE_DIRECTORY_NAME},
source::{LibraryFile, MainFile, LIBRARY_FILENAME, MAIN_FILENAME, SOURCE_DIRECTORY_NAME},
};
use snarkos_curves::edwards_bls12::Fq;
@ -70,9 +70,9 @@ impl CLI for TestCommand {
// Verify a main or library file exists
if MainFile::exists_at(&package_path) {
file_path.push(MAIN_FILE_NAME);
} else if LibFile::exists_at(&package_path) {
file_path.push(LIB_FILE_NAME);
file_path.push(MAIN_FILENAME);
} else if LibraryFile::exists_at(&package_path) {
file_path.push(LIBRARY_FILENAME);
} else {
return Err(ProgramFileDoesNotExist(package_path.into()).into());
}

View File

@ -54,7 +54,7 @@ pub enum CLIError {
InputFileError(InputFileError),
#[error("{}", _0)]
LibFileError(LibFileError),
LibraryFileError(LibraryFileError),
#[error("{}", _0)]
LoginError(LoginError),
@ -74,6 +74,9 @@ pub enum CLIError {
#[error("{}", _0)]
OutputsDirectoryError(OutputsDirectoryError),
#[error("{}", _0)]
PackageError(PackageError),
#[error("{}", _0)]
ProofFileError(ProofFileError),
@ -133,13 +136,14 @@ impl_cli_error!(
InitError,
InputsDirectoryError,
InputFileError,
LibFileError,
LibraryFileError,
LoginError,
MainFileError,
ManifestError,
NewError,
OutputFileError,
OutputsDirectoryError,
PackageError,
ProofFileError,
ProvingKeyFileError,
PublishError,
@ -162,14 +166,14 @@ impl From<clap::Error> for CLIError {
impl From<leo_compiler::errors::CompilerError> for CLIError {
fn from(error: leo_compiler::errors::CompilerError) -> Self {
tracing::error!("{}\n", error);
CLIError::Crate("leo_compiler", "Program failed due to previous error".into())
CLIError::Crate("leo-compiler", "Program failed due to previous error".into())
}
}
impl From<leo_input::errors::InputParserError> for CLIError {
fn from(error: leo_input::errors::InputParserError) -> Self {
tracing::error!("{}\n", error);
CLIError::Crate("leo_input", "Program failed due to previous error".into())
CLIError::Crate("leo-input", "Program failed due to previous error".into())
}
}

View File

@ -29,9 +29,6 @@ pub enum InitError {
#[error("{}", _0)]
ManifestError(#[from] ManifestError),
#[error("package at path {:?} already exists", _0)]
PackageAlreadyExists(OsString),
#[error("package name is missing - {:?}", _0)]
ProjectNameInvalid(OsString),
}

View File

@ -29,9 +29,6 @@ pub enum NewError {
#[error("{}", _0)]
ManifestError(#[from] ManifestError),
#[error("package at path {:?} already exists", _0)]
PackageAlreadyExists(OsString),
#[error("package name is missing - {:?}", _0)]
ProjectNameInvalid(OsString),
}

View File

@ -38,3 +38,6 @@ version = "2"
[dependencies.zip]
version = "0.5"
[dev-dependencies.lazy_static]
version = "1.3.0"

View File

@ -23,6 +23,9 @@ pub use inputs::*;
pub mod outputs;
pub use outputs::*;
pub mod package;
pub use self::package::*;
pub mod root;
pub use self::root::*;

View File

@ -0,0 +1,88 @@
use std::{ffi::OsString, io};
#[derive(Debug, Error)]
pub enum PackageError {
#[error("{}: {}", _0, _1)]
Crate(&'static str, String),
#[error("`{}` creating: {}", _0, _1)]
Creating(&'static str, io::Error),
#[error("Failed to initialize package {:?} ({:?})", _0, _1)]
FailedToInitialize(String, OsString),
#[error("`{}` metadata: {}", _0, _1)]
Removing(&'static str, io::Error),
}
impl From<std::io::Error> for PackageError {
fn from(error: std::io::Error) -> Self {
PackageError::Crate("std::io", format!("{}", error))
}
}
impl From<crate::errors::GitignoreError> for PackageError {
fn from(error: crate::errors::GitignoreError) -> Self {
PackageError::Crate("leo-package", format!("{}", error))
}
}
impl From<crate::errors::InputFileError> for PackageError {
fn from(error: crate::errors::InputFileError) -> Self {
PackageError::Crate("leo-package", format!("{}", error))
}
}
impl From<crate::errors::InputsDirectoryError> for PackageError {
fn from(error: crate::errors::InputsDirectoryError) -> Self {
PackageError::Crate("leo-package", format!("{}", error))
}
}
impl From<crate::errors::ImportsDirectoryError> for PackageError {
fn from(error: crate::errors::ImportsDirectoryError) -> Self {
PackageError::Crate("leo-package", format!("{}", error))
}
}
impl From<crate::errors::OutputsDirectoryError> for PackageError {
fn from(error: crate::errors::OutputsDirectoryError) -> Self {
PackageError::Crate("leo-package", format!("{}", error))
}
}
impl From<crate::errors::READMEError> for PackageError {
fn from(error: crate::errors::READMEError) -> Self {
PackageError::Crate("leo-package", format!("{}", error))
}
}
impl From<crate::errors::SourceDirectoryError> for PackageError {
fn from(error: crate::errors::SourceDirectoryError) -> Self {
PackageError::Crate("leo-package", format!("{}", error))
}
}
impl From<crate::errors::StateFileError> for PackageError {
fn from(error: crate::errors::StateFileError) -> Self {
PackageError::Crate("leo-package", format!("{}", error))
}
}
impl From<crate::errors::LibraryFileError> for PackageError {
fn from(error: crate::errors::LibraryFileError) -> Self {
PackageError::Crate("leo-package", format!("{}", error))
}
}
impl From<crate::errors::ManifestError> for PackageError {
fn from(error: crate::errors::ManifestError) -> Self {
PackageError::Crate("leo-package", format!("{}", error))
}
}
impl From<crate::errors::MainFileError> for PackageError {
fn from(error: crate::errors::MainFileError) -> Self {
PackageError::Crate("leo-package", format!("{}", error))
}
}

View File

@ -17,7 +17,7 @@
use std::io;
#[derive(Debug, Error)]
pub enum LibFileError {
pub enum LibraryFileError {
#[error("{}: {}", _0, _1)]
Crate(&'static str, String),
@ -28,8 +28,8 @@ pub enum LibFileError {
Writing(io::Error),
}
impl From<std::io::Error> for LibFileError {
impl From<std::io::Error> for LibraryFileError {
fn from(error: std::io::Error) -> Self {
LibFileError::Crate("std::io", format!("{}", error))
LibraryFileError::Crate("std::io", format!("{}", error))
}
}

View File

@ -39,6 +39,10 @@ impl InputFile {
}
}
pub fn filename(&self) -> String {
format!("{}{}{}", INPUTS_DIRECTORY_NAME, self.package_name, INPUT_FILE_EXTENSION)
}
pub fn exists_at(&self, path: &PathBuf) -> bool {
let path = self.setup_file_path(path);
path.exists()

View File

@ -39,6 +39,10 @@ impl StateFile {
}
}
pub fn filename(&self) -> String {
format!("{}{}{}", INPUTS_DIRECTORY_NAME, self.package_name, STATE_FILE_EXTENSION)
}
pub fn exists_at(&self, path: &PathBuf) -> bool {
let path = self.setup_file_path(path);
path.exists()

View File

@ -23,5 +23,17 @@ pub use errors::*;
pub mod imports;
pub mod inputs;
pub mod outputs;
pub mod package;
pub mod root;
pub mod source;
use std::path::PathBuf;
pub struct LeoPackage;
impl LeoPackage {
/// Initializes a Leo package at the given path.
pub fn initialize(package_name: &str, is_lib: bool, path: &PathBuf) -> Result<(), PackageError> {
package::Package::initialize(package_name, is_lib, path)
}
}

173
package/src/package.rs Normal file
View File

@ -0,0 +1,173 @@
use crate::{
errors::PackageError,
inputs::{InputFile, InputsDirectory, StateFile},
root::{Gitignore, Manifest, README},
source::{LibraryFile, MainFile, SourceDirectory},
};
use serde::Deserialize;
use std::path::PathBuf;
#[derive(Deserialize)]
pub struct Package {
pub name: String,
pub version: String,
pub description: Option<String>,
pub license: Option<String>,
}
impl Package {
pub fn new(package_name: &str) -> Self {
Self {
name: package_name.to_owned(),
version: "0.1.0".to_owned(),
description: None,
license: None,
}
}
/// Returns `true` if a package is can be initialized at a given path.
pub fn can_initialize(package_name: &str, is_lib: bool, path: &PathBuf) -> bool {
let mut result = true;
let mut existing_files = vec![];
// Check if the manifest file already exists.
if Manifest::exists_at(&path) {
existing_files.push(Manifest::filename());
result = false;
}
if is_lib {
// Check if the library file already exists.
if LibraryFile::exists_at(&path) {
existing_files.push(LibraryFile::filename());
result = false;
}
} else {
// Check if the input file already exists.
let input_file = InputFile::new(&package_name);
if input_file.exists_at(&path) {
existing_files.push(input_file.filename());
result = false;
}
// Check if the state file already exists.
let state_file = StateFile::new(&package_name);
if state_file.exists_at(&path) {
existing_files.push(state_file.filename());
result = false;
}
// Check if the main file already exists.
if MainFile::exists_at(&path) {
existing_files.push(MainFile::filename());
result = false;
}
}
if existing_files.len() > 0 {
tracing::error!("File(s) {:?} already exist", existing_files);
}
return result;
}
/// Returns `true` if a package is initialized at the given path
pub fn is_initialized(package_name: &str, is_lib: bool, path: &PathBuf) -> bool {
// Check if the manifest file exists.
if !Manifest::exists_at(&path) {
return false;
}
if is_lib {
// Check if the library file exists.
if !LibraryFile::exists_at(&path) {
return false;
}
} else {
// Check if the input file exists.
let input_file = InputFile::new(&package_name);
if !input_file.exists_at(&path) {
return false;
}
// Check if the state file exists.
let state_file = StateFile::new(&package_name);
if !state_file.exists_at(&path) {
return false;
}
// Check if the main file exists.
if !MainFile::exists_at(&path) {
return false;
}
}
return true;
}
/// Creates a package at the given path
pub fn initialize(package_name: &str, is_lib: bool, path: &PathBuf) -> Result<(), PackageError> {
// First, verify that this directory is not already initialized as a Leo package.
{
if !Self::can_initialize(package_name, is_lib, path) {
return Err(
PackageError::FailedToInitialize(package_name.to_owned(), path.as_os_str().to_owned()).into(),
);
}
}
// Next, initialize this directory as a Leo package.
{
// Create the manifest file.
Manifest::new(&package_name).write_to(&path)?;
// Verify that the .gitignore file does not exist.
if !Gitignore::exists_at(&path) {
// Create the .gitignore file.
Gitignore::new().write_to(&path)?;
}
// Verify that the README.md file does not exist.
if !README::exists_at(&path) {
// Create the README.md file.
README::new(package_name).write_to(&path)?;
}
// Create the source directory.
SourceDirectory::create(&path)?;
// Create a new library or binary file.
if is_lib {
// Create the library file in the source directory.
LibraryFile::new(&package_name).write_to(&path)?;
} else {
// Create the input directory.
InputsDirectory::create(&path)?;
// Create the input file in the inputs directory.
InputFile::new(&package_name).write_to(&path)?;
// Create the state file in the inputs directory.
StateFile::new(&package_name).write_to(&path)?;
// Create the main file in the source directory.
MainFile::new(&package_name).write_to(&path)?;
}
}
// Next, verify that a valid Leo package has been initialized in this directory
{
if !Self::is_initialized(package_name, is_lib, path) {
return Err(
PackageError::FailedToInitialize(package_name.to_owned(), path.as_os_str().to_owned()).into(),
);
}
}
Ok(())
}
/// Removes the package at the given path
pub fn remove_package(_package_name: &str) -> Result<(), PackageError> {
unimplemented!()
}
}

View File

@ -21,7 +21,7 @@ use crate::errors::GitignoreError;
use serde::Deserialize;
use std::{fs::File, io::Write, path::PathBuf};
pub static GITIGNORE_FILE_NAME: &str = ".gitignore";
pub static GITIGNORE_FILENAME: &str = ".gitignore";
#[derive(Deserialize)]
pub struct Gitignore;
@ -34,7 +34,7 @@ impl Gitignore {
pub fn exists_at(path: &PathBuf) -> bool {
let mut path = path.to_owned();
if path.is_dir() {
path.push(PathBuf::from(GITIGNORE_FILE_NAME));
path.push(PathBuf::from(GITIGNORE_FILENAME));
}
path.exists()
}
@ -42,7 +42,7 @@ impl Gitignore {
pub fn write_to(self, path: &PathBuf) -> Result<(), GitignoreError> {
let mut path = path.to_owned();
if path.is_dir() {
path.push(PathBuf::from(GITIGNORE_FILE_NAME));
path.push(PathBuf::from(GITIGNORE_FILENAME));
}
let mut file = File::create(&path)?;

View File

@ -14,7 +14,7 @@
// You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use crate::errors::ManifestError;
use crate::{errors::ManifestError, package::Package};
use serde::Deserialize;
use std::{
@ -24,44 +24,35 @@ use std::{
path::PathBuf,
};
pub const MANIFEST_FILE_NAME: &str = "Leo.toml";
pub const MANIFEST_FILENAME: &str = "Leo.toml";
#[derive(Clone, Deserialize)]
pub struct Remote {
pub author: String,
}
#[derive(Deserialize)]
pub struct Package {
pub name: String,
pub version: String,
pub description: Option<String>,
pub license: Option<String>,
pub remote: Option<Remote>,
}
#[derive(Deserialize)]
pub struct Manifest {
pub package: Package,
pub remote: Option<Remote>,
}
impl Manifest {
pub fn new(package_name: &str) -> Self {
Self {
package: Package {
name: package_name.to_owned(),
version: "0.1.0".to_owned(),
description: None,
license: None,
remote: None,
},
package: Package::new(package_name),
remote: None,
}
}
pub fn filename() -> String {
MANIFEST_FILENAME.to_string()
}
pub fn exists_at(path: &PathBuf) -> bool {
let mut path = path.to_owned();
if path.is_dir() {
path.push(PathBuf::from(MANIFEST_FILE_NAME));
path.push(PathBuf::from(MANIFEST_FILENAME));
}
path.exists()
}
@ -83,18 +74,18 @@ impl Manifest {
}
pub fn get_package_remote(&self) -> Option<Remote> {
self.package.remote.clone()
self.remote.clone()
}
pub fn write_to(self, path: &PathBuf) -> Result<(), ManifestError> {
let mut path = path.to_owned();
if path.is_dir() {
path.push(PathBuf::from(MANIFEST_FILE_NAME));
path.push(PathBuf::from(MANIFEST_FILENAME));
}
let mut file = File::create(&path).map_err(|error| ManifestError::Creating(MANIFEST_FILE_NAME, error))?;
let mut file = File::create(&path).map_err(|error| ManifestError::Creating(MANIFEST_FILENAME, error))?;
file.write_all(self.template().as_bytes())
.map_err(|error| ManifestError::Writing(MANIFEST_FILE_NAME, error))
.map_err(|error| ManifestError::Writing(MANIFEST_FILENAME, error))
}
fn template(&self) -> String {
@ -119,18 +110,18 @@ impl TryFrom<&PathBuf> for Manifest {
fn try_from(path: &PathBuf) -> Result<Self, Self::Error> {
let mut path = path.to_owned();
if path.is_dir() {
path.push(PathBuf::from(MANIFEST_FILE_NAME));
path.push(PathBuf::from(MANIFEST_FILENAME));
}
let mut file = File::open(path.clone()).map_err(|error| ManifestError::Opening(MANIFEST_FILE_NAME, error))?;
let mut file = File::open(path.clone()).map_err(|error| ManifestError::Opening(MANIFEST_FILENAME, error))?;
let size = file
.metadata()
.map_err(|error| ManifestError::Metadata(MANIFEST_FILE_NAME, error))?
.map_err(|error| ManifestError::Metadata(MANIFEST_FILENAME, error))?
.len() as usize;
let mut buffer = String::with_capacity(size);
file.read_to_string(&mut buffer)
.map_err(|error| ManifestError::Reading(MANIFEST_FILE_NAME, error))?;
.map_err(|error| ManifestError::Reading(MANIFEST_FILENAME, error))?;
// Determine if the old remote format is being used, and update to new convention
@ -185,12 +176,12 @@ author = "{author}"
// Rewrite the toml file if it has been updated
if buffer != new_toml {
let mut file = File::create(&path).map_err(|error| ManifestError::Creating(MANIFEST_FILE_NAME, error))?;
let mut file = File::create(&path).map_err(|error| ManifestError::Creating(MANIFEST_FILENAME, error))?;
file.write_all(new_toml.as_bytes())
.map_err(|error| ManifestError::Writing(MANIFEST_FILE_NAME, error))?;
.map_err(|error| ManifestError::Writing(MANIFEST_FILENAME, error))?;
}
// Read the toml file
Ok(toml::from_str(&new_toml).map_err(|error| ManifestError::Parsing(MANIFEST_FILE_NAME, error))?)
Ok(toml::from_str(&new_toml).map_err(|error| ManifestError::Parsing(MANIFEST_FILENAME, error))?)
}
}

View File

@ -21,7 +21,7 @@ use crate::errors::READMEError;
use serde::Deserialize;
use std::{fs::File, io::Write, path::PathBuf};
pub static README_FILE_NAME: &str = "README.md";
pub static README_FILENAME: &str = "README.md";
#[derive(Deserialize)]
pub struct README {
@ -42,7 +42,7 @@ impl README {
pub fn exists_at(path: &PathBuf) -> bool {
let mut path = path.to_owned();
if path.is_dir() {
path.push(PathBuf::from(README_FILE_NAME));
path.push(PathBuf::from(README_FILENAME));
}
path.exists()
}
@ -50,7 +50,7 @@ impl README {
pub fn write_to(self, path: &PathBuf) -> Result<(), READMEError> {
let mut path = path.to_owned();
if path.is_dir() {
path.push(PathBuf::from(README_FILE_NAME));
path.push(PathBuf::from(README_FILENAME));
}
let mut file = File::create(&path)?;

View File

@ -28,7 +28,7 @@ use crate::{
PROVING_KEY_FILE_EXTENSION,
VERIFICATION_KEY_FILE_EXTENSION,
},
root::{MANIFEST_FILE_NAME, README_FILE_NAME},
root::{MANIFEST_FILENAME, README_FILENAME},
source::{SOURCE_DIRECTORY_NAME, SOURCE_FILE_EXTENSION},
};
@ -172,8 +172,7 @@ fn is_included(path: &Path) -> bool {
}
// Allow the README.md and Leo.toml files in the root directory
if (path.ends_with(README_FILE_NAME) | path.ends_with(MANIFEST_FILE_NAME)) & (path.parent() == Some(Path::new("")))
{
if (path.ends_with(README_FILENAME) | path.ends_with(MANIFEST_FILENAME)) & (path.parent() == Some(Path::new(""))) {
return true;
}

View File

@ -16,43 +16,47 @@
//! The `lib.leo` file.
use crate::{errors::LibFileError, source::directory::SOURCE_DIRECTORY_NAME};
use crate::{errors::LibraryFileError, source::directory::SOURCE_DIRECTORY_NAME};
use serde::Deserialize;
use std::{fs::File, io::Write, path::PathBuf};
pub static LIB_FILE_NAME: &str = "lib.leo";
pub static LIBRARY_FILENAME: &str = "lib.leo";
#[derive(Deserialize)]
pub struct LibFile {
pub struct LibraryFile {
pub package_name: String,
}
impl LibFile {
impl LibraryFile {
pub fn new(package_name: &str) -> Self {
Self {
package_name: package_name.to_string(),
}
}
pub fn filename() -> String {
format!("{}{}", SOURCE_DIRECTORY_NAME, LIBRARY_FILENAME)
}
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.push(PathBuf::from(LIBRARY_FILENAME));
}
path.exists()
}
pub fn write_to(self, path: &PathBuf) -> Result<(), LibFileError> {
pub fn write_to(self, path: &PathBuf) -> Result<(), LibraryFileError> {
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.push(PathBuf::from(LIBRARY_FILENAME));
}
let mut file = File::create(&path)?;

View File

@ -21,7 +21,7 @@ use crate::{errors::MainFileError, source::directory::SOURCE_DIRECTORY_NAME};
use serde::Deserialize;
use std::{fs::File, io::Write, path::PathBuf};
pub static MAIN_FILE_NAME: &str = "main.leo";
pub static MAIN_FILENAME: &str = "main.leo";
#[derive(Deserialize)]
pub struct MainFile {
@ -35,13 +35,17 @@ impl MainFile {
}
}
pub fn filename() -> String {
format!("{}{}", SOURCE_DIRECTORY_NAME, MAIN_FILENAME)
}
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(MAIN_FILE_NAME));
path.push(PathBuf::from(MAIN_FILENAME));
}
path.exists()
}
@ -52,7 +56,7 @@ impl MainFile {
if !path.ends_with(SOURCE_DIRECTORY_NAME) {
path.push(PathBuf::from(SOURCE_DIRECTORY_NAME));
}
path.push(PathBuf::from(MAIN_FILE_NAME));
path.push(PathBuf::from(MAIN_FILENAME));
}
let mut file = File::create(&path)?;

View File

@ -17,8 +17,8 @@
pub mod directory;
pub use directory::*;
pub mod lib;
pub use lib::*;
pub mod library;
pub use library::*;
pub mod main;
pub use main::*;

192
package/tests/initialize.rs Normal file
View File

@ -0,0 +1,192 @@
// Copyright (C) 2019-2020 Aleo Systems Inc.
// This file is part of the Leo library.
// The Leo library is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// The Leo library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use lazy_static::lazy_static;
use std::{
cell::RefCell,
env,
fs,
path::PathBuf,
sync::atomic::{AtomicUsize, Ordering},
};
const PACKAGE_TEST_DIRECTORY: &str = "package-testing";
thread_local! {
/// Establish a test id for each test.
static TEST_ID: RefCell<Option<usize>> = RefCell::new(None);
}
lazy_static! {
/// Create a testing directory for packages in `target/`
static ref TEST_DIR: PathBuf = {
let mut path = env::current_exe().unwrap();
path.pop(); // Remove executable name
path.pop(); // Remove 'debug'
// Attempt to point at the `target` directory
if path.file_name().and_then(|s| s.to_str()) != Some("target") {
path.pop();
}
path.push(PACKAGE_TEST_DIRECTORY);
fs::create_dir_all(&path).unwrap();
path
};
}
/// Create a new directory for each test based on the ID of the test.
fn test_dir() -> PathBuf {
static NEXT_ID: AtomicUsize = AtomicUsize::new(0);
let id = NEXT_ID.fetch_add(1, Ordering::Relaxed);
TEST_ID.with(|n| *n.borrow_mut() = Some(id));
let path: PathBuf = TEST_DIR.join(&format!("t{}", id)).into();
if path.exists() {
if let Err(e) = fs::remove_dir_all(&path) {
panic!("failed to remove {:?}: {:?}", &path, e)
}
}
fs::create_dir_all(&path).unwrap();
path
}
// Tests for package initialization
mod initialize_package {
use super::*;
use leo_package::{
inputs::{InputFile, InputsDirectory, StateFile},
package::Package,
root::Manifest,
source::{LibraryFile, MainFile, SourceDirectory},
};
const TEST_PACKAGE_NAME: &str = "test-package";
#[test]
fn initialize_valid_package() {
let test_directory = test_dir();
// Ensure a package can be initialized at the `test_directory`
assert!(Package::can_initialize(TEST_PACKAGE_NAME, false, &test_directory));
// Initialize a package at the `test_directory`
assert!(Package::initialize(TEST_PACKAGE_NAME, false, &test_directory).is_ok());
// Ensure a package is initialized at the `test_directory`
assert!(Package::is_initialized(TEST_PACKAGE_NAME, false, &test_directory));
}
#[test]
#[ignore]
fn initialize_fails_with_invalid_package_names() {
unimplemented!()
}
#[test]
fn initialize_fails_with_existing_manifest() {
let test_directory = test_dir();
// Ensure a package can be initialized at the `test_directory`
assert!(Package::can_initialize(TEST_PACKAGE_NAME, false, &test_directory));
// Manually add a manifest file to the `test_directory`
Manifest::new(TEST_PACKAGE_NAME).write_to(&test_directory).unwrap();
// Attempt to initialize a package at the `test_directory`
assert!(Package::initialize(TEST_PACKAGE_NAME, false, &test_directory).is_err());
// Ensure package is not initialized at the `test_directory`
assert!(!Package::is_initialized(TEST_PACKAGE_NAME, false, &test_directory));
}
#[test]
fn initialize_fails_with_existing_library_file() {
let test_directory = test_dir();
// Ensure a package can be initialized at the `test_directory`
assert!(Package::can_initialize(TEST_PACKAGE_NAME, true, &test_directory));
// Manually add a source directory and a library file to the `test_directory`
SourceDirectory::create(&test_directory).unwrap();
LibraryFile::new(TEST_PACKAGE_NAME).write_to(&test_directory).unwrap();
// Attempt to initialize a package at the `test_directory`
assert!(Package::initialize(TEST_PACKAGE_NAME, true, &test_directory).is_err());
// Ensure package is not initialized at the `test_directory`
assert!(!Package::is_initialized(TEST_PACKAGE_NAME, true, &test_directory));
}
#[test]
fn initialize_fails_with_existing_input_file() {
let test_directory = test_dir();
// Ensure a package can be initialized at the `test_directory`
assert!(Package::can_initialize(TEST_PACKAGE_NAME, false, &test_directory));
// Manually add an inputs directory and an input file to the `test_directory`
InputsDirectory::create(&test_directory).unwrap();
InputFile::new(TEST_PACKAGE_NAME).write_to(&test_directory).unwrap();
// Attempt to initialize a package at the `test_directory`
assert!(Package::initialize(TEST_PACKAGE_NAME, false, &test_directory).is_err());
// Ensure package is not initialized at the `test_directory`
assert!(!Package::is_initialized(TEST_PACKAGE_NAME, false, &test_directory));
}
#[test]
fn initialize_fails_with_existing_state_file() {
let test_directory = test_dir();
// Ensure a package can be initialized at the `test_directory`
assert!(Package::can_initialize(TEST_PACKAGE_NAME, false, &test_directory));
// Manually add an inputs directory and a state file to the `test_directory`
InputsDirectory::create(&test_directory).unwrap();
StateFile::new(TEST_PACKAGE_NAME).write_to(&test_directory).unwrap();
// Attempt to initialize a package at the `test_directory`
assert!(Package::initialize(TEST_PACKAGE_NAME, false, &test_directory).is_err());
// Ensure package is not initialized at the `test_directory`
assert!(!Package::is_initialized(TEST_PACKAGE_NAME, false, &test_directory));
}
#[test]
fn initialize_fails_with_existing_main_file() {
let test_directory = test_dir();
// Ensure a package can be initialized at the `test_directory`
assert!(Package::can_initialize(TEST_PACKAGE_NAME, false, &test_directory));
// Manually add a source directory and a main file to the `test_directory`
SourceDirectory::create(&test_directory).unwrap();
MainFile::new(TEST_PACKAGE_NAME).write_to(&test_directory).unwrap();
// Attempt to initialize a package at the `test_directory`
assert!(Package::initialize(TEST_PACKAGE_NAME, false, &test_directory).is_err());
// Ensure package is not initialized at the `test_directory`
assert!(!Package::is_initialized(TEST_PACKAGE_NAME, false, &test_directory));
}
}