Remove the init command.

pull/3/head
Joshua Potter 2022-01-07 06:11:25 -05:00
parent 63085593c4
commit 7debe754d1
5 changed files with 28 additions and 156 deletions

View File

@ -1,4 +1,7 @@
--- ---
user:
name: jrpotter
email: jrpotter@github.io
local: $HOME/.homesync local: $HOME/.homesync
remote: remote:
name: origin name: origin

View File

@ -2,13 +2,7 @@ use super::{path, path::ResPathBuf};
use paris::formatter::colorize_string; use paris::formatter::colorize_string;
use serde_derive::{Deserialize, Serialize}; use serde_derive::{Deserialize, Serialize};
use simplelog::{info, paris}; use simplelog::{info, paris};
use std::{ use std::{collections::BTreeMap, env::VarError, error, fmt, fs, io, io::Write, path::PathBuf};
collections::BTreeMap,
env::VarError,
error, fmt, fs, io,
io::Write,
path::{Path, PathBuf},
};
use url::{ParseError, Url}; use url::{ParseError, Url};
// ======================================== // ========================================
@ -77,6 +71,12 @@ impl error::Error for Error {}
// Config // Config
// ======================================== // ========================================
#[derive(Debug, Deserialize, Serialize)]
pub struct User {
pub name: String,
pub email: String,
}
#[derive(Debug, Deserialize, Serialize)] #[derive(Debug, Deserialize, Serialize)]
pub struct Package { pub struct Package {
pub configs: Vec<PathBuf>, pub configs: Vec<PathBuf>,
@ -91,6 +91,7 @@ pub struct Remote {
#[derive(Debug, Deserialize, Serialize)] #[derive(Debug, Deserialize, Serialize)]
pub struct Config { pub struct Config {
pub user: User,
pub local: PathBuf, pub local: PathBuf,
pub remote: Remote, pub remote: Remote,
pub packages: BTreeMap<String, Package>, pub packages: BTreeMap<String, Package>,
@ -164,97 +165,6 @@ pub fn reload(pc: &PathConfig) -> Result<PathConfig> {
load(&vec![pc.homesync_yml.clone()]) load(&vec![pc.homesync_yml.clone()])
} }
// ========================================
// Creation
// ========================================
fn prompt_default(prompt: &str, default: String) -> Result<String> {
print!("{}", prompt);
io::stdout().flush()?;
let mut value = String::new();
io::stdin().read_line(&mut value)?;
let trimmed = value.trim();
if trimmed.is_empty() {
Ok(default)
} else {
Ok(trimmed.to_owned())
}
}
fn prompt_local(path: Option<&Path>) -> Result<PathBuf> {
let default = path.map_or("$HOME/.homesync".to_owned(), |p| p.display().to_string());
let value = prompt_default(
&format!(
"Local git repository <{}> (enter to continue): ",
colorize_string(format!("<yellow>{}</>", &default)),
),
default,
)?;
Ok(PathBuf::from(value))
}
fn prompt_remote(remote: Option<&Remote>) -> Result<Remote> {
let default_name = remote.map_or("origin".to_owned(), |r| r.name.to_owned());
let remote_name = prompt_default(
&format!(
"Remote git name <{}> (enter to continue): ",
colorize_string(format!("<yellow>{}</>", &default_name))
),
default_name,
)?;
let default_branch = remote.map_or("origin".to_owned(), |r| r.branch.to_owned());
let remote_branch = prompt_default(
&format!(
"Remote git branch <{}> (enter to continue): ",
colorize_string(format!("<yellow>{}</>", &default_branch))
),
default_branch,
)?;
let default_url = remote.map_or("https://github.com/owner/repo.git".to_owned(), |r| {
r.url.to_string()
});
let remote_url = prompt_default(
&format!(
"Remote git url <{}> (enter to continue): ",
colorize_string(format!("<yellow>{}</>", &default_url))
),
default_url,
)?;
Ok(Remote {
name: remote_name,
branch: remote_branch,
url: Url::parse(&remote_url)?,
})
}
pub fn write(path: &ResPathBuf, loaded: Option<Config>) -> Result<PathConfig> {
println!(
"Generating config at {}...\n",
colorize_string(format!("<green>{}</>", path.unresolved().display())),
);
let local = prompt_local(match &loaded {
Some(c) => Some(c.local.as_ref()),
None => None,
})?;
let remote = prompt_remote(match &loaded {
Some(c) => Some(&c.remote),
None => None,
})?;
let generated = PathConfig {
homesync_yml: path.clone(),
config: Config {
local,
remote,
packages: loaded.map_or(BTreeMap::new(), |c| c.packages),
},
};
generated.write()?;
Ok(generated)
}
// ======================================== // ========================================
// Listing // Listing
// ======================================== // ========================================

View File

@ -1,5 +1,5 @@
use super::{config::PathConfig, path}; use super::{config::PathConfig, path};
use git2::{IndexAddOption, ObjectType, Remote, Repository, Signature, StashFlags}; use git2::{IndexAddOption, ObjectType, Remote, Repository, Signature};
use path::ResPathBuf; use path::ResPathBuf;
use simplelog::{info, paris}; use simplelog::{info, paris};
use std::{ use std::{

View File

@ -4,8 +4,7 @@ pub mod git;
pub mod path; pub mod path;
use config::PathConfig; use config::PathConfig;
use path::ResPathBuf; use std::error::Error;
use std::{error::Error, io};
type Result = std::result::Result<(), Box<dyn Error>>; type Result = std::result::Result<(), Box<dyn Error>>;
@ -21,35 +20,6 @@ pub fn run_daemon(config: PathConfig, freq_secs: u64) -> Result {
Ok(()) Ok(())
} }
pub fn run_init(candidates: Vec<ResPathBuf>) -> Result {
debug_assert!(!candidates.is_empty(), "Empty candidates found in `init`.");
if candidates.is_empty() {
Err(config::Error::IOError(io::Error::new(
io::ErrorKind::NotFound,
"No suitable config file found.",
)))?;
}
let config = match config::load(&candidates) {
// Check if we already have a local config somewhere. If so, reprompt
// the same configuration options and override the values present in the
// current YAML file.
Ok(loaded) => config::write(&loaded.homesync_yml, Some(loaded.config))?,
// Otherwise create a new config file at the given location. We always
// assume we want to write to the first file in our priority list. If
// not, the user should specify which config they want to write using
// the `-c` flag.
// TODO(jrpotter): Verify I have permission to write at specified path.
// Make directories if necessary.
Err(config::Error::MissingConfig) if !candidates.is_empty() => {
config::write(&candidates[0], None)?
}
Err(e) => Err(e)?,
};
git::init(&config)?;
println!("\nFinished initialization.");
Ok(())
}
pub fn run_list(config: PathConfig) -> Result { pub fn run_list(config: PathConfig) -> Result {
config::list_packages(config); config::list_packages(config);
Ok(()) Ok(())

View File

@ -60,7 +60,6 @@ fn main() {
.default_value("5"), .default_value("5"),
), ),
) )
.subcommand(App::new("init").about("Initialize the homesync local repository"))
.subcommand(App::new("list").about("See which packages homesync manages")) .subcommand(App::new("list").about("See which packages homesync manages"))
.subcommand(App::new("push").about("Push changes from local to remote")) .subcommand(App::new("push").about("Push changes from local to remote"))
.get_matches(); .get_matches();
@ -72,16 +71,8 @@ fn main() {
fn dispatch(matches: clap::ArgMatches) -> Result<(), Box<dyn Error>> { fn dispatch(matches: clap::ArgMatches) -> Result<(), Box<dyn Error>> {
let candidates = find_candidates(&matches)?; let candidates = find_candidates(&matches)?;
match matches.subcommand() {
Some(("init", _)) => Ok(homesync::run_init(candidates)?),
// All subcommands beside `init` require a config. If we invoke any of
// these, immediately attempt to load our config. Note once a config is
// loaded, this same config is used throughout the lifetime of the
// process. We avoid introducing the ability to "change" which config is
// used, even if one of higher priority is eventually defined.
subcommand => {
let config = homesync::config::load(&candidates)?; let config = homesync::config::load(&candidates)?;
match subcommand { match matches.subcommand() {
Some(("apply", _)) => Ok(homesync::run_apply(config)?), Some(("apply", _)) => Ok(homesync::run_apply(config)?),
Some(("daemon", matches)) => { Some(("daemon", matches)) => {
let freq_secs: u64 = match matches.value_of("frequency") { let freq_secs: u64 = match matches.value_of("frequency") {
@ -100,8 +91,6 @@ fn dispatch(matches: clap::ArgMatches) -> Result<(), Box<dyn Error>> {
_ => unreachable!(), _ => unreachable!(),
} }
} }
}
}
fn find_candidates(matches: &clap::ArgMatches) -> Result<Vec<ResPathBuf>, io::Error> { fn find_candidates(matches: &clap::ArgMatches) -> Result<Vec<ResPathBuf>, io::Error> {
let candidates = match matches.value_of("config") { let candidates = match matches.value_of("config") {