Skip to content

Commit

Permalink
Merge pull request #946 from multiversx/meta3
Browse files Browse the repository at this point in the history
sc-meta improvements
  • Loading branch information
andrei-marinica authored Jan 25, 2023
2 parents 9daa73b + 23cbce7 commit d84475b
Show file tree
Hide file tree
Showing 16 changed files with 412 additions and 66 deletions.
28 changes: 28 additions & 0 deletions framework/meta/src/cli_args/cli_args_standalone.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ pub struct StandaloneCliArgs {

#[derive(Clone, PartialEq, Eq, Debug, Subcommand)]
pub enum StandaloneCliAction {
#[command(
about = "General info about the contract an libraries residing in the targetted directory.."
)]
Info(InfoArgs),

#[command(
about = "Calls the meta crates for all contracts under given path with the given arguments."
)]
Expand All @@ -39,6 +44,19 @@ pub enum StandaloneCliAction {
Upgrade(UpgradeArgs),
}

#[derive(Default, Clone, PartialEq, Eq, Debug, Args)]
pub struct InfoArgs {
/// Target directory to retrieve info from.
/// Will be current directory if not specified.
#[arg(long, verbatim_doc_comment)]
pub path: Option<String>,

/// Ignore all directories with these names.
#[arg(long, verbatim_doc_comment)]
#[clap(global = true, default_value = "target")]
pub ignore: Vec<String>,
}

#[derive(Default, Clone, PartialEq, Eq, Debug, Args)]
pub struct AllArgs {
#[command(subcommand)]
Expand All @@ -50,6 +68,11 @@ pub struct AllArgs {
#[clap(global = true)]
pub path: Option<String>,

/// Ignore all directories with these names.
#[arg(long, verbatim_doc_comment)]
#[clap(global = true, default_value = "target")]
pub ignore: Vec<String>,

#[arg(
long = "no-abi-git-version",
help = "Skips loading the Git version into the ABI",
Expand All @@ -76,6 +99,11 @@ pub struct UpgradeArgs {
#[arg(long, verbatim_doc_comment)]
pub path: Option<String>,

/// Ignore all directories with these names.
#[arg(long, verbatim_doc_comment)]
#[clap(global = true, default_value = "target")]
pub ignore: Vec<String>,

/// Overrides the version to upgrade to.
/// By default it will be the last version out.
#[arg(long = "to", verbatim_doc_comment)]
Expand Down
2 changes: 2 additions & 0 deletions framework/meta/src/folder_structure/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
mod pretty_print;
mod relevant_directory;
mod version_req;

pub use pretty_print::*;
pub use relevant_directory::*;
pub use version_req::*;
103 changes: 103 additions & 0 deletions framework/meta/src/folder_structure/pretty_print.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
use super::RelevantDirectory;
use std::{
collections::BTreeMap,
path::{Component, Path},
};

const PIPE_L: &str = " └─";
const PIPE_T: &str = " ├─";
const INDENT_PIPE: &str = " │ ";
const INDENT_SPACE: &str = " ";

struct PrettyPrintTreeNode {
name: String,
dir: Option<RelevantDirectory>,
children: BTreeMap<String, PrettyPrintTreeNode>,
}

impl PrettyPrintTreeNode {
fn new(name: String) -> Self {
PrettyPrintTreeNode {
name,
dir: None,
children: BTreeMap::new(),
}
}

fn add_path(&mut self, path: &Path, dir: &RelevantDirectory) {
let components: Vec<Component> = path
.components()
.filter(|component| component.as_os_str().to_string_lossy() != "/")
.collect();
self.add_components(&components[..], dir);
}

fn add_components(&mut self, components: &[Component], dir: &RelevantDirectory) {
if components.is_empty() {
return;
}

let first = components[0].as_os_str().to_string_lossy().into_owned();
let child = self
.children
.entry(first.to_string())
.or_insert_with(|| PrettyPrintTreeNode::new(first));

let remaining_components = &components[1..];
if remaining_components.is_empty() {
child.dir = Some(dir.clone());
} else {
child.add_components(remaining_components, dir);
}
}

fn coalesce_single_children(&mut self) {
for child in self.children.values_mut() {
child.coalesce_single_children();
}

if self.children.len() == 1 {
let only_child = self.children.first_entry().unwrap().remove();
self.name = format!("{}/{}", &self.name, &only_child.name);
self.children = only_child.children;
}
}

fn print<PrintName>(&self, prefix: &str, child_prefix: &str, print_name: &PrintName)
where
PrintName: Fn(&RelevantDirectory),
{
let num_children = self.children.len();
print!("{prefix} {}", &self.name);
if let Some(dir) = &self.dir {
print_name(dir);
}
println!();

for (i, child) in self.children.values().enumerate() {
let (l_pipe, vertical_pipe) = if i == num_children - 1 {
(PIPE_L, INDENT_SPACE)
} else {
(PIPE_T, INDENT_PIPE)
};

let next_prefix = format!("{child_prefix}{l_pipe}");
let next_child_prefix = format!("{child_prefix}{vertical_pipe}"); // or grandchild prefix
child.print(next_prefix.as_str(), next_child_prefix.as_str(), print_name);
}
}
}

pub fn dir_pretty_print<'a, I, PrintName>(dir_iter: I, prefix: &str, print_name: &PrintName)
where
I: Iterator<Item = &'a RelevantDirectory>,
PrintName: Fn(&RelevantDirectory),
{
let mut root = PrettyPrintTreeNode::new("".to_string());
for dir in dir_iter {
root.add_path(dir.path.as_ref(), dir);
}
root.coalesce_single_children();

root.print(prefix, prefix, print_name);
}
44 changes: 34 additions & 10 deletions framework/meta/src/folder_structure/relevant_directory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,16 +31,24 @@ pub enum DirectoryType {
pub struct RelevantDirectory {
pub path: PathBuf,
pub version: VersionReq,
pub upgrade_in_progress: Option<(&'static str, &'static str)>,
pub dir_type: DirectoryType,
}

pub struct RelevantDirectories(Vec<RelevantDirectory>);
pub struct RelevantDirectories(pub(crate) Vec<RelevantDirectory>);

impl RelevantDirectories {
pub fn find_all(path: impl AsRef<Path>) -> Self {
let canonicalized = fs::canonicalize(path).expect("error canonicalizing input path");
pub fn find_all(path: impl AsRef<Path>, ignore: &[String]) -> Self {
let path_ref = path.as_ref();
let canonicalized = fs::canonicalize(path_ref).unwrap_or_else(|err| {
panic!(
"error canonicalizing input path {}: {}",
path_ref.display(),
err,
)
});
let mut dirs = Vec::new();
populate_directories(canonicalized.as_path(), &mut dirs);
populate_directories(canonicalized.as_path(), ignore, &mut dirs);
RelevantDirectories(dirs)
}

Expand Down Expand Up @@ -79,25 +87,36 @@ impl RelevantDirectories {
.filter(move |dir| dir.version.semver == version)
}

/// Operates no changes on the disk. Only changes this structure in memory.
pub fn update_versions_in_memory(&mut self, from_version: &str, to_version: &str) {
/// Marks all appropriate directories as ready for upgrade.
pub fn start_upgrade(&mut self, from_version: &'static str, to_version: &'static str) {
for dir in self.0.iter_mut() {
if dir.version.semver == from_version {
dir.upgrade_in_progress = Some((from_version, to_version));
}
}
}

/// Updates the versions of all directories being upgraded (in memory)
/// and resets upgrade status.
pub fn finish_upgrade(&mut self) {
for dir in self.0.iter_mut() {
if let Some((_, to_version)) = &dir.upgrade_in_progress {
dir.version.semver = to_version.to_string();
dir.upgrade_in_progress = None;
}
}
}
}

fn populate_directories(path: &Path, result: &mut Vec<RelevantDirectory>) {
fn populate_directories(path: &Path, ignore: &[String], result: &mut Vec<RelevantDirectory>) {
let is_contract = is_marked_contract_crate_dir(path);

if !is_contract && path.is_dir() {
let read_dir = fs::read_dir(path).expect("error reading directory");
for child_result in read_dir {
let child = child_result.unwrap();
if can_continue_recursion(&child) {
populate_directories(child.path().as_path(), result);
if can_continue_recursion(&child, ignore) {
populate_directories(child.path().as_path(), ignore, result);
}
}
}
Expand All @@ -111,6 +130,7 @@ fn populate_directories(path: &Path, result: &mut Vec<RelevantDirectory>) {
result.push(RelevantDirectory {
path: path.to_owned(),
version,
upgrade_in_progress: None,
dir_type,
});
}
Expand All @@ -120,12 +140,16 @@ fn is_marked_contract_crate_dir(path: &Path) -> bool {
path.join("multiversx.json").is_file() || path.join("elrond.json").is_file()
}

fn can_continue_recursion(dir_entry: &DirEntry) -> bool {
fn can_continue_recursion(dir_entry: &DirEntry, blacklist: &[String]) -> bool {
if !dir_entry.file_type().unwrap().is_dir() {
return false;
}

if let Some(dir_name_str) = dir_entry.file_name().to_str() {
if blacklist.iter().any(|ignored| ignored == dir_name_str) {
return false;
}

// do not explore hidden folders
!dir_name_str.starts_with('.')
} else {
Expand Down
1 change: 1 addition & 0 deletions framework/meta/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ mod meta_abi;
mod meta_all;
mod meta_cli;
mod meta_config;
mod meta_info;
mod meta_validate_abi;
mod meta_wasm_tools;
pub mod output_contract;
Expand Down
15 changes: 11 additions & 4 deletions framework/meta/src/meta_all.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use colored::Colorize;

use crate::{
cli_args::{AllArgs, CliArgsToRaw},
folder_structure::RelevantDirectories,
folder_structure::{dir_pretty_print, RelevantDirectories},
};

pub fn call_all_meta(args: &AllArgs) {
Expand All @@ -14,11 +14,13 @@ pub fn call_all_meta(args: &AllArgs) {
"./"
};

perform_call_all_meta(path, args.to_raw());
perform_call_all_meta(path, args.ignore.as_slice(), args.to_raw());
}

fn perform_call_all_meta(path: impl AsRef<Path>, raw_args: Vec<String>) {
let dirs = RelevantDirectories::find_all(path);
fn perform_call_all_meta(path: impl AsRef<Path>, ignore: &[String], raw_args: Vec<String>) {
let dirs = RelevantDirectories::find_all(path, ignore);
dir_pretty_print(dirs.iter_contract_crates(), "", &|_| {});

println!(
"Found {} contract crates.\n",
dirs.iter_contract_crates().count(),
Expand All @@ -34,6 +36,11 @@ fn perform_call_all_meta(path: impl AsRef<Path>, raw_args: Vec<String>) {

pub fn call_contract_meta(contract_crate_path: &Path, cargo_run_args: &[String]) {
let meta_path = contract_crate_path.join("meta");
assert!(
meta_path.exists(),
"Contract meta crate not found at {}",
meta_path.as_path().display()
);

println!(
"\n{} `cargo run {}` in {}",
Expand Down
2 changes: 2 additions & 0 deletions framework/meta/src/meta_cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use super::{
use crate::{
cli_args::{ContractCliAction, ContractCliArgs, StandaloneCliAction, StandaloneCliArgs},
meta_all::call_all_meta,
meta_info::call_info,
sc_upgrade::upgrade_sc,
};
use clap::Parser;
Expand All @@ -13,6 +14,7 @@ use multiversx_sc::contract_base::ContractAbiProvider;
pub fn cli_main_standalone() {
let cli_args = StandaloneCliArgs::parse();
match &cli_args.command {
Some(StandaloneCliAction::Info(args)) => call_info(args),
Some(StandaloneCliAction::All(args)) => call_all_meta(args),
Some(StandaloneCliAction::Upgrade(args)) => {
upgrade_sc(args);
Expand Down
18 changes: 18 additions & 0 deletions framework/meta/src/meta_info.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
use crate::{
cli_args::InfoArgs,
folder_structure::{dir_pretty_print, RelevantDirectories},
sc_upgrade::{print_tree_dir_metadata, DEFAULT_LAST_VERSION},
};

pub fn call_info(args: &InfoArgs) {
let path = if let Some(some_path) = &args.path {
some_path.as_str()
} else {
"./"
};

let dirs = RelevantDirectories::find_all(path, args.ignore.as_slice());
dir_pretty_print(dirs.iter(), "", &|dir| {
print_tree_dir_metadata(dir, DEFAULT_LAST_VERSION)
});
}
4 changes: 4 additions & 0 deletions framework/meta/src/sc_upgrade/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
mod upgrade_0_31;
mod upgrade_0_32;
mod upgrade_0_39;
mod upgrade_common;
mod upgrade_print;
mod upgrade_selector;
mod upgrade_versions;

pub use upgrade_print::print_tree_dir_metadata;
pub use upgrade_selector::upgrade_sc;
pub use upgrade_versions::DEFAULT_LAST_VERSION;
20 changes: 20 additions & 0 deletions framework/meta/src/sc_upgrade/upgrade_0_31.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
use super::upgrade_common::{replace_in_files, version_bump_in_cargo_toml};
use crate::folder_structure::RelevantDirectory;
use ruplacer::Query;
use std::path::Path;

/// Migrate `0.30` to `0.31.0`, including the version bump.
pub fn upgrade_to_31_0(dir: &RelevantDirectory) {
v_0_31_replace_in_files(dir.path.as_ref());

let (from_version, to_version) = dir.upgrade_in_progress.unwrap();
version_bump_in_cargo_toml(&dir.path, from_version, to_version);
}

fn v_0_31_replace_in_files(sc_crate_path: &Path) {
replace_in_files(
sc_crate_path,
"*rs",
&[Query::substring("#[var_args]", "")][..],
);
}
Loading

0 comments on commit d84475b

Please sign in to comment.