Compare commits
10 Commits
65e33a7c9f
...
aaff62cbc6
Author | SHA1 | Date | |
---|---|---|---|
![]() |
aaff62cbc6 | ||
![]() |
8d6f07bc26 | ||
![]() |
11374bf8f6 | ||
![]() |
f0f02a2b60 | ||
![]() |
e27053a4cc | ||
![]() |
d5b9431547 | ||
![]() |
5068420359 | ||
![]() |
07fce376c8 | ||
![]() |
bfdd939fc1 | ||
![]() |
a514ff72d2 |
2
Cargo.lock
generated
2
Cargo.lock
generated
@ -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",
|
||||||
|
@ -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
|
||||||
|
11
Makefile
11
Makefile
@ -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
|
||||||
|
170
src/git.rs
170
src/git.rs
@ -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.")
|
||||||
|
);
|
||||||
|
}
|
17
src/main.rs
17
src/main.rs
@ -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
45
src/sys.rs
Normal 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"));
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user