feat(config): create a proper config file with proper settings manipulation
This commit is contained in:
@@ -8,3 +8,4 @@ pub mod config;
|
||||
pub mod remote_diff;
|
||||
pub mod remote;
|
||||
pub mod pull;
|
||||
pub mod credential;
|
||||
|
||||
@@ -1,6 +1,121 @@
|
||||
use std::fs::OpenOptions;
|
||||
use std::io::{self, Write};
|
||||
use clap::Values;
|
||||
use std::io::{self, Write, BufRead, Seek, SeekFrom};
|
||||
use crate::utils::{path, read};
|
||||
use tempfile::tempfile;
|
||||
use std::collections::HashMap;
|
||||
|
||||
pub struct ConfigSetArgs<'a> {
|
||||
pub name: Option<Values<'a>>,
|
||||
pub value: Option<Values<'a>>,
|
||||
}
|
||||
|
||||
pub fn config_set(args: ConfigSetArgs) {
|
||||
// configure possible options and their associated category
|
||||
let mut option_categories: HashMap<&str, &str> = HashMap::new();
|
||||
option_categories.insert("force_insecure", "core");
|
||||
|
||||
let name = args.name.unwrap().next().unwrap();
|
||||
let value = args.value.unwrap().next().unwrap();
|
||||
|
||||
// get category of option
|
||||
let category = option_categories.get(name);
|
||||
if category.is_none() {
|
||||
eprintln!("fatal: '{}' is not a valid option.", name);
|
||||
std::process::exit(1);
|
||||
}
|
||||
|
||||
write_option_in_cat(category.unwrap(), name, value);
|
||||
}
|
||||
|
||||
|
||||
fn find_option_in_cat(category: &str, option: &str) -> Option<String> {
|
||||
let mut root = path::nextsync();
|
||||
root.push("config");
|
||||
|
||||
let mut in_target_category = false;
|
||||
if let Ok(mut lines) = read::read_lines(root) {
|
||||
|
||||
for line in lines {
|
||||
|
||||
if let Ok(line) = line {
|
||||
let trimmed_line = line.trim();
|
||||
|
||||
if trimmed_line.starts_with('[') && trimmed_line.ends_with(']') {
|
||||
in_target_category = trimmed_line == format!("[{}]", category);
|
||||
} else if in_target_category {
|
||||
let parts: Vec<&str> = trimmed_line.splitn(2, '=').collect();
|
||||
if parts.len() == 2 && parts[0].trim() == option {
|
||||
return Some(parts[1].trim().to_string());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
pub fn write_option_in_cat(category: &str, option: &str, value: &str) -> io::Result<()> {
|
||||
let mut root = path::nextsync();
|
||||
root.push("config");
|
||||
|
||||
let mut file = OpenOptions::new()
|
||||
.read(true)
|
||||
.write(true)
|
||||
.create(true)
|
||||
.open(&root)?;
|
||||
|
||||
let mut in_target_category = false;
|
||||
let mut option_found = false;
|
||||
|
||||
// Go to the beginning of the file
|
||||
file.seek(SeekFrom::Start(0))?;
|
||||
|
||||
// Create a temporary file to hold the modified content
|
||||
let mut tmp_file = tempfile::Builder::new()
|
||||
.prefix(".nextsyncconfig")
|
||||
.tempfile()?;
|
||||
|
||||
let reader = io::BufReader::new(&file);
|
||||
for line in reader.lines() {
|
||||
let line = line?;
|
||||
let trimmed_line = line.trim();
|
||||
|
||||
if trimmed_line.starts_with('[') && trimmed_line.ends_with(']') {
|
||||
in_target_category = trimmed_line == format!("[{}]", category);
|
||||
}
|
||||
|
||||
if in_target_category && !option_found && trimmed_line.starts_with(&format!("{} =", option)) {
|
||||
// Option already exists, update its value
|
||||
writeln!(&mut tmp_file, "\t{} = {}", option, value)?;
|
||||
option_found = true;
|
||||
} else {
|
||||
// Write the original line
|
||||
writeln!(&mut tmp_file, "{}", line)?;
|
||||
}
|
||||
}
|
||||
|
||||
if !option_found {
|
||||
// If the option doesn't exist, add it to the category
|
||||
writeln!(&mut tmp_file, "[{}]", category)?;
|
||||
writeln!(&mut tmp_file, "\t{} = {}", option, value)?;
|
||||
}
|
||||
|
||||
// Flush and sync the temporary file to ensure data is written to disk
|
||||
tmp_file.flush()?;
|
||||
|
||||
// Go back to the beginning of the file
|
||||
tmp_file.seek(SeekFrom::Start(0))?;
|
||||
file.seek(SeekFrom::Start(0))?;
|
||||
|
||||
// Copy the contents of the temporary file to the original file
|
||||
io::copy(&mut tmp_file, &mut file)?;
|
||||
|
||||
Ok(())
|
||||
|
||||
}
|
||||
|
||||
pub fn add_remote(name: &str, url: &str) -> io::Result<()> {
|
||||
let mut root = path::nextsync();
|
||||
@@ -27,32 +142,11 @@ pub fn add_remote(name: &str, url: &str) -> io::Result<()> {
|
||||
}
|
||||
|
||||
pub fn get_remote(name: &str) -> Option<String> {
|
||||
let mut root = path::nextsync();
|
||||
root.push("config");
|
||||
find_option_in_cat(&format!("remote \"{}\"", name), "url")
|
||||
}
|
||||
|
||||
let target = String::from(format!("[remote \"{}\"]", name));
|
||||
|
||||
if let Ok(mut lines) = read::read_lines(root) {
|
||||
while let Some(line_res) = lines.next() {
|
||||
if let Ok(line) = line_res {
|
||||
if line == target {
|
||||
// get the first line starting with 'url = '
|
||||
while let Some(line_res) = lines.next() {
|
||||
if let Ok(line) = line_res {
|
||||
let mut splitted_res = line.split("=");
|
||||
if let Some(splitted) = splitted_res.next() {
|
||||
if splitted == "\turl " {
|
||||
return Some(splitted_res.next().unwrap().to_owned());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return None;
|
||||
pub fn get_core(name: &str) -> Option<String> {
|
||||
find_option_in_cat("core", name)
|
||||
}
|
||||
|
||||
pub fn add_core(name: &str, value: &str) -> io::Result<()> {
|
||||
@@ -72,25 +166,6 @@ pub fn add_core(name: &str, value: &str) -> io::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn set(var: &str, val: &str) -> io::Result<()> {
|
||||
let mut root = path::nextsync();
|
||||
root.push("config");
|
||||
|
||||
// todo check if exist
|
||||
let mut file = OpenOptions::new()
|
||||
.read(true)
|
||||
.write(true)
|
||||
.create(true)
|
||||
.append(true)
|
||||
.open(root)?;
|
||||
|
||||
let mut line = var.to_owned();
|
||||
line.push_str(" ");
|
||||
line.push_str(val);
|
||||
writeln!(file, "{}", line)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn get(var: &str) -> Option<String> {
|
||||
let mut root = path::nextsync();
|
||||
root.push("config");
|
||||
@@ -98,7 +173,7 @@ pub fn get(var: &str) -> Option<String> {
|
||||
if let Ok(lines) = read::read_lines(root) {
|
||||
for line in lines {
|
||||
if let Ok(l) = line {
|
||||
if l.starts_with(var.clone()) {
|
||||
if l.starts_with(var) {
|
||||
let (_, val) = l.split_once(" ").unwrap();
|
||||
return Some(val.to_owned());
|
||||
}
|
||||
@@ -107,3 +182,5 @@ pub fn get(var: &str) -> Option<String> {
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ pub mod copied;
|
||||
|
||||
pub fn push() {
|
||||
// todo err when pushing new folder
|
||||
let _remote = match config::get("remote") {
|
||||
let _remote = match config::get_remote("origin") {
|
||||
Some(r) => r,
|
||||
None => {
|
||||
eprintln!("fatal: no remote set in configuration");
|
||||
|
||||
@@ -42,12 +42,19 @@ impl ApiBuilder {
|
||||
}
|
||||
|
||||
pub fn set_url(&mut self, method: Method, url: &str) -> &mut ApiBuilder {
|
||||
self.request = Some(self.client.request(method, url));
|
||||
let mut new_url = url.to_owned();
|
||||
if let Some(active) = config::get_core("force_insecure") {
|
||||
if active == "true" {
|
||||
new_url = url.replace("https", "http");
|
||||
}
|
||||
}
|
||||
|
||||
self.request = Some(self.client.request(method, new_url));
|
||||
self
|
||||
}
|
||||
|
||||
pub fn build_request(&mut self, method: Method, path: &str) -> &mut ApiBuilder {
|
||||
let remote = match config::get("remote") {
|
||||
let remote = match config::get_remote("origin") {
|
||||
Some(r) => r,
|
||||
None => {
|
||||
eprintln!("fatal: unable to find a remote");
|
||||
@@ -64,8 +71,8 @@ impl ApiBuilder {
|
||||
if path != "/" {
|
||||
url.push_str(path);
|
||||
}
|
||||
self.request = Some(self.client.request(method, url));
|
||||
self
|
||||
|
||||
self.set_url(method, &url)
|
||||
}
|
||||
|
||||
pub fn set_req(&mut self, meth: Method, p: &str, api_props: &ApiProps) -> &mut ApiBuilder {
|
||||
@@ -79,8 +86,8 @@ impl ApiBuilder {
|
||||
if p != "/" {
|
||||
url.push_str(p);
|
||||
}
|
||||
self.request = Some(self.client.request(meth, url));
|
||||
self
|
||||
|
||||
self.set_url(meth, &url)
|
||||
}
|
||||
|
||||
pub fn set_basic_auth(&mut self, login: String, pwd: String) -> &mut ApiBuilder {
|
||||
|
||||
@@ -24,7 +24,7 @@ impl Copy {
|
||||
pub fn set_url_copy(&mut self, url: &str, destination: &str) -> &mut Copy {
|
||||
self.api_builder.build_request(Method::from_bytes(b"COPY").unwrap(), url);
|
||||
|
||||
let remote = match config::get("remote") {
|
||||
let remote = match config::get_remote("origin") {
|
||||
Some(r) => r,
|
||||
None => {
|
||||
eprintln!("fatal: unable to find a remote");
|
||||
|
||||
@@ -25,7 +25,7 @@ impl Move {
|
||||
pub fn set_url_move(&mut self, url: &str, destination: &str) -> &mut Move {
|
||||
self.api_builder.build_request(Method::from_bytes(b"MOVE").unwrap(), url);
|
||||
|
||||
let remote = match config::get("remote") {
|
||||
let remote = match config::get_remote("origin") {
|
||||
Some(r) => r,
|
||||
None => {
|
||||
eprintln!("fatal: unable to find a remote");
|
||||
|
||||
@@ -67,7 +67,7 @@ impl ApiCall for ReqProps {
|
||||
}
|
||||
|
||||
fn set_url(&mut self, url: &str) -> &mut ReqProps {
|
||||
let remote = match config::get("remote") {
|
||||
let remote = match config::get_remote("origin") {
|
||||
Some(r) => r,
|
||||
None => {
|
||||
eprintln!("fatal: unable to find a remote");
|
||||
|
||||
@@ -39,7 +39,7 @@ impl RequestManager {
|
||||
{
|
||||
if self.host.is_none()
|
||||
{
|
||||
let remote = match config::get("remote") {
|
||||
let remote = match config::get_remote("origin") {
|
||||
Some(r) => r,
|
||||
None => {
|
||||
// todo ask user instead
|
||||
|
||||
@@ -1,29 +1,53 @@
|
||||
use clap::{App, Arg, SubCommand, ArgMatches};
|
||||
use crate::commands::config::ConfigSetArgs;
|
||||
|
||||
use crate::commands;
|
||||
|
||||
pub fn create() -> App<'static, 'static> {
|
||||
SubCommand::with_name("config")
|
||||
.arg(
|
||||
Arg::with_name("variable")
|
||||
.required(true)
|
||||
.takes_value(true)
|
||||
.value_name("VARIABLE")
|
||||
.about("Get and set repository or global options")
|
||||
.subcommand(
|
||||
SubCommand::with_name("get")
|
||||
.about("Get the value of a configuration variable")
|
||||
.arg(
|
||||
Arg::with_name("name")
|
||||
.help("The name of the configuration variable")
|
||||
.required(true)
|
||||
.index(1)
|
||||
)
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("value")
|
||||
.required(true)
|
||||
.takes_value(true)
|
||||
.value_name("VALUE")
|
||||
.subcommand(
|
||||
SubCommand::with_name("set")
|
||||
.about("Set a configuration variable")
|
||||
.arg(
|
||||
Arg::with_name("name")
|
||||
.help("The name of the configuration variable")
|
||||
.required(true)
|
||||
.index(1)
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("value")
|
||||
.help("The value to set")
|
||||
.required(true)
|
||||
.index(2)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
pub fn handler(args: &ArgMatches<'_>) {
|
||||
if let Some(mut var) = args.values_of("variable") {
|
||||
if let Some(mut val) = args.values_of("value") {
|
||||
if commands::config::set(var.next().unwrap(), val.next().unwrap()).is_err() {
|
||||
eprintln!("fatal: cannot save the value");
|
||||
}
|
||||
|
||||
match args.subcommand() {
|
||||
("set", Some(set_matches)) => {
|
||||
commands::config::config_set(ConfigSetArgs {
|
||||
name: set_matches.values_of("name"),
|
||||
value: set_matches.values_of("value"),
|
||||
});
|
||||
}
|
||||
_ => println!("Invalid or missing subcommand for 'config'"),
|
||||
}
|
||||
// AddArgs {
|
||||
// files: args.values_of("files"),
|
||||
// force: args.is_present("force"),
|
||||
// all: args.is_present("all"),
|
||||
// });
|
||||
}
|
||||
|
||||
@@ -11,17 +11,13 @@ pub fn create() -> App<'static, 'static> {
|
||||
.arg(
|
||||
Arg::with_name("name")
|
||||
.required(true)
|
||||
.multiple(false)
|
||||
.takes_value(true)
|
||||
.value_name("NAME")
|
||||
.index(1)
|
||||
.help("The name of the remote"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("url")
|
||||
.required(true)
|
||||
.multiple(false)
|
||||
.takes_value(true)
|
||||
.value_name("URL")
|
||||
.index(2)
|
||||
.help("The url of the remote"),
|
||||
)
|
||||
.about("Add a new remote to this repository")
|
||||
|
||||
@@ -18,7 +18,7 @@ impl Clone for ApiProps {
|
||||
}
|
||||
|
||||
pub fn get_api_props() -> ApiProps {
|
||||
let remote = match config::get("remote") {
|
||||
let remote = match config::get_remote("origin") {
|
||||
Some(r) => r,
|
||||
None => {
|
||||
eprintln!("fatal: unable to find a remote");
|
||||
|
||||
Reference in New Issue
Block a user