generated from pure_sagacity/rust-starter
made adding a project work
changed the sql migration to make names unique
This commit is contained in:
Vendored
+3
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"cSpell.words": ["chrono"]
|
||||
}
|
||||
Generated
+1
@@ -1748,6 +1748,7 @@ version = "1.23.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ea5fab0d6c3c01ae70085a09cb03d4c7a1d6314e2b3e075392783396d724ca0a"
|
||||
dependencies = [
|
||||
"getrandom 0.4.3",
|
||||
"js-sys",
|
||||
"serde_core",
|
||||
"wasm-bindgen",
|
||||
|
||||
@@ -20,5 +20,9 @@ colored = "3.1.1"
|
||||
base64 = "0.22.1"
|
||||
chrono = "0.4.45"
|
||||
dotenvy = "0.15"
|
||||
uuid = "1.23.5"
|
||||
uuid = { version = "1.23.5", features = ["v4"] }
|
||||
hex = "0.4"
|
||||
|
||||
[[bin]]
|
||||
name = "harbor"
|
||||
path = "src/main.rs"
|
||||
|
||||
Binary file not shown.
@@ -1,11 +1,13 @@
|
||||
CREATE TABLE projects (
|
||||
id TEXT PRIMARY KEY,
|
||||
id TEXT PRIMARY KEY NOT NULL,
|
||||
name TEXT NOT NULL,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
UNIQUE (name)
|
||||
);
|
||||
|
||||
CREATE TABLE secrets (
|
||||
id TEXT PRIMARY KEY,
|
||||
id TEXT PRIMARY KEY NOT NULL,
|
||||
name TEXT NOT NULL,
|
||||
project_id TEXT NOT NULL,
|
||||
config TEXT NOT NULL,
|
||||
|
||||
@@ -11,6 +11,13 @@ pub struct Project {
|
||||
pub created_at: NaiveDateTime,
|
||||
}
|
||||
|
||||
#[derive(Insertable)]
|
||||
#[diesel(table_name = projects)]
|
||||
pub struct NewProject<'a> {
|
||||
pub id: &'a str,
|
||||
pub name: &'a str,
|
||||
}
|
||||
|
||||
#[derive(Debug, Queryable, Selectable)]
|
||||
#[diesel(table_name = secrets)]
|
||||
#[diesel(check_for_backend(diesel::sqlite::Sqlite))]
|
||||
|
||||
+78
-14
@@ -1,10 +1,12 @@
|
||||
use base64::{Engine, engine::general_purpose::STANDARD};
|
||||
use clap::{Args, Parser, Subcommand};
|
||||
use clap::{Parser, Subcommand};
|
||||
use crypto::helper::gen_key;
|
||||
use keyring::Entry;
|
||||
use std::error::Error;
|
||||
use std::io::{self, Write};
|
||||
mod db;
|
||||
mod store;
|
||||
|
||||
#[derive(Parser)]
|
||||
#[clap(
|
||||
name = "Harbor",
|
||||
@@ -22,7 +24,13 @@ pub struct Cli {
|
||||
|
||||
#[derive(Subcommand)]
|
||||
pub enum Commands {
|
||||
Inject(InjectArgs),
|
||||
Inject {
|
||||
#[arg(short, long)]
|
||||
verbose: bool,
|
||||
|
||||
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
|
||||
after: Vec<String>,
|
||||
},
|
||||
Shell {},
|
||||
Add {},
|
||||
Setup {},
|
||||
@@ -37,30 +45,72 @@ pub enum Commands {
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Args, Debug)]
|
||||
pub struct InjectArgs {
|
||||
#[arg(short, long)]
|
||||
pub verbose: bool,
|
||||
|
||||
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
|
||||
pub after: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Subcommand)]
|
||||
pub enum ProjectCommands {
|
||||
List {},
|
||||
Create { name: String },
|
||||
Create {},
|
||||
Delete { name: String },
|
||||
}
|
||||
|
||||
#[derive(Subcommand)]
|
||||
pub enum ConfigCommands {
|
||||
List {},
|
||||
Create { project: String, name: String },
|
||||
Create { project: String },
|
||||
Delete { project: String, name: String },
|
||||
}
|
||||
|
||||
fn gen_or_get_key() -> Result<crypto::Key, Box<dyn Error>> {
|
||||
pub mod interactions {
|
||||
use super::db::models::{NewProject, Project};
|
||||
use super::db::{
|
||||
establish_connection,
|
||||
schema::projects::dsl::{name as project_name, projects},
|
||||
};
|
||||
use diesel::result::{DatabaseErrorKind, Error as DieselError};
|
||||
use diesel::{ExpressionMethods, OptionalExtension, QueryDsl, RunQueryDsl, SelectableHelper};
|
||||
use std::error::Error;
|
||||
use uuid::Uuid;
|
||||
|
||||
fn construct_error(message: &str) -> Result<(), Box<dyn Error>> {
|
||||
Err(Box::new(std::io::Error::new(
|
||||
std::io::ErrorKind::AlreadyExists,
|
||||
message.to_string(),
|
||||
)))
|
||||
}
|
||||
|
||||
pub fn create_project(proj_name: &str) -> Result<(), Box<dyn Error>> {
|
||||
let mut conn = establish_connection();
|
||||
|
||||
// 1. Check if the project already exists
|
||||
let existing_project = projects
|
||||
.filter(project_name.eq(proj_name))
|
||||
.select(Project::as_select())
|
||||
.first::<Project>(&mut conn)
|
||||
.optional()?;
|
||||
|
||||
if let Some(_) = existing_project {
|
||||
return construct_error("Project already exists");
|
||||
}
|
||||
|
||||
let project_id = Uuid::new_v4().to_string();
|
||||
let new_project = NewProject {
|
||||
id: &project_id,
|
||||
name: proj_name,
|
||||
};
|
||||
|
||||
match diesel::insert_into(projects)
|
||||
.values(&new_project)
|
||||
.execute(&mut conn)
|
||||
{
|
||||
Ok(_) => Ok(()),
|
||||
Err(DieselError::DatabaseError(DatabaseErrorKind::UniqueViolation, _)) => {
|
||||
construct_error("Project already exists")
|
||||
}
|
||||
Err(err) => Err(Box::new(err)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn gen_or_get_key() -> Result<crypto::Key, Box<dyn Error>> {
|
||||
let entry = Entry::new("harbor", "encryption-key")?;
|
||||
|
||||
match entry.get_password() {
|
||||
@@ -84,3 +134,17 @@ fn gen_or_get_key() -> Result<crypto::Key, Box<dyn Error>> {
|
||||
Err(err) => Err(Box::new(err)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_input(message: &str, prompt: char, new_line: bool) -> Result<String, Box<dyn Error>> {
|
||||
let mut input = String::new();
|
||||
|
||||
if new_line {
|
||||
print!("{}\n{} ", message, prompt);
|
||||
} else {
|
||||
print!("{}{} ", message, prompt);
|
||||
}
|
||||
|
||||
io::stdout().flush()?;
|
||||
io::stdin().read_line(&mut input)?;
|
||||
Ok(input.trim().to_string())
|
||||
}
|
||||
|
||||
+66
-2
@@ -3,6 +3,7 @@ use std::process;
|
||||
use clap::Parser;
|
||||
use clap::crate_version;
|
||||
use cli::Cli;
|
||||
use cli::get_input;
|
||||
use colored::*;
|
||||
|
||||
const GIT_VERSION: &str = env!("GIT_VERSION");
|
||||
@@ -20,12 +21,75 @@ fn main() {
|
||||
process::exit(0);
|
||||
}
|
||||
|
||||
if cli.command.is_none() {
|
||||
match cli.command {
|
||||
Some(c) => match c {
|
||||
cli::Commands::Add {} => {
|
||||
println!("Add command executed");
|
||||
}
|
||||
cli::Commands::Config { command } => match command {
|
||||
cli::ConfigCommands::List {} => {
|
||||
println!("Config list command executed");
|
||||
}
|
||||
cli::ConfigCommands::Create { project } => {
|
||||
println!("Config create command executed for project: {}", project);
|
||||
}
|
||||
cli::ConfigCommands::Delete { project, name } => {
|
||||
println!(
|
||||
"Config delete command executed for project: {}, name: {}",
|
||||
project, name
|
||||
);
|
||||
}
|
||||
},
|
||||
cli::Commands::Inject { verbose, after } => {
|
||||
println!(
|
||||
"Inject command executed with verbose: {}, after: {:?}",
|
||||
verbose, after
|
||||
);
|
||||
// for harbor inject -- bun dev
|
||||
// after = ["bun", "dev"]
|
||||
}
|
||||
cli::Commands::List {} => {
|
||||
println!("List command executed");
|
||||
}
|
||||
cli::Commands::Project { command } => match command {
|
||||
cli::ProjectCommands::List {} => {
|
||||
println!("Project list command executed");
|
||||
}
|
||||
cli::ProjectCommands::Create {} => {
|
||||
let project_name = match get_input("Project name", ':', false) {
|
||||
Ok(name) => name,
|
||||
Err(e) => {
|
||||
eprintln!("Error getting project name: {}", e);
|
||||
process::exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
match cli::interactions::create_project(&project_name) {
|
||||
Ok(()) => println!("{}", "Project created successfully".blue()),
|
||||
Err(e) => {
|
||||
eprintln!("Error creating project: {}", e);
|
||||
process::exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
cli::ProjectCommands::Delete { name } => {
|
||||
println!("Project delete command executed for name: {}", name);
|
||||
}
|
||||
},
|
||||
cli::Commands::Shell {} => {
|
||||
println!("Shell command executed");
|
||||
}
|
||||
cli::Commands::Setup {} => {
|
||||
println!("Setup command executed");
|
||||
}
|
||||
},
|
||||
None => {
|
||||
println!(
|
||||
"{}\n{}",
|
||||
"No command was entered.".red(),
|
||||
"Exiting...".dimmed()
|
||||
"Use --help for more information.".dimmed()
|
||||
);
|
||||
process::exit(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user