Merge branch '40-refactor-clean-standard-implementation-of-cli-modules'
This commit is contained in:
commit
245ddf032a
7 changed files with 90 additions and 166 deletions
|
|
@ -1,17 +1,13 @@
|
|||
use crate::module_recipe::{Module, ModuleExt, Recipe};
|
||||
use crate::module_recipe::Recipe;
|
||||
use crate::shadow;
|
||||
|
||||
use anyhow::Result;
|
||||
use askama::Template;
|
||||
use clap::Args;
|
||||
use clap_complete::Shell;
|
||||
use format_serde_error::SerdeError;
|
||||
use fuzzy_matcher::{skim::SkimMatcherV2, FuzzyMatcher};
|
||||
use log::{debug, error, trace};
|
||||
use requestty::question::{completions, Completions};
|
||||
use std::borrow::Cow;
|
||||
use std::fs;
|
||||
use std::path::PathBuf;
|
||||
use std::time::Duration;
|
||||
use typed_builder::TypedBuilder;
|
||||
|
||||
|
|
@ -344,9 +340,7 @@ fn generate_github_issue(
|
|||
environment: &Environment,
|
||||
recipe: &Option<Recipe>,
|
||||
) -> anyhow::Result<String> {
|
||||
let recipe = recipe
|
||||
.as_ref()
|
||||
.map_or_else(Default::default, |r| print_full_recipe(r));
|
||||
let recipe = serde_yaml::to_string(recipe)?;
|
||||
|
||||
let github_template = GithubIssueTemplate::builder()
|
||||
.bb_version(shadow::PKG_VERSION)
|
||||
|
|
@ -381,68 +375,6 @@ fn make_github_issue_link(body: &str) -> String {
|
|||
.collect()
|
||||
}
|
||||
|
||||
fn get_module_from_file(file_name: &str) -> Result<ModuleExt> {
|
||||
let file_path = PathBuf::from("config").join(file_name);
|
||||
let file_path = if file_path.is_absolute() {
|
||||
file_path
|
||||
} else {
|
||||
std::env::current_dir()?.join(file_path)
|
||||
};
|
||||
|
||||
let file = fs::read_to_string(file_path.clone())?;
|
||||
|
||||
serde_yaml::from_str::<ModuleExt>(&file).map_or_else(
|
||||
|err| -> Result<ModuleExt> {
|
||||
error!(
|
||||
"Failed to parse module from {}: {}",
|
||||
file_path.display(),
|
||||
SerdeError::new(file.to_owned(), err).to_string()
|
||||
);
|
||||
|
||||
let module =
|
||||
serde_yaml::from_str::<Module>(&file).map_err(|err| SerdeError::new(file, err))?;
|
||||
Ok(ModuleExt::builder().modules(vec![module]).build())
|
||||
},
|
||||
Ok,
|
||||
)
|
||||
}
|
||||
|
||||
fn get_modules(modules: &[Module]) -> Vec<Module> {
|
||||
modules
|
||||
.iter()
|
||||
.flat_map(|module| {
|
||||
if let Some(file_name) = &module.from_file {
|
||||
match get_module_from_file(file_name) {
|
||||
Err(e) => {
|
||||
error!("Failed to get module from {file_name}: {e}");
|
||||
vec![]
|
||||
}
|
||||
Ok(module_ext) => get_modules(&module_ext.modules),
|
||||
}
|
||||
} else {
|
||||
vec![module.clone()]
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn print_full_recipe(recipe: &Recipe) -> String {
|
||||
let module_list: Vec<Module> = get_modules(&recipe.modules_ext.modules);
|
||||
|
||||
let recipe = Recipe::builder()
|
||||
.name(recipe.name.as_ref())
|
||||
.description(recipe.description.as_ref())
|
||||
.base_image(recipe.base_image.as_ref())
|
||||
.image_version(recipe.image_version.as_ref())
|
||||
.extra(recipe.extra.clone())
|
||||
.modules_ext(ModuleExt::builder().modules(module_list).build())
|
||||
.build();
|
||||
|
||||
serde_yaml::to_string(&recipe).unwrap_or_else(|e| {
|
||||
error!("Failed to serialize recipe: {e}");
|
||||
format!("Error rendering recipe!!\n{e}")
|
||||
})
|
||||
}
|
||||
// ============================================================================= //
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ use std::{
|
|||
|
||||
use anyhow::{anyhow, bail, Result};
|
||||
use clap::Args;
|
||||
use format_serde_error::SerdeError;
|
||||
use log::{debug, info, trace, warn};
|
||||
use typed_builder::TypedBuilder;
|
||||
|
||||
|
|
@ -196,9 +195,7 @@ impl BuildCommand {
|
|||
bail!("Failed to get credentials");
|
||||
}
|
||||
|
||||
let recipe_str = fs::read_to_string(recipe_path)?;
|
||||
let recipe: Recipe = serde_yaml::from_str(&recipe_str)
|
||||
.map_err(|err| SerdeError::new(recipe_str.to_owned(), err))?;
|
||||
let recipe = Recipe::parse(&recipe_path)?;
|
||||
trace!("recipe: {recipe:#?}");
|
||||
|
||||
// Get values for image
|
||||
|
|
@ -282,9 +279,7 @@ impl BuildCommand {
|
|||
fn build_image(&self, recipe_path: &Path) -> Result<()> {
|
||||
trace!("BuildCommand::build_image()");
|
||||
|
||||
let recipe_str = fs::read_to_string(recipe_path)?;
|
||||
let recipe: Recipe = serde_yaml::from_str(&recipe_str)
|
||||
.map_err(|err| SerdeError::new(recipe_str.to_owned(), err))?;
|
||||
let recipe = Recipe::parse(&recipe_path)?;
|
||||
|
||||
let tags = recipe.generate_tags();
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ use std::{
|
|||
|
||||
use anyhow::{bail, Result};
|
||||
use clap::Args;
|
||||
use format_serde_error::SerdeError;
|
||||
use log::{debug, info, trace};
|
||||
use typed_builder::TypedBuilder;
|
||||
use users::{Users, UsersCache};
|
||||
|
|
@ -44,9 +43,7 @@ impl BlueBuildCommand for UpgradeCommand {
|
|||
|
||||
check_can_run()?;
|
||||
|
||||
let recipe_str = fs::read_to_string(&self.common.recipe)?;
|
||||
let recipe: Recipe = serde_yaml::from_str(&recipe_str)
|
||||
.map_err(|err| SerdeError::new(recipe_str.to_owned(), err))?;
|
||||
let recipe = Recipe::parse(&self.common.recipe)?;
|
||||
|
||||
let mut build = BuildCommand::builder()
|
||||
.recipe(self.common.recipe.clone())
|
||||
|
|
@ -93,9 +90,7 @@ impl BlueBuildCommand for RebaseCommand {
|
|||
|
||||
check_can_run()?;
|
||||
|
||||
let recipe_str = fs::read_to_string(&self.common.recipe)?;
|
||||
let recipe: Recipe = serde_yaml::from_str(&recipe_str)
|
||||
.map_err(|err| SerdeError::new(recipe_str.to_owned(), err))?;
|
||||
let recipe = Recipe::parse(&self.common.recipe)?;
|
||||
|
||||
let mut build = BuildCommand::builder()
|
||||
.recipe(self.common.recipe.clone())
|
||||
|
|
|
|||
|
|
@ -7,13 +7,12 @@ use std::{
|
|||
use anyhow::Result;
|
||||
use askama::Template;
|
||||
use clap::Args;
|
||||
use format_serde_error::SerdeError;
|
||||
use log::{debug, error, info, trace};
|
||||
use typed_builder::TypedBuilder;
|
||||
|
||||
use crate::{
|
||||
constants::{self},
|
||||
module_recipe::{Module, ModuleExt, Recipe},
|
||||
module_recipe::{Module, Recipe},
|
||||
};
|
||||
|
||||
use super::BlueBuildCommand;
|
||||
|
|
@ -24,18 +23,10 @@ pub struct ContainerFileTemplate<'a> {
|
|||
recipe: &'a Recipe<'a>,
|
||||
recipe_path: &'a Path,
|
||||
|
||||
module_template: ModuleTemplate<'a>,
|
||||
|
||||
#[builder(default)]
|
||||
export_script: ExportsTemplate,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Template, TypedBuilder)]
|
||||
#[template(path = "Containerfile.module", escape = "none")]
|
||||
pub struct ModuleTemplate<'a> {
|
||||
module_ext: &'a ModuleExt,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, Template)]
|
||||
#[template(path = "export.sh", escape = "none")]
|
||||
pub struct ExportsTemplate;
|
||||
|
|
@ -83,11 +74,6 @@ impl TemplateCommand {
|
|||
let template = ContainerFileTemplate::builder()
|
||||
.recipe(&recipe_de)
|
||||
.recipe_path(&recipe_path)
|
||||
.module_template(
|
||||
ModuleTemplate::builder()
|
||||
.module_ext(&recipe_de.modules_ext)
|
||||
.build(),
|
||||
)
|
||||
.build();
|
||||
|
||||
let output_str = template.render()?;
|
||||
|
|
@ -168,47 +154,6 @@ fn print_containerfile(containerfile: &str) -> String {
|
|||
file
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
fn template_module_from_file(file_name: &str) -> String {
|
||||
debug!("get_module_from_file({file_name})");
|
||||
|
||||
let file_path = PathBuf::from("config").join(file_name);
|
||||
let file = fs::read_to_string(file_path).unwrap_or_else(|e| {
|
||||
error!("Failed to read module {file_name}: {e}");
|
||||
process::exit(1);
|
||||
});
|
||||
|
||||
let template_err_fn = |e| {
|
||||
error!("Failed to render module {file_name}: {e}");
|
||||
process::exit(1);
|
||||
};
|
||||
|
||||
serde_yaml::from_str::<ModuleExt>(file.as_str()).map_or_else(
|
||||
|_| {
|
||||
let module = serde_yaml::from_str::<Module>(file.as_str()).unwrap_or_else(|err| {
|
||||
error!(
|
||||
"Failed to deserialize module {file_name}: {}",
|
||||
SerdeError::new(file_name.to_owned(), err)
|
||||
);
|
||||
process::exit(1);
|
||||
});
|
||||
|
||||
ModuleTemplate::builder()
|
||||
.module_ext(&ModuleExt::builder().modules(vec![module]).build())
|
||||
.build()
|
||||
.render()
|
||||
.unwrap_or_else(template_err_fn)
|
||||
},
|
||||
|module_ext| {
|
||||
ModuleTemplate::builder()
|
||||
.module_ext(&module_ext)
|
||||
.build()
|
||||
.render()
|
||||
.unwrap_or_else(template_err_fn)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
fn print_module_context(module: &Module) -> String {
|
||||
serde_json::to_string(module).unwrap_or_else(|e| {
|
||||
error!("Failed to parse module: {e}");
|
||||
|
|
|
|||
|
|
@ -1,10 +1,16 @@
|
|||
use std::{borrow::Cow, collections::HashMap, env, fs, path::Path, process::Command};
|
||||
use std::{
|
||||
borrow::Cow,
|
||||
collections::HashMap,
|
||||
env, fs,
|
||||
path::{Path, PathBuf},
|
||||
process::Command,
|
||||
};
|
||||
|
||||
use anyhow::Result;
|
||||
use chrono::Local;
|
||||
use format_serde_error::SerdeError;
|
||||
use indexmap::IndexMap;
|
||||
use log::{debug, info, trace, warn};
|
||||
use log::{debug, error, info, trace, warn};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::Value as JsonValue;
|
||||
use serde_yaml::Value;
|
||||
|
|
@ -136,7 +142,12 @@ impl<'a> Recipe<'a> {
|
|||
|
||||
debug!("Recipe contents: {file}");
|
||||
|
||||
Ok(serde_yaml::from_str::<Recipe>(&file).map_err(|err| SerdeError::new(file, err))?)
|
||||
let mut recipe =
|
||||
serde_yaml::from_str::<Recipe>(&file).map_err(|err| SerdeError::new(file, err))?;
|
||||
|
||||
recipe.modules_ext.modules = Module::get_modules(&recipe.modules_ext.modules);
|
||||
|
||||
Ok(recipe)
|
||||
}
|
||||
|
||||
fn get_os_version(&self) -> String {
|
||||
|
|
@ -197,6 +208,34 @@ pub struct ModuleExt {
|
|||
pub modules: Vec<Module>,
|
||||
}
|
||||
|
||||
impl ModuleExt {
|
||||
pub fn parse_module_from_file(file_name: &str) -> Result<ModuleExt> {
|
||||
let file_path = PathBuf::from("config").join(file_name);
|
||||
let file_path = if file_path.is_absolute() {
|
||||
file_path
|
||||
} else {
|
||||
std::env::current_dir()?.join(file_path)
|
||||
};
|
||||
|
||||
let file = fs::read_to_string(file_path.clone())?;
|
||||
|
||||
serde_yaml::from_str::<ModuleExt>(&file).map_or_else(
|
||||
|err| -> Result<ModuleExt> {
|
||||
error!(
|
||||
"Failed to parse module from {}: {}",
|
||||
file_path.display(),
|
||||
SerdeError::new(file.to_owned(), err).to_string()
|
||||
);
|
||||
|
||||
let module = serde_yaml::from_str::<Module>(&file)
|
||||
.map_err(|err| SerdeError::new(file, err))?;
|
||||
Ok(ModuleExt::builder().modules(vec![module]).build())
|
||||
},
|
||||
Ok,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, TypedBuilder)]
|
||||
pub struct Module {
|
||||
#[builder(default, setter(into, strip_option))]
|
||||
|
|
@ -212,6 +251,27 @@ pub struct Module {
|
|||
pub config: IndexMap<String, Value>,
|
||||
}
|
||||
|
||||
impl Module {
|
||||
pub fn get_modules(modules: &[Self]) -> Vec<Self> {
|
||||
modules
|
||||
.iter()
|
||||
.flat_map(|module| {
|
||||
if let Some(file_name) = &module.from_file {
|
||||
match ModuleExt::parse_module_from_file(file_name) {
|
||||
Err(e) => {
|
||||
error!("Failed to get module from {file_name}: {e}");
|
||||
vec![]
|
||||
}
|
||||
Ok(module_ext) => Self::get_modules(&module_ext.modules),
|
||||
}
|
||||
} else {
|
||||
vec![module.clone()]
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug, Clone)]
|
||||
struct ImageInspection {
|
||||
#[serde(alias = "Labels")]
|
||||
|
|
|
|||
|
|
@ -49,6 +49,25 @@ ARG CONFIG_DIRECTORY="/tmp/config"
|
|||
ARG IMAGE_NAME="{{ recipe.name }}"
|
||||
ARG BASE_IMAGE="{{ recipe.base_image }}"
|
||||
|
||||
{{ module_template }}
|
||||
{%- for module in recipe.modules_ext.modules %}
|
||||
{%- if let Some(type) = module.module_type %}
|
||||
{%- if type == "containerfile" %}
|
||||
{%- if let Some(containerfiles) = self::get_containerfile_list(module) %}
|
||||
{%- for c in containerfiles %}
|
||||
{{ self::print_containerfile(c) }}
|
||||
{%- endfor %}
|
||||
{%- endif %}
|
||||
{%- else if type == "files" %}
|
||||
{%- if let Some(files) = self::get_files_list(module) %}
|
||||
{%- for (src, dest) in files %}
|
||||
COPY {{ src }} {{ dest }}
|
||||
{%- endfor %}
|
||||
{%- endif %}
|
||||
{%- else %}
|
||||
RUN chmod +x /tmp/modules/{{ type }}/{{ type }}.sh && source /tmp/exports.sh && /tmp/modules/{{ type }}/{{ type }}.sh '{{ self::print_module_context(module) }}'
|
||||
{%- endif %}
|
||||
{%- endif %}
|
||||
{%- endfor %}
|
||||
|
||||
|
||||
RUN rm -rf /tmp/* /var/* && ostree container commit
|
||||
|
|
|
|||
|
|
@ -1,22 +0,0 @@
|
|||
{%- for module in module_ext.modules %}
|
||||
{%- if let Some(type) = module.module_type %}
|
||||
{%- if type == "containerfile" %}
|
||||
{%- if let Some(containerfiles) = self::get_containerfile_list(module) %}
|
||||
{%- for c in containerfiles %}
|
||||
{{ self::print_containerfile(c) }}
|
||||
{%- endfor %}
|
||||
{%- endif %}
|
||||
{%- else if type == "files" %}
|
||||
{%- if let Some(files) = self::get_files_list(module) %}
|
||||
{%- for (src, dest) in files %}
|
||||
COPY {{ src }} {{ dest }}
|
||||
{%- endfor %}
|
||||
{%- endif %}
|
||||
{%- else %}
|
||||
RUN chmod +x /tmp/modules/{{ type }}/{{ type }}.sh && source /tmp/exports.sh && /tmp/modules/{{ type }}/{{ type }}.sh '{{ self::print_module_context(module) }}'
|
||||
{%- endif %}
|
||||
{%- else if let Some(from_file) = module.from_file %}
|
||||
{{ self::template_module_from_file(from_file) }}
|
||||
{%- endif %}
|
||||
{%- endfor %}
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue