Skip to content

Commit

Permalink
Add target selector (#1347)
Browse files Browse the repository at this point in the history
commit-id:2ec662b7

---

**Stack**:
- #1348
- #1347⚠️ *Part of a stack created by [spr](https://github.com/ejoffe/spr). Do
not merge manually using the UI - doing so may have unexpected results.*
  • Loading branch information
maciektr authored Jun 12, 2024
1 parent 1e920b0 commit 79b2ce1
Show file tree
Hide file tree
Showing 5 changed files with 104 additions and 52 deletions.
8 changes: 8 additions & 0 deletions scarb/src/bin/scarb/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,14 @@ pub struct ExpandArgs {
#[command(flatten)]
pub features: FeaturesSpec,

/// Specify the target to expand by target kind.
#[arg(long)]
pub target_kind: Option<String>,

/// Specify the target to expand by target name.
#[arg(long)]
pub target_name: Option<String>,

/// Do not attempt formatting.
#[arg(long, default_value_t = false)]
pub ugly: bool,
Expand Down
5 changes: 4 additions & 1 deletion scarb/src/bin/scarb/commands/expand.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use anyhow::Result;
use smol_str::ToSmolStr;

use crate::args::ExpandArgs;
use scarb::core::Config;
use scarb::core::{Config, TargetKind};
use scarb::ops;
use scarb::ops::ExpandOpts;

Expand All @@ -12,6 +13,8 @@ pub fn run(args: ExpandArgs, config: &Config) -> Result<()> {
let opts = ExpandOpts {
features: args.features.try_into()?,
ugly: args.ugly,
target_name: args.target_name.map(|n| n.to_smolstr()),
target_kind: args.target_kind.map(TargetKind::try_new).transpose()?,
};
ops::expand(package, opts, &ws)
}
22 changes: 2 additions & 20 deletions scarb/src/ops/compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ use crate::core::{
FeatureName, PackageId, PackageName, TargetKind, Utf8PathWorkspaceExt, Workspace,
};
use crate::ops;
use crate::ops::get_test_package_ids;

#[derive(Debug, Clone)]
pub enum FeaturesSelector {
Expand Down Expand Up @@ -81,26 +82,7 @@ where
let resolve = ops::resolve_workspace(ws)?;

// Add test compilation units to build
let packages = packages
.into_iter()
.flat_map(|package_id| {
let package = ws.members().find(|p| p.id == package_id).unwrap();
let mut result: Vec<PackageId> = package
.manifest
.targets
.iter()
.filter(|t| t.is_test())
.map(|t| {
package
.id
.for_test_target(t.group_id.clone().unwrap_or(t.name.clone()))
})
.collect();
result.push(package_id);
result
})
.collect::<Vec<PackageId>>();

let packages = get_test_package_ids(packages, ws);
let compilation_units = ops::generate_compilation_units(&resolve, &opts.features, ws)?
.into_iter()
.filter(|cu| {
Expand Down
95 changes: 64 additions & 31 deletions scarb/src/ops/expand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,8 @@ use crate::compiler::helpers::{build_compiler_config, write_string};
use crate::compiler::{CairoCompilationUnit, CompilationUnit, CompilationUnitAttributes};
use crate::core::{Package, TargetKind, Workspace};
use crate::ops;
use crate::ops::FeaturesOpts;
use crate::ops::{get_test_package_ids, FeaturesOpts};
use anyhow::{anyhow, bail, Context, Result};
use cairo_lang_compiler::db::RootDatabase;
use cairo_lang_compiler::diagnostics::DiagnosticsError;
use cairo_lang_defs::db::DefsGroup;
use cairo_lang_defs::ids::{LanguageElementId, ModuleId, ModuleItemId};
Expand All @@ -18,11 +17,14 @@ use cairo_lang_parser::db::ParserGroup;
use cairo_lang_syntax::node::helpers::UsePathEx;
use cairo_lang_syntax::node::{ast, TypedStablePtr, TypedSyntaxNode};
use cairo_lang_utils::Upcast;
use smol_str::SmolStr;
use std::collections::HashSet;

#[derive(Debug)]
#[derive(Clone, Debug)]
pub struct ExpandOpts {
pub features: FeaturesOpts,
pub target_kind: Option<TargetKind>,
pub target_name: Option<SmolStr>,
pub ugly: bool,
}

Expand All @@ -38,30 +40,49 @@ pub fn expand(package: Package, opts: ExpandOpts, ws: &Workspace<'_>) -> Result<
.map(|unit| ops::compile::compile_unit(unit.clone(), ws))
.collect::<Result<Vec<_>>>()?;

let Some(compilation_unit) = compilation_units.into_iter().find(|unit| {
unit.main_package_id() == package.id
&& unit.main_component().target_kind() == TargetKind::LIB
}) else {
bail!("compilation unit not found for `{package_name}`")
};
let CompilationUnit::Cairo(compilation_unit) = compilation_unit else {
bail!("only cairo compilation units can be expanded")
};
let ScarbDatabase { db, .. } = build_scarb_root_database(&compilation_unit, ws)?;
let mut compiler_config = build_compiler_config(&compilation_unit, ws);
compiler_config
.diagnostics_reporter
.ensure(&db)
.map_err(|err| err.into())
.map_err(|err| {
if !suppress_error(&err) {
ws.config().ui().anyhow(&err);
}
let compilation_units = compilation_units
.into_iter()
// We rewrite group compilation units to single source paths ones. We value simplicity over
// performance here, as expand output will be read by people rather than tooling.
.flat_map(|unit| match unit {
CompilationUnit::Cairo(unit) => unit
.rewrite_to_single_source_paths()
.into_iter()
.map(CompilationUnit::Cairo)
.collect::<Vec<_>>(),
// We include non-cairo compilation units here, so we can show better error msg later.
_ => vec![unit],
})
.filter(|unit| {
let target_kind = if opts.target_name.is_none() && opts.target_kind.is_none() {
// If no target specifier is used - default to lib.
Some(TargetKind::LIB)
} else {
opts.target_kind.clone()
};
// Includes test package ids.
get_test_package_ids(vec![package.id], ws).contains(&unit.main_package_id())
// We can use main_component below, as targets are not grouped.
&& target_kind.as_ref()
.map_or(true, |kind| unit.main_component().target_kind() == *kind)
&& opts
.target_name
.as_ref()
.map_or(true, |name| unit.main_component().first_target().name == *name)
})
.map(|unit| match unit {
CompilationUnit::Cairo(unit) => Ok(unit),
_ => bail!("only cairo compilation units can be expanded"),
})
.collect::<Result<Vec<_>>>()?;

anyhow!("could not check `{package_name}` due to previous error")
})?;
if compilation_units.is_empty() {
bail!("no compilation units found for `{package_name}`")
}

do_expand(&db, &compilation_unit, opts, ws)?;
for compilation_unit in compilation_units {
do_expand(&compilation_unit, opts.clone(), ws)?;
}

Ok(())
}
Expand Down Expand Up @@ -123,11 +144,23 @@ impl ModuleStack {
}

fn do_expand(
db: &RootDatabase,
compilation_unit: &CairoCompilationUnit,
opts: ExpandOpts,
ws: &Workspace<'_>,
) -> Result<()> {
let ScarbDatabase { db, .. } = build_scarb_root_database(compilation_unit, ws)?;
let mut compiler_config = build_compiler_config(compilation_unit, ws);
compiler_config
.diagnostics_reporter
.ensure(&db)
.map_err(|err| err.into())
.map_err(|err| {
if !suppress_error(&err) {
ws.config().ui().anyhow(&err);
}

anyhow!("could not check due to previous error")
})?;
let main_crate_id = db.intern_crate(CrateLongId::Real(
compilation_unit.main_component().cairo_package_name(),
));
Expand All @@ -142,21 +175,21 @@ fn do_expand(
.context("failed to retrieve module main file syntax")?;

let crate_modules = db.crate_modules(main_crate_id);
let item_asts = file_syntax.items(db);
let item_asts = file_syntax.items(&db);

let mut builder = PatchBuilder::new(db, &item_asts);
let mut builder = PatchBuilder::new(&db, &item_asts);
let mut module_stack = ModuleStack::new();

for module_id in crate_modules.iter() {
builder.add_str(module_stack.register(module_id.full_path(db)).as_str());
builder.add_str(module_stack.register(module_id.full_path(&db)).as_str());
let Some(module_items) = db.module_items(*module_id).to_option() else {
continue;
};
let mut seen_uses = HashSet::new();
for item_id in module_items.iter() {
// We need to handle uses manually, as module data only includes use leaf instead of path.
if let ModuleItemId::Use(use_id) = item_id {
let use_item = use_id.stable_ptr(db).lookup(db.upcast());
let use_item = use_id.stable_ptr(&db).lookup(db.upcast());
let item = ast::UsePath::Leaf(use_item.clone()).get_item(db.upcast());
let item = item.use_path(db.upcast());
// We need to deduplicate multi-uses (`a::{b, c}`), which are split into multiple leaves.
Expand All @@ -172,7 +205,7 @@ fn do_expand(
if let ModuleItemId::Submodule(_) = item_id {
continue;
}
let node = item_id.stable_location(db).syntax_node(db);
let node = item_id.stable_location(&db).syntax_node(&db);
builder.add_node(node);
}
}
Expand Down
26 changes: 26 additions & 0 deletions scarb/src/ops/resolve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -571,3 +571,29 @@ fn generate_cairo_plugin_compilation_units(member: &Package) -> Result<Vec<Compi
)?],
})])
}

/// Generate package ids associated with test compilation units for the given packages.
/// This function will return input list along with generated test package ids.
pub fn get_test_package_ids(packages: Vec<PackageId>, ws: &Workspace<'_>) -> Vec<PackageId> {
packages
.into_iter()
.flat_map(|package_id| {
let Some(package) = ws.members().find(|p| p.id == package_id) else {
return Vec::new();
};
let mut result: Vec<PackageId> = package
.manifest
.targets
.iter()
.filter(|t| t.is_test())
.map(|t| {
package
.id
.for_test_target(t.group_id.clone().unwrap_or(t.name.clone()))
})
.collect();
result.push(package_id);
result
})
.collect::<Vec<PackageId>>()
}

0 comments on commit 79b2ce1

Please sign in to comment.