Added support for including already packed resources
This commit is contained in:
parent
8c85dc5c13
commit
ce400dbe14
@ -13,6 +13,7 @@ use flate2::write::GzEncoder;
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
|
use std::iter;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::io::copy;
|
use std::io::copy;
|
||||||
@ -80,15 +81,15 @@ fn patch_runner(arch: &str, exec_name: &str) -> io::Result<Vec<u8>> {
|
|||||||
Ok(buf)
|
Ok(buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_tgz(dirs: &Vec<&Path>, out: &Path) -> io::Result<()> {
|
fn create_tgz(dirs: &Vec<&Path>, out: &Path) -> io::Result<()> {
|
||||||
let f = fs::File::create(out)?;
|
let f = fs::File::create(out)?;
|
||||||
let gz = GzEncoder::new(f, Compression::best());
|
let gz = GzEncoder::new(f, Compression::best());
|
||||||
let mut tar = tar::Builder::new(gz);
|
let mut tar = tar::Builder::new(gz);
|
||||||
tar.follow_symlinks(false);
|
tar.follow_symlinks(false);
|
||||||
for dir in dirs.iter() {
|
for dir in dirs.iter() {
|
||||||
println!("Compressing input directory {:?}...", dir);
|
println!("Compressing input directory {:?}...", dir);
|
||||||
tar.append_dir_all(".", dir)?;
|
tar.append_dir_all(".", dir)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -111,22 +112,39 @@ fn create_app_file(out: &Path) -> io::Result<File> {
|
|||||||
.open(out)
|
.open(out)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_app(runner_buf: &Vec<u8>, tgz_path: &Path, out: &Path) -> io::Result<()> {
|
fn create_app(runner_buf: &Vec<u8>, tgz_paths: &Vec<&Path>, out: &Path) -> io::Result<()> {
|
||||||
let mut outf = create_app_file(out)?;
|
let mut outf = create_app_file(out)?;
|
||||||
let mut tgzf = fs::File::open(tgz_path)?;
|
|
||||||
outf.write_all(runner_buf)?;
|
outf.write_all(runner_buf)?;
|
||||||
copy(&mut tgzf, &mut outf)?;
|
|
||||||
|
for tgz_path in tgz_paths.iter() {
|
||||||
|
let mut tgzf = fs::File::open(tgz_path)?;
|
||||||
|
copy(&mut tgzf, &mut outf)?;
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_path(path_str: &str) -> &Path {
|
fn make_path(path_str: &str) -> &Path {
|
||||||
let path = Path::new(path_str);
|
let path = Path::new(path_str);
|
||||||
if fs::metadata(path).is_err() {
|
if fs::metadata(path).is_err() {
|
||||||
bail!("Cannot access specified input directory {:?}", path);
|
bail!("Cannot access specified input path {:?}", path);
|
||||||
}
|
}
|
||||||
return &path;
|
return &path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_executable_exists(exec_path: &Path){
|
||||||
|
match fs::metadata(&exec_path) {
|
||||||
|
Err(_) => {
|
||||||
|
bail!("Cannot find file {:?}", exec_path);
|
||||||
|
}
|
||||||
|
Ok(metadata) => {
|
||||||
|
if !metadata.is_file() {
|
||||||
|
bail!("{:?} isn't a file", exec_path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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])
|
||||||
@ -151,20 +169,35 @@ fn main() -> Result<(), Box<Error>> {
|
|||||||
.required(true)
|
.required(true)
|
||||||
.multiple(true)
|
.multiple(true)
|
||||||
.min_values(1))
|
.min_values(1))
|
||||||
|
.arg(Arg::with_name("input_tgz")
|
||||||
|
.short("t")
|
||||||
|
.long("input_tgz")
|
||||||
|
.value_name("input_tgz")
|
||||||
|
.help("Sets additional already packed tar-gzipped files to be included in package. Might provide multiple files. Can be used with --disable_exec_check param if main executable file is in packed file.")
|
||||||
|
.display_order(3)
|
||||||
|
.takes_value(true)
|
||||||
|
.required(false)
|
||||||
|
.multiple(true))
|
||||||
.arg(Arg::with_name("exec")
|
.arg(Arg::with_name("exec")
|
||||||
.short("e")
|
.short("e")
|
||||||
.long("exec")
|
.long("exec")
|
||||||
.value_name("exec")
|
.value_name("exec")
|
||||||
.help("Sets the application executable file name")
|
.help("Sets the application executable file name")
|
||||||
.display_order(3)
|
.display_order(4)
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
.required(true))
|
.required(true))
|
||||||
|
.arg(Arg::with_name("disable_exec_check")
|
||||||
|
.long("disable_exec_check")
|
||||||
|
.help("Disables the check for existence of executable file in target directory. Useful for cases when main executable file is in already packed tgzip file (see input_tgz param)")
|
||||||
|
.display_order(5)
|
||||||
|
.takes_value(false)
|
||||||
|
.required(false))
|
||||||
.arg(Arg::with_name("output")
|
.arg(Arg::with_name("output")
|
||||||
.short("o")
|
.short("o")
|
||||||
.long("output")
|
.long("output")
|
||||||
.value_name("output")
|
.value_name("output")
|
||||||
.help("Sets the resulting self-contained application file name")
|
.help("Sets the resulting self-contained application file name")
|
||||||
.display_order(4)
|
.display_order(6)
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
.required(true))
|
.required(true))
|
||||||
.get_matches();
|
.get_matches();
|
||||||
@ -174,40 +207,39 @@ fn main() -> Result<(), Box<Error>> {
|
|||||||
bail!("Unknown architecture specified: {}, supported: {:?}", arch, RUNNER_BY_ARCH.keys());
|
bail!("Unknown architecture specified: {}, supported: {:?}", arch, RUNNER_BY_ARCH.keys());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let tmp_dir = TempDir::new(APP_NAME)?;
|
||||||
|
let main_tgz = tmp_dir.path().join("input.tgz");
|
||||||
|
let main_tgz_path = main_tgz.as_path();
|
||||||
|
|
||||||
let input_dirs: Vec<&Path> = args.values_of("input_dir")
|
let input_dirs: Vec<&Path> = args.values_of("input_dir")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.map(make_path)
|
.map(make_path)
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
let input_tgzs: Vec<&Path> = args.values_of("input_tgz")
|
||||||
|
.unwrap_or(clap::Values::default())
|
||||||
|
.map(make_path)
|
||||||
|
.chain(iter::once(main_tgz_path))
|
||||||
|
.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_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");
|
||||||
}
|
}
|
||||||
|
|
||||||
let exec_path = Path::new(input_dirs[0]).join(exec_name);
|
let do_check_exec_existence = !args.is_present("disable_exec_check");
|
||||||
match fs::metadata(&exec_path) {
|
if do_check_exec_existence {
|
||||||
Err(_) => {
|
let exec_path = Path::new(input_dirs[0]).join(exec_name);
|
||||||
bail!("Cannot find file {:?}", exec_path);
|
check_executable_exists(&exec_path);
|
||||||
}
|
|
||||||
Ok(metadata) => {
|
|
||||||
if !metadata.is_file() {
|
|
||||||
bail!("{:?} isn't a file", exec_path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let runner_buf = patch_runner(&arch, &exec_name)?;
|
let runner_buf = patch_runner(&arch, &exec_name)?;
|
||||||
|
|
||||||
let tmp_dir = TempDir::new(APP_NAME)?;
|
create_tgz(&input_dirs, &main_tgz_path)?;
|
||||||
let tgz_path = tmp_dir.path().join("input.tgz");
|
|
||||||
|
|
||||||
create_tgz(&input_dirs, &tgz_path)?;
|
|
||||||
|
|
||||||
|
|
||||||
let exec_name = Path::new(args.value_of("output").unwrap());
|
let exec_name = Path::new(args.value_of("output").unwrap());
|
||||||
println!("Creating self-contained application binary {:?}...", exec_name);
|
println!("Creating self-contained application binary {:?}...", exec_name);
|
||||||
create_app(&runner_buf, &tgz_path, &exec_name)?;
|
create_app(&runner_buf, &input_tgzs, &exec_name)?;
|
||||||
|
|
||||||
println!("All done");
|
println!("All done");
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -77,7 +77,6 @@ pub fn extract_to(src: &Path, dst: &Path) -> io::Result<()> {
|
|||||||
if extract_at_offset(src, offs, dst).is_ok() {
|
if extract_at_offset(src, offs, dst).is_ok() {
|
||||||
trace!("tarball found at offset {} was extracted successfully", offs);
|
trace!("tarball found at offset {} was extracted successfully", offs);
|
||||||
found = true;
|
found = true;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user