Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Helpers: is_contract & is_parachain #105

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 1 addition & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ reqwest = { version = "0.11", optional = true }
serde_json = { version = "1.0", optional = true }
serde = { version = "1.0", features = ["derive"], optional = true }
symlink = { version = "0.1", optional = true }
toml_edit = { version = "0.22", optional = true }
toml_edit = { version = "0.22.9" }
tracing-subscriber = { version = "0.3", optional = true }
zombienet-sdk = { git = "https://github.com/r0gue-io/zombienet-sdk", branch = "pop", optional = true }
zombienet-support = { git = "https://github.com/r0gue-io/zombienet-sdk", branch = "pop", optional = true }
Expand Down Expand Up @@ -73,7 +73,6 @@ parachain = [
"dep:serde",
"dep:serde_json",
"dep:symlink",
"dep:toml_edit",
"dep:tracing-subscriber",
"dep:url",
"dep:zombienet-sdk",
Expand Down
5 changes: 2 additions & 3 deletions src/commands/build/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,11 @@ pub struct BuildContractCommand {
}

impl BuildContractCommand {
pub(crate) fn execute(&self) -> anyhow::Result<()> {
pub(crate) fn execute(self) -> anyhow::Result<()> {
clear_screen()?;
intro(format!("{}: Building a contract", style(" Pop CLI ").black().on_magenta()))?;
set_theme(Theme);

build_smart_contract(&self.path)?;
build_smart_contract(self.path)?;
outro("Build completed successfully!")?;
Ok(())
}
Expand Down
4 changes: 2 additions & 2 deletions src/commands/build/parachain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@ pub struct BuildParachainCommand {
}

impl BuildParachainCommand {
pub(crate) fn execute(&self) -> anyhow::Result<()> {
pub(crate) fn execute(self) -> anyhow::Result<()> {
clear_screen()?;
intro(format!("{}: Building a parachain", style(" Pop CLI ").black().on_magenta()))?;
set_theme(Theme);
build_parachain(&self.path)?;
build_parachain(self.path)?;

outro("Build Completed Successfully!")?;
Ok(())
Expand Down
14 changes: 6 additions & 8 deletions src/engines/contract_engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,16 @@ pub fn create_smart_contract(name: String, target: &Path) -> anyhow::Result<()>
}

/// Build a smart contract
pub fn build_smart_contract(path: &Option<PathBuf>) -> anyhow::Result<()> {
pub fn build_smart_contract(path: Option<PathBuf>) -> anyhow::Result<()> {
// If the user specifies a path (which is not the current directory), it will have to manually
// add a Cargo.toml file. If not provided, pop-cli will ask the user for a specific path. or ask
// to the user the specific path (Like cargo-contract does)
let manifest_path;
if path.is_some() {
let full_path: PathBuf =
PathBuf::from(path.as_ref().unwrap().to_string_lossy().to_string() + "/Cargo.toml");
manifest_path = ManifestPath::try_from(Some(full_path))?;
let manifest_path = if let Some(path) = path {
let full_path = path.join("/Cargo.toml");
ManifestPath::try_from(Some(full_path))?
} else {
manifest_path = ManifestPath::try_from(path.as_ref())?;
}
ManifestPath::try_from(path.as_ref())?
};

let args = ExecuteArgs {
manifest_path,
Expand Down
17 changes: 10 additions & 7 deletions src/engines/parachain_engine.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
use crate::{
commands::new::parachain::Template,
engines::generator::{ChainSpec, Network},
helpers::{clone_and_degit, sanitize, write_to_file},
helpers::{clone_and_degit, is_parachain, sanitize, write_to_file},
};
use anyhow::Result;
use anyhow::{bail, Result};
use duct::cmd;
use git2::Repository;
use std::{
env::current_dir,
fs,
path::{Path, PathBuf},
};
Expand Down Expand Up @@ -73,11 +74,13 @@ pub fn instantiate_base_template(target: &Path, config: Config) -> Result<Option
Ok(tag)
}

pub fn build_parachain(path: &Option<PathBuf>) -> anyhow::Result<()> {
cmd("cargo", vec!["build", "--release"])
.dir(path.clone().unwrap_or("./".into()))
.run()?;

pub fn build_parachain(path: Option<PathBuf>) -> anyhow::Result<()> {
let path = path.unwrap_or(current_dir()?);
if is_parachain(&path)? {
cmd("cargo", vec!["build", "--release"]).dir(path).run()?;
} else {
bail!("Build failed: Not a parachain project")
}
Ok(())
}

Expand Down
67 changes: 65 additions & 2 deletions src/helpers.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use anyhow::Result;
use anyhow::{Context, Result};
use cliclack::{log, outro_cancel};
use git2::{IndexAddOption, Repository, ResetType};
use regex::Regex;
Expand Down Expand Up @@ -119,7 +119,70 @@ pub(crate) fn resolve_pallet_path(path: Option<String>) -> PathBuf {
}
}
}

/// Checks if `path` is a ink contract project directory by searching its dependencies
pub(crate) fn is_contract(path: &Path) -> Result<bool> {
let mut confidence = 0;
let manifest_path = path.join("Cargo.toml");
if manifest_path.exists() {
let manifest =
fs::read_to_string(manifest_path).context("is_contract: Failed to read Cargo.toml")?;
let manifest: toml_edit::DocumentMut =
manifest.parse().context("is_contract: Cargo.toml is not well formed")?;
if let Some(deps) = manifest.get("dependencies") {
if let Some(dependencies) = deps.as_table() {
if dependencies.contains_key("ink") {
confidence += 5;
}
}
}
if let Some(dev_deps) = manifest.get("dev-dependencies") {
if let Some(dev_deps) = dev_deps.as_table() {
if dev_deps.contains_key("ink_e2e") {
confidence += 2;
}
}
}
}
Ok(if confidence >= 5 { true } else { false })
}
/// Checks if `path` is a substrate parachain project directory by searching its dependencies
pub(crate) fn is_parachain(path: &Path) -> Result<bool> {
// +2 for dir structure node/ runtime/
// +5 for substrate core dependencies such as `frame` or `substrate-wasm-builder`
// We choose a threshold of 5 meanining that just having dir structures doesn't count as parachain
// It must have at least one substrate dependency
let mut confidence = 0;
let workspace_manifest = path.join("Cargo.toml");
if workspace_manifest.exists() {
let workspace_manifest = fs::read_to_string(workspace_manifest)
.context("is_parachain: Failed to read Cargo.toml")?;
let workspace_manifest: toml_edit::DocumentMut = workspace_manifest
.parse()
.context("is_parachain: Cargo.toml is not well formed")?;
// workspace root checks
if let Some(workspace_root) = workspace_manifest.get("workspace") {
if let Some(deps) = workspace_root.get("dependencies") {
if let Some(deps) = deps.as_table() {
if deps.contains_key("substrate-wasm-builder") {
confidence += 5;
}
}
}
}
}
if path.join("node/Cargo.toml").exists() {
confidence += 2;
}
if path.join("pallets").exists() {
confidence += 2;
}
if path.join("runtime/Cargo.toml").exists() {
confidence += 1;
}
// We choose a threshold of 5 to determine if it is a parachain
// This is satisfied if one substrate-wasm-builder dependency is found
Ok(if confidence >= 5 { true } else { false })
}
#[cfg(test)]
mod tests {
use super::*;
Expand Down
2 changes: 1 addition & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ async fn main() -> Result<()> {
#[cfg(feature = "contract")]
commands::new::NewCommands::Contract(cmd) => cmd.execute(),
},
Commands::Build(args) => match &args.command {
Commands::Build(args) => match args.command {
#[cfg(feature = "parachain")]
commands::build::BuildCommands::Parachain(cmd) => cmd.execute(),
#[cfg(feature = "contract")]
Expand Down
14 changes: 7 additions & 7 deletions src/parachains/zombienet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use std::{
};
use symlink::{remove_symlink_file, symlink_file};
use tempfile::{Builder, NamedTempFile};
use toml_edit::{value, Document, Formatted, Item, Table, Value};
use toml_edit::{value, DocumentMut, Formatted, Item, Table, Value};
use url::Url;
use zombienet_sdk::{Network, NetworkConfig, NetworkConfigExt};
use zombienet_support::fs::local::LocalFileSystem;
Expand All @@ -27,7 +27,7 @@ pub struct Zombienet {
/// The cache location, used for caching binaries.
cache: PathBuf,
/// The config to be used to launch a network.
network_config: (PathBuf, Document),
network_config: (PathBuf, DocumentMut),
/// The binary required to launch the relay chain.
relay_chain: Binary,
/// The binaries required to launch parachains.
Expand All @@ -44,7 +44,7 @@ impl Zombienet {
) -> Result<Self> {
// Parse network config
let network_config_path = PathBuf::from(network_config);
let config = std::fs::read_to_string(&network_config_path)?.parse::<Document>()?;
let config = std::fs::read_to_string(&network_config_path)?.parse::<DocumentMut>()?;
// Determine binaries
let relay_chain_binary = Self::relay_chain(relay_chain_version, &config, &cache).await?;
let mut parachain_binaries = IndexMap::new();
Expand Down Expand Up @@ -258,7 +258,7 @@ impl Zombienet {

async fn relay_chain(
version: Option<&String>,
network_config: &Document,
network_config: &DocumentMut,
cache: &PathBuf,
) -> Result<Binary> {
const BINARY: &str = "polkadot";
Expand Down Expand Up @@ -610,7 +610,7 @@ mod tests {
let cache = PathBuf::from(temp_dir.path());

let network_config_path = PathBuf::from(CONFIG_FILE_PATH);
let config = std::fs::read_to_string(&network_config_path)?.parse::<Document>()?;
let config = std::fs::read_to_string(&network_config_path)?.parse::<DocumentMut>()?;

let binary_relay_chain =
Zombienet::relay_chain(Some(&TESTING_POLKADOT_VERSION.to_string()), &config, &cache)
Expand All @@ -635,7 +635,7 @@ mod tests {
let cache = PathBuf::from(temp_dir.path());

let network_config_path = PathBuf::from(CONFIG_FILE_PATH);
let config = std::fs::read_to_string(&network_config_path)?.parse::<Document>()?;
let config = std::fs::read_to_string(&network_config_path)?.parse::<DocumentMut>()?;

// Ideally here we will Mock GitHub struct and its get_latest_release function response
let binary_relay_chain = Zombienet::relay_chain(None, &config, &cache).await?;
Expand All @@ -659,7 +659,7 @@ mod tests {
let network_config_path = generate_wrong_config_no_relay(&temp_dir)
.expect("Error generating the testing toml file");

let config = std::fs::read_to_string(&network_config_path)?.parse::<Document>()?;
let config = std::fs::read_to_string(&network_config_path)?.parse::<DocumentMut>()?;

let result_error =
Zombienet::relay_chain(Some(&TESTING_POLKADOT_VERSION.to_string()), &config, &cache)
Expand Down
18 changes: 18 additions & 0 deletions tests/build_contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,3 +90,21 @@ fn test_contract_build_fails_if_no_contract_exists() -> Result<(), Error> {

Ok(())
}

#[test]
fn build_non_contract_project() {
let non_contract_dir = tempfile::tempdir().unwrap();
Command::cargo_bin("pop")
.unwrap()
.current_dir(&non_contract_dir)
.args(&["new", "parachain", "test_parachain"])
.assert()
.success();
// pop build contract
Command::cargo_bin("pop")
.unwrap()
.args(&["build", "contract"])
.assert()
.failure()
.stderr(predicate::str::contains("Error: No 'ink' dependency found"));
}
20 changes: 20 additions & 0 deletions tests/build_parachain.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#![cfg(feature = "e2e_parachain")]
use anyhow::{Error, Result};
use assert_cmd::Command;
use predicates::prelude::predicate;

fn setup_test_environment() -> Result<tempfile::TempDir, Error> {
let temp_dir = tempfile::tempdir().unwrap();
Expand Down Expand Up @@ -30,3 +31,22 @@ fn test_parachain_build_after_instantiating_template() -> Result<()> {
assert!(temp_dir.path().join("test_parachain/target").exists());
Ok(())
}

#[test]
fn build_non_parachain_project() {
let non_parachain = tempfile::tempdir().unwrap();
Command::cargo_bin("pop")
.unwrap()
.current_dir(&non_parachain)
.args(&["new", "contract", "non_parachain_rust_project"])
.assert()
.success();

Command::cargo_bin("pop")
.unwrap()
.current_dir(&non_parachain)
.args(&["build", "parachain"])
.assert()
.failure()
.stderr(predicate::str::contains("Build failed: Not a parachain project"));
}
Loading