Update dependencies, improve CLI asset generation, and add man page

- Bump `git2` from 0.20.4 to 0.21.0 and `rusqlite` from 0.39.0 to 0.40.1 in Cargo.toml.
- Refactor CLI asset generation in `cli_assets.rs` to write a man page directly instead of generating it with `clap_mangen`.
- Implement a function to remove old man pages before writing the new one.
- Add tests to ensure the generated man page documents all visible command paths.
- Update the install script to copy the newly generated man page correctly.
- Introduce a new man page for the `depot` command with comprehensive documentation.
This commit is contained in:
2026-06-10 06:33:39 -05:00
parent 65cec6903a
commit 5b23ea95e0
7 changed files with 783 additions and 359 deletions
Generated
+242 -341
View File
File diff suppressed because it is too large Load Diff
+2 -3
View File
@@ -24,10 +24,10 @@ ar = "0.9.0"
bzip2 = "0.6.1" bzip2 = "0.6.1"
clap = { version = "4.6.0", features = ["derive"] } clap = { version = "4.6.0", features = ["derive"] }
flate2 = "1.1.9" flate2 = "1.1.9"
git2 = "0.20.4" git2 = "0.21.0"
indicatif = "0.18.4" indicatif = "0.18.4"
nix = { version = "0.31.3", features = ["user"] } nix = { version = "0.31.3", features = ["user"] }
rusqlite = "0.39.0" rusqlite = "0.40.1"
semver = "1.0.28" semver = "1.0.28"
serde = { version = "1.0.228", features = ["derive"] } serde = { version = "1.0.228", features = ["derive"] }
yaml-rust2 = "0.11.0" yaml-rust2 = "0.11.0"
@@ -50,7 +50,6 @@ fd-lock = "4.0.4"
reqwest = { version = "0.13.4", default-features = false, features = ["blocking", "native-tls"] } reqwest = { version = "0.13.4", default-features = false, features = ["blocking", "native-tls"] }
filetime = "0.2.29" filetime = "0.2.29"
clap_complete = "4.6.5" clap_complete = "4.6.5"
clap_mangen = "0.3.0"
sys-mount = { version = "3.1.0", default-features = false } sys-mount = { version = "3.1.0", default-features = false }
time = { version = "0.3.47", features = ["formatting", "parsing"] } time = { version = "0.3.47", features = ["formatting", "parsing"] }
b2sum-rust = "0.3.0" b2sum-rust = "0.3.0"
+471
View File
@@ -0,0 +1,471 @@
.TH DEPOT 1 "2026-06-10" "depot 0.50.0" "User Commands"
.SH NAME
depot \- source-based package manager for Linux
.SH SYNOPSIS
.SY depot
.I COMMAND
.RI [ COMMAND_OPTIONS ]
.YS
.SH DESCRIPTION
.B depot
builds, installs, removes, updates, signs, indexes, and queries Depot packages.
Depot commands operate on a root filesystem, using
.B /
by default, and use configured source and binary repositories for dependency and
update resolution.
.SH GLOBAL OPTIONS
.TP
.B \-h, \-\-help
Print help for
.B depot
or for the selected command.
.TP
.B \-V, \-\-version
Print the Depot version.
.SH COMMON OPTIONS
.TP
.B \-r, \-\-rootfs \fIROOTFS\fR
Use a custom root filesystem path. The default is
.BR / .
.TP
.B \-y, \-\-yes
Automatically answer yes to prompts and pick the default provider choice.
.TP
.B \-\-no\-deps
Skip dependency checks.
.TP
.B \-\-no\-flags\fR[\fB=\fITRUE_OR_FALSE\fR]
Do not export
.BR CFLAGS ,
.BR CXXFLAGS ,
or
.B LDFLAGS
to build commands. Accepted values are
.B true
and
.BR false ;
when the option is present without a value it means
.BR true .
.TP
.B \-\-cross\-prefix \fICROSS_PREFIX\fR
Use a cross-compilation prefix such as
.B x86_64-linux-musl
or
.BR aarch64-linux-gnu .
.TP
.B \-\-clean
Clean the build workspace and source cache after a successful install or build.
.TP
.B \-\-dry\-run
Show what would happen without performing builds or installs.
.TP
.B \-\-test\-deps
Install test dependencies alongside build and runtime dependencies.
.TP
.B \-\-lib32\-only
Build or install only the lib32 companion package path, skipping the primary
package output.
.SH COMMANDS
.SS depot install
.SY depot install
.RI [ OPTIONS ]
.RI [ SPEC_OR_ARCHIVE ...]
.YS
Build and install one or more package names, package spec paths
.RB ( .toml ),
or package archives
.RB ( .tar.zst ).
Use
.B \-s, \-\-spec \fISPEC\fR
to explicitly select one spec file instead of positional targets. The visible
alias
.B \-\-package
and compatibility alias
.B \-p
are also accepted.
.PP
Options:
.BR \-r ", " \-\-rootfs ;
.BR \-y ", " \-\-yes ;
.BR \-\-no\-deps ;
.BR \-\-no\-flags ;
.BR \-\-cross\-prefix ;
.BR \-\-clean ;
.BR \-\-dry\-run ;
.BR \-\-test\-deps ;
.BR \-\-lib32\-only ;
.BR \-s ", " \-\-spec .
.SS depot remove
.SY depot remove
.RI [ OPTIONS ]
.I PACKAGE
.YS
Remove an installed package.
.PP
Options:
.BR \-r ", " \-\-rootfs ;
.BR \-y ", " \-\-yes .
.SS depot build
.SY depot build
.RI [ OPTIONS ]
.RI [ SPEC ]
.YS
Build a package without installing it by default. The spec may be positional or
provided with
.B \-s, \-\-spec \fISPEC\fR
using the visible alias
.B \-\-package
or compatibility alias
.BR \-p .
.PP
Options:
.BR \-r ", " \-\-rootfs ;
.BR \-y ", " \-\-yes ;
.BR \-\-no\-deps ;
.BR \-\-no\-flags ;
.BR \-\-cross\-prefix ;
.BR \-\-clean ;
.BR \-\-dry\-run ;
.BR \-\-test\-deps ;
.BR \-\-lib32\-only ;
.BR \-s ", " \-\-spec ;
.BR \-\-install ;
.BR \-\-install\-deps ;
.BR \-\-cleanup\-deps .
.TP
.B \-\-install
Install package archives to the root filesystem after creating them.
.TP
.B \-\-install\-deps
Automatically install missing dependencies before building.
.TP
.B \-\-cleanup\-deps
Remove dependencies auto-installed for this build after the command finishes.
.SS depot update
.SY depot update
.RI [ OPTIONS ]
.RI [ PACKAGE ...]
.YS
Update installed packages from configured repositories. If no package names are
given, Depot checks all installed packages with available upgrades.
.PP
Options:
.BR \-r ", " \-\-rootfs ;
.BR \-y ", " \-\-yes ;
.BR \-\-no\-deps ;
.BR \-\-no\-flags ;
.BR \-\-cross\-prefix ;
.BR \-\-clean ;
.BR \-\-dry\-run ;
.BR \-\-test\-deps .
.SS depot check
.SY depot check
.RI [ DIR ]
.YS
Scan package specs recursively for upstream version updates. The default
directory is
.BR . .
.SS depot info
.SY depot info
.RI [ OPTIONS ]
.I PACKAGE
.YS
Show information about an installed package name or a package spec path.
.PP
Options:
.BR \-r ", " \-\-rootfs .
.SS depot search
.SY depot search
.RI [ OPTIONS ]
.I QUERY
.YS
Search configured source and binary repositories by package name or provides.
.PP
Options:
.BR \-r ", " \-\-rootfs ;
.BR \-\-files .
.TP
.B \-\-files
Search repository file lists from binary repo metadata by path substring.
.SS depot owns
.SY depot owns
.RI [ OPTIONS ]
.I PATH
.YS
Show which installed package owns an absolute path or a path relative to the
root filesystem.
.PP
Options:
.BR \-r ", " \-\-rootfs .
.SS depot list
.SY depot list
.RI [ OPTIONS ]
.YS
List installed packages.
.PP
Options:
.BR \-r ", " \-\-rootfs .
.SS depot sign
.SY depot sign
.RI [ OPTIONS ]
.I FILE
.RI [ FILE ...]
.YS
Create detached minisign signatures for one or more
.B .zst
files.
.PP
Options:
.BR \-r ", " \-\-rootfs .
.SS depot repo
.SY depot repo
.I REPO_COMMAND
.RI [ REPO_OPTIONS ]
.YS
Manage source and binary repositories.
.SS depot repo create
.SY depot repo create
.RI [ OPTIONS ]
.RI [ DIR ]
.YS
Create a repository database from a directory containing
.B .depot.pkg.tar.zst
files. The default directory is
.BR . .
.PP
Options:
.BR \-r ", " \-\-rootfs .
.SS depot repo sync
.SY depot repo sync
.RI [ OPTIONS ]
.YS
Sync git mirrors configured in
.B /etc/depot.d/mirrors.toml
into
.BR /usr/src/depot .
.PP
Options:
.BR \-r ", " \-\-rootfs .
.SS depot repo update
.SY depot repo update
.RI [ OPTIONS ]
.RI [ NAME ]
.YS
Sync source repositories configured in
.B /etc/depot.d/repos.toml
into
.BR /usr/src/depot .
When
.I NAME
is provided, update only that source repo.
.PP
Options:
.BR \-r ", " \-\-rootfs .
.SS depot repo index
.SY depot repo index
.RI [ OPTIONS ]
.RI [ DIR ]
.YS
Create or update a source index at the root of a source repository. The default
directory is
.BR . .
.PP
Options:
.BR \-r ", " \-\-rootfs ;
.BR \-\-subdir .
.TP
.B \-\-subdir \fISUBDIR\fR
Optional source repo subdirectory to scan. May be repeated, for example
.B \-\-subdir core \-\-subdir extra\fR.
.SS depot repo list
.SY depot repo list
.RI [ OPTIONS ]
.YS
List configured source and binary repositories.
.PP
Options:
.BR \-r ", " \-\-rootfs .
.SS depot repo add
.SY depot repo add
.RI [ OPTIONS ]
.I NAME
.I URL
.YS
Add or update a repository entry in
.BR /etc/depot.d/repos.toml .
.I NAME
is the repo name, and
.I URL
is a source git URL or binary repo base URL.
.PP
Options:
.BR \-r ", " \-\-rootfs ;
.BR \-\-kind ;
.BR \-\-subdir ;
.BR \-\-priority ;
.BR \-\-disabled ;
.BR \-\-arch ;
.BR \-\-repo\-db ;
.BR \-\-allow\-unsigned .
.TP
.B \-\-kind \fIsource|binary\fR
Repo kind. The default is
.BR source .
.TP
.B \-\-subdir \fISUBDIR\fR
Optional source repo subdirectory to index. May be repeated.
.TP
.B \-\-priority \fIPRIORITY\fR
Repo priority. Lower values have higher priority. The default is
.BR 0 .
.TP
.B \-\-disabled
Add the repo as disabled.
.TP
.B \-\-arch \fIARCH\fR
Binary repo architecture table entry to add or update. Defaults to this
machine's architecture.
.TP
.B \-\-repo\-db \fIREPO_DB\fR
Binary repo database filename or path relative to the repo URL. The default is
.BR repo.db.zst .
.TP
.B \-\-allow\-unsigned
Allow unsigned repo metadata for this binary repo.
.SS depot repo remove
.SY depot repo remove
.RI [ OPTIONS ]
.I NAME
.YS
Remove a repo entry from
.BR /etc/depot.d/repos.toml .
.PP
Options:
.BR \-r ", " \-\-rootfs ;
.BR \-\-kind .
.TP
.B \-\-kind \fIsource|binary\fR
Repo kind. If omitted, Depot auto-detects the kind when the repo name is unique.
.SS depot repo enable
.SY depot repo enable
.RI [ OPTIONS ]
.I NAME
.YS
Enable a repo entry in
.BR /etc/depot.d/repos.toml .
.PP
Options:
.BR \-r ", " \-\-rootfs ;
.BR \-\-kind .
.TP
.B \-\-kind \fIsource|binary\fR
Repo kind. If omitted, Depot auto-detects the kind when the repo name is unique.
.SS depot repo disable
.SY depot repo disable
.RI [ OPTIONS ]
.I NAME
.YS
Disable a repo entry in
.BR /etc/depot.d/repos.toml .
.PP
Options:
.BR \-r ", " \-\-rootfs ;
.BR \-\-kind .
.TP
.B \-\-kind \fIsource|binary\fR
Repo kind. If omitted, Depot auto-detects the kind when the repo name is unique.
.SS depot repo owns
.SY depot repo owns
.RI [ OPTIONS ]
.I PATH
.YS
Query binary repo metadata for the package that owns an absolute path or a
relative install path.
.PP
Options:
.BR \-r ", " \-\-rootfs .
.SS depot repo status
.SY depot repo status
.RI [ OPTIONS ]
.YS
Show status of configured git mirrors.
.PP
Options:
.BR \-r ", " \-\-rootfs .
.SS depot config
.SY depot config
.RI [ OPTIONS ]
.YS
Show the current Depot configuration.
.PP
Options:
.BR \-r ", " \-\-rootfs .
.SS depot set
.SY depot set
.RI [ OPTIONS ]
.I ROLE
.B to
.I IMPLEMENTATION
.YS
Select canonical tool aliases in the configured tool directory. Supported roles
are
.BR compiler ,
.BR linker ,
and
.BR shell .
For example:
.PP
.EX
depot set compiler to clang
.EE
.PP
Options:
.BR \-r ", " \-\-rootfs .
.SS depot make-spec
.SY depot make-spec
.RI [ OPTIONS ]
.YS
Create a new package specification interactively.
.PP
Options:
.BR \-o ", " \-\-output .
.TP
.B \-o, \-\-output \fIOUTPUT\fR
Output file path. If omitted, Depot writes
.BI name .toml
from the selected package name.
.SS depot convert
.SY depot convert
.RI [ OPTIONS ]
.RI [ INPUT ]
.YS
Convert a legacy
.B STARBUILD
file into a Depot package spec. The default input is
.BR STARBUILD .
.PP
Options:
.BR \-o ", " \-\-output .
.TP
.B \-o, \-\-output \fIOUTPUT\fR
Output TOML path. If omitted, Depot writes
.BI mainpkgname .toml
beside the STARBUILD.
.SH FILES
.TP
.B /etc/depot.toml
System configuration file.
.TP
.B /etc/depot.d/repos.toml
Configured source and binary repositories.
.TP
.B /etc/depot.d/mirrors.toml
Configured git mirrors.
.TP
.B /usr/src/depot
Default source repository and mirror clone directory.
.SH EXIT STATUS
.B depot
exits with status 0 on success and a non-zero status on error.
.SH SEE ALSO
.BR minisign (1)
+60 -7
View File
@@ -1,4 +1,4 @@
//! Generation helpers for CLI man pages and shell completions. //! Generation helpers for CLI assets.
use crate::cli::Cli; use crate::cli::Cli;
use anyhow::{Context, Result}; use anyhow::{Context, Result};
@@ -8,8 +8,9 @@ use std::fs;
use std::path::Path; use std::path::Path;
const BIN_NAME: &str = "depot"; const BIN_NAME: &str = "depot";
const MAN_PAGE: &str = include_str!("../man/depot.1");
/// Generate all supported shell completion scripts and a man page into `out_dir`. /// Generate all supported shell completion scripts and the manual page into `out_dir`.
pub fn generate_cli_assets(out_dir: &Path) -> Result<()> { pub fn generate_cli_assets(out_dir: &Path) -> Result<()> {
fs::create_dir_all(out_dir) fs::create_dir_all(out_dir)
.with_context(|| format!("Failed to create output directory {}", out_dir.display()))?; .with_context(|| format!("Failed to create output directory {}", out_dir.display()))?;
@@ -17,7 +18,7 @@ pub fn generate_cli_assets(out_dir: &Path) -> Result<()> {
generate_completion(out_dir, Shell::Bash, "depot.bash")?; generate_completion(out_dir, Shell::Bash, "depot.bash")?;
generate_completion(out_dir, Shell::Zsh, "_depot")?; generate_completion(out_dir, Shell::Zsh, "_depot")?;
generate_completion(out_dir, Shell::Fish, "depot.fish")?; generate_completion(out_dir, Shell::Fish, "depot.fish")?;
generate_man_pages(out_dir)?; write_man_page(out_dir)?;
Ok(()) Ok(())
} }
@@ -40,19 +41,59 @@ fn generate_completion(out_dir: &Path, shell: Shell, filename: &str) -> Result<(
Ok(()) Ok(())
} }
fn generate_man_pages(out_dir: &Path) -> Result<()> { fn write_man_page(out_dir: &Path) -> Result<()> {
clap_mangen::generate_to(command_for_generation(), out_dir) remove_old_depot_man_pages(out_dir)?;
.context("Failed to generate clap man pages")?; let output_path = out_dir.join("depot.1");
fs::write(&output_path, MAN_PAGE)
.with_context(|| format!("Failed to write man page to {}", output_path.display()))?;
Ok(())
}
fn remove_old_depot_man_pages(out_dir: &Path) -> Result<()> {
for entry in fs::read_dir(out_dir)
.with_context(|| format!("Failed to read output directory {}", out_dir.display()))?
{
let path = entry
.with_context(|| format!("Failed to inspect output directory {}", out_dir.display()))?
.path();
let Some(file_name) = path.file_name().and_then(|name| name.to_str()) else {
continue;
};
if file_name == "depot.1" || file_name.starts_with("depot-") && file_name.ends_with(".1") {
fs::remove_file(&path)
.with_context(|| format!("Failed to remove stale man page {}", path.display()))?;
}
}
Ok(()) Ok(())
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use clap::Command;
fn visible_command_paths(command: &Command) -> Vec<String> {
command
.get_subcommands()
.filter(|subcommand| !subcommand.is_hide_set())
.flat_map(|subcommand| {
let name = subcommand.get_name();
let nested = visible_command_paths(subcommand);
if nested.is_empty() {
vec![name.to_string()]
} else {
let mut paths = vec![name.to_string()];
paths.extend(nested.into_iter().map(|nested| format!("{name} {nested}")));
paths
}
})
.collect()
}
#[test] #[test]
fn generate_cli_assets_writes_expected_files() { fn generate_cli_assets_writes_expected_files() {
let temp = tempfile::tempdir().unwrap(); let temp = tempfile::tempdir().unwrap();
std::fs::write(temp.path().join("depot-install.1"), "stale").unwrap();
generate_cli_assets(temp.path()).unwrap(); generate_cli_assets(temp.path()).unwrap();
let bash = temp.path().join("depot.bash"); let bash = temp.path().join("depot.bash");
@@ -69,7 +110,19 @@ mod tests {
assert!(zsh.exists()); assert!(zsh.exists());
assert!(fish.exists()); assert!(fish.exists());
assert!(man.exists()); assert!(man.exists());
assert!(man_pages > 1); assert_eq!(man_pages, 1);
assert!(!std::fs::read_to_string(&man).unwrap().is_empty()); assert!(!std::fs::read_to_string(&man).unwrap().is_empty());
assert!(!temp.path().join("depot-install.1").exists());
}
#[test]
fn manual_page_documents_visible_command_paths() {
let command = command_for_generation();
for path in visible_command_paths(&command) {
assert!(
MAN_PAGE.contains(&format!("depot {path}")),
"manual page does not document `depot {path}`"
);
}
} }
} }
+2 -2
View File
@@ -4,7 +4,7 @@ use crate::metadata_time;
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use rusqlite::{Connection, params}; use rusqlite::{Connection, params};
use sha2::{Digest, Sha256, Sha512}; use sha2::{Digest, Sha256, Sha512};
use std::collections::{HashMap, BTreeSet}; use std::collections::{BTreeSet, HashMap};
use std::fs; use std::fs;
use std::io::{Read, Write}; use std::io::{Read, Write};
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
@@ -2538,7 +2538,7 @@ pub fn mirrors_status(
let head = repo.head().ok(); let head = repo.head().ok();
let branch = head let branch = head
.as_ref() .as_ref()
.and_then(|h| h.shorthand().map(|s| s.to_string())) .and_then(|h| h.shorthand().ok().map(|s| s.to_string()))
.unwrap_or_else(|| "(no branch)".to_string()); .unwrap_or_else(|| "(no branch)".to_string());
// Latest commit OID // Latest commit OID
+5 -5
View File
@@ -170,7 +170,7 @@ fn apply_cherry_picks(repo: &Repository, cherry_pick_revs: &[String]) -> Result<
let tree = repo let tree = repo
.find_tree(tree_id) .find_tree(tree_id)
.with_context(|| format!("Failed to find tree after cherry-pick {}", rev))?; .with_context(|| format!("Failed to find tree after cherry-pick {}", rev))?;
let message = commit.summary().unwrap_or("cherry-pick"); let message = commit.summary().ok().flatten().unwrap_or("cherry-pick");
let new_head = repo let new_head = repo
.commit( .commit(
None, None,
@@ -336,7 +336,7 @@ fn repair_mirror_refs(repo: &Repository) -> Result<()> {
fn sync_remote_tracking_heads(repo: &Repository) -> Result<()> { fn sync_remote_tracking_heads(repo: &Repository) -> Result<()> {
for reference_result in repo.references_glob("refs/remotes/origin/*")? { for reference_result in repo.references_glob("refs/remotes/origin/*")? {
let reference = reference_result?; let reference = reference_result?;
let Some(name) = reference.name() else { let Ok(name) = reference.name() else {
continue; continue;
}; };
if name == "refs/remotes/origin/HEAD" { if name == "refs/remotes/origin/HEAD" {
@@ -368,7 +368,7 @@ fn ensure_valid_local_head(repo: &Repository) -> Result<()> {
let mut candidates: Vec<String> = Vec::new(); let mut candidates: Vec<String> = Vec::new();
for reference_result in repo.references_glob("refs/heads/*")? { for reference_result in repo.references_glob("refs/heads/*")? {
let reference = reference_result?; let reference = reference_result?;
let Some(name) = reference.name() else { let Ok(name) = reference.name() else {
continue; continue;
}; };
candidates.push(name.to_string()); candidates.push(name.to_string());
@@ -517,7 +517,7 @@ fn resolve_remote_head_like<'a>(repo: &'a Repository) -> Result<Option<git2::Obj
let mut candidates: Vec<(String, Oid)> = Vec::new(); let mut candidates: Vec<(String, Oid)> = Vec::new();
for reference_result in repo.references_glob("refs/remotes/origin/*")? { for reference_result in repo.references_glob("refs/remotes/origin/*")? {
let reference = reference_result?; let reference = reference_result?;
let Some(name) = reference.name() else { let Ok(name) = reference.name() else {
continue; continue;
}; };
if name == "refs/remotes/origin/HEAD" { if name == "refs/remotes/origin/HEAD" {
@@ -1049,7 +1049,7 @@ mod tests {
assert_eq!( assert_eq!(
repo.head().unwrap().resolve().unwrap().name(), repo.head().unwrap().resolve().unwrap().name(),
Some("refs/heads/main") Ok("refs/heads/main")
); );
} }
+1 -1
View File
@@ -43,4 +43,4 @@ mkdir -p "$bash_dest" "$zsh_dest" "$fish_dest" "$man_dest"
cp "$tmpdir/depot.bash" "$bash_dest/depot" cp "$tmpdir/depot.bash" "$bash_dest/depot"
cp "$tmpdir/_depot" "$zsh_dest/_depot" cp "$tmpdir/_depot" "$zsh_dest/_depot"
cp "$tmpdir/depot.fish" "$fish_dest/depot.fish" cp "$tmpdir/depot.fish" "$fish_dest/depot.fish"
cp "$tmpdir"/*.1 "$man_dest/" cp "$tmpdir/depot.1" "$man_dest/depot.1"