Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ensure autopacking packs dependencies first #11

Merged
merged 3 commits into from
Sep 9, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
113 changes: 92 additions & 21 deletions crates/brioche-autopack/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use std::{
collections::{HashMap, HashSet, VecDeque},
collections::{BTreeMap, HashMap, HashSet, VecDeque},
io::{BufRead as _, Read as _, Write as _},
path::{Path, PathBuf},
};
Expand Down Expand Up @@ -151,18 +151,21 @@ fn relative_template(
#[derive(Debug, Clone)]
pub struct RepackConfig {}

struct AutopackPathConfig {
can_skip: bool,
}

pub fn autopack(config: &AutopackConfig) -> eyre::Result<()> {
let ctx = autopack_context(config)?;
let mut pending_paths = BTreeMap::<PathBuf, AutopackPathConfig>::new();

match &config.inputs {
AutopackInputs::Paths(paths) => {
for path in paths {
let did_pack = try_autopack_path(&ctx, path, path)?;
eyre::ensure!(did_pack, "failed to autopack path: {path:?}");
if !config.quiet {
println!("autopacked {}", path.display());
}
}
pending_paths.extend(
paths
.iter()
.map(|path| (path.clone(), AutopackPathConfig { can_skip: true })),
);
}
AutopackInputs::Globs {
base_path,
Expand Down Expand Up @@ -191,19 +194,19 @@ pub fn autopack(config: &AutopackConfig) -> eyre::Result<()> {
})?;

if globs.is_match(&relative_entry_path) {
let did_pack = try_autopack_path(&ctx, entry.path(), entry.path())?;
if !config.quiet {
if did_pack {
println!("autopacked {}", entry.path().display());
} else {
println!("skipped {}", entry.path().display());
}
}
pending_paths.insert(
entry.path().to_owned(),
AutopackPathConfig { can_skip: false },
);
}
}
}
}

while let Some((path, path_config)) = pending_paths.pop_first() {
autopack_path(&ctx, &path, &path_config, &mut pending_paths)?;
}

Ok(())
}

Expand Down Expand Up @@ -294,20 +297,47 @@ fn autopack_context(config: &AutopackConfig) -> eyre::Result<AutopackContext> {
})
}

fn autopack_path(
ctx: &AutopackContext,
path: &Path,
path_config: &AutopackPathConfig,
pending_paths: &mut BTreeMap<PathBuf, AutopackPathConfig>,
) -> eyre::Result<()> {
let did_pack = try_autopack_path(ctx, path, path, pending_paths)?;
if did_pack {
if !ctx.config.quiet {
println!("autopacked {}", path.display());
}
} else if !path_config.can_skip {
if !ctx.config.quiet {
println!("skipped {}", path.display());
}
} else {
eyre::bail!("failed to autopack path: {path:?}");
}

Ok(())
}

fn try_autopack_path(
ctx: &AutopackContext,
source_path: &Path,
output_path: &Path,
pending_paths: &mut BTreeMap<PathBuf, AutopackPathConfig>,
) -> eyre::Result<bool> {
let Some(kind) = autopack_kind(source_path)? else {
return Ok(false);
};

match kind {
AutopackKind::DynamicBinary => autopack_dynamic_binary(ctx, source_path, output_path),
AutopackKind::SharedLibrary => autopack_shared_library(ctx, source_path, output_path),
AutopackKind::Script => autopack_script(ctx, source_path, output_path),
AutopackKind::Repack => autopack_repack(ctx, source_path, output_path),
AutopackKind::DynamicBinary => {
autopack_dynamic_binary(ctx, source_path, output_path, pending_paths)
}
AutopackKind::SharedLibrary => {
autopack_shared_library(ctx, source_path, output_path, pending_paths)
}
AutopackKind::Script => autopack_script(ctx, source_path, output_path, pending_paths),
AutopackKind::Repack => autopack_repack(ctx, source_path, output_path, pending_paths),
}
}

Expand Down Expand Up @@ -350,6 +380,7 @@ fn autopack_dynamic_binary(
ctx: &AutopackContext,
source_path: &Path,
output_path: &Path,
pending_paths: &mut BTreeMap<PathBuf, AutopackPathConfig>,
) -> eyre::Result<bool> {
let Some(dynamic_binary_config) = &ctx.config.dynamic_binary else {
return Ok(false);
Expand Down Expand Up @@ -391,6 +422,10 @@ fn autopack_dynamic_binary(
let interpreter_path = interpreter_path.ok_or_else(|| {
eyre::eyre!("could not find interpreter for dynamic binary: {source_path:?}")
})?;

// Autopack the interpreter if it's pending
try_autopack_dependency(ctx, &interpreter_path, pending_paths)?;

let interpreter_resource_path = add_named_blob_from(ctx, &interpreter_path, None)
.with_context(|| format!("failed to add resource for interpreter {interpreter_path:?}"))?;
let program_resource_path = add_named_blob_from(ctx, source_path, None)
Expand All @@ -414,6 +449,7 @@ fn autopack_dynamic_binary(
ctx,
&dynamic_binary_config.dynamic_linking,
needed_libraries,
pending_paths,
)?;

let program = <Vec<u8>>::from_path_buf(program_resource_path)
Expand Down Expand Up @@ -461,6 +497,7 @@ fn autopack_shared_library(
ctx: &AutopackContext,
source_path: &Path,
output_path: &Path,
pending_paths: &mut BTreeMap<PathBuf, AutopackPathConfig>,
) -> eyre::Result<bool> {
let Some(shared_library_config) = &ctx.config.shared_library else {
return Ok(false);
Expand Down Expand Up @@ -500,6 +537,7 @@ fn autopack_shared_library(
ctx,
&shared_library_config.dynamic_linking,
needed_libraries,
pending_paths,
)?;

let library_dirs = library_dir_resource_paths
Expand Down Expand Up @@ -527,6 +565,7 @@ fn autopack_script(
ctx: &AutopackContext,
source_path: &Path,
output_path: &Path,
pending_paths: &mut BTreeMap<PathBuf, AutopackPathConfig>,
) -> eyre::Result<bool> {
let Some(script_config) = &ctx.config.script else {
return Ok(false);
Expand Down Expand Up @@ -571,6 +610,10 @@ fn autopack_script(
}

let command = command.ok_or_else(|| eyre::eyre!("could not find command {command_name:?}"))?;

// Autopack the command if it's pending
try_autopack_dependency(ctx, &command, pending_paths)?;

let command_resource = add_named_blob_from(ctx, &command, None)?;
let script_resource = add_named_blob_from(ctx, source_path, None)?;

Expand Down Expand Up @@ -661,6 +704,7 @@ fn autopack_repack(
ctx: &AutopackContext,
source_path: &Path,
output_path: &Path,
pending_paths: &mut BTreeMap<PathBuf, AutopackPathConfig>,
) -> eyre::Result<bool> {
let Some(_) = &ctx.config.repack else {
return Ok(false);
Expand Down Expand Up @@ -756,7 +800,12 @@ fn autopack_repack(
}
}

let result = try_autopack_path(ctx, &unpacked_source_path, &unpacked_output_path)?;
let result = try_autopack_path(
ctx,
&unpacked_source_path,
&unpacked_output_path,
pending_paths,
)?;
Ok(result)
}

Expand All @@ -769,6 +818,7 @@ fn collect_all_library_dirs(
ctx: &AutopackContext,
dynamic_linking_config: &DynamicLinkingConfig,
mut needed_libraries: VecDeque<String>,
pending_paths: &mut BTreeMap<PathBuf, AutopackPathConfig>,
) -> eyre::Result<Vec<PathBuf>> {
let mut library_search_paths = vec![];
let mut resource_library_dirs = vec![];
Expand All @@ -794,6 +844,9 @@ fn collect_all_library_dirs(
}
};

// Autopack the library if it's pending
try_autopack_dependency(ctx, &library_path, pending_paths)?;

found_libraries.insert(library_name.clone());

// Don't add the library if it's been skipped. We still do everything
Expand Down Expand Up @@ -955,3 +1008,21 @@ fn add_named_blob_from(
)?;
Ok(resource_path)
}

fn try_autopack_dependency(
ctx: &AutopackContext,
path: &Path,
pending_paths: &mut BTreeMap<PathBuf, AutopackPathConfig>,
) -> eyre::Result<()> {
// Get the canonical path of the dependency
let canonical_path = path
.canonicalize()
.with_context(|| format!("failed to canonicalize path {path:?}"))?;

// If the path is pending, then autopack it
if let Some(path_config) = pending_paths.remove(&canonical_path) {
autopack_path(ctx, path, &path_config, pending_paths)?;
}

Ok(())
}