Skip to content

Commit

Permalink
refactor(crates-io): use toml_edit instead of cargo_toml (#3581)
Browse files Browse the repository at this point in the history
  • Loading branch information
clearloop authored Dec 14, 2023
1 parent 665d74b commit d684632
Show file tree
Hide file tree
Showing 10 changed files with 219 additions and 159 deletions.
7 changes: 5 additions & 2 deletions .github/workflows/crates-io.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ on:
description: "If publish packages"
type: boolean
default: false
version:
description: "Workspace version to publish"
type: string
pull_request:
branches: [master]

Expand All @@ -29,8 +32,8 @@ jobs:
uses: dsherret/rust-toolchain-file@v1

- name: "Check packages"
run: cargo run --release -p crates-io-manager check
run: cargo run --release -p crates-io check

- name: "Publish packages"
if: ${{ github.event_name == 'workflow_dispatch' && inputs.publish }}
run: cargo run --release -p crates-io-manager publish
run: cargo run --release -p crates-io publish -v ${{ inputs.version }}
32 changes: 16 additions & 16 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 1 addition & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -445,9 +445,7 @@ fail = "0.5" # gear
scale-value = "^0.12" # gsdk
heck = "0.4.1" # gsdk-api-gen
etc = "0.1.16" # gcli
cargo_toml = "0.15.3" # crates-io
crates-io = "0.37.0" # crates-io
curl = "0.4.44" # crates-io
toml_edit = "0.21.0" # crates-io
scale-decode = "0.9.0" # gsdk
directories = "5.0.1" # utils/key-finder
num-traits = { version = "0.2", default-features = false } # gear-core
Expand Down
7 changes: 3 additions & 4 deletions utils/crates-io/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
[package]
name = "crates-io-manager"
name = "crates-io"
version.workspace = true
edition.workspace = true

[dependencies]
anyhow.workspace = true
cargo_metadata.workspace = true
cargo_toml.workspace = true
clap = { workspace = true, features = ["derive"] }
reqwest = { workspace = true, features = ["blocking", "json", "default-tls"] }
serde = { workspace = true, features = ["derive"] }
toml.workspace = true
reqwest = { workspace = true, features = ["blocking", "json", "default-tls"] }
toml_edit.workspace = true
3 changes: 1 addition & 2 deletions utils/crates-io/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,9 @@

mod manifest;
mod publisher;
pub mod rename;
mod version;

pub use self::{manifest::ManifestWithPath, publisher::Publisher, version::verify};
pub use self::{manifest::Manifest, publisher::Publisher, version::verify};
use anyhow::Result;
use std::process::{Command, ExitStatus};

Expand Down
20 changes: 15 additions & 5 deletions utils/crates-io/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,21 @@
use anyhow::Result;
use clap::Parser;
use crates_io_manager::Publisher;
use crates_io::Publisher;

/// The command to run.
#[derive(Clone, Debug, Parser)]
enum Command {
/// Build manifests for packages that to be published.
Build,
/// Check packages that to be published.
Check,
/// Publish packages.
Publish,
Publish {
/// The version to publish.
#[clap(long, short)]
version: Option<String>,
},
}

/// Gear crates-io manager command line interface
Expand All @@ -44,9 +50,13 @@ pub struct Opt {
fn main() -> Result<()> {
let Opt { command } = Opt::parse();

let publisher = Publisher::new()?.build()?;
let publisher = Publisher::new()?;
match command {
Command::Check => publisher.check(),
Command::Publish => publisher.publish(),
Command::Check => publisher.build(None)?.check(),
Command::Publish { version } => publisher.build(version)?.publish(),
Command::Build => {
publisher.build(None)?;
Ok(())
}
}
}
156 changes: 138 additions & 18 deletions utils/crates-io/src/manifest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,24 +18,26 @@

//! Manifest utils for crates-io-manager
use anyhow::Result;
use cargo_toml::{Manifest, Value};
use std::{
fs,
path::{Path, PathBuf},
};
use anyhow::{anyhow, Result};
use cargo_metadata::Package;
use std::{fs, path::PathBuf};
use toml_edit::Document;

use crate::version;

const WORKSPACE_NAME: &str = "__gear_workspace";

/// Cargo manifest with path
pub struct ManifestWithPath {
pub struct Manifest {
/// Crate name
pub name: String,
/// Cargo manifest
pub manifest: Manifest,
pub manifest: Document,
/// Path of the manifest
pub path: PathBuf,
}

impl ManifestWithPath {
impl Manifest {
/// Get the workspace manifest
pub fn workspace() -> Result<Self> {
let path = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
Expand All @@ -46,23 +48,141 @@ impl ManifestWithPath {
.canonicalize()?;

Ok(Self {
name: "__gear_workspace".into(),
manifest: Manifest::from_path(&path)?,
name: WORKSPACE_NAME.to_string(),
manifest: fs::read_to_string(&path)?.parse()?,
path,
})
}

/// Complete the manifest of the specified crate from
/// the current manifest
pub fn manifest(&self, path: impl AsRef<Path>) -> Result<Self> {
let mut manifest = Manifest::<Value>::from_slice_with_metadata(&fs::read(&path)?)?;
manifest
.complete_from_path_and_workspace(path.as_ref(), Some((&self.manifest, &self.path)))?;
/// the workspace manifest
pub fn manifest(&self, pkg: &Package) -> Result<Self> {
self.ensure_workspace()?;

// Complete documentation as from <https://docs.rs>
let mut manifest: Document = fs::read_to_string(&pkg.manifest_path)?.parse()?;
let name = pkg.name.clone();
manifest["package"]["documentation"] = toml_edit::value(format!("https://docs.rs/{name}"));

Ok(Self {
name: manifest.package.clone().map(|p| p.name).unwrap_or_default(),
name,
manifest,
path: path.as_ref().to_path_buf(),
path: pkg.manifest_path.clone().into(),
})
}

/// complete the versions of the specified crates
pub fn complete_versions(&mut self, index: &[&str]) -> Result<()> {
self.ensure_workspace()?;

let version = self.manifest["workspace"]["package"]["version"]
.clone()
.as_str()
.ok_or_else(|| anyhow!("Could not find version in workspace manifest"))?
.to_string();

let Some(deps) = self.manifest["workspace"]["dependencies"].as_table_mut() else {
return Err(anyhow!(
"Failed to parse dependencies from workspace {}",
self.path.display()
));
};

for (key, dep) in deps.iter_mut() {
let name = key.get();
if !index.contains(&name) {
continue;
}

dep["version"] = toml_edit::value(version.clone());
}

self.rename_deps()?;
Ok(())
}

/// Set version for the workspace.
pub fn with_version(mut self, version: Option<String>) -> Result<Self> {
self.ensure_workspace()?;

let version = if let Some(version) = version {
version
} else {
self.version()? + "-" + &version::hash()?
};

self.manifest["workspace"]["package"]["version"] = toml_edit::value(version);

Ok(self)
}

/// Get version from the current manifest.
pub fn version(&self) -> Result<String> {
self.ensure_workspace()?;

Ok(self.manifest["workspace"]["package"]["version"]
.as_str()
.ok_or_else(|| {
anyhow!(
"Could not find version in workspace manifest: {}",
self.path.display()
)
})?
.to_string())
}

/// Write manifest to disk.
pub fn write(&self) -> Result<()> {
fs::write(&self.path, self.manifest.to_string()).map_err(Into::into)
}

/// Rename dependencies
fn rename_deps(&mut self) -> Result<()> {
self.ensure_workspace()?;

let Some(deps) = self.manifest["workspace"]["dependencies"].as_table_like_mut() else {
return Ok(());
};

for (name, dep) in deps.iter_mut() {
let name = name.get();
if !name.starts_with("sp-") {
continue;
}

// Format dotted values into inline table.
if let Some(table) = dep.as_table_mut() {
table.remove("branch");
table.remove("git");
table.remove("workspace");

if name == "sp-arithmetic" {
// NOTE: the required version of sp-arithmetic is 6.0.0 in
// git repo, but 7.0.0 in crates.io, so we need to fix it.
table.insert("version", toml_edit::value("7.0.0"));
}

// Force the dep to be inline table in case of losing
// documentation.
let mut inline = table.clone().into_inline_table();
inline.fmt();
*dep = toml_edit::value(inline);
};
}

Ok(())
}

/// Ensure the current function is called on the workspace manifest
///
/// TODO: remove this interface after #3565
fn ensure_workspace(&self) -> Result<()> {
if self.name != WORKSPACE_NAME {
return Err(anyhow!(
"This method can only be called on the workspace manifest"
));
}

Ok(())
}
}
Loading

0 comments on commit d684632

Please sign in to comment.