First commit.

This commit is contained in:
Eduard Tolosa 2019-04-20 16:14:23 -05:00
commit 3ebaf7e732
7 changed files with 649 additions and 0 deletions

53
src/cli.yml Normal file
View file

@ -0,0 +1,53 @@
name: blackarch-devtools
version: "0.1.0"
author: Eduard Tolosa <tolosaeduard@gmail.com>
about: Development tools for BlackArch Linux
args:
- setup:
short: s
long: setup
help: Setup the clean chroot environment.
takes_value: false
- update:
short: u
long: update
help: Update BlackArch Linux chroot environment.
takes_value: false
- build:
short: b
long: build
help: Build package from PKGBUILD in clean chroot environment.
takes_value: false
- test:
short: t
long: test
help: Install and test package in clean chroot environment.
takes_value: false
requires:
- package
- executable
- package:
short: p
long: package
help: Build package to install in the clean chroot environment.
takes_value: true
- executable:
short: e
long: executable
help: Name of the binary file provided by the package that you're installing in the chroot environment.
takes_value: true
- install-missing:
short: I
long: install-missing
help: Build package files that aren't available in repos. You can specify it multiple times.
multiple: true
takes_value: true
- clean:
short: c
long: clean
help: Clean chroot environment before building.
takes_value: false
- verbose:
short: v
multiple: true
help: Sets the level of verbosity

364
src/functions.rs Normal file
View file

@ -0,0 +1,364 @@
// Crate termcolor
use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor};
// Standard imports
use std::io::Write;
use std::path::Path;
use std::process;
use std::process::Command;
use std::{env, fs};
pub fn get_vars(get_var: &str) -> String {
let home_dir: String = env::var("HOME").expect("Failed to read HOME system variable.");
let chroot_dir: String = [&home_dir, "/blackarch_chroot"].concat();
let devtools_mkarchroot = String::from("/usr/bin/mkarchroot");
let devtools_nspawn = String::from("/usr/bin/arch-nspawn");
let blackarch_instance: String = String::from("blackarch");
let chroot_root: String = [&chroot_dir, "/root/"].concat();
let chroot_blackarch: String = [&chroot_dir, "/blackarch/"].concat();
let devtools_makechrootpkg: String = String::from("/usr/bin/makechrootpkg");
let pacman: String = String::from("/usr/bin/pacman");
if get_var == "home_dir" {
home_dir
} else if get_var == "chroot_dir" {
chroot_dir
} else if get_var == "mkarchroot" {
devtools_mkarchroot
} else if get_var == "nspawn" {
devtools_nspawn
} else if get_var == "chroot_root" {
chroot_root
} else if get_var == "chroot_blackarch" {
chroot_blackarch
} else if get_var == "blackarch_instance" {
blackarch_instance
} else if get_var == "makechrootpkg" {
devtools_makechrootpkg
} else if get_var == "pacman" {
pacman
} else {
String::from("Error returning the value.")
}
}
pub fn coloring(color: &str) -> termcolor::StandardStream {
let mut stdout = StandardStream::stdout(ColorChoice::Always);
if color == "green" {
stdout.set_color(ColorSpec::new().set_bold(true).set_fg(Some(Color::Green)));
stdout
} else if color == "yellow" {
stdout.set_color(ColorSpec::new().set_bold(true).set_fg(Some(Color::Yellow)));
stdout
} else if color == "red" {
stdout.set_color(ColorSpec::new().set_bold(true).set_fg(Some(Color::Red)));
stdout
} else {
stdout.set_color(ColorSpec::new().set_bold(true).set_fg(Some(Color::White)));
stdout
}
}
pub fn setup_chroot() {
let chroot_dir = get_vars("chroot_dir");
if Path::new(&chroot_dir).exists() {
if Path::new(&chroot_dir).is_dir() {
writeln!(coloring("red"), "The directory {} already exists in the system, remove it or try with a different path.", &chroot_dir);
process::exit(1);
} else if Path::new(&chroot_dir).is_file() {
writeln!(
coloring("red"),
"The file {} already exists in the system, remove it or try a different path.",
&chroot_dir
);
process::exit(1);
}
} else {
writeln!(
coloring("yellow"),
"Creating chroot directory with name: {}",
&chroot_dir
);
fs::create_dir(&chroot_dir)
.expect("An error as ocurred while creating the chroot directoy.");
writeln!(coloring("yellow"), "Setting up chroot environment...");
let devtools_mkarchroot = get_vars("mkarchroot");
let devtools_nspawn = get_vars("nspawn");
let chroot_root = get_vars("chroot_root");
if Path::new(&devtools_mkarchroot).exists() {
let up_chroot = Command::new(&devtools_mkarchroot)
.args(&[&chroot_root, "base", "base-devel"])
.status()
.expect("Failed to setup chroot environment.");
if up_chroot.success() {
writeln!(
coloring("yellow"),
"Configuring BlackArch Linux repo in the chroot environment..."
);
let get_strap = Command::new(&devtools_nspawn)
.args(&[&chroot_root, "curl", "-O", "https://blackarch.org/strap.sh"])
.status()
.expect("Failed to retrieve strap.sh from blackarch.org");
if get_strap.success() {
let strap_perms = Command::new(&devtools_nspawn)
.args(&[&chroot_root, "chmod", "+x", "strap.sh"])
.status()
.expect("Failed to change permisions for strap.sh");
if strap_perms.success() {
let strap_exec = Command::new(&devtools_nspawn)
.args(&[&chroot_root, "sh", "strap.sh"])
.status()
.expect("Failed to exec strap.sh");
if strap_exec.success() {
Command::new(&devtools_nspawn)
.args(&[&chroot_root, "rm", "strap.sh"])
.status()
.expect("Error deleting strap.sh from chroot environment.");
writeln!(coloring("green"), "Chroot environment setup complete!");
} else {
writeln!(
coloring("red"),
"Can't install strap.sh into {}!",
&chroot_root
);
}
}
}
}
} else {
writeln!(
coloring("red"),
"Executable file {} not found, install the devtools package from repos.",
&devtools_mkarchroot
);
}
}
}
pub fn update_chroot_packages() {
writeln!(coloring("green"), "Updating the chroot environment...");
let devtools_nspawn = get_vars("nspawn");
let chroot_root = get_vars("chroot_root");
let update_packages = Command::new(&devtools_nspawn)
.args(&[&chroot_root, "/bin/sh", "-c", "pacman --noconfirm -Syuu"])
.status()
.expect("Failed updating chroot environment");
if update_packages.success() {
writeln!(coloring("green"), "Chroot environment updated correctly!");
} else {
writeln!(
coloring("red"),
"An error as ocurred while updating the chroot environment."
);
}
}
pub fn build_package() {
update_chroot_packages();
let devtools_makechrootpkg = get_vars("makechrootpkg");
let chroot_dir = get_vars("chroot_dir");
let chroot_blackarch = get_vars("chroot_blackarch");
let build_package = Command::new(&devtools_makechrootpkg)
.args(&["-l", &chroot_blackarch, "-r", &chroot_dir])
.status()
.expect("Failed to build the package.");
if build_package.success() {
writeln!(coloring("green"), "Package built sucessfully!");
} else {
writeln!(coloring("red"), "Failed to build the package.");
}
}
pub fn build_package_with_missing_deps(missing: &[&str]) {
update_chroot_packages();
let chroot_blackarch = get_vars("chroot_blackarch");
let devtools_nspawn = get_vars("nspawn");
for missing in missing.iter() {
let copy_path: String = [&chroot_blackarch, "root/", &missing].concat();
println!("{}", &missing);
println!("{}", &copy_path);
Command::new("sudo")
.args(&["cp", &missing, &copy_path])
.spawn()
.expect("Failed to copy missing packages.");
}
writeln!(
coloring("yellow"),
"Installing missing packages: {:?}",
missing
);
let install_missing = Command::new(&devtools_nspawn)
.args(&[
&chroot_blackarch,
"/bin/sh",
"-c",
"pacman -U --noconfirm root/*",
])
.status()
.expect("Failed to install missing packages.");
if install_missing.success() {
build_package();
Command::new(&devtools_nspawn).args(&[&chroot_blackarch, "/bin/sh", "-c", "rm -rf root/*"]);
}
}
pub fn sync_chroot() {
let chroot_blackarch = get_vars("chroot_blackarch");
let chroot_root = get_vars("chroot_root");
let chroot_dir = get_vars("chroot_dir");
writeln!(
coloring("green"),
"Syncing chroot copy {} with {} ...",
&chroot_blackarch,
&chroot_root
);
if Path::new(&chroot_dir).exists() {
if Path::new(&chroot_blackarch).exists() {
let fs_type = Command::new("stat")
.args(&["-f", "-c", "%T", &chroot_blackarch])
.output()
.expect("Failed to read filesystem type");
let fs_id_hex = Command::new("stat")
.args(&["-c", "%i", &chroot_blackarch])
.output()
.expect("Failed to read filesystem ID");
if String::from_utf8_lossy(&fs_type.stdout) == "btrfs"
&& String::from_utf8_lossy(&fs_id_hex.stdout) == "256"
{
Command::new("sudo")
.args(&["btrfs", "subvolume", "delete", &chroot_blackarch])
.status()
.expect("Failed to delete chroot copy.");
Command::new("sudo")
.args(&[
"btrfs",
"subvolume",
"snapshot",
&chroot_root,
&chroot_blackarch,
])
.spawn()
.expect("Failed to create chroot copy.");
} else {
let delete_existing_chroot = Command::new("sudo")
.args(&[
"rm",
"--recursive",
"--force",
"--one-file-system",
&chroot_blackarch,
])
.status()
.expect("Failed to delete chroot copy.");
if delete_existing_chroot.success() {
let create_chroot_copy = Command::new("sudo")
.args(&["mkdir", &chroot_blackarch])
.status()
.expect("Failed to create working copy of chroot environment.");
if create_chroot_copy.success() {
let make_chroot_copy = Command::new("sudo")
.args(&[
"rsync",
"-a",
"--delete",
"-q",
"-W",
"-x",
&chroot_root,
&chroot_blackarch,
])
.status()
.expect("Failed to create copy of root chroot environment.");
if make_chroot_copy.success() {
writeln!(coloring("green"), "Chroot environment is ready!");
} else {
writeln!(
coloring("red"),
"Failed to create copy of root chroot environment."
);
}
} else {
writeln!(
coloring("red"),
"Error while trying to create the directory for the chroot copy."
);
}
} else {
writeln!(
coloring("red"),
"Failed while trying to delete the chroot copy."
);
}
}
} else {
let create_chroot_copy = Command::new("sudo")
.args(&["mkdir", &chroot_blackarch])
.status()
.expect("Failed to create working copy of chroot environment.");
if create_chroot_copy.success() {
let make_chroot_copy = Command::new("sudo")
.args(&[
"rsync",
"-a",
"--delete",
"-q",
"-W",
"-x",
&chroot_root,
&chroot_blackarch,
])
.status()
.expect("Failed to create chroot copy.");
if make_chroot_copy.success() {
writeln!(coloring("green"), "Chroot environment is ready!");
} else {
writeln!(
coloring("red"),
"Failed to create copy of root chroot environment."
);
}
}
}
} else {
writeln!(
coloring("red"),
"Chroot environment doesn't exists. Please use the -s option first."
);
}
}
pub fn test_package(package: &str, executable: &str) {
let pacman = get_vars("pacman");
let chroot_blackarch = get_vars("chroot_blackarch");
let install_package = Command::new("sudo")
.args(&[&pacman, "--root", &chroot_blackarch, "-U", &package])
.status()
.expect("Failed to install the package in the chroot environment.");
if install_package.success() {
writeln!(
coloring("green"),
"Package {} installed correctly! Testing it now...",
&package
);
let execute_package = Command::new("sudo")
.args(&["chroot", &chroot_blackarch, &executable])
.status()
.expect(
"Failed to execute the {} binary in the chroot environment, check the binary name.",
);
if execute_package.success() {
writeln!(
coloring("green"),
"Binary {} sucessfully executed!",
executable
);
} else {
writeln!(coloring("red"), "An error as ocurred while trying to execute the binary {}, are you sure that it's the binary name?", &executable);
}
} else {
writeln!(
coloring("red"),
"Package {} wasn't installed in the chroot environment, please check the package name.",
&package
);
}
}

54
src/main.rs Normal file
View file

@ -0,0 +1,54 @@
// Crate clap
#[macro_use]
extern crate clap;
use clap::App;
use clap::AppSettings;
// Functions module
mod functions;
fn main() {
let yaml = load_yaml!("cli.yml");
let matches = App::from_yaml(yaml)
.setting(AppSettings::ArgRequiredElseHelp)
.setting(AppSettings::StrictUtf8)
.get_matches();
if matches.is_present("setup") {
functions::setup_chroot();
} else if matches.is_present("build") {
if matches.is_present("clean") {
functions::sync_chroot();
functions::build_package();
} else {
functions::build_package();
}
} else if matches.is_present("update") {
functions::update_chroot_packages();
} else if matches.is_present("test") {
let package = matches
.value_of("package")
.expect("Failed to convert in a valid String")
.to_string();
let executable = matches
.value_of("executable")
.expect("Failed to convert in a valid String")
.to_string();
if matches.is_present("clean") {
functions::sync_chroot();
functions::test_package(&package, &executable);
} else {
functions::test_package(&package, &executable);
}
} else if matches.is_present("install-missing") {
if matches.is_present("clean") {
functions::sync_chroot();
let missing_deps: Vec<&str> = matches.values_of("install-missing").unwrap().collect();
functions::build_package_with_missing_deps(&missing_deps.as_slice());
} else {
let missing_deps: Vec<&str> = matches.values_of("install-missing").unwrap().collect();
functions::build_package_with_missing_deps(&missing_deps.as_slice());
}
} else if matches.is_present("clean") {
functions::sync_chroot();
}
}