diff --git a/Cargo.lock b/Cargo.lock index 75044275..55e55643 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -131,6 +131,7 @@ name = "deploy-rs" version = "0.1.0" dependencies = [ "clap", + "dirs", "flexi_logger", "fork", "futures-util", @@ -149,6 +150,27 @@ dependencies = [ "yn", ] +[[package]] +name = "dirs" +version = "5.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" +dependencies = [ + "libc", + "option-ext", + "redox_users", + "windows-sys 0.48.0", +] + [[package]] name = "filetime" version = "0.2.13" @@ -157,7 +179,7 @@ checksum = "0c122a393ea57648015bf06fbd3d372378992e86b9ff5a7a497b076a28c79efe" dependencies = [ "cfg-if 1.0.0", "libc", - "redox_syscall", + "redox_syscall 0.1.57", "winapi", ] @@ -238,6 +260,17 @@ dependencies = [ "slab", ] +[[package]] +name = "getrandom" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", +] + [[package]] name = "glob" version = "0.3.0" @@ -332,9 +365,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.141" +version = "0.2.147" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3304a64d199bb964be99741b7a14d26972741915b3649639149b2479bb46f4b5" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" [[package]] name = "log" @@ -470,6 +503,12 @@ version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13bd41f508810a131401606d54ac32a467c97172d74ba7662562ebba5ad07fa0" +[[package]] +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + [[package]] name = "os_str_bytes" version = "2.4.0" @@ -568,6 +607,26 @@ version = "0.1.57" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" +[[package]] +name = "redox_syscall" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +dependencies = [ + "bitflags", +] + +[[package]] +name = "redox_users" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" +dependencies = [ + "getrandom", + "redox_syscall 0.2.16", + "thiserror", +] + [[package]] name = "regex" version = "1.7.3" @@ -698,7 +757,7 @@ checksum = "2c29947abdee2a218277abeca306f25789c938e500ea5a9d4b12a5a504466902" dependencies = [ "cfg-if 1.0.0", "libc", - "redox_syscall", + "redox_syscall 0.1.57", "winapi", ] @@ -925,13 +984,13 @@ version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", ] [[package]] @@ -940,7 +999,16 @@ version = "0.45.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" dependencies = [ - "windows-targets", + "windows-targets 0.42.2", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", ] [[package]] @@ -949,13 +1017,28 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", ] [[package]] @@ -964,42 +1047,84 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + [[package]] name = "windows_aarch64_msvc" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + [[package]] name = "windows_i686_gnu" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + [[package]] name = "windows_i686_msvc" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + [[package]] name = "windows_x86_64_gnu" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + [[package]] name = "windows_x86_64_gnullvm" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + [[package]] name = "windows_x86_64_msvc" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + [[package]] name = "yansi" version = "0.5.0" diff --git a/Cargo.toml b/Cargo.toml index 7b93c3d2..638e8a27 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,6 +12,7 @@ edition = "2018" [dependencies] clap = { version = "3.0.0-beta.2", features = [ "wrap_help" ] } +dirs = "5.0.1" flexi_logger = "0.16" fork = "0.1" futures-util = "0.3.6" diff --git a/README.md b/README.md index aff46f97..a5beaf82 100644 --- a/README.md +++ b/README.md @@ -125,8 +125,11 @@ This is the core of how `deploy-rs` was designed, any number of these can run on path = deploy-rs.lib.x86_64-linux.activate.custom pkgs.hello "./bin/hello"; # An optional path to where your profile should be installed to, this is useful if you want to use a common profile name across multiple users, but would have conflicts in your node's profile list. - # This will default to `"/nix/var/nix/profiles/$PROFILE_NAME` if `user` is root (see: generic options), and `/nix/var/nix/profiles/per-user/$USER/$PROFILE_NAME` if it is not. - profilePath = "/nix/var/nix/profiles/per-user/someuser/someprofile"; + # This will default to `"/nix/var/nix/profiles/system` if `user` is `root` and profile name is `system`, + # `/nix/var/nix/profiles/per-user/root/$PROFILE_NAME` if profile name is different. + # For non-root profiles will default to /nix/var/nix/profiles/per-user/$USER/$PROFILE_NAME if `/nix/var/nix/profiles/per-user/$USER` already exists, + # and `${XDG_STATE_HOME:-$HOME/.local/state}/nix/profiles/$PROFILE_NAME` otherwise. + profilePath = "/home/someuser/.local/state/nix/profiles/someprofile"; # ...generic options... (see lower section) } diff --git a/src/bin/activate.rs b/src/bin/activate.rs index bf035389..4a2760b6 100644 --- a/src/bin/activate.rs +++ b/src/bin/activate.rs @@ -15,9 +15,10 @@ use tokio::time::timeout; use std::time::Duration; -use std::path::PathBuf; +use std::env; +use std::path::{Path, PathBuf}; -use notify::{RecommendedWatcher, RecursiveMode, Watcher, recommended_watcher}; +use notify::{recommended_watcher, RecommendedWatcher, RecursiveMode, Watcher}; use thiserror::Error; @@ -47,11 +48,24 @@ enum SubCommand { /// Activate a profile #[derive(Clap, Debug)] +#[clap(group( + clap::ArgGroup::new("profile") + .required(true) + .multiple(false) + .args(&["profile-path","profile-user"]) +))] struct ActivateOpts { /// The closure to activate closure: String, /// The profile path to install into - profile_path: String, + #[clap(long)] + profile_path: Option, + /// The profile user if explicit profile path is not specified + #[clap(long, requires = "profile-name")] + profile_user: Option, + /// The profile name + #[clap(long, requires = "profile-user")] + profile_name: Option, /// Maximum time to wait for confirmation after activation #[clap(long)] @@ -78,7 +92,7 @@ struct ActivateOpts { temp_path: PathBuf, } -/// Activate a profile +/// Wait for profile activation #[derive(Clap, Debug)] struct WaitOpts { /// The closure to wait for @@ -89,11 +103,18 @@ struct WaitOpts { temp_path: PathBuf, } -/// Activate a profile +/// Revoke profile activation #[derive(Clap, Debug)] struct RevokeOpts { - /// The profile path to revoke - profile_path: String, + /// The profile path to install into + #[clap(long)] + profile_path: Option, + /// The profile user if explicit profile path is not specified + #[clap(long, requires = "profile-name")] + profile_user: Option, + /// The profile name + #[clap(long, requires = "profile-user")] + profile_name: Option, } #[derive(Error, Debug)] @@ -315,8 +336,8 @@ pub async fn wait(temp_path: PathBuf, closure: String) -> Result<(), WaitError> // 'lock_path' may not exist yet when some other files are created in 'temp_path' // x is already supposed to be canonical path Ok(lock_path) if x == &lock_path => created.try_send(Ok(())), - _ => Ok (()) - } + _ => Ok(()), + }, _ => Ok(()), } } @@ -459,6 +480,61 @@ async fn revoke(profile_path: String) -> Result<(), DeactivateError> { Ok(()) } +#[derive(Error, Debug)] +pub enum GetProfilePathError { + #[error("Failed to deduce HOME directory for user {0}")] + NoUserHome(String), +} + +fn get_profile_path( + profile_path: Option, + profile_user: Option, + profile_name: Option, +) -> Result { + match (profile_path, profile_user, profile_name) { + (Some(profile_path), None, None) => Ok(profile_path), + (None, Some(profile_user), Some(profile_name)) => { + let nix_state_dir = env::var("NIX_STATE_DIR").unwrap_or("/nix/var/nix".to_string()); + // As per https://nixos.org/manual/nix/stable/command-ref/files/profiles#profiles + match &profile_user[..] { + "root" => { + match &profile_name[..] { + // NixOS system profile belongs to the root user, but isn't stored in the 'per-user/root' + "system" => Ok(format!("{}/profiles/system", nix_state_dir)), + _ => Ok(format!( + "{}/profiles/per-user/root/{}", + nix_state_dir, profile_name + )), + } + } + _ => { + let old_user_profiles_dir = + format!("{}/profiles/per-user/{}", nix_state_dir, profile_user); + // To stay backward compatible + if Path::new(&old_user_profiles_dir).exists() { + Ok(format!("{}/{}", old_user_profiles_dir, profile_name)) + } else { + // https://github.com/NixOS/nix/blob/2.17.0/src/libstore/profiles.cc#L308 + // This is basically the equivalent of calling 'dirs::state_dir()'. + // However, this function returns 'None' on macOS, while nix will actually + // check env variables, so we imitate nix implementation below instead of + // using 'dirs::state_dir()' directly. + let state_dir = env::var("XDG_STATE_HOME").or_else(|_| { + dirs::home_dir() + .map(|h| { + format!("{}/.local/state", h.as_path().display().to_string()) + }) + .ok_or(GetProfilePathError::NoUserHome(profile_user)) + })?; + Ok(format!("{}/nix/profiles/{}", state_dir, profile_name)) + } + } + } + } + _ => panic!("impossible"), + } +} + #[tokio::main] async fn main() -> Result<(), Box> { // Ensure that this process stays alive after the SSH connection dies @@ -483,7 +559,11 @@ async fn main() -> Result<(), Box> { let r = match opts.subcmd { SubCommand::Activate(activate_opts) => activate( - activate_opts.profile_path, + get_profile_path( + activate_opts.profile_path, + activate_opts.profile_user, + activate_opts.profile_name, + )?, activate_opts.closure, activate_opts.auto_rollback, activate_opts.temp_path, @@ -499,9 +579,13 @@ async fn main() -> Result<(), Box> { .await .map_err(|x| Box::new(x) as Box), - SubCommand::Revoke(revoke_opts) => revoke(revoke_opts.profile_path) - .await - .map_err(|x| Box::new(x) as Box), + SubCommand::Revoke(revoke_opts) => revoke(get_profile_path( + revoke_opts.profile_path, + revoke_opts.profile_user, + revoke_opts.profile_name, + )?) + .await + .map_err(|x| Box::new(x) as Box), }; match r { diff --git a/src/deploy.rs b/src/deploy.rs index 574e9b2e..41cd58ba 100644 --- a/src/deploy.rs +++ b/src/deploy.rs @@ -9,11 +9,11 @@ use std::path::Path; use thiserror::Error; use tokio::process::Command; -use crate::DeployDataDefsError; +use crate::{DeployDataDefsError, ProfileInfo}; struct ActivateCommandData<'a> { sudo: &'a Option, - profile_path: &'a str, + profile_info: &'a ProfileInfo, closure: &'a str, auto_rollback: bool, temp_path: &'a Path, @@ -37,8 +37,21 @@ fn build_activate_command(data: &ActivateCommandData) -> String { } self_activate_command = format!( - "{} activate '{}' '{}' --temp-path '{}'", - self_activate_command, data.closure, data.profile_path, data.temp_path.display() + "{} activate '{}' {} --temp-path '{}'", + self_activate_command, + data.closure, + match data.profile_info { + ProfileInfo::ProfilePath { profile_path } => + format!("--profile-path '{}'", profile_path), + ProfileInfo::ProfileUserAndName { + profile_user, + profile_name, + } => format!( + "--profile-user {} --profile-name {}", + profile_user, profile_name + ), + }, + data.temp_path.display() ); self_activate_command = format!( @@ -72,7 +85,9 @@ fn build_activate_command(data: &ActivateCommandData) -> String { #[test] fn test_activation_command_builder() { let sudo = Some("sudo -u test".to_string()); - let profile_path = "/blah/profiles/test"; + let profile_info = &ProfileInfo::ProfilePath { + profile_path: "/blah/profiles/test".to_string(), + }; let closure = "/nix/store/blah/etc"; let auto_rollback = true; let dry_activate = false; @@ -86,7 +101,7 @@ fn test_activation_command_builder() { assert_eq!( build_activate_command(&ActivateCommandData { sudo: &sudo, - profile_path, + profile_info, closure, auto_rollback, temp_path, @@ -97,7 +112,7 @@ fn test_activation_command_builder() { dry_activate, boot, }), - "sudo -u test /nix/store/blah/etc/activate-rs --debug-logs --log-dir /tmp/something.txt activate '/nix/store/blah/etc' '/blah/profiles/test' --temp-path '/tmp' --confirm-timeout 30 --magic-rollback --auto-rollback" + "sudo -u test /nix/store/blah/etc/activate-rs --debug-logs --log-dir /tmp/something.txt activate '/nix/store/blah/etc' --profile-path '/blah/profiles/test' --temp-path '/tmp' --confirm-timeout 30 --magic-rollback --auto-rollback" .to_string(), ); } @@ -123,7 +138,9 @@ fn build_wait_command(data: &WaitCommandData) -> String { self_activate_command = format!( "{} wait '{}' --temp-path '{}'", - self_activate_command, data.closure, data.temp_path.display(), + self_activate_command, + data.closure, + data.temp_path.display(), ); if let Some(sudo_cmd) = &data.sudo { @@ -157,7 +174,7 @@ fn test_wait_command_builder() { struct RevokeCommandData<'a> { sudo: &'a Option, closure: &'a str, - profile_path: &'a str, + profile_info: ProfileInfo, debug_logs: bool, log_dir: Option<&'a str>, } @@ -173,7 +190,21 @@ fn build_revoke_command(data: &RevokeCommandData) -> String { self_activate_command = format!("{} --log-dir {}", self_activate_command, log_dir); } - self_activate_command = format!("{} revoke '{}'", self_activate_command, data.profile_path); + self_activate_command = format!( + "{} revoke {}", + self_activate_command, + match &data.profile_info { + ProfileInfo::ProfilePath { profile_path } => + format!("--profile-path '{}'", profile_path), + ProfileInfo::ProfileUserAndName { + profile_user, + profile_name, + } => format!( + "--profile-user {} --profile-name {}", + profile_user, profile_name + ), + } + ); if let Some(sudo_cmd) = &data.sudo { self_activate_command = format!("{} {}", sudo_cmd, self_activate_command); @@ -186,7 +217,9 @@ fn build_revoke_command(data: &RevokeCommandData) -> String { fn test_revoke_command_builder() { let sudo = Some("sudo -u test".to_string()); let closure = "/nix/store/blah/etc"; - let profile_path = "/nix/var/nix/per-user/user/profile"; + let profile_info = ProfileInfo::ProfilePath { + profile_path: "/nix/var/nix/per-user/user/profile".to_string(), + }; let debug_logs = true; let log_dir = Some("/tmp/something.txt"); @@ -194,11 +227,11 @@ fn test_revoke_command_builder() { build_revoke_command(&RevokeCommandData { sudo: &sudo, closure, - profile_path, + profile_info, debug_logs, log_dir }), - "sudo -u test /nix/store/blah/etc/activate-rs --debug-logs --log-dir /tmp/something.txt revoke '/nix/var/nix/per-user/user/profile'" + "sudo -u test /nix/store/blah/etc/activate-rs --debug-logs --log-dir /tmp/something.txt revoke --profile-path '/nix/var/nix/per-user/user/profile'" .to_string(), ); } @@ -271,6 +304,8 @@ pub enum DeployProfileError { #[error("Error confirming deployment: {0}")] Confirm(#[from] ConfirmProfileError), + #[error("Deployment data invalid: {0}")] + InvalidDeployDataDefs(#[from] DeployDataDefsError), } pub async fn deploy_profile( @@ -299,7 +334,7 @@ pub async fn deploy_profile( let self_activate_command = build_activate_command(&ActivateCommandData { sudo: &deploy_defs.sudo, - profile_path: &deploy_defs.profile_path, + profile_info: &deploy_data.get_profile_info()?, closure: &deploy_data.profile.profile_settings.path, auto_rollback, temp_path: temp_path, @@ -439,7 +474,7 @@ pub async fn revoke( let self_revoke_command = build_revoke_command(&RevokeCommandData { sudo: &deploy_defs.sudo, closure: &deploy_data.profile.profile_settings.path, - profile_path: &deploy_data.get_profile_path()?, + profile_info: deploy_data.get_profile_info()?, debug_logs: deploy_data.debug_logs, log_dir: deploy_data.log_dir, }); diff --git a/src/lib.rs b/src/lib.rs index c6f8e030..0e5d817b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -332,9 +332,17 @@ pub struct DeployData<'a> { pub struct DeployDefs { pub ssh_user: String, pub profile_user: String, - pub profile_path: String, pub sudo: Option, } +enum ProfileInfo { + ProfilePath { + profile_path: String, + }, + ProfileUserAndName { + profile_user: String, + profile_name: String, + }, +} #[derive(Error, Debug)] pub enum DeployDataDefsError { @@ -351,8 +359,6 @@ impl<'a> DeployData<'a> { let profile_user = self.get_profile_user()?; - let profile_path = self.get_profile_path()?; - let sudo: Option = match self.merged_settings.user { Some(ref user) if user != &ssh_user => Some(format!("{} {}", self.get_sudo(), user)), _ => None, @@ -361,26 +367,10 @@ impl<'a> DeployData<'a> { Ok(DeployDefs { ssh_user, profile_user, - profile_path, sudo, }) } - fn get_profile_path(&'a self) -> Result { - let profile_user = self.get_profile_user()?; - let profile_path = match self.profile.profile_settings.profile_path { - None => match &profile_user[..] { - "root" => format!("/nix/var/nix/profiles/{}", self.profile_name), - _ => format!( - "/nix/var/nix/profiles/per-user/{}/{}", - profile_user, self.profile_name - ), - }, - Some(ref x) => x.clone(), - }; - Ok(profile_path) - } - fn get_profile_user(&'a self) -> Result { let profile_user = match self.merged_settings.user { Some(ref x) => x.clone(), @@ -403,6 +393,16 @@ impl<'a> DeployData<'a> { None => "sudo -u".to_string(), } } + + fn get_profile_info(&'a self) -> Result { + match self.profile.profile_settings.profile_path { + Some(ref profile_path) => Ok(ProfileInfo::ProfilePath { profile_path: profile_path.to_string() }), + None => { + let profile_user = self.get_profile_user()?; + Ok(ProfileInfo::ProfileUserAndName { profile_user, profile_name: self.profile_name.to_string() }) + }, + } + } } pub fn make_deploy_data<'a, 's>(