Cleanup of EtcTree.
This commit is contained in:
parent
0e5a2c4bd7
commit
95f9897766
3 changed files with 146 additions and 121 deletions
|
|
@ -13,7 +13,7 @@ use std::{fs, io};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
create_link, create_store_link, remove_dir, remove_file, remove_link, StorePath,
|
create_link, create_store_link, remove_dir, remove_file, remove_link, StorePath,
|
||||||
ETC_STATE_FILE_NAME, SYSTEM_MANAGER_STATE_DIR,
|
ETC_STATE_FILE_NAME, SYSTEM_MANAGER_STATE_DIR, SYSTEM_MANAGER_STATIC_NAME,
|
||||||
};
|
};
|
||||||
use etc_tree::EtcTree;
|
use etc_tree::EtcTree;
|
||||||
|
|
||||||
|
|
@ -57,16 +57,16 @@ pub fn activate(store_path: &StorePath, ephemeral: bool) -> Result<()> {
|
||||||
DirBuilder::new().recursive(true).create(&etc_dir)?;
|
DirBuilder::new().recursive(true).create(&etc_dir)?;
|
||||||
|
|
||||||
let old_state = read_created_files()?;
|
let old_state = read_created_files()?;
|
||||||
|
let initial_state = EtcTree::root_node();
|
||||||
|
|
||||||
// TODO: constant?
|
|
||||||
let static_dir_name = ".system-manager-static";
|
|
||||||
let (state, status) = create_etc_static_link(
|
let (state, status) = create_etc_static_link(
|
||||||
static_dir_name,
|
SYSTEM_MANAGER_STATIC_NAME,
|
||||||
&config.static_env,
|
&config.static_env,
|
||||||
&etc_dir,
|
&etc_dir,
|
||||||
EtcTree::new(PathBuf::new()),
|
initial_state,
|
||||||
);
|
);
|
||||||
status?;
|
status?;
|
||||||
|
|
||||||
let new_state = create_etc_links(config.entries.values(), &etc_dir, state).update_state(
|
let new_state = create_etc_links(config.entries.values(), &etc_dir, state).update_state(
|
||||||
old_state,
|
old_state,
|
||||||
&|path| {
|
&|path| {
|
||||||
|
|
@ -75,7 +75,7 @@ pub fn activate(store_path: &StorePath, ephemeral: bool) -> Result<()> {
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
serialise_state(&new_state.unwrap_or_else(|| EtcTree::new(PathBuf::from("/"))))?;
|
serialise_state(new_state)?;
|
||||||
|
|
||||||
log::info!("Done");
|
log::info!("Done");
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
@ -85,17 +85,15 @@ pub fn deactivate() -> Result<()> {
|
||||||
let state = read_created_files()?;
|
let state = read_created_files()?;
|
||||||
log::debug!("{:?}", state);
|
log::debug!("{:?}", state);
|
||||||
|
|
||||||
serialise_state(&state.deactivate_managed_entry(
|
serialise_state(state.deactivate(&|path| {
|
||||||
Path::new("/"),
|
try_delete_path(path)
|
||||||
&|path| match try_delete_path(path) {
|
.map_err(|e| {
|
||||||
Ok(()) => true,
|
|
||||||
Err(e) => {
|
|
||||||
log::error!("Error deleting path: {}", path.display());
|
log::error!("Error deleting path: {}", path.display());
|
||||||
log::error!("{e}");
|
log::error!("{e}");
|
||||||
false
|
e
|
||||||
}
|
})
|
||||||
},
|
.is_ok()
|
||||||
))?;
|
}))?;
|
||||||
|
|
||||||
log::info!("Done");
|
log::info!("Done");
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
@ -154,7 +152,7 @@ fn create_etc_link(link_target: &OsStr, etc_dir: &Path, state: EtcTree) -> (EtcT
|
||||||
match status.and_then(|_| {
|
match status.and_then(|_| {
|
||||||
create_link(
|
create_link(
|
||||||
Path::new(".")
|
Path::new(".")
|
||||||
.join(".system-manager-static")
|
.join(SYSTEM_MANAGER_STATIC_NAME)
|
||||||
.join("etc")
|
.join("etc")
|
||||||
.join(link_target)
|
.join(link_target)
|
||||||
.as_path(),
|
.as_path(),
|
||||||
|
|
@ -207,7 +205,7 @@ fn create_dir_recursively(dir: &Path, state: EtcTree) -> (EtcTree, Result<()>) {
|
||||||
let (new_state, _, status) = dir
|
let (new_state, _, status) = dir
|
||||||
.components()
|
.components()
|
||||||
.fold_while(
|
.fold_while(
|
||||||
(state, PathBuf::from("/"), Ok(())),
|
(state, PathBuf::from(path::MAIN_SEPARATOR_STR), Ok(())),
|
||||||
|(state, path, _), component| match component {
|
|(state, path, _), component| match component {
|
||||||
Component::RootDir => Continue((state, path, Ok(()))),
|
Component::RootDir => Continue((state, path, Ok(()))),
|
||||||
Component::Normal(dir) => {
|
Component::Normal(dir) => {
|
||||||
|
|
@ -240,10 +238,15 @@ fn create_dir_recursively(dir: &Path, state: EtcTree) -> (EtcTree, Result<()>) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn copy_file(source: &Path, target: &Path, mode: &str) -> Result<()> {
|
fn copy_file(source: &Path, target: &Path, mode: &str) -> Result<()> {
|
||||||
|
let exists = target.try_exists()?;
|
||||||
|
if !exists {
|
||||||
fs::copy(source, target)?;
|
fs::copy(source, target)?;
|
||||||
let mode_int = u32::from_str_radix(mode, 8).map_err(anyhow::Error::from)?;
|
let mode_int = u32::from_str_radix(mode, 8)?;
|
||||||
fs::set_permissions(target, Permissions::from_mode(mode_int))?;
|
fs::set_permissions(target, Permissions::from_mode(mode_int))?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
} else {
|
||||||
|
anyhow::bail!("File {} already exists, ignoring.", target.display());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn etc_dir(ephemeral: bool) -> PathBuf {
|
fn etc_dir(ephemeral: bool) -> PathBuf {
|
||||||
|
|
@ -254,7 +257,10 @@ fn etc_dir(ephemeral: bool) -> PathBuf {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialise_state(created_files: &EtcTree) -> Result<()> {
|
fn serialise_state<E>(created_files: Option<E>) -> Result<()>
|
||||||
|
where
|
||||||
|
E: AsRef<EtcTree>,
|
||||||
|
{
|
||||||
let state_file = Path::new(SYSTEM_MANAGER_STATE_DIR).join(ETC_STATE_FILE_NAME);
|
let state_file = Path::new(SYSTEM_MANAGER_STATE_DIR).join(ETC_STATE_FILE_NAME);
|
||||||
DirBuilder::new()
|
DirBuilder::new()
|
||||||
.recursive(true)
|
.recursive(true)
|
||||||
|
|
@ -262,7 +268,12 @@ fn serialise_state(created_files: &EtcTree) -> Result<()> {
|
||||||
|
|
||||||
log::info!("Writing state info into file: {}", state_file.display());
|
log::info!("Writing state info into file: {}", state_file.display());
|
||||||
let writer = io::BufWriter::new(fs::File::create(state_file)?);
|
let writer = io::BufWriter::new(fs::File::create(state_file)?);
|
||||||
serde_json::to_writer(writer, created_files)?;
|
|
||||||
|
if let Some(e) = created_files {
|
||||||
|
serde_json::to_writer(writer, e.as_ref())?;
|
||||||
|
} else {
|
||||||
|
serde_json::to_writer(writer, &EtcTree::default())?;
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -283,5 +294,5 @@ fn read_created_files() -> Result<EtcTree> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(EtcTree::new(PathBuf::from("/")))
|
Ok(EtcTree::default())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,10 @@
|
||||||
use im::HashMap;
|
use im::HashMap;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::cmp::Eq;
|
use std::cmp::Eq;
|
||||||
use std::ffi::OsString;
|
|
||||||
use std::iter::Peekable;
|
use std::iter::Peekable;
|
||||||
use std::path;
|
use std::path;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
||||||
#[serde(rename_all = "camelCase")]
|
|
||||||
pub struct EtcTree {
|
|
||||||
status: EtcFileStatus,
|
|
||||||
path: PathBuf,
|
|
||||||
// TODO directories and files are now both represented as a string associated with a nested
|
|
||||||
// map. For files the nested map is simple empty.
|
|
||||||
// We could potentially optimise this.
|
|
||||||
nested: HashMap<OsString, EtcTree>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub enum EtcFileStatus {
|
pub enum EtcFileStatus {
|
||||||
|
|
@ -35,22 +23,45 @@ impl EtcFileStatus {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct EtcTree {
|
||||||
|
status: EtcFileStatus,
|
||||||
|
path: PathBuf,
|
||||||
|
// TODO directories and files are now both represented as a string associated with a nested
|
||||||
|
// map. For files the nested map is simple empty.
|
||||||
|
// We could potentially optimise this.
|
||||||
|
nested: HashMap<String, EtcTree>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsRef<EtcTree> for EtcTree {
|
||||||
|
fn as_ref(&self) -> &EtcTree {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for EtcTree {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::root_node()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Data structure to represent files that are managed by system-manager.
|
/// Data structure to represent files that are managed by system-manager.
|
||||||
///
|
///
|
||||||
/// This data will be serialised to disk and read on the next run.
|
/// This data will be serialised to disk and read on the next run.
|
||||||
///
|
///
|
||||||
/// We need these basic operations:
|
/// We need these basic operations:
|
||||||
/// 1. Create a new, empty structure
|
/// 1. Create a new root structure
|
||||||
/// 2. Persist to a file
|
/// 2. Persist to a file
|
||||||
/// 3. Import from a file
|
/// 3. Import from a file
|
||||||
/// 4. Add a path to the tree, that will from then on be considered as managed
|
/// 4. Add a path to the tree, that will from then on be considered as managed
|
||||||
/// 5.
|
/// 5.
|
||||||
impl EtcTree {
|
impl EtcTree {
|
||||||
pub fn new(path: PathBuf) -> Self {
|
fn new(path: PathBuf) -> Self {
|
||||||
Self::with_status(path, EtcFileStatus::Unmanaged)
|
Self::with_status(path, EtcFileStatus::Unmanaged)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_status(path: PathBuf, status: EtcFileStatus) -> Self {
|
fn with_status(path: PathBuf, status: EtcFileStatus) -> Self {
|
||||||
Self {
|
Self {
|
||||||
status,
|
status,
|
||||||
path,
|
path,
|
||||||
|
|
@ -58,6 +69,10 @@ impl EtcTree {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn root_node() -> Self {
|
||||||
|
Self::new(PathBuf::from(path::MAIN_SEPARATOR_STR))
|
||||||
|
}
|
||||||
|
|
||||||
// TODO is recursion OK here?
|
// TODO is recursion OK here?
|
||||||
// Should we convert to CPS and use a crate like tramp to TCO this?
|
// Should we convert to CPS and use a crate like tramp to TCO this?
|
||||||
pub fn register_managed_entry(self, path: &Path) -> Self {
|
pub fn register_managed_entry(self, path: &Path) -> Self {
|
||||||
|
|
@ -75,26 +90,24 @@ impl EtcTree {
|
||||||
maybe_subtree.unwrap_or_else(|| {
|
maybe_subtree.unwrap_or_else(|| {
|
||||||
EtcTree::with_status(
|
EtcTree::with_status(
|
||||||
new_path.to_owned(),
|
new_path.to_owned(),
|
||||||
if components.peek().is_some() {
|
components
|
||||||
|
.peek()
|
||||||
|
.map_or(EtcFileStatus::Managed, |_| {
|
||||||
EtcFileStatus::Unmanaged
|
EtcFileStatus::Unmanaged
|
||||||
} else {
|
}),
|
||||||
EtcFileStatus::Managed
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
}),
|
}),
|
||||||
components,
|
components,
|
||||||
new_path,
|
new_path,
|
||||||
))
|
))
|
||||||
},
|
},
|
||||||
name.to_owned(),
|
name.to_string_lossy().to_string(),
|
||||||
);
|
);
|
||||||
tree
|
tree
|
||||||
}
|
}
|
||||||
path::Component::RootDir => go(
|
path::Component::RootDir => {
|
||||||
tree,
|
go(tree, components, path.join(path::MAIN_SEPARATOR_STR))
|
||||||
components,
|
}
|
||||||
path.join(path::MAIN_SEPARATOR.to_string()),
|
|
||||||
),
|
|
||||||
_ => panic!(
|
_ => panic!(
|
||||||
"Unsupported path provided! At path component: {:?}",
|
"Unsupported path provided! At path component: {:?}",
|
||||||
component
|
component
|
||||||
|
|
@ -131,63 +144,6 @@ impl EtcTree {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deactivate_managed_entry<F>(self, path: &Path, delete_action: &F) -> Self
|
|
||||||
where
|
|
||||||
F: Fn(&Path) -> bool,
|
|
||||||
{
|
|
||||||
fn go<'a, C, F>(
|
|
||||||
mut tree: EtcTree,
|
|
||||||
path: PathBuf,
|
|
||||||
mut components: Peekable<C>,
|
|
||||||
delete_action: &F,
|
|
||||||
) -> EtcTree
|
|
||||||
where
|
|
||||||
C: Iterator<Item = path::Component<'a>>,
|
|
||||||
F: Fn(&Path) -> bool,
|
|
||||||
{
|
|
||||||
log::debug!("Deactivating {}", path.display());
|
|
||||||
|
|
||||||
if let Some(component) = components.next() {
|
|
||||||
match component {
|
|
||||||
path::Component::Normal(name) => {
|
|
||||||
let new_path = path.join(name);
|
|
||||||
tree.nested = tree.nested.alter(
|
|
||||||
|maybe_subtree| {
|
|
||||||
maybe_subtree.and_then(|subtree| {
|
|
||||||
if components.peek().is_some() {
|
|
||||||
Some(go(subtree, new_path, components, delete_action))
|
|
||||||
} else {
|
|
||||||
subtree.deactivate(delete_action)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
},
|
|
||||||
name.to_owned(),
|
|
||||||
);
|
|
||||||
tree
|
|
||||||
}
|
|
||||||
path::Component::RootDir => go(
|
|
||||||
tree,
|
|
||||||
path.join(path::MAIN_SEPARATOR.to_string()),
|
|
||||||
components,
|
|
||||||
delete_action,
|
|
||||||
),
|
|
||||||
_ => panic!(
|
|
||||||
"Unsupported path provided! At path component: {:?}",
|
|
||||||
component
|
|
||||||
),
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
tree
|
|
||||||
}
|
|
||||||
}
|
|
||||||
go(
|
|
||||||
self,
|
|
||||||
PathBuf::new(),
|
|
||||||
path.components().peekable(),
|
|
||||||
delete_action,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn update_state<F>(self, other: Self, delete_action: &F) -> Option<Self>
|
pub fn update_state<F>(self, other: Self, delete_action: &F) -> Option<Self>
|
||||||
where
|
where
|
||||||
F: Fn(&Path) -> bool,
|
F: Fn(&Path) -> bool,
|
||||||
|
|
@ -237,29 +193,86 @@ impl EtcTree {
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use std::ffi::OsStr;
|
|
||||||
|
impl EtcTree {
|
||||||
|
pub fn deactivate_managed_entry<F>(self, path: &Path, delete_action: &F) -> Self
|
||||||
|
where
|
||||||
|
F: Fn(&Path) -> bool,
|
||||||
|
{
|
||||||
|
fn go<'a, C, F>(
|
||||||
|
mut tree: EtcTree,
|
||||||
|
path: PathBuf,
|
||||||
|
mut components: Peekable<C>,
|
||||||
|
delete_action: &F,
|
||||||
|
) -> EtcTree
|
||||||
|
where
|
||||||
|
C: Iterator<Item = path::Component<'a>>,
|
||||||
|
F: Fn(&Path) -> bool,
|
||||||
|
{
|
||||||
|
log::debug!("Deactivating {}", path.display());
|
||||||
|
|
||||||
|
if let Some(component) = components.next() {
|
||||||
|
match component {
|
||||||
|
path::Component::Normal(name) => {
|
||||||
|
let new_path = path.join(name);
|
||||||
|
tree.nested = tree.nested.alter(
|
||||||
|
|maybe_subtree| {
|
||||||
|
maybe_subtree.and_then(|subtree| {
|
||||||
|
if components.peek().is_some() {
|
||||||
|
Some(go(subtree, new_path, components, delete_action))
|
||||||
|
} else {
|
||||||
|
subtree.deactivate(delete_action)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
name.to_string_lossy().to_string(),
|
||||||
|
);
|
||||||
|
tree
|
||||||
|
}
|
||||||
|
path::Component::RootDir => go(
|
||||||
|
tree,
|
||||||
|
path.join(path::MAIN_SEPARATOR.to_string()),
|
||||||
|
components,
|
||||||
|
delete_action,
|
||||||
|
),
|
||||||
|
_ => panic!(
|
||||||
|
"Unsupported path provided! At path component: {:?}",
|
||||||
|
component
|
||||||
|
),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
tree
|
||||||
|
}
|
||||||
|
}
|
||||||
|
go(
|
||||||
|
self,
|
||||||
|
PathBuf::new(),
|
||||||
|
path.components().peekable(),
|
||||||
|
delete_action,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn etc_tree_register() {
|
fn etc_tree_register() {
|
||||||
let tree1 = EtcTree::new(PathBuf::from("/"))
|
let tree = EtcTree::root_node()
|
||||||
.register_managed_entry(&PathBuf::from("/").join("foo").join("bar"))
|
.register_managed_entry(&PathBuf::from("/").join("foo").join("bar"))
|
||||||
.register_managed_entry(&PathBuf::from("/").join("foo2").join("baz").join("bar"))
|
.register_managed_entry(&PathBuf::from("/").join("foo2").join("baz").join("bar"))
|
||||||
.register_managed_entry(&PathBuf::from("/").join("foo2").join("baz2").join("bar"));
|
.register_managed_entry(&PathBuf::from("/").join("foo2").join("baz2").join("bar"));
|
||||||
dbg!(&tree1);
|
dbg!(&tree);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
tree1.nested.keys().sorted().collect::<Vec<_>>(),
|
tree.nested.keys().sorted().collect::<Vec<_>>(),
|
||||||
["foo", "foo2"]
|
["foo", "foo2"]
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
tree1
|
tree.nested
|
||||||
.nested
|
.get("foo2")
|
||||||
.get(OsStr::new("foo2"))
|
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.nested
|
.nested
|
||||||
.get(OsStr::new("baz"))
|
.get("baz")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.nested
|
.nested
|
||||||
.get(OsStr::new("bar"))
|
.get("bar")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.path,
|
.path,
|
||||||
PathBuf::from("/").join("foo2").join("baz").join("bar")
|
PathBuf::from("/").join("foo2").join("baz").join("bar")
|
||||||
|
|
@ -268,7 +281,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn etc_tree_deactivate() {
|
fn etc_tree_deactivate() {
|
||||||
let tree1 = EtcTree::new(PathBuf::from("/"))
|
let tree1 = EtcTree::root_node()
|
||||||
.register_managed_entry(&PathBuf::from("/").join("foo").join("bar"))
|
.register_managed_entry(&PathBuf::from("/").join("foo").join("bar"))
|
||||||
.register_managed_entry(&PathBuf::from("/").join("foo2"))
|
.register_managed_entry(&PathBuf::from("/").join("foo2"))
|
||||||
.register_managed_entry(&PathBuf::from("/").join("foo2").join("baz"))
|
.register_managed_entry(&PathBuf::from("/").join("foo2").join("baz"))
|
||||||
|
|
@ -301,10 +314,10 @@ mod tests {
|
||||||
);
|
);
|
||||||
assert!(tree2
|
assert!(tree2
|
||||||
.nested
|
.nested
|
||||||
.get(OsStr::new("foo3"))
|
.get("foo3")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.nested
|
.nested
|
||||||
.get(OsStr::new("baz2"))
|
.get("baz2")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.nested
|
.nested
|
||||||
.keys()
|
.keys()
|
||||||
|
|
@ -319,7 +332,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn etc_tree_update_state() {
|
fn etc_tree_update_state() {
|
||||||
let tree1 = EtcTree::new(PathBuf::from("/"))
|
let tree1 = EtcTree::root_node()
|
||||||
.register_managed_entry(&PathBuf::from("/").join("foo").join("bar"))
|
.register_managed_entry(&PathBuf::from("/").join("foo").join("bar"))
|
||||||
.register_managed_entry(&PathBuf::from("/").join("foo2"))
|
.register_managed_entry(&PathBuf::from("/").join("foo2"))
|
||||||
.register_managed_entry(&PathBuf::from("/").join("foo2").join("baz"))
|
.register_managed_entry(&PathBuf::from("/").join("foo2").join("baz"))
|
||||||
|
|
@ -327,7 +340,7 @@ mod tests {
|
||||||
.register_managed_entry(&PathBuf::from("/").join("foo2").join("baz2"))
|
.register_managed_entry(&PathBuf::from("/").join("foo2").join("baz2"))
|
||||||
.register_managed_entry(&PathBuf::from("/").join("foo2").join("baz2").join("bar"))
|
.register_managed_entry(&PathBuf::from("/").join("foo2").join("baz2").join("bar"))
|
||||||
.register_managed_entry(&PathBuf::from("/").join("foo3").join("baz2").join("bar"));
|
.register_managed_entry(&PathBuf::from("/").join("foo3").join("baz2").join("bar"));
|
||||||
let tree2 = EtcTree::new(PathBuf::from("/"))
|
let tree2 = EtcTree::root_node()
|
||||||
.register_managed_entry(&PathBuf::from("/").join("foo").join("bar"))
|
.register_managed_entry(&PathBuf::from("/").join("foo").join("bar"))
|
||||||
.register_managed_entry(&PathBuf::from("/").join("foo3").join("bar"))
|
.register_managed_entry(&PathBuf::from("/").join("foo3").join("bar"))
|
||||||
.register_managed_entry(&PathBuf::from("/").join("foo4"))
|
.register_managed_entry(&PathBuf::from("/").join("foo4"))
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ const GCROOT_PATH: &str = "/nix/var/nix/gcroots/system-manager-current";
|
||||||
const SYSTEM_MANAGER_STATE_DIR: &str = "/var/lib/system-manager/state";
|
const SYSTEM_MANAGER_STATE_DIR: &str = "/var/lib/system-manager/state";
|
||||||
const SERVICES_STATE_FILE_NAME: &str = "services.json";
|
const SERVICES_STATE_FILE_NAME: &str = "services.json";
|
||||||
const ETC_STATE_FILE_NAME: &str = "etc-files.json";
|
const ETC_STATE_FILE_NAME: &str = "etc-files.json";
|
||||||
|
const SYSTEM_MANAGER_STATIC_NAME: &str = ".system-manager-static";
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
#[serde(from = "String", into = "String", rename_all = "camelCase")]
|
#[serde(from = "String", into = "String", rename_all = "camelCase")]
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue