working
This commit is contained in:
parent
757020689c
commit
93b2b5c512
9 changed files with 255 additions and 114 deletions
147
src/actions.rs
147
src/actions.rs
|
|
@ -1,6 +1,5 @@
|
|||
use crate::types::{CadeActions, Env};
|
||||
use crate::types::{CadeActions, Env, EnvSet, InnerHook};
|
||||
use anyhow::{Context, Result, anyhow, bail};
|
||||
use serde_json::Value;
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
ffi::OsString,
|
||||
|
|
@ -8,7 +7,6 @@ use std::{
|
|||
io::{BufRead, Read},
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
type RawEnv = Vec<(String, Vec<String>)>;
|
||||
|
||||
#[repr(u8)]
|
||||
#[derive(bincode::Encode, bincode::Decode, PartialEq, Debug)]
|
||||
|
|
@ -37,11 +35,10 @@ pub fn load_flake(path: &Path, output: Option<String>) -> Result<RawEnv> {
|
|||
.output()
|
||||
.with_context(|| format!("loading flake at {}", path.display()))?
|
||||
.stdout;
|
||||
let json: Value = serde_json::from_slice(&output).context("parsing output as json")?;
|
||||
parse_json(json)
|
||||
parse_json(output)
|
||||
}
|
||||
|
||||
pub fn load_shell(path: &Path, filename: String) -> Result<CadeActions> {
|
||||
pub fn load_shell(path: &Path, filename: String) -> Result<RawEnv> {
|
||||
let mut nix_cmd = String::from("nix print-dev-env --json ");
|
||||
// let mut nix_cmd = String::from("nix-shell ");
|
||||
if !filename.is_empty() {
|
||||
|
|
@ -59,11 +56,10 @@ pub fn load_shell(path: &Path, filename: String) -> Result<CadeActions> {
|
|||
.output()
|
||||
.with_context(|| format!("loading shell at {}", path.display()))?
|
||||
.stdout;
|
||||
let json: Value = serde_json::from_slice(&output).context("parsing output as json")?;
|
||||
parse_json(json)
|
||||
EnvSet::from_json(output)?
|
||||
}
|
||||
|
||||
pub fn load_env(path: &Path, filename: String) -> Result<CadeActions> {
|
||||
pub fn load_env(path: &Path, filename: String) -> Result<EnvSet> {
|
||||
let mut p = path.to_path_buf();
|
||||
if filename.is_empty() {
|
||||
p.push(".env");
|
||||
|
|
@ -77,7 +73,7 @@ pub fn load_env(path: &Path, filename: String) -> Result<CadeActions> {
|
|||
parse_envs(buf)
|
||||
}
|
||||
|
||||
pub fn call(path: &Path, argv: Vec<String>) -> Result<CadeActions> {
|
||||
pub fn call(path: &Path, argv: Vec<String>) -> Result<EnvSet> {
|
||||
let mut it = argv.iter();
|
||||
// safety: already checked at parsing
|
||||
let mut process = std::process::Command::new(it.next().unwrap());
|
||||
|
|
@ -94,117 +90,54 @@ pub fn call(path: &Path, argv: Vec<String>) -> Result<CadeActions> {
|
|||
parse_envs(text)
|
||||
}
|
||||
|
||||
fn parse_envs(text: String) -> Result<RawEnv> {
|
||||
let mut envs = Vec::new();
|
||||
for line in text.lines() {
|
||||
let split: Vec<&str> = line.split('=').collect();
|
||||
let parse = match split.len() {
|
||||
3 => {
|
||||
let key = split[0];
|
||||
let values = &split[2].split(":").to_owned().collect();
|
||||
}
|
||||
2 => {
|
||||
// TODO
|
||||
}
|
||||
_ => {
|
||||
return Err(anyhow!("parsing variable from {text}"));
|
||||
}
|
||||
// 1 => Clear(split[0].to_string()),
|
||||
// _ => Add(split[0].to_string(), split[1..].concat().to_string()),
|
||||
};
|
||||
envs.push(parse);
|
||||
}
|
||||
Ok(envs)
|
||||
}
|
||||
// TODO cache results by hash/storepath and read from db so we don't
|
||||
// need to eat eval every time
|
||||
|
||||
fn parse_json(json: Value) -> Result<RawEnv> {
|
||||
if json.is_object()
|
||||
&& let Some(all_vars) = json.get("variables")
|
||||
{
|
||||
let vars = all_vars
|
||||
.as_object()
|
||||
.map(|inner| {
|
||||
inner
|
||||
.iter()
|
||||
.filter(|(var, _)| match var.as_str() {
|
||||
"NIX_BUILD_TOP"
|
||||
| "NIX_BUILD_CORES"
|
||||
| "NIX_STORE"
|
||||
| "TEMP"
|
||||
| "TEMPDIR"
|
||||
| "TMP"
|
||||
| "TMPDIR"
|
||||
| "builder"
|
||||
| "out"
|
||||
| "stdenv"
|
||||
| "system"
|
||||
| "dontAddDisableDepTrack"
|
||||
| "outputs" => false,
|
||||
_ => true,
|
||||
})
|
||||
.filter_map(|var| {
|
||||
Some((var.0.to_string(), var.1.get("value")?.as_str()?.to_owned()))
|
||||
})
|
||||
.map(|(name, value)| {
|
||||
(
|
||||
name,
|
||||
value
|
||||
.split(':')
|
||||
.map(|s| s.to_string())
|
||||
.collect::<Vec<String>>(),
|
||||
)
|
||||
})
|
||||
.collect()
|
||||
})
|
||||
.context("collecting env vars")?;
|
||||
Ok(vars)
|
||||
} else {
|
||||
Err(anyhow!("failed to parse PATH value from JSON output"))
|
||||
}
|
||||
fn check_permission(dir: &Path) -> Permission {
|
||||
// TODO check database for permission
|
||||
todo!();
|
||||
}
|
||||
|
||||
pub fn do_activation() -> Result<()> {
|
||||
let dir = ensure_dir()?;
|
||||
let db = sled::open(dir).context("open database")?;
|
||||
let cwd = std::env::current_dir()
|
||||
.context("determine CWD")?
|
||||
.into_os_string();
|
||||
// TODO finish sqlite impl
|
||||
let db = rusqlite::Connection::open(dir)?;
|
||||
|
||||
if db
|
||||
.get(cwd.into_encoded_bytes())
|
||||
.map(|perm| {
|
||||
perm.map(|inner| {
|
||||
let (p, _) =
|
||||
bincode::decode_from_slice(inner.as_ref(), bincode::config::standard())
|
||||
.unwrap_or((Permission::Disallowed, 0));
|
||||
p
|
||||
})
|
||||
.unwrap_or(Permission::Disallowed)
|
||||
})
|
||||
.unwrap_or(Permission::Disallowed)
|
||||
== Permission::Disallowed
|
||||
{
|
||||
// let db = sled::open(dir).context("open database")?;
|
||||
let mut cwd = std::env::current_dir().context("determine CWD")?;
|
||||
let cwd_str = cwd
|
||||
.clone()
|
||||
.into_os_string()
|
||||
.into_string()
|
||||
.map_err(|_| anyhow!("cwd has invalid unicode"))?;
|
||||
|
||||
let permission = db.query_one(
|
||||
"SELECT Permission FROM WorkingPaths WHERE Path=(:path)",
|
||||
&[(":path", &cwd_str)],
|
||||
|row| Ok(row.get(0).unwrap_or(false)),
|
||||
)?;
|
||||
if !permission {
|
||||
bail!("cade is not permitted to operate here; use 'cade allow'.");
|
||||
}
|
||||
|
||||
let mut current_dir = std::env::current_dir().context("determine CWD")?;
|
||||
let base_env = std::env::vars().collect::<HashMap<String, String>>();
|
||||
|
||||
use crate::core::{read_cade, realise};
|
||||
let mut cascade = HashMap::new();
|
||||
cascade.insert(
|
||||
current_dir.clone(),
|
||||
read_cade(¤t_dir.join(".cade")).context("reading cade file")?,
|
||||
cwd.clone(),
|
||||
read_cade(&cwd.join(".cade")).context("reading cade file")?,
|
||||
);
|
||||
|
||||
while let Some(parent) = current_dir.parent()
|
||||
// recurse into parent dirs
|
||||
while let Some(parent) = cwd.parent()
|
||||
&& std::fs::exists(parent.join(".cade"))
|
||||
.context("check for .cade file in parent directory")?
|
||||
{
|
||||
current_dir = parent.to_path_buf();
|
||||
cwd = parent.to_path_buf();
|
||||
cascade.insert(
|
||||
current_dir.clone(),
|
||||
read_cade(¤t_dir.join(".cade")).context("reading cade file")?,
|
||||
cwd.clone(),
|
||||
read_cade(&cwd.join(".cade")).context("reading cade file")?,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -217,24 +150,27 @@ pub fn do_activation() -> Result<()> {
|
|||
for action in env_actions {
|
||||
env.entry(action.name)
|
||||
.and_modify(|iv: &mut Vec<String>| {
|
||||
iv.extend(action.value);
|
||||
iv.extend(action.value.clone());
|
||||
})
|
||||
.or_insert(action.value);
|
||||
}
|
||||
}
|
||||
Purify => {
|
||||
// FIXME this is a dumb way to purify an env
|
||||
for (bk, bv) in base_env.iter() {
|
||||
env.entry(bk).and_modify(|inner| inner)
|
||||
if env.get(bk).is_some_and(|inner| inner.contains(bv)) {
|
||||
env.remove(bk);
|
||||
}
|
||||
}
|
||||
}
|
||||
Hook(hook) => {}
|
||||
Hook(hook) => match hook.kind {
|
||||
_ => todo!(),
|
||||
},
|
||||
};
|
||||
}
|
||||
for (k, v) in env {
|
||||
println!("{k}={v}");
|
||||
let value: String = v.into_iter().map(|s| [&s, ":"].concat()).collect();
|
||||
println!("{k}={}", &value[..value.len() - 1]);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -265,6 +201,7 @@ fn ensure_dir() -> Result<PathBuf> {
|
|||
if !std::fs::exists(&path).is_ok_and(|v| v) {
|
||||
std::fs::create_dir(&path).context("create cade's state path")?;
|
||||
}
|
||||
// FIXME should this be appended after ? we only guarantee the dir here ..
|
||||
path.push("permissions.db");
|
||||
Ok(path)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue