From f787ece122aab325d10fa3ff43ed52c2748691d4 Mon Sep 17 00:00:00 2001 From: Tip ten Brink <75669206+tiptenbrink@users.noreply.github.com> Date: Thu, 2 May 2024 21:09:07 +0200 Subject: [PATCH] resolve part mostly done, partially migrated next --- src/next/config.rs | 48 ++++----- src/next/process.rs | 15 ++- src/next/resolve.rs | 193 ++++++++++++++++++++++++------------ src/next/run.rs | 54 +++++++--- src/next/secrets.rs | 52 ++++++---- src/next/state.rs | 233 ++++++++++++++++++++------------------------ 6 files changed, 336 insertions(+), 259 deletions(-) diff --git a/src/next/config.rs b/src/next/config.rs index 6867a90..fb67869 100644 --- a/src/next/config.rs +++ b/src/next/config.rs @@ -86,35 +86,25 @@ fn overwrite_scope(original: ConfigScope, replacing: ConfigScope) -> ConfigScope } pub(crate) fn merge_vars( - root_vars: Option>, - overwrite_vars: Option>, -) -> Option> { - if let Some(root_vars) = root_vars { - if let Some(overwrite_vars) = overwrite_vars { - let mut vars_map: HashMap = root_vars - .iter() - .map(|v| (v.key.clone(), v.env_name.clone())) - .collect(); - - for cfg_var in overwrite_vars { - vars_map.insert(cfg_var.key, cfg_var.env_name); - } - - Some( - vars_map - .into_iter() - .map(|(k, v)| ConfigVar { - env_name: v, - key: k, - }) - .collect(), - ) - } else { - Some(root_vars) - } - } else { - overwrite_vars.clone() + root_vars: Vec, + overwrite_vars: Vec, +) -> Vec { + let mut vars_map: HashMap = root_vars + .iter() + .map(|v| (v.key.clone(), v.env_name.clone())) + .collect(); + + for cfg_var in overwrite_vars { + vars_map.insert(cfg_var.key, cfg_var.env_name); } + + vars_map + .into_iter() + .map(|(k, v)| ConfigVar { + env_name: v, + key: k, + }) + .collect() } fn overwrite_arguments(root_config: ArgumentConfig, overwrite_config: ArgumentConfig) -> ArgumentConfig { @@ -122,7 +112,7 @@ fn overwrite_arguments(root_config: ArgumentConfig, overwrite_config: ArgumentCo let execution_path = overwrite_option(root_config.execution_path, overwrite_config.execution_path); let executable = overwrite_option(root_config.executable, overwrite_config.executable); - let envs = merge_vars(root_config.envs, overwrite_config.envs); + let envs = merge_option(root_config.envs, overwrite_config.envs, &merge_vars); ArgumentConfig { scope, diff --git a/src/next/process.rs b/src/next/process.rs index 147cc68..7e23ad2 100644 --- a/src/next/process.rs +++ b/src/next/process.rs @@ -60,20 +60,19 @@ where /// Runs the entrypoint, sending the entrypoint's stdout and stderr to stdout. It adds the provided envs to /// the envs of the tidploy process. `input_bytes` is useful mostly for testing, if set to None then the /// child process will just inherit the stdin of the tidploy process. -pub(crate) fn run_entrypoint>( - entrypoint_dir: P, - entrypoint: &RelativePath, +pub(crate) fn run_entrypoint( + working_dir: &Path, + entrypoint: &Path, envs: HashMap, input_bytes: Option>, ) -> Result { - println!("Running {}!", &entrypoint); - let program_path = entrypoint.to_path(entrypoint_dir.as_ref()); + println!("Running {:?} in working dir {:?}!", &entrypoint, &working_dir); // Use parent process env variables as base let mut combined_envs: HashMap<_, _> = std::env::vars().collect(); combined_envs.extend(envs); - let cmd_expr = cmd(&program_path, Vec::::new()) - .dir(entrypoint_dir.as_ref()) + let cmd_expr = cmd(entrypoint, Vec::::new()) + .dir(working_dir) .full_env(&combined_envs) .stderr_to_stdout() .unchecked(); @@ -87,7 +86,7 @@ pub(crate) fn run_entrypoint>( let reader = cmd_expr.reader()?; - let entry_span = span!(Level::DEBUG, "entrypoint", path = program_path.to_str()); + let entry_span = span!(Level::DEBUG, "entrypoint", path = entrypoint.to_string_lossy().as_ref()); let _enter = entry_span.enter(); let mut out: String = String::with_capacity(128); diff --git a/src/next/resolve.rs b/src/next/resolve.rs index f880ef3..3f5cc80 100644 --- a/src/next/resolve.rs +++ b/src/next/resolve.rs @@ -1,17 +1,18 @@ use std::{collections::HashMap, env, path::{Path, PathBuf}}; -use relative_path::RelativePath; +use relative_path::{RelativePath, RelativePathBuf}; -use super::{config::traverse_configs, errors::ResolutionError}; +use super::{config::{merge_vars, traverse_configs, ArgumentConfig, ConfigScope, ConfigVar}, errors::ResolutionError}; #[derive(Default)] -struct SecretScopeArguments { - name: Option, - sub: Option, - service: Option +pub(crate) struct SecretScopeArguments { + pub(crate) name: Option, + pub(crate) sub: Option, + pub(crate) service: Option } impl SecretScopeArguments { + /// Overrides fields with other if other has them defined fn merge(&self, other: Self) -> Self { Self { service: other.service.or(self.service), @@ -21,12 +22,45 @@ impl SecretScopeArguments { } } +impl From for SecretScopeArguments { + fn from(value: ConfigScope) -> Self { + Self { + service: value.service, + name: value.name, + sub: value.sub + } + } +} + #[derive(Default)] -struct RunArguments { - executable: Option, - execution_path: Option, - envs: Vec, - scope_args: SecretScopeArguments +pub(crate) struct RunArguments { + pub(crate) executable: Option, + pub(crate) execution_path: Option, + pub(crate) envs: Vec, + pub(crate) scope_args: SecretScopeArguments +} + +impl RunArguments { + /// Overrides fields with other if other has them defined + fn merge(&self, other: Self) -> Self { + Self { + executable: other.executable.or(self.executable), + execution_path: other.execution_path.or(self.execution_path), + envs: merge_vars(self.envs, other.envs), + scope_args: self.scope_args.merge(other.scope_args) + } + } +} + +impl From for RunArguments { + fn from(value: ArgumentConfig) -> Self { + RunArguments { + executable: value.executable, + execution_path: value.execution_path, + envs: value.envs.unwrap_or_default(), + scope_args: value.scope.map(|s| s.into()).unwrap_or_default(), + } + } } struct SecretArguments { @@ -34,18 +68,18 @@ struct SecretArguments { scope_args: SecretScopeArguments } -struct SecretScope { - service: String, - name: String, - sub: String, - hash: String +pub(crate) struct SecretScope { + pub(crate) service: String, + pub(crate) name: String, + pub(crate) sub: String, + pub(crate) hash: String } -struct RunResolved { - executable: PathBuf, - execution_path: PathBuf, - envs: HashMap, - scope: SecretScope +pub(crate) struct RunResolved { + pub(crate) executable: PathBuf, + pub(crate) execution_path: PathBuf, + pub(crate) envs: Vec, + pub(crate) scope: SecretScope } struct SecretResolved { @@ -53,16 +87,16 @@ struct SecretResolved { scope: SecretScope } -enum OutArguments { - Secret, - Run -} - enum Arguments { Secret(SecretArguments), Run(RunArguments) } +// enum ResolvedEnvironment { +// Run(RunResolved), +// Secret(SecretResolved) +// } + fn env_scope_args() -> SecretScopeArguments { let mut scope_args = SecretScopeArguments::default(); @@ -103,46 +137,79 @@ fn env_run_args() -> RunArguments { run_arguments } -fn merge_scope(root_config: SecretScope, overwrite_config: SecretScope) -> SecretScope { - ArgumentConfig { - scope, - executable, - execution_path, - envs +pub(crate) trait Resolve where Self: Sized { + fn merge_env_config(self, state_root: &Path, state_path: &RelativePath) -> Result; + + fn resolve(self, resolve_root: &Path, name: &str, sub: &str, hash: &str) -> Resolved; +} + +fn resolve_scope(args: Arguments, name: &str, sub: &str, hash: &str) -> SecretScope { + let scope_args = match args { + Arguments::Run(run_args) => run_args.scope_args, + Arguments::Secret(secret_args) => secret_args.scope_args + }; + + SecretScope { + service: scope_args.service.unwrap_or("tidploy".to_owned()), + name: scope_args.name.unwrap_or(name.to_owned()), + sub: scope_args.sub.unwrap_or(sub.to_owned()), + hash: hash.to_owned() } } -fn resolve(state_root: &Path, state_path: &RelativePath, resolve_root: &Path, hash: String, args: Arguments) -> Result<(), ResolutionError> { - let config = traverse_configs(state_root, state_path)?; - - match args { - Arguments::Secret(secret_args) => { - let secret_args_env = env_secret_args(); - - let merged_args = SecretArguments { - key: secret_args.key, - scope_args: secret_args_env.scope_args.merge(secret_args.scope_args) - }; - - let merged_args = if let Some(config_args) = config.argument { - if let Some(config_scope) = config_args.scope { - let scope_args = merged_args.scope_args; - SecretArguments { - key: merged_args.key, - scope_args: SecretScopeArguments { - service: scope_args.service.or(config_scope.service), - name: scope_args.name.or(config_scope.name), - sub: scope_args.sub.or(config_scope.sub), - } - } - } else { - merged_args - } - } else { - merged_args - }; +impl Resolve for RunArguments { + fn merge_env_config(self, state_root: &Path, state_path: &RelativePath) -> Result { + let config = traverse_configs(state_root, state_path)?; + + let run_args_env = env_run_args(); + + let merged_args = run_args_env.merge(self); + + let config_run = config.argument.map(|a| RunArguments::from(a)) + .unwrap_or_default(); + + Ok(config_run.merge(merged_args)) + } + + fn resolve(self, resolve_root: &Path, name: &str, sub: &str, hash: &str) -> RunResolved { + let scope = resolve_scope(Arguments::Run(self), name, sub, hash); + + let relative_exe = RelativePathBuf::from(self.executable.unwrap_or("".to_owned())); + let relative_exn_path = RelativePathBuf::from(self.execution_path.unwrap_or("".to_owned())); + RunResolved { + executable: relative_exe.to_path(resolve_root), + execution_path: relative_exn_path.to_path(resolve_root), + envs: self.envs, + scope } } +} + +impl Resolve for SecretArguments { + fn merge_env_config(self, state_root: &Path, state_path: &RelativePath) -> Result { + let config = traverse_configs(state_root, state_path)?; + + let secret_args_env = env_secret_args(); + + let mut merged_args = SecretArguments { + key: self.key, + scope_args: secret_args_env.scope_args.merge(self.scope_args) + }; + + let config_scope = config.argument.map(|a| a.scope).flatten().map(|s| SecretScopeArguments::from(s)) + .unwrap_or_default(); + + merged_args.scope_args = config_scope.merge(merged_args.scope_args); - Ok(()) -} \ No newline at end of file + Ok(merged_args) + } + + fn resolve(self, resolve_root: &Path, name: &str, sub: &str, hash: &str) -> SecretResolved { + let scope = resolve_scope(Arguments::Secret(self), name, sub, hash); + + SecretResolved { + key: self.key, + scope + } + } +} diff --git a/src/next/run.rs b/src/next/run.rs index 5f368c9..886da8a 100644 --- a/src/next/run.rs +++ b/src/next/run.rs @@ -3,22 +3,20 @@ use relative_path::RelativePathBuf; use tracing::{debug, instrument}; use crate::{ - archives::extract_archive, - filesystem::get_dirs, - state::{create_state_create, create_state_run, CliEnvState}, + archives::extract_archive, filesystem::get_dirs, next::{resolve::{Resolve, RunArguments, SecretScopeArguments}, run, secrets::secret_vars_to_envs, state::{create_resolve_state, ResolveState}}, state::{create_state_create, create_state_run, CliEnvState} }; use super::{ - process::{run_entrypoint, EntrypointOut}, - state::{create_state_run as create_state_run_next, resolve_paths, StateIn}, + process::{run_entrypoint, EntrypointOut}, resolve::RunResolved, state::StateIn }; pub(crate) fn run_command( state_in: StateIn, + service: Option, executable: Option, variables: Vec, ) -> Result { - run_command_input(state_in, executable, variables, None) + run_command_input(state_in, service, executable, variables, None) } #[instrument(name = "run", level = "debug", skip_all)] @@ -68,27 +66,57 @@ pub(crate) fn run_command_input_old_state( // let state = extra_envs(state); let relative_path = RelativePathBuf::from(&state.exe_name); - - run_entrypoint(state.deploy_dir(), &relative_path, state.envs, input_bytes) + let exe_path = relative_path.to_path(&state.deploy_dir()); + run_entrypoint(&state.deploy_dir(), &exe_path, state.envs, input_bytes) } #[instrument(name = "run", level = "debug", skip_all)] pub(crate) fn run_command_input( state_in: StateIn, + service: Option, executable: Option, variables: Vec, input_bytes: Option>, ) -> Result { debug!("Run command called with in_state {:?}, executable {:?}, variables {:?} and input_bytes {:?}", state_in, executable, variables, input_bytes); + + let mut scope_args = SecretScopeArguments::default(); + scope_args.service = service; + let run_args = RunArguments { + executable, + execution_path: None, + envs: Vec::new(), + scope_args + }; + let ResolveState { + state_root, + state_path, + resolve_root, + name, + sub, + hash + } = create_resolve_state(state_in)?; + + + let run_args = run_args.merge_env_config(&state_root, &state_path)?; + let run_resolved = run_args.resolve(&resolve_root, &name, &sub, &hash); + - let state = create_state_run_next(state_in, executable.as_deref(), variables)?; + run_unit_input(run_resolved, input_bytes) +} + +pub(crate) fn run_unit_input( + run_resolved: RunResolved, + input_bytes: Option>, +) -> Result { + //debug!("Run command called with in_state {:?}, executable {:?}, variables {:?} and input_bytes {:?}", state_in, executable, variables, input_bytes); - let resolved_paths = resolve_paths(state.paths); + let secret_vars = secret_vars_to_envs(&run_resolved.scope, run_resolved.envs)?; run_entrypoint( - &resolved_paths.exe_dir, - &resolved_paths.exe_path, - state.envs, + &run_resolved.execution_path, + &run_resolved.executable, + secret_vars, input_bytes, ) } diff --git a/src/next/secrets.rs b/src/next/secrets.rs index 8ba9394..542e296 100644 --- a/src/next/secrets.rs +++ b/src/next/secrets.rs @@ -1,4 +1,4 @@ -use std::thread::scope; +use std::{collections::HashMap}; use color_eyre::eyre::Report; use keyring::{Entry, Error as KeyringError}; @@ -8,8 +8,7 @@ use tracing::{debug, instrument}; use crate::commands::TIDPLOY_DEFAULT; use super::{ - errors::{SecretError, SecretKeyringError, StateError, WrapStateErr}, - state::{create_state, Scope, State, StateIn}, + config::ConfigVar, errors::{SecretError, SecretKeyringError, StateError, WrapStateErr}, resolve::SecretScope, state::{create_state, StateIn} }; fn get_keyring_secret(key: &str, service: &str) -> Result, KeyringError> { @@ -41,7 +40,7 @@ fn set_keyring_secret(secret: &str, key: &str, service: &str) -> Result<(), Keyr } fn key_from_scope( - scope: &Scope, + scope: &SecretScope, key: &str, ) -> String { format!("{}::{}::{}:{}", scope.name, scope.sub, scope.hash, key) @@ -50,7 +49,7 @@ fn key_from_scope( /// Gets secret using a key with format `:::::`. #[instrument(name = "get_secret", level = "debug", skip_all)] pub(crate) fn get_secret( - scope: &Scope, + scope: &SecretScope, key: &str, ) -> Result { debug!("Getting secret with key {}", key); @@ -68,7 +67,7 @@ pub(crate) fn get_secret( /// Prompts for secret and saves it at `:::::`. /// If `prompt` is None it will prompt for a password, otherwise it will use the given prompt. fn secret_prompt( - scope: &Scope, + scope: &SecretScope, key: &str, prompt: Option, ) -> Result { @@ -87,20 +86,35 @@ fn secret_prompt( Ok(store_key) } -pub(crate) fn secret_command( - state_in: StateIn, - key: &str, - prompt: Option, -) -> Result { - debug!( - "Secret command called with in_state {:?}, key {:?} and prompt {:?}", - state_in, key, prompt - ); +// pub(crate) fn secret_command( +// state_in: StateIn, +// key: &str, +// prompt: Option, +// ) -> Result { +// debug!( +// "Secret command called with in_state {:?}, key {:?} and prompt {:?}", +// state_in, key, prompt +// ); - let state = create_state(state_in)?; +// let state = create_state(state_in)?; - let store_key = secret_prompt(&state, key, prompt)?; +// let store_key = secret_prompt(&state, key, prompt)?; - println!("Set secret with store key {}!", &store_key); - Ok(store_key) +// println!("Set secret with store key {}!", &store_key); +// Ok(store_key) +// } + +pub(crate) fn secret_vars_to_envs( + scope: &SecretScope, + vars: Vec, +) -> Result, StateError> { + let mut envs = HashMap::::new(); + for e in vars { + debug!("Getting pass for {:?}", e); + let pass = get_secret(scope, &e.key) + .to_state_err("Getting secret for config var to create env map.".to_owned())?; + + envs.insert(e.env_name, pass); + } + Ok(envs) } diff --git a/src/next/state.rs b/src/next/state.rs index 5973e72..5ea4bd1 100644 --- a/src/next/state.rs +++ b/src/next/state.rs @@ -26,7 +26,6 @@ impl Default for InferContext { #[derive(Default, Debug)] pub(crate) struct StateIn { pub(crate) context: InferContext, - pub(crate) service: Option, } impl StateIn { @@ -48,8 +47,6 @@ pub(crate) struct StatePaths { pub(crate) context_root: PathBuf, pub(crate) state_root: RelativePathBuf, pub(crate) state_path: RelativePathBuf, - pub(crate) exe_dir: RelativePathBuf, - pub(crate) exe_path: RelativePathBuf, } impl StatePaths { @@ -67,120 +64,85 @@ impl StatePaths { }; let state_root = RelativePathBuf::new(); let state_path = RelativePathBuf::new(); - let exe_dir = RelativePathBuf::new(); - let exe_path = RelativePathBuf::from("entrypoint.sh"); Ok(StatePaths { context_root, state_path, state_root, - exe_dir, - exe_path, }) } } -#[derive(Debug)] -pub(crate) struct State { - pub(crate) context_name: String, - pub(crate) paths: StatePaths, - pub(crate) envs: HashMap, - /// This defaults to 'tidploy' almost everywhere, it is mostly used for testing - pub(crate) service: String, -} - -impl State { - /// Creates a new state, initializing the context root as the current directory. The context name is - /// derived from the directory name, with non-UTF-8 characters replaced by � (U+FFFD) - fn new(state_in: StateIn) -> Result { - let paths = StatePaths::new(state_in.context)?; - - let service = state_in.service.unwrap_or("tidploy".to_owned()); - - let context_name = paths - .context_root - .file_name() - .map(|s| s.to_string_lossy().to_string()) - .ok_or_else(|| { - StateErrorKind::InvalidRoot(paths.context_root.to_string_lossy().to_string()) - }) - .to_state_err( - "Getting context name from context root path for new state.".to_owned(), - )?; - - Ok(State { - context_name, - paths, - envs: HashMap::new(), - service, - }) - } - - pub(crate) fn state_name(&self) -> &str { - let rel_name = self.paths.state_path.as_str(); - if rel_name.is_empty() { - "tidploy_root" - } else { - rel_name - } - } - - pub(crate) fn state_hash(&self) -> Result { - Ok("todo_hash".to_owned()) - } -} - -#[instrument(name = "get_secret_vars", level = "debug", skip_all)] -fn secret_vars_to_envs( - state: &State, - vars: Vec, -) -> Result, StateError> { - let mut envs = HashMap::::new(); - for e in vars { - debug!("Getting pass for {:?}", e); - let pass = get_secret( - &state.service, - Some(&state.context_name), - Some(state.state_name()), - &state.state_hash()?, - &e.key, - ) - .to_state_err("Getting secret for config var to create env map.".to_owned())?; - - envs.insert(e.env_name, pass); - } - Ok(envs) -} - -pub(crate) struct StatePathsResolved { - pub(crate) context_root: PathBuf, - pub(crate) state_root: PathBuf, - pub(crate) state_path: RelativePathBuf, - pub(crate) exe_dir: PathBuf, - pub(crate) exe_path: RelativePathBuf, -} - -pub(crate) struct Scope { - pub(crate) service: String, - pub(crate) name: String, - pub(crate) sub: String, - pub(crate) hash: String -} - -pub(crate) struct ResolvedEnvironment { - pub(crate) exe_dir: PathBuf, - pub(crate) exe_path: RelativePathBuf, -} - -pub(crate) fn resolve_paths(state_paths: StatePaths) -> StatePathsResolved { - StatePathsResolved { - state_root: state_paths.state_root.to_path(&state_paths.context_root), - state_path: state_paths.state_path, - exe_dir: state_paths.exe_dir.to_path(&state_paths.context_root), - exe_path: state_paths.exe_path, - context_root: state_paths.context_root, - } -} +// #[derive(Debug)] +// pub(crate) struct State { +// pub(crate) context_name: String, +// pub(crate) paths: StatePaths, +// pub(crate) envs: HashMap, +// /// This defaults to 'tidploy' almost everywhere, it is mostly used for testing +// pub(crate) service: String, +// } + +// impl State { +// /// Creates a new state, initializing the context root as the current directory. The context name is +// /// derived from the directory name, with non-UTF-8 characters replaced by � (U+FFFD) +// fn new(state_in: StateIn) -> Result { +// let paths = StatePaths::new(state_in.context)?; + +// let context_name = paths +// .context_root +// .file_name() +// .map(|s| s.to_string_lossy().to_string()) +// .ok_or_else(|| { +// StateErrorKind::InvalidRoot(paths.context_root.to_string_lossy().to_string()) +// }) +// .to_state_err( +// "Getting context name from context root path for new state.".to_owned(), +// )?; + +// Ok(State { +// context_name, +// paths, +// envs: HashMap::new(), +// service, +// }) +// } + +// pub(crate) fn state_name(&self) -> &str { +// let rel_name = self.paths.state_path.as_str(); +// if rel_name.is_empty() { +// "tidploy_root" +// } else { +// rel_name +// } +// } + +// // pub(crate) fn state_hash(&self) -> Result { +// // Ok("todo_hash".to_owned()) +// // } +// } + +// pub(crate) struct StatePathsResolved { +// pub(crate) context_root: PathBuf, +// pub(crate) state_root: PathBuf, +// pub(crate) state_path: RelativePathBuf, +// pub(crate) exe_dir: PathBuf, +// pub(crate) exe_path: RelativePathBuf, +// } + +// pub(crate) struct ResolvedEnvironment { +// pub(crate) exe_dir: PathBuf, +// pub(crate) exe_path: RelativePathBuf, +// } + +// pub(crate) fn resolve_paths(state_paths: StatePaths) -> StatePathsResolved { +// StatePathsResolved { +// state_root: state_paths.state_root.to_path(&state_paths.context_root), +// state_path: state_paths.state_path, +// exe_dir: state_paths.exe_dir.to_path(&state_paths.context_root), +// exe_path: state_paths.exe_path, +// context_root: state_paths.context_root, +// } +// } /// Parses the list of strings given and interprets them as each pair of two being a secret key and target /// env name. @@ -195,26 +157,43 @@ fn parse_cli_vars(envs: Vec) -> Vec { .collect() } -/// Creates the state that is used to run the executable. -#[instrument(name = "run_state", level = "debug", skip_all)] -pub(crate) fn create_state_run( - state_in: StateIn, - exe_path: Option<&str>, - envs: Vec, -) -> Result { - let mut state = create_state(state_in)?; - let secret_vars = parse_cli_vars(envs); - state.envs = secret_vars_to_envs(&state, secret_vars)?; - if let Some(exe_path) = exe_path { - state.paths.exe_path = RelativePathBuf::from(exe_path); - } - debug!("Created run state is {:?}", state); - Ok(state) +// pub(crate) fn create_state(state_in: StateIn) -> Result { +// let state = State::new(state_in)?; + +// debug!("Created state is {:?}", state); +// Ok(state) +// } + +#[derive(Debug)] +pub(crate) struct ResolveState { + pub(crate) state_root: PathBuf, + pub(crate) state_path: RelativePathBuf, + pub(crate) resolve_root: PathBuf, + pub(crate) name: String, + pub(crate) sub: String, + pub(crate) hash: String, } -pub(crate) fn create_state(state_in: StateIn) -> Result { - let state = State::new(state_in)?; +pub(crate) fn create_resolve_state(state_in: StateIn) -> Result { + let paths = StatePaths::new(state_in.context)?; - debug!("Created state is {:?}", state); - Ok(state) + let name = paths + .context_root + .file_name() + .map(|s| s.to_string_lossy().to_string()) + .ok_or_else(|| { + StateErrorKind::InvalidRoot(paths.context_root.to_string_lossy().to_string()) + }) + .to_state_err( + "Getting context name from context root path for new state.".to_owned(), + )?; + + Ok(ResolveState { + state_root: paths.state_root.to_path(&paths.context_root), + state_path: paths.state_path, + resolve_root: paths.context_root, + name, + sub: "tidploy_root".to_owned(), + hash: "todo_hash".to_owned() + }) }