refactor: Move modules into their own directory structure (#80)
This separates out the module template logic so that it is easier to undertstand what each section does. This will also allow creating in repo documentation for any special modules that don't use a bash base.
This commit is contained in:
parent
0b4e1003a2
commit
4c8a8f7aa8
22 changed files with 239 additions and 688 deletions
7
src/akmods_info.rs
Normal file
7
src/akmods_info.rs
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
use typed_builder::TypedBuilder;
|
||||
|
||||
#[derive(Debug, Clone, TypedBuilder, PartialEq, Eq, Hash)]
|
||||
pub struct AkmodsInfo {
|
||||
pub images: (String, Option<String>),
|
||||
pub stage_name: String,
|
||||
}
|
||||
|
|
@ -1,5 +1,4 @@
|
|||
use std::{
|
||||
collections::HashSet,
|
||||
env, fs,
|
||||
path::{Path, PathBuf},
|
||||
process,
|
||||
|
|
@ -12,15 +11,12 @@ use log::{debug, error, info, trace};
|
|||
use typed_builder::TypedBuilder;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::{
|
||||
constants::*,
|
||||
module_recipe::{Module, ModuleExt, Recipe},
|
||||
};
|
||||
use crate::{constants::*, module_recipe::Recipe};
|
||||
|
||||
use super::BlueBuildCommand;
|
||||
|
||||
#[derive(Debug, Clone, Template, TypedBuilder)]
|
||||
#[template(path = "Containerfile")]
|
||||
#[template(path = "Containerfile.j2", escape = "none")]
|
||||
pub struct ContainerFileTemplate<'a> {
|
||||
recipe: &'a Recipe<'a>,
|
||||
|
||||
|
|
@ -38,6 +34,24 @@ pub struct ContainerFileTemplate<'a> {
|
|||
#[template(path = "export.sh", escape = "none")]
|
||||
pub struct ExportsTemplate;
|
||||
|
||||
impl ExportsTemplate {
|
||||
fn print_script(&self) -> String {
|
||||
trace!("print_script({self})");
|
||||
|
||||
format!(
|
||||
"\"{}\"",
|
||||
self.render()
|
||||
.unwrap_or_else(|e| {
|
||||
error!("Failed to render export.sh script: {e}");
|
||||
process::exit(1);
|
||||
})
|
||||
.replace('\n', "\\n")
|
||||
.replace('\"', "\\\"")
|
||||
.replace('$', "\\$")
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Args, TypedBuilder)]
|
||||
pub struct TemplateCommand {
|
||||
/// The recipe file to create a template from
|
||||
|
|
@ -114,23 +128,6 @@ impl TemplateCommand {
|
|||
// ========================= Helpers ====================== //
|
||||
// ======================================================== //
|
||||
|
||||
fn print_script(script_contents: &ExportsTemplate) -> String {
|
||||
trace!("print_script({script_contents})");
|
||||
|
||||
format!(
|
||||
"\"{}\"",
|
||||
script_contents
|
||||
.render()
|
||||
.unwrap_or_else(|e| {
|
||||
error!("Failed to render export.sh script: {e}");
|
||||
process::exit(1);
|
||||
})
|
||||
.replace('\n', "\\n")
|
||||
.replace('\"', "\\\"")
|
||||
.replace('$', "\\$")
|
||||
)
|
||||
}
|
||||
|
||||
fn has_cosign_file() -> bool {
|
||||
trace!("has_cosign_file()");
|
||||
std::env::current_dir()
|
||||
|
|
@ -138,33 +135,6 @@ fn has_cosign_file() -> bool {
|
|||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
fn get_module_type_list(module: &Module, typ: &str, list_key: &str) -> Option<Vec<String>> {
|
||||
if module.module_type.as_ref()? == typ {
|
||||
Some(
|
||||
module
|
||||
.config
|
||||
.get(list_key)?
|
||||
.as_sequence()?
|
||||
.iter()
|
||||
.filter_map(|t| Some(t.as_str()?.to_owned()))
|
||||
.collect(),
|
||||
)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
fn get_containerfile_list(module: &Module) -> Option<Vec<String>> {
|
||||
get_module_type_list(module, "containerfile", "containerfiles")
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
fn get_containerfile_snippets(module: &Module) -> Option<Vec<String>> {
|
||||
get_module_type_list(module, "containerfile", "snippets")
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
fn print_containerfile(containerfile: &str) -> String {
|
||||
trace!("print_containerfile({containerfile})");
|
||||
|
|
@ -182,32 +152,6 @@ fn print_containerfile(containerfile: &str) -> String {
|
|||
file
|
||||
}
|
||||
|
||||
fn print_module_context(module: &Module) -> String {
|
||||
serde_json::to_string(module).unwrap_or_else(|e| {
|
||||
error!("Failed to parse module!!!!!: {e}");
|
||||
process::exit(1);
|
||||
})
|
||||
}
|
||||
|
||||
fn get_files_list(module: &Module) -> Option<Vec<(String, String)>> {
|
||||
Some(
|
||||
module
|
||||
.config
|
||||
.get("files")?
|
||||
.as_sequence()?
|
||||
.iter()
|
||||
.filter_map(|entry| entry.as_mapping())
|
||||
.flatten()
|
||||
.filter_map(|(src, dest)| {
|
||||
Some((
|
||||
format!("./config/files/{}", src.as_str()?),
|
||||
dest.as_str()?.to_string(),
|
||||
))
|
||||
})
|
||||
.collect(),
|
||||
)
|
||||
}
|
||||
|
||||
fn get_github_repo_owner() -> Option<String> {
|
||||
Some(env::var(GITHUB_REPOSITORY_OWNER).ok()?.to_lowercase())
|
||||
}
|
||||
|
|
@ -228,56 +172,3 @@ fn modules_exists() -> bool {
|
|||
let mod_path = Path::new("modules");
|
||||
mod_path.exists() && mod_path.is_dir()
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, TypedBuilder, PartialEq, Eq, Hash)]
|
||||
struct AkmodsInfo {
|
||||
images: (String, Option<String>),
|
||||
stage_name: String,
|
||||
}
|
||||
|
||||
fn get_akmods_info_list(module_ext: &ModuleExt, os_version: &str) -> Vec<AkmodsInfo> {
|
||||
trace!("get_akmods_image_list({module_ext:#?}, {os_version})");
|
||||
|
||||
let mut seen = HashSet::new();
|
||||
|
||||
module_ext
|
||||
.modules
|
||||
.iter()
|
||||
.filter(|module| module.module_type.as_ref().is_some_and(|t| t == "akmods"))
|
||||
.map(|module| generate_akmods_info(module, os_version))
|
||||
.filter(|image| seen.insert(image.clone()))
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn generate_akmods_info(module: &Module, os_version: &str) -> AkmodsInfo {
|
||||
trace!("generate_akmods_base({module:#?}, {os_version})");
|
||||
|
||||
let base = module
|
||||
.config
|
||||
.get("base")
|
||||
.map(|b| b.as_str().unwrap_or_default());
|
||||
let nvidia_version = module
|
||||
.config
|
||||
.get("nvidia-version")
|
||||
.map(|v| v.as_u64().unwrap_or_default());
|
||||
|
||||
AkmodsInfo::builder()
|
||||
.images(match (base, nvidia_version) {
|
||||
(Some(b), Some(nv)) if !b.is_empty() && nv > 0 => (
|
||||
format!("akmods:{b}-{os_version}"),
|
||||
Some(format!("akmods-nvidia:{b}-{os_version}-{nv}")),
|
||||
),
|
||||
(Some(b), _) if !b.is_empty() => (format!("akmods:{b}-{os_version}"), None),
|
||||
(_, Some(nv)) if nv > 0 => (
|
||||
format!("akmods:main-{os_version}"),
|
||||
Some(format!("akmods-nvidia:main-{os_version}")),
|
||||
),
|
||||
_ => (format!("akmods:main-{os_version}"), None),
|
||||
})
|
||||
.stage_name(format!(
|
||||
"{}{}",
|
||||
base.unwrap_or("main"),
|
||||
nvidia_version.map_or_else(String::default, |nv| format!("-{nv}"))
|
||||
))
|
||||
.build()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
shadow_rs::shadow!(shadow);
|
||||
|
||||
pub mod akmods_info;
|
||||
pub mod commands;
|
||||
pub mod constants;
|
||||
pub mod module_recipe;
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
use std::{
|
||||
borrow::Cow,
|
||||
collections::HashMap,
|
||||
collections::{HashMap, HashSet},
|
||||
env, fs,
|
||||
path::{Path, PathBuf},
|
||||
process::Command,
|
||||
process::{self, Command},
|
||||
};
|
||||
|
||||
use anyhow::Result;
|
||||
|
|
@ -17,6 +17,7 @@ use serde_yaml::Value;
|
|||
use typed_builder::TypedBuilder;
|
||||
|
||||
use crate::{
|
||||
akmods_info::AkmodsInfo,
|
||||
constants::*,
|
||||
ops::{self, check_command_exists},
|
||||
};
|
||||
|
|
@ -236,6 +237,19 @@ impl ModuleExt<'_> {
|
|||
Ok,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn get_akmods_info_list(&self, os_version: &str) -> Vec<AkmodsInfo> {
|
||||
trace!("get_akmods_image_list({self:#?}, {os_version})");
|
||||
|
||||
let mut seen = HashSet::new();
|
||||
|
||||
self.modules
|
||||
.iter()
|
||||
.filter(|module| module.module_type.as_ref().is_some_and(|t| t == "akmods"))
|
||||
.map(|module| module.generate_akmods_info(os_version))
|
||||
.filter(|image| seen.insert(image.clone()))
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, TypedBuilder)]
|
||||
|
|
@ -257,7 +271,7 @@ pub struct Module<'a> {
|
|||
pub config: IndexMap<String, Value>,
|
||||
}
|
||||
|
||||
impl Module<'_> {
|
||||
impl<'a> Module<'a> {
|
||||
#[must_use]
|
||||
pub fn get_modules(modules: &[Self]) -> Vec<Self> {
|
||||
modules
|
||||
|
|
@ -276,6 +290,90 @@ impl Module<'_> {
|
|||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn get_module_type_list(&'a self, typ: &str, list_key: &str) -> Option<Vec<String>> {
|
||||
if self.module_type.as_ref()? == typ {
|
||||
Some(
|
||||
self.config
|
||||
.get(list_key)?
|
||||
.as_sequence()?
|
||||
.iter()
|
||||
.filter_map(|t| Some(t.as_str()?.to_owned()))
|
||||
.collect(),
|
||||
)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn get_containerfile_list(&'a self) -> Option<Vec<String>> {
|
||||
self.get_module_type_list("containerfile", "containerfiles")
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn get_containerfile_snippets(&'a self) -> Option<Vec<String>> {
|
||||
self.get_module_type_list("containerfile", "snippets")
|
||||
}
|
||||
|
||||
pub fn print_module_context(&'a self) -> String {
|
||||
serde_json::to_string(self).unwrap_or_else(|e| {
|
||||
error!("Failed to parse module!!!!!: {e}");
|
||||
process::exit(1);
|
||||
})
|
||||
}
|
||||
|
||||
pub fn get_files_list(&'a self) -> Option<Vec<(String, String)>> {
|
||||
Some(
|
||||
self.config
|
||||
.get("files")?
|
||||
.as_sequence()?
|
||||
.iter()
|
||||
.filter_map(|entry| entry.as_mapping())
|
||||
.flatten()
|
||||
.filter_map(|(src, dest)| {
|
||||
Some((
|
||||
format!("./config/files/{}", src.as_str()?),
|
||||
dest.as_str()?.to_string(),
|
||||
))
|
||||
})
|
||||
.collect(),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn generate_akmods_info(&'a self, os_version: &str) -> AkmodsInfo {
|
||||
trace!("generate_akmods_base({self:#?}, {os_version})");
|
||||
|
||||
let base = self
|
||||
.config
|
||||
.get("base")
|
||||
.map(|b| b.as_str().unwrap_or_default());
|
||||
let nvidia_version = self
|
||||
.config
|
||||
.get("nvidia-version")
|
||||
.map(|v| v.as_u64().unwrap_or_default());
|
||||
|
||||
AkmodsInfo::builder()
|
||||
.images(match (base, nvidia_version) {
|
||||
(Some(b), Some(nv)) if !b.is_empty() && nv > 0 => (
|
||||
format!("akmods:{b}-{os_version}"),
|
||||
Some(format!("akmods-nvidia:{b}-{os_version}-{nv}")),
|
||||
),
|
||||
(Some(b), _) if !b.is_empty() => (format!("akmods:{b}-{os_version}"), None),
|
||||
(_, Some(nv)) if nv > 0 => (
|
||||
format!("akmods:main-{os_version}"),
|
||||
Some(format!("akmods-nvidia:main-{os_version}")),
|
||||
),
|
||||
_ => (format!("akmods:main-{os_version}"), None),
|
||||
})
|
||||
.stage_name(format!(
|
||||
"{}{}",
|
||||
base.unwrap_or("main"),
|
||||
nvidia_version.map_or_else(String::default, |nv| format!("-{nv}"))
|
||||
))
|
||||
.build()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug, Clone)]
|
||||
|
|
|
|||
|
|
@ -1,104 +0,0 @@
|
|||
{%- let os_version = recipe.get_os_version() %}
|
||||
# This stage is responsible for holding onto
|
||||
# your config without copying it directly into
|
||||
# the final image
|
||||
FROM scratch as stage-config
|
||||
COPY ./config /config
|
||||
|
||||
# Copy modules
|
||||
# The default modules are inside ublue-os/bling
|
||||
# Custom modules overwrite defaults
|
||||
FROM scratch as stage-modules
|
||||
COPY --from=ghcr.io/ublue-os/bling:latest /modules /modules
|
||||
{%- if self::modules_exists() %}
|
||||
COPY ./modules /modules
|
||||
{%- endif %}
|
||||
|
||||
{%- for info in self::get_akmods_info_list(recipe.modules_ext, os_version) %}
|
||||
FROM scratch as stage-akmods-{{ info.stage_name }}
|
||||
COPY --from=ghcr.io/ublue-os/{{ info.images.0 }} /rpms /rpms
|
||||
{%- if let Some(nv_image) = info.images.1 %}
|
||||
COPY --from=ghcr.io/ublue-os/{{ nv_image }} /rpms /rpms
|
||||
{%- endif %}
|
||||
{%- endfor %}
|
||||
|
||||
# This stage is responsible for holding onto
|
||||
# exports like the exports.sh
|
||||
FROM docker.io/alpine as stage-exports
|
||||
RUN printf {{ self::print_script(export_script) }} >> /exports.sh && chmod +x /exports.sh
|
||||
|
||||
FROM {{ recipe.base_image }}:{{ recipe.image_version }}
|
||||
|
||||
LABEL {{ crate::constants::BUILD_ID_LABEL }}="{{ build_id }}"
|
||||
LABEL org.opencontainers.image.title="{{ recipe.name }}"
|
||||
LABEL org.opencontainers.image.description="{{ recipe.description }}"
|
||||
LABEL io.artifacthub.package.readme-url=https://raw.githubusercontent.com/blue-build/cli/main/README.md
|
||||
|
||||
ARG RECIPE={{ recipe_path.display() }}
|
||||
|
||||
{%- if let Some(repo_owner) = self::get_github_repo_owner() %}
|
||||
ARG IMAGE_REGISTRY=ghcr.io/{{ repo_owner }}
|
||||
{%- else if let Some(registry) = self::get_gitlab_registry_path() %}
|
||||
ARG IMAGE_REGISTRY={{ registry }}
|
||||
{%- else %}
|
||||
ARG IMAGE_REGISTRY=localhost
|
||||
{%- endif %}
|
||||
|
||||
{%- if self::has_cosign_file() %}
|
||||
COPY cosign.pub /usr/share/ublue-os/cosign.pub
|
||||
{%- endif %}
|
||||
|
||||
ARG CONFIG_DIRECTORY="/tmp/config"
|
||||
ARG IMAGE_NAME="{{ recipe.name }}"
|
||||
ARG BASE_IMAGE="{{ recipe.base_image }}"
|
||||
|
||||
{%- 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 %}
|
||||
{%- if let Some(snippets) = self::get_containerfile_snippets(module) %}
|
||||
{%- for s in snippets %}
|
||||
{{ s }}
|
||||
{%- 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 \
|
||||
--mount=type=tmpfs,target=/tmp \
|
||||
--mount=type=tmpfs,target=/var \
|
||||
--mount=type=bind,from=docker.io/mikefarah/yq,src=/usr/bin/yq,dst=/usr/bin/yq \
|
||||
--mount=type=bind,from=stage-config,src=/config,dst=/tmp/config,rw \
|
||||
{%- if let Some(source) = module.source %}
|
||||
--mount=type=bind,from={{ source }},src=/modules,dst=/tmp/modules,rw \
|
||||
{%- else %}
|
||||
--mount=type=bind,from=stage-modules,src=/modules,dst=/tmp/modules,rw \
|
||||
{%- endif %}
|
||||
{%- if type == "akmods" %}
|
||||
--mount=type=bind,from=stage-akmods-{{ self::generate_akmods_info(module, os_version).stage_name }},src=/rpms,dst=/tmp/rpms,rw \
|
||||
{%- endif %}
|
||||
--mount=type=bind,from=stage-exports,src=/exports.sh,dst=/tmp/exports.sh \
|
||||
--mount=type=cache,dst=/var/cache/rpm-ostree,id=rpm-ostree-cache-{{ recipe.name }}-{{ recipe.image_version }},sharing=locked \
|
||||
chmod +x /tmp/modules/{{ type }}/{{ type }}.sh \
|
||||
&& source /tmp/exports.sh && /tmp/modules/{{ type }}/{{ type }}.sh '{{ self::print_module_context(module) }}'
|
||||
{%- endif %}
|
||||
{%- endif %}
|
||||
{%- endfor %}
|
||||
|
||||
COPY --from=gcr.io/projectsigstore/cosign /ko-app/cosign /usr/bin/cosign
|
||||
COPY --from=ghcr.io/blue-build/cli:
|
||||
{%- if let Some(tag) = recipe.blue_build_tag -%}
|
||||
{{ tag }}
|
||||
{%- else -%}
|
||||
latest-installer
|
||||
{%- endif %} /out/bluebuild /usr/bin/bluebuild
|
||||
|
||||
RUN ostree container commit
|
||||
59
templates/Containerfile.j2
Normal file
59
templates/Containerfile.j2
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
{%- let os_version = recipe.get_os_version() %}
|
||||
# This stage is responsible for holding onto
|
||||
# your config without copying it directly into
|
||||
# the final image
|
||||
FROM scratch as stage-config
|
||||
COPY ./config /config
|
||||
|
||||
# Copy modules
|
||||
# The default modules are inside ublue-os/bling
|
||||
# Custom modules overwrite defaults
|
||||
FROM scratch as stage-modules
|
||||
COPY --from=ghcr.io/ublue-os/bling:latest /modules /modules
|
||||
{%- if self::modules_exists() %}
|
||||
COPY ./modules /modules
|
||||
{%- endif %}
|
||||
|
||||
{%- include "modules/akmods/akmods.j2" %}
|
||||
|
||||
# This stage is responsible for holding onto
|
||||
# exports like the exports.sh
|
||||
FROM docker.io/alpine as stage-exports
|
||||
RUN printf {{ export_script.print_script() }} >> /exports.sh && chmod +x /exports.sh
|
||||
|
||||
FROM {{ recipe.base_image }}:{{ recipe.image_version }}
|
||||
|
||||
LABEL {{ crate::constants::BUILD_ID_LABEL }}="{{ build_id }}"
|
||||
LABEL org.opencontainers.image.title="{{ recipe.name }}"
|
||||
LABEL org.opencontainers.image.description="{{ recipe.description }}"
|
||||
LABEL io.artifacthub.package.readme-url=https://raw.githubusercontent.com/blue-build/cli/main/README.md
|
||||
|
||||
ARG RECIPE={{ recipe_path.display() }}
|
||||
|
||||
{%- if let Some(repo_owner) = self::get_github_repo_owner() %}
|
||||
ARG IMAGE_REGISTRY=ghcr.io/{{ repo_owner }}
|
||||
{%- else if let Some(registry) = self::get_gitlab_registry_path() %}
|
||||
ARG IMAGE_REGISTRY={{ registry }}
|
||||
{%- else %}
|
||||
ARG IMAGE_REGISTRY=localhost
|
||||
{%- endif %}
|
||||
|
||||
{%- if self::has_cosign_file() %}
|
||||
COPY cosign.pub /usr/share/ublue-os/cosign.pub
|
||||
{%- endif %}
|
||||
|
||||
ARG CONFIG_DIRECTORY="/tmp/config"
|
||||
ARG IMAGE_NAME="{{ recipe.name }}"
|
||||
ARG BASE_IMAGE="{{ recipe.base_image }}"
|
||||
|
||||
{%- include "modules/modules.j2" %}
|
||||
|
||||
COPY --from=gcr.io/projectsigstore/cosign /ko-app/cosign /usr/bin/cosign
|
||||
COPY --from=ghcr.io/blue-build/cli:
|
||||
{%- if let Some(tag) = recipe.blue_build_tag -%}
|
||||
{{ tag }}
|
||||
{%- else -%}
|
||||
latest-installer
|
||||
{%- endif %} /out/bluebuild /usr/bin/bluebuild
|
||||
|
||||
RUN ostree container commit
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
# this file is a placeholder,
|
||||
# making changes here is not supported
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
import '100-bling.just'
|
||||
# Include some of your custom scripts here!
|
||||
|
|
@ -1,91 +0,0 @@
|
|||
# Starting point
|
||||
|
||||
This is a constantly updating template repository for creating [a native container image](https://fedoraproject.org/wiki/Changes/OstreeNativeContainerStable) designed to be customized however you want. GitHub will build your image for you, and then host it for you on [ghcr.io](https://github.com/features/packages). You then just tell your computer to boot off of that image. GitHub keeps 90 days worth image backups for you, thanks Microsoft!
|
||||
|
||||
For more info, check out the [uBlue homepage](https://universal-blue.org/) and the [main uBlue repo](https://github.com/ublue-os/main/)
|
||||
|
||||
## Getting started
|
||||
|
||||
See the [Make Your Own-page in the documentation](https://universal-blue.org/tinker/make-your-own/) for quick setup instructions for setting up your own repository based on this template.
|
||||
|
||||
Don't worry, it only requires some basic knowledge about using the terminal and git.
|
||||
|
||||
After setup, it is recommended you update this README to describe your custom image.
|
||||
|
||||
> **Note**
|
||||
> Everywhere in this repository, make sure to replace `ublue-os/startingpoint` with the details of your own repository. Unless you used one of the automatic repository setup tools in which case the previous repo identifier should already be your repo's details.
|
||||
|
||||
> **Warning**
|
||||
> To start, you *must* create a branch called `live` which is exclusively for your customizations. That is the **only** branch the GitHub workflow will deploy to your container registry. Don't make any changes to the original "template" branch. It should remain untouched. By using this branch structure, you ensure a clear separation between your own "published image" branch, your development branches, and the original upstream "template" branch. Periodically sync and fast-forward the upstream "template" branch to the most recent revision. Then, simply rebase your `live` branch onto the updated template to effortlessly incorporate the latest improvements into your own repository, without the need for any messy, manual "merge commits".
|
||||
|
||||
## Customization
|
||||
|
||||
The easiest way to start customizing is by looking at and modifying `config/recipe.yml`. It's documented using comments and should be pretty easy to understand.
|
||||
|
||||
If you want to add custom configuration files, you can just add them in the `/usr/etc/` directory, which is the official OSTree "configuration template" directory and will be applied to `/etc/` on boot. `config/files/usr` is copied into your image's `/usr` by default. If you need to add other directories in the root of your image, that can be done using the `files` module. Writing to `/var/` in the image builds of OSTree-based distros isn't supported and will not work, as that is a local user-managed directory!
|
||||
|
||||
For more information about customization, see [the README in the config directory](config/README.md)
|
||||
|
||||
Documentation around making custom images exists / should be written in two separate places:
|
||||
* [The Tinkerer's Guide on the website](https://universal-blue.org/tinker/make-your-own/) for general documentation around making custom images, best practices, tutorials, and so on.
|
||||
* Inside this repository for documentation specific to the ins and outs of the template (like module documentation), and just some essential guidance on how to make custom images.
|
||||
|
||||
## Installation
|
||||
|
||||
> **Warning**
|
||||
> [This is an experimental feature](https://www.fedoraproject.org/wiki/Changes/OstreeNativeContainerStable) and should not be used in production, try it in a VM for a while!
|
||||
|
||||
To rebase an existing Silverblue/Kinoite installation to the latest build:
|
||||
|
||||
- First rebase to the unsigned image, to get the proper signing keys and policies installed:
|
||||
```
|
||||
rpm-ostree rebase ostree-unverified-registry:ghcr.io/ublue-os/startingpoint:latest
|
||||
```
|
||||
- Reboot to complete the rebase:
|
||||
```
|
||||
systemctl reboot
|
||||
```
|
||||
- Then rebase to the signed image, like so:
|
||||
```
|
||||
rpm-ostree rebase ostree-image-signed:docker://ghcr.io/ublue-os/startingpoint:latest
|
||||
```
|
||||
- Reboot again to complete the installation
|
||||
```
|
||||
systemctl reboot
|
||||
```
|
||||
|
||||
This repository builds date tags as well, so if you want to rebase to a particular day's build:
|
||||
|
||||
```
|
||||
rpm-ostree rebase ostree-image-signed:docker://ghcr.io/ublue-os/startingpoint:20230403
|
||||
```
|
||||
|
||||
This repository by default also supports signing.
|
||||
|
||||
The `latest` tag will automatically point to the latest build. That build will still always use the Fedora version specified in `recipe.yml`, so you won't get accidentally updated to the next major version.
|
||||
|
||||
## ISO
|
||||
|
||||
This template includes a simple Github Action to build and release an ISO of your image.
|
||||
|
||||
To run the action, simply edit the `boot_menu.yml` by changing all the references to startingpoint to your repository. This should trigger the action automatically.
|
||||
|
||||
The Action uses [isogenerator](https://github.com/ublue-os/isogenerator) and works in a similar manner to the official Universal Blue ISO. If you have any issues, you should first check [the documentation page on installation](https://universal-blue.org/installation/). The ISO is a netinstaller and should always pull the latest version of your image.
|
||||
|
||||
Note that this release-iso action is not a replacement for a full-blown release automation like [release-please](https://github.com/googleapis/release-please).
|
||||
|
||||
## `just`
|
||||
|
||||
The [`just`](https://just.systems/) command runner is included in all `ublue-os/main`-derived images.
|
||||
|
||||
You need to have a `~/.justfile` with the following contents and `just` aliased to `just --unstable` (default in posix-compatible shells on ublue) to get started with just locally.
|
||||
```
|
||||
!include /usr/share/ublue-os/just/main.just
|
||||
!include /usr/share/ublue-os/just/nvidia.just
|
||||
!include /usr/share/ublue-os/just/custom.just
|
||||
```
|
||||
Then type `just` to list the just recipes available.
|
||||
|
||||
The file `/usr/share/ublue-os/just/custom.just` is intended for the custom just commands (recipes) you wish to include in your image. By default, it includes the justfiles from [`ublue-os/bling`](https://github.com/ublue-os/bling), if you wish to disable that, you need to just remove the line that includes bling.just.
|
||||
|
||||
See [the just-page in the Universal Blue documentation](https://universal-blue.org/guide/just/) for more information.
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
[Desktop Entry]
|
||||
Name=uBlue First Boot Setup
|
||||
Comment=Sets up the uBlue desktop on first boot.
|
||||
GenericName=Launcher
|
||||
Categories=Utility;System;
|
||||
Exec=/usr/share/ublue-os/firstboot/launcher/autostart.sh
|
||||
Icon=application-x-executable
|
||||
Terminal=false
|
||||
Type=Application
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
# Simply launches the "yafti" GUI with the uBlue image's configuration.
|
||||
/usr/bin/yafti /usr/share/ublue-os/firstboot/yafti.yml
|
||||
|
|
@ -1,42 +0,0 @@
|
|||
# Configuring your image
|
||||
|
||||
The main file of your is *the recipe file*. You can have multiple recipe files, and the ones to build are declared in the matrix section of [.gitlab-ci.yml](../.gitlab-ci.yml).
|
||||
|
||||
## Basic options
|
||||
|
||||
At the top of the recipe, there are four *mandatory* configuration options.
|
||||
|
||||
`name:` is the name of the image that is used when rebasing to it. For example, the name "sapphire" would result in the final URL of the container being `registry.gitlab.com/<yourusername>/sapphire`.
|
||||
|
||||
`description:` is a short description of your image that will be attached to your image's metadata.
|
||||
|
||||
`base-image:` is the URL of the image your image will be built upon.
|
||||
|
||||
`image-version:` is the version tag of the `base-image` that will be pulled. For example, Universal Blue's images build with Fedora version tags (`38`, `39`), with the `latest` tag for the latest major version, and [many other tags](https://github.com/ublue-os/main/pkgs/container/base-main/versions?filters%5Bversion_type%5D=tagged).
|
||||
|
||||
## Modules
|
||||
|
||||
The core of startingpoint's configuration is built around the idea of modules. Modules are scripts in the [`../modules`](../modules/) directory that you configure under `modules:` in the recipe. They are executed in order, and can run arbitrary shell commands and write any files.
|
||||
|
||||
This repository fetches some useful default modules from [`ublue-os/bling`](https://github.com/ublue-os/bling/), like [`rpm-ostree`](https://universal-blue.org/tinker/modules/rpm-ostree) for pseudo-declarative package management, [`bling`](https://universal-blue.org/tinker/modules/bling) for pulling extra components from [`ublue-os/bling`](https://github.com/ublue-os/bling), and [`files`](https://universal-blue.org/tinker/modules/files) for copying files from the `config/files/` directory into your image.
|
||||
|
||||
For a comprehensive list of modules, their in-depth documentation and example configuration, check out [the Modules page on the website](https://universal-blue.org/tinker/modules/).
|
||||
|
||||
### Building multiple images and including module configuration from other files and
|
||||
|
||||
To build multiple images, you need to create another recipe.yml file, which you should name based on what kind of image you want it to build. Then, edit the [.gitlab-ci.yml](../.gitlab-ci.yml) file. Inside the file, under `build-image: parallel: matrix:`, there's a list of recipe files to build images, which you need to add your new recipe file to. These should be paths to files inside the `config` directory.
|
||||
|
||||
Module configuration can be included from other files using the `from-file` syntax. The value should be a path to a file inside the `config` directory. For example, the following snippet could be used to include the configuration for installing a set of packages common to multiple images.
|
||||
```yaml
|
||||
modules:
|
||||
- from-file: common-packages.yml
|
||||
```
|
||||
And inside config/common-packages.yml
|
||||
```yaml
|
||||
type: rpm-ostree
|
||||
install:
|
||||
- i3
|
||||
- dunst
|
||||
- rofi
|
||||
- kitty
|
||||
```
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
# Tell this script to exit if there are any errors.
|
||||
# You should have this in every custom script, to ensure that your completed
|
||||
# builds actually ran successfully without any errors!
|
||||
set -oue pipefail
|
||||
|
||||
# Your code goes here.
|
||||
echo 'This is an example shell script'
|
||||
echo 'Scripts here will run during build if specified in recipe.yml'
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
workflow:
|
||||
rules:
|
||||
- if: $CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS && $CI_PIPELINE_SOURCE == "push"
|
||||
when: never
|
||||
- if: "$CI_COMMIT_TAG"
|
||||
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
|
||||
- if: "$CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS"
|
||||
when: never
|
||||
- if: "$CI_COMMIT_BRANCH"
|
||||
|
||||
stages:
|
||||
- build
|
||||
|
||||
variables:
|
||||
ACTION:
|
||||
description: "Action to perform for the pipeline."
|
||||
value: "build-image"
|
||||
options:
|
||||
- "build-image"
|
||||
|
||||
build-image:
|
||||
stage: build
|
||||
image: registry.gitlab.com/wunker-bunker/ublue-cli
|
||||
retry: 2
|
||||
rules:
|
||||
- if: $ACTION == "build-image"
|
||||
parallel:
|
||||
matrix:
|
||||
- RECIPE:
|
||||
- recipe.yml
|
||||
id_tokens:
|
||||
SIGSTORE_ID_TOKEN:
|
||||
aud: sigstore
|
||||
script:
|
||||
- ublue build --push ./config/$RECIPE
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
# Only process users with home directories, but skip the "root" user.
|
||||
if [ "$(id -u)" != "0" ] && [ ! -z "$HOME" ] && [ -d "$HOME" ]; then
|
||||
# Ensure target file exists and is a symlink (not a regular file or dir).
|
||||
if [ ! -L "$HOME"/.config/autostart/ublue-firstboot.desktop ]; then
|
||||
# Remove any leftovers or incorrect (non-link) files with the same name.
|
||||
rm -rf "$HOME"/.config/autostart/ublue-firstboot.desktop
|
||||
|
||||
# Create symlink to uBlue's autostart runner.
|
||||
# Note that "broken autostart symlinks" are harmless if they remain
|
||||
# after distro switching, and just cause a minor syslog warning. The
|
||||
# user can manually delete this file if they migrate away from uBlue.
|
||||
mkdir -p "$HOME"/.config/autostart
|
||||
ln -s "/usr/share/ublue-os/firstboot/launcher/autostart.desktop" "$HOME"/.config/autostart/ublue-firstboot.desktop
|
||||
fi
|
||||
fi
|
||||
|
|
@ -1,46 +0,0 @@
|
|||
# Making modules
|
||||
|
||||
If you want to extend Startingpoint with custom functionality that requires configuration, you should create a module. Modules are scripts in the subdirectories of this directory. The `type:` key in the recipe.yml should be used as both the name of the folder and script, with the script having an additional `.sh` suffix. Creating a custom module with the same name as a default module will override it.
|
||||
|
||||
Each module intended for public usage should include a `README.md` file inside it's directory with a short description of the module and documentation for each configuration option.
|
||||
|
||||
Modules get only the configuration options given to them in the recipe.yml, not the configuration of other modules or any top-level keys. The configuration is given as the first argument as a single-line json string. You can check out the default modules for examples on how to parse such string using `yq` or `jq`.
|
||||
|
||||
Additionally, each module has access to four environment variables, `CONFIG_DIRECTORY` pointing to the Startingpoint directory in `/usr/share/ublue-os/`, `IMAGE_NAME` being the name of the image as declared in the recipe, `BASE_IMAGE` being the URL of the container image used as the base (FROM) in the image, and `OS_VERSION` being the `VERSION_ID` from `/usr/lib/os-release`.
|
||||
|
||||
When running modules, the working directory is the `CONFIG_DIRECTORY`.
|
||||
|
||||
A helper bash function called `get_yaml_array` is exported from the main build script.
|
||||
```bash
|
||||
# "$1" is the first cli argument, being the module configuration.
|
||||
# If you need to read from some other JSON string, just replace "$1" with "$VARNAME".
|
||||
get_yaml_array OUTPUT_VAR_NAME '.yq.key.to.array[]' "$1"
|
||||
for THING in "${OUTPUT_VAR_NAME[@]}"; do
|
||||
echo "$THING"
|
||||
done
|
||||
```
|
||||
|
||||
All bash-based modules should start with the following lines to ensure the image builds fail on errors, and that the correct shell is used to run them.
|
||||
```bash
|
||||
#!/usr/bin/env bash
|
||||
set -oue pipefail
|
||||
```
|
||||
|
||||
## Style directions for official modules
|
||||
|
||||
These are general directions for writing official modules and their documentation to follow to keep a consistent style. Not all of these are to be mindlessly followed, especially the ones about grammar and writing style. It's good to keep these in mind if you intend to contribute back upstream, though, so that your module doesn't feel out of place.
|
||||
|
||||
### Bash
|
||||
|
||||
- Start with `#!/usr/bin/env bash` and `set -oue pipefail`
|
||||
- Don't print "===", this is only for encapsulating the output of _different_ modules in `build.sh`
|
||||
- Print something on each step and on errors for easier debugging
|
||||
- Use CAPITALIZED names for variables that are read from the configuration
|
||||
|
||||
### README
|
||||
|
||||
- Title should be "`type` Module for Startingpoint", where the name/type of the module is a noun that shows the module's purpose
|
||||
- There should be a subtitle "Example configuration", under which there should be a loosely documented yaml block showcasing each of the module's configuration options
|
||||
- For a YAML block, specify the language as "yaml", not "yml" (MkDocs only supports "yaml")
|
||||
- At the start of each paragraph, refer to the module using its name or with "the module", not "it" or "the script"
|
||||
- Use passive grammar when talking about the user, ie. "should be used", "can be configured", preferring references to what the module does, ie. "This module downloads the answer to the question of life, the universe and everything..."
|
||||
|
|
@ -1,53 +0,0 @@
|
|||
# image will be published to registry.gitlab.com/<user>/<name>
|
||||
name: {{ name }}
|
||||
# description will be included in the image's metadata
|
||||
description: A starting point for further customization of uBlue images. Make your own! https://ublue.it/making-your-own/
|
||||
|
||||
# the base image to build on top of (FROM) and the version tag to use
|
||||
base-image: ghcr.io/ublue-os/silverblue-main
|
||||
image-version: 38 # latest is also supported if you want new updates ASAP
|
||||
|
||||
# module configuration, executed in order
|
||||
# you can include multiple instances of the same module
|
||||
modules:
|
||||
- type: files
|
||||
files:
|
||||
- usr: /usr # copy static configurations
|
||||
#
|
||||
# copies config/files/usr into your image's /usr
|
||||
#
|
||||
# configuration you wish to end up in /etc/ on the booted system
|
||||
# should be added into /usr/etc/ as that is the proper "distro"
|
||||
# config directory on ostree. Read more in the files module's README
|
||||
|
||||
- type: rpm-ostree
|
||||
repos:
|
||||
# - https://copr.fedorainfracloud.org/coprs/atim/starship/repo/fedora-%OS_VERSION%/atim-starship-fedora-%OS_VERSION%.repo
|
||||
install:
|
||||
# - micro
|
||||
# - starship
|
||||
remove:
|
||||
- firefox # default firefox removed in favor of flatpak
|
||||
- firefox-langpacks # langpacks needs to also be removed to prevent dependency problems
|
||||
|
||||
- type: bling # configure what to pull in from ublue-os/bling
|
||||
install:
|
||||
- justfiles # add "!include /usr/share/ublue-os/just/bling.just"
|
||||
# in your custom.just (added by default) or local justfile
|
||||
- nix-installer # shell shortcuts for determinate system's nix installers
|
||||
- ublue-os-wallpapers
|
||||
# - ublue-update # https://github.com/ublue-os/ublue-update
|
||||
# - dconf-update-service # a service unit that updates the dconf db on boot
|
||||
# - devpod # https://devpod.sh/ as an rpm
|
||||
|
||||
|
||||
- type: yafti # if included, yafti and it's dependencies (pip & libadwaita)
|
||||
# will be installed and set up
|
||||
custom-flatpaks: # this section is optional
|
||||
# - Celluloid: io.github.celluloid_player.Celluloid
|
||||
# - Krita: org.kde.krita
|
||||
|
||||
- type: script
|
||||
scripts:
|
||||
# this sets up the proper policy & signing files for signed images to work
|
||||
- signing.sh
|
||||
|
|
@ -1,143 +0,0 @@
|
|||
title: Welcome to uBlue
|
||||
properties:
|
||||
mode: "run-on-change"
|
||||
screens:
|
||||
first-screen:
|
||||
source: yafti.screen.title
|
||||
values:
|
||||
title: "Welcome to uBlue (Alpha)"
|
||||
icon: "/path/to/icon"
|
||||
description: |
|
||||
This guided installer will help you get started with your new system.
|
||||
can-we-modify-your-flatpaks:
|
||||
source: yafti.screen.consent
|
||||
values:
|
||||
title: Welcome, Traveler!
|
||||
condition:
|
||||
run: flatpak remotes --columns=name | grep fedora
|
||||
description: |
|
||||
We have detected the limited, Fedora-provided Flatpak remote on your system, whose applications are usually missing important codecs and other features. This step will therefore remove all basic Fedora Flatpaks from your system! We will instead switch all core Flatpak applications over to the vastly superior, unfiltered Flathub. If you don't want to do this, simply exit this installer.
|
||||
actions:
|
||||
- run: flatpak remote-delete --system --force fedora
|
||||
- run: flatpak remote-delete --user --force fedora
|
||||
- run: flatpak remove --system --noninteractive --all
|
||||
- run: flatpak remote-add --if-not-exists --system flathub https://flathub.org/repo/flathub.flatpakrepo
|
||||
- run: flatpak remote-add --if-not-exists --user flathub https://flathub.org/repo/flathub.flatpakrepo
|
||||
check-system-flathub:
|
||||
source: yafti.screen.consent
|
||||
values:
|
||||
title: Missing Flathub Repository (System)
|
||||
condition:
|
||||
run: flatpak remotes --system --columns=name | grep flathub | wc -l | grep '^0$'
|
||||
description: |
|
||||
We have detected that you don't have Flathub's repository on your system. We will now add that repository to your system-wide list.
|
||||
actions:
|
||||
- run: flatpak remote-add --if-not-exists --system flathub https://flathub.org/repo/flathub.flatpakrepo
|
||||
check-user-flathub:
|
||||
source: yafti.screen.consent
|
||||
values:
|
||||
title: Missing Flathub Repository (User)
|
||||
condition:
|
||||
run: flatpak remotes --user --columns=name | grep flathub | wc -l | grep '^0$'
|
||||
description: |
|
||||
We have detected that you don't have Flathub's repository on your current user account. We will now add that repository to your account.
|
||||
actions:
|
||||
- run: flatpak remote-add --if-not-exists --user flathub https://flathub.org/repo/flathub.flatpakrepo
|
||||
applications:
|
||||
source: yafti.screen.package
|
||||
values:
|
||||
title: Application Installer
|
||||
show_terminal: true
|
||||
package_manager: yafti.plugin.flatpak
|
||||
package_manager_defaults:
|
||||
user: false
|
||||
system: true
|
||||
groups:
|
||||
Core GNOME Apps:
|
||||
description: Core system applications for the GNOME desktop environment.
|
||||
default: true
|
||||
packages:
|
||||
- Calculator: org.gnome.Calculator
|
||||
- Calendar: org.gnome.Calendar
|
||||
- Camera: org.gnome.Snapshot
|
||||
- Characters: org.gnome.Characters
|
||||
- Clocks: org.gnome.clocks
|
||||
- Connections: org.gnome.Connections
|
||||
- Contacts: org.gnome.Contacts
|
||||
- Disk Usage Analyzer: org.gnome.baobab
|
||||
- Document Scanner: org.gnome.SimpleScan
|
||||
- Document Viewer: org.gnome.Evince
|
||||
- Extension Manager: com.mattjakeman.ExtensionManager
|
||||
- Font Viewer: org.gnome.font-viewer
|
||||
- Image Viewer: org.gnome.Loupe
|
||||
- Logs: org.gnome.Logs
|
||||
- Maps: org.gnome.Maps
|
||||
- Photos (Organizer): org.gnome.Photos
|
||||
- Sushi (Nautilus Previewer): org.gnome.NautilusPreviewer
|
||||
- Text Editor: org.gnome.TextEditor
|
||||
- Videos (Player): org.gnome.Totem
|
||||
- Weather: org.gnome.Weather
|
||||
System Apps:
|
||||
description: System applications for all desktop environments.
|
||||
default: true
|
||||
packages:
|
||||
- Deja Dup Backups: org.gnome.DejaDup
|
||||
- Fedora Media Writer: org.fedoraproject.MediaWriter
|
||||
- Flatseal (Permission Manager): com.github.tchx84.Flatseal
|
||||
- Font Downloader: org.gustavoperedo.FontDownloader
|
||||
- Mozilla Firefox: org.mozilla.firefox
|
||||
Web Browsers:
|
||||
description: Additional browsers to complement or replace Firefox.
|
||||
default: false
|
||||
packages:
|
||||
- Brave: com.brave.Browser
|
||||
- GNOME Web: org.gnome.Epiphany
|
||||
- Google Chrome: com.google.Chrome
|
||||
- Microsoft Edge: com.microsoft.Edge
|
||||
- Opera: com.opera.Opera
|
||||
Gaming:
|
||||
description: "Rock and Stone!"
|
||||
default: false
|
||||
packages:
|
||||
- Bottles: com.usebottles.bottles
|
||||
- Discord: com.discordapp.Discord
|
||||
- Heroic Games Launcher: com.heroicgameslauncher.hgl
|
||||
- Steam: com.valvesoftware.Steam
|
||||
- Gamescope (Utility): org.freedesktop.Platform.VulkanLayer.gamescope
|
||||
- MangoHUD (Utility): org.freedesktop.Platform.VulkanLayer.MangoHud//22.08
|
||||
- SteamTinkerLaunch (Utility): com.valvesoftware.Steam.Utility.steamtinkerlaunch
|
||||
- Proton Updater for Steam: net.davidotek.pupgui2
|
||||
Office:
|
||||
description: Boost your productivity.
|
||||
default: false
|
||||
packages:
|
||||
- LibreOffice: org.libreoffice.LibreOffice
|
||||
- OnlyOffice: org.onlyoffice.desktopeditors
|
||||
- Obsidian: md.obsidian.Obsidian
|
||||
- Slack: com.slack.Slack
|
||||
- Standard Notes: org.standardnotes.standardnotes
|
||||
- Thunderbird Email: org.mozilla.Thunderbird
|
||||
Streaming:
|
||||
description: Stream to the Internet.
|
||||
default: false
|
||||
packages:
|
||||
- OBS Studio: com.obsproject.Studio
|
||||
- VkCapture for OBS: com.obsproject.Studio.OBSVkCapture
|
||||
- Gstreamer for OBS: com.obsproject.Studio.Plugin.Gstreamer
|
||||
- Gstreamer VAAPI for OBS: com.obsproject.Studio.Plugin.GStreamerVaapi
|
||||
- Boatswain for Streamdeck: com.feaneron.Boatswain
|
||||
|
||||
final-screen:
|
||||
source: yafti.screen.title
|
||||
values:
|
||||
title: "All done!"
|
||||
icon: "/path/to/icon"
|
||||
links:
|
||||
- "Install More Applications":
|
||||
run: /usr/bin/gnome-software
|
||||
- "Website":
|
||||
run: /usr/bin/xdg-open https://ublue.it
|
||||
- "Join the Discord Community":
|
||||
run: /usr/bin/xdg-open https://discord.gg/XjG48C7VHx
|
||||
description: |
|
||||
Thanks for trying uBlue, we hope you enjoy it!
|
||||
7
templates/modules/akmods/akmods.j2
Normal file
7
templates/modules/akmods/akmods.j2
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
{%- for info in recipe.modules_ext.get_akmods_info_list(os_version) %}
|
||||
FROM scratch as stage-akmods-{{ info.stage_name }}
|
||||
COPY --from=ghcr.io/ublue-os/{{ info.images.0 }} /rpms /rpms
|
||||
{%- if let Some(nv_image) = info.images.1 %}
|
||||
COPY --from=ghcr.io/ublue-os/{{ nv_image }} /rpms /rpms
|
||||
{%- endif %}
|
||||
{%- endfor %}
|
||||
10
templates/modules/containerfile/containerfile.j2
Normal file
10
templates/modules/containerfile/containerfile.j2
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
{%- if let Some(containerfiles) = module.get_containerfile_list() %}
|
||||
{%- for c in containerfiles %}
|
||||
{{ self::print_containerfile(c) }}
|
||||
{%- endfor %}
|
||||
{%- endif %}
|
||||
{%- if let Some(snippets) = module.get_containerfile_snippets() %}
|
||||
{%- for s in snippets %}
|
||||
{{ s }}
|
||||
{%- endfor %}
|
||||
{%- endif %}
|
||||
5
templates/modules/files/files.j2
Normal file
5
templates/modules/files/files.j2
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
{%- if let Some(files) = module.get_files_list() %}
|
||||
{%- for (src, dest) in files %}
|
||||
COPY {{ src }} {{ dest }}
|
||||
{%- endfor %}
|
||||
{%- endif %}
|
||||
29
templates/modules/modules.j2
Normal file
29
templates/modules/modules.j2
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
{%- for module in recipe.modules_ext.modules %}
|
||||
{%- if let Some(type) = module.module_type %}
|
||||
{%- if type == "containerfile" %}
|
||||
{%- include "modules/containerfile/containerfile.j2" %}
|
||||
{%- else if type == "files" %}
|
||||
{%- include "modules/files/files.j2" %}
|
||||
{%- else %}
|
||||
RUN \
|
||||
--mount=type=tmpfs,target=/tmp \
|
||||
--mount=type=tmpfs,target=/var \
|
||||
--mount=type=bind,from=docker.io/mikefarah/yq,src=/usr/bin/yq,dst=/usr/bin/yq \
|
||||
--mount=type=bind,from=stage-config,src=/config,dst=/tmp/config,rw \
|
||||
{%- if let Some(source) = module.source %}
|
||||
--mount=type=bind,from={{ source }},src=/modules,dst=/tmp/modules,rw \
|
||||
{%- else %}
|
||||
--mount=type=bind,from=stage-modules,src=/modules,dst=/tmp/modules,rw \
|
||||
{%- endif %}
|
||||
{%- if type == "akmods" %}
|
||||
--mount=type=bind,from=stage-akmods-{{ module.generate_akmods_info(os_version).stage_name }},src=/rpms,dst=/tmp/rpms,rw \
|
||||
{%- endif %}
|
||||
--mount=type=bind,from=stage-exports,src=/exports.sh,dst=/tmp/exports.sh \
|
||||
--mount=type=cache,dst=/var/cache/rpm-ostree,id=rpm-ostree-cache-{{ recipe.name }}-{{ recipe.image_version }},sharing=locked \
|
||||
chmod +x /tmp/modules/{{ type }}/{{ type }}.sh \
|
||||
&& source /tmp/exports.sh && /tmp/modules/{{ type }}/{{ type }}.sh '{{ module.print_module_context() }}'
|
||||
{%- endif %}
|
||||
{%- endif %}
|
||||
{%- endfor %}
|
||||
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue