Skip to content

Commit

Permalink
feat: pkg tool
Browse files Browse the repository at this point in the history
  • Loading branch information
raphaelcoeffic committed Dec 18, 2024
1 parent 2f019b5 commit 441e41a
Show file tree
Hide file tree
Showing 12 changed files with 696 additions and 65 deletions.
13 changes: 11 additions & 2 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,23 @@ jobs:
- name: Checkout
uses: actions/checkout@v4

- name: Build pkg tool
uses: houseabsolute/actions-rust-cross@v0
with:
target: ${{ matrix.platform.target }}
args: "--locked --release --bin pkg"
strip: true

- name: Build base image
env:
ARCH: ${{ matrix.platform.arch }}
TARGET: ${{ matrix.platform.target }}
run: |
if [ "$ARCH" != "$(uname -m)" ]; then
sudo apt-get update
sudo apt-get install qemu-user-static
fi
cargo run --bin build-img -- -a $ARCH
cargo run --bin build-img -- -a $ARCH -b target/$TARGET/release/pkg
cargo clean
- name: Upload artifacts - base image
Expand All @@ -46,8 +54,9 @@ jobs:
name: base-${{ matrix.platform.target }}
path: |
base.tar.xz
base.sha256
- name: Build binary
- name: Build dive
uses: houseabsolute/actions-rust-cross@v0
with:
target: ${{ matrix.platform.target }}
Expand Down
31 changes: 26 additions & 5 deletions Cargo.lock

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

9 changes: 8 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,21 @@ default-run = "dive"
embedded_image = []

[dependencies]
anstream = { version = "0.6.18", default-features = false, features = ["auto"] }
anyhow = "1.0.93"
base64 = "0.22.1"
clap = { version = "4.5.21", features = ["derive", "env"] }
dirs = "5.0"
env_logger = "0.11.5"
exitcode = "1.1.2"
fd-lock = "4.0.2"
indicatif = "0.17.9"
ioctl-sys = "0.8.0"
itertools = "0.13.0"
libc = "0.2.164"
liblzma = { version = "0.3.5", features = ["static"] }
log = "0.4.22"
owo-colors = "4.1.0"
procfs = { version= "0.17.0" }
regex = "1.11.1"
rustix = { version = "0.38.40", features = ["process", "thread", "mount", "fs", "runtime"] }
Expand All @@ -27,11 +31,14 @@ serde_json = "1.0"
sha2 = "0.10.8"
tar = "0.4.43"
tempfile = "3.14.0"
ureq = { version = "2.10.1", default-features = false, features = ["tls", "native-certs", "gzip"] }
ureq = { version = "2.10.1", default-features = false, features = ["tls", "native-certs", "gzip", "json"] }
which = "7.0.0"

[[bin]]
name = "dive"

[[bin]]
name = "build-img"

[[bin]]
name = "pkg"
78 changes: 78 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
#
# Helper Makefile to build base image
#
# - local build / debug:
# make base-image
#
# - release packaging:
# make base-image package=yes compress=yes build_profile=release
#
# - cross build:
# make base-image build_arch={aarch64 | x86_64}
#
# When building without packaging, dive can then be run with:
# dive -i nix/ [container name]
#

native_arch = $(shell uname -m)

# aarch64 | x86_64
build_arch ?= $(native_arch)

# debug | release
build_profile ?= debug

# yes | no
package ?= no

# yes | no
compress ?= no

cargo_target ?= $(build_arch)-unknown-linux-musl

ifeq ($(build_profile),debug)
cargo_profile = dev
else ifeq ($(build_profile),release)
cargo_profile = release
else
$(error unknown cargo build profile "$(build_profile)")
endif

pkg_bin = target/$(cargo_target)/$(build_profile)/pkg

build_img = cargo run --bin build-img --
build_img_args = -a $(build_arch) -b $(pkg_bin)

ifeq ($(package),no)
build_img_args += -p nix --unpackaged
else ifeq ($(compress),no)
build_img_args += --uncompressed
endif

cargo_build = cargo build --profile $(cargo_profile) --target $(cargo_target)

.PHONY: clean dist-clean base-image pkg-bin $(pkg_bin)

base_files = base.sha256 base.tar base.tar.xz

clean:
@echo "Removing base files"
@rm -f $(base_files)
@echo "Removing nix directory"
@chmod -R +w nix/* 2>/dev/null ; rm -rf ./nix

dist-clean: clean
@echo "Removing rust builds"
@rm -rf target

base-image: pkg-bin
@echo "Building base image"
$(build_img) $(build_img_args)

pkg-bin: $(pkg_bin)

$(pkg_bin):
@echo "Building pkg tool"
$(cargo_build) --bin pkg
@echo "Stripping debug info"
strip $@
16 changes: 14 additions & 2 deletions src/bin/build-img.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,22 @@ struct Args {
#[arg(short, long, env)]
persistent_base_dir: Option<PathBuf>,

/// Persistent base directory
/// Alternative flake directory
#[arg(short, long, env)]
flake_dir: Option<PathBuf>,

/// Add binary into base image
#[arg(short = 'b', long = "add-binary")]
binaries: Vec<PathBuf>,

/// Architecture
#[arg(short, long, env)]
arch: Option<String>,

/// No packaging
#[arg(long, env)]
unpackaged: bool,

/// Compress base image
#[arg(short, long, env)]
uncompressed: bool,
Expand Down Expand Up @@ -102,7 +110,11 @@ fn main() -> Result<()> {

let base_dir = BaseDir::new(args.persistent_base_dir)?;
let mut base_builder = BaseImageBuilder::new(base_dir.path());
base_builder.package(args.output, !args.uncompressed);
base_builder.binaries(args.binaries);

if !args.unpackaged {
base_builder.package(args.output, !args.uncompressed);
}

if let Some(flake_dir) = args.flake_dir {
base_builder.flake_dir(flake_dir);
Expand Down
98 changes: 98 additions & 0 deletions src/bin/pkg.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
use std::process;

use anstream::{eprintln, println};
use anyhow::{Context, Result};
use clap::{Parser, Subcommand};
use owo_colors::OwoColorize;

#[derive(Parser)]
#[command(version, about, long_about = None)]
struct Cli {
#[command(subcommand)]
command: Commands,
}

#[derive(Subcommand)]
enum Commands {
/// List installed packages
List,
/// Search packages
Search { name: String },
/// Install a package
Install { name: String },
/// Remove a package
Remove { name: String },
}

fn init_logging() {
env_logger::Builder::new()
.filter_level(log::LevelFilter::Info)
.parse_env("LOGLEVEL")
.format_timestamp(None)
.format_target(false)
.init();
}

fn main() -> Result<()> {
let cli = Cli::parse();
init_logging();

match &cli.command {
Commands::List => {
for pkg in dive::nixpkgs::all_packages_sorted()? {
println!("{} ({})", pkg.name.bold(), pkg.version.dimmed());
}
}
Commands::Search { name } => {
let matches = dive::nixpkgs::query([name])?;
for pkg in matches {
println!("* {} ({})", pkg.name.bold(), pkg.version.dimmed());
if let Some(description) = pkg.description {
println!(" {}", description);
}
println!();
}
}
Commands::Install { name } => {
let pkgs = dive::nixpkgs::all_packages_sorted()?;
if pkgs.iter().any(|p| &p.name == name) {
eprintln!("error: '{}' is already installed", name);
process::exit(1);
}
match dive::nixpkgs::find_package(name)? {
None => {
eprintln!("error: '{}' does not exist", name);
process::exit(1);
}
Some(pkg) => {
if let Err(err) = dive::nixpkgs::install_package(pkg)
.context("failed to install package")
{
eprintln!("error: {err}");
process::exit(1);
}
}
}
}
Commands::Remove { name } => {
let pkgs = dive::nixpkgs::all_packages_sorted()?;
let maybe_pkg = pkgs.iter().find(|p| &p.name == name);
if maybe_pkg.is_none() {
eprintln!("error: '{}' is not installed", name);
process::exit(1);
}
let pkg = maybe_pkg.unwrap();
if pkg.is_builtin() {
eprintln!(
"Error: '{}' is a built-in package and cannot be removed",
name
);
process::exit(1);
}
return dive::nixpkgs::remove_package(name)
.context("failed to remove package");
}
}

Ok(())
}
Loading

0 comments on commit 441e41a

Please sign in to comment.