exp: cross
This commit is contained in:
@@ -1,16 +1,18 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::cell::{Ref, RefCell};
|
||||
use std::ffi::OsStr;
|
||||
use std::io;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use super::local::LocalDriver;
|
||||
use super::ssh::SshDriver;
|
||||
use super::schroot::SchrootDriver;
|
||||
pub trait ContextDriver {
|
||||
fn ensure_available(&self, src: &Path, dest_root: &str) -> io::Result<PathBuf>;
|
||||
fn retrieve_path(&self, src: &Path, dest: &Path) -> io::Result<()>;
|
||||
fn list_files(&self, path: &Path) -> io::Result<Vec<PathBuf>>;
|
||||
fn run(&self, program: &str, args: &[String]) -> io::Result<std::process::ExitStatus>;
|
||||
fn run_output(&self, program: &str, args: &[String]) -> io::Result<std::process::Output>;
|
||||
fn run(&self, program: &str, args: &[String], env: &[(String, String)]) -> io::Result<std::process::ExitStatus>;
|
||||
fn run_output(&self, program: &str, args: &[String], env: &[(String, String)]) -> io::Result<std::process::Output>;
|
||||
fn prepare_work_dir(&self) -> io::Result<String>;
|
||||
}
|
||||
|
||||
@@ -20,7 +22,7 @@ pub trait ContextDriver {
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(tag = "type")]
|
||||
#[derive(Default)]
|
||||
pub enum Context {
|
||||
pub enum ContextConfig {
|
||||
#[serde(rename = "local")]
|
||||
#[default]
|
||||
Local,
|
||||
@@ -30,14 +32,31 @@ pub enum Context {
|
||||
user: Option<String>,
|
||||
port: Option<u16>,
|
||||
},
|
||||
#[serde(rename = "schroot")]
|
||||
Schroot {
|
||||
name: String,
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Context {
|
||||
config: ContextConfig,
|
||||
driver: RefCell<Option<Box<dyn ContextDriver>>>,
|
||||
}
|
||||
|
||||
impl Context {
|
||||
pub fn command<S: AsRef<OsStr>>(&self, program: S) -> ContextCommand {
|
||||
pub fn new(config: ContextConfig) -> Self {
|
||||
Self {
|
||||
config,
|
||||
driver: RefCell::new(None),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn command<S: AsRef<OsStr>>(&self, program: S) -> ContextCommand<'_> {
|
||||
ContextCommand {
|
||||
driver: self.driver(),
|
||||
context: self,
|
||||
program: program.as_ref().to_string_lossy().to_string(),
|
||||
args: Vec::new(),
|
||||
env: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,15 +85,23 @@ impl Context {
|
||||
self.driver().list_files(path)
|
||||
}
|
||||
|
||||
fn driver(&self) -> Box<dyn ContextDriver> {
|
||||
match self {
|
||||
Context::Local => Box::new(LocalDriver),
|
||||
Context::Ssh { host, user, port } => Box::new(SshDriver {
|
||||
host: host.clone(),
|
||||
user: user.clone(),
|
||||
port: *port,
|
||||
}),
|
||||
fn driver(&self) -> Ref<Box<dyn ContextDriver>> {
|
||||
if self.driver.borrow().is_none() {
|
||||
let driver: Box<dyn ContextDriver> = match &self.config {
|
||||
ContextConfig::Local => Box::new(LocalDriver),
|
||||
ContextConfig::Ssh { host, user, port } => Box::new(SshDriver {
|
||||
host: host.clone(),
|
||||
user: user.clone(),
|
||||
port: *port,
|
||||
}),
|
||||
ContextConfig::Schroot { name } => Box::new(SchrootDriver {
|
||||
name: name.clone(),
|
||||
session: RefCell::new(None),
|
||||
}),
|
||||
};
|
||||
*self.driver.borrow_mut() = Some(driver);
|
||||
}
|
||||
Ref::map(self.driver.borrow(), |opt| opt.as_ref().unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,13 +112,14 @@ impl Context {
|
||||
/// and call `status()` or `output()`.
|
||||
///
|
||||
/// It delegates the actual work to a `ContextDriver`.
|
||||
pub struct ContextCommand {
|
||||
driver: Box<dyn ContextDriver>,
|
||||
pub struct ContextCommand<'a> {
|
||||
context: &'a Context,
|
||||
program: String,
|
||||
args: Vec<String>,
|
||||
env: Vec<(String, String)>,
|
||||
}
|
||||
|
||||
impl ContextCommand {
|
||||
impl<'a> ContextCommand<'a> {
|
||||
pub fn arg<S: AsRef<OsStr>>(&mut self, arg: S) -> &mut Self {
|
||||
self.args.push(arg.as_ref().to_string_lossy().to_string());
|
||||
self
|
||||
@@ -109,12 +137,36 @@ impl ContextCommand {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn env<K, V>(&mut self, key: K, val: V) -> &mut Self
|
||||
where
|
||||
K: AsRef<OsStr>,
|
||||
V: AsRef<OsStr>,
|
||||
{
|
||||
self.env.push((
|
||||
key.as_ref().to_string_lossy().to_string(),
|
||||
val.as_ref().to_string_lossy().to_string(),
|
||||
));
|
||||
self
|
||||
}
|
||||
|
||||
pub fn envs<I, K, V>(&mut self, vars: I) -> &mut Self
|
||||
where
|
||||
I: IntoIterator<Item = (K, V)>,
|
||||
K: AsRef<OsStr>,
|
||||
V: AsRef<OsStr>,
|
||||
{
|
||||
for (key, val) in vars {
|
||||
self.env(key, val);
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
pub fn status(&mut self) -> io::Result<std::process::ExitStatus> {
|
||||
self.driver.run(&self.program, &self.args)
|
||||
self.context.driver().run(&self.program, &self.args, &self.env)
|
||||
}
|
||||
|
||||
// Capture output
|
||||
pub fn output(&mut self) -> io::Result<std::process::Output> {
|
||||
self.driver.run_output(&self.program, &self.args)
|
||||
self.context.driver().run_output(&self.program, &self.args, &self.env)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,11 +30,11 @@ impl ContextDriver for LocalDriver {
|
||||
Ok(entries)
|
||||
}
|
||||
|
||||
fn run(&self, program: &str, args: &[String]) -> io::Result<std::process::ExitStatus> {
|
||||
Command::new(program).args(args).status()
|
||||
fn run(&self, program: &str, args: &[String], env: &[(String, String)]) -> io::Result<std::process::ExitStatus> {
|
||||
Command::new(program).args(args).envs(env.iter().map(|(k, v)| (k, v))).status()
|
||||
}
|
||||
|
||||
fn run_output(&self, program: &str, args: &[String]) -> io::Result<std::process::Output> {
|
||||
Command::new(program).args(args).output()
|
||||
fn run_output(&self, program: &str, args: &[String], env: &[(String, String)]) -> io::Result<std::process::Output> {
|
||||
Command::new(program).args(args).envs(env.iter().map(|(k, v)| (k, v))).output()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,12 +5,12 @@ use std::fs;
|
||||
use std::io;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use super::api::Context;
|
||||
use super::api::{Context, ContextConfig};
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Default, Clone)]
|
||||
pub struct Config {
|
||||
pub current_context: Option<String>,
|
||||
pub contexts: HashMap<String, Context>,
|
||||
pub contexts: HashMap<String, ContextConfig>,
|
||||
}
|
||||
|
||||
pub struct ContextManager {
|
||||
@@ -36,7 +36,7 @@ impl ContextManager {
|
||||
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?
|
||||
} else {
|
||||
let mut cfg = Config::default();
|
||||
cfg.contexts.insert("local".to_string(), Context::Local);
|
||||
cfg.contexts.insert("local".to_string(), ContextConfig::Local);
|
||||
cfg.current_context = Some("local".to_string());
|
||||
cfg
|
||||
};
|
||||
@@ -65,12 +65,12 @@ impl ContextManager {
|
||||
self.config.contexts.keys().cloned().collect()
|
||||
}
|
||||
|
||||
pub fn get_context(&self, name: &str) -> Option<&Context> {
|
||||
self.config.contexts.get(name)
|
||||
pub fn get_context(&self, name: &str) -> Option<Context> {
|
||||
self.config.contexts.get(name).map(|cfg| Context::new(cfg.clone()))
|
||||
}
|
||||
|
||||
pub fn add_context(&mut self, name: &str, context: Context) -> io::Result<()> {
|
||||
self.config.contexts.insert(name.to_string(), context);
|
||||
pub fn add_context(&mut self, name: &str, config: ContextConfig) -> io::Result<()> {
|
||||
self.config.contexts.insert(name.to_string(), config);
|
||||
self.save()
|
||||
}
|
||||
|
||||
@@ -81,7 +81,7 @@ impl ContextManager {
|
||||
if !self.config.contexts.contains_key("local") {
|
||||
self.config
|
||||
.contexts
|
||||
.insert("local".to_string(), Context::Local);
|
||||
.insert("local".to_string(), ContextConfig::Local);
|
||||
}
|
||||
}
|
||||
self.save()?;
|
||||
@@ -107,8 +107,8 @@ impl ContextManager {
|
||||
.current_context
|
||||
.as_deref()
|
||||
.and_then(|name| self.config.contexts.get(name))
|
||||
.cloned()
|
||||
.unwrap_or(Context::Local)
|
||||
.map(|cfg| Context::new(cfg.clone()))
|
||||
.unwrap_or_else(|| Context::new(ContextConfig::Local))
|
||||
}
|
||||
|
||||
pub fn current_name(&self) -> Option<String> {
|
||||
|
||||
@@ -2,14 +2,15 @@ mod api;
|
||||
mod local;
|
||||
mod manager;
|
||||
mod ssh;
|
||||
mod schroot;
|
||||
|
||||
pub use api::{Context, ContextCommand};
|
||||
pub use api::{Context, ContextCommand, ContextConfig};
|
||||
pub use manager::ContextManager;
|
||||
|
||||
pub fn current_context() -> Context {
|
||||
match ContextManager::new() {
|
||||
Ok(mgr) => mgr.current(),
|
||||
Err(_) => Context::Local,
|
||||
Err(_) => Context::new(ContextConfig::Local),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +26,7 @@ mod tests {
|
||||
let src_file = temp_dir.path().join("src.txt");
|
||||
fs::write(&src_file, "local").unwrap();
|
||||
|
||||
let ctx = Context::Local;
|
||||
let ctx = Context::new(ContextConfig::Local);
|
||||
let dest = ctx.ensure_available(&src_file, "/tmp").unwrap();
|
||||
|
||||
// Should return canonical path
|
||||
@@ -40,15 +41,14 @@ mod tests {
|
||||
let mut mgr = ContextManager::with_path(path.clone());
|
||||
|
||||
// Add
|
||||
let ssh_ctx = Context::Ssh {
|
||||
let ssh_cfg = ContextConfig::Ssh {
|
||||
host: "10.0.0.1".into(),
|
||||
user: Some("admin".into()),
|
||||
port: Some(2222),
|
||||
};
|
||||
mgr.add_context("myserver", ssh_ctx.clone()).unwrap();
|
||||
mgr.add_context("myserver", ssh_cfg.clone()).unwrap();
|
||||
|
||||
assert!(mgr.get_context("myserver").is_some());
|
||||
assert_eq!(mgr.get_context("myserver").unwrap(), &ssh_ctx);
|
||||
|
||||
// List
|
||||
let list = mgr.list_contexts();
|
||||
@@ -56,13 +56,11 @@ mod tests {
|
||||
|
||||
// Set Current
|
||||
mgr.set_current("myserver").unwrap();
|
||||
assert_eq!(mgr.current(), ssh_ctx);
|
||||
assert_eq!(mgr.current_name(), Some("myserver".to_string()));
|
||||
|
||||
// Remove
|
||||
mgr.remove_context("myserver").unwrap();
|
||||
assert!(mgr.get_context("myserver").is_none());
|
||||
assert_eq!(mgr.current(), Context::Local);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -72,7 +70,7 @@ mod tests {
|
||||
|
||||
{
|
||||
let mut mgr = ContextManager::with_path(config_path.clone());
|
||||
mgr.add_context("persistent", Context::Local).unwrap();
|
||||
mgr.add_context("persistent", ContextConfig::Local).unwrap();
|
||||
mgr.set_current("persistent").unwrap();
|
||||
}
|
||||
|
||||
|
||||
111
src/context/schroot.rs
Normal file
111
src/context/schroot.rs
Normal file
@@ -0,0 +1,111 @@
|
||||
use super::api::ContextDriver;
|
||||
use std::cell::RefCell;
|
||||
use std::io;
|
||||
use std::path::{Path, PathBuf};
|
||||
use log::debug;
|
||||
|
||||
pub struct SchrootDriver {
|
||||
pub name: String,
|
||||
pub session: RefCell<Option<String>>,
|
||||
}
|
||||
|
||||
impl ContextDriver for SchrootDriver {
|
||||
fn ensure_available(&self, _src: &Path, _dest_root: &str) -> io::Result<PathBuf> {
|
||||
// TODO: Implement schroot file transfer logic
|
||||
Err(io::Error::new(
|
||||
io::ErrorKind::Unsupported,
|
||||
"ensure_available not yet implemented for schroot",
|
||||
))
|
||||
}
|
||||
|
||||
fn retrieve_path(&self, _src: &Path, _dest: &Path) -> io::Result<()> {
|
||||
// TODO: Implement schroot file retrieval logic
|
||||
Err(io::Error::new(
|
||||
io::ErrorKind::Unsupported,
|
||||
"retrieve_path not yet implemented for schroot",
|
||||
))
|
||||
}
|
||||
|
||||
fn list_files(&self, _path: &Path) -> io::Result<Vec<PathBuf>> {
|
||||
// TODO: Implement schroot file listing logic
|
||||
Err(io::Error::new(
|
||||
io::ErrorKind::Unsupported,
|
||||
"list_files not yet implemented for schroot",
|
||||
))
|
||||
}
|
||||
|
||||
fn run(&self, program: &str, args: &[String], env: &[(String, String)]) -> io::Result<std::process::ExitStatus> {
|
||||
// Initialize session on first run
|
||||
if self.session.borrow().is_none() {
|
||||
let session_output = std::process::Command::new("schroot")
|
||||
.arg("-b")
|
||||
.arg("-c")
|
||||
.arg(&self.name)
|
||||
.output()?;
|
||||
|
||||
if !session_output.status.success() {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
format!("Failed to create schroot session: {}",
|
||||
String::from_utf8_lossy(&session_output.stderr))
|
||||
));
|
||||
}
|
||||
|
||||
let session_id = String::from_utf8(session_output.stdout)
|
||||
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?
|
||||
.trim()
|
||||
.to_string();
|
||||
|
||||
*self.session.borrow_mut() = Some(session_id);
|
||||
}
|
||||
|
||||
let session_id = self.session.borrow();
|
||||
let session_id = session_id.as_ref().unwrap();
|
||||
|
||||
let mut cmd = std::process::Command::new("sudo");
|
||||
cmd
|
||||
.args(env.iter().map(|(k, v)| format!("{k}={v}")))
|
||||
.arg("schroot")
|
||||
.arg("-p") // Preserve environment
|
||||
.arg("-r")
|
||||
.arg("-c")
|
||||
.arg(session_id)
|
||||
.arg("--")
|
||||
.arg(program)
|
||||
.args(args);
|
||||
|
||||
debug!("Executing: {:?}", cmd);
|
||||
|
||||
cmd.status()
|
||||
}
|
||||
|
||||
fn run_output(&self, program: &str, args: &[String], env: &[(String, String)]) -> io::Result<std::process::Output> {
|
||||
let mut cmd = std::process::Command::new("sudo");
|
||||
cmd
|
||||
.arg("schroot")
|
||||
.arg("-r")
|
||||
.arg("-c")
|
||||
.arg(&self.name)
|
||||
.arg("--");
|
||||
|
||||
// Handle env variables for schroot by wrapping in env command
|
||||
if !env.is_empty() {
|
||||
cmd.arg("env");
|
||||
for (k, v) in env {
|
||||
cmd.arg(format!("{}={}", k, v));
|
||||
}
|
||||
}
|
||||
|
||||
cmd.arg(program).args(args);
|
||||
|
||||
cmd.output()
|
||||
}
|
||||
|
||||
fn prepare_work_dir(&self) -> io::Result<String> {
|
||||
// TODO: Implement schroot work dir creation
|
||||
Err(io::Error::new(
|
||||
io::ErrorKind::Unsupported,
|
||||
"prepare_work_dir not yet implemented for schroot",
|
||||
))
|
||||
}
|
||||
}
|
||||
@@ -90,12 +90,17 @@ impl ContextDriver for SshDriver {
|
||||
Ok(files)
|
||||
}
|
||||
|
||||
fn run(&self, program: &str, args: &[String]) -> io::Result<std::process::ExitStatus> {
|
||||
fn run(&self, program: &str, args: &[String], env: &[(String, String)]) -> io::Result<std::process::ExitStatus> {
|
||||
let sess = connect_ssh(&self.host, self.user.as_deref(), self.port)?;
|
||||
let mut channel = sess.channel_session().map_err(io::Error::other)?;
|
||||
|
||||
// Construct command line
|
||||
let mut cmd_line = program.to_string();
|
||||
// Construct command line with env vars
|
||||
// TODO: No, use ssh2 channel.set_env
|
||||
let mut cmd_line = String::new();
|
||||
for (key, value) in env {
|
||||
cmd_line.push_str(&format!("export {}='{}'; ", key, value.replace("'", "'\\''")));
|
||||
}
|
||||
cmd_line.push_str(program);
|
||||
for arg in args {
|
||||
cmd_line.push(' ');
|
||||
cmd_line.push_str(arg); // TODO: escape
|
||||
@@ -119,12 +124,16 @@ impl ContextDriver for SshDriver {
|
||||
Ok(ExitStatus::from_raw(code))
|
||||
}
|
||||
|
||||
fn run_output(&self, program: &str, args: &[String]) -> io::Result<std::process::Output> {
|
||||
fn run_output(&self, program: &str, args: &[String], env: &[(String, String)]) -> io::Result<std::process::Output> {
|
||||
let sess = connect_ssh(&self.host, self.user.as_deref(), self.port)?;
|
||||
let mut channel = sess.channel_session().map_err(io::Error::other)?;
|
||||
|
||||
// Construct command line
|
||||
let mut cmd_line = program.to_string();
|
||||
// Construct command line with env vars
|
||||
let mut cmd_line = String::new();
|
||||
for (key, value) in env {
|
||||
cmd_line.push_str(&format!("export {}='{}'; ", key, value.replace("'", "'\\''")));
|
||||
}
|
||||
cmd_line.push_str(program);
|
||||
for arg in args {
|
||||
cmd_line.push(' ');
|
||||
cmd_line.push_str(arg); // TODO: escape
|
||||
|
||||
107
src/deb.rs
107
src/deb.rs
@@ -1,11 +1,14 @@
|
||||
use crate::context::{Context, current_context};
|
||||
use crate::context::{current_context, Context, ContextConfig};
|
||||
use std::error::Error;
|
||||
use std::fs;
|
||||
use std::collections::HashMap;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
pub fn build_binary_package(
|
||||
arch: Option<&str>,
|
||||
series: Option<&str>,
|
||||
cwd: Option<&Path>,
|
||||
cross: bool,
|
||||
) -> Result<(), Box<dyn Error>> {
|
||||
let cwd = cwd.unwrap_or_else(|| Path::new("."));
|
||||
|
||||
@@ -37,7 +40,11 @@ pub fn build_binary_package(
|
||||
);
|
||||
|
||||
// Run sbuild
|
||||
run_sbuild(&ctx, &remote_dsc_path, arch, series, &build_root)?;
|
||||
if cross {
|
||||
run_cross_build(&ctx, &remote_dsc_path, arch, series, &build_root)?;
|
||||
} else {
|
||||
run_sbuild(&ctx, &remote_dsc_path, arch, series, &build_root)?;
|
||||
}
|
||||
|
||||
// Retrieve artifacts
|
||||
// Always retrieve to the directory containing the .dsc file
|
||||
@@ -61,7 +68,9 @@ pub fn build_binary_package(
|
||||
|
||||
fn find_dsc_file(cwd: &Path, package: &str, version: &str) -> Result<PathBuf, Box<dyn Error>> {
|
||||
let parent = cwd.parent().ok_or("Cannot find parent directory")?;
|
||||
let dsc_name = format!("{}_{}.dsc", package, version);
|
||||
// Strip epoch from version (e.g., "1:2.3.4-5" -> "2.3.4-5")
|
||||
let version_without_epoch = version.split_once(':').map(|(_, v)| v).unwrap_or(version);
|
||||
let dsc_name = format!("{}_{}.dsc", package, version_without_epoch);
|
||||
let dsc_path = parent.join(&dsc_name);
|
||||
|
||||
if !dsc_path.exists() {
|
||||
@@ -155,3 +164,95 @@ fn run_sbuild(
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn run_cross_build(
|
||||
ctx: &Context,
|
||||
dsc_path: &Path,
|
||||
arch: Option<&str>,
|
||||
series: Option<&str>,
|
||||
output_dir: &str,
|
||||
) -> Result<(), Box<dyn Error>> {
|
||||
// TODO: Setup the schroot for cross-build?
|
||||
let arch = arch.unwrap();
|
||||
let series = series.unwrap();
|
||||
|
||||
let localarch = "amd64";
|
||||
// let context = Context::new(ContextConfig::Schroot { name: format!("{series}-{localarch}-{arch}") });
|
||||
let context = Context::new(ContextConfig::Schroot { name: format!("{series}-{localarch}") });
|
||||
|
||||
// Set environment variables for cross-compilation: dpkg-architecture variables
|
||||
let dpkg_architecture = String::from_utf8(ctx.command("dpkg-architecture").arg(format!("-a{}", arch)).output()?.stdout)?;
|
||||
let env_var_regex = regex::Regex::new(r"(?<key>.*)=(?<value>.*)").unwrap();
|
||||
let mut env = HashMap::new();
|
||||
for l in dpkg_architecture.lines() {
|
||||
let capture = env_var_regex.captures(l).unwrap();
|
||||
let key = capture.name("key").unwrap().as_str().to_string();
|
||||
let value = capture.name("value").unwrap().as_str().to_string();
|
||||
|
||||
env.insert(key.clone(), value.clone());
|
||||
|
||||
if key == "DEB_HOST_GNU_TYPE" {
|
||||
env.insert("CROSS_COMPILE".to_string(), format!("{value}-"));
|
||||
}
|
||||
}
|
||||
env.insert("DEB_BUILD_PROFILES".to_string(), "cross".to_string());
|
||||
env.insert("DEB_BUILD_OPTIONS".to_string(), "nocheck".to_string());
|
||||
env.insert("LANG".to_string(), "C".to_string());
|
||||
|
||||
// Add target ('host') architecture
|
||||
context.command("dpkg")
|
||||
.envs(env.clone())
|
||||
.arg("--add-architecture")
|
||||
.arg(format!("{arch}"))
|
||||
.status()?;
|
||||
|
||||
// Add missing repositories inside the schroot
|
||||
// let ports_repo = if is_ubuntu {
|
||||
let ports_repo = format!("deb [arch={arch}] http://ports.ubuntu.com/ubuntu-ports {series} main restricted universe multiverse");
|
||||
// } else {
|
||||
// format!("deb [arch={arch}] http://ftp.ports.debian.org/debian-ports {series} main")
|
||||
// };
|
||||
|
||||
// Add ports repository to sources.list
|
||||
context.command("sh")
|
||||
.envs(env.clone())
|
||||
.arg("-c")
|
||||
.arg(format!("echo '{}' >> /etc/apt/sources.list", ports_repo))
|
||||
.status()?;
|
||||
|
||||
// Update package lists
|
||||
context.command("apt-get")
|
||||
.envs(env.clone())
|
||||
.arg("update")
|
||||
.status()?;
|
||||
|
||||
context.command("apt-get")
|
||||
.envs(env.clone())
|
||||
.arg("-y")
|
||||
.arg("install")
|
||||
.arg("build-essential")
|
||||
.arg(format!("crossbuild-essential-{arch}"))
|
||||
.status()?;
|
||||
|
||||
// Install build dependencies
|
||||
context.command("apt-get")
|
||||
.envs(env.clone())
|
||||
.arg("-y")
|
||||
.arg("build-dep")
|
||||
.arg(format!("--host-architecture={arch}"))
|
||||
.arg("./")
|
||||
.status()?;
|
||||
|
||||
context.command("debian/rules")
|
||||
.envs(env.clone())
|
||||
.arg("build")
|
||||
.status()?;
|
||||
|
||||
context.command("fakeroot")
|
||||
.envs(env.clone())
|
||||
.arg("debian/rules")
|
||||
.arg("binary")
|
||||
.status()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
13
src/main.rs
13
src/main.rs
@@ -3,6 +3,7 @@ use std::io::Write;
|
||||
|
||||
extern crate clap;
|
||||
use clap::{Command, arg, command};
|
||||
use pkh::context::ContextConfig;
|
||||
|
||||
extern crate flate2;
|
||||
|
||||
@@ -53,7 +54,8 @@ fn main() {
|
||||
Command::new("deb")
|
||||
.about("Build the binary package")
|
||||
.arg(arg!(-s --series <series> "Target distribution series").required(false))
|
||||
.arg(arg!(-a --arch <arch> "Target architecture").required(false)),
|
||||
.arg(arg!(-a --arch <arch> "Target architecture").required(false))
|
||||
.arg(arg!(--cross "Cross-compile for target architecture (instead of using qemu-binfmt)").required(false)),
|
||||
)
|
||||
.subcommand(
|
||||
Command::new("context")
|
||||
@@ -142,8 +144,11 @@ fn main() {
|
||||
let cwd = std::env::current_dir().unwrap();
|
||||
let series = sub_matches.get_one::<String>("series").map(|s| s.as_str());
|
||||
let arch = sub_matches.get_one::<String>("arch").map(|s| s.as_str());
|
||||
let cross = sub_matches.get_one::<bool>("cross").unwrap_or(&false);
|
||||
|
||||
if let Err(e) = pkh::deb::build_binary_package(arch, series, Some(cwd.as_path())) {
|
||||
if let Err(e) =
|
||||
pkh::deb::build_binary_package(arch, series, Some(cwd.as_path()), *cross)
|
||||
{
|
||||
error!("{}", e);
|
||||
std::process::exit(1);
|
||||
}
|
||||
@@ -168,7 +173,7 @@ fn main() {
|
||||
.unwrap_or("local");
|
||||
|
||||
let context = match type_str {
|
||||
"local" => Context::Local,
|
||||
"local" => ContextConfig::Local,
|
||||
"ssh" => {
|
||||
let endpoint = args
|
||||
.get_one::<String>("endpoint")
|
||||
@@ -191,7 +196,7 @@ fn main() {
|
||||
})
|
||||
});
|
||||
|
||||
Context::Ssh { host, user, port }
|
||||
ContextConfig::Ssh { host, user, port }
|
||||
}
|
||||
_ => {
|
||||
error!("Unknown context type: {}", type_str);
|
||||
|
||||
Reference in New Issue
Block a user