Skip to content

Commit

Permalink
install.sh: support busybox unzip, 7z, 7zz, 7za, bsdtar
Browse files Browse the repository at this point in the history
see denoland/deno_install#321 as well

This makes installing bun easier on systems where you don't have root.
  • Loading branch information
erg committed Jan 30, 2025
1 parent 574a41b commit aefcd65
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 19 deletions.
20 changes: 17 additions & 3 deletions src/cli/install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,9 @@ success() {
echo -e "${Green}$@ ${Color_Off}"
}

command -v unzip >/dev/null ||
error 'unzip is required to install bun'
if ! { command -v unzip || command -v busybox || command -v 7z || command -v 7zz || command -v 7za || command -v bsdtar; } >/dev/null; then
error 'unzip is required to install bun (7z, busybox, and bsdtar supported)'
fi

if [[ $# -gt 2 ]]; then
error 'Too many arguments, only 2 are allowed. The first can be a specific tag of bun to install. (e.g. "bun-v0.1.4") The second can be a build variant of bun to install. (e.g. "debug-info")'
Expand Down Expand Up @@ -143,8 +144,21 @@ fi
curl --fail --location --progress-bar --output "$exe.zip" "$bun_uri" ||
error "Failed to download bun from \"$bun_uri\""

unzip -oqd "$bin_dir" "$exe.zip" ||
if command -v unzip >/dev/null; then
unzip -oqd "$bin_dir" "$exe.zip" ||
error 'Failed to extract bun'
elif command -v busybox >/dev/null; then
busybox unzip -oqd "$bin_dir" "$exe.zip" ||
error 'Failed to extract bun'
elif cmd=$(command -v 7z || command -v 7zz || command -v 7za); then
"$cmd" x -o"$bin_dir" -y "$exe.zip" ||
error 'Failed to extract bun'
elif command -v bsdtar >/dev/null; then
bsdtar -xf "$exe.zip" --xattrs -C "$bin_dir" ||
error 'Failed to extract bun'
else
error 'Failed to extract bun'
fi

mv "$bin_dir/bun-$target/$exe_name" "$exe" ||
error 'Failed to move extracted bun to destination'
Expand Down
80 changes: 64 additions & 16 deletions src/cli/upgrade_command.zig
Original file line number Diff line number Diff line change
Expand Up @@ -607,37 +607,27 @@ pub const UpgradeCommand = struct {
}

if (comptime Environment.isPosix) {
const unzip_exe = which(&unzip_path_buf, env_loader.map.get("PATH") orelse "", filesystem.top_level_dir, "unzip") orelse {
var unzip_command = (try getUnzipCommand(ctx.allocator, &unzip_path_buf, env_loader.map.get("PATH") orelse "", filesystem.top_level_dir, tmpname)) orelse {
save_dir.deleteFileZ(tmpname) catch {};
Output.prettyErrorln("<r><red>error:<r> Failed to locate \"unzip\" in PATH. bun upgrade needs \"unzip\" to work.", .{});
Output.prettyErrorln("<r><red>error:<r> Failed to locate any supported unzip program in PATH. bun upgrade needs one of: unzip, busybox, 7z, 7zz, 7za, or bsdtar to work.", .{});
Global.exit(1);
};
defer unzip_command.deinit();

// We could just embed libz2
// however, we want to be sure that xattrs are preserved
// xattrs are used for codesigning
// it'd be easy to mess that up
var unzip_argv = [_]string{
bun.asByteSlice(unzip_exe),
"-q",
"-o",
tmpname,
};

var unzip_process = std.process.Child.init(&unzip_argv, ctx.allocator);
var unzip_process = std.process.Child.init(unzip_command.args, ctx.allocator);
unzip_process.cwd = tmpdir_path;
unzip_process.stdin_behavior = .Inherit;
unzip_process.stdout_behavior = .Inherit;
unzip_process.stderr_behavior = .Inherit;

const unzip_result = unzip_process.spawnAndWait() catch |err| {
save_dir.deleteFileZ(tmpname) catch {};
Output.prettyErrorln("<r><red>error:<r> Failed to spawn unzip due to {s}.", .{@errorName(err)});
Output.prettyErrorln("<r><red>error:<r> Failed to spawn {s} due to {s}.", .{ unzip_command.exe, @errorName(err) });
Global.exit(1);
};

if (unzip_result.Exited != 0) {
Output.prettyErrorln("<r><red>Unzip failed<r> (exit code: {d})", .{unzip_result.Exited});
Output.prettyErrorln("<r><red>{s} failed<r> (exit code: {d})", .{ unzip_command.exe, unzip_result.Exited });
save_dir.deleteFileZ(tmpname) catch {};
Global.exit(1);
}
Expand Down Expand Up @@ -1058,3 +1048,61 @@ pub const upgrade_js_bindings = struct {
return .undefined;
}
};

const UnzipCommand = struct {
exe: string,
args: []const string,
allocator: std.mem.Allocator,

pub fn init(allocator: std.mem.Allocator, exe: string, args: []const string) !UnzipCommand {
const arg_list = try allocator.alloc(string, args.len);
@memcpy(arg_list, args);
return UnzipCommand{
.exe = exe,
.args = arg_list,
.allocator = allocator,
};
}

pub fn deinit(self: *UnzipCommand) void {
self.allocator.free(self.args);
}
};

fn getUnzipCommand(
allocator: std.mem.Allocator,
path_buf: *bun.PathBuffer,
path: string,
top_level_dir: string,
tmpname: string,
) !?UnzipCommand {
// We could just embed libz2
// however, we want to be sure that xattrs are preserved
// xattrs are used for codesigning
// it'd be easy to mess that up
if (which(path_buf, path, top_level_dir, "unzip")) |unzip_exe| {
const exe = bun.asByteSlice(unzip_exe);
return try UnzipCommand.init(allocator, exe, &[_]string{ exe, "-q", "-o", tmpname });
}

// preserves xattrs
if (which(path_buf, path, top_level_dir, "busybox")) |busybox_exe| {
const exe = bun.asByteSlice(busybox_exe);
return try UnzipCommand.init(allocator, exe, &[_]string{ exe, "unzip", "-q", "-o", tmpname });
}

if (which(path_buf, path, top_level_dir, "7z") orelse
which(path_buf, path, top_level_dir, "7zz") orelse
which(path_buf, path, top_level_dir, "7za")) |sevenzip_exe|
{
const exe = bun.asByteSlice(sevenzip_exe);
return try UnzipCommand.init(allocator, exe, &[_]string{ exe, "x", "-y", tmpname });
}

if (which(path_buf, path, top_level_dir, "bsdtar")) |bsdtar_exe| {
const exe = bun.asByteSlice(bsdtar_exe);
return try UnzipCommand.init(allocator, exe, &[_]string{ exe, "-xf", tmpname, "--xattrs", "-C", "." });
}

return null;
}

0 comments on commit aefcd65

Please sign in to comment.