Pass through arguments unmodified after bun run <script> or bun <script>

Fixes https://github.com/oven-sh/bun/issues/231
This commit is contained in:
Jarred Sumner
2022-09-19 23:37:08 -07:00
parent 8b7f43f855
commit da7b648971
6 changed files with 42 additions and 49 deletions

View File

@@ -57,10 +57,9 @@ pub const Run = struct {
.ctx = ctx,
.entry_path = entry_path,
};
run.vm.argv = ctx.passthrough;
run.vm.arena = &run.arena;
run.vm.argv = ctx.positionals;
if (ctx.debug.macros) |macros| {
run.vm.bundler.options.macro_remap = macros;
}

View File

@@ -327,6 +327,10 @@ pub const Arguments = struct {
var args = clap.parse(clap.Help, params_to_use, .{
.diagnostic = &diag,
.allocator = allocator,
.stop_after_positional_at = if (cmd == .RunCommand) 2 else if (cmd == .AutoCommand)
1
else
0,
}) catch |err| {
// Report useful error and exit
clap.help(Output.errorWriter(), params_to_use) catch {};
@@ -399,6 +403,7 @@ pub const Arguments = struct {
opts.generate_node_module_bundle = cmd == .BunCommand;
opts.inject = args.options("--inject");
opts.extension_order = args.options("--extension-order");
ctx.passthrough = args.remaining();
opts.no_summary = args.flag("--no-summary");
opts.disable_hmr = args.flag("--disable-hmr");
@@ -789,6 +794,7 @@ pub const Command = struct {
log: *logger.Log,
allocator: std.mem.Allocator,
positionals: []const string = &[_]string{},
passthrough: []const string = &[_]string{},
install: ?*Api.BunInstall = null,
debug: DebugOptions = DebugOptions{},

View File

@@ -231,7 +231,8 @@ pub const RunCommand = struct {
var combined_script_buf = try allocator.alloc(u8, combined_script_len);
std.mem.copy(u8, combined_script_buf, script);
var remaining_script_buf = combined_script_buf[script.len..];
for (passthrough) |p| {
for (passthrough) |part| {
var p = part;
remaining_script_buf[0] = ' ';
std.mem.copy(u8, remaining_script_buf[1..], p);
remaining_script_buf = remaining_script_buf[p.len + 1 ..];
@@ -715,49 +716,7 @@ pub const RunCommand = struct {
script_name_to_search = positionals[0];
}
var passthrough: []const string = &[_]string{};
var passthrough_list = std.ArrayList(string).init(ctx.allocator);
if (script_name_to_search.len > 0) {
get_passthrough: {
// If they explicitly pass "--", that means they want everything after that to be passed through.
for (std.os.argv) |argv, i| {
if (strings.eqlComptime(std.mem.span(argv), "--")) {
if (std.os.argv.len > i + 1) {
var count: usize = 0;
for (std.os.argv[i + 1 ..]) |_| {
count += 1;
}
try passthrough_list.ensureTotalCapacity(count);
for (std.os.argv[i + 1 ..]) |arg| {
passthrough_list.appendAssumeCapacity(std.mem.span(arg));
}
passthrough = passthrough_list.toOwnedSlice();
break :get_passthrough;
}
}
}
// If they do not pass "--", assume they want everything after the script name to be passed through.
for (std.os.argv) |argv, i| {
if (strings.eql(std.mem.span(argv), script_name_to_search)) {
if (std.os.argv.len > i + 1) {
try passthrough_list.ensureTotalCapacity(std.os.argv[i + 1 ..].len);
for (std.os.argv[i + 1 ..]) |arg| {
passthrough_list.appendAssumeCapacity(std.mem.span(arg));
}
passthrough = passthrough_list.toOwnedSlice();
break :get_passthrough;
}
}
}
}
}
const passthrough = ctx.passthrough;
if (comptime log_errors) {
if (script_name_to_search.len > 0) {

View File

@@ -265,6 +265,10 @@ pub fn Args(comptime Id: type, comptime params: []const Param(Id)) type {
return a.clap.positionals();
}
pub fn remaining(a: @This()) []const []const u8 {
return a.clap.remaining();
}
pub fn hasFlag(comptime name: []const u8) bool {
return ComptimeClap(Id, params).hasFlag(name);
}
@@ -280,6 +284,7 @@ pub const ParseOptions = struct {
/// is fine, as it wraps it in an arena)
allocator: mem.Allocator = heap.page_allocator,
diagnostic: ?*Diagnostic = null,
stop_after_positional_at: usize = 0,
};
/// Same as `parseEx` but uses the `args.OsIterator` by default.
@@ -288,7 +293,7 @@ pub fn parse(
comptime params: []const Param(Id),
opt: ParseOptions,
) !Args(Id, params) {
var iter = try args.OsIterator.init(opt.allocator);
var iter = args.OsIterator.init(opt.allocator);
var res = Args(Id, params){
.arena = iter.arena,
.exe_arg = iter.exe_arg,
@@ -300,6 +305,7 @@ pub fn parse(
res.clap = try parseEx(Id, params, &iter, .{
.allocator = res.arena.allocator(),
.diagnostic = opt.diagnostic,
.stop_after_positional_at = opt.stop_after_positional_at,
});
return res;
}

View File

@@ -56,7 +56,7 @@ pub const OsIterator = struct {
/// return an error when we have no exe.
exe_arg: ?[:0]const u8,
pub fn init(allocator: mem.Allocator) Error!OsIterator {
pub fn init(allocator: mem.Allocator) OsIterator {
var res = OsIterator{
.arena = heap.ArenaAllocator.init(allocator),
.args = process.args(),

View File

@@ -44,6 +44,7 @@ pub fn ComptimeClap(
multi_options: [multi_options][]const []const u8,
flags: [flags]bool,
pos: []const []const u8,
passthrough_positionals: []const []const u8,
allocator: mem.Allocator,
pub fn parse(iter: anytype, opt: clap.ParseOptions) !@This() {
@@ -54,6 +55,7 @@ pub fn ComptimeClap(
}
var pos = std.ArrayList([]const u8).init(allocator);
var passthrough_positionals = std.ArrayList([]const u8).init(allocator);
var res = @This(){
.single_options = [_]?[]const u8{null} ** single_options,
@@ -61,16 +63,33 @@ pub fn ComptimeClap(
.flags = [_]bool{false} ** flags,
.pos = undefined,
.allocator = allocator,
.passthrough_positionals = undefined,
};
var stream = clap.StreamingClap(usize, @typeInfo(@TypeOf(iter)).Pointer.child){
.params = converted_params,
.iter = iter,
};
while (try stream.next()) |arg| {
const param = arg.param;
if (param.names.long == null and param.names.short == null) {
try pos.append(arg.value.?);
if (opt.stop_after_positional_at > 0 and pos.items.len >= opt.stop_after_positional_at) {
const bun = @import("../../../global.zig");
if (comptime bun.Environment.isWindows) @compileError(
"TODO: implement stop_after_positional_at on windows",
);
const remaining_ = std.os.argv[@minimum(std.os.argv.len, stream.iter.args.inner.index)..];
try passthrough_positionals.ensureTotalCapacityPrecise(remaining_.len);
for (remaining_) |arg_| {
// use bun.span due to the optimization for long strings
passthrough_positionals.appendAssumeCapacity(bun.span(arg_));
}
break;
}
} else if (param.takes_value == .one or param.takes_value == .one_optional) {
debug.assert(res.single_options.len != 0);
if (res.single_options.len != 0)
@@ -89,7 +108,7 @@ pub fn ComptimeClap(
for (multis) |*multi, i|
res.multi_options[i] = multi.toOwnedSlice();
res.pos = pos.toOwnedSlice();
res.passthrough_positionals = passthrough_positionals.toOwnedSlice();
return res;
}
@@ -130,6 +149,10 @@ pub fn ComptimeClap(
return parser.pos;
}
pub fn remaining(parser: @This()) []const []const u8 {
return parser.passthrough_positionals;
}
pub fn hasFlag(comptime name: []const u8) bool {
comptime {
for (converted_params) |param| {