Skip to content

sc-meta source pack#2354

Draft
andrei-marinica wants to merge 1 commit intofeat/rbfrom
source2
Draft

sc-meta source pack#2354
andrei-marinica wants to merge 1 commit intofeat/rbfrom
source2

Conversation

@andrei-marinica
Copy link
Copy Markdown
Contributor

No description provided.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new sc-meta source command group to generate reproducible “source packs” (*.source.json) for smart-contract projects, and refactors local-deps logic so it can be reused by the new packer.

Changes:

  • Introduces framework/meta/src/cmd/source.rs implementing sc-meta source pack to discover contracts, collect source files, and emit a packaged JSON with base64-encoded contents.
  • Refactors local_deps to expose reusable helpers (compute_local_deps, expand_deps, serialize_local_deps_json) and centralizes the local_deps.txt filename.
  • Moves the base64 crate dependency from multiversx-sc-snippets to multiversx-sc-meta (and updates Cargo.lock accordingly).

Reviewed changes

Copilot reviewed 8 out of 9 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
framework/snippets/Cargo.toml Removes now-unneeded base64 dependency from snippets crate.
framework/meta/src/cmd/source.rs New source packaging implementation (source pack).
framework/meta/src/cmd/local_deps.rs Exposes reusable local dependency computation for source pack.
framework/meta/src/cmd.rs Registers new source command module.
framework/meta/src/cli/cli_standalone_main.rs Wires new CLI route for sc-meta source ....
framework/meta/src/cli/cli_args_standalone.rs Adds source command and subcommands (local-deps, pack) + PackArgs.
framework/meta/Cargo.toml Adds base64 dependency needed by source packer.
framework/meta-lib/src/cargo_toml/cargo_toml_contents.rs Improves panic messages and adds package_version().
Cargo.lock Updates lockfile for dependency move/addition.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +228 to +229
let rel = pathdiff::diff_paths(file, project_folder).unwrap();
let path_str = rel.to_string_lossy().replace('\\', "/");
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

make_entry unconditionally unwraps pathdiff::diff_paths(file, project_folder). This will panic when a local dependency (or any collected file) is outside project_folder (e.g. path = "../shared"). Consider falling back to an absolute path (or a module-relative path) when diff_paths returns None, similar to module_path, so source packing works for out-of-tree dependencies.

Suggested change
let rel = pathdiff::diff_paths(file, project_folder).unwrap();
let path_str = rel.to_string_lossy().replace('\\', "/");
let path_str = pathdiff::diff_paths(file, project_folder)
.unwrap_or_else(|| file.to_path_buf())
.to_string_lossy()
.replace('\\', "/");

Copilot uses AI. Check for mistakes.
Comment on lines +56 to +62
let mut dep_map: BTreeMap<PathBuf, LocalDep> = BTreeMap::new();
expand_deps(&contract_dir, contract_dir.clone(), &mut dep_map);

let common_dependency_path = common_path_all(dep_map.keys().map(|p| p.as_path()));

LocalDeps {
root: contract_dir.clone(),
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

compute_local_deps calls expand_deps(&contract_dir, ...), but expand_deps computes child_path = pathdiff::diff_paths(&full_path, root_path).unwrap(). If any local dependency resolves outside contract_dir (common with path = "../..."), this will panic and break source pack. Either make expand_deps tolerate diff_paths == None (e.g. store absolute paths / a separate canonical path field) or allow compute_local_deps to accept a workspace root and use that as root_path.

Suggested change
let mut dep_map: BTreeMap<PathBuf, LocalDep> = BTreeMap::new();
expand_deps(&contract_dir, contract_dir.clone(), &mut dep_map);
let common_dependency_path = common_path_all(dep_map.keys().map(|p| p.as_path()));
LocalDeps {
root: contract_dir.clone(),
let root_path = contract_dir
.ancestors()
.last()
.unwrap_or(contract_dir.as_path())
.to_path_buf();
let mut dep_map: BTreeMap<PathBuf, LocalDep> = BTreeMap::new();
expand_deps(&root_path, contract_dir.clone(), &mut dep_map);
let common_dependency_path = common_path_all(dep_map.keys().map(|p| p.as_path()));
LocalDeps {
root: root_path,

Copilot uses AI. Check for mistakes.
if let Ok(read_dir) = fs::read_dir(current) {
for entry in read_dir.flatten() {
let path = entry.path();
if path.is_dir() && path.file_name().map(|n| n != "target").unwrap_or(true) {
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Directory recursion here only skips target. Unlike RelevantDirectories (which avoids hidden folders), this will traverse hidden directories like .git and can become very slow on large repos. Consider also skipping entries whose names start with . (and possibly other well-known build/output folders) to keep discovery fast and consistent with the rest of the meta tooling.

Suggested change
if path.is_dir() && path.file_name().map(|n| n != "target").unwrap_or(true) {
let should_recurse = path.is_dir()
&& path
.file_name()
.and_then(|n| n.to_str())
.map(|name| name != "target" && !name.starts_with('.'))
.unwrap_or(true);
if should_recurse {

Copilot uses AI. Check for mistakes.
Comment on lines +257 to +269
fn collect_recursive(current: &Path, result: &mut Vec<PathBuf>) {
let entries = match fs::read_dir(current) {
Ok(e) => e,
Err(_) => return,
};
for entry in entries.flatten() {
let path = entry.path();
if path.is_dir() {
if path.file_name().map(|n| n != "target").unwrap_or(true) {
collect_recursive(&path, result);
}
} else if is_source_file(&path) {
result.push(path);
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

collect_recursive recurses into all subdirectories except target, including hidden folders (e.g. .git) and other large trees. This can cause significant overhead even though only a few files are ultimately collected. Consider applying the same hidden-folder skip used elsewhere in this crate (and optionally skipping known output directories like output) during traversal.

Copilot uses AI. Check for mistakes.
Comment thread framework/meta/src/cmd/source.rs
Comment on lines +87 to +106
pub fn source_pack(args: &PackArgs) {
let project_folder = if let Some(p) = &args.path {
Path::new(p).canonicalize().unwrap()
} else {
Path::new(".").canonicalize().unwrap()
};

let contract_folders = find_contract_folders(&project_folder);
if contract_folders.is_empty() {
println!(
"No contracts found (no multiversx.json) under: {}",
project_folder.display()
);
return;
}

for contract_folder in &contract_folders {
source_pack_contract(&project_folder, contract_folder, args.contract.as_deref());
}
}
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new source pack command introduces non-trivial behavior (contract discovery, dependency expansion, file ordering, base64 encoding) but there are no tests covering the output format/ordering. Adding a small integration/unit test that builds a temporary project structure and asserts the produced .source.json schema/order would help prevent regressions.

Copilot uses AI. Check for mistakes.
@github-actions
Copy link
Copy Markdown

Contract comparison - from eb3672b to dfffb2e

Path                                                                                             size                  has-allocator                     has-format
esdt-transfer-with-fee.wasm 7502 false without message
factorial.wasm 579 false None
crypto-bubbles.wasm 2541 false None
order-book-factory.wasm 3401 false None
order-book-pair.wasm 14229 false None
adder.wasm 699 false None
fractional-nfts.wasm 8306 false without message
multisig-full.wasm 15130 false without message
multisig-view.wasm 5590 false None
multisig.wasm 13442 false without message
crypto-zombies.wasm 9255 false without message
digital-cash.wasm 9845 false None
nft-minter.wasm 9725 false without message
nft-storage-prepay.wasm 2606 false None
kitty-ownership.wasm 12965 false without message
kitty-auction.wasm 9411 false without message
kitty-genetic-alg.wasm 3494 false without message
proxy-pause.wasm 4148 false None
nft-subscription.wasm 8840 false without message
ping-pong-egld.wasm 6397 false None
crowdfunding.wasm 3557 false None
empty.wasm 244 false None
bonding-curve-contract.wasm 14132 false None
token-release.wasm 6977 false without message
rewards-distribution.wasm 9605 false without message
seed-nft-minter.wasm 14443 false without message
check-pause.wasm 1260 false None
multiversx-price-aggregator-sc.wasm 17910 false without message
multiversx-wegld-swap-sc.wasm 4492 false None
std-contract.wasm 3469 true without message
vault.wasm 9035 false None
vault-upgrade.wasm 708 false None
recursive-caller.wasm 5163 false without message
forwarder-blind.wasm 14242 false without message
transfer-role-features.wasm 8667 false without message
proxy-test-second.wasm 2329 false without message
second-contract.wasm 1158 false None
first-contract.wasm 3433 false None
parent.wasm 1979 false None
child.wasm 3982 false without message
forwarder-legacy.wasm 33668 false without message
local-esdt-and-nft.wasm 12568 false without message
proxy-test-first.wasm 5719 false without message
mesh-node.wasm 16145 false without message
forwarder-raw.wasm 13193 false None
forwarder-raw-init-async-call.wasm 2357 false None
forwarder-raw-init-sync-call.wasm 2938 false None
forwarder.wasm 49178 false without message
builtin-func-features.wasm 3820 false None
panic-message-std.wasm 16074 false with message
panic-message-features.wasm 13036 false with message
abi-tester.wasm 8607 true without message
abi-tester-ev.wasm 760 false None
scenario-tester.wasm 1374 false None
forbidden-opcodes.wasm 842 false None
rust-testing-framework-tester.wasm 8608 false None
rust-snippets-generator-test.wasm 4710 false None
alloc-features.wasm 23267 false without message
alloc-mem-fail.wasm 17819 true without message
alloc-mem-leaking.wasm 23424 false without message
esdt-system-sc-mock.wasm 4623 false None
use-module.wasm 32741 false without message
use-module-view.wasm 736 false None
payable-features.wasm 5872 false None
exchange-features.wasm 1514 false None
big-float-features.wasm 6373 false without message
basic-features.wasm 87721 false without message
basic-features-small-int-bug.wasm 824 false None
basic-features-storage-bytes.wasm 541 false None
erc1155.wasm 12023 false without message
erc1155-marketplace.wasm 10602 false without message
erc20.wasm 1870 false None
erc721.wasm 2232 false None
erc1155-user-mock.wasm 1229 false None
crowdfunding-erc20.wasm 4910 false without message
lottery-erc20.wasm 12893 false without message
formatted-message-features.wasm 3600 false without message
multi-contract-features.wasm 681 false None
multi-contract-features-view.wasm 1113 false None
multi-contract-alt-impl.wasm 353 false None
multi-contract-example-feature.wasm 680 false None
send-tx-repeat.wasm 1292 false None
vec-repeat.wasm 4876 false None
linked-list-repeat.wasm 6842 false without message
set-repeat.wasm 6515 false None
map-repeat.wasm 7367 false without message
queue-repeat.wasm 5540 false None
single-value-repeat.wasm 4257 false None
str-repeat-mb-builder-basic.wasm 757 false None
str-repeat.wasm 2733 false without message
str-repeat-mb-builder-cached.wasm 1109 false without message
large-storage.wasm 1656 false None

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants