Skip to content

Commit

Permalink
Pull Cairo crate names from starkware-libs/cairo (#2)
Browse files Browse the repository at this point in the history
* pull_cairo_packages_from_cairo_repository

* .
  • Loading branch information
mkaput authored Dec 11, 2024
1 parent cb3d872 commit 1448971
Showing 1 changed file with 76 additions and 53 deletions.
129 changes: 76 additions & 53 deletions src/upgrade.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
//! Update toolchain crates properly.
use anyhow::Result;
use anyhow::{bail, Result};
use clap::{Parser, ValueEnum};
use semver::Version;
use std::mem;
use std::path::PathBuf;
use std::sync::OnceLock;
use toml_edit::{DocumentMut, InlineTable, Value};
use xshell::{cmd, Shell};

Expand All @@ -29,7 +30,7 @@ enum DepName {
CairoLS,
}

#[derive(clap::Args, Clone)]
#[derive(clap::Args, Clone, Default)]
#[group(required = true, multiple = true)]
struct Spec {
/// Source the dependency from crates.io and use a specific version.
Expand Down Expand Up @@ -86,7 +87,7 @@ fn edit_dependencies(cargo_toml: &mut DocumentMut, table_path: &str, args: &Args
}
let deps = deps.as_table_mut().unwrap();

for (_, dep) in deps.iter_mut().filter(|(key, _)| args.dep.owns(key)) {
for (_, dep) in deps.iter_mut().filter(|(key, _)| args.tool_owns_crate(key)) {
let dep = dep.as_value_mut().unwrap();

// Always use crates.io requirements so that we can reliably patch them with the
Expand All @@ -109,7 +110,7 @@ fn edit_dependencies(cargo_toml: &mut DocumentMut, table_path: &str, args: &Args
deps.sort_values();

eprintln!("[{table_path}]");
for (key, dep) in deps.iter().filter(|(key, _)| args.dep.owns(key)) {
for (key, dep) in deps.iter().filter(|(key, _)| args.tool_owns_crate(key)) {
eprintln!("{key} = {dep}");
}
}
Expand All @@ -120,20 +121,20 @@ fn edit_patch(cargo_toml: &mut DocumentMut, args: &Args) {
.unwrap();

// Clear any existing entries for this dependency.
for crate_name in args.dep.crates() {
for crate_name in args.tool_crates() {
patch.remove(crate_name);
}

// Leave this section as-if if we are requested to just use a specific version.
if args.spec.rev.is_some() || args.spec.branch.is_some() || args.spec.path.is_some() {
// Patch all Cairo crates that exist, even if this project does not directly depend on them,
// to avoid any duplicates in transient dependencies.
for &dep_name in args.dep.crates() {
for &dep_name in args.tool_crates() {
let mut dep = InlineTable::new();

// Add a Git branch or revision reference if requested.
if args.spec.rev.is_some() || args.spec.branch.is_some() {
dep.insert("git", args.dep.repo().into());
dep.insert("git", args.tool_repo().into());
}

if let Some(branch) = &args.spec.branch {
Expand Down Expand Up @@ -171,58 +172,27 @@ fn edit_patch(cargo_toml: &mut DocumentMut, args: &Args) {
}
}

impl DepName {
fn crates(&self) -> &'static [&'static str] {
match self {
DepName::Cairo => {
// List of library crates published from the starkware-libs/cairo repository.
// One can get this list from the `scripts/release_crates.sh` script in that repo.
// Keep this list sorted for better commit diffs.
&[
"cairo-lang-casm",
"cairo-lang-compiler",
"cairo-lang-debug",
"cairo-lang-defs",
"cairo-lang-diagnostics",
"cairo-lang-doc",
"cairo-lang-eq-solver",
"cairo-lang-executable",
"cairo-lang-filesystem",
"cairo-lang-formatter",
"cairo-lang-lowering",
"cairo-lang-parser",
"cairo-lang-plugins",
"cairo-lang-proc-macros",
"cairo-lang-project",
"cairo-lang-runnable-utils",
"cairo-lang-runner",
"cairo-lang-semantic",
"cairo-lang-sierra",
"cairo-lang-sierra-ap-change",
"cairo-lang-sierra-gas",
"cairo-lang-sierra-generator",
"cairo-lang-sierra-to-casm",
"cairo-lang-sierra-type-size",
"cairo-lang-starknet",
"cairo-lang-starknet-classes",
"cairo-lang-syntax",
"cairo-lang-syntax-codegen",
"cairo-lang-test-plugin",
"cairo-lang-test-runner",
"cairo-lang-test-utils",
"cairo-lang-utils",
]
}
impl Args {
fn tool_crates(&self) -> &'static [&'static str] {
static CAIRO_CACHE: OnceLock<Vec<&str>> = OnceLock::new();
match self.dep {
DepName::Cairo => CAIRO_CACHE.get_or_init(|| {
pull_cairo_packages_from_cairo_repository(&self.spec)
.unwrap()
.into_iter()
.map(|s| s.leak() as &str)
.collect()
}),
DepName::CairoLS => &["cairo-language-server"],
}
}

fn owns(&self, crate_name: &str) -> bool {
self.crates().contains(&crate_name)
fn tool_owns_crate(&self, crate_name: &str) -> bool {
self.tool_crates().contains(&crate_name)
}

fn repo(&self) -> &'static str {
match self {
fn tool_repo(&self) -> &'static str {
match self.dep {
DepName::Cairo => "https://github.com/starkware-libs/cairo",
DepName::CairoLS => "https://github.com/software-mansion/cairols",
}
Expand Down Expand Up @@ -286,3 +256,56 @@ fn find_unused_patches(cargo_lock: &DocumentMut) -> Option<Vec<String>> {
.collect(),
)
}

/// Pulls names of crates published from the `starkware-libs/cairo` repository.
///
/// The list is obtained by parsing the `scripts/release_crates.sh` script in that repo.
/// The resulting vector is sorted alphabetically.
fn pull_cairo_packages_from_cairo_repository(spec: &Spec) -> Result<Vec<String>> {
let sh = Shell::new()?;

let release_crates_sh = if let Some(path) = &spec.path {
sh.read_file(path.join("scripts").join("release_crates.sh"))?
} else {
let rev = if let Some(version) = &spec.version {
format!("refs/tags/v{version}")
} else if let Some(rev) = &spec.rev {
rev.to_string()
} else if let Some(branch) = &spec.branch {
format!("refs/heads/{branch}")
} else {
"refs/heads/main".to_string()
};
let url = format!("https://raw.githubusercontent.com/starkware-libs/cairo/{rev}/scripts/release_crates.sh");
cmd!(sh, "curl -sSfL {url}").read()?
};

let Some((_, source_list)) = release_crates_sh.split_once("CRATES_TO_PUBLISH=(") else {
bail!("failed to extract start of `CRATES_TO_PUBLISH` from `scripts/release_crates.sh`");
};
let Some((source_list, _)) = source_list.split_once(")") else {
bail!("failed to extract end of `CRATES_TO_PUBLISH` from `scripts/release_crates.sh`");
};

let mut crates: Vec<String> = source_list
.split_whitespace()
.filter(|s| s.starts_with("cairo-lang-"))
.map(|s| s.into())
.collect();
crates.sort();
Ok(crates)
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_pull_cairo_packages_from_cairo_repository() {
let list = pull_cairo_packages_from_cairo_repository(&Spec::default()).unwrap();
assert!(!list.is_empty());
assert!(list.contains(&"cairo-lang-compiler".to_owned()));
assert!(!list.contains(&"cairo-test".to_owned()));
assert!(list.is_sorted());
}
}

0 comments on commit 1448971

Please sign in to comment.