Implement `rad-push`
Signed-off-by: Alexis Sellier <alexis@radicle.xyz>
This commit is contained in:
parent
5472931ff0
commit
dea268c389
|
|
@ -14,6 +14,8 @@ pub mod rad_init;
|
||||||
pub mod rad_inspect;
|
pub mod rad_inspect;
|
||||||
#[path = "commands/ls.rs"]
|
#[path = "commands/ls.rs"]
|
||||||
pub mod rad_ls;
|
pub mod rad_ls;
|
||||||
|
#[path = "commands/push.rs"]
|
||||||
|
pub mod rad_push;
|
||||||
#[path = "commands/rm.rs"]
|
#[path = "commands/rm.rs"]
|
||||||
pub mod rad_rm;
|
pub mod rad_rm;
|
||||||
#[path = "commands/self.rs"]
|
#[path = "commands/self.rs"]
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,134 @@
|
||||||
|
use std::ffi::OsString;
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
|
use radicle::git;
|
||||||
|
|
||||||
|
use crate::terminal as term;
|
||||||
|
use crate::terminal::args::{Args, Error, Help};
|
||||||
|
|
||||||
|
use anyhow::anyhow;
|
||||||
|
|
||||||
|
pub const HELP: Help = Help {
|
||||||
|
name: "push",
|
||||||
|
description: env!("CARGO_PKG_DESCRIPTION"),
|
||||||
|
version: env!("CARGO_PKG_VERSION"),
|
||||||
|
usage: r#"
|
||||||
|
Usage
|
||||||
|
|
||||||
|
rad push [--all] [--[no-]sync] [<option>...]
|
||||||
|
|
||||||
|
By default, only the current branch is synced.
|
||||||
|
|
||||||
|
Options
|
||||||
|
|
||||||
|
--all Push all branches (default: false)
|
||||||
|
--sync Sync after pushing to the "rad" remote (default: false)
|
||||||
|
--no-sync Do not sync after pushing to the "rad" remote
|
||||||
|
--help Print help
|
||||||
|
|
||||||
|
Git options
|
||||||
|
|
||||||
|
-f, --force Force push
|
||||||
|
-u, --set-upstream Set upstream tracking branch
|
||||||
|
|
||||||
|
"#,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Default, Debug)]
|
||||||
|
pub struct Options {
|
||||||
|
pub verbose: bool,
|
||||||
|
pub force: bool,
|
||||||
|
pub all: bool,
|
||||||
|
pub set_upstream: bool,
|
||||||
|
pub sync: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Args for Options {
|
||||||
|
fn from_args(args: Vec<OsString>) -> anyhow::Result<(Self, Vec<OsString>)> {
|
||||||
|
use lexopt::prelude::*;
|
||||||
|
|
||||||
|
let mut parser = lexopt::Parser::from_args(args);
|
||||||
|
let mut verbose = false;
|
||||||
|
let mut force = false;
|
||||||
|
let mut all = false;
|
||||||
|
let mut sync = false;
|
||||||
|
let mut set_upstream = false;
|
||||||
|
|
||||||
|
while let Some(arg) = parser.next()? {
|
||||||
|
match arg {
|
||||||
|
Long("verbose") | Short('v') => {
|
||||||
|
verbose = true;
|
||||||
|
}
|
||||||
|
Long("help") => {
|
||||||
|
return Err(Error::Help.into());
|
||||||
|
}
|
||||||
|
Long("all") => {
|
||||||
|
all = true;
|
||||||
|
}
|
||||||
|
Long("set-upstream") | Short('u') => {
|
||||||
|
set_upstream = true;
|
||||||
|
}
|
||||||
|
Long("sync") => {
|
||||||
|
sync = true;
|
||||||
|
}
|
||||||
|
Long("no-sync") => {
|
||||||
|
sync = false;
|
||||||
|
}
|
||||||
|
Long("force") | Short('f') => {
|
||||||
|
force = true;
|
||||||
|
}
|
||||||
|
arg => {
|
||||||
|
return Err(anyhow!(arg.unexpected()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok((
|
||||||
|
Options {
|
||||||
|
force,
|
||||||
|
all,
|
||||||
|
set_upstream,
|
||||||
|
sync,
|
||||||
|
verbose,
|
||||||
|
},
|
||||||
|
vec![],
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> {
|
||||||
|
ctx.profile()?;
|
||||||
|
|
||||||
|
term::info!("Pushing 🌱 to remote `rad`");
|
||||||
|
|
||||||
|
let cwd = Path::new(".").canonicalize()?;
|
||||||
|
let mut args = vec!["push"];
|
||||||
|
|
||||||
|
if options.force {
|
||||||
|
args.push("--force");
|
||||||
|
}
|
||||||
|
if options.set_upstream {
|
||||||
|
args.push("--set-upstream");
|
||||||
|
}
|
||||||
|
if options.all {
|
||||||
|
args.push("--all");
|
||||||
|
}
|
||||||
|
if options.verbose {
|
||||||
|
args.push("--verbose");
|
||||||
|
}
|
||||||
|
args.push("rad"); // Push to "rad" remote.
|
||||||
|
|
||||||
|
term::subcommand(&format!("git {}", args.join(" ")));
|
||||||
|
|
||||||
|
// Push to storage.
|
||||||
|
match git::run::<_, _, &str, &str>(&cwd, args, []) {
|
||||||
|
Ok(output) => term::blob(output),
|
||||||
|
Err(err) => return Err(err.into()),
|
||||||
|
}
|
||||||
|
|
||||||
|
if options.sync {
|
||||||
|
term::warning("the `--sync` option is not yet supported");
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
@ -109,22 +109,8 @@ pub fn repository() -> Result<Repository, anyhow::Error> {
|
||||||
pub fn git<S: AsRef<std::ffi::OsStr>>(
|
pub fn git<S: AsRef<std::ffi::OsStr>>(
|
||||||
repo: &std::path::Path,
|
repo: &std::path::Path,
|
||||||
args: impl IntoIterator<Item = S>,
|
args: impl IntoIterator<Item = S>,
|
||||||
) -> Result<String, anyhow::Error> {
|
) -> Result<String, io::Error> {
|
||||||
let output = Command::new("git").current_dir(repo).args(args).output()?;
|
radicle::git::run::<_, _, &str, &str>(repo, args, [])
|
||||||
|
|
||||||
if output.status.success() {
|
|
||||||
let out = if output.stdout.is_empty() {
|
|
||||||
&output.stderr
|
|
||||||
} else {
|
|
||||||
&output.stdout
|
|
||||||
};
|
|
||||||
return Ok(String::from_utf8_lossy(out).into());
|
|
||||||
}
|
|
||||||
|
|
||||||
Err(anyhow::Error::new(std::io::Error::new(
|
|
||||||
std::io::ErrorKind::Other,
|
|
||||||
String::from_utf8_lossy(&output.stderr),
|
|
||||||
)))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Configure SSH signing in the given git repo, for the given peer.
|
/// Configure SSH signing in the given git repo, for the given peer.
|
||||||
|
|
@ -285,7 +271,7 @@ pub fn branch_remote(repo: &Repository, branch: &str) -> anyhow::Result<String>
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Call `git pull`, optionally with `--force`.
|
/// Call `git pull`, optionally with `--force`.
|
||||||
pub fn pull(repo: &Path, force: bool) -> anyhow::Result<String> {
|
pub fn pull(repo: &Path, force: bool) -> io::Result<String> {
|
||||||
let mut args = vec!["-c", "color.diff=always", "pull", "-v"];
|
let mut args = vec!["-c", "color.diff=always", "pull", "-v"];
|
||||||
if force {
|
if force {
|
||||||
args.push("--force");
|
args.push("--force");
|
||||||
|
|
@ -294,7 +280,7 @@ pub fn pull(repo: &Path, force: bool) -> anyhow::Result<String> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Clone the given repository via `git clone` into a directory.
|
/// Clone the given repository via `git clone` into a directory.
|
||||||
pub fn clone(repo: &str, destination: &Path) -> Result<String, anyhow::Error> {
|
pub fn clone(repo: &str, destination: &Path) -> Result<String, io::Error> {
|
||||||
git(
|
git(
|
||||||
Path::new("."),
|
Path::new("."),
|
||||||
["clone", repo, &destination.to_string_lossy()],
|
["clone", repo, &destination.to_string_lossy()],
|
||||||
|
|
@ -353,11 +339,11 @@ pub fn add_tag(
|
||||||
Ok(oid)
|
Ok(oid)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn push_tag(tag_name: &str) -> anyhow::Result<String> {
|
pub fn push_tag(tag_name: &str) -> io::Result<String> {
|
||||||
git(Path::new("."), vec!["push", "rad", "tag", tag_name])
|
git(Path::new("."), vec!["push", "rad", "tag", tag_name])
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn push_branch(name: &str) -> anyhow::Result<String> {
|
pub fn push_branch(name: &str) -> io::Result<String> {
|
||||||
git(Path::new("."), vec!["push", "rad", name])
|
git(Path::new("."), vec!["push", "rad", name])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -384,7 +384,7 @@ pub fn set_upstream(
|
||||||
|
|
||||||
/// Execute a git command by spawning a child process.
|
/// Execute a git command by spawning a child process.
|
||||||
pub fn run<P, S, K, V>(
|
pub fn run<P, S, K, V>(
|
||||||
repo: &P,
|
repo: P,
|
||||||
args: impl IntoIterator<Item = S>,
|
args: impl IntoIterator<Item = S>,
|
||||||
envs: impl IntoIterator<Item = (K, V)>,
|
envs: impl IntoIterator<Item = (K, V)>,
|
||||||
) -> Result<String, io::Error>
|
) -> Result<String, io::Error>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue