mirror of
https://github.com/m5stack/CardputerZero-AppBuilder.git
synced 2026-05-20 11:51:57 -07:00
feat(czdev): add bump command + install docs in README
czdev bump: queries published versions, shows next patch version. README: added install instructions and publish workflow. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
ca6d6fbfc4
commit
34e3f771cd
@@ -145,6 +145,54 @@ cargo run -p czdev --release -- deploy \
|
||||
--deb path/to/my_app_arm64.deb
|
||||
```
|
||||
|
||||
### 8. Publishing to the AppStore
|
||||
|
||||
```bash
|
||||
# Install czdev (one-time, or build from source: cargo build --release -p czdev)
|
||||
curl -fsSL https://github.com/m5stack/CardputerZero-AppBuilder/releases/latest/download/czdev-macos-aarch64 -o czdev
|
||||
chmod +x czdev && sudo mv czdev /usr/local/bin/
|
||||
|
||||
# Login to GitHub (one-time)
|
||||
czdev login
|
||||
|
||||
# Auto-bump patch version and publish
|
||||
czdev bump --deb build/my_app_1.0.0_arm64.deb # → my_app_1.0.1_arm64.deb
|
||||
czdev publish --deb build/my_app_1.0.1_arm64.deb
|
||||
|
||||
# Or publish directly (version in deb must be newer than existing)
|
||||
czdev publish --deb build/my_app_2.0.0_arm64.deb
|
||||
|
||||
# Remove your own package
|
||||
czdev unpublish my_app --version 1.0.1
|
||||
```
|
||||
|
||||
## Install czdev
|
||||
|
||||
**Option A — Download prebuilt binary (recommended):**
|
||||
|
||||
| Platform | Command |
|
||||
|----------|---------|
|
||||
| macOS Apple Silicon | `curl -fsSL https://github.com/m5stack/CardputerZero-AppBuilder/releases/latest/download/czdev-macos-aarch64 -o czdev && chmod +x czdev && sudo mv czdev /usr/local/bin/` |
|
||||
| macOS Intel | `curl -fsSL .../czdev-macos-x86_64 -o czdev && chmod +x czdev && sudo mv czdev /usr/local/bin/` |
|
||||
| Linux x86_64 | `curl -fsSL .../czdev-linux-x86_64 -o czdev && chmod +x czdev && sudo mv czdev /usr/local/bin/` |
|
||||
| Linux aarch64 | `curl -fsSL .../czdev-linux-aarch64 -o czdev && chmod +x czdev && sudo mv czdev /usr/local/bin/` |
|
||||
| Windows | Download `czdev-windows-x86_64.exe` from [Releases](https://github.com/m5stack/CardputerZero-AppBuilder/releases) |
|
||||
|
||||
**Option B — Build from source:**
|
||||
|
||||
```bash
|
||||
git clone --recursive git@github.com:m5stack/CardputerZero-AppBuilder.git
|
||||
cd CardputerZero-AppBuilder
|
||||
cargo build --release -p czdev
|
||||
# Binary at: target/release/czdev
|
||||
```
|
||||
|
||||
**Option C — cargo install:**
|
||||
|
||||
```bash
|
||||
cargo install --git https://github.com/m5stack/CardputerZero-AppBuilder czdev
|
||||
```
|
||||
|
||||
## CI Online Build
|
||||
|
||||
1. Go to **Actions** > **Build DEB Package** > **Run workflow**
|
||||
|
||||
@@ -0,0 +1,129 @@
|
||||
use anyhow::{anyhow, Context, Result};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::Command;
|
||||
|
||||
const PACKAGES_INDEX_URL: &str =
|
||||
"https://cardputerzero.github.io/packages/dists/stable/main/binary-arm64/Packages";
|
||||
|
||||
pub fn run(deb: Option<&Path>) -> Result<()> {
|
||||
let deb_path = resolve_deb(deb)?;
|
||||
|
||||
let package = dpkg_field(&deb_path, "Package")?;
|
||||
let current_ver = dpkg_field(&deb_path, "Version")?;
|
||||
|
||||
println!("Package: {package}");
|
||||
println!("Current version in deb: {current_ver}");
|
||||
|
||||
// Fetch latest published version
|
||||
let latest = fetch_latest_version(&package)?;
|
||||
let next = match &latest {
|
||||
Some(v) => {
|
||||
println!("Latest published version: {v}");
|
||||
bump_patch(v)
|
||||
}
|
||||
None => {
|
||||
println!("No published version found (new package)");
|
||||
bump_patch(¤t_ver)
|
||||
}
|
||||
};
|
||||
|
||||
println!();
|
||||
println!("Next version: {next}");
|
||||
println!();
|
||||
println!("To rebuild with this version, update your package control file:");
|
||||
println!(" Version: {next}");
|
||||
println!();
|
||||
println!("Or if using CMake/packaging scripts, set:");
|
||||
println!(" PKG_VERSION={next}");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn resolve_deb(deb: Option<&Path>) -> Result<PathBuf> {
|
||||
if let Some(p) = deb {
|
||||
if !p.is_file() {
|
||||
return Err(anyhow!("file not found: {}", p.display()));
|
||||
}
|
||||
return Ok(p.to_path_buf());
|
||||
}
|
||||
let build_dir = Path::new("build");
|
||||
if build_dir.is_dir() {
|
||||
let mut debs: Vec<_> = std::fs::read_dir(build_dir)?
|
||||
.filter_map(|e| e.ok())
|
||||
.filter(|e| e.path().extension().map(|x| x == "deb").unwrap_or(false))
|
||||
.collect();
|
||||
if debs.len() == 1 {
|
||||
return Ok(debs.remove(0).path());
|
||||
}
|
||||
if debs.len() > 1 {
|
||||
return Err(anyhow!(
|
||||
"multiple .deb files in build/. Specify one with --deb <path>"
|
||||
));
|
||||
}
|
||||
}
|
||||
Err(anyhow!("no .deb file found. Specify with --deb <path>"))
|
||||
}
|
||||
|
||||
fn dpkg_field(deb: &Path, field: &str) -> Result<String> {
|
||||
let output = Command::new("dpkg-deb")
|
||||
.args(["-f", &deb.to_string_lossy(), field])
|
||||
.output()
|
||||
.with_context(|| format!("dpkg-deb -f {field}"))?;
|
||||
Ok(String::from_utf8_lossy(&output.stdout).trim().to_string())
|
||||
}
|
||||
|
||||
fn fetch_latest_version(package: &str) -> Result<Option<String>> {
|
||||
let resp = reqwest::blocking::get(PACKAGES_INDEX_URL);
|
||||
let content = match resp {
|
||||
Ok(r) if r.status().is_success() => r.text().unwrap_or_default(),
|
||||
_ => return Ok(None),
|
||||
};
|
||||
|
||||
let mut in_package = false;
|
||||
let mut latest: Option<String> = None;
|
||||
|
||||
for line in content.lines() {
|
||||
if line.starts_with("Package: ") {
|
||||
in_package = line.trim_start_matches("Package: ") == package;
|
||||
}
|
||||
if in_package && line.starts_with("Version: ") {
|
||||
let ver = line.trim_start_matches("Version: ").to_string();
|
||||
match &latest {
|
||||
Some(existing) if compare_versions(&ver, existing) == std::cmp::Ordering::Greater => {
|
||||
latest = Some(ver);
|
||||
}
|
||||
None => latest = Some(ver),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
if line.is_empty() {
|
||||
in_package = false;
|
||||
}
|
||||
}
|
||||
Ok(latest)
|
||||
}
|
||||
|
||||
fn bump_patch(version: &str) -> String {
|
||||
// Handle versions like "1.0.0", "1.0", "0.2.0-1~lofibox23"
|
||||
// Strip debian revision (everything after first '-')
|
||||
let base = version.split('-').next().unwrap_or(version);
|
||||
let parts: Vec<&str> = base.split('.').collect();
|
||||
|
||||
match parts.len() {
|
||||
1 => format!("{}.0.1", parts[0]),
|
||||
2 => format!("{}.{}.1", parts[0], parts[1]),
|
||||
_ => {
|
||||
let patch: u64 = parts[2].parse().unwrap_or(0);
|
||||
format!("{}.{}.{}", parts[0], parts[1], patch + 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn compare_versions(a: &str, b: &str) -> std::cmp::Ordering {
|
||||
let parse = |v: &str| -> Vec<u64> {
|
||||
v.split(|c: char| c == '.' || c == '-' || c == '~')
|
||||
.filter_map(|s| s.parse::<u64>().ok())
|
||||
.collect()
|
||||
};
|
||||
parse(a).cmp(&parse(b))
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
mod auth;
|
||||
mod build;
|
||||
mod bump;
|
||||
mod deploy;
|
||||
mod doctor;
|
||||
mod github;
|
||||
@@ -73,6 +74,13 @@ enum Command {
|
||||
/// Remove stored GitHub credentials.
|
||||
Logout,
|
||||
|
||||
/// Show next version (patch bump) for a package based on published versions.
|
||||
Bump {
|
||||
/// Path to the .deb file. If omitted, searches ./build/*.deb
|
||||
#[arg(long)]
|
||||
deb: Option<PathBuf>,
|
||||
},
|
||||
|
||||
/// Publish a .deb package to the CardputerZero app store.
|
||||
Publish {
|
||||
/// Path to the .deb file. If omitted, searches ./build/*.deb
|
||||
@@ -107,6 +115,7 @@ fn main() -> Result<()> {
|
||||
Command::Deploy { path, host, deb } => deploy::run(&path, host.as_deref(), deb.as_deref()),
|
||||
Command::Login => auth::login(),
|
||||
Command::Logout => auth::logout(),
|
||||
Command::Bump { deb } => bump::run(deb.as_deref()),
|
||||
Command::Publish { deb } => publish::run(deb.as_deref()),
|
||||
Command::Unpublish {
|
||||
package,
|
||||
|
||||
Reference in New Issue
Block a user