Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/backend/target
15 changes: 14 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -63,4 +63,17 @@ jobs:
run: flutter analyze --no-fatal-infos

- name: formatting
run: dart format --set-exit-if-changed .
run: dart format --set-exit-if-changed .
e2eTest:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6

- name: Set up Docker
uses: docker/setup-docker-action@v5

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Run E2E test
run: ./scripts/test-e2e.sh hello
6 changes: 4 additions & 2 deletions .github/workflows/docker-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ on:
- master
tags:
- '*'
pull_request:
pull_request_target:
branches:
- master

Expand All @@ -32,6 +32,8 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v6
with:
ref: ${{ github.event.pull_request.head.sha || github.ref }}

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4
Expand All @@ -51,7 +53,7 @@ jobs:
- name: Determine image tag
id: vars
run: |
if [[ "${GITHUB_EVENT_NAME}" == "pull_request" ]]; then
if [[ "${GITHUB_EVENT_NAME}" == "pull_request_target" ]]; then
echo "tag=pr-${{ github.event.pull_request.number }}" >> $GITHUB_OUTPUT
elif [[ "${GITHUB_REF}" == "refs/heads/master" ]]; then
echo "tag=git" >> $GITHUB_OUTPUT
Expand Down
18 changes: 5 additions & 13 deletions backend/aurcache-builder/src/build.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::env::job_timeout_from_env;
use crate::env::{builder_image_from_env, job_timeout_from_env};
use crate::logger::BuildLogger;
use crate::path_utils::create_active_build_path;
use crate::types::BuildStates;
Expand All @@ -12,15 +12,13 @@ use bollard::query_parameters::{
use futures::StreamExt;
use sea_orm::{ActiveModelTrait, DatabaseConnection, IntoActiveModel, Set, TransactionTrait};
use std::collections::HashMap;
use std::fs;
use std::sync::Arc;
use std::time::{SystemTime, UNIX_EPOCH};
use std::{env, fs};
use tokio::sync::Mutex;
use tokio::time::timeout;
use tracing::{debug, info};

static BUILDER_IMAGE_DEFAULT: &str = "ghcr.io/lukas-heiligenbrunner/aurcache-builder:latest";

pub struct Builder {
pub(crate) db: DatabaseConnection,
pub(crate) job_containers: Arc<Mutex<HashMap<i32, String>>>,
Expand Down Expand Up @@ -63,13 +61,7 @@ impl Builder {
info!("Preparing build #{}", self.build_model.id.get()?);
let target_platform = self.prepare_build().await?;

let builder_image = match env::var("BUILDER_IMAGE") {
Ok(v) => {
info!("Using non-default Builder image: {v}");
v
}
Err(_) => BUILDER_IMAGE_DEFAULT.to_string(),
};
let builder_image = builder_image_from_env();

info!(
"Build #{}: Repull builder image",
Expand All @@ -84,7 +76,7 @@ impl Builder {
);

let pkgname = self.package_model.name.get()?;
let host_active_build_path = create_active_build_path(pkgname.clone())?;
let host_active_build_path = create_active_build_path(pkgname)?;

let create_info = self
.create_build_container(target_platform, builder_image.as_str())
Expand Down Expand Up @@ -139,7 +131,7 @@ impl Builder {
"Build {}: Remove shared build folder",
self.build_model.id.get()?
);
fs::remove_dir(host_active_build_path)?;
fs::remove_dir_all(host_active_build_path)?;
Ok(())
}

Expand Down
60 changes: 20 additions & 40 deletions backend/aurcache-builder/src/docker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,21 +138,23 @@ and check also if the 'DOCKER_HOST=unix:///var/run/user/1000/podman/podman.sock'

let build_flags = self.package_model.build_flags.get()?.split(';').join(" ");
// create new docker container for current build
let build_dir_base = "/var/cache/makepkg/pkg";
let host_build_path_docker = match get_build_mode() {
let host_build_dir = match get_build_mode() {
BuildMode::DinD(cfg) => cfg.build_path,
BuildMode::Host(cfg) => cfg.build_artifact_dir_host,
};
let mountpoints = vec![format!("{}:{}", host_build_path_docker, build_dir_base)];
let container_build_dir = "/build";
let mountpoints = vec![format!("{}/{name}:{container_build_dir}", host_build_dir)];

let mut mounts = vec![];

// todo allow for custom mirrorlists for other archs
if arch == "linux/x86_64" {
let archlinux_mirrorlist_path = "/etc/pacman.d";
// Mount only the mirrorlist file, not the entire directory
// This preserves other files in /etc/pacman.d (like gnupg keyring)
let archlinux_mirrorlist_path = "/etc/pacman.d/mirrorlist";
let mnt = match get_build_mode() {
BuildMode::DinD(cfg) => {
let mirrorlist_path = cfg.mirrorlist_path;
let mirrorlist_path = format!("{}/mirrorlist", cfg.mirrorlist_path);

Mount {
target: Some(archlinux_mirrorlist_path.to_string()),
Expand All @@ -163,7 +165,7 @@ and check also if the 'DOCKER_HOST=unix:///var/run/user/1000/podman/podman.sock'
}
}
BuildMode::Host(cfg) => {
let mirrorlist_path = cfg.mirrorlist_path_host;
let mirrorlist_path = format!("{}/mirrorlist", cfg.mirrorlist_path_host);
if mirrorlist_path.starts_with('/') {
Mount {
target: Some(archlinux_mirrorlist_path.to_string()),
Expand All @@ -183,7 +185,7 @@ and check also if the 'DOCKER_HOST=unix:///var/run/user/1000/podman/podman.sock'
typ: Some(MountTypeEnum::VOLUME),
read_only: Some(false),
volume_options: Some(MountVolumeOptions {
subpath: Some(subpath.to_string()),
subpath: Some(format!("{}/mirrorlist", subpath)),
..Default::default()
}),
..Default::default()
Expand All @@ -194,35 +196,20 @@ and check also if the 'DOCKER_HOST=unix:///var/run/user/1000/podman/podman.sock'
mounts.push(mnt);
}

let (makepkg_config, makepkg_config_path) =
create_makepkg_config(name.clone(), build_dir_base)?;
let (makepkg_config, makepkg_config_path) = create_makepkg_config(container_build_dir)?;

let self_update = "paru -Syu --noconfirm --noprogressbar --color never";
let source_data = SourceData::from_str(self.package_model.source_data.get()?)?;
let build_cmd = match source_data {
SourceData::Aur { .. } => {
let build_cmd = format!("paru {build_flags} {name}");
// first update the package list, then update trustdb and then build cmd
let steps = [
"sudo pacman -Sy --noconfirm",
"sudo pacman-key --init",
"sudo pacman-key --populate archlinux",
build_cmd.as_str(),
];
steps.join(" && ")
format!(
"cd {container_build_dir} && {self_update} && paru -G {name} && paru {build_flags} *"
)
}
SourceData::Git { .. } => {
// somehow we need also to `cd` into the repo dir, otherwise builds fail
let build_cmd = format!(
"sudo chmod -R 1777 {GIT_REPO_PATH} && cd {GIT_REPO_PATH} && paru {build_flags} {GIT_REPO_PATH}"
);
// first update the package list, then update trustdb and then build cmd
let steps = [
"sudo pacman -Sy --noconfirm",
"sudo pacman-key --init",
"sudo pacman-key --populate archlinux",
build_cmd.as_str(),
];
steps.join(" && ")
format!(
"chmod -R 1777 {GIT_REPO_PATH} && {self_update} && cd {GIT_REPO_PATH} && paru {build_flags} *"
)
}
SourceData::Upload { .. } => {
todo!("unpack zip and store it in build container dir")
Expand All @@ -239,23 +226,16 @@ and check also if the 'DOCKER_HOST=unix:///var/run/user/1000/podman/podman.sock'

let build_id = self.build_model.id.get()?;
let container_name = format!("aurcache_build_{filtered_name}_{build_id}");
let auto_remove = cfg!(not(debug_assertions));
let conf = ContainerCreateBody {
image: Some(image_name.to_string()),
attach_stdout: Some(true),
attach_stderr: Some(true),
open_stdin: Some(false),
user: Some("ab".to_string()),
cmd: Some(vec![
"sh".to_string(),
"-l".to_string(),
"-c".to_string(),
cmd,
]),
cmd: Some(vec!["sh".to_string(), "-lec".to_string(), cmd]),
host_config: Some(HostConfig {
#[cfg(debug_assertions)]
auto_remove: Some(false),
#[cfg(not(debug_assertions))]
auto_remove: Some(true),
auto_remove: Some(auto_remove),
Comment thread
Lukas-Heiligenbrunner marked this conversation as resolved.
nano_cpus: Some(cpu_limit as i64),
memory_swap: Some(memory_limit),
binds: Some(mountpoints),
Expand Down
10 changes: 8 additions & 2 deletions backend/aurcache-builder/src/env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ use std::env;
use std::time::Duration;
use tracing::debug;

static DEFAULT_BUILDER_IMAGE: &str = "ghcr.io/lukas-heiligenbrunner/aurcache-builder:latest";

pub fn job_timeout_from_env() -> Duration {
let job_timeout = env::var("JOB_TIMEOUT")
.ok()
Expand All @@ -12,17 +14,21 @@ pub fn job_timeout_from_env() -> Duration {
}

pub fn limits_from_env() -> (u64, i64) {
// cpu_limit in milli cpus
let cpu_limit = env::var("CPU_LIMIT")
.ok()
.and_then(|x| x.parse::<u64>().ok())
.map_or(0, |x| x * 1_000_000);
debug!("cpu_limit: {cpu_limit} mCPUs");
// memory_limit in megabytes
let memory_limit = env::var("MEMORY_LIMIT")
.ok()
.and_then(|x| x.parse::<i64>().ok())
.map_or(-1, |x| x * 1024 * 1024);
debug!("memory_limit: {memory_limit}MB");
(cpu_limit, memory_limit)
}

pub fn builder_image_from_env() -> String {
env::var("BUILDER_IMAGE")
.ok()
.unwrap_or_else(|| DEFAULT_BUILDER_IMAGE.to_string())
}
10 changes: 4 additions & 6 deletions backend/aurcache-builder/src/makepkg_utils.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
pub fn create_makepkg_config(
name: String,
build_dir_base: &str,
) -> anyhow::Result<(String, String)> {
pub fn create_makepkg_config(build_dir_base: &str) -> anyhow::Result<(String, String)> {
let makepkg_config = format!(
"\
"
MAKEFLAGS=-j$(nproc)
PKGDEST={build_dir_base}/{name}"
PKGDEST={build_dir_base}
"
);
let makepkg_config_path = "/var/ab/.config/pacman/makepkg.conf";
Ok((makepkg_config, makepkg_config_path.to_string()))
Expand Down
3 changes: 3 additions & 0 deletions backend/aurcache-builder/src/move_location.rs
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,9 @@ fn build_output_map(

for a in archives {
let a = a?;
if a.file_type()?.is_dir() {
continue;
}
let name = a.file_name();
let name = name.to_str().ok_or_else(|| anyhow!("Invalid filename"))?;

Expand Down
23 changes: 5 additions & 18 deletions backend/aurcache-builder/src/path_utils.rs
Original file line number Diff line number Diff line change
@@ -1,26 +1,13 @@
use crate::build_mode::{BuildMode, get_build_mode};
use std::env;
use std::fs;
use std::fs::Permissions;
use std::os::unix::fs::PermissionsExt;
use std::path::PathBuf;

/// create the build directory of the package to newly build (as path view of aurcache)
pub fn create_active_build_path(pkg_name: String) -> anyhow::Result<PathBuf> {
let path = match get_build_mode() {
BuildMode::DinD(v) => {
let mut build_path = PathBuf::from(v.build_path);
build_path.push(pkg_name);
build_path
}
BuildMode::Host(v) => {
let mut build_path = PathBuf::from(v.build_artifact_dir_aurcache);
build_path.push(pkg_name);
build_path
}
};

fs::create_dir_all(path.clone())?;
fs::set_permissions(path.clone(), Permissions::from_mode(0o777))?;
pub fn create_active_build_path(pkg_name: &str) -> anyhow::Result<PathBuf> {
let path = env::current_dir()?.join("builds").join(pkg_name);
fs::create_dir_all(&path)?;
fs::set_permissions(&path, Permissions::from_mode(0o777))?;

Ok(path)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
use crate::helpers::dbtype::database_type;
use sea_orm::DbBackend;
use sea_orm_migration::prelude::*;

#[derive(DeriveMigrationName)]
pub struct Migration;

#[async_trait::async_trait]
impl MigrationTrait for Migration {
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
let db = manager.get_connection();

match database_type() {
DbBackend::Sqlite => {
db.execute_unprepared(
r"
UPDATE packages
SET build_flags = REPLACE(build_flags, '-S', '-B')
WHERE build_flags LIKE '%-S%';
",
)
.await?;
}
DbBackend::Postgres => {
db.execute_unprepared(
r"
UPDATE public.packages
SET build_flags = REGEXP_REPLACE(build_flags, '-S', '-B', 'g')
WHERE build_flags ~ '-S';
",
)
.await?;
}
_ => Err(DbErr::Migration("Unsupported database type".to_string()))?,
}

Ok(())
}

async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
let db = manager.get_connection();

match database_type() {
DbBackend::Sqlite => {
db.execute_unprepared(
r"
UPDATE packages
SET build_flags = REPLACE(build_flags, '-B', '-S')
WHERE build_flags LIKE '%-B%';
",
)
.await?;
}
DbBackend::Postgres => {
db.execute_unprepared(
r"
UPDATE public.packages
SET build_flags = REGEXP_REPLACE(build_flags, '-B', '-S', 'g')
WHERE build_flags ~ '-B';
",
)
.await?;
}
_ => Err(DbErr::Migration("Unsupported database type".to_string()))?,
}

Ok(())
}
}
2 changes: 2 additions & 0 deletions backend/aurcache-db/src/migration/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ mod m20240907_131839_platform_buildflags;
mod m20250213_223900_activity_log;
mod m20251015_230000_pkg_sources;
mod m20251106_100000_build_version;
mod m20251107_000000_build_flags_no_install;

pub struct Migrator;

Expand All @@ -17,6 +18,7 @@ impl MigratorTrait for Migrator {
Box::new(m20250213_223900_activity_log::Migration),
Box::new(m20251106_100000_build_version::Migration),
Box::new(m20251015_230000_pkg_sources::Migration),
Box::new(m20251107_000000_build_flags_no_install::Migration),
]
}
}
Loading
Loading