Skip to content

Commit

Permalink
Add cache module & refactor away client
Browse files Browse the repository at this point in the history
  • Loading branch information
tarkah committed Nov 28, 2023
1 parent 270ab66 commit 9890705
Show file tree
Hide file tree
Showing 11 changed files with 273 additions and 94 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions crates/boulder/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ edition.workspace = true
config = { path = "../config" }
container = { path = "../container" }
moss = { path = "../moss" }
stone_recipe = { path = "../stone_recipe" }
tui = { path = "../tui" }

clap.workspace = true
Expand Down
71 changes: 71 additions & 0 deletions crates/boulder/src/cache.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
// SPDX-FileCopyrightText: Copyright © 2020-2023 Serpent OS Developers
//
// SPDX-License-Identifier: MPL-2.0

use std::path::PathBuf;

use stone_recipe::Recipe;

struct Id(String);

impl Id {
fn new(recipe: &Recipe) -> Self {
Self(format!(
"{}-{}-{}",
recipe.source.name, recipe.source.version, recipe.source.release
))
}
}

pub struct Cache {
id: Id,
host_root: PathBuf,
guest_root: PathBuf,
}

impl Cache {
pub fn new(
recipe: &Recipe,
host_root: impl Into<PathBuf>,
guest_root: impl Into<PathBuf>,
) -> Self {
Self {
id: Id::new(recipe),
host_root: host_root.into(),
guest_root: guest_root.into(),
}
}

pub fn rootfs(&self) -> Mapping {
Mapping {
host: self.host_root.join("root").join(&self.id.0),
guest: "/".into(),
}
}

pub fn artefacts(&self) -> Mapping {
Mapping {
host: self.host_root.join("artefacts").join(&self.id.0),
guest: self.guest_root.join("artefacts"),
}
}

pub fn build(&self) -> Mapping {
Mapping {
host: self.host_root.join("build").join(&self.id.0),
guest: self.guest_root.join("build"),
}
}

pub fn ccache(&self) -> Mapping {
Mapping {
host: self.host_root.join("ccache"),
guest: self.guest_root.join("ccache"),
}
}
}

pub struct Mapping {
pub host: PathBuf,
pub guest: PathBuf,
}
66 changes: 51 additions & 15 deletions crates/boulder/src/cli/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@
//
// SPDX-License-Identifier: MPL-2.0

use std::process;
use std::path::PathBuf;
use std::{fs, process};
use std::{
fs::{create_dir_all, remove_dir_all},
io,
path::Path,
};

use boulder::{client, profile, Client};
use boulder::{env, profile, Cache, Env, Runtime};
use clap::Parser;
use thiserror::Error;

Expand All @@ -20,39 +21,66 @@ use super::Global;
pub struct Command {
#[arg(short, long)]
profile: profile::Id,
#[arg(
short,
long,
default_value = ".",
help = "Directory to store build results"
)]
output: PathBuf,
#[arg(default_value = "./stone.yml", help = "Path to recipe file")]
recipe: PathBuf,
}

pub fn handle(command: Command, global: Global) -> Result<(), Error> {
let Command { profile } = command;
let Command {
profile,
output,
recipe,
} = command;
let Global {
moss_root,
config_dir,
cache_dir,
} = global;

let client = Client::new(config_dir, cache_dir, moss_root)?;
if !output.exists() {
return Err(Error::MissingOutput(output));
}
if !recipe.exists() {
return Err(Error::MissingRecipe(recipe));
}

let recipe_bytes = fs::read(&recipe)?;
let recipe = stone_recipe::from_slice(&recipe_bytes)?;

let runtime = Runtime::new()?;
let env = Env::new(config_dir, cache_dir, moss_root)?;

let profiles = profile::Manager::new(&runtime, &env);
let repos = profiles.repositories(&profile)?.clone();

let ephemeral_root = client.cache_dir.join("test-root");
recreate_dir(&ephemeral_root)?;
let cache = Cache::new(&recipe, &env.cache_dir, "/mason");
let rootfs = cache.rootfs().host;

let repos = client.repositories(&profile)?.clone();
recreate_dir(&rootfs)?;

client.block_on(async {
let mut moss_client = moss::Client::new("boulder", &client.moss_dir)
runtime.block_on(async {
let mut moss_client = moss::Client::new("boulder", &env.moss_dir)
.await?
.explicit_repositories(repos)
.await?
.ephemeral(&ephemeral_root)?;
.ephemeral(&rootfs)?;

moss_client.install(BASE_PACKAGES, true).await?;

Ok(()) as Result<(), Error>
})?;

// Drop client = drop async runtime
drop(client);
// Drop async runtime
drop(runtime);

container::run(ephemeral_root, move || {
container::run(rootfs, move || {
let mut child = process::Command::new("/bin/bash")
.arg("--login")
.env_clear()
Expand Down Expand Up @@ -116,14 +144,22 @@ fn recreate_dir(path: &Path) -> Result<(), Error> {

#[derive(Debug, Error)]
pub enum Error {
#[error("output directory does not exist: {0:?}")]
MissingOutput(PathBuf),
#[error("recipe file does not exist: {0:?}")]
MissingRecipe(PathBuf),
#[error("container")]
Container(Box<dyn std::error::Error + Send + Sync + 'static>),
#[error("client")]
Client(#[from] client::Error),
#[error("env")]
Env(#[from] env::Error),
#[error("profile")]
Profile(#[from] profile::Error),
#[error("moss client")]
MossClient(#[from] moss::client::Error),
#[error("moss install")]
MossInstall(#[from] moss::client::install::Error),
#[error("stone recipe")]
StoneRecipe(#[from] stone_recipe::Error),
#[error("io")]
Io(#[from] io::Error),
}
41 changes: 31 additions & 10 deletions crates/boulder/src/cli/chroot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,45 @@
//
// SPDX-License-Identifier: MPL-2.0

use std::process;
use std::{fs, io, path::PathBuf, process};

use boulder::{client, Client};
use boulder::{env, Cache, Env};
use clap::Parser;
use thiserror::Error;

use super::Global;

#[derive(Debug, Parser)]
#[command(about = "Chroot into the build environment")]
pub struct Command {}
pub struct Command {
#[arg(default_value = "./stone.yml", help = "Path to recipe file")]
recipe: PathBuf,
}

pub fn handle(_command: Command, global: Global) -> Result<(), Error> {
pub fn handle(command: Command, global: Global) -> Result<(), Error> {
let Command { recipe } = command;
let Global {
config_dir,
cache_dir,
moss_root,
} = global;

let client = Client::new(config_dir, cache_dir, moss_root)?;
if !recipe.exists() {
return Err(Error::MissingRecipe(recipe));
}

let recipe_bytes = fs::read(&recipe)?;
let recipe = stone_recipe::from_slice(&recipe_bytes)?;

let ephemeral_root = client.cache_dir.join("test-root");
let env = Env::new(config_dir, cache_dir, moss_root)?;
let cache = Cache::new(&recipe, &env.cache_dir, "/mason");
let rootfs = cache.rootfs().host;

drop(client);
if !rootfs.exists() {
return Err(Error::MissingRootFs);
}

container::run(ephemeral_root, move || {
container::run(rootfs, move || {
let mut child = process::Command::new("/bin/bash")
.arg("--login")
.env_clear()
Expand All @@ -47,8 +60,16 @@ pub fn handle(_command: Command, global: Global) -> Result<(), Error> {

#[derive(Debug, Error)]
pub enum Error {
#[error("recipe file does not exist: {0:?}")]
MissingRecipe(PathBuf),
#[error("build root doesn't exist, make sure to run build first")]
MissingRootFs,
#[error("container")]
Container(Box<dyn std::error::Error + Send + Sync + 'static>),
#[error("client")]
Client(#[from] client::Error),
#[error("env")]
Env(#[from] env::Error),
#[error("stone recipe")]
StoneRecipe(#[from] stone_recipe::Error),
#[error("io")]
Io(#[from] io::Error),
}
49 changes: 31 additions & 18 deletions crates/boulder/src/cli/profile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
//
// SPDX-License-Identifier: MPL-2.0

use std::collections::HashMap;
use std::{collections::HashMap, io};

use boulder::{client, profile, Client, Profile};
use boulder::{env, profile, Env, Profile, Runtime};
use clap::Parser;
use itertools::Itertools;
use moss::{repository, Repository};
Expand Down Expand Up @@ -83,22 +83,24 @@ pub fn handle(command: Command, global: Global) -> Result<(), Error> {
moss_root,
} = global;

let client = Client::new(config_dir, cache_dir, moss_root)?;
let runtime = Runtime::new()?;
let env = Env::new(config_dir, cache_dir, moss_root)?;
let manager = profile::Manager::new(&runtime, &env);

match command.subcommand {
Subcommand::List => list(client),
Subcommand::Add { name, repos } => add(client, name, repos),
Subcommand::Update { profile } => update(client, &profile),
Subcommand::List => list(manager),
Subcommand::Add { name, repos } => add(&runtime, &env, manager, name, repos),
Subcommand::Update { profile } => update(&runtime, &env, manager, &profile),
}
}

pub fn list(client: Client) -> Result<(), Error> {
if client.profiles.is_empty() {
pub fn list(manager: profile::Manager) -> Result<(), Error> {
if manager.profiles.is_empty() {
println!("No profiles have been configured yet");
return Ok(());
}

for (id, profile) in client.profiles.iter() {
for (id, profile) in manager.profiles.iter() {
println!("{id}:");

for (id, repo) in profile
Expand All @@ -114,31 +116,38 @@ pub fn list(client: Client) -> Result<(), Error> {
}

pub fn add(
mut client: Client,
runtime: &Runtime,
env: &Env,
mut manager: profile::Manager,
name: String,
repos: Vec<(repository::Id, Repository)>,
) -> Result<(), Error> {
let id = profile::Id::new(name);

client.save_profile(
manager.save_profile(
id.clone(),
Profile {
collections: repository::Map::with(repos),
},
)?;

update(client, &id)?;
update(runtime, env, manager, &id)?;

println!("Profile \"{id}\" has been added");

Ok(())
}

pub fn update(client: Client, profile: &profile::Id) -> Result<(), Error> {
let repos = client.repositories(profile)?.clone();
pub fn update(
runtime: &Runtime,
env: &Env,
manager: profile::Manager,
profile: &profile::Id,
) -> Result<(), Error> {
let repos = manager.repositories(profile)?.clone();

client.block_on(async {
let mut moss_client = moss::Client::new("boulder", &client.moss_dir)
runtime.block_on(async {
let mut moss_client = moss::Client::new("boulder", &env.moss_dir)
.await?
.explicit_repositories(repos)
.await?;
Expand All @@ -151,10 +160,14 @@ pub fn update(client: Client, profile: &profile::Id) -> Result<(), Error> {
}
#[derive(Debug, Error)]
pub enum Error {
#[error("client")]
Client(#[from] client::Error),
#[error("env")]
Env(#[from] env::Error),
#[error("config")]
Config(#[from] config::SaveError),
#[error("profile")]
Profile(#[from] profile::Error),
#[error("moss client")]
MossClient(#[from] moss::client::Error),
#[error("io")]
Io(#[from] io::Error),
}
Loading

0 comments on commit 9890705

Please sign in to comment.