Added possibility to generate unique id for each build

This commit is contained in:
Marcel Sery 2019-01-29 19:05:52 +01:00
parent ce400dbe14
commit 6c49fad2fa
3 changed files with 62 additions and 18 deletions

View File

@ -8,6 +8,7 @@ clap = "2.32.0"
dirs = "1.0.4" dirs = "1.0.4"
reqwest = "0.9.2" reqwest = "0.9.2"
tempdir = "0.3.7" tempdir = "0.3.7"
rand = "0.6"
flate2 = "1.0" flate2 = "1.0"
tar = "0.4" tar = "0.4"
lazy_static = "1.1.0" lazy_static = "1.1.0"

View File

@ -3,6 +3,7 @@ extern crate dirs;
extern crate flate2; extern crate flate2;
#[macro_use] #[macro_use]
extern crate lazy_static; extern crate lazy_static;
extern crate rand;
extern crate reqwest; extern crate reqwest;
extern crate tar; extern crate tar;
extern crate tempdir; extern crate tempdir;
@ -10,6 +11,8 @@ extern crate tempdir;
use clap::{App, AppSettings, Arg}; use clap::{App, AppSettings, Arg};
use flate2::Compression; use flate2::Compression;
use flate2::write::GzEncoder; use flate2::write::GzEncoder;
use rand::{thread_rng, Rng};
use rand::distributions::Alphanumeric;
use std::collections::HashMap; use std::collections::HashMap;
use std::error::Error; use std::error::Error;
use std::fs; use std::fs;
@ -26,7 +29,8 @@ const APP_NAME: &str = env!("CARGO_PKG_NAME");
const AUTHOR: &str = env!("CARGO_PKG_AUTHORS"); const AUTHOR: &str = env!("CARGO_PKG_AUTHORS");
const VERSION: &str = env!("CARGO_PKG_VERSION"); const VERSION: &str = env!("CARGO_PKG_VERSION");
const RUNNER_MAGIC: &[u8] = b"tVQhhsFFlGGD3oWV4lEPST8I8FEPP54IM0q7daes4E1y3p2U2wlJRYmWmjPYfkhZ0PlT14Ls0j8fdDkoj33f2BlRJavLj3mWGibJsGt5uLAtrCDtvxikZ8UX2mQDCrgE\0"; const RUNNER_EXEC_MAGIC: &[u8] = b"tVQhhsFFlGGD3oWV4lEPST8I8FEPP54IM0q7daes4E1y3p2U2wlJRYmWmjPYfkhZ0PlT14Ls0j8fdDkoj33f2BlRJavLj3mWGibJsGt5uLAtrCDtvxikZ8UX2mQDCrgE\0";
const RUNNER_UID_MAGIC: &[u8] = b"DR1PWsJsM6KxNbng9Y38\0";
const RUNNER_LINUX_X64: &[u8] = include_bytes!("../../target/x86_64-unknown-linux-gnu/release/warp-runner"); const RUNNER_LINUX_X64: &[u8] = include_bytes!("../../target/x86_64-unknown-linux-gnu/release/warp-runner");
const RUNNER_MACOS_X64: &[u8] = include_bytes!("../../target/x86_64-apple-darwin/release/warp-runner"); const RUNNER_MACOS_X64: &[u8] = include_bytes!("../../target/x86_64-apple-darwin/release/warp-runner");
@ -51,34 +55,38 @@ macro_rules! bail {
}) })
} }
fn patch_runner(arch: &str, exec_name: &str) -> io::Result<Vec<u8>> { fn patch_runner(arch: &str, exec_name: &str, uid: &str) -> io::Result<Vec<u8>> {
// Read runner executable in memory // Read runner executable in memory
let runner_contents = RUNNER_BY_ARCH.get(arch).unwrap(); let runner_contents = RUNNER_BY_ARCH.get(arch).unwrap();
let mut buf = runner_contents.to_vec(); let mut buf = runner_contents.to_vec();
// Set the correct target executable name into the local magic buffer write_magic(&mut buf, RUNNER_UID_MAGIC, uid);
let magic_len = RUNNER_MAGIC.len(); write_magic(&mut buf, RUNNER_EXEC_MAGIC, exec_name);
Ok(buf)
}
fn write_magic(buf: &mut Vec<u8>, magic: &[u8], new_value: &str) {
// Set the correct target executable name into the local magic buffer
let magic_len = magic.len();
let mut new_magic = vec![0; magic_len]; let mut new_magic = vec![0; magic_len];
new_magic[..exec_name.len()].clone_from_slice(exec_name.as_bytes()); new_magic[..new_value.len()].clone_from_slice(new_value.as_bytes());
// Find the magic buffer offset inside the runner executable // Find the magic buffer offset inside the runner executable
let mut offs_opt = None; let mut offs_opt = None;
for (i, chunk) in buf.windows(magic_len).enumerate() { for (i, chunk) in buf.windows(magic_len).enumerate() {
if chunk == RUNNER_MAGIC { if chunk == magic {
offs_opt = Some(i); offs_opt = Some(i);
break; break;
} }
} }
if offs_opt.is_none() { if offs_opt.is_none() {
return Err(io::Error::new(io::ErrorKind::Other, "no magic found inside runner")); bail!("no magic found inside runner");
} }
// Replace the magic with the new one that points to the target executable // Replace the magic with the new one that points to the target executable
let offs = offs_opt.unwrap(); let offs = offs_opt.unwrap();
buf[offs..offs + magic_len].clone_from_slice(&new_magic); buf[offs..offs + magic_len].clone_from_slice(&new_magic);
Ok(buf)
} }
fn create_tgz(dirs: &Vec<&Path>, out: &Path) -> io::Result<()> { fn create_tgz(dirs: &Vec<&Path>, out: &Path) -> io::Result<()> {
@ -145,6 +153,13 @@ fn check_executable_exists(exec_path: &Path){
} }
} }
fn generate_uid() -> String {
return thread_rng()
.sample_iter(&Alphanumeric)
.take(RUNNER_UID_MAGIC.len() - 1)
.collect();
}
fn main() -> Result<(), Box<Error>> { fn main() -> Result<(), Box<Error>> {
let args = App::new(APP_NAME) let args = App::new(APP_NAME)
.settings(&[AppSettings::ArgRequiredElseHelp, AppSettings::ColoredHelp]) .settings(&[AppSettings::ArgRequiredElseHelp, AppSettings::ColoredHelp])
@ -200,6 +215,14 @@ fn main() -> Result<(), Box<Error>> {
.display_order(6) .display_order(6)
.takes_value(true) .takes_value(true)
.required(true)) .required(true))
.arg(Arg::with_name("unique_id")
.short("q")
.long("unique_id")
.value_name("unique_id")
.help("Generate unique id for each package build")
.display_order(7)
.takes_value(false)
.required(false))
.get_matches(); .get_matches();
let arch = args.value_of("arch").unwrap(); let arch = args.value_of("arch").unwrap();
@ -223,7 +246,7 @@ fn main() -> Result<(), Box<Error>> {
.collect(); .collect();
let exec_name = args.value_of("exec").unwrap(); let exec_name = args.value_of("exec").unwrap();
if exec_name.len() >= RUNNER_MAGIC.len() { if exec_name.len() >= RUNNER_EXEC_MAGIC.len() {
bail!("Executable name is too long, please consider using a shorter name"); bail!("Executable name is too long, please consider using a shorter name");
} }
@ -233,7 +256,13 @@ fn main() -> Result<(), Box<Error>> {
check_executable_exists(&exec_path); check_executable_exists(&exec_path);
} }
let runner_buf = patch_runner(&arch, &exec_name)?; let mut uid:String = "".to_string();
let do_generate_uid = args.is_present("unique_id");
if do_generate_uid {
uid = generate_uid();
}
let runner_buf = patch_runner(&arch, &exec_name, &uid)?;
create_tgz(&input_dirs, &main_tgz_path)?; create_tgz(&input_dirs, &main_tgz_path)?;

View File

@ -16,17 +16,26 @@ mod extractor;
mod executor; mod executor;
static TARGET_FILE_NAME_BUF: &'static [u8] = b"tVQhhsFFlGGD3oWV4lEPST8I8FEPP54IM0q7daes4E1y3p2U2wlJRYmWmjPYfkhZ0PlT14Ls0j8fdDkoj33f2BlRJavLj3mWGibJsGt5uLAtrCDtvxikZ8UX2mQDCrgE\0"; static TARGET_FILE_NAME_BUF: &'static [u8] = b"tVQhhsFFlGGD3oWV4lEPST8I8FEPP54IM0q7daes4E1y3p2U2wlJRYmWmjPYfkhZ0PlT14Ls0j8fdDkoj33f2BlRJavLj3mWGibJsGt5uLAtrCDtvxikZ8UX2mQDCrgE\0";
static TARGET_UID_BUF: &'static [u8] = b"DR1PWsJsM6KxNbng9Y38\0";
fn build_uid() -> &'static str {
return read_magic("TARGET_UID_BUF", &TARGET_UID_BUF)
}
fn target_file_name() -> &'static str { fn target_file_name() -> &'static str {
let nul_pos = TARGET_FILE_NAME_BUF.iter() return read_magic("TARGET_FILE_NAME_BUF", &TARGET_FILE_NAME_BUF)
.position(|elem| *elem == b'\0') }
.expect("TARGET_FILE_NAME_BUF has no NUL terminator");
let slice = &TARGET_FILE_NAME_BUF[..(nul_pos + 1)]; fn read_magic(magic_name: &str, magic: &'static [u8]) -> &'static str {
let nul_pos = magic.iter()
.position(|elem| *elem == b'\0')
.expect(&format!("{} has no NUL terminator", magic_name));
let slice = &magic[..(nul_pos + 1)];
CStr::from_bytes_with_nul(slice) CStr::from_bytes_with_nul(slice)
.expect("Can't convert TARGET_FILE_NAME_BUF slice to CStr") .expect(&format!("Can't convert {} slice to CStr", magic_name))
.to_str() .to_str()
.expect("Can't convert TARGET_FILE_NAME_BUF CStr to str") .expect(&format!("Can't convert {} CStr to str", magic_name))
} }
fn cache_path(target: &str) -> PathBuf { fn cache_path(target: &str) -> PathBuf {
@ -48,12 +57,17 @@ fn main() -> Result<(), Box<Error>> {
simple_logger::init_with_level(Level::Trace)?; simple_logger::init_with_level(Level::Trace)?;
} }
let build_uid = build_uid();
let self_path = env::current_exe()?; let self_path = env::current_exe()?;
let self_file_name = self_path.file_name().unwrap(); let self_file_name = self_path.file_name().unwrap();
let cache_path = cache_path(&self_file_name.to_string_lossy()); let cache_folder_name = format!("{}.{}", self_file_name.to_string_lossy(), build_uid);
let cache_path = cache_path(&cache_folder_name);
trace!("self_path={:?}", self_path); trace!("self_path={:?}", self_path);
trace!("self_file_name={:?}", self_file_name); trace!("self_file_name={:?}", self_file_name);
trace!("build_uid={:?}", build_uid);
trace!("cache_path={:?}", cache_path); trace!("cache_path={:?}", cache_path);
let target_file_name = target_file_name(); let target_file_name = target_file_name();