From 333dd131b79004a4bd5f6d797af03573ae87c268 Mon Sep 17 00:00:00 2001 From: maciektr Date: Mon, 6 Nov 2023 21:47:54 +0100 Subject: [PATCH] Add package edition field (#858) --- scarb-metadata/src/lib.rs | 4 ++ scarb/Cargo.toml | 2 +- scarb/src/compiler/db.rs | 26 +++++++++- scarb/src/core/manifest/mod.rs | 3 ++ scarb/src/core/manifest/toml_manifest.rs | 12 +++++ .../core/publishing/manifest_normalization.rs | 1 + scarb/src/ops/metadata.rs | 6 +++ scarb/tests/build.rs | 52 +++++++++++++++++++ scarb/tests/local_registry.rs | 10 ++-- scarb/tests/metadata.rs | 44 ++++++++++++---- scarb/tests/package.rs | 3 ++ .../scarb-test-support/src/project_builder.rs | 10 ++++ 12 files changed, 156 insertions(+), 17 deletions(-) diff --git a/scarb-metadata/src/lib.rs b/scarb-metadata/src/lib.rs index 55cee2130..2c5fe4dbc 100644 --- a/scarb-metadata/src/lib.rs +++ b/scarb-metadata/src/lib.rs @@ -208,6 +208,10 @@ pub struct PackageMetadata { /// Package version as given in `Scarb.toml`. pub version: Version, + /// Package edition as given in `Scarb.toml`. + #[serde(skip_serializing_if = "Option::is_none")] + pub edition: Option, + /// The source of the package. pub source: SourceId, diff --git a/scarb/Cargo.toml b/scarb/Cargo.toml index a71a4efc7..544d5c599 100644 --- a/scarb/Cargo.toml +++ b/scarb/Cargo.toml @@ -55,8 +55,8 @@ serde-untagged.workspace = true serde-value.workspace = true serde.workspace = true serde_json.workspace = true -sha2.workspace = true serde_repr.workspace = true +sha2.workspace = true smallvec.workspace = true smol_str.workspace = true tar.workspace = true diff --git a/scarb/src/compiler/db.rs b/scarb/src/compiler/db.rs index c4be04c6e..eeddbb850 100644 --- a/scarb/src/compiler/db.rs +++ b/scarb/src/compiler/db.rs @@ -1,11 +1,15 @@ use anyhow::{anyhow, Result}; use cairo_lang_compiler::db::RootDatabase; -use cairo_lang_compiler::project::{ProjectConfig, ProjectConfigContent}; +use cairo_lang_compiler::project::{ + AllCratesConfig, ProjectConfig, ProjectConfigContent, SingleCrateConfig, +}; use cairo_lang_defs::db::DefsGroup; use cairo_lang_defs::ids::ModuleId; use cairo_lang_defs::plugin::MacroPlugin; use cairo_lang_filesystem::db::{AsFilesGroupMut, FilesGroup, FilesGroupEx}; use cairo_lang_filesystem::ids::{CrateLongId, Directory}; +use cairo_lang_utils::ordered_hash_map::OrderedHashMap; +use smol_str::SmolStr; use std::sync::Arc; use tracing::trace; @@ -87,13 +91,31 @@ fn build_project_config(unit: &CompilationUnit) -> Result { }) .collect(); + let crates_config: OrderedHashMap = unit + .components + .iter() + .map(|component| { + ( + component.cairo_package_name(), + SingleCrateConfig { + edition: component.package.manifest.edition, + }, + ) + }) + .collect(); + + let crates_config = AllCratesConfig { + override_map: crates_config, + ..Default::default() + }; + let corelib = Some(Directory::Real( unit.core_package_component().target.source_root().into(), )); let content = ProjectConfigContent { crate_roots, - crates_config: Default::default(), + crates_config, }; let project_config = ProjectConfig { diff --git a/scarb/src/core/manifest/mod.rs b/scarb/src/core/manifest/mod.rs index 54bdcff10..cc27f38be 100644 --- a/scarb/src/core/manifest/mod.rs +++ b/scarb/src/core/manifest/mod.rs @@ -1,6 +1,7 @@ use std::collections::{BTreeMap, HashSet}; use anyhow::{bail, ensure, Result}; +use cairo_lang_filesystem::db::Edition; use camino::Utf8PathBuf; use derive_builder::Builder; use semver::VersionReq; @@ -41,6 +42,8 @@ pub struct Manifest { pub summary: Summary, pub targets: Vec, #[builder(default)] + pub edition: Edition, + #[builder(default)] pub metadata: ManifestMetadata, #[builder(default = "ManifestCompilerConfig::default_for_profile(&Profile::DEV)")] pub compiler_config: ManifestCompilerConfig, diff --git a/scarb/src/core/manifest/toml_manifest.rs b/scarb/src/core/manifest/toml_manifest.rs index 13be6e079..a84e24933 100644 --- a/scarb/src/core/manifest/toml_manifest.rs +++ b/scarb/src/core/manifest/toml_manifest.rs @@ -4,6 +4,7 @@ use std::default::Default; use std::fs; use anyhow::{anyhow, bail, ensure, Context, Result}; +use cairo_lang_filesystem::db::Edition; use camino::{Utf8Path, Utf8PathBuf}; use itertools::Itertools; use pathdiff::diff_utf8_paths; @@ -103,6 +104,7 @@ pub struct TomlWorkspace { #[serde(rename_all = "kebab-case")] pub struct PackageInheritableFields { pub version: Option, + pub edition: Option, pub authors: Option>, pub description: Option, pub documentation: Option, @@ -140,6 +142,7 @@ impl PackageInheritableFields { get_field!(license, String); get_field!(license_file, String); get_field!(repository, String); + get_field!(edition, Edition); pub fn readme(&self, workspace_root: &Utf8Path, package_root: &Utf8Path) -> Result { let Ok(Some(readme)) = readme_for_package(workspace_root, self.readme.as_ref()) else { @@ -177,6 +180,7 @@ type MaybeWorkspaceField = MaybeWorkspace; pub struct TomlPackage { pub name: PackageName, pub version: MaybeWorkspaceField, + pub edition: Option>, pub authors: Option>>, pub urls: Option>, pub description: Option>, @@ -521,9 +525,17 @@ impl TomlManifest { .transpose()?, }; + let edition = package + .edition + .clone() + .map(|edition| edition.resolve("edition", || inheritable_package.edition())) + .transpose()? + .unwrap_or_default(); + let manifest = ManifestBuilder::default() .summary(summary) .targets(targets) + .edition(edition) .metadata(metadata) .compiler_config(compiler_config) .scripts(scripts) diff --git a/scarb/src/core/publishing/manifest_normalization.rs b/scarb/src/core/publishing/manifest_normalization.rs index d21bf09b9..af78b1408 100644 --- a/scarb/src/core/publishing/manifest_normalization.rs +++ b/scarb/src/core/publishing/manifest_normalization.rs @@ -52,6 +52,7 @@ fn generate_package(pkg: &Package) -> Box { Box::new(TomlPackage { name: summary.package_id.name.clone(), version: MaybeWorkspace::Defined(summary.package_id.version.clone()), + edition: Some(MaybeWorkspace::Defined(pkg.manifest.edition)), authors: metadata.authors.clone().map(MaybeWorkspace::Defined), urls: metadata.urls.clone(), description: metadata.description.clone().map(MaybeWorkspace::Defined), diff --git a/scarb/src/ops/metadata.rs b/scarb/src/ops/metadata.rs index 68058433b..1d17989de 100644 --- a/scarb/src/ops/metadata.rs +++ b/scarb/src/ops/metadata.rs @@ -125,10 +125,16 @@ fn collect_package_metadata(package: &Package) -> m::PackageMetadata { .build() .unwrap(); + let edition = serde_json::to_value(package.manifest.edition).unwrap(); + let serde_json::Value::String(edition) = edition else { + panic!("Edition should always be a string.") + }; + m::PackageMetadataBuilder::default() .id(wrap_package_id(package.id)) .name(package.id.name.clone()) .version(package.id.version.clone()) + .edition(Some(edition.to_string())) .source(wrap_source_id(package.id.source_id)) .manifest_path(package.manifest_path()) .root(package.root()) diff --git a/scarb/tests/build.rs b/scarb/tests/build.rs index 5177ff0c5..ccafa85a9 100644 --- a/scarb/tests/build.rs +++ b/scarb/tests/build.rs @@ -635,3 +635,55 @@ fn workspace_as_dep() { )), ); } + +#[test] +fn can_define_edition() { + let code = indoc! {r#" + fn example() -> Nullable { null() } + "#}; + let t = TempDir::new().unwrap(); + ProjectBuilder::start() + .lib_cairo(code) + .edition("2023_01") + .build(&t); + + Scarb::quick_snapbox() + .arg("build") + .current_dir(&t) + .assert() + .success(); + + let t = TempDir::new().unwrap(); + ProjectBuilder::start() + .lib_cairo(code) + .edition("2023_10") + .build(&t); + + Scarb::quick_snapbox() + .arg("build") + .current_dir(&t) + .assert() + .failure(); +} + +#[test] +fn edition_must_exist() { + let t = TempDir::new().unwrap(); + ProjectBuilder::start().edition("2021").build(&t); + + Scarb::quick_snapbox() + .arg("fetch") + .current_dir(&t) + .assert() + .failure() + .stdout_matches(indoc! {r#" + error: failed to parse manifest at: /[..]/Scarb.toml + + Caused by: + TOML parse error at line 4, column 11 + | + 4 | edition = "2021" + | ^^^^^^ + unknown variant `2021`, expected `2023_01` or `2023_10` + "#}); +} diff --git a/scarb/tests/local_registry.rs b/scarb/tests/local_registry.rs index 62688c983..bc4be0da7 100644 --- a/scarb/tests/local_registry.rs +++ b/scarb/tests/local_registry.rs @@ -179,7 +179,7 @@ fn publish() { { "v": "1.0.0", "deps": [], - "cksum": "sha256:13973a8c7a6d86430ad569fd2c2d5cad282ba67ee587820a4b597f7b0a66a8dd", + "cksum": "sha256:d891504afc86fc0a7a9f38533a66ef2763990a1ff4be3eb9d5836d32a9bd9ad3", } ]) ); @@ -192,12 +192,12 @@ fn publish() { { "v": "1.0.0", "deps": [], - "cksum": "sha256:032b626571a86bb18d93d6e67376d5c9b5a14efd76871bb5e3de4b1ded3c6c64", + "cksum": "sha256:d05d4c524aa0136e42df6138f8e97f8b2b7fc946911cef8ae40baf38acf87ef6", }, { "v": "1.1.0", "deps": [], - "cksum": "sha256:0b9c792212d383b00b3b059461caa1bea64b1528890d54f95ea678d2956ec613", + "cksum": "sha256:ec55410dac39c63ea1372f44f05b74bcf14ec6305749d80bd607be0603271ef1", } ]) ); @@ -230,7 +230,7 @@ fn publish_overwrites_existing() { { "v": "1.0.0", "deps": [], - "cksum": "sha256:d3356ff99d397d9963f88318b4c0019b61037255a9a632cc1fe24b9aa876a607", + "cksum": "sha256:49bb7566594c89da4603578aebe812d750d1fefa1fccc532461963d813093b11", } ]) ); @@ -258,7 +258,7 @@ fn publish_overwrites_existing() { { "v": "1.0.0", "deps": [], - "cksum": "sha256:207317e685713fcda79fa2172b5d3ca8d138efc7cee3c6c0960a17ba980738bd", + "cksum": "sha256:f6555b5b27327d40196578005de811158a3ac7401c36c13ee02b27afe7aab00f", } ]) ); diff --git a/scarb/tests/metadata.rs b/scarb/tests/metadata.rs index 17d772465..319d48517 100644 --- a/scarb/tests/metadata.rs +++ b/scarb/tests/metadata.rs @@ -934,7 +934,7 @@ fn infer_readme_workspace() { [package] name = "t7" version.workspace = true - edition = "2021" + edition = "2023_10" readme.workspace = true "#, ) @@ -956,7 +956,7 @@ fn infer_readme_workspace() { [workspace.package] version = "0.1.0" - edition = "2021" + edition = "2023_10" readme = "MEREAD.md" [package] @@ -974,7 +974,7 @@ fn infer_readme_workspace() { [package] name = "t1" version.workspace = true - edition = "2021" + edition = "2023_10" readme.workspace = true "#, ) @@ -986,7 +986,7 @@ fn infer_readme_workspace() { [package] name = "t2" version.workspace = true - edition = "2021" + edition = "2023_10" readme = true "#, ) @@ -998,7 +998,7 @@ fn infer_readme_workspace() { [package] name = "t3" version.workspace = true - edition = "2021" + edition = "2023_10" "#, ) .unwrap(); @@ -1009,7 +1009,7 @@ fn infer_readme_workspace() { [package] name = "t4" version.workspace = true - edition = "2021" + edition = "2023_10" readme = "TEST.txt" "#, ) @@ -1021,7 +1021,7 @@ fn infer_readme_workspace() { [package] name = "t5" version.workspace = true - edition = "2021" + edition = "2023_10" readme = false "#, ) @@ -1033,7 +1033,7 @@ fn infer_readme_workspace() { [package] name = "t6" version.workspace = true - edition = "2021" + edition = "2023_10" "#, ) .unwrap(); @@ -1046,7 +1046,7 @@ fn infer_readme_workspace() { [package] name = "t7" version.workspace = true - edition = "2021" + edition = "2023_10" readme.workspace = true "#, ) @@ -1112,3 +1112,29 @@ fn infer_readme_workspace() { assert_eq!(packages.get("t5").unwrap().manifest_metadata.readme, None); assert_eq!(packages.get("t6").unwrap().manifest_metadata.readme, None); } + +#[test] +fn includes_edition() { + let t = assert_fs::TempDir::new().unwrap(); + ProjectBuilder::start() + .name("hello") + .version("0.1.0") + .edition("2023_10") + .build(&t); + + let metadata = Scarb::quick_snapbox() + .arg("--json") + .arg("metadata") + .arg("--format-version") + .arg("1") + .current_dir(&t) + .stdout_json::(); + + for package in metadata.packages { + if package.name == "hello" { + assert_eq!(package.edition, Some("2023_10".to_string())); + return; + } + } + panic!("Package not found in metadata!"); +} diff --git a/scarb/tests/package.rs b/scarb/tests/package.rs index af015babf..061b6e2e6 100644 --- a/scarb/tests/package.rs +++ b/scarb/tests/package.rs @@ -209,6 +209,7 @@ fn simple() { [package] name = "foo" version = "1.0.0" + edition = "2023_01" [dependencies] "#}, @@ -356,6 +357,7 @@ fn generated_manifest() { [package] name = "hello" version = "1.0.0" + edition = "2023_01" [dependencies.git_dep] version = "^0.2.0" @@ -454,6 +456,7 @@ fn workspace() { [package] name = "hello" version = "1.0.0" + edition = "2023_01" [dependencies.path_dep] version = "^1.0.0" diff --git a/utils/scarb-test-support/src/project_builder.rs b/utils/scarb-test-support/src/project_builder.rs index d627886f0..5d5877d7d 100644 --- a/utils/scarb-test-support/src/project_builder.rs +++ b/utils/scarb-test-support/src/project_builder.rs @@ -19,6 +19,7 @@ mod to_version; pub struct ProjectBuilder { name: String, version: Version, + edition: Option, cairo_version: Option, src: HashMap, deps: Vec<(String, Value)>, @@ -34,6 +35,7 @@ impl ProjectBuilder { Self { name: format!("pkg{n}"), version: Version::new(1, n, 0), + edition: None, cairo_version: None, src: HashMap::from_iter([( Utf8PathBuf::from("src/lib.cairo"), @@ -54,6 +56,11 @@ impl ProjectBuilder { self } + pub fn edition(mut self, edition: impl ToString) -> Self { + self.edition = Some(edition.to_string()); + self + } + pub fn cairo_version(mut self, cairo_version: impl ToVersion) -> Self { self.cairo_version = Some(cairo_version.to_version().unwrap()); self @@ -91,6 +98,9 @@ impl ProjectBuilder { doc["package"] = toml_edit::table(); doc["package"]["name"] = Item::Value(Value::from(self.name.clone())); doc["package"]["version"] = Item::Value(Value::from(self.version.to_string())); + if let Some(edition) = self.edition.as_ref() { + doc["package"]["edition"] = Item::Value(Value::from(edition.to_string())); + } if let Some(cairo_version) = self.cairo_version.as_ref() { doc["package"]["cairo-version"] = Item::Value(Value::from(cairo_version.to_string())); }