diff --git a/syncat/src/config.rs b/syncat/src/config.rs index 61d2e70..dc9354d 100644 --- a/syncat/src/config.rs +++ b/syncat/src/config.rs @@ -44,6 +44,37 @@ fn config_exists>(file: P) -> bool { .any(|res| res.unwrap().path().unwrap().as_ref() == file.as_ref()) } +pub(crate) fn dump_config>(file: P) -> crate::Result<()> { + let mut config_reader = DEFAULT_CONFIG; + for mut entry in tar::Archive::new(&mut config_reader) + .entries() + .unwrap() + .map(|entry| entry.unwrap()) + { + let input_path = entry.path().unwrap(); + let output_path = file.as_ref().join(input_path); + let parent_path = output_path.parent().unwrap(); + if !parent_path.exists() { + fs::create_dir(parent_path).map_err(|er| { + crate::Error::new("failed to unpack directory") + .with_source(er) + .with_path(parent_path) + })?; + } + let mut file = fs::File::create(&output_path).map_err(|er| { + crate::Error::new("failed to create file") + .with_source(er) + .with_path(&output_path) + })?; + io::copy(&mut entry, &mut file).map_err(|er| { + crate::Error::new("failed to write file") + .with_source(er) + .with_path(&output_path) + })?; + } + Ok(()) +} + pub(crate) fn read_to_string>(file: P) -> crate::Result { let path = config().join(&file); if path.exists() { diff --git a/syncat/src/main.rs b/syncat/src/main.rs index 13b2a8c..5a99f40 100644 --- a/syncat/src/main.rs +++ b/syncat/src/main.rs @@ -70,6 +70,14 @@ pub struct Opts { #[derive(Parser, Debug)] enum Subcommand { + /// Initialize the config directory by filling it with the default configuration. + /// + /// If the config directory already exists, it will not be created. An alternative path + /// may be specified. + Init { + #[arg(short, long)] + out: Option, + }, /// Installs all languages listed in the `languages.toml` file. Previously installed packages /// will be updated, if updates are available. This process may take a long time, depending on /// how many languages are being installed. diff --git a/syncat/src/package_manager.rs b/syncat/src/package_manager.rs index 6b732bc..b2d7d3d 100644 --- a/syncat/src/package_manager.rs +++ b/syncat/src/package_manager.rs @@ -1,5 +1,5 @@ -use crate::config::stylesheet_existence; -use crate::dirs::libraries; +use crate::config::{dump_config, stylesheet_existence}; +use crate::dirs::{config, libraries}; use crate::language::{Lang, LangMap}; use crate::Subcommand; use cc::Build; @@ -156,6 +156,23 @@ pub(crate) fn main(opts: &Subcommand) -> crate::Result<()> { } match opts { + Subcommand::Init { out } => { + let out = out.clone().unwrap_or(config()); + if out.exists() { + eprintln!( + "syncat: {}: configuration directory already exists, will not overwrite", + out.display() + ); + std::process::exit(1); + } + fs::create_dir_all(&out).map_err(|er| { + crate::Error::new("failed to create config directory") + .with_source(er) + .with_path(&out) + .with_hint("ensure you have adequate permissions to create the new directory and try again") + })?; + dump_config(&out)?; + } Subcommand::Install { languages } => { let mut any_errors = false; if languages.is_empty() {