Compare commits

...

10 Commits

Author SHA1 Message Date
breadone
aaff62cbc6
rollback makefile change
add ip addr command
2024-08-12 23:35:29 +12:00
breadone
8d6f07bc26
update makefile 2024-08-12 23:31:41 +12:00
breadone
11374bf8f6
changed git delete to git rm 2024-07-30 11:43:29 +12:00
breadone
f0f02a2b60
Changed some formatting 2024-07-30 11:41:47 +12:00
breadone
e27053a4cc
make update finally works 2024-07-30 11:27:27 +12:00
breadone
d5b9431547
Added sys subcommand
Add restart subsubcommand
2024-07-30 11:18:54 +12:00
breadone
5068420359
update verison 2024-07-28 19:01:56 +12:00
breadone
07fce376c8
version 2 release! 2024-07-28 18:23:56 +12:00
breadone
bfdd939fc1
updated addremoterepo! 2024-07-28 18:14:57 +12:00
breadone
a514ff72d2
Updated initrepo 2024-07-28 18:12:42 +12:00
6 changed files with 183 additions and 72 deletions

2
Cargo.lock generated
View File

@ -100,7 +100,7 @@ checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf"
[[package]] [[package]]
name = "bp" name = "bp"
version = "0.1.0" version = "2.2.0"
dependencies = [ dependencies = [
"clap", "clap",
"inquire", "inquire",

View File

@ -1,6 +1,6 @@
[package] [package]
name = "bp" name = "bp"
version = "0.1.0" version = "2.2.0"
edition = "2021" edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

View File

@ -1,4 +1,4 @@
UNAME := $(shell uname)
build: build:
@cargo build @cargo build
@ -12,5 +12,10 @@ release: clean
@cargo build --release @cargo build --release
update: release update: release
@sudo cp target/release/bp /usr/bin ifeq ($(UNAME), Darwin)
@echo "Copied release file to /usr/bin" cp target/release/bp ~/bin/
endif
ifeq ($(UNAME), Linux)
sudo cp target/release/bp /usr/bin
endif

View File

@ -1,6 +1,6 @@
use clap::Subcommand; use clap::Subcommand;
use openssh::{Session, KnownHosts}; use openssh::{Session, KnownHosts};
use inquire::{Select, InquireError}; use inquire::{Text, Select, Confirm, InquireError};
use core::str; use core::str;
use std::process::Command; use std::process::Command;
@ -10,24 +10,24 @@ pub enum GitCommand {
Init { Init {
#[arg()] #[arg()]
/// Name of the repo /// Name of the repo
name: String name: Option<String>
}, },
/// List all repositories in breadpi. /// List all repositories in breadpi.
Ls, Ls,
/// Delete the specified repository in breadpi. /// Delete the specified repository in breadpi.
Delete { Rm {
#[arg()] #[arg()]
/// Name of the repo /// Name of the repo
name: String name: Option<String>
}, },
/// Add remote to the git repo in the current directory /// Add remote to the git repo in the current directory
Add { Add {
#[arg()] #[arg()]
/// Name of the repo /// Name of the repo
name: String name: Option<String>
}, },
/// Clone a repo from the remote /// Clone a repo from the remote
@ -44,64 +44,25 @@ pub async fn handle_git(cmd: &GitCommand) {
.expect("Could not connect to git@breadpi"); .expect("Could not connect to git@breadpi");
match cmd { match cmd {
GitCommand::Init { name } => { GitCommand::Init { name } => { init_repo(name, &session).await; }
let init = session.command("git")
.arg("init")
.arg("--bare")
.arg("store/".to_owned() + name + ".git")
.output().await.unwrap();
eprintln!( GitCommand::Rm { name } => { rm_repo(name, &session).await; }
"{}",
String::from_utf8(init.stdout).expect("Failed to init git repo.")
);
print!("Would you like to add the remote to the repo in this directory? (Y/n): "); GitCommand::Add { name } => { add_remote_to_repo(name, &session).await; }
}
GitCommand::Delete { name } => { GitCommand::Clone { name } => { clone_repo(name, &session).await; }
let rm = session.command("rm")
.arg("-r")
.arg("-f")
.arg("store/".to_owned() + name + ".git")
.output().await.unwrap();
eprintln!(
"{}",
String::from_utf8(rm.stdout).expect("Failed to rm repo.")
);
}
GitCommand::Ls => { GitCommand::Ls => {
let ls = list_repos(&session).await.join("\n"); let ls = list_repos(&session).await.join("\n") + "\n";
print!("{ls}"); print!("{ls}");
} }
GitCommand::Add { name } => { add_remote_to_repo(name.to_string()); }
GitCommand::Clone { name } => { clone_repo(name, &session).await; }
} }
let _ = session.close().await; let _ = session.close().await;
} }
fn add_remote_to_repo(name: String) {
let cmd = Command::new("git")
.arg("remote")
.arg("add")
.arg("origin")
.arg("git@breadpi:/home/git/store/".to_owned() + &name + ".git")
.output().expect("Could not add remote");
eprintln!(
"{}",
String::from_utf8(cmd.stdout).expect("Failed to add git remote.")
);
println!("Added remote origin git@breadpi:/home/git/store/{name}.git");
}
async fn list_repos(session: &Session) -> Vec<String> { async fn list_repos(session: &Session) -> Vec<String> {
let buf = session.command("ls") let buf = session.command("ls")
.arg("store/") .arg("store/")
@ -118,29 +79,102 @@ async fn list_repos(session: &Session) -> Vec<String> {
// split string into array // split string into array
let list: Vec<String> = s.split("\n").map(str::to_string).collect(); let list: Vec<String> = s.split("\n").map(str::to_string).collect();
let repos: Vec<String> = list.iter().map(|x| { // remove the trailing .git from each item
let mut repos: Vec<String> = list.iter().map(|x| {
let mut chars = x.chars(); let mut chars = x.chars();
for _ in 0..4 { chars.next_back(); } for _ in 0..4 { chars.next_back(); }
return chars.as_str().to_string(); return chars.as_str().to_string();
} ).collect(); }).collect();
repos.truncate(repos.len() - 1);
return repos; return repos;
} }
async fn clone_repo(name: &Option<String>, session: &Session) {
let mut unwrapped_name: String = "".to_string();
// check if name is null and present list if so async fn choose_repo_from_list(session: &Session) -> String {
if name.is_none() {
let list = list_repos(session).await; let list = list_repos(session).await;
let repos = list.iter().map(|s| s as &str).collect(); let repos = list.iter().map(|s| s as &str).collect();
let repo: Result<&str, InquireError> = Select::new("Choose a repo: ", repos).prompt(); let repo: Result<&str, InquireError> = Select::new("Choose a repo: ", repos).prompt();
match repo { match repo {
Ok(s) => unwrapped_name = s.to_string(), Ok(s) => return s.to_string(),
Err(_) => println!("error!") Err(e) => panic!("{e}")
} }
}
async fn add_remote_to_repo(name: &Option<String>, session: &Session) {
let unwrapped_name: String;
// check if name is null and present list if so
if name.is_none() {
unwrapped_name = choose_repo_from_list(session).await;
} else {
unwrapped_name = name.clone().unwrap();
}
let cmd = Command::new("git")
.arg("remote")
.arg("add")
.arg("origin")
.arg("git@breadpi:/home/git/store/".to_owned() + &unwrapped_name + ".git")
.output().expect("Could not add remote");
eprintln!(
"{}",
String::from_utf8(cmd.stdout).expect("Failed to add git remote.")
);
println!("Added remote origin git@breadpi:/home/git/store/{unwrapped_name}.git");
}
async fn init_repo(name: &Option<String>, session: &Session) {
let unwrapped_name: String;
// check if name is null and present list if so
if name.is_none() {
let text = Text::new("Enter the repo name: ").prompt();
match text {
Ok(s) => unwrapped_name = s,
Err(e) => panic!("{e}")
}
} else {
unwrapped_name = name.clone().unwrap();
}
let init = session.command("git")
.arg("init")
.arg("--bare")
.arg("store/".to_owned() + &unwrapped_name + ".git")
.output().await.unwrap();
eprintln!(
"{}",
String::from_utf8(init.stdout).expect("Failed to init git repo.")
);
let add_repo = Confirm::new("Would you like to add the remote to the repo in this directory?").prompt();
if add_repo.is_ok_and(|choice| choice) {
add_remote_to_repo(&Some(unwrapped_name), session).await
}
// match add_repo {
// Ok(true) => add_remote_to_repo(&Some(unwrapped_name), session).await,
// Ok(false) => { return 0; },
// Err(e) => panic!("{e}")
// }
}
async fn clone_repo(name: &Option<String>, session: &Session) {
let unwrapped_name: String;
// check if name is null and present list if so
if name.is_none() {
unwrapped_name = choose_repo_from_list(session).await;
} else { } else {
unwrapped_name = name.clone().unwrap(); unwrapped_name = name.clone().unwrap();
} }
@ -157,3 +191,25 @@ async fn clone_repo(name: &Option<String>, session: &Session) {
println!("Cloned repo git@breadpi:/home/git/store/{unwrapped_name} to {unwrapped_name}."); println!("Cloned repo git@breadpi:/home/git/store/{unwrapped_name} to {unwrapped_name}.");
} }
async fn rm_repo(name: &Option<String>, session: &Session) {
let unwrapped_name: String;
// check if name is null and present list if so
if name.is_none() {
unwrapped_name = choose_repo_from_list(session).await;
} else {
unwrapped_name = name.clone().unwrap();
}
let rm = session.command("rm")
.arg("-r")
.arg("-f")
.arg("store/".to_owned() + &unwrapped_name + ".git")
.output().await.unwrap();
eprintln!(
"{}",
String::from_utf8(rm.stdout).expect("Failed to rm repo.")
);
}

View File

@ -1,25 +1,31 @@
mod git; mod git;
mod sys;
use sys::{SysCommand, handle_sys};
use tokio; use tokio;
use clap::{Parser, Subcommand}; use clap::{Parser, Subcommand};
use crate::git::{handle_git, GitCommand}; use crate::git::{handle_git, GitCommand};
const VERSION: &str = "2.0b1";
#[derive(Subcommand)] #[derive(Subcommand)]
enum Command { enum Command {
/// Various commands for creating and adding git repos to breadpi. /// Various commands for creating and adding git repos to breadpi.
Git { Git {
#[command(subcommand)] #[command(subcommand)]
git_command: GitCommand git_command: GitCommand
},
Sys {
#[command(subcommand)]
sys_command: SysCommand
} }
} }
#[derive(Parser)] #[derive(Parser)]
#[command(version, about, long_about = None)]
struct Cli { struct Cli {
#[command(subcommand)] #[command(subcommand)]
command: Command command: Command,
} }
#[tokio::main] #[tokio::main]
@ -27,8 +33,7 @@ async fn main() {
let cli = Cli::parse(); let cli = Cli::parse();
match &cli.command { match &cli.command {
Command::Git { git_command } => { Command::Git { git_command } => { handle_git(&git_command).await; },
handle_git(&git_command).await; Command::Sys { sys_command } => { handle_sys(&sys_command).await; }
}
} }
} }

45
src/sys.rs Normal file
View File

@ -0,0 +1,45 @@
use clap::Subcommand;
use openssh::{Session, KnownHosts};
use core::str;
#[derive(Subcommand)]
pub enum SysCommand {
/// Reboot breadpi.
Reboot,
/// Returns the local IP address of breadpi.
Ip
}
pub async fn handle_sys(cmd: &SysCommand) {
let session = Session::connect("bread@breadpi", KnownHosts::Strict)
.await
.expect("Could not connect to breadpi");
match cmd {
SysCommand::Reboot => { sys_reboot(&session).await; },
SysCommand::Ip => { ip_addr(&session).await; }
}
let _ = session.close();
}
async fn sys_reboot(session: &Session) {
let cmd = session.command("sudo")
.arg("systemctl")
.arg("reboot")
.output().await.unwrap();
if !cmd.status.success() {
println!("Error rebooting! Try again, possibly directly through ssh...");
println!("Error: {:?}", String::from_utf8(cmd.stderr));
}
}
async fn ip_addr(session: &Session) {
let cmd = session.command("hostname")
.arg("-I")
.raw_arg("| grep -o '^[0-9.]*'")
.output().await.unwrap();
println!("{}", String::from_utf8(cmd.stdout).expect("nuh uh"));
}