Add `rad-push`
Signed-off-by: Alexis Sellier <alexis@radicle.xyz>
This commit is contained in:
parent
a3bf5ab7c3
commit
51e18c27fc
|
|
@ -23,3 +23,7 @@ path = "src/rad-auth.rs"
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "rad-self"
|
name = "rad-self"
|
||||||
path = "src/rad-self.rs"
|
path = "src/rad-self.rs"
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "rad-push"
|
||||||
|
path = "src/rad-push.rs"
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
|
use radicle::storage::WriteStorage;
|
||||||
|
|
||||||
|
fn main() -> anyhow::Result<()> {
|
||||||
|
let cwd = Path::new(".").canonicalize()?;
|
||||||
|
let repo = radicle::git::raw::Repository::open(&cwd)?;
|
||||||
|
let profile = radicle::Profile::load()?;
|
||||||
|
let (_, id) = radicle::rad::remote(&repo)?;
|
||||||
|
|
||||||
|
let output = radicle::git::run(&cwd, &["push", "rad"])?;
|
||||||
|
println!("{}", output);
|
||||||
|
|
||||||
|
let project = profile.storage.repository(&id)?;
|
||||||
|
let sigrefs = profile.storage.sign_refs(&project, &profile.signer)?;
|
||||||
|
println!("ok: {}", sigrefs.signature);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
|
use std::io;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
use std::process::Command;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
use git_ref_format as format;
|
use git_ref_format as format;
|
||||||
|
|
@ -238,3 +240,25 @@ pub fn set_upstream(
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Execute a git command by spawning a child process.
|
||||||
|
pub fn run<P: AsRef<Path>, S: AsRef<std::ffi::OsStr>>(
|
||||||
|
repo: &P,
|
||||||
|
args: impl IntoIterator<Item = S>,
|
||||||
|
) -> Result<String, io::Error> {
|
||||||
|
let output = Command::new("git").current_dir(repo).args(args).output()?;
|
||||||
|
|
||||||
|
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(io::Error::new(
|
||||||
|
io::ErrorKind::Other,
|
||||||
|
String::from_utf8_lossy(&output.stderr),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
#![allow(clippy::let_unit_value)]
|
#![allow(clippy::let_unit_value)]
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
|
|
@ -57,7 +58,7 @@ pub fn init<G: Signer, S: storage::WriteStorage>(
|
||||||
)
|
)
|
||||||
.verified()?;
|
.verified()?;
|
||||||
|
|
||||||
let (id, _, project) = doc.create(pk, "Initialize Radicle", storage)?;
|
let (id, _, project) = doc.create(pk, "Initialize Radicle\n", storage)?;
|
||||||
let url = storage.url(&id);
|
let url = storage.url(&id);
|
||||||
|
|
||||||
git::set_upstream(
|
git::set_upstream(
|
||||||
|
|
@ -299,6 +300,18 @@ pub fn checkout<P: AsRef<Path>, S: storage::ReadStorage>(
|
||||||
Ok(repo)
|
Ok(repo)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the radicle ("rad") remote of a repository, and return the associated project id.
|
||||||
|
pub fn remote(repo: &git2::Repository) -> Result<(git2::Remote<'_>, Id), git2::Error> {
|
||||||
|
let remote = repo.find_remote(REMOTE_NAME)?;
|
||||||
|
let url = remote.url_bytes();
|
||||||
|
let url = git::Url::from_bytes(url).unwrap();
|
||||||
|
let path = url.path.to_string();
|
||||||
|
let id = path.split('/').last().unwrap();
|
||||||
|
let id = Id::from_str(id).unwrap();
|
||||||
|
|
||||||
|
Ok((remote, id))
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
|
||||||
|
|
@ -91,13 +91,7 @@ impl WriteStorage for Storage {
|
||||||
repository: &Repository,
|
repository: &Repository,
|
||||||
signer: G,
|
signer: G,
|
||||||
) -> Result<SignedRefs<Verified>, Error> {
|
) -> Result<SignedRefs<Verified>, Error> {
|
||||||
let remote = signer.public_key();
|
repository.sign_refs(signer)
|
||||||
let refs = repository.references(remote)?;
|
|
||||||
let signed = refs.signed(&signer)?;
|
|
||||||
|
|
||||||
signed.save(remote, repository)?;
|
|
||||||
|
|
||||||
Ok(signed)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fetch(&self, proj_id: &Id, remote: &Url) -> Result<Vec<RefUpdate>, FetchError> {
|
fn fetch(&self, proj_id: &Id, remote: &Url) -> Result<Vec<RefUpdate>, FetchError> {
|
||||||
|
|
@ -370,6 +364,16 @@ impl Repository {
|
||||||
);
|
);
|
||||||
Ok(remotes)
|
Ok(remotes)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn sign_refs<G: Signer>(&self, signer: G) -> Result<SignedRefs<Verified>, Error> {
|
||||||
|
let remote = signer.public_key();
|
||||||
|
let refs = self.references(remote)?;
|
||||||
|
let signed = refs.signed(&signer)?;
|
||||||
|
|
||||||
|
signed.save(remote, self)?;
|
||||||
|
|
||||||
|
Ok(signed)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ReadRepository for Repository {
|
impl ReadRepository for Repository {
|
||||||
|
|
|
||||||
|
|
@ -288,7 +288,7 @@ impl SignedRefs<Verified> {
|
||||||
Some(&sigref),
|
Some(&sigref),
|
||||||
&author,
|
&author,
|
||||||
&author,
|
&author,
|
||||||
&format!("Update {} for {}", sigref, remote),
|
&format!("Update signature for {}\n", remote),
|
||||||
&tree,
|
&tree,
|
||||||
&parent.iter().collect::<Vec<&git2::Commit>>(),
|
&parent.iter().collect::<Vec<&git2::Commit>>(),
|
||||||
);
|
);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue