Rewrite `publish.sh` script in Rust language (#556)

This commit is contained in:
Luni-4 2023-07-28 18:51:41 +02:00 committed by GitHub
parent aa4af29e3f
commit 7dbd43d111
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 162 additions and 55 deletions

View File

@ -18,7 +18,10 @@ jobs:
- name: install rust
uses: dtolnay/rust-toolchain@stable
- name: compile publish binary
run: rustc scripts/publish.rs --crate-type bin --out-dir scripts
- name: publish to crates.io
run: ./scripts/publish.sh ${{ inputs.crate }}
run: ./scripts/publish ${{ inputs.crate }}
env:
CRATES_IO_API_TOKEN: ${{ secrets.CRATES_IO_API_TOKEN }}

View File

@ -281,6 +281,16 @@ recommended to read our
[architecture document](https://github.com/burn-rs/burn/tree/main/ARCHITECTURE.md), which explains
our architectural decisions. Please see more details in our [contributing guide](/CONTRIBUTING.md).
## CI
### Publish crates
Compile `scripts/publish.rs` using this command:
```
rustc scripts/publish.rs --crate-type bin --out-dir scripts
```
## Disclamer
Burn is currently in active development, and there will be breaking changes. While any resulting

148
scripts/publish.rs Normal file
View File

@ -0,0 +1,148 @@
//! This script publishes a crate on `crates.io`.
//!
//! To build this script, run the following command:
//!
//! rustc scripts/publish.rs --crate-type bin --out-dir scripts
//!
//! To run the script:
//!
//! ./scripts/publish crate_name
use std::env;
use std::io::{self, Write};
use std::process::{Command, Output};
use std::str;
// Crates.io API token
const CRATES_IO_API_TOKEN: &str = "CRATES_IO_API_TOKEN";
// Obtain local crate version
fn local_version(crate_name: &str) -> String {
// Obtain local crate version contained in cargo pkgid data
let cargo_pkgid_output = Command::new("cargo")
.args(["pkgid", "-p", crate_name])
.output()
.expect("Failed to run cargo pkgid");
// Convert cargo pkgid output into a str
let cargo_pkgid_str = str::from_utf8(&cargo_pkgid_output.stdout)
.expect("Failed to convert pkgid output into a str");
// Extract only the local crate version from str
let (_, local_version) = cargo_pkgid_str
.split_once('#')
.expect("Failed to get local crate version");
local_version.trim_end().to_string()
}
// Obtain remote crate version
fn remote_version(crate_name: &str) -> Option<String> {
// Obtain remote crate version contained in cargo search data
let cargo_search_output = Command::new("cargo")
.args(["search", crate_name, "--limit", "1"])
.output()
.expect("Failed to run cargo search");
// Cargo search returns an empty string in case of a crate not present on
// crates.io
if cargo_search_output.stdout.is_empty() {
None
} else {
// Convert cargo search output into a str
let remote_version_str = str::from_utf8(&cargo_search_output.stdout)
.expect("Failed to convert cargo search output into a str");
// Extract only the remote crate version from str
remote_version_str
.split_once('=')
.and_then(|(_, second)| second.trim_start().split_once(' '))
.map(|(s, _)| s.trim_matches('"').to_string())
}
}
// If stdout is not empty, write it, otherwise
// write stderr and exit with code error 1
fn stdout_and_stderr_write(output: Output, message_stdout: &str, message_stderr: &str) {
if !output.stdout.is_empty() {
io::stdout()
.write_all(&output.stdout)
.expect(message_stdout);
}
if !output.stderr.is_empty() {
io::stderr()
.write_all(&output.stderr)
.expect(message_stderr);
std::process::exit(1);
}
}
// Publishes a crate
fn publish(crate_name: String) {
// Run cargo publish --dry-run
let cargo_publish_dry = Command::new("cargo")
.args(["publish", "-p", &crate_name, "--dry-run"])
.output()
.expect("Failed to run cargo publish --dry-run");
// Write cargo publish --dry-run either on stdout or on stderr
stdout_and_stderr_write(
cargo_publish_dry,
"Failed to write cargo publish --dry-run on stdout",
"Failed to write cargo publish --dry-run on stderr",
);
let crates_io_token =
env::var(CRATES_IO_API_TOKEN).expect("Failed to retrieve the crates.io API token");
// Publish crate
let cargo_publish = Command::new("cargo")
.args(["publish", "-p", &crate_name, "--token", &crates_io_token])
.output()
.expect("Failed to run cargo publish");
// Write cargo publish either on stdout or on stderr
stdout_and_stderr_write(
cargo_publish,
"Failed to write cargo publish on stdout",
"Failed to write cargo publish on stderr",
);
}
fn main() {
// Get crate name
let crate_name = env::args()
.nth(1) // Index of the first argument, because 0 is the binary name
.expect("You need to pass the crate name as first argument!");
println!("Publishing {crate_name}...\n");
// Retrieve local version for crate
let local_version = local_version(&crate_name);
// Print local version for crate
println!("{crate_name} local version: {local_version}");
// Retrieve remote version for crate
//
// If remote version is None, the crate will be published for the first time
// on crates.io
if let Some(remote_version) = remote_version(&crate_name) {
// Print local version for crate
println!("{crate_name} remote version: {remote_version}\n");
// If local and remote versions are equal, do not publish
if local_version == remote_version {
println!("Remote version {remote_version} is up to date, skipping deployment");
} else {
// Publish crate
publish(crate_name);
}
} else {
// Print crate publishing message
println!("\nFirst time publishing {crate_name} on crates.io!\n");
// Publish crate
publish(crate_name);
}
}

View File

@ -1,54 +0,0 @@
#!/bin/bash
crate=${1}
find_value_inside_quotes() {
text=${1}
value=$(echo ${text} | cut -d'"' -f2)
echo ${value}
}
current_crate_version() {
value=""
while IFS= read -r line; do
case ${line} in "version"*)
value=$(find_value_inside_quotes "${line}")
esac
done < "Cargo.toml"
echo ${value}
}
publish() {
echo "Publishing ${crate} ..."
cd ${crate}
version_local=$(current_crate_version)
version_remote=$(remote_crate_version)
echo " - local version = '${version_local}'"
echo " - remote version = '${version_remote}'"
if [ "${version_local}" == "${version_remote}" ]; then
echo "Remote version ${version_remote} is up to date, skipping deployment"
else
$(cargo publish --token ${CRATES_IO_API_TOKEN})
rc=${?}
if [[ ${rc} != 0 ]]; then
echo "Fail to publish crate ${crate}"
return 1
fi
echo "Sucessfully published ${crate} version ${version_local}"
return 0
fi
}
remote_crate_version() {
text=$(cargo search ${crate} --limit 1)
value=$(find_value_inside_quotes "${text}")
echo ${value}
}
publish || exit 1