nushell/src/object/config.rs

84 lines
2.6 KiB
Rust
Raw Normal View History

2019-08-02 21:15:07 +02:00
use crate::commands::from_toml::convert_toml_value_to_nu_value;
use crate::commands::to_toml::value_to_toml_value;
use crate::errors::ShellError;
2019-08-02 21:15:07 +02:00
use crate::object::{Dictionary, Value};
use crate::prelude::*;
use app_dirs::*;
use indexmap::IndexMap;
use log::trace;
2019-08-02 21:15:07 +02:00
use serde::{Deserialize, Serialize};
use std::fs::{self, OpenOptions};
use std::io;
2019-08-02 21:15:07 +02:00
use std::path::{Path, PathBuf};
const APP_INFO: AppInfo = AppInfo {
name: "nu",
author: "nu shell developers",
};
#[derive(Deserialize, Serialize)]
struct Config {
#[serde(flatten)]
2019-08-01 03:58:42 +02:00
extra: IndexMap<String, Tagged<Value>>,
2019-08-02 21:15:07 +02:00
}
crate fn config_path() -> Result<PathBuf, ShellError> {
let location = app_root(AppDataType::UserConfig, &APP_INFO)
.map_err(|err| ShellError::string(&format!("Couldn't open config file:\n{}", err)))?;
Ok(location.join("config.toml"))
}
2019-08-01 03:58:42 +02:00
crate fn write_config(config: &IndexMap<String, Tagged<Value>>) -> Result<(), ShellError> {
let location = app_root(AppDataType::UserConfig, &APP_INFO)
.map_err(|err| ShellError::string(&format!("Couldn't open config file:\n{}", err)))?;
let filename = location.join("config.toml");
touch(&filename)?;
2019-08-02 21:15:07 +02:00
let contents = value_to_toml_value(&Value::Object(Dictionary::new(config.clone())));
let contents = toml::to_string(&contents)?;
fs::write(&filename, &contents)?;
Ok(())
}
2019-08-01 03:58:42 +02:00
crate fn config(span: impl Into<Span>) -> Result<IndexMap<String, Tagged<Value>>, ShellError> {
2019-07-08 18:44:53 +02:00
let span = span.into();
let location = app_root(AppDataType::UserConfig, &APP_INFO)
.map_err(|err| ShellError::string(&format!("Couldn't open config file:\n{}", err)))?;
let filename = location.join("config.toml");
touch(&filename)?;
trace!("config file = {}", filename.display());
let contents = fs::read_to_string(filename)
.map(|v| v.simple_spanned(span))
.map_err(|err| ShellError::string(&format!("Couldn't read config file:\n{}", err)))?;
2019-08-02 21:15:07 +02:00
let parsed: toml::Value = toml::from_str(&contents)
.map_err(|err| ShellError::string(&format!("Couldn't parse config file:\n{}", err)))?;
2019-08-09 06:51:21 +02:00
let value = convert_toml_value_to_nu_value(&parsed, Tag::unknown_origin(span));
let tag = value.tag();
2019-08-02 21:15:07 +02:00
match value.item {
Value::Object(Dictionary { entries }) => Ok(entries),
other => Err(ShellError::type_error(
"Dictionary",
2019-08-09 06:51:21 +02:00
other.type_name().tagged(tag),
2019-08-02 21:15:07 +02:00
)),
}
}
// A simple implementation of `% touch path` (ignores existing files)
fn touch(path: &Path) -> io::Result<()> {
match OpenOptions::new().create(true).write(true).open(path) {
Ok(_) => Ok(()),
Err(e) => Err(e),
}
}