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

Added check to forc_abi to fail on non-contracts #1105

Merged
merged 30 commits into from
Apr 4, 2022
Merged
Show file tree
Hide file tree
Changes from 29 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
de7977a
Produce an error rather than panicking on unsupported dependency type
mitchmindtree Mar 12, 2022
ae7f76f
Merge branch 'mitchmindtree/semver-dep-error' of github.com:FuelLabs/…
eureka-cpu Mar 12, 2022
49cca46
Merge branch 'master' of github.com:FuelLabs/sway
eureka-cpu Mar 12, 2022
2a85f9e
Merge branch 'master' of github.com:FuelLabs/sway
eureka-cpu Mar 14, 2022
839f2c2
Merge branch 'master' of github.com:FuelLabs/sway
eureka-cpu Mar 14, 2022
5a79849
Merge branch 'master' of github.com:FuelLabs/sway
eureka-cpu Mar 16, 2022
934debe
Merge branch 'master' of github.com:FuelLabs/sway
eureka-cpu Mar 18, 2022
c1f2001
Merge branch 'master' of github.com:FuelLabs/sway
eureka-cpu Mar 25, 2022
ba4c8b1
Merge branch 'master' of github.com:FuelLabs/sway
eureka-cpu Mar 28, 2022
c6a1163
Merge branch 'master' of github.com:FuelLabs/sway
eureka-cpu Mar 28, 2022
c18a6f2
Merge branch 'master' of github.com:FuelLabs/sway
eureka-cpu Mar 29, 2022
635f2b2
wip check forc non-contracts in forc abi
eureka-cpu Mar 30, 2022
cd5559b
small fixes
eureka-cpu Mar 30, 2022
168e850
fixed fmt display for CliError & fixed test in harness
eureka-cpu Mar 30, 2022
49223e7
cleared instances of CliError in favor of anyhow
eureka-cpu Mar 30, 2022
4f71308
mod test for json abi result now gives the actual error message
eureka-cpu Mar 31, 2022
96c8cbe
separated projects with abi
eureka-cpu Mar 31, 2022
41733c1
resolved conflict
eureka-cpu Mar 31, 2022
9d6e741
reduce dup code
eureka-cpu Mar 31, 2022
10a41a4
rmv oracle files from scripts
eureka-cpu Apr 1, 2022
f992293
fix some docstrings
eureka-cpu Apr 1, 2022
8a2a199
changed cli_error function name & condensed std use statement
eureka-cpu Apr 1, 2022
6c5b0ea
updated function names, added is_ok
eureka-cpu Apr 1, 2022
c4cbd3a
mvd functions into forc-pkg::pkg to avoid circular dep, updated funct…
eureka-cpu Apr 2, 2022
81f6f7a
replaced Err with bail
eureka-cpu Apr 2, 2022
5dc6f4e
removed implicit manifest return
eureka-cpu Apr 2, 2022
bbfd123
changed manifest var to self
eureka-cpu Apr 2, 2022
b3c1a6f
removed whitespace at the end of forc-abi-json
eureka-cpu Apr 2, 2022
bb35cc0
fmt
eureka-cpu Apr 2, 2022
2572b9f
merge conflict
eureka-cpu Apr 4, 2022
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
24 changes: 19 additions & 5 deletions forc-pkg/src/manifest.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
use anyhow::{anyhow, bail};
use crate::pkg::parsing_failed;
use anyhow::{anyhow, bail, Result};
use forc_util::{println_yellow_err, validate_name};
use serde::{Deserialize, Serialize};
use std::{
collections::BTreeMap,
path::{Path, PathBuf},
sync::Arc,
};

use sway_core::{parse, TreeType};
use sway_utils::constants;

#[derive(Serialize, Deserialize, Debug)]
Expand Down Expand Up @@ -75,7 +78,7 @@ impl Manifest {
///
/// This also `validate`s the manifest, returning an `Err` in the case that invalid names,
/// fields were used.
pub fn from_file(path: &Path) -> anyhow::Result<Self> {
pub fn from_file(path: &Path) -> Result<Self> {
let manifest_str = std::fs::read_to_string(path)
.map_err(|e| anyhow!("failed to read manifest at {:?}: {}", path, e))?;
let toml_de = &mut toml::de::Deserializer::new(&manifest_str);
Expand All @@ -92,7 +95,7 @@ impl Manifest {
///
/// This is short for `Manifest::from_file`, but takes care of constructing the path to the
/// file.
pub fn from_dir(manifest_dir: &Path) -> anyhow::Result<Self> {
pub fn from_dir(manifest_dir: &Path) -> Result<Self> {
let file_path = manifest_dir.join(constants::MANIFEST_FILE_NAME);
Self::from_file(&file_path)
}
Expand All @@ -101,7 +104,7 @@ impl Manifest {
///
/// This checks the project and organization names against a set of reserved/restricted
/// keywords and patterns, and if a given entry point exists.
pub fn validate(&self, path: &Path) -> anyhow::Result<()> {
pub fn validate(&self, path: &Path) -> Result<()> {
let mut entry_path = path.to_path_buf();
entry_path.pop();
let entry_path = entry_path
Expand Down Expand Up @@ -129,7 +132,7 @@ impl Manifest {
}

/// Produces the string of the entry point file.
pub fn entry_string(&self, manifest_dir: &Path) -> anyhow::Result<Arc<str>> {
pub fn entry_string(&self, manifest_dir: &Path) -> Result<Arc<str>> {
let entry_path = self.entry_path(manifest_dir);
let entry_string = std::fs::read_to_string(&entry_path)?;
Ok(Arc::from(entry_string))
Expand All @@ -150,6 +153,17 @@ impl Manifest {
Dependency::Simple(_) => None,
})
}

/// Parse and return the associated project's program type.
pub fn program_type(&self, manifest_dir: PathBuf) -> Result<TreeType> {
let entry_string = self.entry_string(&manifest_dir)?;
let program_type = parse(entry_string, None);

match program_type.value {
Some(parse_tree) => Ok(parse_tree.tree_type),
None => bail!(parsing_failed(&self.project.name, program_type.errors)),
}
eureka-cpu marked this conversation as resolved.
Show resolved Hide resolved
}
}

fn default_entry() -> String {
Expand Down
62 changes: 60 additions & 2 deletions forc-pkg/src/pkg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use crate::{
lock::Lock,
manifest::{Dependency, Manifest},
};
use anyhow::{anyhow, bail, Context, Result};
use anyhow::{anyhow, bail, Context, Error, Result};
use forc_util::{
find_file_name, git_checkouts_directory, kebab_to_snake_case, print_on_failure,
print_on_success, print_on_success_library, println_yellow_err,
Expand All @@ -16,7 +16,7 @@ use std::{
str::FromStr,
};
use sway_core::{
source_map::SourceMap, BytecodeCompilationResult, CompileAstResult, NamespaceRef,
source_map::SourceMap, BytecodeCompilationResult, CompileAstResult, CompileError, NamespaceRef,
NamespaceWrapper, TreeType, TypedParseTree,
};
use sway_types::JsonABI;
Expand Down Expand Up @@ -1171,3 +1171,61 @@ fn test_source_git_pinned_parsing() {
assert_eq!(&serialized, string);
}
}

/// Format an error message for an absent `Forc.toml`.
pub fn manifest_file_missing(curr_dir: PathBuf) -> anyhow::Error {
let message = format!(
"could not find `{}` in `{}` or any parent directory",
constants::MANIFEST_FILE_NAME,
curr_dir.display()
);
Error::msg(message)
}

/// Format an error message for failed parsing of a manifest.
pub fn parsing_failed(project_name: &str, errors: Vec<CompileError>) -> anyhow::Error {
let error = errors
.iter()
.map(|e| e.to_friendly_error_string())
.collect::<Vec<String>>()
.join("\n");
let message = format!("Parsing {} failed: \n{}", project_name, error);
Error::msg(message)
}

/// Format an error message if an incorrect program type is present.
pub fn wrong_program_type(
project_name: &str,
expected_type: TreeType,
parse_type: TreeType,
) -> anyhow::Error {
let message = format!(
"{} is not a '{:?}' it is a '{:?}'",
project_name, expected_type, parse_type
);
Error::msg(message)
}

/// Format an error message if a given URL fails to produce a working node.
pub fn fuel_core_not_running(node_url: &str) -> anyhow::Error {
let message = format!("could not get a response from node at the URL {}. Start a node with `fuel-core`. See https://github.com/FuelLabs/fuel-core#running for more information", node_url);
Error::msg(message)
}

/// Given the current directory and expected program type, determines whether the correct program type is present.
pub fn check_program_type(
manifest: &Manifest,
manifest_dir: PathBuf,
expected_type: TreeType,
) -> Result<()> {
let parsed_type = manifest.program_type(manifest_dir)?;
if parsed_type != expected_type {
bail!(wrong_program_type(
&manifest.project.name,
expected_type,
parsed_type
));
} else {
Ok(())
}
}
2 changes: 1 addition & 1 deletion forc/src/cli/commands/deploy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ pub struct Command {

pub(crate) async fn exec(command: Command) -> Result<()> {
match forc_deploy::deploy(command).await {
Err(e) => bail!(e.message),
Err(e) => bail!("{}", e),
_ => Ok(()),
}
}
2 changes: 1 addition & 1 deletion forc/src/cli/commands/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ pub struct Command {

pub(crate) async fn exec(command: Command) -> Result<()> {
match forc_run::run(command).await {
Err(e) => bail!(e.message),
sezna marked this conversation as resolved.
Show resolved Hide resolved
Err(e) => bail!("{}", e),
_ => Ok(()),
}
}
19 changes: 18 additions & 1 deletion forc/src/ops/forc_abi_json.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,34 @@
use crate::cli::{BuildCommand, JsonAbiCommand};
use anyhow::Result;
use forc_pkg::{check_program_type, manifest_file_missing, Manifest};
use forc_util::find_manifest_dir;
use serde_json::{json, Value};
use std::fs::File;
use std::path::PathBuf;
use sway_core::TreeType;

pub fn build(command: JsonAbiCommand) -> Result<Value> {
let curr_dir = if let Some(ref path) = command.path {
PathBuf::from(path)
} else {
std::env::current_dir()?
};
let manifest_dir =
find_manifest_dir(&curr_dir).ok_or_else(|| manifest_file_missing(curr_dir))?;
let manifest = Manifest::from_dir(&manifest_dir)?;
check_program_type(&manifest, manifest_dir, TreeType::Contract)?;

let build_command = BuildCommand {
path: command.path,
offline_mode: command.offline_mode,
silent_mode: command.silent_mode,
minify_json_abi: command.minify,
..Default::default()
};

let compiled = crate::ops::forc_build::build(build_command)?;
let json_abi = json!(compiled.json_abi);

eureka-cpu marked this conversation as resolved.
Show resolved Hide resolved
if let Some(outfile) = command.json_outfile {
let file = File::create(outfile).map_err(|e| e)?;
let res = if command.minify {
Expand All @@ -22,9 +38,10 @@ pub fn build(command: JsonAbiCommand) -> Result<Value> {
};
res.map_err(|e| e)?;
} else if command.minify {
println!("{}", json_abi);
println!("{json_abi}");
} else {
println!("{:#}", json_abi);
}
eureka-cpu marked this conversation as resolved.
Show resolved Hide resolved

Ok(json_abi)
}
106 changes: 38 additions & 68 deletions forc/src/ops/forc_deploy.rs
Original file line number Diff line number Diff line change
@@ -1,22 +1,25 @@
use crate::cli::{BuildCommand, DeployCommand};
use crate::ops::forc_build;
use crate::utils::cli_error::CliError;
use anyhow::Result;
use forc_pkg::Manifest;
use anyhow::{bail, Result};
use forc_pkg::{check_program_type, manifest_file_missing, Manifest};
use forc_util::find_manifest_dir;
use fuel_gql_client::client::FuelClient;
use fuel_tx::{Output, Salt, Transaction};
use fuel_vm::prelude::*;
use std::path::PathBuf;
use sway_core::{parse, TreeType};
use sway_utils::constants::*;
use sway_core::TreeType;
use sway_utils::constants::DEFAULT_NODE_URL;

pub async fn deploy(command: DeployCommand) -> Result<fuel_tx::ContractId, CliError> {
pub async fn deploy(command: DeployCommand) -> Result<fuel_tx::ContractId> {
let curr_dir = if let Some(ref path) = command.path {
PathBuf::from(path)
} else {
std::env::current_dir()?
};
let manifest_dir =
find_manifest_dir(&curr_dir).ok_or_else(|| manifest_file_missing(curr_dir))?;
let manifest = Manifest::from_dir(&manifest_dir)?;
check_program_type(&manifest, manifest_dir, TreeType::Contract)?;

let DeployCommand {
path,
Expand All @@ -32,73 +35,40 @@ pub async fn deploy(command: DeployCommand) -> Result<fuel_tx::ContractId, CliEr
minify_json_abi,
} = command;

match find_manifest_dir(&curr_dir) {
Some(manifest_dir) => {
let manifest = Manifest::from_dir(&manifest_dir)?;
let project_name = &manifest.project.name;
let entry_string = manifest.entry_string(&manifest_dir)?;

// Parse the main file and check is it a contract.
let parsed_result = parse(entry_string, None);
match parsed_result.value {
Some(parse_tree) => match parse_tree.tree_type {
TreeType::Contract => {
let build_command = BuildCommand {
path,
use_ir,
print_finalized_asm,
print_intermediate_asm,
print_ir,
binary_outfile,
offline_mode,
debug_outfile,
silent_mode,
output_directory,
minify_json_abi,
};
let build_command = BuildCommand {
path,
use_ir,
print_finalized_asm,
print_intermediate_asm,
print_ir,
binary_outfile,
offline_mode,
debug_outfile,
silent_mode,
output_directory,
minify_json_abi,
};

let compiled = forc_build::build(build_command)?;
let (tx, contract_id) = create_contract_tx(
compiled.bytecode,
Vec::<fuel_tx::Input>::new(),
Vec::<fuel_tx::Output>::new(),
);
let compiled = forc_build::build(build_command)?;
let (tx, contract_id) = create_contract_tx(
compiled.bytecode,
Vec::<fuel_tx::Input>::new(),
Vec::<fuel_tx::Output>::new(),
);

let node_url = match &manifest.network {
Some(network) => &network.url,
_ => DEFAULT_NODE_URL,
};
let node_url = match &manifest.network {
Some(network) => &network.url,
_ => DEFAULT_NODE_URL,
};
sezna marked this conversation as resolved.
Show resolved Hide resolved

let client = FuelClient::new(node_url)?;
let client = FuelClient::new(node_url)?;

match client.submit(&tx).await {
Ok(logs) => {
println!("Logs:\n{:?}", logs);
Ok(contract_id)
}
Err(e) => Err(e.to_string().into()),
}
}
TreeType::Script => Err(CliError::wrong_sway_type(
project_name,
SWAY_CONTRACT,
SWAY_SCRIPT,
)),
TreeType::Predicate => Err(CliError::wrong_sway_type(
project_name,
SWAY_CONTRACT,
SWAY_PREDICATE,
)),
TreeType::Library { .. } => Err(CliError::wrong_sway_type(
project_name,
SWAY_CONTRACT,
SWAY_LIBRARY,
)),
},
None => Err(CliError::parsing_failed(project_name, parsed_result.errors)),
}
match client.submit(&tx).await {
Ok(logs) => {
println!("Logs:\n{:?}", logs);
Ok(contract_id)
}
None => Err(CliError::manifest_file_missing(curr_dir)),
Err(e) => bail!("{e}"),
}
}

Expand Down
Loading