File: prepare migration out of flatenned kind
This commit is contained in:
+23
-14
@@ -1,12 +1,20 @@
|
||||
use eyre::Result;
|
||||
use eyre::{Result, format_err};
|
||||
use log::info;
|
||||
use std::path::Path;
|
||||
use tokio::fs;
|
||||
|
||||
use crate::base64_decode;
|
||||
use crate::{base64_decode, File};
|
||||
|
||||
pub async fn files(files: &[crate::File], root: &str, dry_run: bool) -> Result<()> {
|
||||
for file in files {
|
||||
pub async fn files(files: &[File], root: &str, dry_run: bool) -> Result<()> {
|
||||
for f in files {
|
||||
if let Err(e) = file(f, root, dry_run).await {
|
||||
return Err(format_err!("{}: {e}", f.path))
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn file(file: &File, root: &str, dry_run: bool) -> Result<()> {
|
||||
let path = chroot(root, &file.path);
|
||||
let path = Path::new(&path);
|
||||
|
||||
@@ -15,7 +23,11 @@ pub async fn files(files: &[crate::File], root: &str, dry_run: bool) -> Result<(
|
||||
}
|
||||
|
||||
use crate::{FileKind as K, FilePart as P};
|
||||
match &file.kind {
|
||||
match file.kind().as_ref() {
|
||||
K::Skip => {
|
||||
info!("{}: kind is skip", file.path);
|
||||
return Ok(())
|
||||
},
|
||||
K::Content(content) => {
|
||||
if dry_run {
|
||||
info!(
|
||||
@@ -57,38 +69,35 @@ pub async fn files(files: &[crate::File], root: &str, dry_run: bool) -> Result<(
|
||||
fs::write(path, assembly).await?
|
||||
}
|
||||
}
|
||||
K::Dir(true) => {
|
||||
K::Dir => {
|
||||
if dry_run {
|
||||
info!("would create {} (directory)", file.path);
|
||||
} else {
|
||||
fs::create_dir(path).await?;
|
||||
}
|
||||
}
|
||||
K::Dir(false) => {} // shouldn't happen, but semantic is to ignore
|
||||
K::Symlink(tgt) => {
|
||||
if dry_run {
|
||||
info!("would create {} (symlink to {})", file.path, tgt);
|
||||
} else {
|
||||
let _ = fs::remove_file(path).await; // we're ln --force
|
||||
fs::symlink(tgt, path).await?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if dry_run {
|
||||
continue;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
match file.kind {
|
||||
K::Symlink(_) => {}
|
||||
_ => set_perms(path, file.mode).await?,
|
||||
if file.is_symlink() {
|
||||
set_perms(path, file.mode).await?;
|
||||
}
|
||||
|
||||
info!("created {}", file.path);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn set_perms(path: impl AsRef<Path>, mode: Option<u32>) -> std::io::Result<()> {
|
||||
if let Some(mode) = mode.filter(|m| *m != 0) {
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
|
||||
+53
-7
@@ -1,3 +1,5 @@
|
||||
use std::borrow::Cow;
|
||||
|
||||
pub mod apply;
|
||||
pub mod bootstrap;
|
||||
pub mod cgroup;
|
||||
@@ -56,26 +58,41 @@ pub struct User {
|
||||
pub gid: Option<u32>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, serde::Deserialize, serde::Serialize)]
|
||||
#[derive(Default, Debug, PartialEq, Eq, serde::Deserialize, serde::Serialize)]
|
||||
pub struct File {
|
||||
pub path: String,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub mode: Option<u32>,
|
||||
#[serde(flatten)]
|
||||
pub kind: FileKind,
|
||||
pub kind: Option<FileKind>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub content: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub content64: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub symlink: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub parts: Option<Vec<FilePart>>,
|
||||
#[serde(default, skip_serializing_if = "is_false")]
|
||||
pub dir: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, serde::Deserialize, serde::Serialize)]
|
||||
fn is_false(b: &bool) -> bool {
|
||||
!b
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Eq, serde::Deserialize, serde::Serialize)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub enum FileKind {
|
||||
#[default]
|
||||
Skip,
|
||||
Content(String),
|
||||
Content64(String),
|
||||
Symlink(String),
|
||||
Dir(bool),
|
||||
Parts(Vec<FilePart>),
|
||||
Symlink(String),
|
||||
Dir,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, serde::Deserialize, serde::Serialize)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, serde::Deserialize, serde::Serialize)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub enum FilePart {
|
||||
Content(String),
|
||||
@@ -102,3 +119,32 @@ pub fn base64_encode(b: &[u8]) -> String {
|
||||
use base64::{prelude::BASE64_STANDARD as B64, Engine as _};
|
||||
B64.encode(b)
|
||||
}
|
||||
|
||||
impl<'t> File {
|
||||
pub fn kind(&'t self) -> Cow<'t, FileKind> {
|
||||
self.kind.as_ref().map(Cow::Borrowed).unwrap_or_else(|| {
|
||||
use FileKind::*;
|
||||
Cow::Owned(if let Some(ref s) = self.content {
|
||||
Content(s.clone())
|
||||
} else if let Some(ref s) = self.content64 {
|
||||
Content64(s.clone())
|
||||
} else if let Some(ref s) = self.symlink {
|
||||
Symlink(s.clone())
|
||||
} else if let Some(ref p) = self.parts {
|
||||
Parts(p.clone())
|
||||
} else if self.dir {
|
||||
Dir
|
||||
} else {
|
||||
Skip
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
pub fn is_symlink(&self) -> bool {
|
||||
if let Some(ref kind) = self.kind {
|
||||
matches!(kind, FileKind::Symlink(_))
|
||||
} else {
|
||||
self.symlink.is_some()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user