diff options
Diffstat (limited to 'src')
32 files changed, 7081 insertions, 268 deletions
diff --git a/src/allocators.zig b/src/allocators.zig index 2025c4961..8d1788f51 100644 --- a/src/allocators.zig +++ b/src/allocators.zig @@ -272,6 +272,11 @@ pub fn BSSStringList(comptime _count: usize, comptime _item_length: usize) type return constStrToU8(slice); } + pub fn appendMutable(self: *Self, comptime AppendType: type, _value: AppendType) ![]u8 { + const appended = try @call(.{ .modifier = .always_inline }, append, .{ self, AppendType, _value }); + return constStrToU8(appended); + } + pub fn append(self: *Self, comptime AppendType: type, _value: AppendType) ![]const u8 { mutex.lock(); defer mutex.unlock(); @@ -302,7 +307,7 @@ pub fn BSSStringList(comptime _count: usize, comptime _item_length: usize) type ) ![]const u8 { const value_len: usize = brk: { switch (comptime AppendType) { - []const u8, []u8 => { + []const u8, []u8, [:0]const u8, [:0]u8 => { break :brk _value.len; }, else => { @@ -322,7 +327,7 @@ pub fn BSSStringList(comptime _count: usize, comptime _item_length: usize) type backing_buf_used += value_len; switch (AppendType) { - []const u8, []u8 => { + []const u8, []u8, [:0]const u8, [:0]u8 => { std.mem.copy(u8, backing_buf[start .. backing_buf_used - 1], _value); backing_buf[backing_buf_used - 1] = 0; }, @@ -341,7 +346,7 @@ pub fn BSSStringList(comptime _count: usize, comptime _item_length: usize) type var value_buf = try self.allocator.alloc(u8, value_len); switch (comptime AppendType) { - []const u8, []u8 => { + []const u8, []u8, [:0]const u8, [:0]u8 => { std.mem.copy(u8, value_buf, _value); }, else => { @@ -127,7 +127,7 @@ pub fn moveFileZSlow(from_dir: std.os.fd_t, filename: [*:0]const u8, to_dir: std } pub fn moveFileZSlowWithHandle(in_handle: std.os.fd_t, to_dir: std.os.fd_t, destination: [*:0]const u8) !void { - const stat = try std.os.fstat(in_handle); + const stat_ = try std.os.fstat(in_handle); // delete if exists, don't care if it fails. it may fail due to the file not existing // delete here because we run into weird truncation issues if we do not // ftruncate() instead didn't work. @@ -136,8 +136,8 @@ pub fn moveFileZSlowWithHandle(in_handle: std.os.fd_t, to_dir: std.os.fd_t, dest const out_handle = try std.os.openatZ(to_dir, destination, std.os.O_WRONLY | std.os.O_CREAT | std.os.O_CLOEXEC, 022); defer std.os.close(out_handle); if (comptime Enviroment.isLinux) { - _ = std.os.system.fallocate(out_handle, 0, 0, @intCast(i64, stat.size)); - _ = try std.os.sendfile(out_handle, in_handle, 0, @intCast(usize, stat.size), &[_]std.c.iovec_const{}, &[_]std.c.iovec_const{}, 0); + _ = std.os.system.fallocate(out_handle, 0, 0, @intCast(i64, stat_.size)); + _ = try std.os.sendfile(out_handle, in_handle, 0, @intCast(usize, stat_.size), &[_]std.c.iovec_const{}, &[_]std.c.iovec_const{}, 0); } else { if (comptime Enviroment.isMac) { // if this fails, it doesn't matter @@ -145,7 +145,7 @@ pub fn moveFileZSlowWithHandle(in_handle: std.os.fd_t, to_dir: std.os.fd_t, dest preallocate_file( out_handle, @intCast(std.os.off_t, 0), - @intCast(std.os.off_t, stat.size), + @intCast(std.os.off_t, stat_.size), ) catch {}; } @@ -161,6 +161,6 @@ pub fn moveFileZSlowWithHandle(in_handle: std.os.fd_t, to_dir: std.os.fd_t, dest } } - _ = fchmod(out_handle, stat.mode); - _ = fchown(out_handle, stat.uid, stat.gid); + _ = fchmod(out_handle, stat_.mode); + _ = fchown(out_handle, stat_.uid, stat_.gid); } diff --git a/src/cache.zig b/src/cache.zig index 8bd1221f7..707bb8da4 100644 --- a/src/cache.zig +++ b/src/cache.zig @@ -17,8 +17,6 @@ const ImportRecord = import_record.ImportRecord; pub const FsCacheEntry = struct { contents: string, fd: StoredFileDescriptorType = 0, - // Null means its not usable - mod_key: ?fs.FileSystem.Implementation.ModKey = null, pub fn deinit(entry: *FsCacheEntry, allocator: *std.mem.Allocator) void { if (entry.contents.len > 0) { @@ -66,11 +64,10 @@ pub const Fs = struct { ) !Entry { var rfs = _fs.fs; - var file_handle: std.fs.File = if (_file_handle) |__file| std.fs.File{ .handle = __file } else undefined; - - if (_file_handle == null) { - file_handle = try std.fs.openFileAbsoluteZ(path, .{ .read = true }); - } + const file_handle: std.fs.File = if (_file_handle) |__file| + std.fs.File{ .handle = __file } + else + try std.fs.openFileAbsoluteZ(path, .{ .read = true }); defer { if (rfs.needToCloseFiles() and _file_handle == null) { @@ -78,42 +75,15 @@ pub const Fs = struct { } } - // If the file's modification key hasn't changed since it was cached, assume - // the contents of the file are also the same and skip reading the file. - var mod_key: ?fs.FileSystem.Implementation.ModKey = rfs.modKeyWithFile(path, file_handle) catch |err| handler: { - switch (err) { - error.FileNotFound, error.AccessDenied => { - return err; - }, - else => { - if (isDebug) { - Output.printError("modkey error: {s}", .{@errorName(err)}); - } - break :handler null; - }, + const file = rfs.readFileWithHandle(path, null, file_handle, true, shared) catch |err| { + if (comptime isDebug) { + Output.printError("{s}: readFile error -- {s}", .{ path, @errorName(err) }); } + return err; }; - var file: fs.File = undefined; - if (mod_key) |modk| { - file = rfs.readFileWithHandle(path, modk.size, file_handle, true, shared) catch |err| { - if (isDebug) { - Output.printError("{s}: readFile error -- {s}", .{ path, @errorName(err) }); - } - return err; - }; - } else { - file = rfs.readFileWithHandle(path, null, file_handle, true, shared) catch |err| { - if (isDebug) { - Output.printError("{s}: readFile error -- {s}", .{ path, @errorName(err) }); - } - return err; - }; - } - return Entry{ .contents = file.contents, - .mod_key = mod_key, .fd = if (FeatureFlags.store_file_descriptors) file_handle.handle else 0, }; } @@ -156,42 +126,15 @@ pub const Fs = struct { } } - // If the file's modification key hasn't changed since it was cached, assume - // the contents of the file are also the same and skip reading the file. - var mod_key: ?fs.FileSystem.Implementation.ModKey = rfs.modKeyWithFile(path, file_handle) catch |err| handler: { - switch (err) { - error.FileNotFound, error.AccessDenied => { - return err; - }, - else => { - if (isDebug) { - Output.printError("modkey error: {s}", .{@errorName(err)}); - } - break :handler null; - }, + const file = rfs.readFileWithHandle(path, null, file_handle, use_shared_buffer, &c.shared_buffer) catch |err| { + if (isDebug) { + Output.printError("{s}: readFile error -- {s}", .{ path, @errorName(err) }); } + return err; }; - var file: fs.File = undefined; - if (mod_key) |modk| { - file = rfs.readFileWithHandle(path, modk.size, file_handle, use_shared_buffer, &c.shared_buffer) catch |err| { - if (isDebug) { - Output.printError("{s}: readFile error -- {s}", .{ path, @errorName(err) }); - } - return err; - }; - } else { - file = rfs.readFileWithHandle(path, null, file_handle, use_shared_buffer, &c.shared_buffer) catch |err| { - if (isDebug) { - Output.printError("{s}: readFile error -- {s}", .{ path, @errorName(err) }); - } - return err; - }; - } - return Entry{ .contents = file.contents, - .mod_key = mod_key, .fd = if (FeatureFlags.store_file_descriptors) file_handle.handle else 0, }; } diff --git a/src/cli.zig b/src/cli.zig index e26d94f6d..f6c7217af 100644 --- a/src/cli.zig +++ b/src/cli.zig @@ -32,6 +32,8 @@ const BunCommand = @import("./cli/bun_command.zig").BunCommand; const DevCommand = @import("./cli/dev_command.zig").DevCommand; const DiscordCommand = @import("./cli/discord_command.zig").DiscordCommand; const BuildCommand = @import("./cli/build_command.zig").BuildCommand; +const CreateCommand = @import("./cli/create_command.zig").CreateCommand; +const CreateListExamplesCommand = @import("./cli/create_command.zig").CreateListExamplesCommand; const RunCommand = @import("./cli/run_command.zig").RunCommand; var start_time: i128 = undefined; @@ -62,39 +64,7 @@ pub const Cli = struct { }; const LoaderMatcher = strings.ExactSizeMatcher(4); -pub fn ColonListType(comptime t: type, value_resolver: anytype) type { - return struct { - pub fn init(allocator: *std.mem.Allocator, count: usize) !@This() { - var keys = try allocator.alloc(string, count); - var values = try allocator.alloc(t, count); - - return @This(){ .keys = keys, .values = values }; - } - keys: []string, - values: []t, - - pub fn load(self: *@This(), input: []const string) !void { - for (input) |str, i| { - // Support either ":" or "=" as the separator, preferring whichever is first. - // ":" is less confusing IMO because that syntax is used with flags - // but "=" is what esbuild uses and I want this to be somewhat familiar for people using esbuild - const midpoint = std.math.min(strings.indexOfChar(str, ':') orelse std.math.maxInt(usize), strings.indexOfChar(str, '=') orelse std.math.maxInt(usize)); - if (midpoint == std.math.maxInt(usize)) { - return error.InvalidSeparator; - } - - self.keys[i] = str[0..midpoint]; - self.values[i] = try value_resolver(str[midpoint + 1 .. str.len]); - } - } - - pub fn resolve(allocator: *std.mem.Allocator, input: []const string) !@This() { - var list = try init(allocator, input.len); - try list.load(input); - return list; - } - }; -} +const ColonListType = @import("./cli/colon_list_type.zig").ColonListType; pub const LoaderColonList = ColonListType(Api.Loader, Arguments.loader_resolver); pub const DefineColonList = ColonListType(string, Arguments.noop_resolver); @@ -197,7 +167,10 @@ pub const Arguments = struct { pub fn parse(allocator: *std.mem.Allocator, comptime cmd: Command.Tag) !Api.TransformOptions { var diag = clap.Diagnostic{}; - var args = clap.parse(clap.Help, ¶ms, .{ .diagnostic = &diag }) catch |err| { + var args = clap.parse(clap.Help, ¶ms, .{ + .diagnostic = &diag, + .allocator = allocator, + }) catch |err| { // Report useful error and exit diag.report(Output.errorWriter(), err) catch {}; return err; @@ -469,10 +442,11 @@ const HelpCommand = struct { const dirname = std.fs.path.basename(cwd); if (FeatureFlags.dev_only) { const fmt = - \\> <r> <b><green>dev <r><d> ./a.ts ./b.jsx<r> Start a Bun Dev Server - \\> <r> <b><magenta>bun <r><d> ./a.ts ./b.jsx<r> Bundle dependencies of input files into a <r><magenta>.bun<r> - \\> <r> <b><blue>discord<r> Open Bun's Discord server - \\> <r> <b><d>help <r> Print this help menu + \\> <r> <b><green>dev <r><d> ./a.ts ./b.jsx<r> Start a Bun Dev Server + \\> <r> <b><magenta>bun <r><d> ./a.ts ./b.jsx<r> Bundle dependencies of input files into a <r><magenta>.bun<r> + \\> <r> <b><cyan>create <r><d> next ./app<r> Start a new project from a template <d>(shorthand: c)<r> + \\> <r> <b><blue>discord <r> Open Bun's Discord server + \\> <r> <b><d>help <r> Print this help menu \\ ; @@ -485,6 +459,7 @@ const HelpCommand = struct { \\> <r> <b><white>init<r> Setup Bun in \"{s}\" \\> <r> <b><green>dev <r><d> ./a.ts ./b.jsx<r> Start a Bun Dev Server \\<d>*<r> <b><cyan>build <r><d> ./a.ts ./b.jsx<r> Make JavaScript-like code runnable & bundle CSS + \\> <r> <b><cyan>create<r><d> next<r> Use a template from https://github.com/jarred-sumner/bun/tree/main/examples<r> \\> <r> <b><magenta>bun <r><d> ./a.ts ./b.jsx<r> Bundle dependencies of input files into a <r><magenta>.bun<r> \\> <r> <green>run <r><d> ./a.ts <r> Run a JavaScript-like file with Bun.js \\> <r> <b><blue>discord<r> Open Bun's Discord server @@ -544,7 +519,10 @@ pub const Command = struct { pub fn create(allocator: *std.mem.Allocator, log: *logger.Log, comptime command: Command.Tag) anyerror!Context { return Command.Context{ - .args = try Arguments.parse(allocator, command), + .args = if (comptime command != Command.Tag.CreateCommand) + try Arguments.parse(allocator, command) + else + std.mem.zeroes(Api.TransformOptions), .log = log, .start_time = start_time, .allocator = allocator, @@ -561,7 +539,10 @@ pub const Command = struct { return .AutoCommand; } - const next_arg = (args_iter.next(allocator) orelse return .AutoCommand) catch unreachable; + var next_arg = (args_iter.next(allocator) orelse return .AutoCommand) catch unreachable; + while (next_arg[0] == '-') { + next_arg = (args_iter.next(allocator) orelse return .AutoCommand) catch unreachable; + } const first_arg_name = std.mem.span(next_arg); const RootCommandMatcher = strings.ExactSizeMatcher(8); @@ -571,6 +552,7 @@ pub const Command = struct { RootCommandMatcher.case("init") => .InitCommand, RootCommandMatcher.case("bun") => .BunCommand, RootCommandMatcher.case("discord") => .DiscordCommand, + RootCommandMatcher.case("c"), RootCommandMatcher.case("create") => .CreateCommand, RootCommandMatcher.case("b"), RootCommandMatcher.case("build") => .BuildCommand, RootCommandMatcher.case("r"), RootCommandMatcher.case("run") => .RunCommand, @@ -585,6 +567,7 @@ pub const Command = struct { RootCommandMatcher.case("bun") => .BunCommand, RootCommandMatcher.case("discord") => .DiscordCommand, RootCommandMatcher.case("d"), RootCommandMatcher.case("dev") => .DevCommand, + RootCommandMatcher.case("c"), RootCommandMatcher.case("create") => .CreateCommand, RootCommandMatcher.case("help") => .HelpCommand, else => .AutoCommand, @@ -617,6 +600,32 @@ pub const Command = struct { try BuildCommand.exec(ctx); }, + .CreateCommand => { + const ctx = try Command.Context.create(allocator, log, .CreateCommand); + var positionals: [2]string = undefined; + var positional_i: usize = 0; + + var args = try std.process.argsAlloc(allocator); + + if (args.len > 2) { + var remainder = args[2..]; + var remainder_i: usize = 0; + var i: usize = 0; + while (remainder_i < remainder.len and positional_i < positionals.len) : (remainder_i += 1) { + var slice = std.mem.trim(u8, std.mem.span(remainder[remainder_i]), " \t\n;"); + if (slice.len > 0) { + positionals[positional_i] = slice; + positional_i += 1; + } + } + } + var positionals_ = positionals[0..positional_i]; + + switch (positionals_.len) { + 0...1 => try CreateListExamplesCommand.exec(ctx), + else => try CreateCommand.exec(ctx, positionals_), + } + }, .RunCommand => { const ctx = try Command.Context.create(allocator, log, .RunCommand); @@ -661,5 +670,6 @@ pub const Command = struct { RunCommand, AutoCommand, HelpCommand, + CreateCommand, }; }; diff --git a/src/cli/colon_list_type.zig b/src/cli/colon_list_type.zig new file mode 100644 index 000000000..bb243feff --- /dev/null +++ b/src/cli/colon_list_type.zig @@ -0,0 +1,36 @@ +usingnamespace @import("../global.zig"); +const std = @import("std"); + +pub fn ColonListType(comptime t: type, value_resolver: anytype) type { + return struct { + pub fn init(allocator: *std.mem.Allocator, count: usize) !@This() { + var keys = try allocator.alloc(string, count); + var values = try allocator.alloc(t, count); + + return @This(){ .keys = keys, .values = values }; + } + keys: []string, + values: []t, + + pub fn load(self: *@This(), input: []const string) !void { + for (input) |str, i| { + // Support either ":" or "=" as the separator, preferring whichever is first. + // ":" is less confusing IMO because that syntax is used with flags + // but "=" is what esbuild uses and I want this to be somewhat familiar for people using esbuild + const midpoint = std.math.min(strings.indexOfChar(str, ':') orelse std.math.maxInt(usize), strings.indexOfChar(str, '=') orelse std.math.maxInt(usize)); + if (midpoint == std.math.maxInt(usize)) { + return error.InvalidSeparator; + } + + self.keys[i] = str[0..midpoint]; + self.values[i] = try value_resolver(str[midpoint + 1 .. str.len]); + } + } + + pub fn resolve(allocator: *std.mem.Allocator, input: []const string) !@This() { + var list = try init(allocator, input.len); + try list.load(input); + return list; + } + }; +} diff --git a/src/cli/create.sh b/src/cli/create.sh new file mode 100644 index 000000000..dc8ebd708 --- /dev/null +++ b/src/cli/create.sh @@ -0,0 +1 @@ +git add -A . > /dev/null 2>&1; git commit -am "Initial Commit" > /dev/null 2>&1;
\ No newline at end of file diff --git a/src/cli/create_command.zig b/src/cli/create_command.zig new file mode 100644 index 000000000..a96d48624 --- /dev/null +++ b/src/cli/create_command.zig @@ -0,0 +1,1600 @@ +usingnamespace @import("../global.zig"); +const std = @import("std"); + +const lex = @import("../js_lexer.zig"); +const logger = @import("../logger.zig"); +const alloc = @import("../alloc.zig"); +const options = @import("../options.zig"); +const js_parser = @import("../js_parser.zig"); +const js_ast = @import("../js_ast.zig"); +const linker = @import("../linker.zig"); +usingnamespace @import("../ast/base.zig"); +usingnamespace @import("../defines.zig"); +const panicky = @import("../panic_handler.zig"); +const allocators = @import("../allocators.zig"); +const sync = @import(".././sync.zig"); +const Api = @import("../api/schema.zig").Api; +const resolve_path = @import("../resolver/resolve_path.zig"); +const configureTransformOptionsForBun = @import("../javascript/jsc/config.zig").configureTransformOptionsForBun; +const Command = @import("../cli.zig").Command; +const bundler = @import("../bundler.zig"); +const NodeModuleBundle = @import("../node_module_bundle.zig").NodeModuleBundle; +const fs = @import("../fs.zig"); +const URL = @import("../query_string_map.zig").URL; +const HTTPClient = @import("../http_client.zig"); +const ParseJSON = @import("../json_parser.zig").ParseJSON; +const Archive = @import("../libarchive/libarchive.zig").Archive; +const Zlib = @import("../zlib.zig"); +const JSPrinter = @import("../js_printer.zig"); +const DotEnv = @import("../env_loader.zig"); +const NPMClient = @import("../which_npm_client.zig").NPMClient; +const which = @import("../which.zig").which; +const clap = @import("clap"); +const Lock = @import("../lock.zig").Lock; + +const CopyFile = @import("../copy_file.zig"); +var bun_path_buf: [std.fs.MAX_PATH_BYTES]u8 = undefined; + +const libgit2_basename = switch (std.builtin.os.tag) { + .linux => "libgit2.so.26", + .macos => "libgit2.dylib", + .windows => "libgit2.dll", + else => "libgit2.so", +}; + +const global_libgit2_paths = switch (std.builtin.os.tag) { + .macos => if (Environment.isAarch64) + &[][:0]const u8{ + "/opt/homebrew/lib/libgit2.dylib", + "/opt/homebrew/libgit2/lib/libgit2.dylib", + "/usr/local/lib/libgit2.dylib", + "/usr/local/opt/libgit2/lib/libgit2.dylib", + } + else + &[_][:0]const u8{ + "/usr/local/lib/libgit2.dylib", + "/usr/local/opt/libgit2/lib/libgit2.dylib", + }, + + else => &[_][:0]const u8{}, +}; + +// the standard library function for this returns false when statically linking +fn getSelfExeSharedLibPaths(allocator: *std.mem.Allocator) error{OutOfMemory}![][:0]u8 { + const List = std.ArrayList([:0]u8); + const os = std.os; + const Allocator = std.mem.Allocator; + const builtin = std.builtin; + const mem = std.mem; + + switch (builtin.os.tag) { + .linux, + .freebsd, + .netbsd, + .dragonfly, + .openbsd, + => { + var paths = List.init(allocator); + errdefer { + const slice = paths.toOwnedSlice(); + for (slice) |item| { + allocator.free(item); + } + allocator.free(slice); + } + try os.dl_iterate_phdr(&paths, error{OutOfMemory}, struct { + fn callback(info: *os.dl_phdr_info, size: usize, list: *List) !void { + _ = size; + const name = info.dlpi_name orelse return; + if (name[0] == '/') { + const item = try list.allocator.dupeZ(u8, mem.spanZ(name)); + errdefer list.allocator.free(item); + try list.append(item); + } + } + }.callback); + return paths.toOwnedSlice(); + }, + .macos, .ios, .watchos, .tvos => { + var paths = List.init(allocator); + errdefer { + const slice = paths.toOwnedSlice(); + for (slice) |item| { + allocator.free(item); + } + allocator.free(slice); + } + const img_count = std.c._dyld_image_count(); + var i: u32 = 0; + while (i < img_count) : (i += 1) { + const name = std.c._dyld_get_image_name(i); + const item = try allocator.dupeZ(u8, mem.spanZ(name)); + errdefer allocator.free(item); + try paths.append(item); + } + return paths.toOwnedSlice(); + }, + // revisit if Haiku implements dl_iterat_phdr (https://dev.haiku-os.org/ticket/15743) + .haiku => { + var paths = List.init(allocator); + errdefer { + const slice = paths.toOwnedSlice(); + for (slice) |item| { + allocator.free(item); + } + allocator.free(slice); + } + + var b = "/boot/system/runtime_loader"; + const item = try allocator.dupeZ(u8, mem.spanZ(b)); + errdefer allocator.free(item); + try paths.append(item); + + return paths.toOwnedSlice(); + }, + else => @compileError("getSelfExeSharedLibPaths unimplemented for this target"), + } +} + +const skip_dirs = &[_]string{ "node_modules", ".git" }; +const skip_files = &[_]string{ + "package-lock.json", + "yarn.lock", + "pnpm-lock.yaml", +}; + +const never_conflict = &[_]string{ + "README.md", + "gitignore", + ".gitignore", + ".git/", +}; + +const npm_task_args = &[_]string{ + "exec", +}; + +var bun_path: ?[:0]const u8 = null; +fn execTask(allocator: *std.mem.Allocator, task_: string, cwd: string, PATH: string, npm_client: NPMClient) void { + const task = std.mem.trim(u8, task_, " \n\r\t"); + if (task.len == 0) return; + + var splitter = std.mem.split(u8, task, " "); + var count: usize = 0; + while (splitter.next() != null) { + count += 1; + } + + const npm_args = 2; + const total = count + npm_args; + var argv = allocator.alloc(string, total) catch return; + defer allocator.free(argv); + + argv[0] = npm_client.bin; + argv[1] = npm_task_args[0]; + + { + var i: usize = 2; + + splitter = std.mem.split(u8, task, " "); + while (splitter.next()) |split| { + argv[i] = split; + i += 1; + } + } + + if (strings.startsWith(task, "bun ")) { + // TODO: use self exe + if (bun_path orelse which(&bun_path_buf, PATH, cwd, "bun")) |bun_path_| { + bun_path = bun_path_; + argv = argv[npm_args..]; + argv[0] = std.mem.span(bun_path_); + } + } + + Output.pretty("\n<r><d>$<b>", .{}); + for (argv) |arg, i| { + if (i > argv.len - 1) { + Output.print(" {s} ", .{arg}); + } else { + Output.print(" {s}", .{arg}); + } + } + Output.pretty("<r>", .{}); + Output.print("\n", .{}); + Output.flush(); + + Output.disableBuffering(); + defer Output.enableBuffering(); + + var proc = std.ChildProcess.init(argv, allocator) catch return; + defer proc.deinit(); + proc.stdin_behavior = .Inherit; + proc.stdout_behavior = .Inherit; + proc.stderr_behavior = .Inherit; + proc.cwd = cwd; + _ = proc.spawnAndWait() catch undefined; +} + +// We don't want to allocate memory each time +// But we cannot print over an existing buffer or weird stuff will happen +// so we keep two and switch between them +pub const ProgressBuf = struct { + var bufs: [2][1024]u8 = [2][1024]u8{ + @as([1024]u8, undefined), + @as([1024]u8, undefined), + }; + + var buf_index: usize = 0; + + pub fn print(comptime fmt: string, args: anytype) !string { + buf_index += 1; + return try std.fmt.bufPrint(std.mem.span(&bufs[buf_index % 2]), fmt, args); + } +}; + +const CreateOptions = struct { + npm_client: ?NPMClient.Tag = null, + skip_install: bool = false, + overwrite: bool = false, + skip_git: bool = false, + verbose: bool = false, + + const params = [_]clap.Param(clap.Help){ + clap.parseParam("--help Print this menu") catch unreachable, + clap.parseParam("--npm Use npm for tasks & install") catch unreachable, + clap.parseParam("--yarn Use yarn for tasks & install") catch unreachable, + clap.parseParam("--pnpm Use pnpm for tasks & install") catch unreachable, + clap.parseParam("--force Overwrite existing files") catch unreachable, + clap.parseParam("--no-install Don't install node_modules") catch unreachable, + clap.parseParam("--no-git Don't create a git repository") catch unreachable, + clap.parseParam("--verbose Too many logs") catch unreachable, + clap.parseParam("<POS>... ") catch unreachable, + }; + + pub fn parse(allocator: *std.mem.Allocator, comptime print_flags_only: bool) !CreateOptions { + var diag = clap.Diagnostic{}; + + var args = clap.parse(clap.Help, ¶ms, .{ .diagnostic = &diag, .allocator = allocator }) catch |err| { + // Report useful error and exit + diag.report(Output.errorWriter(), err) catch {}; + return err; + }; + + if (args.flag("--help") or comptime print_flags_only) { + if (comptime print_flags_only) { + clap.help(Output.writer(), params[1..]) catch {}; + return undefined; + } + + Output.prettyln("<r><b>bun create<r> flags:\n", .{}); + Output.flush(); + clap.help(Output.writer(), params[1..]) catch {}; + Output.flush(); + std.os.exit(0); + } + + var opts = CreateOptions{}; + if (args.flag("--npm")) { + opts.npm_client = NPMClient.Tag.npm; + } + + if (args.flag("--yarn")) { + opts.npm_client = NPMClient.Tag.yarn; + } + + if (args.flag("--pnpm")) { + opts.npm_client = NPMClient.Tag.pnpm; + } + + opts.verbose = args.flag("--verbose"); + opts.skip_install = args.flag("--no-install"); + opts.skip_git = args.flag("--no-git"); + opts.overwrite = args.flag("--force"); + + return opts; + } +}; + +const BUN_CREATE_DIR = ".bun-create"; +var home_dir_buf: [std.fs.MAX_PATH_BYTES]u8 = undefined; +pub const CreateCommand = struct { + var client: HTTPClient = undefined; + + pub fn exec(ctx: Command.Context, positionals: []const []const u8) !void { + var create_options = try CreateOptions.parse(ctx.allocator, false); + + var filesystem = try fs.FileSystem.init1(ctx.allocator, null); + var env_loader: DotEnv.Loader = brk: { + var map = try ctx.allocator.create(DotEnv.Map); + map.* = DotEnv.Map.init(ctx.allocator); + + break :brk DotEnv.Loader.init(map, ctx.allocator); + }; + + env_loader.loadProcess(); + + const template = brk: { + var positional = positionals[0]; + + if (!std.fs.path.isAbsolute(positional)) { + outer: { + if (env_loader.map.get("BUN_CREATE_DIR")) |home_dir| { + var parts = [_]string{ home_dir, positional }; + var outdir_path = filesystem.absBuf(&parts, &home_dir_buf); + home_dir_buf[outdir_path.len] = 0; + var outdir_path_ = home_dir_buf[0..outdir_path.len :0]; + std.fs.accessAbsoluteZ(outdir_path_, .{}) catch break :outer; + if (create_options.verbose) { + Output.prettyErrorln("reading from {s}", .{outdir_path}); + } + break :brk outdir_path; + } + } + + outer: { + var parts = [_]string{ filesystem.top_level_dir, BUN_CREATE_DIR, positional }; + var outdir_path = filesystem.absBuf(&parts, &home_dir_buf); + home_dir_buf[outdir_path.len] = 0; + var outdir_path_ = home_dir_buf[0..outdir_path.len :0]; + std.fs.accessAbsoluteZ(outdir_path_, .{}) catch break :outer; + if (create_options.verbose) { + Output.prettyErrorln("reading from {s}", .{outdir_path}); + } + break :brk outdir_path; + } + + outer: { + if (env_loader.map.get("HOME")) |home_dir| { + var parts = [_]string{ home_dir, BUN_CREATE_DIR, positional }; + var outdir_path = filesystem.absBuf(&parts, &home_dir_buf); + home_dir_buf[outdir_path.len] = 0; + var outdir_path_ = home_dir_buf[0..outdir_path.len :0]; + std.fs.accessAbsoluteZ(outdir_path_, .{}) catch break :outer; + if (create_options.verbose) { + Output.prettyErrorln("reading from {s}", .{outdir_path}); + } + break :brk outdir_path; + } + } + } + + break :brk positional; + }; + const dirname = positionals[1]; + var filename_writer = filesystem.dirname_store; + const destination = try filesystem.dirname_store.append([]const u8, resolve_path.joinAbs(filesystem.top_level_dir, .auto, dirname)); + + var progress = std.Progress{}; + var node = try progress.start(try ProgressBuf.print("Loading {s}", .{template}), 0); + progress.supports_ansi_escape_codes = Output.enable_ansi_colors; + + // alacritty is fast + if (env_loader.map.get("ALACRITTY_LOG") != null) { + progress.refresh_rate_ns = std.time.ns_per_ms * 8; + + if (create_options.verbose) { + Output.prettyErrorln("your using alacritty", .{}); + } + } + + defer { + progress.refresh(); + } + + var package_json_contents: MutableString = undefined; + var package_json_file: std.fs.File = undefined; + + const is_remote_template = !std.fs.path.isAbsolute(template); + + if (create_options.verbose) { + Output.prettyErrorln("is_remote_template {d}", .{@boolToInt(is_remote_template)}); + } + + if (is_remote_template) { + var tarball_bytes: MutableString = Example.fetch(ctx, template, &progress, node) catch |err| { + switch (err) { + error.HTTPForbidden, error.ExampleNotFound => { + node.end(); + progress.refresh(); + + Output.prettyError("\n<r><red>error:<r> <b>\"{s}\"<r> was not found. Here are templates you can use:\n\n", .{ + template, + }); + Output.flush(); + + const examples = try Example.fetchAllLocalAndRemote(ctx, null, &env_loader, filesystem); + Example.print(examples.items, dirname); + Output.flush(); + std.os.exit(1); + }, + else => { + return err; + }, + } + }; + + node.name = try ProgressBuf.print("Decompressing {s}", .{template}); + node.setCompletedItems(0); + node.setEstimatedTotalItems(0); + + progress.refresh(); + + var file_buf = try ctx.allocator.alloc(u8, 16384); + + var tarball_buf_list = std.ArrayListUnmanaged(u8){ .capacity = file_buf.len, .items = file_buf }; + var gunzip = try Zlib.ZlibReaderArrayList.init(tarball_bytes.list.items, &tarball_buf_list, ctx.allocator); + try gunzip.readAll(); + gunzip.deinit(); + + node.name = try ProgressBuf.print("Extracting {s}", .{template}); + node.setCompletedItems(0); + node.setEstimatedTotalItems(0); + + progress.refresh(); + + var pluckers = [_]Archive.Plucker{ + try Archive.Plucker.init("package.json", 2048, ctx.allocator), + try Archive.Plucker.init("GETTING_STARTED", 512, ctx.allocator), + }; + + var archive_context = Archive.Context{ + .pluckers = &pluckers, + .all_files = undefined, + .overwrite_list = std.StringArrayHashMap(void).init(ctx.allocator), + }; + + if (!create_options.overwrite) { + try Archive.getOverwritingFileList( + tarball_buf_list.items, + destination, + &archive_context, + @TypeOf(filesystem.dirname_store), + filesystem.dirname_store, + 1, + ); + + inline for (never_conflict) |never_conflict_path| { + _ = archive_context.overwrite_list.swapRemove(never_conflict_path); + } + + if (archive_context.overwrite_list.count() > 0) { + node.end(); + progress.refresh(); + + // Thank you create-react-app for this copy (and idea) + Output.prettyErrorln( + "<r><red>error<r><d>: <r>The directory <b><blue>{s}<r>/ contains files that could conflict:\n\n", + .{ + std.fs.path.basename(destination), + }, + ); + for (archive_context.overwrite_list.keys()) |path| { + if (strings.endsWith(path, std.fs.path.sep_str)) { + Output.prettyError("<r> <blue>{s}<r>", .{path[0 .. std.math.max(path.len, 1) - 1]}); + Output.prettyErrorln(std.fs.path.sep_str, .{}); + } else { + Output.prettyErrorln("<r> {s}", .{path}); + } + } + Output.flush(); + std.os.exit(1); + } + } + + const extracted_file_count = try Archive.extractToDisk( + tarball_buf_list.items, + destination, + &archive_context, + void, + void{}, + 1, + false, + false, + ); + + var plucker = pluckers[0]; + + if (!plucker.found or plucker.fd == 0) { + node.end(); + + Output.prettyErrorln("package.json not found. This package is corrupt. Please try again or file an issue if it keeps happening.", .{}); + Output.flush(); + std.os.exit(1); + } + + node.name = "Updating package.json"; + progress.refresh(); + + package_json_contents = plucker.contents; + package_json_file = std.fs.File{ .handle = plucker.fd }; + } else { + var template_parts = [_]string{template}; + + node.name = "Copying files"; + progress.refresh(); + + const template_dir = std.fs.openDirAbsolute(filesystem.abs(&template_parts), .{ .iterate = true }) catch |err| { + node.end(); + progress.refresh(); + + Output.prettyErrorln("<r><red>{s}<r>: opening dir {s}", .{ @errorName(err), template }); + Output.flush(); + std.os.exit(1); + }; + + std.fs.deleteTreeAbsolute(destination) catch {}; + const destination_dir = std.fs.cwd().makeOpenPath(destination, .{ .iterate = true }) catch |err| { + node.end(); + + progress.refresh(); + + Output.prettyErrorln("<r><red>{s}<r>: creating dir {s}", .{ @errorName(err), destination }); + Output.flush(); + std.os.exit(1); + }; + + const Walker = @import("../walker_skippable.zig"); + var walker_ = try Walker.walk(template_dir, ctx.allocator, skip_files, skip_dirs); + defer walker_.deinit(); + + var count: usize = 0; + + const FileCopier = struct { + pub fn copy( + destination_dir_: std.fs.Dir, + walker: *Walker, + node_: *std.Progress.Node, + progress_: *std.Progress, + ) !void { + while (try walker.next()) |entry| { + // TODO: make this not walk these folders entirely + // rather than checking each file path..... + if (entry.kind != .File) continue; + + var outfile = destination_dir_.createFile(entry.path, .{}) catch brk: { + if (std.fs.path.dirname(entry.path)) |entry_dirname| { + destination_dir_.makePath(entry_dirname) catch {}; + } + break :brk destination_dir_.createFile(entry.path, .{}) catch |err| { + node_.end(); + + progress_.refresh(); + + Output.prettyErrorln("<r><red>{s}<r>: copying file {s}", .{ @errorName(err), entry.path }); + Output.flush(); + std.os.exit(1); + }; + }; + defer outfile.close(); + defer node_.completeOne(); + + var infile = try entry.dir.openFile(entry.basename, .{ .read = true }); + defer infile.close(); + + // Assumption: you only really care about making sure something that was executable is still executable + const stat = infile.stat() catch continue; + _ = C.fchmod(outfile.handle, stat.mode); + + CopyFile.copy(infile.handle, outfile.handle) catch { + entry.dir.copyFile(entry.basename, destination_dir_, entry.path, .{}) catch |err| { + node_.end(); + + progress_.refresh(); + + Output.prettyErrorln("<r><red>{s}<r>: copying file {s}", .{ @errorName(err), entry.path }); + Output.flush(); + std.os.exit(1); + }; + }; + } + } + }; + + try FileCopier.copy(destination_dir, &walker_, node, &progress); + + package_json_file = destination_dir.openFile("package.json", .{ .read = true, .write = true }) catch |err| { + node.end(); + + progress.refresh(); + + Output.prettyErrorln("Failed to open package.json due to error <r><red>{s}", .{@errorName(err)}); + Output.flush(); + std.os.exit(1); + }; + const stat = package_json_file.stat() catch |err| { + node.end(); + + progress.refresh(); + + Output.prettyErrorln("Failed to stat package.json due to error <r><red>{s}", .{@errorName(err)}); + Output.flush(); + std.os.exit(1); + }; + + if (stat.kind != .File or stat.size == 0) { + node.end(); + + progress.refresh(); + + Output.prettyErrorln("package.json must be a file with content", .{}); + Output.flush(); + std.os.exit(1); + } + package_json_contents = try MutableString.init(ctx.allocator, stat.size); + package_json_contents.list.expandToCapacity(); + + _ = package_json_file.preadAll(package_json_contents.list.items, 0) catch |err| { + node.end(); + + progress.refresh(); + + Output.prettyErrorln("Error reading package.json: <r><red>{s}", .{@errorName(err)}); + Output.flush(); + std.os.exit(1); + }; + // The printer doesn't truncate, so we must do so manually + std.os.ftruncate(package_json_file.handle, 0) catch {}; + + js_ast.Expr.Data.Store.create(default_allocator); + js_ast.Stmt.Data.Store.create(default_allocator); + } + + node.end(); + progress.refresh(); + + var source = logger.Source.initPathString("package.json", package_json_contents.list.items); + var package_json_expr = ParseJSON(&source, ctx.log, ctx.allocator) catch |err| { + Output.prettyErrorln("package.json failed to parse with error: {s}", .{@errorName(err)}); + Output.flush(); + std.os.exit(1); + }; + + if (ctx.log.errors > 0) { + if (Output.enable_ansi_colors) { + try ctx.log.printForLogLevelWithEnableAnsiColors(Output.errorWriter(), true); + } else { + try ctx.log.printForLogLevelWithEnableAnsiColors(Output.errorWriter(), false); + } + + Output.flush(); + std.os.exit(1); + } + + if (package_json_expr.asProperty("name")) |name_expr| { + if (name_expr.expr.data != .e_string) { + Output.prettyErrorln("package.json failed to parse correctly. its missing a name. it shouldnt be missing a name.", .{}); + Output.flush(); + std.os.exit(1); + } + + var basename = std.fs.path.basename(destination); + name_expr.expr.data.e_string.utf8 = @intToPtr([*]u8, @ptrToInt(basename.ptr))[0..basename.len]; + } else { + Output.prettyErrorln("package.json failed to parse correctly. its missing a name. it shouldnt be missing a name.", .{}); + Output.flush(); + std.os.exit(1); + } + + package_json_expr.data.e_object.is_single_line = false; + + var preinstall_tasks = std.mem.zeroes(std.ArrayListUnmanaged([]const u8)); + var postinstall_tasks = std.mem.zeroes(std.ArrayListUnmanaged([]const u8)); + + var has_dependencies: bool = false; + + { + var i: usize = 0; + var property_i: usize = 0; + while (i < package_json_expr.data.e_object.properties.len) : (i += 1) { + const property = package_json_expr.data.e_object.properties[i]; + const key = property.key.?.asString(ctx.allocator).?; + + has_dependencies = has_dependencies or + ((strings.eqlComptime(key, "dependencies") or + strings.eqlComptime(key, "devDependencies") or + std.mem.indexOf(u8, key, "optionalDependencies") != null or + strings.eqlComptime(key, "peerDependencies")) and + (property.value.?.data == .e_object and property.value.?.data.e_object.properties.len > 0)); + + if (key.len == 0 or !strings.eqlComptime(key, "bun-create")) { + package_json_expr.data.e_object.properties[property_i] = property; + property_i += 1; + continue; + } + + var value = property.value.?; + if (value.asProperty("postinstall")) |postinstall| { + switch (postinstall.expr.data) { + .e_string => |single_task| { + try postinstall_tasks.append( + ctx.allocator, + try single_task.string(ctx.allocator), + ); + }, + .e_array => |tasks| { + for (tasks.items) |task| { + if (task.asString(ctx.allocator)) |task_entry| { + try postinstall_tasks.append( + ctx.allocator, + task_entry, + ); + } + } + }, + else => {}, + } + } + + if (value.asProperty("preinstall")) |preinstall| { + switch (preinstall.expr.data) { + .e_string => |single_task| { + try preinstall_tasks.append( + ctx.allocator, + try single_task.string(ctx.allocator), + ); + }, + .e_array => |tasks| { + for (tasks.items) |task| { + if (task.asString(ctx.allocator)) |task_entry| { + try preinstall_tasks.append( + ctx.allocator, + task_entry, + ); + } + } + }, + else => {}, + } + } + } + package_json_expr.data.e_object.properties = package_json_expr.data.e_object.properties[0..property_i]; + } + + if (create_options.verbose) { + Output.prettyErrorln("Has dependencies? {d}", .{@boolToInt(has_dependencies)}); + } + + var package_json_writer = JSPrinter.NewFileWriter(package_json_file); + + _ = JSPrinter.printJSON(@TypeOf(package_json_writer), package_json_writer, package_json_expr, &source) catch |err| { + Output.prettyErrorln("package.json failed to write due to error {s}", .{@errorName(err)}); + Output.flush(); + std.os.exit(1); + }; + + { + var parent_dir = try std.fs.openDirAbsolute(destination, .{}); + defer parent_dir.close(); + std.os.linkat(parent_dir.fd, "gitignore", parent_dir.fd, ".gitignore", 0) catch {}; + std.os.unlinkat( + parent_dir.fd, + "gitignore", + 0, + ) catch {}; + std.os.unlinkat( + parent_dir.fd, + ".npmignore", + 0, + ) catch {}; + } + + const PATH = env_loader.map.get("PATH") orelse ""; + + var npm_client_: ?NPMClient = null; + create_options.skip_install = create_options.skip_install or !has_dependencies; + + if (!create_options.skip_git) { + if (!create_options.skip_install) { + GitHandler.spawn(destination, PATH, create_options.verbose); + } else { + if (create_options.verbose) { + create_options.skip_git = GitHandler.run(destination, PATH, true) catch false; + } else { + create_options.skip_git = GitHandler.run(destination, PATH, false) catch false; + } + } + } + + if (!create_options.skip_install) { + if (env_loader.map.get("NPM_CLIENT")) |npm_client_bin| { + npm_client_ = NPMClient{ .tag = .npm, .bin = npm_client_bin }; + } else if (PATH.len > 0) { + var realpath_buf: [std.fs.MAX_PATH_BYTES]u8 = undefined; + + if (create_options.npm_client) |tag| { + if (which(&realpath_buf, PATH, destination, @tagName(tag))) |bin| { + npm_client_ = NPMClient{ .tag = tag, .bin = try ctx.allocator.dupe(u8, bin) }; + } + } else if (try NPMClient.detect(ctx.allocator, &realpath_buf, PATH, destination, true)) |npmclient| { + npm_client_ = NPMClient{ + .bin = try ctx.allocator.dupe(u8, npmclient.bin), + .tag = npmclient.tag, + }; + } + } + } + + if (npm_client_ != null and preinstall_tasks.items.len > 0) { + for (preinstall_tasks.items) |task, i| { + execTask(ctx.allocator, task, destination, PATH, npm_client_.?); + } + } + + if (npm_client_) |npm_client| { + const start_time = std.time.nanoTimestamp(); + const install_args_ = [_]string{ npm_client.bin, "install", "--loglevel=error", "--no-fund", "--no-audit" }; + const len: usize = switch (npm_client.tag) { + .npm => install_args_.len, + else => 2, + }; + + const install_args = install_args_[0..len]; + Output.flush(); + Output.pretty("\n<r><d>$ <b><cyan>{s}<r><d> install", .{@tagName(npm_client.tag)}); + var writer = Output.writer(); + + if (install_args.len > 2) { + for (install_args[2..]) |arg| { + Output.pretty(" ", .{}); + Output.pretty("{s}", .{arg}); + } + } + + Output.pretty("<r>\n", .{}); + Output.flush(); + + var process = try std.ChildProcess.init(install_args, ctx.allocator); + process.cwd = destination; + + defer { + Output.printErrorln("\n", .{}); + Output.printStartEnd(start_time, std.time.nanoTimestamp()); + Output.prettyError(" <r><d>{s} install<r>\n", .{@tagName(npm_client.tag)}); + Output.flush(); + + Output.print("\n", .{}); + Output.flush(); + } + defer process.deinit(); + + var term = try process.spawnAndWait(); + + _ = process.kill() catch undefined; + } else if (!create_options.skip_install) { + progress.log("Failed to detect npm client. Tried pnpm, yarn, and npm.\n", .{}); + } + + if (npm_client_ != null and !create_options.skip_install and postinstall_tasks.items.len > 0) { + for (postinstall_tasks.items) |task, i| { + execTask(ctx.allocator, task, destination, PATH, npm_client_.?); + } + } + + if (!create_options.skip_install and !create_options.skip_git) { + create_options.skip_git = !GitHandler.wait(); + } + + Output.printError("\n", .{}); + Output.printStartEnd(ctx.start_time, std.time.nanoTimestamp()); + Output.prettyErrorln(" <r><d>bun create {s}<r>", .{template}); + Output.flush(); + + if (!create_options.skip_install) { + Output.pretty( + \\ + \\<r><d>-----<r> + \\ + , .{}); + } + + if (!create_options.skip_git and !create_options.skip_install) { + Output.pretty( + \\ + \\<d>A local git repository was created for you and dependencies were installed automatically.<r> + \\ + , .{}); + } else if (!create_options.skip_git) { + Output.pretty( + \\ + \\<d>A local git repository was created for you.<r> + \\ + , .{}); + } else if (!create_options.skip_install) { + Output.pretty( + \\ + \\<d>Dependencies were installed automatically.<r> + \\ + , .{}); + } + + Output.pretty( + \\ + \\<b>Created <green>{s}<r> project successfully + \\ + \\<d>#<r><b> To get started, run:<r> + \\ + \\ <b><cyan>cd {s}<r> + \\ <b><cyan>bun<r> + \\ + , .{ + std.fs.path.basename(template), + filesystem.relativeTo(destination), + }); + + Output.flush(); + } +}; +const Commands = .{ + &[_]string{""}, + &[_]string{""}, + &[_]string{""}, +}; +const picohttp = @import("picohttp"); + +const PackageDownloadThread = struct { + thread: std.Thread, + client: HTTPClient, + tarball_url: string, + allocator: *std.mem.Allocator, + buffer: MutableString, + done: std.atomic.Atomic(u32), + response: picohttp.Response = undefined, + + pub fn threadHandler(this: *PackageDownloadThread) !void { + this.done.store(0, .Release); + this.response = try this.client.send("", &this.buffer); + this.done.store(1, .Release); + std.Thread.Futex.wake(&this.done, 1); + } + + pub fn spawn(allocator: *std.mem.Allocator, tarball_url: string, progress_node: *std.Progress.Node) !*PackageDownloadThread { + var download = try allocator.create(PackageDownloadThread); + download.* = PackageDownloadThread{ + .allocator = allocator, + .client = HTTPClient.init(allocator, .GET, URL.parse(tarball_url), .{}, ""), + .tarball_url = tarball_url, + .buffer = try MutableString.init(allocator, 1024), + .done = std.atomic.Atomic(u32).init(0), + .thread = undefined, + }; + + if (Output.enable_ansi_colors) { + download.client.progress_node = progress_node; + } + + download.thread = try std.Thread.spawn(.{}, threadHandler, .{download}); + + return download; + } +}; + +pub const DownloadedExample = struct { + tarball_bytes: MutableString, + example: Example, +}; + +pub const Example = struct { + name: string, + version: string, + description: string, + local: bool = false, + + var client: HTTPClient = undefined; + const examples_url: string = "https://registry.npmjs.org/bun-examples-all/latest"; + var url: URL = undefined; + pub const timeout: u32 = 6000; + + var app_name_buf: [512]u8 = undefined; + pub fn print(examples: []const Example, default_app_name: ?string) void { + for (examples) |example, i| { + var app_name = default_app_name orelse (std.fmt.bufPrint(&app_name_buf, "./{s}-app", .{example.name[0..std.math.min(example.name.len, 492)]}) catch unreachable); + + if (example.description.len > 0) { + Output.pretty(" <r># {s}<r>\n <b>bun create <cyan>{s}<r><b> {s}<r>\n<d> \n\n", .{ + example.description, + example.name, + app_name, + }); + } else { + Output.pretty(" <r><b>bun create <cyan>{s}<r><b> {s}<r>\n\n", .{ + example.name, + app_name, + }); + } + } + } + + pub fn fetchAllLocalAndRemote(ctx: Command.Context, node: ?*std.Progress.Node, env_loader: *DotEnv.Loader, filesystem: *fs.FileSystem) !std.ArrayList(Example) { + const remote_examples = try Example.fetchAll(ctx, node); + if (node) |node_| node_.end(); + + var examples = std.ArrayList(Example).fromOwnedSlice(ctx.allocator, remote_examples); + { + var folders = [3]std.fs.Dir{ std.fs.Dir{ .fd = 0 }, std.fs.Dir{ .fd = 0 }, std.fs.Dir{ .fd = 0 } }; + if (env_loader.map.get("BUN_CREATE_DIR")) |home_dir| { + var parts = [_]string{home_dir}; + var outdir_path = filesystem.absBuf(&parts, &home_dir_buf); + folders[0] = std.fs.openDirAbsolute(outdir_path, .{ .iterate = true }) catch std.fs.Dir{ .fd = 0 }; + } + + { + var parts = [_]string{ filesystem.top_level_dir, BUN_CREATE_DIR }; + var outdir_path = filesystem.absBuf(&parts, &home_dir_buf); + folders[1] = std.fs.openDirAbsolute(outdir_path, .{ .iterate = true }) catch std.fs.Dir{ .fd = 0 }; + } + + if (env_loader.map.get("HOME")) |home_dir| { + var parts = [_]string{ home_dir, BUN_CREATE_DIR }; + var outdir_path = filesystem.absBuf(&parts, &home_dir_buf); + folders[2] = std.fs.openDirAbsolute(outdir_path, .{ .iterate = true }) catch std.fs.Dir{ .fd = 0 }; + } + + // subfolders with package.json + for (folders) |folder_| { + if (folder_.fd != 0) { + const folder: std.fs.Dir = folder_; + var iter = folder.iterate(); + + loop: while (iter.next() catch null) |entry_| { + const entry: std.fs.Dir.Entry = entry_; + + switch (entry.kind) { + .Directory => { + inline for (skip_dirs) |skip_dir| { + if (strings.eqlComptime(entry.name, skip_dir)) { + continue :loop; + } + } + + std.mem.copy(u8, &home_dir_buf, entry.name); + home_dir_buf[entry.name.len] = std.fs.path.sep; + std.mem.copy(u8, home_dir_buf[entry.name.len + 1 ..], "package.json"); + home_dir_buf[entry.name.len + 1 + "package.json".len] = 0; + + var path: [:0]u8 = home_dir_buf[0 .. entry.name.len + 1 + "package.json".len :0]; + + folder.accessZ(path, .{ + .read = true, + }) catch continue :loop; + + try examples.append( + Example{ + .name = try filesystem.filename_store.append(@TypeOf(entry.name), entry.name), + .version = "", + .local = true, + .description = "", + }, + ); + continue :loop; + }, + else => continue, + } + } + } + } + } + + return examples; + } + + pub fn fetch(ctx: Command.Context, name: string, refresher: *std.Progress, progress: *std.Progress.Node) !MutableString { + progress.name = "Fetching package.json"; + refresher.refresh(); + + const example_start = std.time.nanoTimestamp(); + var url_buf: [1024]u8 = undefined; + var mutable = try MutableString.init(ctx.allocator, 2048); + + url = URL.parse(try std.fmt.bufPrint(&url_buf, "https://registry.npmjs.org/@bun-examples/{s}/latest", .{name})); + client = HTTPClient.init(ctx.allocator, .GET, url, .{}, ""); + client.timeout = timeout; + client.progress_node = progress; + var response = try client.send("", &mutable); + + switch (response.status_code) { + 404 => return error.ExampleNotFound, + 403 => return error.HTTPForbidden, + 429 => return error.HTTPTooManyRequests, + 499...599 => return error.NPMIsDown, + 200 => {}, + else => return error.HTTPError, + } + + progress.name = "Parsing package.json"; + refresher.refresh(); + js_ast.Expr.Data.Store.create(default_allocator); + js_ast.Stmt.Data.Store.create(default_allocator); + + var source = logger.Source.initPathString("package.json", mutable.list.items); + var expr = ParseJSON(&source, ctx.log, ctx.allocator) catch |err| { + progress.end(); + refresher.refresh(); + + if (ctx.log.errors > 0) { + if (Output.enable_ansi_colors) { + try ctx.log.printForLogLevelWithEnableAnsiColors(Output.errorWriter(), true); + } else { + try ctx.log.printForLogLevelWithEnableAnsiColors(Output.errorWriter(), false); + } + Output.flush(); + std.os.exit(1); + } else { + Output.prettyErrorln("Error parsing package: <r><red>{s}<r>", .{@errorName(err)}); + Output.flush(); + std.os.exit(1); + } + }; + + if (ctx.log.errors > 0) { + progress.end(); + refresher.refresh(); + + if (Output.enable_ansi_colors) { + try ctx.log.printForLogLevelWithEnableAnsiColors(Output.errorWriter(), true); + } else { + try ctx.log.printForLogLevelWithEnableAnsiColors(Output.errorWriter(), false); + } + Output.flush(); + std.os.exit(1); + } + + const tarball_url: string = brk: { + if (expr.asProperty("dist")) |q| { + if (q.expr.asProperty("tarball")) |p| { + if (p.expr.asString(ctx.allocator)) |s| { + if (s.len > 0 and (strings.startsWith(s, "https://") or strings.startsWith(s, "http://"))) { + break :brk s; + } + } + } + } + + progress.end(); + refresher.refresh(); + + Output.prettyErrorln("package.json is missing tarball url. This is an internal error!", .{}); + Output.flush(); + std.os.exit(1); + }; + + progress.name = "Downloading tarball"; + refresher.refresh(); + + var thread: *PackageDownloadThread = try PackageDownloadThread.spawn(ctx.allocator, tarball_url, progress); + refresher.maybeRefresh(); + + while (thread.done.load(.Acquire) == 0) { + std.Thread.Futex.wait(&thread.done, 1, std.time.ns_per_ms * 10000) catch {}; + } + + refresher.maybeRefresh(); + + if (thread.response.status_code != 200) { + progress.end(); + refresher.refresh(); + Output.prettyErrorln("Error fetching tarball: <r><red>{d}<r>", .{thread.response.status_code}); + Output.flush(); + std.os.exit(1); + } + + refresher.refresh(); + thread.thread.join(); + + return thread.buffer; + } + + pub fn fetchAll(ctx: Command.Context, progress_node: ?*std.Progress.Node) ![]Example { + url = URL.parse(examples_url); + client = HTTPClient.init(ctx.allocator, .GET, url, .{}, ""); + client.timeout = timeout; + + if (Output.enable_ansi_colors) { + client.progress_node = progress_node; + } + + var mutable: MutableString = try MutableString.init(ctx.allocator, 1024); + var response = client.send("", &mutable) catch |err| { + switch (err) { + error.WouldBlock => { + Output.prettyErrorln("Request timed out while trying to fetch examples list. Please try again", .{}); + Output.flush(); + std.os.exit(1); + }, + else => { + Output.prettyErrorln("<r><red>{s}<r> while trying to fetch examples list. Please try again", .{@errorName(err)}); + Output.flush(); + std.os.exit(1); + }, + } + }; + + if (response.status_code != 200) { + Output.prettyErrorln("<r><red>{d}<r> fetching examples :( {s}", .{ response.status_code, mutable.list.items }); + Output.flush(); + std.os.exit(1); + } + + js_ast.Expr.Data.Store.create(default_allocator); + js_ast.Stmt.Data.Store.create(default_allocator); + var source = logger.Source.initPathString("examples.json", mutable.list.items); + const examples_object = ParseJSON(&source, ctx.log, ctx.allocator) catch |err| { + if (ctx.log.errors > 0) { + if (Output.enable_ansi_colors) { + try ctx.log.printForLogLevelWithEnableAnsiColors(Output.errorWriter(), true); + } else { + try ctx.log.printForLogLevelWithEnableAnsiColors(Output.errorWriter(), false); + } + std.os.exit(1); + Output.flush(); + } else { + Output.prettyErrorln("Error parsing examples: <r><red>{s}<r>", .{@errorName(err)}); + Output.flush(); + std.os.exit(1); + } + }; + + if (ctx.log.errors > 0) { + if (Output.enable_ansi_colors) { + try ctx.log.printForLogLevelWithEnableAnsiColors(Output.errorWriter(), true); + } else { + try ctx.log.printForLogLevelWithEnableAnsiColors(Output.errorWriter(), false); + } + Output.flush(); + std.os.exit(1); + } + + if (examples_object.asProperty("examples")) |q| { + if (q.expr.data == .e_object) { + var count: usize = 0; + for (q.expr.data.e_object.properties) |property| { + count += 1; + } + + var list = try ctx.allocator.alloc(Example, count); + for (q.expr.data.e_object.properties) |property, i| { + const name = property.key.?.data.e_string.utf8; + list[i] = Example{ + .name = if (std.mem.indexOfScalar(u8, name, '/')) |slash| + name[slash + 1 ..] + else + name, + .version = property.value.?.asProperty("version").?.expr.data.e_string.utf8, + .description = property.value.?.asProperty("description").?.expr.data.e_string.utf8, + }; + } + return list; + } + } + + Output.prettyErrorln("Corrupt examples data: expected object but received {s}", .{@tagName(examples_object.data)}); + Output.flush(); + std.os.exit(1); + } +}; + +pub const CreateListExamplesCommand = struct { + pub fn exec(ctx: Command.Context) !void { + var filesystem = try fs.FileSystem.init1(ctx.allocator, null); + var env_loader: DotEnv.Loader = brk: { + var map = try ctx.allocator.create(DotEnv.Map); + map.* = DotEnv.Map.init(ctx.allocator); + + break :brk DotEnv.Loader.init(map, ctx.allocator); + }; + + env_loader.loadProcess(); + + const time = std.time.nanoTimestamp(); + var progress = std.Progress{}; + var node = try progress.start("Fetching manifest", 0); + progress.refresh(); + + const examples = try Example.fetchAllLocalAndRemote(ctx, node, &env_loader, filesystem); + Output.printStartEnd(time, std.time.nanoTimestamp()); + Output.prettyln(" <d>Fetched manifest<r>", .{}); + Output.prettyln("Welcome to Bun! Create a new project by pasting any of the following:\n\n", .{}); + Output.flush(); + + Example.print(examples.items, null); + + if (env_loader.map.get("HOME")) |homedir| { + Output.prettyln( + "<d>This command is completely optional. To add a new local template, create a folder in {s}/.bun-create/. To publish a new template, git clone https://github.com/jarred-sumner/bun, add a new folder to the \"examples\" folder, and submit a PR.<r>", + .{homedir}, + ); + } else { + Output.prettyln( + "<d>This command is completely optional. To add a new local template, create a folder in $HOME/.bun-create/. To publish a new template, git clone https://github.com/jarred-sumner/bun, add a new folder to the \"examples\" folder, and submit a PR.<r>", + .{}, + ); + } + + Output.flush(); + } +}; + +const GitHandler = struct { + var success: std.atomic.Atomic(u32) = undefined; + var thread: std.Thread = undefined; + pub fn spawn( + destination: string, + PATH: string, + verbose: bool, + ) void { + success = std.atomic.Atomic(u32).init(0); + + thread = std.Thread.spawn(.{}, spawnThread, .{ destination, PATH, verbose }) catch |err| { + Output.prettyErrorln("<r><red>{s}<r>", .{@errorName(err)}); + Output.flush(); + std.os.exit(1); + }; + } + + fn spawnThread( + destination: string, + PATH: string, + verbose: bool, + ) void { + Output.Source.configureThread(); + std.Thread.setName(thread, "git") catch {}; + defer Output.flush(); + const outcome = if (verbose) + run(destination, PATH, true) catch false + else + run(destination, PATH, false) catch false; + + @fence(.Acquire); + success.store( + if (outcome) + 1 + else + 2, + .Release, + ); + std.Thread.Futex.wake(&success, 1); + } + + pub fn wait() bool { + @fence(.Release); + + while (success.load(.Acquire) == 0) { + std.Thread.Futex.wait(&success, 0, 1000) catch continue; + } + + const outcome = success.load(.Acquire) == 1; + thread.join(); + return outcome; + } + + pub fn run( + destination: string, + PATH: string, + comptime verbose: bool, + ) !bool { + const git_start = std.time.nanoTimestamp(); + + // This feature flag is disabled. + // using libgit2 is slower than the CLI. + // [481.00ms] git + // [89.00ms] git + // if (comptime FeatureFlags.use_libgit2) { + // try_to_use_libgit2: { + // if (comptime Environment.isWindows) @compileError("TODO win32"); + + // // since we link libc, it always goes through dlopen unless windows + // const DlDynlib = std.DynLib; + // var libgit2_dylib: std.DynLib = brk: { + // for (global_libgit2_paths) |lib_path| { + // break :brk DlDynlib.openZ(lib_path) catch continue; + // } + + // var lib_paths = getSelfExeSharedLibPaths(default_allocator) catch break :try_to_use_libgit2; + + // // this is a list of every dynamically loaded library on the user's computer? + // for (lib_paths) |lib_path| { + // const basename = std.fs.path.basename(std.mem.span(lib_path)); + // if (basename.len == (comptime libgit2_basename.len) and + // std.hash.Wyhash.hash(10, basename) == comptime std.hash.Wyhash.hash(10, libgit2_basename)) + // { + // break :brk DlDynlib.openZ(lib_path) catch continue; + // } + // } + // break :try_to_use_libgit2; + // }; + + // const libgit2 = @import("../deps/libgit2.zig"); + // var repo: ?*libgit2.git_repository = null; + // // https://libgit2.org/docs/examples/init/ + // // Note: git_threads_init was renamed to git_libgit2_init + // // https://mail.gnome.org/archives/commits-list/2015-January/msg03703.html + // // ...in 2015 and that doc is still out of date + + // const git_repository_init = libgit2_dylib.lookup(libgit2.git_repository_init, "git_repository_init") orelse break :try_to_use_libgit2; + // const git_repository_free = libgit2_dylib.lookup(libgit2.git_repository_free, "git_repository_free") orelse break :try_to_use_libgit2; + // const git_signature_free = libgit2_dylib.lookup(libgit2.git_signature_free, "git_signature_free") orelse break :try_to_use_libgit2; + // const git_signature_default = libgit2_dylib.lookup(libgit2.git_signature_default, "git_signature_default") orelse break :try_to_use_libgit2; + // const git_repository_index = libgit2_dylib.lookup(libgit2.git_repository_index, "git_repository_index") orelse break :try_to_use_libgit2; + // const git_index_read_tree = libgit2_dylib.lookup(libgit2.git_index_read_tree, "git_index_read_tree") orelse break :try_to_use_libgit2; + // const git_index_write_tree = libgit2_dylib.lookup(libgit2.git_index_write_tree, "git_index_write_tree") orelse break :try_to_use_libgit2; + // const git_index_write = libgit2_dylib.lookup(libgit2.git_index_write, "git_index_write") orelse break :try_to_use_libgit2; + + // const git_index_add_all = libgit2_dylib.lookup(libgit2.git_index_add_all, "git_index_add_all") orelse break :try_to_use_libgit2; + // const git_tree_lookup = libgit2_dylib.lookup(libgit2.git_tree_lookup, "git_tree_lookup") orelse break :try_to_use_libgit2; + // const git_commit_create_v = libgit2_dylib.lookup(libgit2.git_commit_create_v, "git_commit_create_v") orelse break :try_to_use_libgit2; + // const git_index_free = libgit2_dylib.lookup(libgit2.git_index_free, "git_index_free") orelse break :try_to_use_libgit2; + // const git_tree_free = libgit2_dylib.lookup(libgit2.git_tree_free, "git_tree_free") orelse break :try_to_use_libgit2; + // const git_index_add_bypath = libgit2_dylib.lookup(libgit2.git_index_add_bypath, "git_index_add_bypath") orelse break :try_to_use_libgit2; + // const git_status_should_ignore = libgit2_dylib.lookup(libgit2.git_status_should_ignore, "git_status_should_ignore") orelse break :try_to_use_libgit2; + + // var sig: ?*libgit2.git_signature = null; + // // var destination_z = destination.ptr[0..destination.len :0]; + // // const original_cwd = std.os.getcwd(&bun_path_buf) catch break :try_to_use_libgit2; + // // bun_path_buf[original_cwd.len] = 0; + // // std.os.chdirZ(destination_z) catch {}; + // // var origin_z = bun_path_buf[0..original_cwd.len :0]; + // // defer std.os.chdirZ(origin_z) catch {}; + + // if (libgit2_dylib.lookup(libgit2.git_libgit2_init, "git_libgit2_init")) |git_libgit2_init| { + // std.debug.assert(git_libgit2_init() > -1); + // } + + // var rc: c_int = 0; + // rc = git_repository_init(&repo, destination.ptr, 0); + // if (rc < 0) break :try_to_use_libgit2; + // var repo_ = repo orelse break :try_to_use_libgit2; + // // defer git_repository_free(repo_); + + // rc = git_signature_default(&sig, repo_); + // // this fails if they never ran git config + // // the child process will fail too, so we just skip + // if (rc < 0) { + // return false; + // } + // // defer git_signature_free(sig.?); + + // var index: ?*libgit2.git_index = null; + // var tree_id: libgit2.git_oid = undefined; + // var commit_id: libgit2.git_oid = undefined; + // var second_commit_id: libgit2.git_oid = undefined; + // var git_tree: *libgit2.git_tree = undefined; + + // rc = git_repository_index(&index, repo_); + // if (rc < 0) break :try_to_use_libgit2; + + // // // add gitignore file first + // // // technically, we should add every gitignore first but i'll leave that as a future TODO + // // if (files_list.containsAdapted(comptime std.hash.Wyhash.hash(0, "gitignore"), Archive.Context.U64Context{})) { + // // rc = git_index_add_bypath(index.?, ".gitignore"); + // // if (rc < 0) break :try_to_use_libgit2; + // // } else if (files_list.containsAdapted(comptime std.hash.Wyhash.hash(0, ".gitignore"), Archive.Context.U64Context{})) { + // // rc = git_index_add_bypath(index.?, ".gitignore"); + // // if (rc < 0) break :try_to_use_libgit2; + // // } + + // var files = files_list.values(); + + // // without git + // // [6.00ms] bun create /Users/jarred/.bun-create/react2 + + // // with git: + // // [44.00ms] bun create /Users/jarred/.bun-create/react2 + + // var strs = std.mem.zeroes(libgit2.git_strarray); + // // var star = [_]u8{ '*', 0 }; + // // var star_ptr: [*c]u8 = ☆ + // strs.strings = files.ptr; + // strs.count = files.len; + // rc = git_index_add_all(index, &strs, libgit2.GIT_INDEX_ADD_DISABLE_PATHSPEC_MATCH, null, null); + // if (rc < 0) break :try_to_use_libgit2; + + // // if (comptime verbose) { + // // for (files) |file| { + // // var ignored: c_int = 0; + // // rc = git_status_should_ignore(&ignored, repo_, file); + // // if (rc < 0) break :try_to_use_libgit2; + // // if (ignored > 0) { + // // Output.prettyErrorln("[libgit2]: ignored {s}", .{std.mem.sliceTo(file, 0)}); + // // continue; + // // } + + // // // this can fail for a variety of reasons + // // // if it does, better to get most of the files than stop + // // rc = git_index_add_bypath(index.?, file); + // // switch (rc) { + // // libgit2.GIT_OK => { + // // Output.prettyErrorln("[libgit2]: Added {s}", .{std.mem.sliceTo(file, 0)}); + // // }, + // // libgit2.GIT_ENOTFOUND => { + // // Output.prettyErrorln("[libgit2]: not found {s}", .{std.mem.sliceTo(file, 0)}); + // // }, + // // else => { + // // Output.prettyErrorln("[libgit2]: error {d} for {s}", .{ rc, std.mem.sliceTo(file, 0) }); + // // }, + // // } + // // } + // // } else { + // // for (files) |file| { + // // var ignored: c_int = 0; + // // rc = git_status_should_ignore(&ignored, repo_, file); + // // if (rc < 0) break :try_to_use_libgit2; + // // if (ignored > 0) continue; + + // // // this can fail for a variety of reasons + // // // if it does, better to get most of the files than stop + // // _ = git_index_add_bypath(index.?, file); + // // } + // // } + + // // if you don't call git_index_write, git status will look very strange. + // rc = git_index_write(index.?); + // if (rc < 0) break :try_to_use_libgit2; + + // rc = git_index_write_tree(&tree_id, index); + // if (rc < 0) break :try_to_use_libgit2; + + // rc = git_tree_lookup(&git_tree, repo_, &tree_id); + // if (rc < 0) break :try_to_use_libgit2; + // // defer git_tree_free(git_tree); + + // rc = git_commit_create_v( + // &commit_id, + // repo_, + // "HEAD", + // sig.?, + // sig.?, + // null, + // "Initial commit (via bun create)", + // git_tree, + // 0, + // ); + // if (rc < 0) break :try_to_use_libgit2; + + // if (comptime verbose) { + // Output.prettyErrorln("git backend: libgit2", .{}); + // } + + // Output.prettyError("\n", .{}); + // Output.printStartEnd(git_start, std.time.nanoTimestamp()); + // Output.prettyError(" <d>git<r>\n", .{}); + + // // success! + // return true; + // } + // } + + if (which(&bun_path_buf, PATH, destination, "git")) |git| { + const git_commands = .{ + &[_]string{ std.mem.span(git), "init", "--quiet" }, + &[_]string{ std.mem.span(git), "add", destination, "--ignore-errors" }, + &[_]string{ std.mem.span(git), "commit", "-am", "\"Initial commit (via bun create)\"", "--quiet" }, + }; + + if (comptime verbose) { + Output.prettyErrorln("git backend: {s}", .{git}); + } + + // same names, just comptime known values + + inline for (comptime std.meta.fieldNames(@TypeOf(Commands))) |command_field| { + const command: []const string = @field(git_commands, command_field); + var process = try std.ChildProcess.init(command, default_allocator); + process.cwd = destination; + process.stdin_behavior = .Inherit; + process.stdout_behavior = .Inherit; + process.stderr_behavior = .Inherit; + defer process.deinit(); + + var term = try process.spawnAndWait(); + _ = process.kill() catch undefined; + } + + Output.prettyError("\n", .{}); + Output.printStartEnd(git_start, std.time.nanoTimestamp()); + Output.prettyError(" <d>git<r>\n", .{}); + return true; + } + + return false; + } +}; diff --git a/src/copy_file.zig b/src/copy_file.zig new file mode 100644 index 000000000..f60638f9f --- /dev/null +++ b/src/copy_file.zig @@ -0,0 +1,50 @@ +const std = @import("std"); +const os = std.os; +const math = std.math; + +const CopyFileError = error{SystemResources} || os.CopyFileRangeError || os.SendFileError; + +// Transfer all the data between two file descriptors in the most efficient way. +// The copy starts at offset 0, the initial offsets are preserved. +// No metadata is transferred over. +pub fn copy(fd_in: os.fd_t, fd_out: os.fd_t) CopyFileError!void { + if (comptime std.Target.current.isDarwin()) { + const rc = os.system.fcopyfile(fd_in, fd_out, null, os.system.COPYFILE_DATA); + switch (os.errno(rc)) { + .SUCCESS => return, + .INVAL => unreachable, + .NOMEM => return error.SystemResources, + // The source file is not a directory, symbolic link, or regular file. + // Try with the fallback path before giving up. + .OPNOTSUPP => {}, + else => |err| return os.unexpectedErrno(err), + } + } + + if (comptime std.Target.current.os.tag == .linux) { + // Try copy_file_range first as that works at the FS level and is the + // most efficient method (if available). + var offset: u64 = 0; + cfr_loop: while (true) { + // The kernel checks the u64 value `offset+count` for overflow, use + // a 32 bit value so that the syscall won't return EINVAL except for + // impossibly large files (> 2^64-1 - 2^32-1). + const amt = try os.copy_file_range(fd_in, offset, fd_out, offset, math.maxInt(u32), 0); + // Terminate when no data was copied + if (amt == 0) break :cfr_loop; + offset += amt; + } + return; + } + + // Sendfile is a zero-copy mechanism iff the OS supports it, otherwise the + // fallback code will copy the contents chunk by chunk. + const empty_iovec = [0]os.iovec_const{}; + var offset: u64 = 0; + sendfile_loop: while (true) { + const amt = try os.sendfile(fd_out, fd_in, offset, 0, &empty_iovec, &empty_iovec, 0); + // Terminate when no data was copied + if (amt == 0) break :sendfile_loop; + offset += amt; + } +} diff --git a/src/deps/libarchive b/src/deps/libarchive new file mode 160000 +Subproject dc321febde83dd0f31158e1be61a7aedda65e7a diff --git a/src/deps/libgit2.zig b/src/deps/libgit2.zig new file mode 100644 index 000000000..06943a99b --- /dev/null +++ b/src/deps/libgit2.zig @@ -0,0 +1,2209 @@ +pub const GIT_FEATURE_THREADS: c_int = 1; +pub const GIT_FEATURE_HTTPS: c_int = 2; +pub const GIT_FEATURE_SSH: c_int = 4; +pub const GIT_FEATURE_NSEC: c_int = 8; +pub const git_feature_t = c_uint; +pub const GIT_OPT_GET_MWINDOW_SIZE: c_int = 0; +pub const GIT_OPT_SET_MWINDOW_SIZE: c_int = 1; +pub const GIT_OPT_GET_MWINDOW_MAPPED_LIMIT: c_int = 2; +pub const GIT_OPT_SET_MWINDOW_MAPPED_LIMIT: c_int = 3; +pub const GIT_OPT_GET_SEARCH_PATH: c_int = 4; +pub const GIT_OPT_SET_SEARCH_PATH: c_int = 5; +pub const GIT_OPT_SET_CACHE_OBJECT_LIMIT: c_int = 6; +pub const GIT_OPT_SET_CACHE_MAX_SIZE: c_int = 7; +pub const GIT_OPT_ENABLE_CACHING: c_int = 8; +pub const GIT_OPT_GET_CACHED_MEMORY: c_int = 9; +pub const GIT_OPT_GET_TEMPLATE_PATH: c_int = 10; +pub const GIT_OPT_SET_TEMPLATE_PATH: c_int = 11; +pub const GIT_OPT_SET_SSL_CERT_LOCATIONS: c_int = 12; +pub const GIT_OPT_SET_USER_AGENT: c_int = 13; +pub const GIT_OPT_ENABLE_STRICT_OBJECT_CREATION: c_int = 14; +pub const GIT_OPT_ENABLE_STRICT_SYMBOLIC_REF_CREATION: c_int = 15; +pub const GIT_OPT_SET_SSL_CIPHERS: c_int = 16; +pub const GIT_OPT_GET_USER_AGENT: c_int = 17; +pub const GIT_OPT_ENABLE_OFS_DELTA: c_int = 18; +pub const GIT_OPT_ENABLE_FSYNC_GITDIR: c_int = 19; +pub const GIT_OPT_GET_WINDOWS_SHAREMODE: c_int = 20; +pub const GIT_OPT_SET_WINDOWS_SHAREMODE: c_int = 21; +pub const GIT_OPT_ENABLE_STRICT_HASH_VERIFICATION: c_int = 22; +pub const GIT_OPT_SET_ALLOCATOR: c_int = 23; +pub const GIT_OPT_ENABLE_UNSAVED_INDEX_SAFETY: c_int = 24; +pub const GIT_OPT_GET_PACK_MAX_OBJECTS: c_int = 25; +pub const GIT_OPT_SET_PACK_MAX_OBJECTS: c_int = 26; +pub const GIT_OPT_DISABLE_PACK_KEEP_FILE_CHECKS: c_int = 27; +pub const GIT_OPT_ENABLE_HTTP_EXPECT_CONTINUE: c_int = 28; +pub const GIT_OPT_GET_MWINDOW_FILE_LIMIT: c_int = 29; +pub const GIT_OPT_SET_MWINDOW_FILE_LIMIT: c_int = 30; +pub const GIT_OPT_SET_ODB_PACKED_PRIORITY: c_int = 31; +pub const GIT_OPT_SET_ODB_LOOSE_PRIORITY: c_int = 32; +pub const GIT_OPT_GET_EXTENSIONS: c_int = 33; +pub const GIT_OPT_SET_EXTENSIONS: c_int = 34; +pub const git_libgit2_opt_t = c_uint; + +pub const git_off_t = i64; +pub const git_time_t = i64; +pub const git_object_size_t = u64; +pub const git_buf = extern struct { + ptr: [*c]u8, + asize: usize, + size: usize, +}; +pub const struct_git_oid = extern struct { + id: [20]u8, +}; +pub const git_oid = struct_git_oid; +pub const struct_git_oid_shorten = opaque {}; +pub const git_oid_shorten = struct_git_oid_shorten; +pub const GIT_OBJECT_ANY: c_int = -2; +pub const GIT_OBJECT_INVALID: c_int = -1; +pub const GIT_OBJECT_COMMIT: c_int = 1; +pub const GIT_OBJECT_TREE: c_int = 2; +pub const GIT_OBJECT_BLOB: c_int = 3; +pub const GIT_OBJECT_TAG: c_int = 4; +pub const GIT_OBJECT_OFS_DELTA: c_int = 6; +pub const GIT_OBJECT_REF_DELTA: c_int = 7; +pub const git_object_t = c_int; +pub const struct_git_odb = opaque {}; +pub const git_odb = struct_git_odb; +pub const struct_git_odb_backend = opaque {}; +pub const git_odb_backend = struct_git_odb_backend; +pub const struct_git_odb_object = opaque {}; +pub const git_odb_object = struct_git_odb_object; +pub const git_odb_stream = struct_git_odb_stream; +pub const struct_git_odb_stream = extern struct { + backend: *git_odb_backend, + mode: c_uint, + hash_ctx: *c_void, + declared_size: git_object_size_t, + received_bytes: git_object_size_t, + read: ?fn ([*c]git_odb_stream, [*c]u8, usize) callconv(.C) c_int, + write: ?fn ([*c]git_odb_stream, [*c]const u8, usize) callconv(.C) c_int, + finalize_write: ?fn ([*c]git_odb_stream, [*c]const git_oid) callconv(.C) c_int, + free: ?fn ([*c]git_odb_stream) callconv(.C) void, +}; +pub const git_odb_writepack = struct_git_odb_writepack; +pub const struct_git_indexer_progress = extern struct { + total_objects: c_uint, + indexed_objects: c_uint, + received_objects: c_uint, + local_objects: c_uint, + total_deltas: c_uint, + indexed_deltas: c_uint, + received_bytes: usize, +}; +pub const git_indexer_progress = struct_git_indexer_progress; +pub const struct_git_odb_writepack = extern struct { + backend: *git_odb_backend, + append: ?fn ([*c]git_odb_writepack, *const c_void, usize, [*c]git_indexer_progress) callconv(.C) c_int, + commit: ?fn ([*c]git_odb_writepack, [*c]git_indexer_progress) callconv(.C) c_int, + free: ?fn ([*c]git_odb_writepack) callconv(.C) void, +}; +pub const struct_git_midx_writer = opaque {}; +pub const git_midx_writer = struct_git_midx_writer; +pub const struct_git_refdb = opaque {}; +pub const git_refdb = struct_git_refdb; +pub const struct_git_refdb_backend = opaque {}; +pub const git_refdb_backend = struct_git_refdb_backend; +pub const struct_git_commit_graph = opaque {}; +pub const git_commit_graph = struct_git_commit_graph; +pub const struct_git_commit_graph_writer = opaque {}; +pub const git_commit_graph_writer = struct_git_commit_graph_writer; +pub const struct_git_repository = opaque {}; +pub const git_repository = struct_git_repository; +pub const struct_git_worktree = opaque {}; +pub const git_worktree = struct_git_worktree; +pub const struct_git_object = opaque {}; +pub const git_object = struct_git_object; +pub const struct_git_revwalk = opaque {}; +pub const git_revwalk = struct_git_revwalk; +pub const struct_git_tag = opaque {}; +pub const git_tag = struct_git_tag; +pub const struct_git_blob = opaque {}; +pub const git_blob = struct_git_blob; +pub const struct_git_commit = opaque {}; +pub const git_commit = struct_git_commit; +pub const struct_git_tree_entry = opaque {}; +pub const git_tree_entry = struct_git_tree_entry; +pub const struct_git_tree = opaque {}; +pub const git_tree = struct_git_tree; +pub const struct_git_treebuilder = opaque {}; +pub const git_treebuilder = struct_git_treebuilder; +pub const struct_git_index = opaque {}; +pub const git_index = struct_git_index; +pub const struct_git_index_iterator = opaque {}; +pub const git_index_iterator = struct_git_index_iterator; +pub const struct_git_index_conflict_iterator = opaque {}; +pub const git_index_conflict_iterator = struct_git_index_conflict_iterator; +pub const struct_git_config = opaque {}; +pub const git_config = struct_git_config; +pub const struct_git_config_backend = opaque {}; +pub const git_config_backend = struct_git_config_backend; +pub const struct_git_reflog_entry = opaque {}; +pub const git_reflog_entry = struct_git_reflog_entry; +pub const struct_git_reflog = opaque {}; +pub const git_reflog = struct_git_reflog; +pub const struct_git_note = opaque {}; +pub const git_note = struct_git_note; +pub const struct_git_packbuilder = opaque {}; +pub const git_packbuilder = struct_git_packbuilder; +pub const struct_git_time = extern struct { + time: git_time_t, + offset: c_int, + sign: u8, +}; +pub const git_time = struct_git_time; +pub const struct_git_signature = extern struct { + name: [*c]u8, + email: [*c]u8, + when: git_time, +}; +pub const git_signature = struct_git_signature; +pub const struct_git_reference = opaque {}; +pub const git_reference = struct_git_reference; +pub const struct_git_reference_iterator = opaque {}; +pub const git_reference_iterator = struct_git_reference_iterator; +pub const struct_git_transaction = opaque {}; +pub const git_transaction = struct_git_transaction; +pub const struct_git_annotated_commit = opaque {}; +pub const git_annotated_commit = struct_git_annotated_commit; +pub const struct_git_status_list = opaque {}; +pub const git_status_list = struct_git_status_list; +pub const struct_git_rebase = opaque {}; +pub const git_rebase = struct_git_rebase; +pub const GIT_REFERENCE_INVALID: c_int = 0; +pub const GIT_REFERENCE_DIRECT: c_int = 1; +pub const GIT_REFERENCE_SYMBOLIC: c_int = 2; +pub const GIT_REFERENCE_ALL: c_int = 3; +pub const git_reference_t = c_uint; +pub const GIT_BRANCH_LOCAL: c_int = 1; +pub const GIT_BRANCH_REMOTE: c_int = 2; +pub const GIT_BRANCH_ALL: c_int = 3; +pub const git_branch_t = c_uint; +pub const GIT_FILEMODE_UNREADABLE: c_int = 0; +pub const GIT_FILEMODE_TREE: c_int = 16384; +pub const GIT_FILEMODE_BLOB: c_int = 33188; +pub const GIT_FILEMODE_BLOB_EXECUTABLE: c_int = 33261; +pub const GIT_FILEMODE_LINK: c_int = 40960; +pub const GIT_FILEMODE_COMMIT: c_int = 57344; +pub const git_filemode_t = c_uint; +pub const struct_git_refspec = opaque {}; +pub const git_refspec = struct_git_refspec; +pub const struct_git_remote = opaque {}; +pub const git_remote = struct_git_remote; +pub const struct_git_transport = opaque {}; +pub const git_transport = struct_git_transport; +pub const struct_git_push = opaque {}; +pub const git_push = struct_git_push; +pub const struct_git_remote_head = extern struct { + local: c_int, + oid: git_oid, + loid: git_oid, + name: [*c]u8, + symref_target: [*c]u8, +}; +pub const git_remote_head = struct_git_remote_head; +pub const git_transport_message_cb = ?fn ([*c]const u8, c_int, *c_void) callconv(.C) c_int; +pub const GIT_REMOTE_COMPLETION_DOWNLOAD: c_int = 0; +pub const GIT_REMOTE_COMPLETION_INDEXING: c_int = 1; +pub const GIT_REMOTE_COMPLETION_ERROR: c_int = 2; +pub const enum_git_remote_completion_t = c_uint; +pub const git_remote_completion_t = enum_git_remote_completion_t; +pub const struct_git_credential = extern struct { + credtype: git_credential_t, + free: ?fn ([*c]git_credential) callconv(.C) void, +}; +pub const git_credential = struct_git_credential; +pub const git_credential_acquire_cb = ?fn ([*c][*c]git_credential, [*c]const u8, [*c]const u8, c_uint, *c_void) callconv(.C) c_int; +pub const GIT_CERT_NONE: c_int = 0; +pub const GIT_CERT_X509: c_int = 1; +pub const GIT_CERT_HOSTKEY_LIBSSH2: c_int = 2; +pub const GIT_CERT_STRARRAY: c_int = 3; +pub const enum_git_cert_t = c_uint; +pub const git_cert_t = enum_git_cert_t; +pub const struct_git_cert = extern struct { + cert_type: git_cert_t, +}; +pub const git_cert = struct_git_cert; +pub const git_transport_certificate_check_cb = ?fn ([*c]git_cert, c_int, [*c]const u8, *c_void) callconv(.C) c_int; +pub const git_indexer_progress_cb = ?fn ([*c]const git_indexer_progress, *c_void) callconv(.C) c_int; +pub const git_packbuilder_progress = ?fn (c_int, u32, u32, *c_void) callconv(.C) c_int; +pub const git_push_transfer_progress_cb = ?fn (c_uint, c_uint, usize, *c_void) callconv(.C) c_int; +pub const git_push_update_reference_cb = ?fn ([*c]const u8, [*c]const u8, *c_void) callconv(.C) c_int; +pub const git_push_negotiation = ?fn ([*c][*c]const git_push_update, usize, *c_void) callconv(.C) c_int; +pub const git_transport_cb = ?fn ([*c]*git_transport, *git_remote, *c_void) callconv(.C) c_int; +pub const git_remote_ready_cb = ?fn (*git_remote, c_int, *c_void) callconv(.C) c_int; +pub const git_url_resolve_cb = ?fn ([*c]git_buf, [*c]const u8, c_int, *c_void) callconv(.C) c_int; +pub const struct_git_remote_callbacks = extern struct { + version: c_uint, + sideband_progress: git_transport_message_cb, + completion: ?fn (git_remote_completion_t, *c_void) callconv(.C) c_int, + credentials: git_credential_acquire_cb, + certificate_check: git_transport_certificate_check_cb, + transfer_progress: git_indexer_progress_cb, + update_tips: ?fn ([*c]const u8, [*c]const git_oid, [*c]const git_oid, *c_void) callconv(.C) c_int, + pack_progress: git_packbuilder_progress, + push_transfer_progress: git_push_transfer_progress_cb, + push_update_reference: git_push_update_reference_cb, + push_negotiation: git_push_negotiation, + transport: git_transport_cb, + remote_ready: git_remote_ready_cb, + payload: *c_void, + resolve_url: git_url_resolve_cb, +}; +pub const git_remote_callbacks = struct_git_remote_callbacks; +pub const struct_git_submodule = opaque {}; +pub const git_submodule = struct_git_submodule; +pub const GIT_SUBMODULE_UPDATE_CHECKOUT: c_int = 1; +pub const GIT_SUBMODULE_UPDATE_REBASE: c_int = 2; +pub const GIT_SUBMODULE_UPDATE_MERGE: c_int = 3; +pub const GIT_SUBMODULE_UPDATE_NONE: c_int = 4; +pub const GIT_SUBMODULE_UPDATE_DEFAULT: c_int = 0; +pub const git_submodule_update_t = c_uint; +pub const GIT_SUBMODULE_IGNORE_UNSPECIFIED: c_int = -1; +pub const GIT_SUBMODULE_IGNORE_NONE: c_int = 1; +pub const GIT_SUBMODULE_IGNORE_UNTRACKED: c_int = 2; +pub const GIT_SUBMODULE_IGNORE_DIRTY: c_int = 3; +pub const GIT_SUBMODULE_IGNORE_ALL: c_int = 4; +pub const git_submodule_ignore_t = c_int; +pub const GIT_SUBMODULE_RECURSE_NO: c_int = 0; +pub const GIT_SUBMODULE_RECURSE_YES: c_int = 1; +pub const GIT_SUBMODULE_RECURSE_ONDEMAND: c_int = 2; +pub const git_submodule_recurse_t = c_uint; +pub const git_writestream = struct_git_writestream; +pub const struct_git_writestream = extern struct { + write: ?fn ([*c]git_writestream, [*c]const u8, usize) callconv(.C) c_int, + close: ?fn ([*c]git_writestream) callconv(.C) c_int, + free: ?fn ([*c]git_writestream) callconv(.C) void, +}; +pub const struct_git_mailmap = opaque {}; +pub const git_mailmap = struct_git_mailmap; +pub const GIT_REPOSITORY_OPEN_NO_SEARCH: c_int = 1; +pub const GIT_REPOSITORY_OPEN_CROSS_FS: c_int = 2; +pub const GIT_REPOSITORY_OPEN_BARE: c_int = 4; +pub const GIT_REPOSITORY_OPEN_NO_DOTGIT: c_int = 8; +pub const GIT_REPOSITORY_OPEN_FROM_ENV: c_int = 16; +pub const git_repository_open_flag_t = c_uint; +pub const GIT_REPOSITORY_INIT_BARE: c_int = 1; +pub const GIT_REPOSITORY_INIT_NO_REINIT: c_int = 2; +pub const GIT_REPOSITORY_INIT_NO_DOTGIT_DIR: c_int = 4; +pub const GIT_REPOSITORY_INIT_MKDIR: c_int = 8; +pub const GIT_REPOSITORY_INIT_MKPATH: c_int = 16; +pub const GIT_REPOSITORY_INIT_EXTERNAL_TEMPLATE: c_int = 32; +pub const GIT_REPOSITORY_INIT_RELATIVE_GITLINK: c_int = 64; +pub const git_repository_init_flag_t = c_uint; +pub const GIT_REPOSITORY_INIT_SHARED_UMASK: c_int = 0; +pub const GIT_REPOSITORY_INIT_SHARED_GROUP: c_int = 1533; +pub const GIT_REPOSITORY_INIT_SHARED_ALL: c_int = 1535; +pub const git_repository_init_mode_t = c_uint; +pub const git_repository_init_options = extern struct { + version: c_uint, + flags: u32, + mode: u32, + workdir_path: [*c]const u8, + description: [*c]const u8, + template_path: [*c]const u8, + initial_head: [*c]const u8, + origin_url: [*c]const u8, +}; +pub const GIT_REPOSITORY_ITEM_GITDIR: c_int = 0; +pub const GIT_REPOSITORY_ITEM_WORKDIR: c_int = 1; +pub const GIT_REPOSITORY_ITEM_COMMONDIR: c_int = 2; +pub const GIT_REPOSITORY_ITEM_INDEX: c_int = 3; +pub const GIT_REPOSITORY_ITEM_OBJECTS: c_int = 4; +pub const GIT_REPOSITORY_ITEM_REFS: c_int = 5; +pub const GIT_REPOSITORY_ITEM_PACKED_REFS: c_int = 6; +pub const GIT_REPOSITORY_ITEM_REMOTES: c_int = 7; +pub const GIT_REPOSITORY_ITEM_CONFIG: c_int = 8; +pub const GIT_REPOSITORY_ITEM_INFO: c_int = 9; +pub const GIT_REPOSITORY_ITEM_HOOKS: c_int = 10; +pub const GIT_REPOSITORY_ITEM_LOGS: c_int = 11; +pub const GIT_REPOSITORY_ITEM_MODULES: c_int = 12; +pub const GIT_REPOSITORY_ITEM_WORKTREES: c_int = 13; +pub const GIT_REPOSITORY_ITEM__LAST: c_int = 14; +pub const git_repository_item_t = c_uint; +pub const git_repository_fetchhead_foreach_cb = ?fn ([*c]const u8, [*c]const u8, [*c]const git_oid, c_uint, *c_void) callconv(.C) c_int; +pub const git_repository_mergehead_foreach_cb = ?fn ([*c]const git_oid, *c_void) callconv(.C) c_int; +pub const GIT_REPOSITORY_STATE_NONE: c_int = 0; +pub const GIT_REPOSITORY_STATE_MERGE: c_int = 1; +pub const GIT_REPOSITORY_STATE_REVERT: c_int = 2; +pub const GIT_REPOSITORY_STATE_REVERT_SEQUENCE: c_int = 3; +pub const GIT_REPOSITORY_STATE_CHERRYPICK: c_int = 4; +pub const GIT_REPOSITORY_STATE_CHERRYPICK_SEQUENCE: c_int = 5; +pub const GIT_REPOSITORY_STATE_BISECT: c_int = 6; +pub const GIT_REPOSITORY_STATE_REBASE: c_int = 7; +pub const GIT_REPOSITORY_STATE_REBASE_INTERACTIVE: c_int = 8; +pub const GIT_REPOSITORY_STATE_REBASE_MERGE: c_int = 9; +pub const GIT_REPOSITORY_STATE_APPLY_MAILBOX: c_int = 10; +pub const GIT_REPOSITORY_STATE_APPLY_MAILBOX_OR_REBASE: c_int = 11; +pub const git_repository_state_t = c_uint; +pub const git_treebuilder_filter_cb = ?fn (*const git_tree_entry, *c_void) callconv(.C) c_int; +pub const git_treewalk_cb = ?fn ([*c]const u8, *const git_tree_entry, *c_void) callconv(.C) c_int; +pub const GIT_TREEWALK_PRE: c_int = 0; +pub const GIT_TREEWALK_POST: c_int = 1; +pub const git_treewalk_mode = c_uint; +pub const GIT_TREE_UPDATE_UPSERT: c_int = 0; +pub const GIT_TREE_UPDATE_REMOVE: c_int = 1; +pub const git_tree_update_t = c_uint; +pub const git_tree_update = extern struct { + action: git_tree_update_t, + id: git_oid, + filemode: git_filemode_t, + path: [*c]const u8, +}; +pub const struct_git_strarray = extern struct { + strings: [*c][*c]u8, + count: usize, +}; +pub const git_strarray = struct_git_strarray; +pub const git_reference_foreach_cb = ?fn (*git_reference, *c_void) callconv(.C) c_int; +pub const git_reference_foreach_name_cb = ?fn ([*c]const u8, *c_void) callconv(.C) c_int; +pub const GIT_REFERENCE_FORMAT_NORMAL: c_int = 0; +pub const GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL: c_int = 1; +pub const GIT_REFERENCE_FORMAT_REFSPEC_PATTERN: c_int = 2; +pub const GIT_REFERENCE_FORMAT_REFSPEC_SHORTHAND: c_int = 4; +pub const git_reference_format_t = c_uint; +pub const GIT_DIFF_NORMAL: c_int = 0; +pub const GIT_DIFF_REVERSE: c_int = 1; +pub const GIT_DIFF_INCLUDE_IGNORED: c_int = 2; +pub const GIT_DIFF_RECURSE_IGNORED_DIRS: c_int = 4; +pub const GIT_DIFF_INCLUDE_UNTRACKED: c_int = 8; +pub const GIT_DIFF_RECURSE_UNTRACKED_DIRS: c_int = 16; +pub const GIT_DIFF_INCLUDE_UNMODIFIED: c_int = 32; +pub const GIT_DIFF_INCLUDE_TYPECHANGE: c_int = 64; +pub const GIT_DIFF_INCLUDE_TYPECHANGE_TREES: c_int = 128; +pub const GIT_DIFF_IGNORE_FILEMODE: c_int = 256; +pub const GIT_DIFF_IGNORE_SUBMODULES: c_int = 512; +pub const GIT_DIFF_IGNORE_CASE: c_int = 1024; +pub const GIT_DIFF_INCLUDE_CASECHANGE: c_int = 2048; +pub const GIT_DIFF_DISABLE_PATHSPEC_MATCH: c_int = 4096; +pub const GIT_DIFF_SKIP_BINARY_CHECK: c_int = 8192; +pub const GIT_DIFF_ENABLE_FAST_UNTRACKED_DIRS: c_int = 16384; +pub const GIT_DIFF_UPDATE_INDEX: c_int = 32768; +pub const GIT_DIFF_INCLUDE_UNREADABLE: c_int = 65536; +pub const GIT_DIFF_INCLUDE_UNREADABLE_AS_UNTRACKED: c_int = 131072; +pub const GIT_DIFF_INDENT_HEURISTIC: c_int = 262144; +pub const GIT_DIFF_IGNORE_BLANK_LINES: c_int = 524288; +pub const GIT_DIFF_FORCE_TEXT: c_int = 1048576; +pub const GIT_DIFF_FORCE_BINARY: c_int = 2097152; +pub const GIT_DIFF_IGNORE_WHITESPACE: c_int = 4194304; +pub const GIT_DIFF_IGNORE_WHITESPACE_CHANGE: c_int = 8388608; +pub const GIT_DIFF_IGNORE_WHITESPACE_EOL: c_int = 16777216; +pub const GIT_DIFF_SHOW_UNTRACKED_CONTENT: c_int = 33554432; +pub const GIT_DIFF_SHOW_UNMODIFIED: c_int = 67108864; +pub const GIT_DIFF_PATIENCE: c_int = 268435456; +pub const GIT_DIFF_MINIMAL: c_int = 536870912; +pub const GIT_DIFF_SHOW_BINARY: c_int = 1073741824; +pub const git_diff_option_t = c_uint; +pub const struct_git_diff = opaque {}; +pub const git_diff = struct_git_diff; +pub const GIT_DIFF_FLAG_BINARY: c_int = 1; +pub const GIT_DIFF_FLAG_NOT_BINARY: c_int = 2; +pub const GIT_DIFF_FLAG_VALID_ID: c_int = 4; +pub const GIT_DIFF_FLAG_EXISTS: c_int = 8; +pub const git_diff_flag_t = c_uint; +pub const GIT_DELTA_UNMODIFIED: c_int = 0; +pub const GIT_DELTA_ADDED: c_int = 1; +pub const GIT_DELTA_DELETED: c_int = 2; +pub const GIT_DELTA_MODIFIED: c_int = 3; +pub const GIT_DELTA_RENAMED: c_int = 4; +pub const GIT_DELTA_COPIED: c_int = 5; +pub const GIT_DELTA_IGNORED: c_int = 6; +pub const GIT_DELTA_UNTRACKED: c_int = 7; +pub const GIT_DELTA_TYPECHANGE: c_int = 8; +pub const GIT_DELTA_UNREADABLE: c_int = 9; +pub const GIT_DELTA_CONFLICTED: c_int = 10; +pub const git_delta_t = c_uint; +pub const git_diff_file = extern struct { + id: git_oid, + path: [*c]const u8, + size: git_object_size_t, + flags: u32, + mode: u16, + id_abbrev: u16, +}; +pub const git_diff_delta = extern struct { + status: git_delta_t, + flags: u32, + similarity: u16, + nfiles: u16, + old_file: git_diff_file, + new_file: git_diff_file, +}; +pub const git_diff_notify_cb = ?fn (*const git_diff, [*c]const git_diff_delta, [*c]const u8, *c_void) callconv(.C) c_int; +pub const git_diff_progress_cb = ?fn (*const git_diff, [*c]const u8, [*c]const u8, *c_void) callconv(.C) c_int; +pub const git_diff_options = extern struct { + version: c_uint, + flags: u32, + ignore_submodules: git_submodule_ignore_t, + pathspec: git_strarray, + notify_cb: git_diff_notify_cb, + progress_cb: git_diff_progress_cb, + payload: *c_void, + context_lines: u32, + interhunk_lines: u32, + id_abbrev: u16, + max_size: git_off_t, + old_prefix: [*c]const u8, + new_prefix: [*c]const u8, +}; +pub const git_diff_file_cb = ?fn ([*c]const git_diff_delta, f32, *c_void) callconv(.C) c_int; +pub const GIT_DIFF_BINARY_NONE: c_int = 0; +pub const GIT_DIFF_BINARY_LITERAL: c_int = 1; +pub const GIT_DIFF_BINARY_DELTA: c_int = 2; +pub const git_diff_binary_t = c_uint; +pub const git_diff_binary_file = extern struct { + type: git_diff_binary_t, + data: [*c]const u8, + datalen: usize, + inflatedlen: usize, +}; +pub const git_diff_binary = extern struct { + contains_data: c_uint, + old_file: git_diff_binary_file, + new_file: git_diff_binary_file, +}; +pub const git_diff_binary_cb = ?fn ([*c]const git_diff_delta, [*c]const git_diff_binary, *c_void) callconv(.C) c_int; +pub const git_diff_hunk = extern struct { + old_start: c_int, + old_lines: c_int, + new_start: c_int, + new_lines: c_int, + header_len: usize, + header: [128]u8, +}; +pub const git_diff_hunk_cb = ?fn ([*c]const git_diff_delta, [*c]const git_diff_hunk, *c_void) callconv(.C) c_int; +pub const GIT_DIFF_LINE_CONTEXT: c_int = 32; +pub const GIT_DIFF_LINE_ADDITION: c_int = 43; +pub const GIT_DIFF_LINE_DELETION: c_int = 45; +pub const GIT_DIFF_LINE_CONTEXT_EOFNL: c_int = 61; +pub const GIT_DIFF_LINE_ADD_EOFNL: c_int = 62; +pub const GIT_DIFF_LINE_DEL_EOFNL: c_int = 60; +pub const GIT_DIFF_LINE_FILE_HDR: c_int = 70; +pub const GIT_DIFF_LINE_HUNK_HDR: c_int = 72; +pub const GIT_DIFF_LINE_BINARY: c_int = 66; +pub const git_diff_line_t = c_uint; +pub const git_diff_line = extern struct { + origin: u8, + old_lineno: c_int, + new_lineno: c_int, + num_lines: c_int, + content_len: usize, + content_offset: git_off_t, + content: [*c]const u8, +}; +pub const git_diff_line_cb = ?fn ([*c]const git_diff_delta, [*c]const git_diff_hunk, [*c]const git_diff_line, *c_void) callconv(.C) c_int; +pub const GIT_DIFF_FIND_BY_CONFIG: c_int = 0; +pub const GIT_DIFF_FIND_RENAMES: c_int = 1; +pub const GIT_DIFF_FIND_RENAMES_FROM_REWRITES: c_int = 2; +pub const GIT_DIFF_FIND_COPIES: c_int = 4; +pub const GIT_DIFF_FIND_COPIES_FROM_UNMODIFIED: c_int = 8; +pub const GIT_DIFF_FIND_REWRITES: c_int = 16; +pub const GIT_DIFF_BREAK_REWRITES: c_int = 32; +pub const GIT_DIFF_FIND_AND_BREAK_REWRITES: c_int = 48; +pub const GIT_DIFF_FIND_FOR_UNTRACKED: c_int = 64; +pub const GIT_DIFF_FIND_ALL: c_int = 255; +pub const GIT_DIFF_FIND_IGNORE_LEADING_WHITESPACE: c_int = 0; +pub const GIT_DIFF_FIND_IGNORE_WHITESPACE: c_int = 4096; +pub const GIT_DIFF_FIND_DONT_IGNORE_WHITESPACE: c_int = 8192; +pub const GIT_DIFF_FIND_EXACT_MATCH_ONLY: c_int = 16384; +pub const GIT_DIFF_BREAK_REWRITES_FOR_RENAMES_ONLY: c_int = 32768; +pub const GIT_DIFF_FIND_REMOVE_UNMODIFIED: c_int = 65536; +pub const git_diff_find_t = c_uint; +pub const git_diff_similarity_metric = extern struct { + file_signature: ?fn ([*c]*c_void, [*c]const git_diff_file, [*c]const u8, *c_void) callconv(.C) c_int, + buffer_signature: ?fn ([*c]*c_void, [*c]const git_diff_file, [*c]const u8, usize, *c_void) callconv(.C) c_int, + free_signature: ?fn (*c_void, *c_void) callconv(.C) void, + similarity: ?fn ([*c]c_int, *c_void, *c_void, *c_void) callconv(.C) c_int, + payload: *c_void, +}; +pub const git_diff_find_options = extern struct { + version: c_uint, + flags: u32, + rename_threshold: u16, + rename_from_rewrite_threshold: u16, + copy_threshold: u16, + break_rewrite_threshold: u16, + rename_limit: usize, + metric: [*c]git_diff_similarity_metric, +}; +pub const GIT_DIFF_FORMAT_PATCH: c_int = 1; +pub const GIT_DIFF_FORMAT_PATCH_HEADER: c_int = 2; +pub const GIT_DIFF_FORMAT_RAW: c_int = 3; +pub const GIT_DIFF_FORMAT_NAME_ONLY: c_int = 4; +pub const GIT_DIFF_FORMAT_NAME_STATUS: c_int = 5; +pub const GIT_DIFF_FORMAT_PATCH_ID: c_int = 6; +pub const git_diff_format_t = c_uint; +pub const struct_git_diff_stats = opaque {}; +pub const git_diff_stats = struct_git_diff_stats; +pub const GIT_DIFF_STATS_NONE: c_int = 0; +pub const GIT_DIFF_STATS_FULL: c_int = 1; +pub const GIT_DIFF_STATS_SHORT: c_int = 2; +pub const GIT_DIFF_STATS_NUMBER: c_int = 4; +pub const GIT_DIFF_STATS_INCLUDE_SUMMARY: c_int = 8; +pub const git_diff_stats_format_t = c_uint; +pub const struct_git_diff_patchid_options = extern struct { + version: c_uint, +}; +pub const git_diff_patchid_options = struct_git_diff_patchid_options; +pub const git_apply_delta_cb = ?fn ([*c]const git_diff_delta, *c_void) callconv(.C) c_int; +pub const git_apply_hunk_cb = ?fn ([*c]const git_diff_hunk, *c_void) callconv(.C) c_int; +pub const GIT_APPLY_CHECK: c_int = 1; +pub const git_apply_flags_t = c_uint; +pub const git_apply_options = extern struct { + version: c_uint, + delta_cb: git_apply_delta_cb, + hunk_cb: git_apply_hunk_cb, + payload: *c_void, + flags: c_uint, +}; +pub const GIT_APPLY_LOCATION_WORKDIR: c_int = 0; +pub const GIT_APPLY_LOCATION_INDEX: c_int = 1; +pub const GIT_APPLY_LOCATION_BOTH: c_int = 2; +pub const git_apply_location_t = c_uint; +pub const GIT_ATTR_VALUE_UNSPECIFIED: c_int = 0; +pub const GIT_ATTR_VALUE_TRUE: c_int = 1; +pub const GIT_ATTR_VALUE_FALSE: c_int = 2; +pub const GIT_ATTR_VALUE_STRING: c_int = 3; +pub const git_attr_value_t = c_uint; +pub const git_attr_options = extern struct { + version: c_uint, + flags: c_uint, + commit_id: [*c]git_oid, + attr_commit_id: git_oid, +}; +pub const git_attr_foreach_cb = ?fn ([*c]const u8, [*c]const u8, *c_void) callconv(.C) c_int; +pub const GIT_BLOB_FILTER_CHECK_FOR_BINARY: c_int = 1; +pub const GIT_BLOB_FILTER_NO_SYSTEM_ATTRIBUTES: c_int = 2; +pub const GIT_BLOB_FILTER_ATTRIBUTES_FROM_HEAD: c_int = 4; +pub const GIT_BLOB_FILTER_ATTRIBUTES_FROM_COMMIT: c_int = 8; +pub const git_blob_filter_flag_t = c_uint; +pub const git_blob_filter_options = extern struct { + version: c_int, + flags: u32, + commit_id: [*c]git_oid, + attr_commit_id: git_oid, +}; +pub const GIT_BLAME_NORMAL: c_int = 0; +pub const GIT_BLAME_TRACK_COPIES_SAME_FILE: c_int = 1; +pub const GIT_BLAME_TRACK_COPIES_SAME_COMMIT_MOVES: c_int = 2; +pub const GIT_BLAME_TRACK_COPIES_SAME_COMMIT_COPIES: c_int = 4; +pub const GIT_BLAME_TRACK_COPIES_ANY_COMMIT_COPIES: c_int = 8; +pub const GIT_BLAME_FIRST_PARENT: c_int = 16; +pub const GIT_BLAME_USE_MAILMAP: c_int = 32; +pub const GIT_BLAME_IGNORE_WHITESPACE: c_int = 64; +pub const git_blame_flag_t = c_uint; +pub const struct_git_blame_options = extern struct { + version: c_uint, + flags: u32, + min_match_characters: u16, + newest_commit: git_oid, + oldest_commit: git_oid, + min_line: usize, + max_line: usize, +}; +pub const git_blame_options = struct_git_blame_options; +pub const struct_git_blame_hunk = extern struct { + lines_in_hunk: usize, + final_commit_id: git_oid, + final_start_line_number: usize, + final_signature: [*c]git_signature, + orig_commit_id: git_oid, + orig_path: [*c]const u8, + orig_start_line_number: usize, + orig_signature: [*c]git_signature, + boundary: u8, +}; +pub const git_blame_hunk = struct_git_blame_hunk; +pub const struct_git_blame = opaque {}; +pub const git_blame = struct_git_blame; +pub const struct_git_branch_iterator = opaque {}; +pub const git_branch_iterator = struct_git_branch_iterator; +pub const GIT_CERT_SSH_MD5: c_int = 1; +pub const GIT_CERT_SSH_SHA1: c_int = 2; +pub const GIT_CERT_SSH_SHA256: c_int = 4; +pub const GIT_CERT_SSH_RAW: c_int = 8; +pub const git_cert_ssh_t = c_uint; +pub const GIT_CERT_SSH_RAW_TYPE_UNKNOWN: c_int = 0; +pub const GIT_CERT_SSH_RAW_TYPE_RSA: c_int = 1; +pub const GIT_CERT_SSH_RAW_TYPE_DSS: c_int = 2; +pub const GIT_CERT_SSH_RAW_TYPE_KEY_ECDSA_256: c_int = 3; +pub const GIT_CERT_SSH_RAW_TYPE_KEY_ECDSA_384: c_int = 4; +pub const GIT_CERT_SSH_RAW_TYPE_KEY_ECDSA_521: c_int = 5; +pub const GIT_CERT_SSH_RAW_TYPE_KEY_ED25519: c_int = 6; +pub const git_cert_ssh_raw_type_t = c_uint; +pub const git_cert_hostkey = extern struct { + parent: git_cert, + type: git_cert_ssh_t, + hash_md5: [16]u8, + hash_sha1: [20]u8, + hash_sha256: [32]u8, + raw_type: git_cert_ssh_raw_type_t, + hostkey: [*c]const u8, + hostkey_len: usize, +}; +pub const git_cert_x509 = extern struct { + parent: git_cert, + data: *c_void, + len: usize, +}; +pub const GIT_CHECKOUT_NONE: c_int = 0; +pub const GIT_CHECKOUT_SAFE: c_int = 1; +pub const GIT_CHECKOUT_FORCE: c_int = 2; +pub const GIT_CHECKOUT_RECREATE_MISSING: c_int = 4; +pub const GIT_CHECKOUT_ALLOW_CONFLICTS: c_int = 16; +pub const GIT_CHECKOUT_REMOVE_UNTRACKED: c_int = 32; +pub const GIT_CHECKOUT_REMOVE_IGNORED: c_int = 64; +pub const GIT_CHECKOUT_UPDATE_ONLY: c_int = 128; +pub const GIT_CHECKOUT_DONT_UPDATE_INDEX: c_int = 256; +pub const GIT_CHECKOUT_NO_REFRESH: c_int = 512; +pub const GIT_CHECKOUT_SKIP_UNMERGED: c_int = 1024; +pub const GIT_CHECKOUT_USE_OURS: c_int = 2048; +pub const GIT_CHECKOUT_USE_THEIRS: c_int = 4096; +pub const GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH: c_int = 8192; +pub const GIT_CHECKOUT_SKIP_LOCKED_DIRECTORIES: c_int = 262144; +pub const GIT_CHECKOUT_DONT_OVERWRITE_IGNORED: c_int = 524288; +pub const GIT_CHECKOUT_CONFLICT_STYLE_MERGE: c_int = 1048576; +pub const GIT_CHECKOUT_CONFLICT_STYLE_DIFF3: c_int = 2097152; +pub const GIT_CHECKOUT_DONT_REMOVE_EXISTING: c_int = 4194304; +pub const GIT_CHECKOUT_DONT_WRITE_INDEX: c_int = 8388608; +pub const GIT_CHECKOUT_DRY_RUN: c_int = 16777216; +pub const GIT_CHECKOUT_UPDATE_SUBMODULES: c_int = 65536; +pub const GIT_CHECKOUT_UPDATE_SUBMODULES_IF_CHANGED: c_int = 131072; +pub const git_checkout_strategy_t = c_uint; +pub const GIT_CHECKOUT_NOTIFY_NONE: c_int = 0; +pub const GIT_CHECKOUT_NOTIFY_CONFLICT: c_int = 1; +pub const GIT_CHECKOUT_NOTIFY_DIRTY: c_int = 2; +pub const GIT_CHECKOUT_NOTIFY_UPDATED: c_int = 4; +pub const GIT_CHECKOUT_NOTIFY_UNTRACKED: c_int = 8; +pub const GIT_CHECKOUT_NOTIFY_IGNORED: c_int = 16; +pub const GIT_CHECKOUT_NOTIFY_ALL: c_int = 65535; +pub const git_checkout_notify_t = c_uint; +pub const git_checkout_perfdata = extern struct { + mkdir_calls: usize, + stat_calls: usize, + chmod_calls: usize, +}; +pub const git_checkout_notify_cb = ?fn (git_checkout_notify_t, [*c]const u8, [*c]const git_diff_file, [*c]const git_diff_file, [*c]const git_diff_file, *c_void) callconv(.C) c_int; +pub const git_checkout_progress_cb = ?fn ([*c]const u8, usize, usize, *c_void) callconv(.C) void; +pub const git_checkout_perfdata_cb = ?fn ([*c]const git_checkout_perfdata, *c_void) callconv(.C) void; +pub const struct_git_checkout_options = extern struct { + version: c_uint, + checkout_strategy: c_uint, + disable_filters: c_int, + dir_mode: c_uint, + file_mode: c_uint, + file_open_flags: c_int, + notify_flags: c_uint, + notify_cb: git_checkout_notify_cb, + notify_payload: *c_void, + progress_cb: git_checkout_progress_cb, + progress_payload: *c_void, + paths: git_strarray, + baseline: *git_tree, + baseline_index: *git_index, + target_directory: [*c]const u8, + ancestor_label: [*c]const u8, + our_label: [*c]const u8, + their_label: [*c]const u8, + perfdata_cb: git_checkout_perfdata_cb, + perfdata_payload: *c_void, +}; +pub const git_checkout_options = struct_git_checkout_options; +pub const struct_git_oidarray = extern struct { + ids: [*c]git_oid, + count: usize, +}; +pub const git_oidarray = struct_git_oidarray; +pub const struct_git_indexer = opaque {}; +pub const git_indexer = struct_git_indexer; +pub const struct_git_indexer_options = extern struct { + version: c_uint, + progress_cb: git_indexer_progress_cb, + progress_cb_payload: *c_void, + verify: u8, +}; +pub const git_indexer_options = struct_git_indexer_options; +pub const git_index_time = extern struct { + seconds: i32, + nanoseconds: u32, +}; +pub const struct_git_index_entry = extern struct { + ctime: git_index_time, + mtime: git_index_time, + dev: u32, + ino: u32, + mode: u32, + uid: u32, + gid: u32, + file_size: u32, + id: git_oid, + flags: u16, + flags_extended: u16, + path: [*c]const u8, +}; +pub const git_index_entry = struct_git_index_entry; +pub const GIT_INDEX_ENTRY_EXTENDED: c_int = 16384; +pub const GIT_INDEX_ENTRY_VALID: c_int = 32768; +pub const git_index_entry_flag_t = c_uint; +pub const GIT_INDEX_ENTRY_INTENT_TO_ADD: c_int = 8192; +pub const GIT_INDEX_ENTRY_SKIP_WORKTREE: c_int = 16384; +pub const GIT_INDEX_ENTRY_EXTENDED_FLAGS: c_int = 24576; +pub const GIT_INDEX_ENTRY_UPTODATE: c_int = 4; +pub const git_index_entry_extended_flag_t = c_uint; +pub const GIT_INDEX_CAPABILITY_IGNORE_CASE: c_int = 1; +pub const GIT_INDEX_CAPABILITY_NO_FILEMODE: c_int = 2; +pub const GIT_INDEX_CAPABILITY_NO_SYMLINKS: c_int = 4; +pub const GIT_INDEX_CAPABILITY_FROM_OWNER: c_int = -1; +pub const git_index_capability_t = c_int; +pub const git_index_matched_path_cb = ?fn ([*c]const u8, [*c]const u8, *c_void) callconv(.C) c_int; +pub const GIT_INDEX_ADD_DEFAULT: c_int = 0; +pub const GIT_INDEX_ADD_FORCE: c_int = 1; +pub const GIT_INDEX_ADD_DISABLE_PATHSPEC_MATCH: c_int = 2; +pub const GIT_INDEX_ADD_CHECK_PATHSPEC: c_int = 4; +pub const git_index_add_option_t = c_uint; +pub const GIT_INDEX_STAGE_ANY: c_int = -1; +pub const GIT_INDEX_STAGE_NORMAL: c_int = 0; +pub const GIT_INDEX_STAGE_ANCESTOR: c_int = 1; +pub const GIT_INDEX_STAGE_OURS: c_int = 2; +pub const GIT_INDEX_STAGE_THEIRS: c_int = 3; +pub const git_index_stage_t = c_int; +pub const git_merge_file_input = extern struct { + version: c_uint, + ptr: [*c]const u8, + size: usize, + path: [*c]const u8, + mode: c_uint, +}; +pub const GIT_MERGE_FIND_RENAMES: c_int = 1; +pub const GIT_MERGE_FAIL_ON_CONFLICT: c_int = 2; +pub const GIT_MERGE_SKIP_REUC: c_int = 4; +pub const GIT_MERGE_NO_RECURSIVE: c_int = 8; +pub const git_merge_flag_t = c_uint; +pub const GIT_MERGE_FILE_FAVOR_NORMAL: c_int = 0; +pub const GIT_MERGE_FILE_FAVOR_OURS: c_int = 1; +pub const GIT_MERGE_FILE_FAVOR_THEIRS: c_int = 2; +pub const GIT_MERGE_FILE_FAVOR_UNION: c_int = 3; +pub const git_merge_file_favor_t = c_uint; +pub const GIT_MERGE_FILE_DEFAULT: c_int = 0; +pub const GIT_MERGE_FILE_STYLE_MERGE: c_int = 1; +pub const GIT_MERGE_FILE_STYLE_DIFF3: c_int = 2; +pub const GIT_MERGE_FILE_SIMPLIFY_ALNUM: c_int = 4; +pub const GIT_MERGE_FILE_IGNORE_WHITESPACE: c_int = 8; +pub const GIT_MERGE_FILE_IGNORE_WHITESPACE_CHANGE: c_int = 16; +pub const GIT_MERGE_FILE_IGNORE_WHITESPACE_EOL: c_int = 32; +pub const GIT_MERGE_FILE_DIFF_PATIENCE: c_int = 64; +pub const GIT_MERGE_FILE_DIFF_MINIMAL: c_int = 128; +pub const git_merge_file_flag_t = c_uint; +pub const git_merge_file_options = extern struct { + version: c_uint, + ancestor_label: [*c]const u8, + our_label: [*c]const u8, + their_label: [*c]const u8, + favor: git_merge_file_favor_t, + flags: u32, + marker_size: c_ushort, +}; +pub const git_merge_file_result = extern struct { + automergeable: c_uint, + path: [*c]const u8, + mode: c_uint, + ptr: [*c]const u8, + len: usize, +}; +pub const git_merge_options = extern struct { + version: c_uint, + flags: u32, + rename_threshold: c_uint, + target_limit: c_uint, + metric: [*c]git_diff_similarity_metric, + recursion_limit: c_uint, + default_driver: [*c]const u8, + file_favor: git_merge_file_favor_t, + file_flags: u32, +}; +pub const GIT_MERGE_ANALYSIS_NONE: c_int = 0; +pub const GIT_MERGE_ANALYSIS_NORMAL: c_int = 1; +pub const GIT_MERGE_ANALYSIS_UP_TO_DATE: c_int = 2; +pub const GIT_MERGE_ANALYSIS_FASTFORWARD: c_int = 4; +pub const GIT_MERGE_ANALYSIS_UNBORN: c_int = 8; +pub const git_merge_analysis_t = c_uint; +pub const GIT_MERGE_PREFERENCE_NONE: c_int = 0; +pub const GIT_MERGE_PREFERENCE_NO_FASTFORWARD: c_int = 1; +pub const GIT_MERGE_PREFERENCE_FASTFORWARD_ONLY: c_int = 2; +pub const git_merge_preference_t = c_uint; +pub const git_cherrypick_options = extern struct { + version: c_uint, + mainline: c_uint, + merge_opts: git_merge_options, + checkout_opts: git_checkout_options, +}; +pub const GIT_DIRECTION_FETCH: c_int = 0; +pub const GIT_DIRECTION_PUSH: c_int = 1; +pub const git_direction = c_uint; +pub const GIT_CREDENTIAL_USERPASS_PLAINTEXT: c_int = 1; +pub const GIT_CREDENTIAL_SSH_KEY: c_int = 2; +pub const GIT_CREDENTIAL_SSH_CUSTOM: c_int = 4; +pub const GIT_CREDENTIAL_DEFAULT: c_int = 8; +pub const GIT_CREDENTIAL_SSH_INTERACTIVE: c_int = 16; +pub const GIT_CREDENTIAL_USERNAME: c_int = 32; +pub const GIT_CREDENTIAL_SSH_MEMORY: c_int = 64; +pub const git_credential_t = c_uint; +pub const struct_git_credential_userpass_plaintext = extern struct { + parent: git_credential, + username: [*c]u8, + password: [*c]u8, +}; +pub const git_credential_userpass_plaintext = struct_git_credential_userpass_plaintext; +pub const struct_git_credential_username = extern struct { + parent: git_credential, + username: [1]u8, +}; +pub const git_credential_username = struct_git_credential_username; +pub const git_credential_default = struct_git_credential; +pub const struct_git_credential_ssh_key = extern struct { + parent: git_credential, + username: [*c]u8, + publickey: [*c]u8, + privatekey: [*c]u8, + passphrase: [*c]u8, +}; +pub const git_credential_ssh_key = struct_git_credential_ssh_key; +pub const struct__LIBSSH2_USERAUTH_KBDINT_PROMPT = opaque {}; +pub const LIBSSH2_USERAUTH_KBDINT_PROMPT = struct__LIBSSH2_USERAUTH_KBDINT_PROMPT; +pub const struct__LIBSSH2_USERAUTH_KBDINT_RESPONSE = opaque {}; +pub const LIBSSH2_USERAUTH_KBDINT_RESPONSE = struct__LIBSSH2_USERAUTH_KBDINT_RESPONSE; +pub const git_credential_ssh_interactive_cb = ?fn ([*c]const u8, c_int, [*c]const u8, c_int, c_int, *const LIBSSH2_USERAUTH_KBDINT_PROMPT, *LIBSSH2_USERAUTH_KBDINT_RESPONSE, [*c]*c_void) callconv(.C) void; +pub const struct_git_credential_ssh_interactive = extern struct { + parent: git_credential, + username: [*c]u8, + prompt_callback: git_credential_ssh_interactive_cb, + payload: *c_void, +}; +pub const git_credential_ssh_interactive = struct_git_credential_ssh_interactive; +pub const struct__LIBSSH2_SESSION = opaque {}; +pub const LIBSSH2_SESSION = struct__LIBSSH2_SESSION; +pub const git_credential_sign_cb = ?fn (*LIBSSH2_SESSION, [*c][*c]u8, [*c]usize, [*c]const u8, usize, [*c]*c_void) callconv(.C) c_int; +pub const struct_git_credential_ssh_custom = extern struct { + parent: git_credential, + username: [*c]u8, + publickey: [*c]u8, + publickey_len: usize, + sign_callback: git_credential_sign_cb, + payload: *c_void, +}; +pub const git_credential_ssh_custom = struct_git_credential_ssh_custom; +pub const GIT_PACKBUILDER_ADDING_OBJECTS: c_int = 0; +pub const GIT_PACKBUILDER_DELTAFICATION: c_int = 1; +pub const git_packbuilder_stage_t = c_uint; +pub const git_packbuilder_foreach_cb = ?fn (*c_void, usize, *c_void) callconv(.C) c_int; +pub const GIT_PROXY_NONE: c_int = 0; +pub const GIT_PROXY_AUTO: c_int = 1; +pub const GIT_PROXY_SPECIFIED: c_int = 2; +pub const git_proxy_t = c_uint; +pub const git_proxy_options = extern struct { + version: c_uint, + type: git_proxy_t, + url: [*c]const u8, + credentials: git_credential_acquire_cb, + certificate_check: git_transport_certificate_check_cb, + payload: *c_void, +}; +pub const GIT_REMOTE_CREATE_SKIP_INSTEADOF: c_int = 1; +pub const GIT_REMOTE_CREATE_SKIP_DEFAULT_FETCHSPEC: c_int = 2; +pub const git_remote_create_flags = c_uint; +pub const struct_git_remote_create_options = extern struct { + version: c_uint, + repository: *git_repository, + name: [*c]const u8, + fetchspec: [*c]const u8, + flags: c_uint, +}; +pub const git_remote_create_options = struct_git_remote_create_options; +pub const git_push_update = extern struct { + src_refname: [*c]u8, + dst_refname: [*c]u8, + src: git_oid, + dst: git_oid, +}; +pub const GIT_FETCH_PRUNE_UNSPECIFIED: c_int = 0; +pub const GIT_FETCH_PRUNE: c_int = 1; +pub const GIT_FETCH_NO_PRUNE: c_int = 2; +pub const git_fetch_prune_t = c_uint; +pub const GIT_REMOTE_DOWNLOAD_TAGS_UNSPECIFIED: c_int = 0; +pub const GIT_REMOTE_DOWNLOAD_TAGS_AUTO: c_int = 1; +pub const GIT_REMOTE_DOWNLOAD_TAGS_NONE: c_int = 2; +pub const GIT_REMOTE_DOWNLOAD_TAGS_ALL: c_int = 3; +pub const git_remote_autotag_option_t = c_uint; +pub const git_fetch_options = extern struct { + version: c_int, + callbacks: git_remote_callbacks, + prune: git_fetch_prune_t, + update_fetchhead: c_int, + download_tags: git_remote_autotag_option_t, + proxy_opts: git_proxy_options, + custom_headers: git_strarray, +}; +pub const git_push_options = extern struct { + version: c_uint, + pb_parallelism: c_uint, + callbacks: git_remote_callbacks, + proxy_opts: git_proxy_options, + custom_headers: git_strarray, +}; +pub const GIT_CLONE_LOCAL_AUTO: c_int = 0; +pub const GIT_CLONE_LOCAL: c_int = 1; +pub const GIT_CLONE_NO_LOCAL: c_int = 2; +pub const GIT_CLONE_LOCAL_NO_LINKS: c_int = 3; +pub const git_clone_local_t = c_uint; +pub const git_remote_create_cb = ?fn ([*c]*git_remote, *git_repository, [*c]const u8, [*c]const u8, *c_void) callconv(.C) c_int; +pub const git_repository_create_cb = ?fn (*git_repository, [*c]const u8, c_int, *c_void) callconv(.C) c_int; +pub const struct_git_clone_options = extern struct { + version: c_uint, + checkout_opts: git_checkout_options, + fetch_opts: git_fetch_options, + bare: c_int, + local: git_clone_local_t, + checkout_branch: [*c]const u8, + repository_cb: git_repository_create_cb, + repository_cb_payload: *c_void, + remote_cb: git_remote_create_cb, + remote_cb_payload: *c_void, +}; +pub const git_clone_options = struct_git_clone_options; +pub const git_commit_create_cb = ?fn ([*c]git_oid, [*c]const git_signature, [*c]const git_signature, [*c]const u8, [*c]const u8, *const git_tree, usize, [*c]*const git_commit, *c_void) callconv(.C) c_int; +pub const GIT_CONFIG_LEVEL_PROGRAMDATA: c_int = 1; +pub const GIT_CONFIG_LEVEL_SYSTEM: c_int = 2; +pub const GIT_CONFIG_LEVEL_XDG: c_int = 3; +pub const GIT_CONFIG_LEVEL_GLOBAL: c_int = 4; +pub const GIT_CONFIG_LEVEL_LOCAL: c_int = 5; +pub const GIT_CONFIG_LEVEL_APP: c_int = 6; +pub const GIT_CONFIG_HIGHEST_LEVEL: c_int = -1; +pub const git_config_level_t = c_int; +pub const struct_git_config_entry = extern struct { + name: [*c]const u8, + value: [*c]const u8, + include_depth: c_uint, + level: git_config_level_t, + free: ?fn ([*c]struct_git_config_entry) callconv(.C) void, + payload: *c_void, +}; +pub const git_config_entry = struct_git_config_entry; +pub const git_config_foreach_cb = ?fn ([*c]const git_config_entry, *c_void) callconv(.C) c_int; +pub const struct_git_config_iterator = opaque {}; +pub const git_config_iterator = struct_git_config_iterator; +pub const GIT_CONFIGMAP_FALSE: c_int = 0; +pub const GIT_CONFIGMAP_TRUE: c_int = 1; +pub const GIT_CONFIGMAP_INT32: c_int = 2; +pub const GIT_CONFIGMAP_STRING: c_int = 3; +pub const git_configmap_t = c_uint; +pub const git_configmap = extern struct { + type: git_configmap_t, + str_match: [*c]const u8, + map_value: c_int, +}; +pub const GIT_DESCRIBE_DEFAULT: c_int = 0; +pub const GIT_DESCRIBE_TAGS: c_int = 1; +pub const GIT_DESCRIBE_ALL: c_int = 2; +pub const git_describe_strategy_t = c_uint; +pub const struct_git_describe_options = extern struct { + version: c_uint, + max_candidates_tags: c_uint, + describe_strategy: c_uint, + pattern: [*c]const u8, + only_follow_first_parent: c_int, + show_commit_oid_as_fallback: c_int, +}; +pub const git_describe_options = struct_git_describe_options; +pub const git_describe_format_options = extern struct { + version: c_uint, + abbreviated_size: c_uint, + always_use_long_format: c_int, + dirty_suffix: [*c]const u8, +}; +pub const struct_git_describe_result = opaque {}; +pub const git_describe_result = struct_git_describe_result; +pub const GIT_OK: c_int = 0; +pub const GIT_ERROR: c_int = -1; +pub const GIT_ENOTFOUND: c_int = -3; +pub const GIT_EEXISTS: c_int = -4; +pub const GIT_EAMBIGUOUS: c_int = -5; +pub const GIT_EBUFS: c_int = -6; +pub const GIT_EUSER: c_int = -7; +pub const GIT_EBAREREPO: c_int = -8; +pub const GIT_EUNBORNBRANCH: c_int = -9; +pub const GIT_EUNMERGED: c_int = -10; +pub const GIT_ENONFASTFORWARD: c_int = -11; +pub const GIT_EINVALIDSPEC: c_int = -12; +pub const GIT_ECONFLICT: c_int = -13; +pub const GIT_ELOCKED: c_int = -14; +pub const GIT_EMODIFIED: c_int = -15; +pub const GIT_EAUTH: c_int = -16; +pub const GIT_ECERTIFICATE: c_int = -17; +pub const GIT_EAPPLIED: c_int = -18; +pub const GIT_EPEEL: c_int = -19; +pub const GIT_EEOF: c_int = -20; +pub const GIT_EINVALID: c_int = -21; +pub const GIT_EUNCOMMITTED: c_int = -22; +pub const GIT_EDIRECTORY: c_int = -23; +pub const GIT_EMERGECONFLICT: c_int = -24; +pub const GIT_PASSTHROUGH: c_int = -30; +pub const GIT_ITEROVER: c_int = -31; +pub const GIT_RETRY: c_int = -32; +pub const GIT_EMISMATCH: c_int = -33; +pub const GIT_EINDEXDIRTY: c_int = -34; +pub const GIT_EAPPLYFAIL: c_int = -35; +pub const git_error_code = c_int; +pub const git_error = extern struct { + message: [*c]u8, + klass: c_int, +}; +pub const GIT_ERROR_NONE: c_int = 0; +pub const GIT_ERROR_NOMEMORY: c_int = 1; +pub const GIT_ERROR_OS: c_int = 2; +pub const GIT_ERROR_INVALID: c_int = 3; +pub const GIT_ERROR_REFERENCE: c_int = 4; +pub const GIT_ERROR_ZLIB: c_int = 5; +pub const GIT_ERROR_REPOSITORY: c_int = 6; +pub const GIT_ERROR_CONFIG: c_int = 7; +pub const GIT_ERROR_REGEX: c_int = 8; +pub const GIT_ERROR_ODB: c_int = 9; +pub const GIT_ERROR_INDEX: c_int = 10; +pub const GIT_ERROR_OBJECT: c_int = 11; +pub const GIT_ERROR_NET: c_int = 12; +pub const GIT_ERROR_TAG: c_int = 13; +pub const GIT_ERROR_TREE: c_int = 14; +pub const GIT_ERROR_INDEXER: c_int = 15; +pub const GIT_ERROR_SSL: c_int = 16; +pub const GIT_ERROR_SUBMODULE: c_int = 17; +pub const GIT_ERROR_THREAD: c_int = 18; +pub const GIT_ERROR_STASH: c_int = 19; +pub const GIT_ERROR_CHECKOUT: c_int = 20; +pub const GIT_ERROR_FETCHHEAD: c_int = 21; +pub const GIT_ERROR_MERGE: c_int = 22; +pub const GIT_ERROR_SSH: c_int = 23; +pub const GIT_ERROR_FILTER: c_int = 24; +pub const GIT_ERROR_REVERT: c_int = 25; +pub const GIT_ERROR_CALLBACK: c_int = 26; +pub const GIT_ERROR_CHERRYPICK: c_int = 27; +pub const GIT_ERROR_DESCRIBE: c_int = 28; +pub const GIT_ERROR_REBASE: c_int = 29; +pub const GIT_ERROR_FILESYSTEM: c_int = 30; +pub const GIT_ERROR_PATCH: c_int = 31; +pub const GIT_ERROR_WORKTREE: c_int = 32; +pub const GIT_ERROR_SHA1: c_int = 33; +pub const GIT_ERROR_HTTP: c_int = 34; +pub const GIT_ERROR_INTERNAL: c_int = 35; +pub const git_error_t = c_uint; +pub const GIT_FILTER_TO_WORKTREE: c_int = 0; +pub const GIT_FILTER_SMUDGE: c_int = 0; +pub const GIT_FILTER_TO_ODB: c_int = 1; +pub const GIT_FILTER_CLEAN: c_int = 1; +pub const git_filter_mode_t = c_uint; +pub const GIT_FILTER_DEFAULT: c_int = 0; +pub const GIT_FILTER_ALLOW_UNSAFE: c_int = 1; +pub const GIT_FILTER_NO_SYSTEM_ATTRIBUTES: c_int = 2; +pub const GIT_FILTER_ATTRIBUTES_FROM_HEAD: c_int = 4; +pub const GIT_FILTER_ATTRIBUTES_FROM_COMMIT: c_int = 8; +pub const git_filter_flag_t = c_uint; +pub const git_filter_options = extern struct { + version: c_uint, + flags: u32, + commit_id: [*c]git_oid, + attr_commit_id: git_oid, +}; +pub const struct_git_filter = opaque {}; +pub const git_filter = struct_git_filter; +pub const struct_git_filter_list = opaque {}; +pub const git_filter_list = struct_git_filter_list; +pub const git_rebase_options = extern struct { + version: c_uint, + quiet: c_int, + inmemory: c_int, + rewrite_notes_ref: [*c]const u8, + merge_options: git_merge_options, + checkout_options: git_checkout_options, + commit_create_cb: git_commit_create_cb, + signing_cb: ?fn ([*c]git_buf, [*c]git_buf, [*c]const u8, *c_void) callconv(.C) c_int, + payload: *c_void, +}; +pub const GIT_REBASE_OPERATION_PICK: c_int = 0; +pub const GIT_REBASE_OPERATION_REWORD: c_int = 1; +pub const GIT_REBASE_OPERATION_EDIT: c_int = 2; +pub const GIT_REBASE_OPERATION_SQUASH: c_int = 3; +pub const GIT_REBASE_OPERATION_FIXUP: c_int = 4; +pub const GIT_REBASE_OPERATION_EXEC: c_int = 5; +pub const git_rebase_operation_t = c_uint; +pub const git_rebase_operation = extern struct { + type: git_rebase_operation_t, + id: git_oid, + exec: [*c]const u8, +}; +pub const GIT_TRACE_NONE: c_int = 0; +pub const GIT_TRACE_FATAL: c_int = 1; +pub const GIT_TRACE_ERROR: c_int = 2; +pub const GIT_TRACE_WARN: c_int = 3; +pub const GIT_TRACE_INFO: c_int = 4; +pub const GIT_TRACE_DEBUG: c_int = 5; +pub const GIT_TRACE_TRACE: c_int = 6; +pub const git_trace_level_t = c_uint; +pub const git_trace_cb = ?fn (git_trace_level_t, [*c]const u8) callconv(.C) void; +pub const git_revert_options = extern struct { + version: c_uint, + mainline: c_uint, + merge_opts: git_merge_options, + checkout_opts: git_checkout_options, +}; +pub const GIT_REVSPEC_SINGLE: c_int = 1; +pub const GIT_REVSPEC_RANGE: c_int = 2; +pub const GIT_REVSPEC_MERGE_BASE: c_int = 4; +pub const git_revspec_t = c_uint; +pub const git_revspec = extern struct { + from: *git_object, + to: *git_object, + flags: c_uint, +}; +pub const GIT_STASH_DEFAULT: c_int = 0; +pub const GIT_STASH_KEEP_INDEX: c_int = 1; +pub const GIT_STASH_INCLUDE_UNTRACKED: c_int = 2; +pub const GIT_STASH_INCLUDE_IGNORED: c_int = 4; +pub const git_stash_flags = c_uint; +pub const GIT_STASH_APPLY_DEFAULT: c_int = 0; +pub const GIT_STASH_APPLY_REINSTATE_INDEX: c_int = 1; +pub const git_stash_apply_flags = c_uint; +pub const GIT_STASH_APPLY_PROGRESS_NONE: c_int = 0; +pub const GIT_STASH_APPLY_PROGRESS_LOADING_STASH: c_int = 1; +pub const GIT_STASH_APPLY_PROGRESS_ANALYZE_INDEX: c_int = 2; +pub const GIT_STASH_APPLY_PROGRESS_ANALYZE_MODIFIED: c_int = 3; +pub const GIT_STASH_APPLY_PROGRESS_ANALYZE_UNTRACKED: c_int = 4; +pub const GIT_STASH_APPLY_PROGRESS_CHECKOUT_UNTRACKED: c_int = 5; +pub const GIT_STASH_APPLY_PROGRESS_CHECKOUT_MODIFIED: c_int = 6; +pub const GIT_STASH_APPLY_PROGRESS_DONE: c_int = 7; +pub const git_stash_apply_progress_t = c_uint; +pub const git_stash_apply_progress_cb = ?fn (git_stash_apply_progress_t, *c_void) callconv(.C) c_int; +pub const struct_git_stash_apply_options = extern struct { + version: c_uint, + flags: u32, + checkout_options: git_checkout_options, + progress_cb: git_stash_apply_progress_cb, + progress_payload: *c_void, +}; +pub const git_stash_apply_options = struct_git_stash_apply_options; +pub const git_stash_cb = ?fn (usize, [*c]const u8, [*c]const git_oid, *c_void) callconv(.C) c_int; +pub const GIT_STATUS_CURRENT: c_int = 0; +pub const GIT_STATUS_INDEX_NEW: c_int = 1; +pub const GIT_STATUS_INDEX_MODIFIED: c_int = 2; +pub const GIT_STATUS_INDEX_DELETED: c_int = 4; +pub const GIT_STATUS_INDEX_RENAMED: c_int = 8; +pub const GIT_STATUS_INDEX_TYPECHANGE: c_int = 16; +pub const GIT_STATUS_WT_NEW: c_int = 128; +pub const GIT_STATUS_WT_MODIFIED: c_int = 256; +pub const GIT_STATUS_WT_DELETED: c_int = 512; +pub const GIT_STATUS_WT_TYPECHANGE: c_int = 1024; +pub const GIT_STATUS_WT_RENAMED: c_int = 2048; +pub const GIT_STATUS_WT_UNREADABLE: c_int = 4096; +pub const GIT_STATUS_IGNORED: c_int = 16384; +pub const GIT_STATUS_CONFLICTED: c_int = 32768; +pub const git_status_t = c_uint; +pub const git_status_cb = ?fn ([*c]const u8, c_uint, *c_void) callconv(.C) c_int; +pub const GIT_STATUS_SHOW_INDEX_AND_WORKDIR: c_int = 0; +pub const GIT_STATUS_SHOW_INDEX_ONLY: c_int = 1; +pub const GIT_STATUS_SHOW_WORKDIR_ONLY: c_int = 2; +pub const git_status_show_t = c_uint; +pub const GIT_STATUS_OPT_INCLUDE_UNTRACKED: c_int = 1; +pub const GIT_STATUS_OPT_INCLUDE_IGNORED: c_int = 2; +pub const GIT_STATUS_OPT_INCLUDE_UNMODIFIED: c_int = 4; +pub const GIT_STATUS_OPT_EXCLUDE_SUBMODULES: c_int = 8; +pub const GIT_STATUS_OPT_RECURSE_UNTRACKED_DIRS: c_int = 16; +pub const GIT_STATUS_OPT_DISABLE_PATHSPEC_MATCH: c_int = 32; +pub const GIT_STATUS_OPT_RECURSE_IGNORED_DIRS: c_int = 64; +pub const GIT_STATUS_OPT_RENAMES_HEAD_TO_INDEX: c_int = 128; +pub const GIT_STATUS_OPT_RENAMES_INDEX_TO_WORKDIR: c_int = 256; +pub const GIT_STATUS_OPT_SORT_CASE_SENSITIVELY: c_int = 512; +pub const GIT_STATUS_OPT_SORT_CASE_INSENSITIVELY: c_int = 1024; +pub const GIT_STATUS_OPT_RENAMES_FROM_REWRITES: c_int = 2048; +pub const GIT_STATUS_OPT_NO_REFRESH: c_int = 4096; +pub const GIT_STATUS_OPT_UPDATE_INDEX: c_int = 8192; +pub const GIT_STATUS_OPT_INCLUDE_UNREADABLE: c_int = 16384; +pub const GIT_STATUS_OPT_INCLUDE_UNREADABLE_AS_UNTRACKED: c_int = 32768; +pub const git_status_opt_t = c_uint; +pub const git_status_options = extern struct { + version: c_uint, + show: git_status_show_t, + flags: c_uint, + pathspec: git_strarray, + baseline: *git_tree, +}; +pub const git_status_entry = extern struct { + status: git_status_t, + head_to_index: [*c]git_diff_delta, + index_to_workdir: [*c]git_diff_delta, +}; +pub const GIT_SUBMODULE_STATUS_IN_HEAD: c_int = 1; +pub const GIT_SUBMODULE_STATUS_IN_INDEX: c_int = 2; +pub const GIT_SUBMODULE_STATUS_IN_CONFIG: c_int = 4; +pub const GIT_SUBMODULE_STATUS_IN_WD: c_int = 8; +pub const GIT_SUBMODULE_STATUS_INDEX_ADDED: c_int = 16; +pub const GIT_SUBMODULE_STATUS_INDEX_DELETED: c_int = 32; +pub const GIT_SUBMODULE_STATUS_INDEX_MODIFIED: c_int = 64; +pub const GIT_SUBMODULE_STATUS_WD_UNINITIALIZED: c_int = 128; +pub const GIT_SUBMODULE_STATUS_WD_ADDED: c_int = 256; +pub const GIT_SUBMODULE_STATUS_WD_DELETED: c_int = 512; +pub const GIT_SUBMODULE_STATUS_WD_MODIFIED: c_int = 1024; +pub const GIT_SUBMODULE_STATUS_WD_INDEX_MODIFIED: c_int = 2048; +pub const GIT_SUBMODULE_STATUS_WD_WD_MODIFIED: c_int = 4096; +pub const GIT_SUBMODULE_STATUS_WD_UNTRACKED: c_int = 8192; +pub const git_submodule_status_t = c_uint; +pub const git_submodule_cb = ?fn (*git_submodule, [*c]const u8, *c_void) callconv(.C) c_int; +pub const struct_git_submodule_update_options = extern struct { + version: c_uint, + checkout_opts: git_checkout_options, + fetch_opts: git_fetch_options, + allow_fetch: c_int, +}; +pub const git_submodule_update_options = struct_git_submodule_update_options; +pub const struct_git_worktree_add_options = extern struct { + version: c_uint, + lock: c_int, + ref: *git_reference, +}; +pub const git_worktree_add_options = struct_git_worktree_add_options; +pub const GIT_WORKTREE_PRUNE_VALID: c_int = 1; +pub const GIT_WORKTREE_PRUNE_LOCKED: c_int = 2; +pub const GIT_WORKTREE_PRUNE_WORKING_TREE: c_int = 4; +pub const git_worktree_prune_t = c_uint; +pub const struct_git_worktree_prune_options = extern struct { + version: c_uint, + flags: u32, +}; +pub const git_worktree_prune_options = struct_git_worktree_prune_options; +pub const struct_git_credential_userpass_payload = extern struct { + username: [*c]const u8, + password: [*c]const u8, +}; +pub const git_credential_userpass_payload = struct_git_credential_userpass_payload; +pub const git_attr_t = git_attr_value_t; +pub const git_commit_signing_cb = ?fn ([*c]git_buf, [*c]git_buf, [*c]const u8, *c_void) callconv(.C) c_int; +pub const git_cvar_map = git_configmap; +pub const GIT_DIFF_FORMAT_EMAIL_NONE: c_int = 0; +pub const GIT_DIFF_FORMAT_EMAIL_EXCLUDE_SUBJECT_PATCH_MARKER: c_int = 1; +pub const git_diff_format_email_flags_t = c_uint; +pub const git_diff_format_email_options = extern struct { + version: c_uint, + flags: u32, + patch_no: usize, + total_patches: usize, + id: [*c]const git_oid, + summary: [*c]const u8, + body: [*c]const u8, + author: [*c]const git_signature, +}; +pub const git_revparse_mode_t = git_revspec_t; +pub const git_cred = git_credential; +pub const git_cred_userpass_plaintext = git_credential_userpass_plaintext; +pub const git_cred_username = git_credential_username; +pub const git_cred_default = git_credential_default; +pub const git_cred_ssh_key = git_credential_ssh_key; +pub const git_cred_ssh_interactive = git_credential_ssh_interactive; +pub const git_cred_ssh_custom = git_credential_ssh_custom; +pub const git_cred_acquire_cb = git_credential_acquire_cb; +pub const git_cred_sign_callback = git_credential_sign_cb; +pub const git_cred_sign_cb = git_credential_sign_cb; +pub const git_cred_ssh_interactive_callback = git_credential_ssh_interactive_cb; +pub const git_cred_ssh_interactive_cb = git_credential_ssh_interactive_cb; +pub const git_cred_userpass_payload = git_credential_userpass_payload; +pub const git_trace_callback = git_trace_cb; +pub const git_transfer_progress = git_indexer_progress; +pub const git_transfer_progress_cb = git_indexer_progress_cb; +pub const git_push_transfer_progress = git_push_transfer_progress_cb; +pub const git_headlist_cb = ?fn ([*c]git_remote_head, *c_void) callconv(.C) c_int; +pub const GIT_EMAIL_CREATE_DEFAULT: c_int = 0; +pub const GIT_EMAIL_CREATE_OMIT_NUMBERS: c_int = 1; +pub const GIT_EMAIL_CREATE_ALWAYS_NUMBER: c_int = 2; +pub const GIT_EMAIL_CREATE_NO_RENAMES: c_int = 4; +pub const git_email_create_flags_t = c_uint; +pub const git_email_create_options = extern struct { + version: c_uint, + flags: u32, + diff_opts: git_diff_options, + diff_find_opts: git_diff_find_options, + subject_prefix: [*c]const u8, + start_number: usize, + reroll_number: usize, +}; +pub const git_message_trailer = extern struct { + key: [*c]const u8, + value: [*c]const u8, +}; +pub const git_message_trailer_array = extern struct { + trailers: [*c]git_message_trailer, + count: usize, + _trailer_block: [*c]u8, +}; +pub const git_note_foreach_cb = ?fn ([*c]const git_oid, [*c]const git_oid, *c_void) callconv(.C) c_int; +pub const struct_git_iterator = opaque {}; +pub const git_note_iterator = struct_git_iterator; +pub const git_odb_foreach_cb = ?fn ([*c]const git_oid, *c_void) callconv(.C) c_int; +pub const struct_git_odb_expand_id = extern struct { + id: git_oid, + length: c_ushort, + type: git_object_t, +}; +pub const git_odb_expand_id = struct_git_odb_expand_id; +pub const GIT_STREAM_RDONLY: c_int = 2; +pub const GIT_STREAM_WRONLY: c_int = 4; +pub const GIT_STREAM_RW: c_int = 6; +pub const git_odb_stream_t = c_uint; +pub const struct_git_patch = opaque {}; +pub const git_patch = struct_git_patch; +pub const struct_git_pathspec = opaque {}; +pub const git_pathspec = struct_git_pathspec; +pub const struct_git_pathspec_match_list = opaque {}; +pub const git_pathspec_match_list = struct_git_pathspec_match_list; +pub const GIT_PATHSPEC_DEFAULT: c_int = 0; +pub const GIT_PATHSPEC_IGNORE_CASE: c_int = 1; +pub const GIT_PATHSPEC_USE_CASE: c_int = 2; +pub const GIT_PATHSPEC_NO_GLOB: c_int = 4; +pub const GIT_PATHSPEC_NO_MATCH_ERROR: c_int = 8; +pub const GIT_PATHSPEC_FIND_FAILURES: c_int = 16; +pub const GIT_PATHSPEC_FAILURES_ONLY: c_int = 32; +pub const git_pathspec_flag_t = c_uint; +pub const GIT_RESET_SOFT: c_int = 1; +pub const GIT_RESET_MIXED: c_int = 2; +pub const GIT_RESET_HARD: c_int = 3; +pub const git_reset_t = c_uint; +pub const GIT_SORT_NONE: c_int = 0; +pub const GIT_SORT_TOPOLOGICAL: c_int = 1; +pub const GIT_SORT_TIME: c_int = 2; +pub const GIT_SORT_REVERSE: c_int = 4; +pub const git_sort_t = c_uint; +pub const git_revwalk_hide_cb = ?fn ([*c]const git_oid, *c_void) callconv(.C) c_int; +pub const git_tag_foreach_cb = ?fn ([*c]const u8, [*c]git_oid, *c_void) callconv(.C) c_int; + +pub const git_libgit2_version = fn (major: [*c]c_int, minor: [*c]c_int, rev: [*c]c_int) callconv(.C) c_int; +pub const git_libgit2_features = fn () callconv(.C) c_int; +pub const git_libgit2_opts = fn (option: c_int, ...) callconv(.C) c_int; +pub const git_buf_dispose = fn (buffer: [*c]git_buf) callconv(.C) void; +pub const git_buf_grow = fn (buffer: [*c]git_buf, target_size: usize) callconv(.C) c_int; +pub const git_buf_set = fn (buffer: [*c]git_buf, data: *const c_void, datalen: usize) callconv(.C) c_int; +pub const git_buf_is_binary = fn (buf: [*c]const git_buf) callconv(.C) c_int; +pub const git_buf_contains_nul = fn (buf: [*c]const git_buf) callconv(.C) c_int; +pub const git_oid_fromstr = fn (out: [*c]git_oid, str: [*c]const u8) callconv(.C) c_int; +pub const git_oid_fromstrp = fn (out: [*c]git_oid, str: [*c]const u8) callconv(.C) c_int; +pub const git_oid_fromstrn = fn (out: [*c]git_oid, str: [*c]const u8, length: usize) callconv(.C) c_int; +pub const git_oid_fromraw = fn (out: [*c]git_oid, raw: [*c]const u8) callconv(.C) c_int; +pub const git_oid_fmt = fn (out: [*c]u8, id: [*c]const git_oid) callconv(.C) c_int; +pub const git_oid_nfmt = fn (out: [*c]u8, n: usize, id: [*c]const git_oid) callconv(.C) c_int; +pub const git_oid_pathfmt = fn (out: [*c]u8, id: [*c]const git_oid) callconv(.C) c_int; +pub const git_oid_tostr_s = fn (oid: [*c]const git_oid) callconv(.C) [*c]u8; +pub const git_oid_tostr = fn (out: [*c]u8, n: usize, id: [*c]const git_oid) callconv(.C) [*c]u8; +pub const git_oid_cpy = fn (out: [*c]git_oid, src: [*c]const git_oid) callconv(.C) c_int; +pub const git_oid_cmp = fn (a: [*c]const git_oid, b: [*c]const git_oid) callconv(.C) c_int; +pub const git_oid_equal = fn (a: [*c]const git_oid, b: [*c]const git_oid) callconv(.C) c_int; +pub const git_oid_ncmp = fn (a: [*c]const git_oid, b: [*c]const git_oid, len: usize) callconv(.C) c_int; +pub const git_oid_streq = fn (id: [*c]const git_oid, str: [*c]const u8) callconv(.C) c_int; +pub const git_oid_strcmp = fn (id: [*c]const git_oid, str: [*c]const u8) callconv(.C) c_int; +pub const git_oid_is_zero = fn (id: [*c]const git_oid) callconv(.C) c_int; +pub const git_oid_shorten_new = fn (min_length: usize) callconv(.C) *git_oid_shorten; +pub const git_oid_shorten_add = fn (os: *git_oid_shorten, text_id: [*c]const u8) callconv(.C) c_int; +pub const git_oid_shorten_free = fn (os: *git_oid_shorten) callconv(.C) void; +pub const git_repository_open = fn (out: *git_repository, path: [*c]const u8) callconv(.C) c_int; +pub const git_repository_open_from_worktree = fn (out: *git_repository, wt: *git_worktree) callconv(.C) c_int; +pub const git_repository_wrap_odb = fn (out: *git_repository, odb: *git_odb) callconv(.C) c_int; +pub const git_repository_discover = fn (out: [*c]git_buf, start_path: [*c]const u8, across_fs: c_int, ceiling_dirs: [*c]const u8) callconv(.C) c_int; +pub const git_repository_open_ext = fn (out: *git_repository, path: [*c]const u8, flags: c_uint, ceiling_dirs: [*c]const u8) callconv(.C) c_int; +pub const git_repository_open_bare = fn (out: *git_repository, bare_path: [*c]const u8) callconv(.C) c_int; +pub const git_repository_free = fn (repo: *git_repository) callconv(.C) void; +pub const git_repository_init = fn (out: *?*git_repository, path: [*c]const u8, is_bare: c_uint) callconv(.C) c_int; +pub const git_repository_init_options_init = fn (opts: ?*git_repository_init_options, version: c_uint) callconv(.C) c_int; +pub const git_repository_init_ext = fn (out: ?*git_repository, repo_path: [*c]const u8, opts: ?*git_repository_init_options) callconv(.C) c_int; +pub const git_repository_head = fn (out: [*c]*git_reference, repo: *git_repository) callconv(.C) c_int; +pub const git_repository_head_for_worktree = fn (out: [*c]*git_reference, repo: *git_repository, name: [*c]const u8) callconv(.C) c_int; +pub const git_repository_head_detached = fn (repo: *git_repository) callconv(.C) c_int; +pub const git_repository_head_detached_for_worktree = fn (repo: *git_repository, name: [*c]const u8) callconv(.C) c_int; +pub const git_repository_head_unborn = fn (repo: *git_repository) callconv(.C) c_int; +pub const git_repository_is_empty = fn (repo: *git_repository) callconv(.C) c_int; +pub const git_repository_item_path = fn (out: [*c]git_buf, repo: *const git_repository, item: git_repository_item_t) callconv(.C) c_int; +pub const git_repository_path = fn (repo: *const git_repository) callconv(.C) [*c]const u8; +pub const git_repository_workdir = fn (repo: *const git_repository) callconv(.C) [*c]const u8; +pub const git_repository_commondir = fn (repo: *const git_repository) callconv(.C) [*c]const u8; +pub const git_repository_set_workdir = fn (repo: *git_repository, workdir: [*c]const u8, update_gitlink: c_int) callconv(.C) c_int; +pub const git_repository_is_bare = fn (repo: *const git_repository) callconv(.C) c_int; +pub const git_repository_is_worktree = fn (repo: *const git_repository) callconv(.C) c_int; +pub const git_repository_config = fn (out: [*c]*git_config, repo: *git_repository) callconv(.C) c_int; +pub const git_repository_config_snapshot = fn (out: [*c]*git_config, repo: *git_repository) callconv(.C) c_int; +pub const git_repository_odb = fn (out: [*c]*git_odb, repo: *git_repository) callconv(.C) c_int; +pub const git_repository_refdb = fn (out: [*c]*git_refdb, repo: *git_repository) callconv(.C) c_int; +pub const git_repository_index = fn (out: *?*git_index, repo: *git_repository) callconv(.C) c_int; +pub const git_repository_message = fn (out: [*c]git_buf, repo: *git_repository) callconv(.C) c_int; +pub const git_repository_message_remove = fn (repo: *git_repository) callconv(.C) c_int; +pub const git_repository_state_cleanup = fn (repo: *git_repository) callconv(.C) c_int; +pub const git_repository_fetchhead_foreach = fn (repo: *git_repository, callback: git_repository_fetchhead_foreach_cb, payload: *c_void) callconv(.C) c_int; +pub const git_repository_mergehead_foreach = fn (repo: *git_repository, callback: git_repository_mergehead_foreach_cb, payload: *c_void) callconv(.C) c_int; +pub const git_repository_hashfile = fn (out: [*c]git_oid, repo: *git_repository, path: [*c]const u8, @"type": git_object_t, as_path: [*c]const u8) callconv(.C) c_int; +pub const git_repository_set_head = fn (repo: *git_repository, refname: [*c]const u8) callconv(.C) c_int; +pub const git_repository_set_head_detached = fn (repo: *git_repository, commitish: [*c]const git_oid) callconv(.C) c_int; +pub const git_repository_set_head_detached_from_annotated = fn (repo: *git_repository, commitish: *const git_annotated_commit) callconv(.C) c_int; +pub const git_repository_detach_head = fn (repo: *git_repository) callconv(.C) c_int; +pub const git_repository_state = fn (repo: *git_repository) callconv(.C) c_int; +pub const git_repository_set_namespace = fn (repo: *git_repository, nmspace: [*c]const u8) callconv(.C) c_int; +pub const git_repository_get_namespace = fn (repo: *git_repository) callconv(.C) [*c]const u8; +pub const git_repository_is_shallow = fn (repo: *git_repository) callconv(.C) c_int; +pub const git_repository_ident = fn (name: [*c][*c]const u8, email: [*c][*c]const u8, repo: *const git_repository) callconv(.C) c_int; +pub const git_repository_set_ident = fn (repo: *git_repository, name: [*c]const u8, email: [*c]const u8) callconv(.C) c_int; +pub const git_annotated_commit_from_ref = fn (out: [*c]*git_annotated_commit, repo: *git_repository, ref: *const git_reference) callconv(.C) c_int; +pub const git_annotated_commit_from_fetchhead = fn (out: [*c]*git_annotated_commit, repo: *git_repository, branch_name: [*c]const u8, remote_url: [*c]const u8, id: [*c]const git_oid) callconv(.C) c_int; +pub const git_annotated_commit_lookup = fn (out: [*c]*git_annotated_commit, repo: *git_repository, id: [*c]const git_oid) callconv(.C) c_int; +pub const git_annotated_commit_from_revspec = fn (out: [*c]*git_annotated_commit, repo: *git_repository, revspec: [*c]const u8) callconv(.C) c_int; +pub const git_annotated_commit_id = fn (commit: *const git_annotated_commit) callconv(.C) [*c]const git_oid; +pub const git_annotated_commit_ref = fn (commit: *const git_annotated_commit) callconv(.C) [*c]const u8; +pub const git_annotated_commit_free = fn (commit: *git_annotated_commit) callconv(.C) void; +pub const git_object_lookup = fn (object: [*c]*git_object, repo: *git_repository, id: [*c]const git_oid, @"type": git_object_t) callconv(.C) c_int; +pub const git_object_lookup_prefix = fn (object_out: [*c]*git_object, repo: *git_repository, id: [*c]const git_oid, len: usize, @"type": git_object_t) callconv(.C) c_int; +pub const git_object_lookup_bypath = fn (out: [*c]*git_object, treeish: *const git_object, path: [*c]const u8, @"type": git_object_t) callconv(.C) c_int; +pub const git_object_id = fn (obj: *const git_object) callconv(.C) [*c]const git_oid; +pub const git_object_short_id = fn (out: [*c]git_buf, obj: *const git_object) callconv(.C) c_int; +pub const git_object_type = fn (obj: *const git_object) callconv(.C) git_object_t; +pub const git_object_owner = fn (obj: *const git_object) callconv(.C) *git_repository; +pub const git_object_free = fn (object: *git_object) callconv(.C) void; +pub const git_object_type2string = fn (@"type": git_object_t) callconv(.C) [*c]const u8; +pub const git_object_string2type = fn (str: [*c]const u8) callconv(.C) git_object_t; +pub const git_object_typeisloose = fn (@"type": git_object_t) callconv(.C) c_int; +pub const git_object_peel = fn (peeled: [*c]*git_object, object: *const git_object, target_type: git_object_t) callconv(.C) c_int; +pub const git_object_dup = fn (dest: [*c]*git_object, source: *git_object) callconv(.C) c_int; +pub const git_tree_lookup = fn (out: [*c]*git_tree, repo: *git_repository, id: [*c]const git_oid) callconv(.C) c_int; +pub const git_tree_lookup_prefix = fn (out: [*c]*git_tree, repo: *git_repository, id: [*c]const git_oid, len: usize) callconv(.C) c_int; +pub const git_tree_free = fn (tree: *git_tree) callconv(.C) void; +pub const git_tree_id = fn (tree: *const git_tree) callconv(.C) [*c]const git_oid; +pub const git_tree_owner = fn (tree: *const git_tree) callconv(.C) *git_repository; +pub const git_tree_entrycount = fn (tree: *const git_tree) callconv(.C) usize; +pub const git_tree_entry_byname = fn (tree: *const git_tree, filename: [*c]const u8) callconv(.C) *const git_tree_entry; +pub const git_tree_entry_byindex = fn (tree: *const git_tree, idx: usize) callconv(.C) *const git_tree_entry; +pub const git_tree_entry_byid = fn (tree: *const git_tree, id: [*c]const git_oid) callconv(.C) *const git_tree_entry; +pub const git_tree_entry_bypath = fn (out: [*c]*git_tree_entry, root: *const git_tree, path: [*c]const u8) callconv(.C) c_int; +pub const git_tree_entry_dup = fn (dest: [*c]*git_tree_entry, source: *const git_tree_entry) callconv(.C) c_int; +pub const git_tree_entry_free = fn (entry: *git_tree_entry) callconv(.C) void; +pub const git_tree_entry_name = fn (entry: *const git_tree_entry) callconv(.C) [*c]const u8; +pub const git_tree_entry_id = fn (entry: *const git_tree_entry) callconv(.C) [*c]const git_oid; +pub const git_tree_entry_type = fn (entry: *const git_tree_entry) callconv(.C) git_object_t; +pub const git_tree_entry_filemode = fn (entry: *const git_tree_entry) callconv(.C) git_filemode_t; +pub const git_tree_entry_filemode_raw = fn (entry: *const git_tree_entry) callconv(.C) git_filemode_t; +pub const git_tree_entry_cmp = fn (e1: *const git_tree_entry, e2: *const git_tree_entry) callconv(.C) c_int; +pub const git_tree_entry_to_object = fn (object_out: [*c]*git_object, repo: *git_repository, entry: *const git_tree_entry) callconv(.C) c_int; +pub const git_treebuilder_new = fn (out: [*c]*git_treebuilder, repo: *git_repository, source: *const git_tree) callconv(.C) c_int; +pub const git_treebuilder_clear = fn (bld: *git_treebuilder) callconv(.C) c_int; +pub const git_treebuilder_entrycount = fn (bld: *git_treebuilder) callconv(.C) usize; +pub const git_treebuilder_free = fn (bld: *git_treebuilder) callconv(.C) void; +pub const git_treebuilder_get = fn (bld: *git_treebuilder, filename: [*c]const u8) callconv(.C) *const git_tree_entry; +pub const git_treebuilder_insert = fn (out: [*c]*const git_tree_entry, bld: *git_treebuilder, filename: [*c]const u8, id: [*c]const git_oid, filemode: git_filemode_t) callconv(.C) c_int; +pub const git_treebuilder_remove = fn (bld: *git_treebuilder, filename: [*c]const u8) callconv(.C) c_int; +pub const git_treebuilder_filter = fn (bld: *git_treebuilder, filter: git_treebuilder_filter_cb, payload: *c_void) callconv(.C) c_int; +pub const git_treebuilder_write = fn (id: [*c]git_oid, bld: *git_treebuilder) callconv(.C) c_int; +pub const git_tree_walk = fn (tree: *const git_tree, mode: git_treewalk_mode, callback: git_treewalk_cb, payload: *c_void) callconv(.C) c_int; +pub const git_tree_dup = fn (out: [*c]*git_tree, source: *git_tree) callconv(.C) c_int; +pub const git_tree_create_updated = fn (out: [*c]git_oid, repo: *git_repository, baseline: *git_tree, nupdates: usize, updates: [*c]const git_tree_update) callconv(.C) c_int; +pub const git_strarray_dispose = fn (array: [*c]git_strarray) callconv(.C) void; +pub const git_strarray_copy = fn (tgt: [*c]git_strarray, src: [*c]const git_strarray) callconv(.C) c_int; +pub const git_reference_lookup = fn (out: [*c]*git_reference, repo: *git_repository, name: [*c]const u8) callconv(.C) c_int; +pub const git_reference_name_to_id = fn (out: [*c]git_oid, repo: *git_repository, name: [*c]const u8) callconv(.C) c_int; +pub const git_reference_dwim = fn (out: [*c]*git_reference, repo: *git_repository, shorthand: [*c]const u8) callconv(.C) c_int; +pub const git_reference_symbolic_create_matching = fn (out: [*c]*git_reference, repo: *git_repository, name: [*c]const u8, target: [*c]const u8, force: c_int, current_value: [*c]const u8, log_message: [*c]const u8) callconv(.C) c_int; +pub const git_reference_symbolic_create = fn (out: [*c]*git_reference, repo: *git_repository, name: [*c]const u8, target: [*c]const u8, force: c_int, log_message: [*c]const u8) callconv(.C) c_int; +pub const git_reference_create = fn (out: [*c]*git_reference, repo: *git_repository, name: [*c]const u8, id: [*c]const git_oid, force: c_int, log_message: [*c]const u8) callconv(.C) c_int; +pub const git_reference_create_matching = fn (out: [*c]*git_reference, repo: *git_repository, name: [*c]const u8, id: [*c]const git_oid, force: c_int, current_id: [*c]const git_oid, log_message: [*c]const u8) callconv(.C) c_int; +pub const git_reference_target = fn (ref: *const git_reference) callconv(.C) [*c]const git_oid; +pub const git_reference_target_peel = fn (ref: *const git_reference) callconv(.C) [*c]const git_oid; +pub const git_reference_symbolic_target = fn (ref: *const git_reference) callconv(.C) [*c]const u8; +pub const git_reference_type = fn (ref: *const git_reference) callconv(.C) git_reference_t; +pub const git_reference_name = fn (ref: *const git_reference) callconv(.C) [*c]const u8; +pub const git_reference_resolve = fn (out: [*c]*git_reference, ref: *const git_reference) callconv(.C) c_int; +pub const git_reference_owner = fn (ref: *const git_reference) callconv(.C) *git_repository; +pub const git_reference_symbolic_set_target = fn (out: [*c]*git_reference, ref: *git_reference, target: [*c]const u8, log_message: [*c]const u8) callconv(.C) c_int; +pub const git_reference_set_target = fn (out: [*c]*git_reference, ref: *git_reference, id: [*c]const git_oid, log_message: [*c]const u8) callconv(.C) c_int; +pub const git_reference_rename = fn (new_ref: [*c]*git_reference, ref: *git_reference, new_name: [*c]const u8, force: c_int, log_message: [*c]const u8) callconv(.C) c_int; +pub const git_reference_delete = fn (ref: *git_reference) callconv(.C) c_int; +pub const git_reference_remove = fn (repo: *git_repository, name: [*c]const u8) callconv(.C) c_int; +pub const git_reference_list = fn (array: [*c]git_strarray, repo: *git_repository) callconv(.C) c_int; +pub const git_reference_foreach = fn (repo: *git_repository, callback: git_reference_foreach_cb, payload: *c_void) callconv(.C) c_int; +pub const git_reference_foreach_name = fn (repo: *git_repository, callback: git_reference_foreach_name_cb, payload: *c_void) callconv(.C) c_int; +pub const git_reference_dup = fn (dest: [*c]*git_reference, source: *git_reference) callconv(.C) c_int; +pub const git_reference_free = fn (ref: *git_reference) callconv(.C) void; +pub const git_reference_cmp = fn (ref1: *const git_reference, ref2: *const git_reference) callconv(.C) c_int; +pub const git_reference_iterator_new = fn (out: [*c]*git_reference_iterator, repo: *git_repository) callconv(.C) c_int; +pub const git_reference_iterator_glob_new = fn (out: [*c]*git_reference_iterator, repo: *git_repository, glob: [*c]const u8) callconv(.C) c_int; +pub const git_reference_next = fn (out: [*c]*git_reference, iter: *git_reference_iterator) callconv(.C) c_int; +pub const git_reference_next_name = fn (out: [*c][*c]const u8, iter: *git_reference_iterator) callconv(.C) c_int; +pub const git_reference_iterator_free = fn (iter: *git_reference_iterator) callconv(.C) void; +pub const git_reference_foreach_glob = fn (repo: *git_repository, glob: [*c]const u8, callback: git_reference_foreach_name_cb, payload: *c_void) callconv(.C) c_int; +pub const git_reference_has_log = fn (repo: *git_repository, refname: [*c]const u8) callconv(.C) c_int; +pub const git_reference_ensure_log = fn (repo: *git_repository, refname: [*c]const u8) callconv(.C) c_int; +pub const git_reference_is_branch = fn (ref: *const git_reference) callconv(.C) c_int; +pub const git_reference_is_remote = fn (ref: *const git_reference) callconv(.C) c_int; +pub const git_reference_is_tag = fn (ref: *const git_reference) callconv(.C) c_int; +pub const git_reference_is_note = fn (ref: *const git_reference) callconv(.C) c_int; +pub const git_reference_normalize_name = fn (buffer_out: [*c]u8, buffer_size: usize, name: [*c]const u8, flags: c_uint) callconv(.C) c_int; +pub const git_reference_peel = fn (out: [*c]*git_object, ref: *const git_reference, @"type": git_object_t) callconv(.C) c_int; +pub const git_reference_name_is_valid = fn (valid: [*c]c_int, refname: [*c]const u8) callconv(.C) c_int; +pub const git_reference_shorthand = fn (ref: *const git_reference) callconv(.C) [*c]const u8; +pub const git_diff_options_init = fn (opts: [*c]git_diff_options, version: c_uint) callconv(.C) c_int; +pub const git_diff_find_options_init = fn (opts: [*c]git_diff_find_options, version: c_uint) callconv(.C) c_int; +pub const git_diff_free = fn (diff: *git_diff) callconv(.C) void; +pub const git_diff_tree_to_tree = fn (diff: [*c]*git_diff, repo: *git_repository, old_tree: *git_tree, new_tree: *git_tree, opts: [*c]const git_diff_options) callconv(.C) c_int; +pub const git_diff_tree_to_index = fn (diff: [*c]*git_diff, repo: *git_repository, old_tree: *git_tree, index: *git_index, opts: [*c]const git_diff_options) callconv(.C) c_int; +pub const git_diff_index_to_workdir = fn (diff: [*c]*git_diff, repo: *git_repository, index: *git_index, opts: [*c]const git_diff_options) callconv(.C) c_int; +pub const git_diff_tree_to_workdir = fn (diff: [*c]*git_diff, repo: *git_repository, old_tree: *git_tree, opts: [*c]const git_diff_options) callconv(.C) c_int; +pub const git_diff_tree_to_workdir_with_index = fn (diff: [*c]*git_diff, repo: *git_repository, old_tree: *git_tree, opts: [*c]const git_diff_options) callconv(.C) c_int; +pub const git_diff_index_to_index = fn (diff: [*c]*git_diff, repo: *git_repository, old_index: *git_index, new_index: *git_index, opts: [*c]const git_diff_options) callconv(.C) c_int; +pub const git_diff_merge = fn (onto: *git_diff, from: *const git_diff) callconv(.C) c_int; +pub const git_diff_find_similar = fn (diff: *git_diff, options: [*c]const git_diff_find_options) callconv(.C) c_int; +pub const git_diff_num_deltas = fn (diff: *const git_diff) callconv(.C) usize; +pub const git_diff_num_deltas_of_type = fn (diff: *const git_diff, @"type": git_delta_t) callconv(.C) usize; +pub const git_diff_get_delta = fn (diff: *const git_diff, idx: usize) callconv(.C) [*c]const git_diff_delta; +pub const git_diff_is_sorted_icase = fn (diff: *const git_diff) callconv(.C) c_int; +pub const git_diff_foreach = fn (diff: *git_diff, file_cb: git_diff_file_cb, binary_cb: git_diff_binary_cb, hunk_cb: git_diff_hunk_cb, line_cb: git_diff_line_cb, payload: *c_void) callconv(.C) c_int; +pub const git_diff_status_char = fn (status: git_delta_t) callconv(.C) u8; +pub const git_diff_print = fn (diff: *git_diff, format: git_diff_format_t, print_cb: git_diff_line_cb, payload: *c_void) callconv(.C) c_int; +pub const git_diff_to_buf = fn (out: [*c]git_buf, diff: *git_diff, format: git_diff_format_t) callconv(.C) c_int; +pub const git_diff_blobs = fn (old_blob: *const git_blob, old_as_path: [*c]const u8, new_blob: *const git_blob, new_as_path: [*c]const u8, options: [*c]const git_diff_options, file_cb: git_diff_file_cb, binary_cb: git_diff_binary_cb, hunk_cb: git_diff_hunk_cb, line_cb: git_diff_line_cb, payload: *c_void) callconv(.C) c_int; +pub const git_diff_blob_to_buffer = fn (old_blob: *const git_blob, old_as_path: [*c]const u8, buffer: [*c]const u8, buffer_len: usize, buffer_as_path: [*c]const u8, options: [*c]const git_diff_options, file_cb: git_diff_file_cb, binary_cb: git_diff_binary_cb, hunk_cb: git_diff_hunk_cb, line_cb: git_diff_line_cb, payload: *c_void) callconv(.C) c_int; +pub const git_diff_buffers = fn (old_buffer: *const c_void, old_len: usize, old_as_path: [*c]const u8, new_buffer: *const c_void, new_len: usize, new_as_path: [*c]const u8, options: [*c]const git_diff_options, file_cb: git_diff_file_cb, binary_cb: git_diff_binary_cb, hunk_cb: git_diff_hunk_cb, line_cb: git_diff_line_cb, payload: *c_void) callconv(.C) c_int; +pub const git_diff_from_buffer = fn (out: [*c]*git_diff, content: [*c]const u8, content_len: usize) callconv(.C) c_int; +pub const git_diff_get_stats = fn (out: [*c]*git_diff_stats, diff: *git_diff) callconv(.C) c_int; +pub const git_diff_stats_files_changed = fn (stats: *const git_diff_stats) callconv(.C) usize; +pub const git_diff_stats_insertions = fn (stats: *const git_diff_stats) callconv(.C) usize; +pub const git_diff_stats_deletions = fn (stats: *const git_diff_stats) callconv(.C) usize; +pub const git_diff_stats_to_buf = fn (out: [*c]git_buf, stats: *const git_diff_stats, format: git_diff_stats_format_t, width: usize) callconv(.C) c_int; +pub const git_diff_stats_free = fn (stats: *git_diff_stats) callconv(.C) void; +pub const git_diff_patchid_options_init = fn (opts: [*c]git_diff_patchid_options, version: c_uint) callconv(.C) c_int; +pub const git_diff_patchid = fn (out: [*c]git_oid, diff: *git_diff, opts: [*c]git_diff_patchid_options) callconv(.C) c_int; +pub const git_apply_options_init = fn (opts: [*c]git_apply_options, version: c_uint) callconv(.C) c_int; +pub const git_apply_to_tree = fn (out: [*c]*git_index, repo: *git_repository, preimage: *git_tree, diff: *git_diff, options: [*c]const git_apply_options) callconv(.C) c_int; +pub const git_apply = fn (repo: *git_repository, diff: *git_diff, location: git_apply_location_t, options: [*c]const git_apply_options) callconv(.C) c_int; +pub const git_attr_value = fn (attr: [*c]const u8) callconv(.C) git_attr_value_t; +pub const git_attr_get = fn (value_out: [*c][*c]const u8, repo: *git_repository, flags: u32, path: [*c]const u8, name: [*c]const u8) callconv(.C) c_int; +pub const git_attr_get_ext = fn (value_out: [*c][*c]const u8, repo: *git_repository, opts: [*c]git_attr_options, path: [*c]const u8, name: [*c]const u8) callconv(.C) c_int; +pub const git_attr_get_many = fn (values_out: [*c][*c]const u8, repo: *git_repository, flags: u32, path: [*c]const u8, num_attr: usize, names: [*c][*c]const u8) callconv(.C) c_int; +pub const git_attr_get_many_ext = fn (values_out: [*c][*c]const u8, repo: *git_repository, opts: [*c]git_attr_options, path: [*c]const u8, num_attr: usize, names: [*c][*c]const u8) callconv(.C) c_int; +pub const git_attr_foreach = fn (repo: *git_repository, flags: u32, path: [*c]const u8, callback: git_attr_foreach_cb, payload: *c_void) callconv(.C) c_int; +pub const git_attr_foreach_ext = fn (repo: *git_repository, opts: [*c]git_attr_options, path: [*c]const u8, callback: git_attr_foreach_cb, payload: *c_void) callconv(.C) c_int; +pub const git_attr_cache_flush = fn (repo: *git_repository) callconv(.C) c_int; +pub const git_attr_add_macro = fn (repo: *git_repository, name: [*c]const u8, values: [*c]const u8) callconv(.C) c_int; +pub const git_blob_lookup = fn (blob: [*c]*git_blob, repo: *git_repository, id: [*c]const git_oid) callconv(.C) c_int; +pub const git_blob_lookup_prefix = fn (blob: [*c]*git_blob, repo: *git_repository, id: [*c]const git_oid, len: usize) callconv(.C) c_int; +pub const git_blob_free = fn (blob: *git_blob) callconv(.C) void; +pub const git_blob_id = fn (blob: *const git_blob) callconv(.C) [*c]const git_oid; +pub const git_blob_owner = fn (blob: *const git_blob) callconv(.C) *git_repository; +pub const git_blob_rawcontent = fn (blob: *const git_blob) callconv(.C) *const c_void; +pub const git_blob_rawsize = fn (blob: *const git_blob) callconv(.C) git_object_size_t; +pub const git_blob_filter_options_init = fn (opts: [*c]git_blob_filter_options, version: c_uint) callconv(.C) c_int; +pub const git_blob_filter = fn (out: [*c]git_buf, blob: *git_blob, as_path: [*c]const u8, opts: [*c]git_blob_filter_options) callconv(.C) c_int; +pub const git_blob_create_from_workdir = fn (id: [*c]git_oid, repo: *git_repository, relative_path: [*c]const u8) callconv(.C) c_int; +pub const git_blob_create_from_disk = fn (id: [*c]git_oid, repo: *git_repository, path: [*c]const u8) callconv(.C) c_int; +pub const git_blob_create_from_stream = fn (out: [*c][*c]git_writestream, repo: *git_repository, hintpath: [*c]const u8) callconv(.C) c_int; +pub const git_blob_create_from_stream_commit = fn (out: [*c]git_oid, stream: [*c]git_writestream) callconv(.C) c_int; +pub const git_blob_create_from_buffer = fn (id: [*c]git_oid, repo: *git_repository, buffer: *const c_void, len: usize) callconv(.C) c_int; +pub const git_blob_is_binary = fn (blob: *const git_blob) callconv(.C) c_int; +pub const git_blob_dup = fn (out: [*c]*git_blob, source: *git_blob) callconv(.C) c_int; +pub const git_blame_options_init = fn (opts: [*c]git_blame_options, version: c_uint) callconv(.C) c_int; +pub const git_blame_get_hunk_count = fn (blame: *git_blame) callconv(.C) u32; +pub const git_blame_get_hunk_byindex = fn (blame: *git_blame, index: u32) callconv(.C) [*c]const git_blame_hunk; +pub const git_blame_get_hunk_byline = fn (blame: *git_blame, lineno: usize) callconv(.C) [*c]const git_blame_hunk; +pub const git_blame_file = fn (out: [*c]*git_blame, repo: *git_repository, path: [*c]const u8, options: [*c]git_blame_options) callconv(.C) c_int; +pub const git_blame_buffer = fn (out: [*c]*git_blame, reference: *git_blame, buffer: [*c]const u8, buffer_len: usize) callconv(.C) c_int; +pub const git_blame_free = fn (blame: *git_blame) callconv(.C) void; +pub const git_branch_create = fn (out: [*c]*git_reference, repo: *git_repository, branch_name: [*c]const u8, target: *const git_commit, force: c_int) callconv(.C) c_int; +pub const git_branch_create_from_annotated = fn (ref_out: [*c]*git_reference, repository: *git_repository, branch_name: [*c]const u8, commit: *const git_annotated_commit, force: c_int) callconv(.C) c_int; +pub const git_branch_delete = fn (branch: *git_reference) callconv(.C) c_int; +pub const git_branch_iterator_new = fn (out: [*c]*git_branch_iterator, repo: *git_repository, list_flags: git_branch_t) callconv(.C) c_int; +pub const git_branch_next = fn (out: [*c]*git_reference, out_type: [*c]git_branch_t, iter: *git_branch_iterator) callconv(.C) c_int; +pub const git_branch_iterator_free = fn (iter: *git_branch_iterator) callconv(.C) void; +pub const git_branch_move = fn (out: [*c]*git_reference, branch: *git_reference, new_branch_name: [*c]const u8, force: c_int) callconv(.C) c_int; +pub const git_branch_lookup = fn (out: [*c]*git_reference, repo: *git_repository, branch_name: [*c]const u8, branch_type: git_branch_t) callconv(.C) c_int; +pub const git_branch_name = fn (out: [*c][*c]const u8, ref: *const git_reference) callconv(.C) c_int; +pub const git_branch_upstream = fn (out: [*c]*git_reference, branch: *const git_reference) callconv(.C) c_int; +pub const git_branch_set_upstream = fn (branch: *git_reference, branch_name: [*c]const u8) callconv(.C) c_int; +pub const git_branch_upstream_name = fn (out: [*c]git_buf, repo: *git_repository, refname: [*c]const u8) callconv(.C) c_int; +pub const git_branch_is_head = fn (branch: *const git_reference) callconv(.C) c_int; +pub const git_branch_is_checked_out = fn (branch: *const git_reference) callconv(.C) c_int; +pub const git_branch_remote_name = fn (out: [*c]git_buf, repo: *git_repository, refname: [*c]const u8) callconv(.C) c_int; +pub const git_branch_upstream_remote = fn (buf: [*c]git_buf, repo: *git_repository, refname: [*c]const u8) callconv(.C) c_int; +pub const git_branch_upstream_merge = fn (buf: [*c]git_buf, repo: *git_repository, refname: [*c]const u8) callconv(.C) c_int; +pub const git_branch_name_is_valid = fn (valid: [*c]c_int, name: [*c]const u8) callconv(.C) c_int; +pub const git_checkout_options_init = fn (opts: [*c]git_checkout_options, version: c_uint) callconv(.C) c_int; +pub const git_checkout_head = fn (repo: *git_repository, opts: [*c]const git_checkout_options) callconv(.C) c_int; +pub const git_checkout_index = fn (repo: *git_repository, index: *git_index, opts: [*c]const git_checkout_options) callconv(.C) c_int; +pub const git_checkout_tree = fn (repo: *git_repository, treeish: *const git_object, opts: [*c]const git_checkout_options) callconv(.C) c_int; +pub const git_oidarray_dispose = fn (array: [*c]git_oidarray) callconv(.C) void; +pub const git_indexer_options_init = fn (opts: [*c]git_indexer_options, version: c_uint) callconv(.C) c_int; +pub const git_indexer_new = fn (out: [*c]*git_indexer, path: [*c]const u8, mode: c_uint, odb: *git_odb, opts: [*c]git_indexer_options) callconv(.C) c_int; +pub const git_indexer_append = fn (idx: *git_indexer, data: *const c_void, size: usize, stats: [*c]git_indexer_progress) callconv(.C) c_int; +pub const git_indexer_commit = fn (idx: *git_indexer, stats: [*c]git_indexer_progress) callconv(.C) c_int; +pub const git_indexer_hash = fn (idx: *const git_indexer) callconv(.C) [*c]const git_oid; +pub const git_indexer_free = fn (idx: *git_indexer) callconv(.C) void; +pub const git_index_open = fn (out: [*c]*git_index, index_path: [*c]const u8) callconv(.C) c_int; +pub const git_index_new = fn (out: [*c]*git_index) callconv(.C) c_int; +pub const git_index_free = fn (index: *git_index) callconv(.C) void; +pub const git_index_owner = fn (index: *const git_index) callconv(.C) *git_repository; +pub const git_index_caps = fn (index: *const git_index) callconv(.C) c_int; +pub const git_index_set_caps = fn (index: *git_index, caps: c_int) callconv(.C) c_int; +pub const git_index_version = fn (index: *git_index) callconv(.C) c_uint; +pub const git_index_set_version = fn (index: *git_index, version: c_uint) callconv(.C) c_int; +pub const git_index_read = fn (index: *git_index, force: c_int) callconv(.C) c_int; +pub const git_index_write = fn (index: *git_index) callconv(.C) c_int; +pub const git_index_path = fn (index: *const git_index) callconv(.C) [*c]const u8; +pub const git_index_checksum = fn (index: *git_index) callconv(.C) [*c]const git_oid; +pub const git_index_read_tree = fn (index: *git_index, tree: *const git_tree) callconv(.C) c_int; +pub const git_index_write_tree = fn (out: [*c]git_oid, index: ?*git_index) callconv(.C) c_int; +pub const git_index_write_tree_to = fn (out: [*c]git_oid, index: *git_index, repo: *git_repository) callconv(.C) c_int; +pub const git_index_entrycount = fn (index: *const git_index) callconv(.C) usize; +pub const git_index_clear = fn (index: *git_index) callconv(.C) c_int; +pub const git_index_get_byindex = fn (index: *git_index, n: usize) callconv(.C) [*c]const git_index_entry; +pub const git_index_get_bypath = fn (index: *git_index, path: [*c]const u8, stage: c_int) callconv(.C) [*c]const git_index_entry; +pub const git_index_remove = fn (index: *git_index, path: [*c]const u8, stage: c_int) callconv(.C) c_int; +pub const git_index_remove_directory = fn (index: *git_index, dir: [*c]const u8, stage: c_int) callconv(.C) c_int; +pub const git_index_add = fn (index: *git_index, source_entry: [*c]const git_index_entry) callconv(.C) c_int; +pub const git_index_entry_stage = fn (entry: [*c]const git_index_entry) callconv(.C) c_int; +pub const git_index_entry_is_conflict = fn (entry: [*c]const git_index_entry) callconv(.C) c_int; +pub const git_index_iterator_new = fn (iterator_out: [*c]*git_index_iterator, index: *git_index) callconv(.C) c_int; +pub const git_index_iterator_next = fn (out: [*c][*c]const git_index_entry, iterator: *git_index_iterator) callconv(.C) c_int; +pub const git_index_iterator_free = fn (iterator: *git_index_iterator) callconv(.C) void; +pub const git_index_add_bypath = fn (index: *git_index, path: [*c]const u8) callconv(.C) c_int; +pub const git_index_add_from_buffer = fn (index: ?*git_index, entry: [*c]const git_index_entry, buffer: *const c_void, len: usize) callconv(.C) c_int; +pub const git_index_remove_bypath = fn (index: ?*git_index, path: [*c]const u8) callconv(.C) c_int; +pub const git_index_add_all = fn (index: ?*git_index, pathspec: [*c]const git_strarray, flags: c_uint, callback: git_index_matched_path_cb, payload: ?*c_void) callconv(.C) c_int; +pub const git_index_remove_all = fn (index: ?*git_index, pathspec: [*c]const git_strarray, callback: git_index_matched_path_cb, payload: *c_void) callconv(.C) c_int; +pub const git_index_update_all = fn (index: ?*git_index, pathspec: [*c]const git_strarray, callback: git_index_matched_path_cb, payload: *c_void) callconv(.C) c_int; +pub const git_index_find = fn (at_pos: [*c]usize, index: *git_index, path: [*c]const u8) callconv(.C) c_int; +pub const git_index_find_prefix = fn (at_pos: [*c]usize, index: *git_index, prefix: [*c]const u8) callconv(.C) c_int; +pub const git_index_conflict_add = fn (index: *git_index, ancestor_entry: [*c]const git_index_entry, our_entry: [*c]const git_index_entry, their_entry: [*c]const git_index_entry) callconv(.C) c_int; +pub const git_index_conflict_get = fn (ancestor_out: [*c][*c]const git_index_entry, our_out: [*c][*c]const git_index_entry, their_out: [*c][*c]const git_index_entry, index: *git_index, path: [*c]const u8) callconv(.C) c_int; +pub const git_index_conflict_remove = fn (index: *git_index, path: [*c]const u8) callconv(.C) c_int; +pub const git_index_conflict_cleanup = fn (index: *git_index) callconv(.C) c_int; +pub const git_index_has_conflicts = fn (index: *const git_index) callconv(.C) c_int; +pub const git_index_conflict_iterator_new = fn (iterator_out: [*c]*git_index_conflict_iterator, index: *git_index) callconv(.C) c_int; +pub const git_index_conflict_next = fn (ancestor_out: [*c][*c]const git_index_entry, our_out: [*c][*c]const git_index_entry, their_out: [*c][*c]const git_index_entry, iterator: *git_index_conflict_iterator) callconv(.C) c_int; +pub const git_index_conflict_iterator_free = fn (iterator: *git_index_conflict_iterator) callconv(.C) void; +pub const git_merge_file_input_init = fn (opts: [*c]git_merge_file_input, version: c_uint) callconv(.C) c_int; +pub const git_merge_file_options_init = fn (opts: [*c]git_merge_file_options, version: c_uint) callconv(.C) c_int; +pub const git_merge_options_init = fn (opts: [*c]git_merge_options, version: c_uint) callconv(.C) c_int; +pub const git_merge_analysis = fn (analysis_out: [*c]git_merge_analysis_t, preference_out: [*c]git_merge_preference_t, repo: *git_repository, their_heads: [*c]*const git_annotated_commit, their_heads_len: usize) callconv(.C) c_int; +pub const git_merge_analysis_for_ref = fn (analysis_out: [*c]git_merge_analysis_t, preference_out: [*c]git_merge_preference_t, repo: *git_repository, our_ref: *git_reference, their_heads: [*c]*const git_annotated_commit, their_heads_len: usize) callconv(.C) c_int; +pub const git_merge_base = fn (out: [*c]git_oid, repo: *git_repository, one: [*c]const git_oid, two: [*c]const git_oid) callconv(.C) c_int; +pub const git_merge_bases = fn (out: [*c]git_oidarray, repo: *git_repository, one: [*c]const git_oid, two: [*c]const git_oid) callconv(.C) c_int; +pub const git_merge_base_many = fn (out: [*c]git_oid, repo: *git_repository, length: usize, input_array: [*c]const git_oid) callconv(.C) c_int; +pub const git_merge_bases_many = fn (out: [*c]git_oidarray, repo: *git_repository, length: usize, input_array: [*c]const git_oid) callconv(.C) c_int; +pub const git_merge_base_octopus = fn (out: [*c]git_oid, repo: *git_repository, length: usize, input_array: [*c]const git_oid) callconv(.C) c_int; +pub const git_merge_file = fn (out: [*c]git_merge_file_result, ancestor: [*c]const git_merge_file_input, ours: [*c]const git_merge_file_input, theirs: [*c]const git_merge_file_input, opts: [*c]const git_merge_file_options) callconv(.C) c_int; +pub const git_merge_file_from_index = fn (out: [*c]git_merge_file_result, repo: *git_repository, ancestor: [*c]const git_index_entry, ours: [*c]const git_index_entry, theirs: [*c]const git_index_entry, opts: [*c]const git_merge_file_options) callconv(.C) c_int; +pub const git_merge_file_result_free = fn (result: [*c]git_merge_file_result) callconv(.C) void; +pub const git_merge_trees = fn (out: [*c]*git_index, repo: *git_repository, ancestor_tree: *const git_tree, our_tree: *const git_tree, their_tree: *const git_tree, opts: [*c]const git_merge_options) callconv(.C) c_int; +pub const git_merge_commits = fn (out: [*c]*git_index, repo: *git_repository, our_commit: *const git_commit, their_commit: *const git_commit, opts: [*c]const git_merge_options) callconv(.C) c_int; +pub const git_merge = fn (repo: *git_repository, their_heads: [*c]*const git_annotated_commit, their_heads_len: usize, merge_opts: [*c]const git_merge_options, checkout_opts: [*c]const git_checkout_options) callconv(.C) c_int; +pub const git_cherrypick_options_init = fn (opts: [*c]git_cherrypick_options, version: c_uint) callconv(.C) c_int; +pub const git_cherrypick_commit = fn (out: [*c]*git_index, repo: *git_repository, cherrypick_commit: *git_commit, our_commit: *git_commit, mainline: c_uint, merge_options: [*c]const git_merge_options) callconv(.C) c_int; +pub const git_cherrypick = fn (repo: *git_repository, commit: *git_commit, cherrypick_options: [*c]const git_cherrypick_options) callconv(.C) c_int; +pub const git_refspec_parse = fn (refspec: [*c]*git_refspec, input: [*c]const u8, is_fetch: c_int) callconv(.C) c_int; +pub const git_refspec_free = fn (refspec: *git_refspec) callconv(.C) void; +pub const git_refspec_src = fn (refspec: *const git_refspec) callconv(.C) [*c]const u8; +pub const git_refspec_dst = fn (refspec: *const git_refspec) callconv(.C) [*c]const u8; +pub const git_refspec_string = fn (refspec: *const git_refspec) callconv(.C) [*c]const u8; +pub const git_refspec_force = fn (refspec: *const git_refspec) callconv(.C) c_int; +pub const git_refspec_direction = fn (spec: *const git_refspec) callconv(.C) git_direction; +pub const git_refspec_src_matches = fn (refspec: *const git_refspec, refname: [*c]const u8) callconv(.C) c_int; +pub const git_refspec_dst_matches = fn (refspec: *const git_refspec, refname: [*c]const u8) callconv(.C) c_int; +pub const git_refspec_transform = fn (out: [*c]git_buf, spec: *const git_refspec, name: [*c]const u8) callconv(.C) c_int; +pub const git_refspec_rtransform = fn (out: [*c]git_buf, spec: *const git_refspec, name: [*c]const u8) callconv(.C) c_int; +pub const git_credential_free = fn (cred: [*c]git_credential) callconv(.C) void; +pub const git_credential_has_username = fn (cred: [*c]git_credential) callconv(.C) c_int; +pub const git_credential_get_username = fn (cred: [*c]git_credential) callconv(.C) [*c]const u8; +pub const git_credential_userpass_plaintext_new = fn (out: [*c][*c]git_credential, username: [*c]const u8, password: [*c]const u8) callconv(.C) c_int; +pub const git_credential_default_new = fn (out: [*c][*c]git_credential) callconv(.C) c_int; +pub const git_credential_username_new = fn (out: [*c][*c]git_credential, username: [*c]const u8) callconv(.C) c_int; +pub const git_credential_ssh_key_new = fn (out: [*c][*c]git_credential, username: [*c]const u8, publickey: [*c]const u8, privatekey: [*c]const u8, passphrase: [*c]const u8) callconv(.C) c_int; +pub const git_credential_ssh_key_memory_new = fn (out: [*c][*c]git_credential, username: [*c]const u8, publickey: [*c]const u8, privatekey: [*c]const u8, passphrase: [*c]const u8) callconv(.C) c_int; +pub const git_credential_ssh_interactive_new = fn (out: [*c][*c]git_credential, username: [*c]const u8, prompt_callback: git_credential_ssh_interactive_cb, payload: *c_void) callconv(.C) c_int; +pub const git_credential_ssh_key_from_agent = fn (out: [*c][*c]git_credential, username: [*c]const u8) callconv(.C) c_int; +pub const git_credential_ssh_custom_new = fn (out: [*c][*c]git_credential, username: [*c]const u8, publickey: [*c]const u8, publickey_len: usize, sign_callback: git_credential_sign_cb, payload: *c_void) callconv(.C) c_int; +pub const git_packbuilder_new = fn (out: [*c]*git_packbuilder, repo: *git_repository) callconv(.C) c_int; +pub const git_packbuilder_set_threads = fn (pb: *git_packbuilder, n: c_uint) callconv(.C) c_uint; +pub const git_packbuilder_insert = fn (pb: *git_packbuilder, id: [*c]const git_oid, name: [*c]const u8) callconv(.C) c_int; +pub const git_packbuilder_insert_tree = fn (pb: *git_packbuilder, id: [*c]const git_oid) callconv(.C) c_int; +pub const git_packbuilder_insert_commit = fn (pb: *git_packbuilder, id: [*c]const git_oid) callconv(.C) c_int; +pub const git_packbuilder_insert_walk = fn (pb: *git_packbuilder, walk: *git_revwalk) callconv(.C) c_int; +pub const git_packbuilder_insert_recur = fn (pb: *git_packbuilder, id: [*c]const git_oid, name: [*c]const u8) callconv(.C) c_int; +pub const git_packbuilder_write_buf = fn (buf: [*c]git_buf, pb: *git_packbuilder) callconv(.C) c_int; +pub const git_packbuilder_write = fn (pb: *git_packbuilder, path: [*c]const u8, mode: c_uint, progress_cb: git_indexer_progress_cb, progress_cb_payload: *c_void) callconv(.C) c_int; +pub const git_packbuilder_hash = fn (pb: *git_packbuilder) callconv(.C) [*c]const git_oid; +pub const git_packbuilder_foreach = fn (pb: *git_packbuilder, cb: git_packbuilder_foreach_cb, payload: *c_void) callconv(.C) c_int; +pub const git_packbuilder_object_count = fn (pb: *git_packbuilder) callconv(.C) usize; +pub const git_packbuilder_written = fn (pb: *git_packbuilder) callconv(.C) usize; +pub const git_packbuilder_set_callbacks = fn (pb: *git_packbuilder, progress_cb: git_packbuilder_progress, progress_cb_payload: *c_void) callconv(.C) c_int; +pub const git_packbuilder_free = fn (pb: *git_packbuilder) callconv(.C) void; +pub const git_proxy_options_init = fn (opts: [*c]git_proxy_options, version: c_uint) callconv(.C) c_int; +pub const git_remote_create = fn (out: [*c]*git_remote, repo: *git_repository, name: [*c]const u8, url: [*c]const u8) callconv(.C) c_int; +pub const git_remote_create_options_init = fn (opts: [*c]git_remote_create_options, version: c_uint) callconv(.C) c_int; +pub const git_remote_create_with_opts = fn (out: [*c]*git_remote, url: [*c]const u8, opts: [*c]const git_remote_create_options) callconv(.C) c_int; +pub const git_remote_create_with_fetchspec = fn (out: [*c]*git_remote, repo: *git_repository, name: [*c]const u8, url: [*c]const u8, fetch: [*c]const u8) callconv(.C) c_int; +pub const git_remote_create_anonymous = fn (out: [*c]*git_remote, repo: *git_repository, url: [*c]const u8) callconv(.C) c_int; +pub const git_remote_create_detached = fn (out: [*c]*git_remote, url: [*c]const u8) callconv(.C) c_int; +pub const git_remote_lookup = fn (out: [*c]*git_remote, repo: *git_repository, name: [*c]const u8) callconv(.C) c_int; +pub const git_remote_dup = fn (dest: [*c]*git_remote, source: *git_remote) callconv(.C) c_int; +pub const git_remote_owner = fn (remote: *const git_remote) callconv(.C) *git_repository; +pub const git_remote_name = fn (remote: *const git_remote) callconv(.C) [*c]const u8; +pub const git_remote_url = fn (remote: *const git_remote) callconv(.C) [*c]const u8; +pub const git_remote_pushurl = fn (remote: *const git_remote) callconv(.C) [*c]const u8; +pub const git_remote_set_url = fn (repo: *git_repository, remote: [*c]const u8, url: [*c]const u8) callconv(.C) c_int; +pub const git_remote_set_pushurl = fn (repo: *git_repository, remote: [*c]const u8, url: [*c]const u8) callconv(.C) c_int; +pub const git_remote_set_instance_url = fn (remote: *git_remote, url: [*c]const u8) callconv(.C) c_int; +pub const git_remote_set_instance_pushurl = fn (remote: *git_remote, url: [*c]const u8) callconv(.C) c_int; +pub const git_remote_add_fetch = fn (repo: *git_repository, remote: [*c]const u8, refspec: [*c]const u8) callconv(.C) c_int; +pub const git_remote_get_fetch_refspecs = fn (array: [*c]git_strarray, remote: *const git_remote) callconv(.C) c_int; +pub const git_remote_add_push = fn (repo: *git_repository, remote: [*c]const u8, refspec: [*c]const u8) callconv(.C) c_int; +pub const git_remote_get_push_refspecs = fn (array: [*c]git_strarray, remote: *const git_remote) callconv(.C) c_int; +pub const git_remote_refspec_count = fn (remote: *const git_remote) callconv(.C) usize; +pub const git_remote_get_refspec = fn (remote: *const git_remote, n: usize) callconv(.C) *const git_refspec; +pub const git_remote_connect = fn (remote: *git_remote, direction: git_direction, callbacks: [*c]const git_remote_callbacks, proxy_opts: [*c]const git_proxy_options, custom_headers: [*c]const git_strarray) callconv(.C) c_int; +pub const git_remote_ls = fn (out: [*c][*c][*c]const git_remote_head, size: [*c]usize, remote: *git_remote) callconv(.C) c_int; +pub const git_remote_connected = fn (remote: *const git_remote) callconv(.C) c_int; +pub const git_remote_stop = fn (remote: *git_remote) callconv(.C) c_int; +pub const git_remote_disconnect = fn (remote: *git_remote) callconv(.C) c_int; +pub const git_remote_free = fn (remote: *git_remote) callconv(.C) void; +pub const git_remote_list = fn (out: [*c]git_strarray, repo: *git_repository) callconv(.C) c_int; +pub const git_remote_init_callbacks = fn (opts: [*c]git_remote_callbacks, version: c_uint) callconv(.C) c_int; +pub const git_fetch_options_init = fn (opts: [*c]git_fetch_options, version: c_uint) callconv(.C) c_int; +pub const git_push_options_init = fn (opts: [*c]git_push_options, version: c_uint) callconv(.C) c_int; +pub const git_remote_download = fn (remote: *git_remote, refspecs: [*c]const git_strarray, opts: [*c]const git_fetch_options) callconv(.C) c_int; +pub const git_remote_upload = fn (remote: *git_remote, refspecs: [*c]const git_strarray, opts: [*c]const git_push_options) callconv(.C) c_int; +pub const git_remote_update_tips = fn (remote: *git_remote, callbacks: [*c]const git_remote_callbacks, update_fetchhead: c_int, download_tags: git_remote_autotag_option_t, reflog_message: [*c]const u8) callconv(.C) c_int; +pub const git_remote_fetch = fn (remote: *git_remote, refspecs: [*c]const git_strarray, opts: [*c]const git_fetch_options, reflog_message: [*c]const u8) callconv(.C) c_int; +pub const git_remote_prune = fn (remote: *git_remote, callbacks: [*c]const git_remote_callbacks) callconv(.C) c_int; +pub const git_remote_push = fn (remote: *git_remote, refspecs: [*c]const git_strarray, opts: [*c]const git_push_options) callconv(.C) c_int; +pub const git_remote_stats = fn (remote: *git_remote) callconv(.C) [*c]const git_indexer_progress; +pub const git_remote_autotag = fn (remote: *const git_remote) callconv(.C) git_remote_autotag_option_t; +pub const git_remote_set_autotag = fn (repo: *git_repository, remote: [*c]const u8, value: git_remote_autotag_option_t) callconv(.C) c_int; +pub const git_remote_prune_refs = fn (remote: *const git_remote) callconv(.C) c_int; +pub const git_remote_rename = fn (problems: [*c]git_strarray, repo: *git_repository, name: [*c]const u8, new_name: [*c]const u8) callconv(.C) c_int; +pub const git_remote_name_is_valid = fn (valid: [*c]c_int, remote_name: [*c]const u8) callconv(.C) c_int; +pub const git_remote_delete = fn (repo: *git_repository, name: [*c]const u8) callconv(.C) c_int; +pub const git_remote_default_branch = fn (out: [*c]git_buf, remote: *git_remote) callconv(.C) c_int; +pub const git_clone_options_init = fn (opts: [*c]git_clone_options, version: c_uint) callconv(.C) c_int; +pub const git_clone = fn (out: *git_repository, url: [*c]const u8, local_path: [*c]const u8, options: [*c]const git_clone_options) callconv(.C) c_int; +pub const git_commit_lookup = fn (commit: [*c]*git_commit, repo: *git_repository, id: [*c]const git_oid) callconv(.C) c_int; +pub const git_commit_lookup_prefix = fn (commit: [*c]*git_commit, repo: *git_repository, id: [*c]const git_oid, len: usize) callconv(.C) c_int; +pub const git_commit_free = fn (commit: *git_commit) callconv(.C) void; +pub const git_commit_id = fn (commit: *const git_commit) callconv(.C) [*c]const git_oid; +pub const git_commit_owner = fn (commit: *const git_commit) callconv(.C) *git_repository; +pub const git_commit_message_encoding = fn (commit: *const git_commit) callconv(.C) [*c]const u8; +pub const git_commit_message = fn (commit: *const git_commit) callconv(.C) [*c]const u8; +pub const git_commit_message_raw = fn (commit: *const git_commit) callconv(.C) [*c]const u8; +pub const git_commit_summary = fn (commit: *git_commit) callconv(.C) [*c]const u8; +pub const git_commit_body = fn (commit: *git_commit) callconv(.C) [*c]const u8; +pub const git_commit_time = fn (commit: *const git_commit) callconv(.C) git_time_t; +pub const git_commit_time_offset = fn (commit: *const git_commit) callconv(.C) c_int; +pub const git_commit_committer = fn (commit: *const git_commit) callconv(.C) [*c]const git_signature; +pub const git_commit_author = fn (commit: *const git_commit) callconv(.C) [*c]const git_signature; +pub const git_commit_committer_with_mailmap = fn (out: [*c]?*git_signature, commit: *const git_commit, mailmap: *const git_mailmap) callconv(.C) c_int; +pub const git_commit_author_with_mailmap = fn (out: [*c]?*git_signature, commit: *const git_commit, mailmap: *const git_mailmap) callconv(.C) c_int; +pub const git_commit_raw_header = fn (commit: *const git_commit) callconv(.C) [*c]const u8; +pub const git_commit_tree = fn (tree_out: [*c]*git_tree, commit: *const git_commit) callconv(.C) c_int; +pub const git_commit_tree_id = fn (commit: *const git_commit) callconv(.C) [*c]const git_oid; +pub const git_commit_parentcount = fn (commit: *const git_commit) callconv(.C) c_uint; +pub const git_commit_parent = fn (out: [*c]*git_commit, commit: *const git_commit, n: c_uint) callconv(.C) c_int; +pub const git_commit_parent_id = fn (commit: *const git_commit, n: c_uint) callconv(.C) [*c]const git_oid; +pub const git_commit_nth_gen_ancestor = fn (ancestor: [*c]*git_commit, commit: *const git_commit, n: c_uint) callconv(.C) c_int; +pub const git_commit_header_field = fn (out: [*c]git_buf, commit: *const git_commit, field: [*c]const u8) callconv(.C) c_int; +pub const git_commit_extract_signature = fn (signature: [*c]git_buf, signed_data: [*c]git_buf, repo: *git_repository, commit_id: [*c]git_oid, field: [*c]const u8) callconv(.C) c_int; +pub const git_commit_create = fn (id: [*c]git_oid, repo: *git_repository, update_ref: [*c]const u8, author: [*c]const git_signature, committer: [*c]const git_signature, message_encoding: [*c]const u8, message: [*c]const u8, tree: *const git_tree, parent_count: usize, parents: [*c]*const git_commit) callconv(.C) c_int; +pub const git_commit_create_v = fn (id: [*c]git_oid, repo: *git_repository, update_ref: [*c]const u8, author: [*c]const git_signature, committer: [*c]const git_signature, message_encoding: [*c]const u8, message: [*c]const u8, tree: *const git_tree, parent_count: usize, ...) callconv(.C) c_int; +pub const git_commit_amend = fn (id: [*c]git_oid, commit_to_amend: *const git_commit, update_ref: [*c]const u8, author: [*c]const git_signature, committer: [*c]const git_signature, message_encoding: [*c]const u8, message: [*c]const u8, tree: *const git_tree) callconv(.C) c_int; +pub const git_commit_create_buffer = fn (out: [*c]git_buf, repo: *git_repository, author: [*c]const git_signature, committer: [*c]const git_signature, message_encoding: [*c]const u8, message: [*c]const u8, tree: *const git_tree, parent_count: usize, parents: [*c]*const git_commit) callconv(.C) c_int; +pub const git_commit_create_with_signature = fn (out: [*c]git_oid, repo: *git_repository, commit_content: [*c]const u8, signature: [*c]const u8, signature_field: [*c]const u8) callconv(.C) c_int; +pub const git_commit_dup = fn (out: [*c]*git_commit, source: *git_commit) callconv(.C) c_int; +pub const git_config_entry_free = fn ([*c]git_config_entry) callconv(.C) void; +pub const git_config_find_global = fn (out: [*c]git_buf) callconv(.C) c_int; +pub const git_config_find_xdg = fn (out: [*c]git_buf) callconv(.C) c_int; +pub const git_config_find_system = fn (out: [*c]git_buf) callconv(.C) c_int; +pub const git_config_find_programdata = fn (out: [*c]git_buf) callconv(.C) c_int; +pub const git_config_open_default = fn (out: [*c]*git_config) callconv(.C) c_int; +pub const git_config_new = fn (out: [*c]*git_config) callconv(.C) c_int; +pub const git_config_add_file_ondisk = fn (cfg: *git_config, path: [*c]const u8, level: git_config_level_t, repo: *const git_repository, force: c_int) callconv(.C) c_int; +pub const git_config_open_ondisk = fn (out: [*c]*git_config, path: [*c]const u8) callconv(.C) c_int; +pub const git_config_open_level = fn (out: [*c]*git_config, parent: *const git_config, level: git_config_level_t) callconv(.C) c_int; +pub const git_config_open_global = fn (out: [*c]*git_config, config: *git_config) callconv(.C) c_int; +pub const git_config_snapshot = fn (out: [*c]*git_config, config: *git_config) callconv(.C) c_int; +pub const git_config_free = fn (cfg: *git_config) callconv(.C) void; +pub const git_config_get_entry = fn (out: [*c][*c]git_config_entry, cfg: *const git_config, name: [*c]const u8) callconv(.C) c_int; +pub const git_config_get_int32 = fn (out: [*c]i32, cfg: *const git_config, name: [*c]const u8) callconv(.C) c_int; +pub const git_config_get_int64 = fn (out: [*c]i64, cfg: *const git_config, name: [*c]const u8) callconv(.C) c_int; +pub const git_config_get_bool = fn (out: [*c]c_int, cfg: *const git_config, name: [*c]const u8) callconv(.C) c_int; +pub const git_config_get_path = fn (out: [*c]git_buf, cfg: *const git_config, name: [*c]const u8) callconv(.C) c_int; +pub const git_config_get_string = fn (out: [*c][*c]const u8, cfg: *const git_config, name: [*c]const u8) callconv(.C) c_int; +pub const git_config_get_string_buf = fn (out: [*c]git_buf, cfg: *const git_config, name: [*c]const u8) callconv(.C) c_int; +pub const git_config_get_multivar_foreach = fn (cfg: *const git_config, name: [*c]const u8, regexp: [*c]const u8, callback: git_config_foreach_cb, payload: *c_void) callconv(.C) c_int; +pub const git_config_multivar_iterator_new = fn (out: [*c]*git_config_iterator, cfg: *const git_config, name: [*c]const u8, regexp: [*c]const u8) callconv(.C) c_int; +pub const git_config_next = fn (entry: [*c][*c]git_config_entry, iter: *git_config_iterator) callconv(.C) c_int; +pub const git_config_iterator_free = fn (iter: *git_config_iterator) callconv(.C) void; +pub const git_config_set_int32 = fn (cfg: *git_config, name: [*c]const u8, value: i32) callconv(.C) c_int; +pub const git_config_set_int64 = fn (cfg: *git_config, name: [*c]const u8, value: i64) callconv(.C) c_int; +pub const git_config_set_bool = fn (cfg: *git_config, name: [*c]const u8, value: c_int) callconv(.C) c_int; +pub const git_config_set_string = fn (cfg: *git_config, name: [*c]const u8, value: [*c]const u8) callconv(.C) c_int; +pub const git_config_set_multivar = fn (cfg: *git_config, name: [*c]const u8, regexp: [*c]const u8, value: [*c]const u8) callconv(.C) c_int; +pub const git_config_delete_entry = fn (cfg: *git_config, name: [*c]const u8) callconv(.C) c_int; +pub const git_config_delete_multivar = fn (cfg: *git_config, name: [*c]const u8, regexp: [*c]const u8) callconv(.C) c_int; +pub const git_config_foreach = fn (cfg: *const git_config, callback: git_config_foreach_cb, payload: *c_void) callconv(.C) c_int; +pub const git_config_iterator_new = fn (out: [*c]*git_config_iterator, cfg: *const git_config) callconv(.C) c_int; +pub const git_config_iterator_glob_new = fn (out: [*c]*git_config_iterator, cfg: *const git_config, regexp: [*c]const u8) callconv(.C) c_int; +pub const git_config_foreach_match = fn (cfg: *const git_config, regexp: [*c]const u8, callback: git_config_foreach_cb, payload: *c_void) callconv(.C) c_int; +pub const git_config_get_mapped = fn (out: [*c]c_int, cfg: *const git_config, name: [*c]const u8, maps: [*c]const git_configmap, map_n: usize) callconv(.C) c_int; +pub const git_config_lookup_map_value = fn (out: [*c]c_int, maps: [*c]const git_configmap, map_n: usize, value: [*c]const u8) callconv(.C) c_int; +pub const git_config_parse_bool = fn (out: [*c]c_int, value: [*c]const u8) callconv(.C) c_int; +pub const git_config_parse_int32 = fn (out: [*c]i32, value: [*c]const u8) callconv(.C) c_int; +pub const git_config_parse_int64 = fn (out: [*c]i64, value: [*c]const u8) callconv(.C) c_int; +pub const git_config_parse_path = fn (out: [*c]git_buf, value: [*c]const u8) callconv(.C) c_int; +pub const git_config_backend_foreach_match = fn (backend: *git_config_backend, regexp: [*c]const u8, callback: git_config_foreach_cb, payload: *c_void) callconv(.C) c_int; +pub const git_config_lock = fn (tx: [*c]*git_transaction, cfg: *git_config) callconv(.C) c_int; +pub const git_describe_options_init = fn (opts: [*c]git_describe_options, version: c_uint) callconv(.C) c_int; +pub const git_describe_format_options_init = fn (opts: [*c]git_describe_format_options, version: c_uint) callconv(.C) c_int; +pub const git_describe_commit = fn (result: [*c]*git_describe_result, committish: *git_object, opts: [*c]git_describe_options) callconv(.C) c_int; +pub const git_describe_workdir = fn (out: [*c]*git_describe_result, repo: *git_repository, opts: [*c]git_describe_options) callconv(.C) c_int; +pub const git_describe_format = fn (out: [*c]git_buf, result: *const git_describe_result, opts: [*c]const git_describe_format_options) callconv(.C) c_int; +pub const git_describe_result_free = fn (result: *git_describe_result) callconv(.C) void; +pub const git_error_last = fn () callconv(.C) [*c]const git_error; +pub const git_error_clear = fn () callconv(.C) void; +pub const git_error_set_str = fn (error_class: c_int, string: [*c]const u8) callconv(.C) c_int; +pub const git_error_set_oom = fn () callconv(.C) void; +pub const git_filter_list_load = fn (filters: [*c]*git_filter_list, repo: *git_repository, blob: *git_blob, path: [*c]const u8, mode: git_filter_mode_t, flags: u32) callconv(.C) c_int; +pub const git_filter_list_load_ext = fn (filters: [*c]*git_filter_list, repo: *git_repository, blob: *git_blob, path: [*c]const u8, mode: git_filter_mode_t, opts: [*c]git_filter_options) callconv(.C) c_int; +pub const git_filter_list_contains = fn (filters: *git_filter_list, name: [*c]const u8) callconv(.C) c_int; +pub const git_filter_list_apply_to_buffer = fn (out: [*c]git_buf, filters: *git_filter_list, in: [*c]const u8, in_len: usize) callconv(.C) c_int; +pub const git_filter_list_apply_to_file = fn (out: [*c]git_buf, filters: *git_filter_list, repo: *git_repository, path: [*c]const u8) callconv(.C) c_int; +pub const git_filter_list_apply_to_blob = fn (out: [*c]git_buf, filters: *git_filter_list, blob: *git_blob) callconv(.C) c_int; +pub const git_filter_list_stream_buffer = fn (filters: *git_filter_list, buffer: [*c]const u8, len: usize, target: [*c]git_writestream) callconv(.C) c_int; +pub const git_filter_list_stream_file = fn (filters: *git_filter_list, repo: *git_repository, path: [*c]const u8, target: [*c]git_writestream) callconv(.C) c_int; +pub const git_filter_list_stream_blob = fn (filters: *git_filter_list, blob: *git_blob, target: [*c]git_writestream) callconv(.C) c_int; +pub const git_filter_list_free = fn (filters: *git_filter_list) callconv(.C) void; +pub const git_rebase_options_init = fn (opts: [*c]git_rebase_options, version: c_uint) callconv(.C) c_int; +pub const git_rebase_init = fn (out: [*c]*git_rebase, repo: *git_repository, branch: *const git_annotated_commit, upstream: *const git_annotated_commit, onto: *const git_annotated_commit, opts: [*c]const git_rebase_options) callconv(.C) c_int; +pub const git_rebase_open = fn (out: [*c]*git_rebase, repo: *git_repository, opts: [*c]const git_rebase_options) callconv(.C) c_int; +pub const git_rebase_orig_head_name = fn (rebase: *git_rebase) callconv(.C) [*c]const u8; +pub const git_rebase_orig_head_id = fn (rebase: *git_rebase) callconv(.C) [*c]const git_oid; +pub const git_rebase_onto_name = fn (rebase: *git_rebase) callconv(.C) [*c]const u8; +pub const git_rebase_onto_id = fn (rebase: *git_rebase) callconv(.C) [*c]const git_oid; +pub const git_rebase_operation_entrycount = fn (rebase: *git_rebase) callconv(.C) usize; +pub const git_rebase_operation_current = fn (rebase: *git_rebase) callconv(.C) usize; +pub const git_rebase_operation_byindex = fn (rebase: *git_rebase, idx: usize) callconv(.C) [*c]git_rebase_operation; +pub const git_rebase_next = fn (operation: [*c][*c]git_rebase_operation, rebase: *git_rebase) callconv(.C) c_int; +pub const git_rebase_inmemory_index = fn (index: [*c]*git_index, rebase: *git_rebase) callconv(.C) c_int; +pub const git_rebase_commit = fn (id: [*c]git_oid, rebase: *git_rebase, author: [*c]const git_signature, committer: [*c]const git_signature, message_encoding: [*c]const u8, message: [*c]const u8) callconv(.C) c_int; +pub const git_rebase_abort = fn (rebase: *git_rebase) callconv(.C) c_int; +pub const git_rebase_finish = fn (rebase: *git_rebase, signature: [*c]const git_signature) callconv(.C) c_int; +pub const git_rebase_free = fn (rebase: *git_rebase) callconv(.C) void; +pub const git_trace_set = fn (level: git_trace_level_t, cb: git_trace_cb) callconv(.C) c_int; +pub const git_revert_options_init = fn (opts: [*c]git_revert_options, version: c_uint) callconv(.C) c_int; +pub const git_revert_commit = fn (out: [*c]*git_index, repo: *git_repository, revert_commit: *git_commit, our_commit: *git_commit, mainline: c_uint, merge_options: [*c]const git_merge_options) callconv(.C) c_int; +pub const git_revert = fn (repo: *git_repository, commit: *git_commit, given_opts: [*c]const git_revert_options) callconv(.C) c_int; +pub const git_revparse_single = fn (out: [*c]*git_object, repo: *git_repository, spec: [*c]const u8) callconv(.C) c_int; +pub const git_revparse_ext = fn (object_out: [*c]*git_object, reference_out: [*c]*git_reference, repo: *git_repository, spec: [*c]const u8) callconv(.C) c_int; +pub const git_revparse = fn (revspec: [*c]git_revspec, repo: *git_repository, spec: [*c]const u8) callconv(.C) c_int; +pub const git_stash_save = fn (out: [*c]git_oid, repo: *git_repository, stasher: [*c]const git_signature, message: [*c]const u8, flags: u32) callconv(.C) c_int; +pub const git_stash_apply_options_init = fn (opts: [*c]git_stash_apply_options, version: c_uint) callconv(.C) c_int; +pub const git_stash_apply = fn (repo: *git_repository, index: usize, options: [*c]const git_stash_apply_options) callconv(.C) c_int; +pub const git_stash_foreach = fn (repo: *git_repository, callback: git_stash_cb, payload: *c_void) callconv(.C) c_int; +pub const git_stash_drop = fn (repo: *git_repository, index: usize) callconv(.C) c_int; +pub const git_stash_pop = fn (repo: *git_repository, index: usize, options: [*c]const git_stash_apply_options) callconv(.C) c_int; +pub const git_status_options_init = fn (opts: [*c]git_status_options, version: c_uint) callconv(.C) c_int; +pub const git_status_foreach = fn (repo: *git_repository, callback: git_status_cb, payload: *c_void) callconv(.C) c_int; +pub const git_status_foreach_ext = fn (repo: *git_repository, opts: [*c]const git_status_options, callback: git_status_cb, payload: *c_void) callconv(.C) c_int; +pub const git_status_file = fn (status_flags: [*c]c_uint, repo: *git_repository, path: [*c]const u8) callconv(.C) c_int; +pub const git_status_list_new = fn (out: [*c]*git_status_list, repo: *git_repository, opts: [*c]const git_status_options) callconv(.C) c_int; +pub const git_status_list_entrycount = fn (statuslist: *git_status_list) callconv(.C) usize; +pub const git_status_byindex = fn (statuslist: *git_status_list, idx: usize) callconv(.C) [*c]const git_status_entry; +pub const git_status_list_free = fn (statuslist: *git_status_list) callconv(.C) void; +pub const git_status_should_ignore = fn (ignored: [*c]c_int, repo: *git_repository, path: [*c]const u8) callconv(.C) c_int; +pub const git_submodule_update_options_init = fn (opts: [*c]git_submodule_update_options, version: c_uint) callconv(.C) c_int; +pub const git_submodule_update = fn (submodule: *git_submodule, init: c_int, options: [*c]git_submodule_update_options) callconv(.C) c_int; +pub const git_submodule_lookup = fn (out: [*c]*git_submodule, repo: *git_repository, name: [*c]const u8) callconv(.C) c_int; +pub const git_submodule_dup = fn (out: [*c]*git_submodule, source: *git_submodule) callconv(.C) c_int; +pub const git_submodule_free = fn (submodule: *git_submodule) callconv(.C) void; +pub const git_submodule_foreach = fn (repo: *git_repository, callback: git_submodule_cb, payload: *c_void) callconv(.C) c_int; +pub const git_submodule_add_setup = fn (out: [*c]*git_submodule, repo: *git_repository, url: [*c]const u8, path: [*c]const u8, use_gitlink: c_int) callconv(.C) c_int; +pub const git_submodule_clone = fn (out: *git_repository, submodule: *git_submodule, opts: [*c]const git_submodule_update_options) callconv(.C) c_int; +pub const git_submodule_add_finalize = fn (submodule: *git_submodule) callconv(.C) c_int; +pub const git_submodule_add_to_index = fn (submodule: *git_submodule, write_index: c_int) callconv(.C) c_int; +pub const git_submodule_owner = fn (submodule: *git_submodule) callconv(.C) *git_repository; +pub const git_submodule_name = fn (submodule: *git_submodule) callconv(.C) [*c]const u8; +pub const git_submodule_path = fn (submodule: *git_submodule) callconv(.C) [*c]const u8; +pub const git_submodule_url = fn (submodule: *git_submodule) callconv(.C) [*c]const u8; +pub const git_submodule_resolve_url = fn (out: [*c]git_buf, repo: *git_repository, url: [*c]const u8) callconv(.C) c_int; +pub const git_submodule_branch = fn (submodule: *git_submodule) callconv(.C) [*c]const u8; +pub const git_submodule_set_branch = fn (repo: *git_repository, name: [*c]const u8, branch: [*c]const u8) callconv(.C) c_int; +pub const git_submodule_set_url = fn (repo: *git_repository, name: [*c]const u8, url: [*c]const u8) callconv(.C) c_int; +pub const git_submodule_index_id = fn (submodule: *git_submodule) callconv(.C) [*c]const git_oid; +pub const git_submodule_head_id = fn (submodule: *git_submodule) callconv(.C) [*c]const git_oid; +pub const git_submodule_wd_id = fn (submodule: *git_submodule) callconv(.C) [*c]const git_oid; +pub const git_submodule_ignore = fn (submodule: *git_submodule) callconv(.C) git_submodule_ignore_t; +pub const git_submodule_set_ignore = fn (repo: *git_repository, name: [*c]const u8, ignore: git_submodule_ignore_t) callconv(.C) c_int; +pub const git_submodule_update_strategy = fn (submodule: *git_submodule) callconv(.C) git_submodule_update_t; +pub const git_submodule_set_update = fn (repo: *git_repository, name: [*c]const u8, update: git_submodule_update_t) callconv(.C) c_int; +pub const git_submodule_fetch_recurse_submodules = fn (submodule: *git_submodule) callconv(.C) git_submodule_recurse_t; +pub const git_submodule_set_fetch_recurse_submodules = fn (repo: *git_repository, name: [*c]const u8, fetch_recurse_submodules: git_submodule_recurse_t) callconv(.C) c_int; +pub const git_submodule_init = fn (submodule: *git_submodule, overwrite: c_int) callconv(.C) c_int; +pub const git_submodule_repo_init = fn (out: *git_repository, sm: *const git_submodule, use_gitlink: c_int) callconv(.C) c_int; +pub const git_submodule_sync = fn (submodule: *git_submodule) callconv(.C) c_int; +pub const git_submodule_open = fn (repo: *git_repository, submodule: *git_submodule) callconv(.C) c_int; +pub const git_submodule_reload = fn (submodule: *git_submodule, force: c_int) callconv(.C) c_int; +pub const git_submodule_status = fn (status: [*c]c_uint, repo: *git_repository, name: [*c]const u8, ignore: git_submodule_ignore_t) callconv(.C) c_int; +pub const git_submodule_location = fn (location_status: [*c]c_uint, submodule: *git_submodule) callconv(.C) c_int; +pub const git_worktree_list = fn (out: [*c]git_strarray, repo: *git_repository) callconv(.C) c_int; +pub const git_worktree_lookup = fn (out: [*c]*git_worktree, repo: *git_repository, name: [*c]const u8) callconv(.C) c_int; +pub const git_worktree_open_from_repository = fn (out: [*c]*git_worktree, repo: *git_repository) callconv(.C) c_int; +pub const git_worktree_free = fn (wt: *git_worktree) callconv(.C) void; +pub const git_worktree_validate = fn (wt: *const git_worktree) callconv(.C) c_int; +pub const git_worktree_add_options_init = fn (opts: [*c]git_worktree_add_options, version: c_uint) callconv(.C) c_int; +pub const git_worktree_add = fn (out: [*c]*git_worktree, repo: *git_repository, name: [*c]const u8, path: [*c]const u8, opts: [*c]const git_worktree_add_options) callconv(.C) c_int; +pub const git_worktree_lock = fn (wt: *git_worktree, reason: [*c]const u8) callconv(.C) c_int; +pub const git_worktree_unlock = fn (wt: *git_worktree) callconv(.C) c_int; +pub const git_worktree_is_locked = fn (reason: [*c]git_buf, wt: *const git_worktree) callconv(.C) c_int; +pub const git_worktree_name = fn (wt: *const git_worktree) callconv(.C) [*c]const u8; +pub const git_worktree_path = fn (wt: *const git_worktree) callconv(.C) [*c]const u8; +pub const git_worktree_prune_options_init = fn (opts: [*c]git_worktree_prune_options, version: c_uint) callconv(.C) c_int; +pub const git_worktree_is_prunable = fn (wt: *git_worktree, opts: [*c]git_worktree_prune_options) callconv(.C) c_int; +pub const git_worktree_prune = fn (wt: *git_worktree, opts: [*c]git_worktree_prune_options) callconv(.C) c_int; +pub const git_credential_userpass = fn (out: [*c][*c]git_credential, url: [*c]const u8, user_from_url: [*c]const u8, allowed_types: c_uint, payload: *c_void) callconv(.C) c_int; +pub const git_blob_create_fromworkdir = fn (id: [*c]git_oid, repo: *git_repository, relative_path: [*c]const u8) callconv(.C) c_int; +pub const git_blob_create_fromdisk = fn (id: [*c]git_oid, repo: *git_repository, path: [*c]const u8) callconv(.C) c_int; +pub const git_blob_create_fromstream = fn (out: [*c][*c]git_writestream, repo: *git_repository, hintpath: [*c]const u8) callconv(.C) c_int; +pub const git_blob_create_fromstream_commit = fn (out: [*c]git_oid, stream: [*c]git_writestream) callconv(.C) c_int; +pub const git_blob_create_frombuffer = fn (id: [*c]git_oid, repo: *git_repository, buffer: *const c_void, len: usize) callconv(.C) c_int; +pub const git_blob_filtered_content = fn (out: [*c]git_buf, blob: *git_blob, as_path: [*c]const u8, check_for_binary_data: c_int) callconv(.C) c_int; +pub const git_filter_list_stream_data = fn (filters: *git_filter_list, data: [*c]git_buf, target: [*c]git_writestream) callconv(.C) c_int; +pub const git_filter_list_apply_to_data = fn (out: [*c]git_buf, filters: *git_filter_list, in: [*c]git_buf) callconv(.C) c_int; +pub const git_treebuilder_write_with_buffer = fn (oid: [*c]git_oid, bld: *git_treebuilder, tree: [*c]git_buf) callconv(.C) c_int; +pub const git_buf_free = fn (buffer: [*c]git_buf) callconv(.C) void; +pub const git_diff_format_email = fn (out: [*c]git_buf, diff: *git_diff, opts: [*c]const git_diff_format_email_options) callconv(.C) c_int; +pub const git_diff_commit_as_email = fn (out: [*c]git_buf, repo: *git_repository, commit: *git_commit, patch_no: usize, total_patches: usize, flags: u32, diff_opts: [*c]const git_diff_options) callconv(.C) c_int; +pub const git_diff_format_email_options_init = fn (opts: [*c]git_diff_format_email_options, version: c_uint) callconv(.C) c_int; +pub const giterr_last = fn () callconv(.C) [*c]const git_error; +pub const giterr_clear = fn () callconv(.C) void; +pub const giterr_set_str = fn (error_class: c_int, string: [*c]const u8) callconv(.C) void; +pub const giterr_set_oom = fn () callconv(.C) void; +pub const git_index_add_frombuffer = fn (index: *git_index, entry: [*c]const git_index_entry, buffer: *const c_void, len: usize) callconv(.C) c_int; +pub const git_object__size = fn (@"type": git_object_t) callconv(.C) usize; +pub const git_remote_is_valid_name = fn (remote_name: [*c]const u8) callconv(.C) c_int; +pub const git_reference_is_valid_name = fn (refname: [*c]const u8) callconv(.C) c_int; +pub const git_tag_create_frombuffer = fn (oid: [*c]git_oid, repo: *git_repository, buffer: [*c]const u8, force: c_int) callconv(.C) c_int; +pub const git_cred_free = fn (cred: [*c]git_credential) callconv(.C) void; +pub const git_cred_has_username = fn (cred: [*c]git_credential) callconv(.C) c_int; +pub const git_cred_get_username = fn (cred: [*c]git_credential) callconv(.C) [*c]const u8; +pub const git_cred_userpass_plaintext_new = fn (out: [*c][*c]git_credential, username: [*c]const u8, password: [*c]const u8) callconv(.C) c_int; +pub const git_cred_default_new = fn (out: [*c][*c]git_credential) callconv(.C) c_int; +pub const git_cred_username_new = fn (out: [*c][*c]git_credential, username: [*c]const u8) callconv(.C) c_int; +pub const git_cred_ssh_key_new = fn (out: [*c][*c]git_credential, username: [*c]const u8, publickey: [*c]const u8, privatekey: [*c]const u8, passphrase: [*c]const u8) callconv(.C) c_int; +pub const git_cred_ssh_key_memory_new = fn (out: [*c][*c]git_credential, username: [*c]const u8, publickey: [*c]const u8, privatekey: [*c]const u8, passphrase: [*c]const u8) callconv(.C) c_int; +pub const git_cred_ssh_interactive_new = fn (out: [*c][*c]git_credential, username: [*c]const u8, prompt_callback: git_credential_ssh_interactive_cb, payload: *c_void) callconv(.C) c_int; +pub const git_cred_ssh_key_from_agent = fn (out: [*c][*c]git_credential, username: [*c]const u8) callconv(.C) c_int; +pub const git_cred_ssh_custom_new = fn (out: [*c][*c]git_credential, username: [*c]const u8, publickey: [*c]const u8, publickey_len: usize, sign_callback: git_credential_sign_cb, payload: *c_void) callconv(.C) c_int; +pub const git_cred_userpass = fn (out: [*c][*c]git_credential, url: [*c]const u8, user_from_url: [*c]const u8, allowed_types: c_uint, payload: *c_void) callconv(.C) c_int; +pub const git_oid_iszero = fn (id: [*c]const git_oid) callconv(.C) c_int; +pub const git_oidarray_free = fn (array: [*c]git_oidarray) callconv(.C) void; +pub const git_strarray_free = fn (array: [*c]git_strarray) callconv(.C) void; +pub const git_blame_init_options = fn (opts: [*c]git_blame_options, version: c_uint) callconv(.C) c_int; +pub const git_checkout_init_options = fn (opts: [*c]git_checkout_options, version: c_uint) callconv(.C) c_int; +pub const git_cherrypick_init_options = fn (opts: [*c]git_cherrypick_options, version: c_uint) callconv(.C) c_int; +pub const git_clone_init_options = fn (opts: [*c]git_clone_options, version: c_uint) callconv(.C) c_int; +pub const git_describe_init_options = fn (opts: [*c]git_describe_options, version: c_uint) callconv(.C) c_int; +pub const git_describe_init_format_options = fn (opts: [*c]git_describe_format_options, version: c_uint) callconv(.C) c_int; +pub const git_diff_init_options = fn (opts: [*c]git_diff_options, version: c_uint) callconv(.C) c_int; +pub const git_diff_find_init_options = fn (opts: [*c]git_diff_find_options, version: c_uint) callconv(.C) c_int; +pub const git_diff_format_email_init_options = fn (opts: [*c]git_diff_format_email_options, version: c_uint) callconv(.C) c_int; +pub const git_diff_patchid_init_options = fn (opts: [*c]git_diff_patchid_options, version: c_uint) callconv(.C) c_int; +pub const git_fetch_init_options = fn (opts: [*c]git_fetch_options, version: c_uint) callconv(.C) c_int; +pub const git_indexer_init_options = fn (opts: [*c]git_indexer_options, version: c_uint) callconv(.C) c_int; +pub const git_merge_init_options = fn (opts: [*c]git_merge_options, version: c_uint) callconv(.C) c_int; +pub const git_merge_file_init_input = fn (input: [*c]git_merge_file_input, version: c_uint) callconv(.C) c_int; +pub const git_merge_file_init_options = fn (opts: [*c]git_merge_file_options, version: c_uint) callconv(.C) c_int; +pub const git_proxy_init_options = fn (opts: [*c]git_proxy_options, version: c_uint) callconv(.C) c_int; +pub const git_push_init_options = fn (opts: [*c]git_push_options, version: c_uint) callconv(.C) c_int; +pub const git_rebase_init_options = fn (opts: [*c]git_rebase_options, version: c_uint) callconv(.C) c_int; +pub const git_remote_create_init_options = fn (opts: [*c]git_remote_create_options, version: c_uint) callconv(.C) c_int; +pub const git_repository_init_init_options = fn (opts: ?*git_repository_init_options, version: c_uint) callconv(.C) c_int; +pub const git_revert_init_options = fn (opts: [*c]git_revert_options, version: c_uint) callconv(.C) c_int; +pub const git_stash_apply_init_options = fn (opts: [*c]git_stash_apply_options, version: c_uint) callconv(.C) c_int; +pub const git_status_init_options = fn (opts: [*c]git_status_options, version: c_uint) callconv(.C) c_int; +pub const git_submodule_update_init_options = fn (opts: [*c]git_submodule_update_options, version: c_uint) callconv(.C) c_int; +pub const git_worktree_add_init_options = fn (opts: [*c]git_worktree_add_options, version: c_uint) callconv(.C) c_int; +pub const git_worktree_prune_init_options = fn (opts: [*c]git_worktree_prune_options, version: c_uint) callconv(.C) c_int; +pub const git_email_create_from_diff = fn (out: [*c]git_buf, diff: *git_diff, patch_idx: usize, patch_count: usize, commit_id: [*c]const git_oid, summary: [*c]const u8, body: [*c]const u8, author: [*c]const git_signature, opts: [*c]const git_email_create_options) callconv(.C) c_int; +pub const git_email_create_from_commit = fn (out: [*c]git_buf, commit: *git_commit, opts: [*c]const git_email_create_options) callconv(.C) c_int; +pub const git_libgit2_init = fn () callconv(.C) c_int; +pub const git_libgit2_shutdown = fn () callconv(.C) c_int; +pub const git_graph_ahead_behind = fn (ahead: [*c]usize, behind: [*c]usize, repo: *git_repository, local: [*c]const git_oid, upstream: [*c]const git_oid) callconv(.C) c_int; +pub const git_graph_descendant_of = fn (repo: *git_repository, commit: [*c]const git_oid, ancestor: [*c]const git_oid) callconv(.C) c_int; +pub const git_graph_reachable_from_any = fn (repo: *git_repository, commit: [*c]const git_oid, descendant_array: [*c]const git_oid, length: usize) callconv(.C) c_int; +pub const git_ignore_add_rule = fn (repo: *git_repository, rules: [*c]const u8) callconv(.C) c_int; +pub const git_ignore_clear_internal_rules = fn (repo: *git_repository) callconv(.C) c_int; +pub const git_ignore_path_is_ignored = fn (ignored: [*c]c_int, repo: *git_repository, path: [*c]const u8) callconv(.C) c_int; +pub const git_mailmap_new = fn (out: [*c]*git_mailmap) callconv(.C) c_int; +pub const git_mailmap_free = fn (mm: *git_mailmap) callconv(.C) void; +pub const git_mailmap_add_entry = fn (mm: *git_mailmap, real_name: [*c]const u8, real_email: [*c]const u8, replace_name: [*c]const u8, replace_email: [*c]const u8) callconv(.C) c_int; +pub const git_mailmap_from_buffer = fn (out: [*c]*git_mailmap, buf: [*c]const u8, len: usize) callconv(.C) c_int; +pub const git_mailmap_from_repository = fn (out: [*c]*git_mailmap, repo: *git_repository) callconv(.C) c_int; +pub const git_mailmap_resolve = fn (real_name: [*c][*c]const u8, real_email: [*c][*c]const u8, mm: *const git_mailmap, name: [*c]const u8, email: [*c]const u8) callconv(.C) c_int; +pub const git_mailmap_resolve_signature = fn (out: [*c]?*git_signature, mm: *const git_mailmap, sig: [*c]const git_signature) callconv(.C) c_int; +pub const git_message_prettify = fn (out: [*c]git_buf, message: [*c]const u8, strip_comments: c_int, comment_char: u8) callconv(.C) c_int; +pub const git_message_trailers = fn (arr: [*c]git_message_trailer_array, message: [*c]const u8) callconv(.C) c_int; +pub const git_message_trailer_array_free = fn (arr: [*c]git_message_trailer_array) callconv(.C) void; +pub const git_note_iterator_new = fn (out: [*c]*git_note_iterator, repo: *git_repository, notes_ref: [*c]const u8) callconv(.C) c_int; +pub const git_note_commit_iterator_new = fn (out: [*c]*git_note_iterator, notes_commit: *git_commit) callconv(.C) c_int; +pub const git_note_iterator_free = fn (it: *git_note_iterator) callconv(.C) void; +pub const git_note_next = fn (note_id: [*c]git_oid, annotated_id: [*c]git_oid, it: *git_note_iterator) callconv(.C) c_int; +pub const git_note_read = fn (out: [*c]*git_note, repo: *git_repository, notes_ref: [*c]const u8, oid: [*c]const git_oid) callconv(.C) c_int; +pub const git_note_commit_read = fn (out: [*c]*git_note, repo: *git_repository, notes_commit: *git_commit, oid: [*c]const git_oid) callconv(.C) c_int; +pub const git_note_author = fn (note: *const git_note) callconv(.C) [*c]const git_signature; +pub const git_note_committer = fn (note: *const git_note) callconv(.C) [*c]const git_signature; +pub const git_note_message = fn (note: *const git_note) callconv(.C) [*c]const u8; +pub const git_note_id = fn (note: *const git_note) callconv(.C) [*c]const git_oid; +pub const git_note_create = fn (out: [*c]git_oid, repo: *git_repository, notes_ref: [*c]const u8, author: [*c]const git_signature, committer: [*c]const git_signature, oid: [*c]const git_oid, note: [*c]const u8, force: c_int) callconv(.C) c_int; +pub const git_note_commit_create = fn (notes_commit_out: [*c]git_oid, notes_blob_out: [*c]git_oid, repo: *git_repository, parent: *git_commit, author: [*c]const git_signature, committer: [*c]const git_signature, oid: [*c]const git_oid, note: [*c]const u8, allow_note_overwrite: c_int) callconv(.C) c_int; +pub const git_note_remove = fn (repo: *git_repository, notes_ref: [*c]const u8, author: [*c]const git_signature, committer: [*c]const git_signature, oid: [*c]const git_oid) callconv(.C) c_int; +pub const git_note_commit_remove = fn (notes_commit_out: [*c]git_oid, repo: *git_repository, notes_commit: *git_commit, author: [*c]const git_signature, committer: [*c]const git_signature, oid: [*c]const git_oid) callconv(.C) c_int; +pub const git_note_free = fn (note: *git_note) callconv(.C) void; +pub const git_note_default_ref = fn (out: [*c]git_buf, repo: *git_repository) callconv(.C) c_int; +pub const git_note_foreach = fn (repo: *git_repository, notes_ref: [*c]const u8, note_cb: git_note_foreach_cb, payload: *c_void) callconv(.C) c_int; +pub const git_odb_new = fn (out: [*c]*git_odb) callconv(.C) c_int; +pub const git_odb_open = fn (out: [*c]*git_odb, objects_dir: [*c]const u8) callconv(.C) c_int; +pub const git_odb_add_disk_alternate = fn (odb: *git_odb, path: [*c]const u8) callconv(.C) c_int; +pub const git_odb_free = fn (db: *git_odb) callconv(.C) void; +pub const git_odb_read = fn (out: [*c]*git_odb_object, db: *git_odb, id: [*c]const git_oid) callconv(.C) c_int; +pub const git_odb_read_prefix = fn (out: [*c]*git_odb_object, db: *git_odb, short_id: [*c]const git_oid, len: usize) callconv(.C) c_int; +pub const git_odb_read_header = fn (len_out: [*c]usize, type_out: [*c]git_object_t, db: *git_odb, id: [*c]const git_oid) callconv(.C) c_int; +pub const git_odb_exists = fn (db: *git_odb, id: [*c]const git_oid) callconv(.C) c_int; +pub const git_odb_exists_prefix = fn (out: [*c]git_oid, db: *git_odb, short_id: [*c]const git_oid, len: usize) callconv(.C) c_int; +pub const git_odb_expand_ids = fn (db: *git_odb, ids: [*c]git_odb_expand_id, count: usize) callconv(.C) c_int; +pub const git_odb_refresh = fn (db: *struct_git_odb) callconv(.C) c_int; +pub const git_odb_foreach = fn (db: *git_odb, cb: git_odb_foreach_cb, payload: *c_void) callconv(.C) c_int; +pub const git_odb_write = fn (out: [*c]git_oid, odb: *git_odb, data: *const c_void, len: usize, @"type": git_object_t) callconv(.C) c_int; +pub const git_odb_open_wstream = fn (out: [*c][*c]git_odb_stream, db: *git_odb, size: git_object_size_t, @"type": git_object_t) callconv(.C) c_int; +pub const git_odb_stream_write = fn (stream: [*c]git_odb_stream, buffer: [*c]const u8, len: usize) callconv(.C) c_int; +pub const git_odb_stream_finalize_write = fn (out: [*c]git_oid, stream: [*c]git_odb_stream) callconv(.C) c_int; +pub const git_odb_stream_read = fn (stream: [*c]git_odb_stream, buffer: [*c]u8, len: usize) callconv(.C) c_int; +pub const git_odb_stream_free = fn (stream: [*c]git_odb_stream) callconv(.C) void; +pub const git_odb_open_rstream = fn (out: [*c][*c]git_odb_stream, len: [*c]usize, @"type": [*c]git_object_t, db: *git_odb, oid: [*c]const git_oid) callconv(.C) c_int; +pub const git_odb_write_pack = fn (out: [*c][*c]git_odb_writepack, db: *git_odb, progress_cb: git_indexer_progress_cb, progress_payload: *c_void) callconv(.C) c_int; +pub const git_odb_write_multi_pack_index = fn (db: *git_odb) callconv(.C) c_int; +pub const git_odb_hash = fn (out: [*c]git_oid, data: *const c_void, len: usize, @"type": git_object_t) callconv(.C) c_int; +pub const git_odb_hashfile = fn (out: [*c]git_oid, path: [*c]const u8, @"type": git_object_t) callconv(.C) c_int; +pub const git_odb_object_dup = fn (dest: [*c]*git_odb_object, source: *git_odb_object) callconv(.C) c_int; +pub const git_odb_object_free = fn (object: *git_odb_object) callconv(.C) void; +pub const git_odb_object_id = fn (object: *git_odb_object) callconv(.C) [*c]const git_oid; +pub const git_odb_object_data = fn (object: *git_odb_object) callconv(.C) *const c_void; +pub const git_odb_object_size = fn (object: *git_odb_object) callconv(.C) usize; +pub const git_odb_object_type = fn (object: *git_odb_object) callconv(.C) git_object_t; +pub const git_odb_add_backend = fn (odb: *git_odb, backend: *git_odb_backend, priority: c_int) callconv(.C) c_int; +pub const git_odb_add_alternate = fn (odb: *git_odb, backend: *git_odb_backend, priority: c_int) callconv(.C) c_int; +pub const git_odb_num_backends = fn (odb: *git_odb) callconv(.C) usize; +pub const git_odb_get_backend = fn (out: [*c]*git_odb_backend, odb: *git_odb, pos: usize) callconv(.C) c_int; +pub const git_odb_set_commit_graph = fn (odb: *git_odb, cgraph: *git_commit_graph) callconv(.C) c_int; +pub const git_odb_backend_pack = fn (out: [*c]*git_odb_backend, objects_dir: [*c]const u8) callconv(.C) c_int; +pub const git_odb_backend_loose = fn (out: [*c]*git_odb_backend, objects_dir: [*c]const u8, compression_level: c_int, do_fsync: c_int, dir_mode: c_uint, file_mode: c_uint) callconv(.C) c_int; +pub const git_odb_backend_one_pack = fn (out: [*c]*git_odb_backend, index_file: [*c]const u8) callconv(.C) c_int; +pub const git_patch_owner = fn (patch: *const git_patch) callconv(.C) *git_repository; +pub const git_patch_from_diff = fn (out: [*c]*git_patch, diff: *git_diff, idx: usize) callconv(.C) c_int; +pub const git_patch_from_blobs = fn (out: [*c]*git_patch, old_blob: *const git_blob, old_as_path: [*c]const u8, new_blob: *const git_blob, new_as_path: [*c]const u8, opts: [*c]const git_diff_options) callconv(.C) c_int; +pub const git_patch_from_blob_and_buffer = fn (out: [*c]*git_patch, old_blob: *const git_blob, old_as_path: [*c]const u8, buffer: *const c_void, buffer_len: usize, buffer_as_path: [*c]const u8, opts: [*c]const git_diff_options) callconv(.C) c_int; +pub const git_patch_from_buffers = fn (out: [*c]*git_patch, old_buffer: *const c_void, old_len: usize, old_as_path: [*c]const u8, new_buffer: *const c_void, new_len: usize, new_as_path: [*c]const u8, opts: [*c]const git_diff_options) callconv(.C) c_int; +pub const git_patch_free = fn (patch: *git_patch) callconv(.C) void; +pub const git_patch_get_delta = fn (patch: *const git_patch) callconv(.C) [*c]const git_diff_delta; +pub const git_patch_num_hunks = fn (patch: *const git_patch) callconv(.C) usize; +pub const git_patch_line_stats = fn (total_context: [*c]usize, total_additions: [*c]usize, total_deletions: [*c]usize, patch: *const git_patch) callconv(.C) c_int; +pub const git_patch_get_hunk = fn (out: [*c][*c]const git_diff_hunk, lines_in_hunk: [*c]usize, patch: *git_patch, hunk_idx: usize) callconv(.C) c_int; +pub const git_patch_num_lines_in_hunk = fn (patch: *const git_patch, hunk_idx: usize) callconv(.C) c_int; +pub const git_patch_get_line_in_hunk = fn (out: [*c][*c]const git_diff_line, patch: *git_patch, hunk_idx: usize, line_of_hunk: usize) callconv(.C) c_int; +pub const git_patch_size = fn (patch: *git_patch, include_context: c_int, include_hunk_headers: c_int, include_file_headers: c_int) callconv(.C) usize; +pub const git_patch_print = fn (patch: *git_patch, print_cb: git_diff_line_cb, payload: *c_void) callconv(.C) c_int; +pub const git_patch_to_buf = fn (out: [*c]git_buf, patch: *git_patch) callconv(.C) c_int; +pub const git_pathspec_new = fn (out: [*c]*git_pathspec, pathspec: [*c]const git_strarray) callconv(.C) c_int; +pub const git_pathspec_free = fn (ps: *git_pathspec) callconv(.C) void; +pub const git_pathspec_matches_path = fn (ps: *const git_pathspec, flags: u32, path: [*c]const u8) callconv(.C) c_int; +pub const git_pathspec_match_workdir = fn (out: [*c]*git_pathspec_match_list, repo: *git_repository, flags: u32, ps: *git_pathspec) callconv(.C) c_int; +pub const git_pathspec_match_index = fn (out: [*c]*git_pathspec_match_list, index: *git_index, flags: u32, ps: *git_pathspec) callconv(.C) c_int; +pub const git_pathspec_match_tree = fn (out: [*c]*git_pathspec_match_list, tree: *git_tree, flags: u32, ps: *git_pathspec) callconv(.C) c_int; +pub const git_pathspec_match_diff = fn (out: [*c]*git_pathspec_match_list, diff: *git_diff, flags: u32, ps: *git_pathspec) callconv(.C) c_int; +pub const git_pathspec_match_list_free = fn (m: *git_pathspec_match_list) callconv(.C) void; +pub const git_pathspec_match_list_entrycount = fn (m: *const git_pathspec_match_list) callconv(.C) usize; +pub const git_pathspec_match_list_entry = fn (m: *const git_pathspec_match_list, pos: usize) callconv(.C) [*c]const u8; +pub const git_pathspec_match_list_diff_entry = fn (m: *const git_pathspec_match_list, pos: usize) callconv(.C) [*c]const git_diff_delta; +pub const git_pathspec_match_list_failed_entrycount = fn (m: *const git_pathspec_match_list) callconv(.C) usize; +pub const git_pathspec_match_list_failed_entry = fn (m: *const git_pathspec_match_list, pos: usize) callconv(.C) [*c]const u8; +pub const git_refdb_new = fn (out: [*c]*git_refdb, repo: *git_repository) callconv(.C) c_int; +pub const git_refdb_open = fn (out: [*c]*git_refdb, repo: *git_repository) callconv(.C) c_int; +pub const git_refdb_compress = fn (refdb: *git_refdb) callconv(.C) c_int; +pub const git_refdb_free = fn (refdb: *git_refdb) callconv(.C) void; +pub const git_reflog_read = fn (out: [*c]*git_reflog, repo: *git_repository, name: [*c]const u8) callconv(.C) c_int; +pub const git_reflog_write = fn (reflog: *git_reflog) callconv(.C) c_int; +pub const git_reflog_append = fn (reflog: *git_reflog, id: [*c]const git_oid, committer: [*c]const git_signature, msg: [*c]const u8) callconv(.C) c_int; +pub const git_reflog_rename = fn (repo: *git_repository, old_name: [*c]const u8, name: [*c]const u8) callconv(.C) c_int; +pub const git_reflog_delete = fn (repo: *git_repository, name: [*c]const u8) callconv(.C) c_int; +pub const git_reflog_entrycount = fn (reflog: *git_reflog) callconv(.C) usize; +pub const git_reflog_entry_byindex = fn (reflog: *const git_reflog, idx: usize) callconv(.C) *const git_reflog_entry; +pub const git_reflog_drop = fn (reflog: *git_reflog, idx: usize, rewrite_previous_entry: c_int) callconv(.C) c_int; +pub const git_reflog_entry_id_old = fn (entry: *const git_reflog_entry) callconv(.C) [*c]const git_oid; +pub const git_reflog_entry_id_new = fn (entry: *const git_reflog_entry) callconv(.C) [*c]const git_oid; +pub const git_reflog_entry_committer = fn (entry: *const git_reflog_entry) callconv(.C) [*c]const git_signature; +pub const git_reflog_entry_message = fn (entry: *const git_reflog_entry) callconv(.C) [*c]const u8; +pub const git_reflog_free = fn (reflog: *git_reflog) callconv(.C) void; +pub const git_reset = fn (repo: *git_repository, target: *const git_object, reset_type: git_reset_t, checkout_opts: [*c]const git_checkout_options) callconv(.C) c_int; +pub const git_reset_from_annotated = fn (repo: *git_repository, commit: *const git_annotated_commit, reset_type: git_reset_t, checkout_opts: [*c]const git_checkout_options) callconv(.C) c_int; +pub const git_reset_default = fn (repo: *git_repository, target: *const git_object, pathspecs: [*c]const git_strarray) callconv(.C) c_int; +pub const git_revwalk_new = fn (out: [*c]*git_revwalk, repo: *git_repository) callconv(.C) c_int; +pub const git_revwalk_reset = fn (walker: *git_revwalk) callconv(.C) c_int; +pub const git_revwalk_push = fn (walk: *git_revwalk, id: [*c]const git_oid) callconv(.C) c_int; +pub const git_revwalk_push_glob = fn (walk: *git_revwalk, glob: [*c]const u8) callconv(.C) c_int; +pub const git_revwalk_push_head = fn (walk: *git_revwalk) callconv(.C) c_int; +pub const git_revwalk_hide = fn (walk: *git_revwalk, commit_id: [*c]const git_oid) callconv(.C) c_int; +pub const git_revwalk_hide_glob = fn (walk: *git_revwalk, glob: [*c]const u8) callconv(.C) c_int; +pub const git_revwalk_hide_head = fn (walk: *git_revwalk) callconv(.C) c_int; +pub const git_revwalk_push_ref = fn (walk: *git_revwalk, refname: [*c]const u8) callconv(.C) c_int; +pub const git_revwalk_hide_ref = fn (walk: *git_revwalk, refname: [*c]const u8) callconv(.C) c_int; +pub const git_revwalk_next = fn (out: [*c]git_oid, walk: *git_revwalk) callconv(.C) c_int; +pub const git_revwalk_sorting = fn (walk: *git_revwalk, sort_mode: c_uint) callconv(.C) c_int; +pub const git_revwalk_push_range = fn (walk: *git_revwalk, range: [*c]const u8) callconv(.C) c_int; +pub const git_revwalk_simplify_first_parent = fn (walk: *git_revwalk) callconv(.C) c_int; +pub const git_revwalk_free = fn (walk: *git_revwalk) callconv(.C) void; +pub const git_revwalk_repository = fn (walk: *git_revwalk) callconv(.C) *git_repository; +pub const git_revwalk_add_hide_cb = fn (walk: *git_revwalk, hide_cb: git_revwalk_hide_cb, payload: *c_void) callconv(.C) c_int; +pub const git_signature_new = fn (out: [*c]?*git_signature, name: [*c]const u8, email: [*c]const u8, time: git_time_t, offset: c_int) callconv(.C) c_int; +pub const git_signature_now = fn (out: [*c]?*git_signature, name: [*c]const u8, email: [*c]const u8) callconv(.C) c_int; +pub const git_signature_default = fn (out: *?*git_signature, repo: *git_repository) callconv(.C) c_int; +pub const git_signature_from_buffer = fn (out: [*c]?*git_signature, buf: [*c]const u8) callconv(.C) c_int; +pub const git_signature_dup = fn (dest: [*c]?*git_signature, sig: [*c]const git_signature) callconv(.C) c_int; +pub const git_signature_free = fn (sig: [*c]git_signature) callconv(.C) void; +pub const git_tag_lookup = fn (out: [*c]*git_tag, repo: *git_repository, id: [*c]const git_oid) callconv(.C) c_int; +pub const git_tag_lookup_prefix = fn (out: [*c]*git_tag, repo: *git_repository, id: [*c]const git_oid, len: usize) callconv(.C) c_int; +pub const git_tag_free = fn (tag: *git_tag) callconv(.C) void; +pub const git_tag_id = fn (tag: *const git_tag) callconv(.C) [*c]const git_oid; +pub const git_tag_owner = fn (tag: *const git_tag) callconv(.C) *git_repository; +pub const git_tag_target = fn (target_out: [*c]*git_object, tag: *const git_tag) callconv(.C) c_int; +pub const git_tag_target_id = fn (tag: *const git_tag) callconv(.C) [*c]const git_oid; +pub const git_tag_target_type = fn (tag: *const git_tag) callconv(.C) git_object_t; +pub const git_tag_name = fn (tag: *const git_tag) callconv(.C) [*c]const u8; +pub const git_tag_tagger = fn (tag: *const git_tag) callconv(.C) [*c]const git_signature; +pub const git_tag_message = fn (tag: *const git_tag) callconv(.C) [*c]const u8; +pub const git_tag_create = fn (oid: [*c]git_oid, repo: *git_repository, tag_name: [*c]const u8, target: *const git_object, tagger: [*c]const git_signature, message: [*c]const u8, force: c_int) callconv(.C) c_int; +pub const git_tag_annotation_create = fn (oid: [*c]git_oid, repo: *git_repository, tag_name: [*c]const u8, target: *const git_object, tagger: [*c]const git_signature, message: [*c]const u8) callconv(.C) c_int; +pub const git_tag_create_from_buffer = fn (oid: [*c]git_oid, repo: *git_repository, buffer: [*c]const u8, force: c_int) callconv(.C) c_int; +pub const git_tag_create_lightweight = fn (oid: [*c]git_oid, repo: *git_repository, tag_name: [*c]const u8, target: *const git_object, force: c_int) callconv(.C) c_int; +pub const git_tag_delete = fn (repo: *git_repository, tag_name: [*c]const u8) callconv(.C) c_int; +pub const git_tag_list = fn (tag_names: [*c]git_strarray, repo: *git_repository) callconv(.C) c_int; +pub const git_tag_list_match = fn (tag_names: [*c]git_strarray, pattern: [*c]const u8, repo: *git_repository) callconv(.C) c_int; +pub const git_tag_foreach = fn (repo: *git_repository, callback: git_tag_foreach_cb, payload: *c_void) callconv(.C) c_int; +pub const git_tag_peel = fn (tag_target_out: [*c]*git_object, tag: *const git_tag) callconv(.C) c_int; +pub const git_tag_dup = fn (out: [*c]*git_tag, source: *git_tag) callconv(.C) c_int; +pub const git_tag_name_is_valid = fn (valid: [*c]c_int, name: [*c]const u8) callconv(.C) c_int; +pub const git_transaction_new = fn (out: [*c]*git_transaction, repo: *git_repository) callconv(.C) c_int; +pub const git_transaction_lock_ref = fn (tx: *git_transaction, refname: [*c]const u8) callconv(.C) c_int; +pub const git_transaction_set_target = fn (tx: *git_transaction, refname: [*c]const u8, target: [*c]const git_oid, sig: [*c]const git_signature, msg: [*c]const u8) callconv(.C) c_int; +pub const git_transaction_set_symbolic_target = fn (tx: *git_transaction, refname: [*c]const u8, target: [*c]const u8, sig: [*c]const git_signature, msg: [*c]const u8) callconv(.C) c_int; +pub const git_transaction_set_reflog = fn (tx: *git_transaction, refname: [*c]const u8, reflog: *const git_reflog) callconv(.C) c_int; +pub const git_transaction_remove = fn (tx: *git_transaction, refname: [*c]const u8) callconv(.C) c_int; +pub const git_transaction_commit = fn (tx: *git_transaction) callconv(.C) c_int; +pub const git_transaction_free = fn (tx: *git_transaction) callconv(.C) void; diff --git a/src/deps/picohttp.zig b/src/deps/picohttp.zig index cdd26b710..43f216cf4 100644 --- a/src/deps/picohttp.zig +++ b/src/deps/picohttp.zig @@ -1,7 +1,8 @@ const std = @import("std"); -const c = @cImport(@cInclude("picohttpparser.h")); +const c = @import("picohttpparser.zig"); const ExactSizeMatcher = @import("../exact_size_matcher.zig").ExactSizeMatcher; const Match = ExactSizeMatcher(2); +const Output = @import("../global.zig").Output; const fmt = std.fmt; @@ -16,10 +17,18 @@ pub const Header = struct { } pub fn format(self: Header, comptime layout: []const u8, opts: fmt.FormatOptions, writer: anytype) !void { - if (self.isMultiline()) { - try fmt.format(writer, "{s}", .{self.value}); + if (Output.enable_ansi_colors) { + if (self.isMultiline()) { + try fmt.format(writer, comptime Output.prettyFmt("<r><cyan>{s}", true), .{self.value}); + } else { + try fmt.format(writer, comptime Output.prettyFmt("<r><cyan>{s}<r><d>: <r>{s}", true), .{ self.name, self.value }); + } } else { - try fmt.format(writer, "{s}: {s}", .{ self.name, self.value }); + if (self.isMultiline()) { + try fmt.format(writer, comptime Output.prettyFmt("<r><cyan>{s}", false), .{self.value}); + } else { + try fmt.format(writer, comptime Output.prettyFmt("<r><cyan>{s}<r><d>: <r>{s}", false), .{ self.name, self.value }); + } } } @@ -143,7 +152,7 @@ pub const Response = struct { ); return switch (rc) { - -1 => error.BadResponse, + -1 => error.Malformed_HTTP_Response, -2 => brk: { offset.?.* += buf.len; @@ -154,7 +163,7 @@ pub const Response = struct { .status_code = @intCast(usize, status_code), .status = status, .headers = src[0..num_headers], - .bytes_read = bytes_read, + .bytes_read = rc, }, }; } @@ -229,3 +238,5 @@ test "pico_http: parse headers" { std.debug.print("{}\n", .{header}); } } + +pub usingnamespace c; diff --git a/src/deps/picohttpparser.zig b/src/deps/picohttpparser.zig new file mode 100644 index 000000000..ea9ad9f3a --- /dev/null +++ b/src/deps/picohttpparser.zig @@ -0,0 +1,21 @@ +pub usingnamespace @import("std").zig.c_builtins; + +pub const struct_phr_header = extern struct { + name: [*c]const u8, + name_len: usize, + value: [*c]const u8, + value_len: usize, +}; +pub extern fn phr_parse_request(buf: [*c]const u8, len: usize, method: [*c][*c]const u8, method_len: [*c]usize, path: [*c][*c]const u8, path_len: [*c]usize, minor_version: [*c]c_int, headers: [*c]struct_phr_header, num_headers: [*c]usize, last_len: usize) c_int; +pub extern fn phr_parse_response(_buf: [*c]const u8, len: usize, minor_version: [*c]c_int, status: [*c]c_int, msg: [*c][*c]const u8, msg_len: [*c]usize, headers: [*c]struct_phr_header, num_headers: [*c]usize, last_len: usize) c_int; +pub extern fn phr_parse_headers(buf: [*c]const u8, len: usize, headers: [*c]struct_phr_header, num_headers: [*c]usize, last_len: usize) c_int; +pub const struct_phr_chunked_decoder = extern struct { + bytes_left_in_chunk: usize, + consume_trailer: u8, + _hex_count: u8, + _state: u8, +}; +pub extern fn phr_decode_chunked(decoder: *struct_phr_chunked_decoder, buf: [*]u8, bufsz: *usize) isize; +pub extern fn phr_decode_chunked_is_in_data(decoder: *struct_phr_chunked_decoder) c_int; +pub const phr_header = struct_phr_header; +pub const phr_chunked_decoder = struct_phr_chunked_decoder; diff --git a/src/deps/s2n-tls b/src/deps/s2n-tls new file mode 160000 +Subproject 4c31c6e790f14b299bb16de550a2132666e69a6 diff --git a/src/deps/zig-clap/clap.zig b/src/deps/zig-clap/clap.zig index e6bf56f08..907ece37f 100644 --- a/src/deps/zig-clap/clap.zig +++ b/src/deps/zig-clap/clap.zig @@ -63,6 +63,8 @@ pub fn Param(comptime Id: type) type { /// Takes a string and parses it to a Param(Help). /// This is the reverse of 'help' but for at single parameter only. pub fn parseParam(line: []const u8) !Param(Help) { + @setEvalBranchQuota(9999); + var found_comma = false; var it = mem.tokenize(u8, line, " \t"); var param_str = it.next() orelse return error.NoParamFound; diff --git a/src/feature_flags.zig b/src/feature_flags.zig index 777753561..1772cfb77 100644 --- a/src/feature_flags.zig +++ b/src/feature_flags.zig @@ -77,3 +77,22 @@ pub const force_macro = false; pub const include_filename_in_jsx = false; pub const verbose_analytics = false; + +pub const disable_compression_in_http_client = false; + +// Not sure why... +// But this is slower! +// ~/Build/throw +// ❯ hyperfine "bun create react3 app --force --no-install" --prepare="rm -rf app" +// Benchmark #1: bun create react3 app --force --no-install +// Time (mean ± σ): 974.6 ms ± 6.8 ms [User: 170.5 ms, System: 798.3 ms] +// Range (min … max): 960.8 ms … 984.6 ms 10 runs + +// ❯ mv /usr/local/opt/libgit2/lib/libgit2.dylib /usr/local/opt/libgit2/lib/libgit2.dylib.1 + +// ~/Build/throw +// ❯ hyperfine "bun create react3 app --force --no-install" --prepare="rm -rf app" +// Benchmark #1: bun create react3 app --force --no-install +// Time (mean ± σ): 306.7 ms ± 6.1 ms [User: 31.7 ms, System: 269.8 ms] +// Range (min … max): 299.5 ms … 318.8 ms 10 runs +pub const use_libgit2 = true; diff --git a/src/global.zig b/src/global.zig index 738b294b5..b55a64a8d 100644 --- a/src/global.zig +++ b/src/global.zig @@ -128,7 +128,14 @@ pub const Output = struct { } pub fn printElapsed(elapsed: f64) void { - Output.prettyError("<r><d>[<b>{d:>.2}ms<r><d>]<r>", .{elapsed}); + switch (elapsed) { + 0...1500 => { + Output.prettyError("<r><d>[<b>{d:>.2}ms<r><d>]<r>", .{elapsed}); + }, + else => { + Output.prettyError("<r><d>[<b>{d:>.2}s<r><d>]<r>", .{elapsed / 1000.0}); + }, + } } pub fn printStartEnd(start: i128, end: i128) void { diff --git a/src/http.zig b/src/http.zig index 5cc7376cb..4ceccfaa4 100644 --- a/src/http.zig +++ b/src/http.zig @@ -60,54 +60,7 @@ const ZigURL = @import("./query_string_map.zig").URL; const HTTPStatusCode = u10; const URLPath = @import("./http/url_path.zig"); - -pub const Method = enum { - GET, - HEAD, - PATCH, - PUT, - POST, - OPTIONS, - CONNECT, - TRACE, - - pub fn which(str: []const u8) ?Method { - if (str.len < 3) { - return null; - } - const Match = strings.ExactSizeMatcher(2); - // we already did the length check - switch (Match.match(str[0..2])) { - Match.case("GE"), Match.case("ge") => { - return .GET; - }, - Match.case("HE"), Match.case("he") => { - return .HEAD; - }, - Match.case("PA"), Match.case("pa") => { - return .PATCH; - }, - Match.case("PO"), Match.case("po") => { - return .POST; - }, - Match.case("PU"), Match.case("pu") => { - return .PUT; - }, - Match.case("OP"), Match.case("op") => { - return .OPTIONS; - }, - Match.case("CO"), Match.case("co") => { - return .CONNECT; - }, - Match.case("TR"), Match.case("tr") => { - return .TRACE; - }, - else => { - return null; - }, - } - } -}; +const Method = @import("./http/method.zig").Method; pub const RequestContext = struct { request: Request, diff --git a/src/http/method.zig b/src/http/method.zig new file mode 100644 index 000000000..f306e522e --- /dev/null +++ b/src/http/method.zig @@ -0,0 +1,49 @@ +usingnamespace @import("../global.zig"); + +pub const Method = enum { + GET, + HEAD, + PATCH, + PUT, + POST, + OPTIONS, + CONNECT, + TRACE, + + pub fn which(str: []const u8) ?Method { + if (str.len < 3) { + return null; + } + const Match = strings.ExactSizeMatcher(2); + // we already did the length check + switch (Match.match(str[0..2])) { + Match.case("GE"), Match.case("ge") => { + return .GET; + }, + Match.case("HE"), Match.case("he") => { + return .HEAD; + }, + Match.case("PA"), Match.case("pa") => { + return .PATCH; + }, + Match.case("PO"), Match.case("po") => { + return .POST; + }, + Match.case("PU"), Match.case("pu") => { + return .PUT; + }, + Match.case("OP"), Match.case("op") => { + return .OPTIONS; + }, + Match.case("CO"), Match.case("co") => { + return .CONNECT; + }, + Match.case("TR"), Match.case("tr") => { + return .TRACE; + }, + else => { + return null; + }, + } + } +}; diff --git a/src/http_client.zig b/src/http_client.zig index c14e5d1c2..bc1a82406 100644 --- a/src/http_client.zig +++ b/src/http_client.zig @@ -1,17 +1,18 @@ // @link "/Users/jarred/Code/bun/src/deps/zlib/libz.a" -// @link "/Users/jarred/Code/bun/src/deps/picohttpparser.o" -const picohttp = @import("picohttp"); +const picohttp = @import("./deps/picohttp.zig"); usingnamespace @import("./global.zig"); const std = @import("std"); const Headers = @import("./javascript/jsc/webcore/response.zig").Headers; const URL = @import("./query_string_map.zig").URL; -const Method = @import("./http.zig").Method; -const iguanaTLS = @import("iguanaTLS"); +const Method = @import("./http/method.zig").Method; +const iguanaTLS = @import("./deps/iguanaTLS/src/main.zig"); const Api = @import("./api/schema.zig").Api; const Lock = @import("./lock.zig").Lock; const HTTPClient = @This(); const SOCKET_FLAGS = os.SOCK_CLOEXEC; +const S2n = @import("./s2n.zig"); +const Zlib = @import("./zlib.zig"); fn writeRequest( comptime Writer: type, @@ -40,6 +41,13 @@ url: URL, allocator: *std.mem.Allocator, verbose: bool = isTest, tcp_client: tcp.Client = undefined, +body_size: u32 = 0, +read_count: u32 = 0, +remaining_redirect_count: i8 = 127, +redirect_buf: [2048]u8 = undefined, +disable_shutdown: bool = false, +timeout: u32 = 0, +progress_node: ?*std.Progress.Node = null, pub fn init(allocator: *std.mem.Allocator, method: Method, url: URL, header_entries: Headers.Entries, header_buf: string) HTTPClient { return HTTPClient{ @@ -88,9 +96,11 @@ pub const Encoding = enum { gzip, deflate, brotli, + chunked, }; const content_encoding_hash = hashHeaderName("Content-Encoding"); +const transfer_encoding_header = hashHeaderName("Transfer-Encoding"); const host_header_name = "Host"; const content_length_header_name = "Content-Length"; @@ -98,15 +108,29 @@ const content_length_header_hash = hashHeaderName("Content-Length"); const connection_header = picohttp.Header{ .name = "Connection", .value = "close" }; const accept_header = picohttp.Header{ .name = "Accept", .value = "*/*" }; const accept_header_hash = hashHeaderName("Accept"); -const accept_encoding_header = picohttp.Header{ .name = "Accept-Encoding", .value = "deflate, gzip" }; + +const accept_encoding_no_compression = "identity"; +const accept_encoding_compression = "deflate, gzip"; +const accept_encoding_header_compression = picohttp.Header{ .name = "Accept-Encoding", .value = accept_encoding_compression }; +const accept_encoding_header_no_compression = picohttp.Header{ .name = "Accept-Encoding", .value = accept_encoding_no_compression }; + +const accept_encoding_header = if (FeatureFlags.disable_compression_in_http_client) + accept_encoding_header_no_compression +else + accept_encoding_header_compression; + const accept_encoding_header_hash = hashHeaderName("Accept-Encoding"); + const user_agent_header = picohttp.Header{ .name = "User-Agent", .value = "Bun.js " ++ Global.package_json_version }; const user_agent_header_hash = hashHeaderName("User-Agent"); +const location_header_hash = hashHeaderName("Location"); pub fn headerStr(this: *const HTTPClient, ptr: Api.StringPointer) string { return this.header_buf[ptr.offset..][0..ptr.length]; } +threadlocal var server_name_buf: [1024]u8 = undefined; + pub fn buildRequest(this: *const HTTPClient, body_len: usize) picohttp.Request { var header_count: usize = 0; var header_entries = this.header_entries.slice(); @@ -199,6 +223,14 @@ pub fn connect( ) !tcp.Client { var client: tcp.Client = try tcp.Client.init(tcp.Domain.ip, .{ .close_on_exec = true }); const port = this.url.getPortAuto(); + client.setNoDelay(true) catch {}; + client.setReadBufferSize(http_req_buf.len) catch {}; + client.setQuickACK(true) catch {}; + + if (this.timeout > 0) { + client.setReadTimeout(this.timeout) catch {}; + client.setWriteTimeout(this.timeout) catch {}; + } // if (this.url.isLocalhost()) { // try client.connect( @@ -208,6 +240,7 @@ pub fn connect( // } else if (this.url.isDomainName()) { var stream = try std.net.tcpConnectToHost(default_allocator, this.url.hostname, port); client.socket = std.x.os.Socket.from(stream.handle); + // } // } else if (this.url.getIPv4Address()) |ip_addr| { // try client.connect(std.x.os.Socket.Address(ip_addr, port)); @@ -222,19 +255,38 @@ pub fn connect( threadlocal var http_req_buf: [65436]u8 = undefined; -pub inline fn send(this: *HTTPClient, body: []const u8, body_out_str: *MutableString) !picohttp.Response { - if (this.url.isHTTPS()) { - return this.sendHTTPS(body, body_out_str); - } else { - return this.sendHTTP(body, body_out_str); +pub fn send(this: *HTTPClient, body: []const u8, body_out_str: *MutableString) !picohttp.Response { + // this prevents stack overflow + redirect: while (this.remaining_redirect_count >= -1) { + if (this.url.isHTTPS()) { + return this.sendHTTPS(body, body_out_str) catch |err| { + switch (err) { + error.Redirect => { + this.remaining_redirect_count -= 1; + continue :redirect; + }, + else => return err, + } + }; + } else { + return this.sendHTTP(body, body_out_str) catch |err| { + switch (err) { + error.Redirect => { + this.remaining_redirect_count -= 1; + continue :redirect; + }, + else => return err, + } + }; + } } + + return error.TooManyRedirects; } pub fn sendHTTP(this: *HTTPClient, body: []const u8, body_out_str: *MutableString) !picohttp.Response { this.tcp_client = try this.connect(); - defer { - std.os.closeSocket(this.tcp_client.socket.fd); - } + defer std.os.closeSocket(this.tcp_client.socket.fd); var request = buildRequest(this, body.len); if (this.verbose) { Output.prettyErrorln("{s}", .{request}); @@ -255,12 +307,23 @@ pub fn sendHTTP(this: *HTTPClient, body: []const u8, body_out_str: *MutableStrin var client_reader = this.tcp_client.reader(SOCKET_FLAGS); - return this.processResponse( - false, - @TypeOf(client_reader), - client_reader, - body_out_str, - ); + if (this.progress_node == null) { + return this.processResponse( + false, + false, + @TypeOf(client_reader), + client_reader, + body_out_str, + ); + } else { + return this.processResponse( + false, + true, + @TypeOf(client_reader), + client_reader, + body_out_str, + ); + } } const ZlibPool = struct { @@ -302,24 +365,28 @@ const ZlibPool = struct { } }; -pub fn processResponse(this: *HTTPClient, comptime is_https: bool, comptime Client: type, client: Client, body_out_str: *MutableString) !picohttp.Response { +pub fn processResponse(this: *HTTPClient, comptime is_https: bool, comptime report_progress: bool, comptime Client: type, client: Client, body_out_str: *MutableString) !picohttp.Response { var response: picohttp.Response = undefined; - + var read_length: usize = 0; { - var req_buf_len: usize = 0; + var read_headers_up_to: usize = 0; + var req_buf_read: usize = std.math.maxInt(usize); + defer this.read_count += @intCast(u32, read_length); - var response_length: usize = 0; restart: while (req_buf_read != 0) { - req_buf_read = try client.read(if (comptime is_https) - &http_req_buf - else - http_req_buf[req_buf_len..]); - req_buf_len += req_buf_read; + req_buf_read = try client.read(http_req_buf[read_length..]); + read_length += req_buf_read; + if (comptime report_progress) { + this.progress_node.?.activate(); + this.progress_node.?.setCompletedItems(read_length); + this.progress_node.?.context.maybeRefresh(); + } - var request_buffer = http_req_buf[0..req_buf_len]; + var request_buffer = http_req_buf[0..read_length]; + read_headers_up_to = if (read_headers_up_to > read_length) read_length else read_headers_up_to; - response = picohttp.Response.parseParts(request_buffer, &response_headers_buf, &response_length) catch |err| { + response = picohttp.Response.parseParts(request_buffer, &response_headers_buf, &read_headers_up_to) catch |err| { switch (err) { error.ShortRead => { continue :restart; @@ -336,17 +403,21 @@ pub fn processResponse(this: *HTTPClient, comptime is_https: bool, comptime Clie body_out_str.reset(); var content_length: u32 = 0; var encoding = Encoding.identity; + var transfer_encoding = Encoding.identity; - for (response.headers) |header| { - if (this.verbose) { - Output.prettyErrorln("Response: {s}", .{response}); - } + var location: string = ""; + + if (this.verbose) { + Output.prettyErrorln("Response: {s}", .{response}); + } + for (response.headers) |header| { switch (hashHeaderName(header.name)) { content_length_header_hash => { content_length = std.fmt.parseInt(u32, header.value, 10) catch 0; try body_out_str.inflate(content_length); body_out_str.list.expandToCapacity(); + this.body_size = content_length; }, content_encoding_hash => { if (strings.eqlComptime(header.value, "gzip")) { @@ -354,21 +425,160 @@ pub fn processResponse(this: *HTTPClient, comptime is_https: bool, comptime Clie } else if (strings.eqlComptime(header.value, "deflate")) { encoding = Encoding.deflate; } else if (!strings.eqlComptime(header.value, "identity")) { - return error.UnsupportedEncoding; + return error.UnsupportedContentEncoding; + } + }, + transfer_encoding_header => { + if (strings.eqlComptime(header.value, "gzip")) { + transfer_encoding = Encoding.gzip; + } else if (strings.eqlComptime(header.value, "deflate")) { + transfer_encoding = Encoding.deflate; + } else if (strings.eqlComptime(header.value, "identity")) { + transfer_encoding = Encoding.identity; + } else if (strings.eqlComptime(header.value, "chunked")) { + transfer_encoding = Encoding.chunked; + } else { + return error.UnsupportedTransferEncoding; } }, + location_header_hash => { + location = header.value; + }, + else => {}, } } + if (location.len > 0 and this.remaining_redirect_count > 0) { + switch (response.status_code) { + 302, 301, 307, 308, 303 => { + if (strings.indexOf(location, "://")) |i| { + const protocol_name = location[0..i]; + if (strings.eqlComptime(protocol_name, "http") or strings.eqlComptime(protocol_name, "https")) {} else { + return error.UnsupportedRedirectProtocol; + } + + std.mem.copy(u8, &this.redirect_buf, location); + this.url = URL.parse(location); + } else { + const original_url = this.url; + this.url = URL.parse(std.fmt.bufPrint( + &this.redirect_buf, + "{s}://{s}{s}", + .{ original_url.displayProtocol(), original_url.displayHostname(), location }, + ) catch return error.RedirectURLTooLong); + } + + // https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/303 + if (response.status_code == 303) { + this.method = .GET; + } + + return error.Redirect; + }, + else => {}, + } + } + + if (transfer_encoding == Encoding.chunked) { + var decoder = std.mem.zeroes(picohttp.phr_chunked_decoder); + var buffer_: *MutableString = body_out_str; + + switch (encoding) { + Encoding.gzip, Encoding.deflate => { + if (!ZlibPool.loaded) { + ZlibPool.instance = ZlibPool.init(default_allocator); + ZlibPool.loaded = true; + } + + buffer_ = try ZlibPool.instance.get(); + }, + else => {}, + } + + var buffer = buffer_.*; + + var last_read: usize = 0; + { + var remainder = http_req_buf[@intCast(usize, response.bytes_read)..read_length]; + last_read = remainder.len; + try buffer.inflate(std.math.max(remainder.len, 2048)); + buffer.list.expandToCapacity(); + std.mem.copy(u8, buffer.list.items, remainder); + } + + // set consume_trailer to 1 to discard the trailing header + // using content-encoding per chunk is not supported + decoder.consume_trailer = 1; + + // these variable names are terrible + // it's copypasta from https://github.com/h2o/picohttpparser#phr_decode_chunked + // (but ported from C -> zig) + var rret: usize = 0; + var rsize: usize = last_read; + var pret: isize = picohttp.phr_decode_chunked(&decoder, buffer.list.items.ptr, &rsize); + var total_size = rsize; + + while (pret == -2) { + if (buffer.list.items[total_size..].len < @intCast(usize, decoder.bytes_left_in_chunk)) { + try buffer.inflate(total_size + @intCast(usize, decoder.bytes_left_in_chunk)); + buffer.list.expandToCapacity(); + var slice = buffer.list.items[total_size..]; + } + + rret = try client.read(buffer.list.items[total_size..]); + + if (rret == 0) { + return error.ChunkedEncodingError; + } + + rsize = rret; + pret = picohttp.phr_decode_chunked(&decoder, buffer.list.items[total_size..].ptr, &rsize); + if (pret == -1) return error.ChunkedEncodingParseError; + + total_size += rsize; + + if (comptime report_progress) { + this.progress_node.?.activate(); + this.progress_node.?.setCompletedItems(total_size); + this.progress_node.?.context.maybeRefresh(); + } + } + + buffer.list.shrinkRetainingCapacity(total_size); + buffer_.* = buffer; + + switch (encoding) { + Encoding.gzip, Encoding.deflate => { + body_out_str.list.expandToCapacity(); + defer ZlibPool.instance.put(buffer_) catch unreachable; + var reader = try Zlib.ZlibReaderArrayList.init(buffer.list.items, &body_out_str.list, default_allocator); + reader.readAll() catch |err| { + if (reader.errorMessage()) |msg| { + Output.prettyErrorln("<r><red>Zlib error<r>: <b>{s}<r>", .{msg}); + Output.flush(); + } + return err; + }; + }, + else => {}, + } + + if (comptime report_progress) { + this.progress_node.?.activate(); + this.progress_node.?.setCompletedItems(body_out_str.list.items.len); + this.progress_node.?.context.maybeRefresh(); + } + + this.body_size = @intCast(u32, body_out_str.list.items.len); + return response; + } + if (content_length > 0) { var remaining_content_length = content_length; - var remainder = http_req_buf[@intCast(u32, response.bytes_read)..]; + var remainder = http_req_buf[@intCast(usize, response.bytes_read)..read_length]; remainder = remainder[0..std.math.min(remainder.len, content_length)]; - - const Zlib = @import("./zlib.zig"); - - var buffer: *MutableString = body_out_str; + var buffer_: *MutableString = body_out_str; switch (encoding) { Encoding.gzip, Encoding.deflate => { @@ -377,40 +587,54 @@ pub fn processResponse(this: *HTTPClient, comptime is_https: bool, comptime Clie ZlibPool.loaded = true; } - buffer = try ZlibPool.instance.get(); - if (buffer.list.capacity < remaining_content_length) { - try buffer.list.ensureUnusedCapacity(buffer.allocator, remaining_content_length); + buffer_ = try ZlibPool.instance.get(); + if (buffer_.list.capacity < remaining_content_length) { + try buffer_.list.ensureUnusedCapacity(buffer_.allocator, remaining_content_length); } - buffer.list.items = buffer.list.items.ptr[0..remaining_content_length]; + buffer_.list.items = buffer_.list.items.ptr[0..remaining_content_length]; }, else => {}, } + var buffer = buffer_.*; var body_size: usize = 0; - if (comptime !is_https) { - if (remainder.len > 0) { - std.mem.copy(u8, buffer.list.items, remainder); - body_size = @intCast(u32, remainder.len); - remaining_content_length -= @intCast(u32, remainder.len); - } + if (remainder.len > 0) { + std.mem.copy(u8, buffer.list.items, remainder); + body_size = remainder.len; + this.read_count += @intCast(u32, body_size); + remaining_content_length -= @intCast(u32, remainder.len); } while (remaining_content_length > 0) { const size = @intCast(u32, try client.read( buffer.list.items[body_size..], )); + this.read_count += size; if (size == 0) break; body_size += size; remaining_content_length -= size; + + if (comptime report_progress) { + this.progress_node.?.activate(); + this.progress_node.?.setCompletedItems(body_size); + this.progress_node.?.context.maybeRefresh(); + } + } + + if (comptime report_progress) { + this.progress_node.?.activate(); + this.progress_node.?.setCompletedItems(body_size); + this.progress_node.?.context.maybeRefresh(); } buffer.list.shrinkRetainingCapacity(body_size); + buffer_.* = buffer; switch (encoding) { Encoding.gzip, Encoding.deflate => { body_out_str.list.expandToCapacity(); - defer ZlibPool.instance.put(buffer) catch unreachable; + defer ZlibPool.instance.put(buffer_) catch unreachable; var reader = try Zlib.ZlibReaderArrayList.init(buffer.list.items, &body_out_str.list, default_allocator); reader.readAll() catch |err| { if (reader.errorMessage()) |msg| { @@ -424,36 +648,27 @@ pub fn processResponse(this: *HTTPClient, comptime is_https: bool, comptime Clie } } + if (comptime report_progress) { + this.progress_node.?.activate(); + this.progress_node.?.setCompletedItems(body_out_str.list.items.len); + this.progress_node.?.context.maybeRefresh(); + } + return response; } pub fn sendHTTPS(this: *HTTPClient, body_str: []const u8, body_out_str: *MutableString) !picohttp.Response { var connection = try this.connect(); + S2n.boot(default_allocator); + const hostname = this.url.displayHostname(); + std.mem.copy(u8, &server_name_buf, hostname); + server_name_buf[hostname.len] = 0; + var server_name = server_name_buf[0..hostname.len :0]; - var arena = std.heap.ArenaAllocator.init(this.allocator); - defer arena.deinit(); - - var rand = blk: { - var seed: [std.rand.DefaultCsprng.secret_seed_length]u8 = undefined; - try std.os.getrandom(&seed); - break :blk &std.rand.DefaultCsprng.init(seed).random; - }; - - var client = try iguanaTLS.client_connect( - .{ - .rand = rand, - .temp_allocator = &arena.allocator, - .reader = connection.reader(SOCKET_FLAGS), - .writer = connection.writer(SOCKET_FLAGS), - .cert_verifier = .none, - .protocols = &[_][]const u8{"http/1.1"}, - }, - this.url.hostname, - ); - - defer { - client.close_notify() catch {}; - } + var client = S2n.Connection.init(connection.socket.fd); + try client.start(server_name); + client.disable_shutdown = this.disable_shutdown; + defer client.close() catch {}; var request = buildRequest(this, body_str.len); if (this.verbose) { @@ -475,9 +690,11 @@ pub fn sendHTTPS(this: *HTTPClient, body_str: []const u8, body_out_str: *Mutable try client_writer.writeAll(body); } - var reader = client.reader(); - - return try this.processResponse(true, @TypeOf(&reader), &reader, body_out_str); + if (this.progress_node == null) { + return try this.processResponse(true, false, @TypeOf(&client), &client, body_out_str); + } else { + return try this.processResponse(true, true, @TypeOf(&client), &client, body_out_str); + } } // zig test src/http_client.zig --test-filter "sendHTTP - only" -lc -lc++ /Users/jarred/Code/bun/src/deps/zlib/libz.a /Users/jarred/Code/bun/src/deps/picohttpparser.o --cache-dir /Users/jarred/Code/bun/zig-cache --global-cache-dir /Users/jarred/.cache/zig --name bun --pkg-begin clap /Users/jarred/Code/bun/src/deps/zig-clap/clap.zig --pkg-end --pkg-begin picohttp /Users/jarred/Code/bun/src/deps/picohttp.zig --pkg-end --pkg-begin iguanaTLS /Users/jarred/Code/bun/src/deps/iguanaTLS/src/main.zig --pkg-end -I /Users/jarred/Code/bun/src/deps -I /Users/jarred/Code/bun/src/deps/mimalloc -I /usr/local/opt/icu4c/include -L src/deps/mimalloc -L /usr/local/opt/icu4c/lib --main-pkg-path /Users/jarred/Code/bun --enable-cache -femit-bin=zig-out/bin/test --test-no-exec @@ -568,7 +785,6 @@ test "sendHTTPS - identity" { try std.testing.expectEqualStrings(body_out_str.list.items, @embedFile("fixtures_example.com.html")); } -// zig test src/http_client.zig --test-filter "sendHTTPS - gzip" -lc -lc++ /Users/jarred/Code/bun/src/deps/zlib/libz.a /Users/jarred/Code/bun/src/deps/picohttpparser.o --cache-dir /Users/jarred/Code/bun/zig-cache --global-cache-dir /Users/jarred/.cache/zig --name bun --pkg-begin clap /Users/jarred/Code/bun/src/deps/zig-clap/clap.zig --pkg-end --pkg-begin picohttp /Users/jarred/Code/bun/src/deps/picohttp.zig --pkg-end --pkg-begin iguanaTLS /Users/jarred/Code/bun/src/deps/iguanaTLS/src/main.zig --pkg-end -I /Users/jarred/Code/bun/src/deps -I /Users/jarred/Code/bun/src/deps/mimalloc -I /usr/local/opt/icu4c/include -L src/deps/mimalloc -L /usr/local/opt/icu4c/lib --main-pkg-path /Users/jarred/Code/bun --enable-cache -femit-bin=zig-out/bin/test --test-no-exec test "sendHTTPS - gzip" { Output.initTest(); defer Output.flush(); @@ -596,4 +812,61 @@ test "sendHTTPS - gzip" { try std.testing.expectEqualStrings(body_out_str.list.items, @embedFile("fixtures_example.com.html")); } +// zig test src/http_client.zig --test-filter "sendHTTPS - deflate" -lc -lc++ /Users/jarred/Code/bun/src/deps/zlib/libz.a /Users/jarred/Code/bun/src/deps/picohttpparser.o --cache-dir /Users/jarred/Code/bun/zig-cache --global-cache-dir /Users/jarred/.cache/zig --name bun --pkg-begin clap /Users/jarred/Code/bun/src/deps/zig-clap/clap.zig --pkg-end --pkg-begin picohttp /Users/jarred/Code/bun/src/deps/picohttp.zig --pkg-end --pkg-begin iguanaTLS /Users/jarred/Code/bun/src/deps/iguanaTLS/src/main.zig --pkg-end -I /Users/jarred/Code/bun/src/deps -I /Users/jarred/Code/bun/src/deps/mimalloc -I /usr/local/opt/icu4c/include -L src/deps/mimalloc -L /usr/local/opt/icu4c/lib --main-pkg-path /Users/jarred/Code/bun --enable-cache -femit-bin=zig-out/bin/test +test "sendHTTPS - deflate" { + Output.initTest(); + defer Output.flush(); + + var headers = try std.heap.c_allocator.create(Headers); + headers.* = Headers{ + .entries = @TypeOf(headers.entries){}, + .buf = @TypeOf(headers.buf){}, + .used = 0, + .allocator = std.heap.c_allocator, + }; + + headers.appendHeader("Accept-Encoding", "deflate", false, false, false); + + var client = HTTPClient.init( + std.heap.c_allocator, + .GET, + URL.parse("https://example.com/"), + headers.entries, + headers.buf.items, + ); + var body_out_str = try MutableString.init(std.heap.c_allocator, 0); + var response = try client.sendHTTPS("", &body_out_str); + try std.testing.expectEqual(response.status_code, 200); + try std.testing.expectEqualStrings(body_out_str.list.items, @embedFile("fixtures_example.com.html")); +} + // zig test src/http_client.zig --test-filter "sendHTTP" -lc -lc++ /Users/jarred/Code/bun/src/deps/zlib/libz.a /Users/jarred/Code/bun/src/deps/picohttpparser.o --cache-dir /Users/jarred/Code/bun/zig-cache --global-cache-dir /Users/jarred/.cache/zig --name bun --pkg-begin clap /Users/jarred/Code/bun/src/deps/zig-clap/clap.zig --pkg-end --pkg-begin picohttp /Users/jarred/Code/bun/src/deps/picohttp.zig --pkg-end --pkg-begin iguanaTLS /Users/jarred/Code/bun/src/deps/iguanaTLS/src/main.zig --pkg-end -I /Users/jarred/Code/bun/src/deps -I /Users/jarred/Code/bun/src/deps/mimalloc -I /usr/local/opt/icu4c/include -L src/deps/mimalloc -L /usr/local/opt/icu4c/lib --main-pkg-path /Users/jarred/Code/bun --enable-cache -femit-bin=zig-out/bin/test + +test "send - redirect" { + Output.initTest(); + defer Output.flush(); + + var headers = try std.heap.c_allocator.create(Headers); + headers.* = Headers{ + .entries = @TypeOf(headers.entries){}, + .buf = @TypeOf(headers.buf){}, + .used = 0, + .allocator = std.heap.c_allocator, + }; + + headers.appendHeader("Accept-Encoding", "gzip", false, false, false); + + var client = HTTPClient.init( + std.heap.c_allocator, + .GET, + URL.parse("https://www.bun.sh/"), + headers.entries, + headers.buf.items, + ); + try std.testing.expectEqualStrings(client.url.hostname, "www.bun.sh"); + var body_out_str = try MutableString.init(std.heap.c_allocator, 0); + var response = try client.send("", &body_out_str); + try std.testing.expectEqual(response.status_code, 200); + try std.testing.expectEqual(client.url.hostname, "bun.sh"); + try std.testing.expectEqualStrings(body_out_str.list.items, @embedFile("fixtures_example.com.html")); +} diff --git a/src/javascript/jsc/webcore/response.zig b/src/javascript/jsc/webcore/response.zig index ff399990e..76be74d84 100644 --- a/src/javascript/jsc/webcore/response.zig +++ b/src/javascript/jsc/webcore/response.zig @@ -6,6 +6,8 @@ usingnamespace @import("../javascript.zig"); usingnamespace @import("../bindings/bindings.zig"); const ZigURL = @import("../../../query_string_map.zig").URL; const HTTPClient = @import("../../../http_client.zig"); +const Method = @import("../../../http/method.zig").Method; + const picohttp = @import("picohttp"); pub const Response = struct { pub const Class = NewClass( @@ -500,7 +502,7 @@ pub const Fetch = struct { defer js.JSStringRelease(string_ref); var method_name_buf: [16]u8 = undefined; var method_name = method_name_buf[0..js.JSStringGetUTF8CString(string_ref, &method_name_buf, method_name_buf.len)]; - http_client.method = http.Method.which(method_name) orelse http_client.method; + http_client.method = Method.which(method_name) orelse http_client.method; } } }, diff --git a/src/js_printer.zig b/src/js_printer.zig index 95e8ea22c..cc6f71fa7 100644 --- a/src/js_printer.zig +++ b/src/js_printer.zig @@ -81,11 +81,11 @@ pub const SourceMapChunk = struct { pub const Options = struct { transform_imports: bool = true, - to_module_ref: js_ast.Ref, + to_module_ref: js_ast.Ref = js_ast.Ref.None, require_ref: ?js_ast.Ref = null, indent: usize = 0, externals: []u32 = &[_]u32{}, - runtime_imports: runtime.Runtime.Imports, + runtime_imports: runtime.Runtime.Imports = runtime.Runtime.Imports{}, module_hash: u32 = 0, source_path: ?fs.Path = null, bundle_export_ref: ?js_ast.Ref = null, @@ -219,6 +219,7 @@ pub fn NewPrinter( comptime rewrite_esm_to_cjs: bool, comptime bun: bool, comptime is_inside_bundle: bool, + comptime is_json: bool, ) type { return struct { symbols: Symbol.Map, @@ -506,7 +507,11 @@ pub fn NewPrinter( } } - pub fn bestQuoteCharForString(p: *Printer, str: anytype, allow_backtick: bool) u8 { + pub fn bestQuoteCharForString(p: *Printer, str: anytype, allow_backtick_: bool) u8 { + if (comptime is_json) return '"'; + + const allow_backtick = allow_backtick_; + var single_cost: usize = 0; var double_cost: usize = 0; var backtick_cost: usize = 0; @@ -867,6 +872,8 @@ pub fn NewPrinter( } pub inline fn canPrintIdentifier(p: *Printer, name: string) bool { + if (comptime is_json) return false; + if (comptime ascii_only) { return js_lexer.isIdentifier(name) and !strings.containsNonBmpCodePoint(name); } else { @@ -889,8 +896,6 @@ pub fn NewPrinter( pub fn printExpr(p: *Printer, expr: Expr, level: Level, _flags: ExprFlag) void { p.addSourceMapping(expr.loc); var flags = _flags; - debugl("<printExpr>"); - defer debugl("</printExpr>"); switch (expr.data) { .e_missing => {}, @@ -1321,7 +1326,10 @@ pub fn NewPrinter( }, .e_object => |e| { const n = p.writer.written; - const wrap = p.stmt_start == n or p.arrow_expr_start == n; + const wrap = if (comptime is_json) + false + else + p.stmt_start == n or p.arrow_expr_start == n; if (wrap) { p.print("("); @@ -1879,7 +1887,7 @@ pub fn NewPrinter( // While each of those property keys are ASCII, a subset of ASCII is valid as the start of an identifier // "=" and ":" are not valid // So we need to check - if (js_lexer.isIdentifier(key.utf8)) { + if ((comptime !is_json) and js_lexer.isIdentifier(key.utf8)) { p.print(key.utf8); } else { allow_shorthand = false; @@ -4087,7 +4095,7 @@ pub fn printAst( comptime LinkerType: type, linker: ?*LinkerType, ) !usize { - const PrinterType = NewPrinter(false, Writer, LinkerType, false, false, false); + const PrinterType = NewPrinter(false, Writer, LinkerType, false, false, false, false); var writer = _writer; var printer = try PrinterType.init( @@ -4122,6 +4130,39 @@ pub fn printAst( return @intCast(usize, std.math.max(printer.writer.written, 0)); } +pub fn printJSON( + comptime Writer: type, + _writer: Writer, + expr: Expr, + source: *const logger.Source, +) !usize { + const PrinterType = NewPrinter(false, Writer, void, false, false, false, true); + var writer = _writer; + var s_expr = S.SExpr{ .value = expr }; + var stmt = Stmt{ .loc = logger.Loc.Empty, .data = .{ + .s_expr = &s_expr, + } }; + var stmts = &[_]js_ast.Stmt{stmt}; + var parts = &[_]js_ast.Part{.{ .stmts = stmts }}; + const ast = Ast.initTest(parts); + var printer = try PrinterType.init( + writer, + &ast, + source, + std.mem.zeroes(Symbol.Map), + .{}, + null, + ); + + printer.printExpr(expr, Level.lowest, ExprFlag{}); + if (printer.writer.getError()) {} else |err| { + return err; + } + try printer.writer.done(); + + return @intCast(usize, std.math.max(printer.writer.written, 0)); +} + pub fn printCommonJS( comptime Writer: type, _writer: Writer, @@ -4133,7 +4174,7 @@ pub fn printCommonJS( comptime LinkerType: type, linker: ?*LinkerType, ) !usize { - const PrinterType = NewPrinter(false, Writer, LinkerType, true, false, false); + const PrinterType = NewPrinter(false, Writer, LinkerType, true, false, false, false); var writer = _writer; var printer = try PrinterType.init( writer, @@ -4191,7 +4232,7 @@ pub fn printCommonJSThreaded( comptime getPos: fn (ctx: GetPosType) anyerror!u64, end_off_ptr: *u32, ) !WriteResult { - const PrinterType = NewPrinter(false, Writer, LinkerType, true, false, true); + const PrinterType = NewPrinter(false, Writer, LinkerType, true, false, true, false); var writer = _writer; var printer = try PrinterType.init( writer, diff --git a/src/libarchive/libarchive-bindings.zig b/src/libarchive/libarchive-bindings.zig new file mode 100644 index 000000000..d449642ef --- /dev/null +++ b/src/libarchive/libarchive-bindings.zig @@ -0,0 +1,628 @@ +pub const wchar_t = c_int; +pub const la_int64_t = i64; +pub const la_ssize_t = isize; +pub const struct_archive = opaque {}; +pub const struct_archive_entry = opaque {}; +pub const archive = struct_archive; +pub const archive_entry = struct_archive_entry; +const mode_t = @import("std").c.mode_t; + +pub const FileType = enum(mode_t) { + regular = 0100000, + link = 0120000, + socket = 0140000, + character_oriented_device = 0020000, + block_oriented_device = 0060000, + directory = 0040000, + fifo = 0010000, +}; + +pub const SymlinkType = enum(c_int) { + none = 0, + file = 1, + directory = 2, +}; + +pub const ARCHIVE_VERSION_ONLY_STRING = "3.5.3dev"; +pub const ARCHIVE_VERSION_STRING = "libarchive " ++ ARCHIVE_VERSION_ONLY_STRING; +pub const ARCHIVE_EOF = @as(c_int, 1); +pub const ARCHIVE_OK = @as(c_int, 0); +pub const ARCHIVE_RETRY = -@as(c_int, 10); +pub const ARCHIVE_WARN = -@as(c_int, 20); +pub const ARCHIVE_FAILED = -@as(c_int, 25); +pub const ARCHIVE_FATAL = -@as(c_int, 30); +pub const ARCHIVE_FILTER_NONE = @as(c_int, 0); +pub const ARCHIVE_FILTER_GZIP = @as(c_int, 1); +pub const ARCHIVE_FILTER_BZIP2 = @as(c_int, 2); +pub const ARCHIVE_FILTER_COMPRESS = @as(c_int, 3); +pub const ARCHIVE_FILTER_PROGRAM = @as(c_int, 4); +pub const ARCHIVE_FILTER_LZMA = @as(c_int, 5); +pub const ARCHIVE_FILTER_XZ = @as(c_int, 6); +pub const ARCHIVE_FILTER_UU = @as(c_int, 7); +pub const ARCHIVE_FILTER_RPM = @as(c_int, 8); +pub const ARCHIVE_FILTER_LZIP = @as(c_int, 9); +pub const ARCHIVE_FILTER_LRZIP = @as(c_int, 10); +pub const ARCHIVE_FILTER_LZOP = @as(c_int, 11); +pub const ARCHIVE_FILTER_GRZIP = @as(c_int, 12); +pub const ARCHIVE_FILTER_LZ4 = @as(c_int, 13); +pub const ARCHIVE_FILTER_ZSTD = @as(c_int, 14); +pub const ARCHIVE_COMPRESSION_NONE = ARCHIVE_FILTER_NONE; +pub const ARCHIVE_COMPRESSION_GZIP = ARCHIVE_FILTER_GZIP; +pub const ARCHIVE_COMPRESSION_BZIP2 = ARCHIVE_FILTER_BZIP2; +pub const ARCHIVE_COMPRESSION_COMPRESS = ARCHIVE_FILTER_COMPRESS; +pub const ARCHIVE_COMPRESSION_PROGRAM = ARCHIVE_FILTER_PROGRAM; +pub const ARCHIVE_COMPRESSION_LZMA = ARCHIVE_FILTER_LZMA; +pub const ARCHIVE_COMPRESSION_XZ = ARCHIVE_FILTER_XZ; +pub const ARCHIVE_COMPRESSION_UU = ARCHIVE_FILTER_UU; +pub const ARCHIVE_COMPRESSION_RPM = ARCHIVE_FILTER_RPM; +pub const ARCHIVE_COMPRESSION_LZIP = ARCHIVE_FILTER_LZIP; +pub const ARCHIVE_COMPRESSION_LRZIP = ARCHIVE_FILTER_LRZIP; +pub const ARCHIVE_FORMAT_BASE_MASK = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0xff0000, .hexadecimal); +pub const ARCHIVE_FORMAT_CPIO = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x10000, .hexadecimal); +pub const ARCHIVE_FORMAT_CPIO_POSIX = ARCHIVE_FORMAT_CPIO | @as(c_int, 1); +pub const ARCHIVE_FORMAT_CPIO_BIN_LE = ARCHIVE_FORMAT_CPIO | @as(c_int, 2); +pub const ARCHIVE_FORMAT_CPIO_BIN_BE = ARCHIVE_FORMAT_CPIO | @as(c_int, 3); +pub const ARCHIVE_FORMAT_CPIO_SVR4_NOCRC = ARCHIVE_FORMAT_CPIO | @as(c_int, 4); +pub const ARCHIVE_FORMAT_CPIO_SVR4_CRC = ARCHIVE_FORMAT_CPIO | @as(c_int, 5); +pub const ARCHIVE_FORMAT_CPIO_AFIO_LARGE = ARCHIVE_FORMAT_CPIO | @as(c_int, 6); +pub const ARCHIVE_FORMAT_CPIO_PWB = ARCHIVE_FORMAT_CPIO | @as(c_int, 7); +pub const ARCHIVE_FORMAT_SHAR = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x20000, .hexadecimal); +pub const ARCHIVE_FORMAT_SHAR_BASE = ARCHIVE_FORMAT_SHAR | @as(c_int, 1); +pub const ARCHIVE_FORMAT_SHAR_DUMP = ARCHIVE_FORMAT_SHAR | @as(c_int, 2); +pub const ARCHIVE_FORMAT_TAR = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x30000, .hexadecimal); +pub const ARCHIVE_FORMAT_TAR_USTAR = ARCHIVE_FORMAT_TAR | @as(c_int, 1); +pub const ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE = ARCHIVE_FORMAT_TAR | @as(c_int, 2); +pub const ARCHIVE_FORMAT_TAR_PAX_RESTRICTED = ARCHIVE_FORMAT_TAR | @as(c_int, 3); +pub const ARCHIVE_FORMAT_TAR_GNUTAR = ARCHIVE_FORMAT_TAR | @as(c_int, 4); +pub const ARCHIVE_FORMAT_ISO9660 = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x40000, .hexadecimal); +pub const ARCHIVE_FORMAT_ISO9660_ROCKRIDGE = ARCHIVE_FORMAT_ISO9660 | @as(c_int, 1); +pub const ARCHIVE_FORMAT_ZIP = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x50000, .hexadecimal); +pub const ARCHIVE_FORMAT_EMPTY = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x60000, .hexadecimal); +pub const ARCHIVE_FORMAT_AR = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x70000, .hexadecimal); +pub const ARCHIVE_FORMAT_AR_GNU = ARCHIVE_FORMAT_AR | @as(c_int, 1); +pub const ARCHIVE_FORMAT_AR_BSD = ARCHIVE_FORMAT_AR | @as(c_int, 2); +pub const ARCHIVE_FORMAT_MTREE = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x80000, .hexadecimal); +pub const ARCHIVE_FORMAT_RAW = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x90000, .hexadecimal); +pub const ARCHIVE_FORMAT_XAR = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0xA0000, .hexadecimal); +pub const ARCHIVE_FORMAT_LHA = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0xB0000, .hexadecimal); +pub const ARCHIVE_FORMAT_CAB = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0xC0000, .hexadecimal); +pub const ARCHIVE_FORMAT_RAR = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0xD0000, .hexadecimal); +pub const ARCHIVE_FORMAT_7ZIP = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0xE0000, .hexadecimal); +pub const ARCHIVE_FORMAT_WARC = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0xF0000, .hexadecimal); +pub const ARCHIVE_FORMAT_RAR_V5 = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x100000, .hexadecimal); +pub const ARCHIVE_READ_FORMAT_CAPS_NONE = @as(c_int, 0); +pub const ARCHIVE_READ_FORMAT_CAPS_ENCRYPT_DATA = @as(c_int, 1) << @as(c_int, 0); +pub const ARCHIVE_READ_FORMAT_CAPS_ENCRYPT_METADATA = @as(c_int, 1) << @as(c_int, 1); +pub const ARCHIVE_READ_FORMAT_ENCRYPTION_UNSUPPORTED = -@as(c_int, 2); +pub const ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW = -@as(c_int, 1); +pub const ARCHIVE_EXTRACT_OWNER = @as(c_int, 0x0001); +pub const ARCHIVE_EXTRACT_PERM = @as(c_int, 0x0002); +pub const ARCHIVE_EXTRACT_TIME = @as(c_int, 0x0004); +pub const ARCHIVE_EXTRACT_NO_OVERWRITE = @as(c_int, 0x0008); +pub const ARCHIVE_EXTRACT_UNLINK = @as(c_int, 0x0010); +pub const ARCHIVE_EXTRACT_ACL = @as(c_int, 0x0020); +pub const ARCHIVE_EXTRACT_FFLAGS = @as(c_int, 0x0040); +pub const ARCHIVE_EXTRACT_XATTR = @as(c_int, 0x0080); +pub const ARCHIVE_EXTRACT_SECURE_SYMLINKS = @as(c_int, 0x0100); +pub const ARCHIVE_EXTRACT_SECURE_NODOTDOT = @as(c_int, 0x0200); +pub const ARCHIVE_EXTRACT_NO_AUTODIR = @as(c_int, 0x0400); +pub const ARCHIVE_EXTRACT_NO_OVERWRITE_NEWER = @as(c_int, 0x0800); +pub const ARCHIVE_EXTRACT_SPARSE = @as(c_int, 0x1000); +pub const ARCHIVE_EXTRACT_MAC_METADATA = @as(c_int, 0x2000); +pub const ARCHIVE_EXTRACT_NO_HFS_COMPRESSION = @as(c_int, 0x4000); +pub const ARCHIVE_EXTRACT_HFS_COMPRESSION_FORCED = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x8000, .hexadecimal); +pub const ARCHIVE_EXTRACT_SECURE_NOABSOLUTEPATHS = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x10000, .hexadecimal); +pub const ARCHIVE_EXTRACT_CLEAR_NOCHANGE_FFLAGS = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x20000, .hexadecimal); +pub const ARCHIVE_EXTRACT_SAFE_WRITES = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x40000, .hexadecimal); +pub const ARCHIVE_READDISK_RESTORE_ATIME = @as(c_int, 0x0001); +pub const ARCHIVE_READDISK_HONOR_NODUMP = @as(c_int, 0x0002); +pub const ARCHIVE_READDISK_MAC_COPYFILE = @as(c_int, 0x0004); +pub const ARCHIVE_READDISK_NO_TRAVERSE_MOUNTS = @as(c_int, 0x0008); +pub const ARCHIVE_READDISK_NO_XATTR = @as(c_int, 0x0010); +pub const ARCHIVE_READDISK_NO_ACL = @as(c_int, 0x0020); +pub const ARCHIVE_READDISK_NO_FFLAGS = @as(c_int, 0x0040); +pub const ARCHIVE_MATCH_MTIME = @as(c_int, 0x0100); +pub const ARCHIVE_MATCH_CTIME = @as(c_int, 0x0200); +pub const ARCHIVE_MATCH_NEWER = @as(c_int, 0x0001); +pub const ARCHIVE_MATCH_OLDER = @as(c_int, 0x0002); +pub const ARCHIVE_MATCH_EQUAL = @as(c_int, 0x0010); + +pub extern fn archive_version_number() c_int; +pub extern fn archive_version_string() [*c]const u8; +pub extern fn archive_version_details() [*c]const u8; +pub extern fn archive_zlib_version() [*c]const u8; +pub extern fn archive_liblzma_version() [*c]const u8; +pub extern fn archive_bzlib_version() [*c]const u8; +pub extern fn archive_liblz4_version() [*c]const u8; +pub extern fn archive_libzstd_version() [*c]const u8; + +pub const archive_read_callback = fn (*struct_archive, *c_void, [*c]*const c_void) callconv(.C) la_ssize_t; +pub const archive_skip_callback = fn (*struct_archive, *c_void, la_int64_t) callconv(.C) la_int64_t; +pub const archive_seek_callback = fn (*struct_archive, *c_void, la_int64_t, c_int) callconv(.C) la_int64_t; +pub const archive_write_callback = fn (*struct_archive, *c_void, ?*const c_void, usize) callconv(.C) la_ssize_t; +pub const archive_open_callback = fn (*struct_archive, *c_void) callconv(.C) c_int; +pub const archive_close_callback = fn (*struct_archive, *c_void) callconv(.C) c_int; +pub const archive_free_callback = fn (*struct_archive, *c_void) callconv(.C) c_int; +pub const archive_switch_callback = fn (*struct_archive, *c_void, ?*c_void) callconv(.C) c_int; +pub const archive_passphrase_callback = fn (*struct_archive, *c_void) callconv(.C) [*c]const u8; +pub extern fn archive_read_new() *struct_archive; +pub extern fn archive_read_support_compression_all(*struct_archive) c_int; +pub extern fn archive_read_support_compression_bzip2(*struct_archive) c_int; +pub extern fn archive_read_support_compression_compress(*struct_archive) c_int; +pub extern fn archive_read_support_compression_gzip(*struct_archive) c_int; +pub extern fn archive_read_support_compression_lzip(*struct_archive) c_int; +pub extern fn archive_read_support_compression_lzma(*struct_archive) c_int; +pub extern fn archive_read_support_compression_none(*struct_archive) c_int; +pub extern fn archive_read_support_compression_program(*struct_archive, command: [*c]const u8) c_int; +pub extern fn archive_read_support_compression_program_signature(*struct_archive, [*c]const u8, ?*const c_void, usize) c_int; +pub extern fn archive_read_support_compression_rpm(*struct_archive) c_int; +pub extern fn archive_read_support_compression_uu(*struct_archive) c_int; +pub extern fn archive_read_support_compression_xz(*struct_archive) c_int; +pub extern fn archive_read_support_filter_all(*struct_archive) c_int; +pub extern fn archive_read_support_filter_by_code(*struct_archive, c_int) c_int; +pub extern fn archive_read_support_filter_bzip2(*struct_archive) c_int; +pub extern fn archive_read_support_filter_compress(*struct_archive) c_int; +pub extern fn archive_read_support_filter_gzip(*struct_archive) c_int; +pub extern fn archive_read_support_filter_grzip(*struct_archive) c_int; +pub extern fn archive_read_support_filter_lrzip(*struct_archive) c_int; +pub extern fn archive_read_support_filter_lz4(*struct_archive) c_int; +pub extern fn archive_read_support_filter_lzip(*struct_archive) c_int; +pub extern fn archive_read_support_filter_lzma(*struct_archive) c_int; +pub extern fn archive_read_support_filter_lzop(*struct_archive) c_int; +pub extern fn archive_read_support_filter_none(*struct_archive) c_int; +pub extern fn archive_read_support_filter_program(*struct_archive, command: [*c]const u8) c_int; +pub extern fn archive_read_support_filter_program_signature(*struct_archive, [*c]const u8, ?*const c_void, usize) c_int; +pub extern fn archive_read_support_filter_rpm(*struct_archive) c_int; +pub extern fn archive_read_support_filter_uu(*struct_archive) c_int; +pub extern fn archive_read_support_filter_xz(*struct_archive) c_int; +pub extern fn archive_read_support_filter_zstd(*struct_archive) c_int; +pub extern fn archive_read_support_format_7zip(*struct_archive) c_int; +pub extern fn archive_read_support_format_all(*struct_archive) c_int; +pub extern fn archive_read_support_format_ar(*struct_archive) c_int; +pub extern fn archive_read_support_format_by_code(*struct_archive, c_int) c_int; +pub extern fn archive_read_support_format_cab(*struct_archive) c_int; +pub extern fn archive_read_support_format_cpio(*struct_archive) c_int; +pub extern fn archive_read_support_format_empty(*struct_archive) c_int; +pub extern fn archive_read_support_format_gnutar(*struct_archive) c_int; +pub extern fn archive_read_support_format_iso9660(*struct_archive) c_int; +pub extern fn archive_read_support_format_lha(*struct_archive) c_int; +pub extern fn archive_read_support_format_mtree(*struct_archive) c_int; +pub extern fn archive_read_support_format_rar(*struct_archive) c_int; +pub extern fn archive_read_support_format_rar5(*struct_archive) c_int; +pub extern fn archive_read_support_format_raw(*struct_archive) c_int; +pub extern fn archive_read_support_format_tar(*struct_archive) c_int; +pub extern fn archive_read_support_format_warc(*struct_archive) c_int; +pub extern fn archive_read_support_format_xar(*struct_archive) c_int; +pub extern fn archive_read_support_format_zip(*struct_archive) c_int; +pub extern fn archive_read_support_format_zip_streamable(*struct_archive) c_int; +pub extern fn archive_read_support_format_zip_seekable(*struct_archive) c_int; +pub extern fn archive_read_set_format(*struct_archive, c_int) c_int; +pub extern fn archive_read_append_filter(*struct_archive, c_int) c_int; +pub extern fn archive_read_append_filter_program(*struct_archive, [*c]const u8) c_int; +pub extern fn archive_read_append_filter_program_signature(*struct_archive, [*c]const u8, ?*const c_void, usize) c_int; +pub extern fn archive_read_set_open_callback(*struct_archive, ?archive_open_callback) c_int; +pub extern fn archive_read_set_read_callback(*struct_archive, ?archive_read_callback) c_int; +pub extern fn archive_read_set_seek_callback(*struct_archive, ?archive_seek_callback) c_int; +pub extern fn archive_read_set_skip_callback(*struct_archive, ?archive_skip_callback) c_int; +pub extern fn archive_read_set_close_callback(*struct_archive, ?archive_close_callback) c_int; +pub extern fn archive_read_set_switch_callback(*struct_archive, ?archive_switch_callback) c_int; +pub extern fn archive_read_set_callback_data(*struct_archive, ?*c_void) c_int; +pub extern fn archive_read_set_callback_data2(*struct_archive, ?*c_void, c_uint) c_int; +pub extern fn archive_read_add_callback_data(*struct_archive, ?*c_void, c_uint) c_int; +pub extern fn archive_read_append_callback_data(*struct_archive, ?*c_void) c_int; +pub extern fn archive_read_prepend_callback_data(*struct_archive, ?*c_void) c_int; +pub extern fn archive_read_open1(*struct_archive) c_int; +pub extern fn archive_read_open(*struct_archive, _client_data: ?*c_void, ?archive_open_callback, ?archive_read_callback, ?archive_close_callback) c_int; +pub extern fn archive_read_open2(*struct_archive, _client_data: ?*c_void, ?archive_open_callback, ?archive_read_callback, ?archive_skip_callback, ?archive_close_callback) c_int; +pub extern fn archive_read_open_filename(*struct_archive, _filename: [*c]const u8, _block_size: usize) c_int; +pub extern fn archive_read_open_filenames(*struct_archive, _filenames: [*c][*c]const u8, _block_size: usize) c_int; +pub extern fn archive_read_open_filename_w(*struct_archive, _filename: [*c]const wchar_t, _block_size: usize) c_int; +pub extern fn archive_read_open_file(*struct_archive, _filename: [*c]const u8, _block_size: usize) c_int; +pub extern fn archive_read_open_memory(*struct_archive, buff: ?*const c_void, size: usize) c_int; +pub extern fn archive_read_open_memory2(a: *struct_archive, buff: ?*const c_void, size: usize, read_size: usize) c_int; +pub extern fn archive_read_open_fd(*struct_archive, _fd: c_int, _block_size: usize) c_int; +pub extern fn archive_read_open_FILE(*struct_archive, _file: [*c]FILE) c_int; +pub extern fn archive_read_next_header(*struct_archive, [*c]*struct_archive_entry) c_int; +pub extern fn archive_read_next_header2(*struct_archive, *struct_archive_entry) c_int; +pub extern fn archive_read_header_position(*struct_archive) la_int64_t; +pub extern fn archive_read_has_encrypted_entries(*struct_archive) c_int; +pub extern fn archive_read_format_capabilities(*struct_archive) c_int; +pub extern fn archive_read_data(*struct_archive, ?*c_void, usize) la_ssize_t; +pub extern fn archive_seek_data(*struct_archive, la_int64_t, c_int) la_int64_t; +pub extern fn archive_read_data_block(a: *struct_archive, buff: [*c]*const c_void, size: [*c]usize, offset: [*c]la_int64_t) c_int; +pub extern fn archive_read_data_skip(*struct_archive) c_int; +pub extern fn archive_read_data_into_fd(*struct_archive, fd: c_int) c_int; +pub extern fn archive_read_set_format_option(_a: *struct_archive, m: [*c]const u8, o: [*c]const u8, v: [*c]const u8) c_int; +pub extern fn archive_read_set_filter_option(_a: *struct_archive, m: [*c]const u8, o: [*c]const u8, v: [*c]const u8) c_int; +pub extern fn archive_read_set_option(_a: *struct_archive, m: [*c]const u8, o: [*c]const u8, v: [*c]const u8) c_int; +pub extern fn archive_read_set_options(_a: *struct_archive, opts: [*c]const u8) c_int; +pub extern fn archive_read_add_passphrase(*struct_archive, [*c]const u8) c_int; +pub extern fn archive_read_set_passphrase_callback(*struct_archive, client_data: ?*c_void, ?archive_passphrase_callback) c_int; +pub extern fn archive_read_extract(*struct_archive, *struct_archive_entry, flags: c_int) c_int; +pub extern fn archive_read_extract2(*struct_archive, *struct_archive_entry, *struct_archive) c_int; +pub extern fn archive_read_extract_set_progress_callback(*struct_archive, _progress_func: ?fn (?*c_void) callconv(.C) void, _user_data: ?*c_void) void; +pub extern fn archive_read_extract_set_skip_file(*struct_archive, la_int64_t, la_int64_t) void; +pub extern fn archive_read_close(*struct_archive) c_int; +pub extern fn archive_read_free(*struct_archive) c_int; +pub extern fn archive_read_finish(*struct_archive) c_int; +pub extern fn archive_write_new() *struct_archive; +pub extern fn archive_write_set_bytes_per_block(*struct_archive, bytes_per_block: c_int) c_int; +pub extern fn archive_write_get_bytes_per_block(*struct_archive) c_int; +pub extern fn archive_write_set_bytes_in_last_block(*struct_archive, bytes_in_last_block: c_int) c_int; +pub extern fn archive_write_get_bytes_in_last_block(*struct_archive) c_int; +pub extern fn archive_write_set_skip_file(*struct_archive, la_int64_t, la_int64_t) c_int; +pub extern fn archive_write_set_compression_bzip2(*struct_archive) c_int; +pub extern fn archive_write_set_compression_compress(*struct_archive) c_int; +pub extern fn archive_write_set_compression_gzip(*struct_archive) c_int; +pub extern fn archive_write_set_compression_lzip(*struct_archive) c_int; +pub extern fn archive_write_set_compression_lzma(*struct_archive) c_int; +pub extern fn archive_write_set_compression_none(*struct_archive) c_int; +pub extern fn archive_write_set_compression_program(*struct_archive, cmd: [*c]const u8) c_int; +pub extern fn archive_write_set_compression_xz(*struct_archive) c_int; +pub extern fn archive_write_add_filter(*struct_archive, filter_code: c_int) c_int; +pub extern fn archive_write_add_filter_by_name(*struct_archive, name: [*c]const u8) c_int; +pub extern fn archive_write_add_filter_b64encode(*struct_archive) c_int; +pub extern fn archive_write_add_filter_bzip2(*struct_archive) c_int; +pub extern fn archive_write_add_filter_compress(*struct_archive) c_int; +pub extern fn archive_write_add_filter_grzip(*struct_archive) c_int; +pub extern fn archive_write_add_filter_gzip(*struct_archive) c_int; +pub extern fn archive_write_add_filter_lrzip(*struct_archive) c_int; +pub extern fn archive_write_add_filter_lz4(*struct_archive) c_int; +pub extern fn archive_write_add_filter_lzip(*struct_archive) c_int; +pub extern fn archive_write_add_filter_lzma(*struct_archive) c_int; +pub extern fn archive_write_add_filter_lzop(*struct_archive) c_int; +pub extern fn archive_write_add_filter_none(*struct_archive) c_int; +pub extern fn archive_write_add_filter_program(*struct_archive, cmd: [*c]const u8) c_int; +pub extern fn archive_write_add_filter_uuencode(*struct_archive) c_int; +pub extern fn archive_write_add_filter_xz(*struct_archive) c_int; +pub extern fn archive_write_add_filter_zstd(*struct_archive) c_int; +pub extern fn archive_write_set_format(*struct_archive, format_code: c_int) c_int; +pub extern fn archive_write_set_format_by_name(*struct_archive, name: [*c]const u8) c_int; +pub extern fn archive_write_set_format_7zip(*struct_archive) c_int; +pub extern fn archive_write_set_format_ar_bsd(*struct_archive) c_int; +pub extern fn archive_write_set_format_ar_svr4(*struct_archive) c_int; +pub extern fn archive_write_set_format_cpio(*struct_archive) c_int; +pub extern fn archive_write_set_format_cpio_bin(*struct_archive) c_int; +pub extern fn archive_write_set_format_cpio_newc(*struct_archive) c_int; +pub extern fn archive_write_set_format_cpio_odc(*struct_archive) c_int; +pub extern fn archive_write_set_format_cpio_pwb(*struct_archive) c_int; +pub extern fn archive_write_set_format_gnutar(*struct_archive) c_int; +pub extern fn archive_write_set_format_iso9660(*struct_archive) c_int; +pub extern fn archive_write_set_format_mtree(*struct_archive) c_int; +pub extern fn archive_write_set_format_mtree_classic(*struct_archive) c_int; +pub extern fn archive_write_set_format_pax(*struct_archive) c_int; +pub extern fn archive_write_set_format_pax_restricted(*struct_archive) c_int; +pub extern fn archive_write_set_format_raw(*struct_archive) c_int; +pub extern fn archive_write_set_format_shar(*struct_archive) c_int; +pub extern fn archive_write_set_format_shar_dump(*struct_archive) c_int; +pub extern fn archive_write_set_format_ustar(*struct_archive) c_int; +pub extern fn archive_write_set_format_v7tar(*struct_archive) c_int; +pub extern fn archive_write_set_format_warc(*struct_archive) c_int; +pub extern fn archive_write_set_format_xar(*struct_archive) c_int; +pub extern fn archive_write_set_format_zip(*struct_archive) c_int; +pub extern fn archive_write_set_format_filter_by_ext(a: *struct_archive, filename: [*c]const u8) c_int; +pub extern fn archive_write_set_format_filter_by_ext_def(a: *struct_archive, filename: [*c]const u8, def_ext: [*c]const u8) c_int; +pub extern fn archive_write_zip_set_compression_deflate(*struct_archive) c_int; +pub extern fn archive_write_zip_set_compression_store(*struct_archive) c_int; +pub extern fn archive_write_open(*struct_archive, ?*c_void, ?archive_open_callback, ?archive_write_callback, ?archive_close_callback) c_int; +pub extern fn archive_write_open2(*struct_archive, ?*c_void, ?archive_open_callback, ?archive_write_callback, ?archive_close_callback, ?archive_free_callback) c_int; +pub extern fn archive_write_open_fd(*struct_archive, _fd: c_int) c_int; +pub extern fn archive_write_open_filename(*struct_archive, _file: [*c]const u8) c_int; +pub extern fn archive_write_open_filename_w(*struct_archive, _file: [*c]const wchar_t) c_int; +pub extern fn archive_write_open_file(*struct_archive, _file: [*c]const u8) c_int; +pub extern fn archive_write_open_FILE(*struct_archive, [*c]FILE) c_int; +pub extern fn archive_write_open_memory(*struct_archive, _buffer: ?*c_void, _buffSize: usize, _used: [*c]usize) c_int; +pub extern fn archive_write_header(*struct_archive, *struct_archive_entry) c_int; +pub extern fn archive_write_data(*struct_archive, ?*const c_void, usize) la_ssize_t; +pub extern fn archive_write_data_block(*struct_archive, ?*const c_void, usize, la_int64_t) la_ssize_t; +pub extern fn archive_write_finish_entry(*struct_archive) c_int; +pub extern fn archive_write_close(*struct_archive) c_int; +pub extern fn archive_write_fail(*struct_archive) c_int; +pub extern fn archive_write_free(*struct_archive) c_int; +pub extern fn archive_write_finish(*struct_archive) c_int; +pub extern fn archive_write_set_format_option(_a: *struct_archive, m: [*c]const u8, o: [*c]const u8, v: [*c]const u8) c_int; +pub extern fn archive_write_set_filter_option(_a: *struct_archive, m: [*c]const u8, o: [*c]const u8, v: [*c]const u8) c_int; +pub extern fn archive_write_set_option(_a: *struct_archive, m: [*c]const u8, o: [*c]const u8, v: [*c]const u8) c_int; +pub extern fn archive_write_set_options(_a: *struct_archive, opts: [*c]const u8) c_int; +pub extern fn archive_write_set_passphrase(_a: *struct_archive, p: [*c]const u8) c_int; +pub extern fn archive_write_set_passphrase_callback(*struct_archive, client_data: ?*c_void, ?archive_passphrase_callback) c_int; +pub extern fn archive_write_disk_new() *struct_archive; +pub extern fn archive_write_disk_set_skip_file(*struct_archive, la_int64_t, la_int64_t) c_int; +pub extern fn archive_write_disk_set_options(*struct_archive, flags: c_int) c_int; +pub extern fn archive_write_disk_set_standard_lookup(*struct_archive) c_int; +pub extern fn archive_write_disk_set_group_lookup(*struct_archive, ?*c_void, ?fn (?*c_void, [*c]const u8, la_int64_t) callconv(.C) la_int64_t, ?fn (?*c_void) callconv(.C) void) c_int; +pub extern fn archive_write_disk_set_user_lookup(*struct_archive, ?*c_void, ?fn (?*c_void, [*c]const u8, la_int64_t) callconv(.C) la_int64_t, ?fn (?*c_void) callconv(.C) void) c_int; +pub extern fn archive_write_disk_gid(*struct_archive, [*c]const u8, la_int64_t) la_int64_t; +pub extern fn archive_write_disk_uid(*struct_archive, [*c]const u8, la_int64_t) la_int64_t; +pub extern fn archive_read_disk_new() *struct_archive; +pub extern fn archive_read_disk_set_symlink_logical(*struct_archive) c_int; +pub extern fn archive_read_disk_set_symlink_physical(*struct_archive) c_int; +pub extern fn archive_read_disk_set_symlink_hybrid(*struct_archive) c_int; +pub extern fn archive_read_disk_entry_from_file(*struct_archive, *struct_archive_entry, c_int, [*c]const struct_stat) c_int; +pub extern fn archive_read_disk_gname(*struct_archive, la_int64_t) [*c]const u8; +pub extern fn archive_read_disk_uname(*struct_archive, la_int64_t) [*c]const u8; +pub extern fn archive_read_disk_set_standard_lookup(*struct_archive) c_int; +pub extern fn archive_read_disk_set_gname_lookup(*struct_archive, ?*c_void, ?fn (?*c_void, la_int64_t) callconv(.C) [*c]const u8, ?fn (?*c_void) callconv(.C) void) c_int; +pub extern fn archive_read_disk_set_uname_lookup(*struct_archive, ?*c_void, ?fn (?*c_void, la_int64_t) callconv(.C) [*c]const u8, ?fn (?*c_void) callconv(.C) void) c_int; +pub extern fn archive_read_disk_open(*struct_archive, [*c]const u8) c_int; +pub extern fn archive_read_disk_open_w(*struct_archive, [*c]const wchar_t) c_int; +pub extern fn archive_read_disk_descend(*struct_archive) c_int; +pub extern fn archive_read_disk_can_descend(*struct_archive) c_int; +pub extern fn archive_read_disk_current_filesystem(*struct_archive) c_int; +pub extern fn archive_read_disk_current_filesystem_is_synthetic(*struct_archive) c_int; +pub extern fn archive_read_disk_current_filesystem_is_remote(*struct_archive) c_int; +pub extern fn archive_read_disk_set_atime_restored(*struct_archive) c_int; +pub extern fn archive_read_disk_set_behavior(*struct_archive, flags: c_int) c_int; +pub extern fn archive_read_disk_set_matching(*struct_archive, _matching: *struct_archive, _excluded_func: ?fn (*struct_archive, ?*c_void, *struct_archive_entry) callconv(.C) void, _client_data: ?*c_void) c_int; +pub extern fn archive_read_disk_set_metadata_filter_callback(*struct_archive, _metadata_filter_func: ?fn (*struct_archive, ?*c_void, *struct_archive_entry) callconv(.C) c_int, _client_data: ?*c_void) c_int; +pub extern fn archive_free(*struct_archive) c_int; +pub extern fn archive_filter_count(*struct_archive) c_int; +pub extern fn archive_filter_bytes(*struct_archive, c_int) la_int64_t; +pub extern fn archive_filter_code(*struct_archive, c_int) c_int; +pub extern fn archive_filter_name(*struct_archive, c_int) [*c]const u8; +pub extern fn archive_position_compressed(*struct_archive) la_int64_t; +pub extern fn archive_position_uncompressed(*struct_archive) la_int64_t; +pub extern fn archive_compression_name(*struct_archive) [*c]const u8; +pub extern fn archive_compression(*struct_archive) c_int; +pub extern fn archive_errno(*struct_archive) c_int; +pub extern fn archive_error_string(*struct_archive) [*c]const u8; +pub extern fn archive_format_name(*struct_archive) [*c]const u8; +pub extern fn archive_format(*struct_archive) c_int; +pub extern fn archive_clear_error(*struct_archive) void; +pub extern fn archive_set_error(*struct_archive, _err: c_int, fmt: [*c]const u8, ...) void; +pub extern fn archive_copy_error(dest: *struct_archive, src: *struct_archive) void; +pub extern fn archive_file_count(*struct_archive) c_int; +pub extern fn archive_match_new() *struct_archive; +pub extern fn archive_match_free(*struct_archive) c_int; +pub extern fn archive_match_excluded(*struct_archive, *struct_archive_entry) c_int; +pub extern fn archive_match_path_excluded(*struct_archive, *struct_archive_entry) c_int; +pub extern fn archive_match_set_inclusion_recursion(*struct_archive, c_int) c_int; +pub extern fn archive_match_exclude_pattern(*struct_archive, [*c]const u8) c_int; +pub extern fn archive_match_exclude_pattern_w(*struct_archive, [*c]const wchar_t) c_int; +pub extern fn archive_match_exclude_pattern_from_file(*struct_archive, [*c]const u8, _nullSeparator: c_int) c_int; +pub extern fn archive_match_exclude_pattern_from_file_w(*struct_archive, [*c]const wchar_t, _nullSeparator: c_int) c_int; +pub extern fn archive_match_include_pattern(*struct_archive, [*c]const u8) c_int; +pub extern fn archive_match_include_pattern_w(*struct_archive, [*c]const wchar_t) c_int; +pub extern fn archive_match_include_pattern_from_file(*struct_archive, [*c]const u8, _nullSeparator: c_int) c_int; +pub extern fn archive_match_include_pattern_from_file_w(*struct_archive, [*c]const wchar_t, _nullSeparator: c_int) c_int; +pub extern fn archive_match_path_unmatched_inclusions(*struct_archive) c_int; +pub extern fn archive_match_path_unmatched_inclusions_next(*struct_archive, [*c][*c]const u8) c_int; +pub extern fn archive_match_path_unmatched_inclusions_next_w(*struct_archive, [*c][*c]const wchar_t) c_int; +pub extern fn archive_match_time_excluded(*struct_archive, *struct_archive_entry) c_int; +pub extern fn archive_match_include_time(*struct_archive, _flag: c_int, _sec: time_t, _nsec: c_long) c_int; +pub extern fn archive_match_include_date(*struct_archive, _flag: c_int, _datestr: [*c]const u8) c_int; +pub extern fn archive_match_include_date_w(*struct_archive, _flag: c_int, _datestr: [*c]const wchar_t) c_int; +pub extern fn archive_match_include_file_time(*struct_archive, _flag: c_int, _pathname: [*c]const u8) c_int; +pub extern fn archive_match_include_file_time_w(*struct_archive, _flag: c_int, _pathname: [*c]const wchar_t) c_int; +pub extern fn archive_match_exclude_entry(*struct_archive, _flag: c_int, *struct_archive_entry) c_int; +pub extern fn archive_match_owner_excluded(*struct_archive, *struct_archive_entry) c_int; +pub extern fn archive_match_include_uid(*struct_archive, la_int64_t) c_int; +pub extern fn archive_match_include_gid(*struct_archive, la_int64_t) c_int; +pub extern fn archive_match_include_uname(*struct_archive, [*c]const u8) c_int; +pub extern fn archive_match_include_uname_w(*struct_archive, [*c]const wchar_t) c_int; +pub extern fn archive_match_include_gname(*struct_archive, [*c]const u8) c_int; +pub extern fn archive_match_include_gname_w(*struct_archive, [*c]const wchar_t) c_int; +pub extern fn archive_utility_string_sort([*c][*c]u8) c_int; + +pub extern fn archive_entry_clear(*struct_archive_entry) *struct_archive_entry; +pub extern fn archive_entry_clone(*struct_archive_entry) *struct_archive_entry; +pub extern fn archive_entry_free(*struct_archive_entry) void; +pub extern fn archive_entry_new() *struct_archive_entry; +pub extern fn archive_entry_new2(*struct_archive) *struct_archive_entry; +pub extern fn archive_entry_atime(*struct_archive_entry) time_t; +pub extern fn archive_entry_atime_nsec(*struct_archive_entry) c_long; +pub extern fn archive_entry_atime_is_set(*struct_archive_entry) c_int; +pub extern fn archive_entry_birthtime(*struct_archive_entry) time_t; +pub extern fn archive_entry_birthtime_nsec(*struct_archive_entry) c_long; +pub extern fn archive_entry_birthtime_is_set(*struct_archive_entry) c_int; +pub extern fn archive_entry_ctime(*struct_archive_entry) time_t; +pub extern fn archive_entry_ctime_nsec(*struct_archive_entry) c_long; +pub extern fn archive_entry_ctime_is_set(*struct_archive_entry) c_int; +pub extern fn archive_entry_dev(*struct_archive_entry) dev_t; +pub extern fn archive_entry_dev_is_set(*struct_archive_entry) c_int; +pub extern fn archive_entry_devmajor(*struct_archive_entry) dev_t; +pub extern fn archive_entry_devminor(*struct_archive_entry) dev_t; +pub extern fn archive_entry_filetype(*struct_archive_entry) mode_t; +pub extern fn archive_entry_fflags(*struct_archive_entry, [*c]c_ulong, [*c]c_ulong) void; +pub extern fn archive_entry_fflags_text(*struct_archive_entry) [*c]const u8; +pub extern fn archive_entry_gid(*struct_archive_entry) la_int64_t; +pub extern fn archive_entry_gname(*struct_archive_entry) [*c]const u8; +pub extern fn archive_entry_gname_utf8(*struct_archive_entry) [*c]const u8; +pub extern fn archive_entry_gname_w(*struct_archive_entry) [*c]const wchar_t; +pub extern fn archive_entry_hardlink(*struct_archive_entry) [*c]const u8; +pub extern fn archive_entry_hardlink_utf8(*struct_archive_entry) [*c]const u8; +pub extern fn archive_entry_hardlink_w(*struct_archive_entry) [*c]const wchar_t; +pub extern fn archive_entry_ino(*struct_archive_entry) la_int64_t; +pub extern fn archive_entry_ino64(*struct_archive_entry) la_int64_t; +pub extern fn archive_entry_ino_is_set(*struct_archive_entry) c_int; +pub extern fn archive_entry_mode(*struct_archive_entry) mode_t; +pub extern fn archive_entry_mtime(*struct_archive_entry) time_t; +pub extern fn archive_entry_mtime_nsec(*struct_archive_entry) c_long; +pub extern fn archive_entry_mtime_is_set(*struct_archive_entry) c_int; +pub extern fn archive_entry_nlink(*struct_archive_entry) c_uint; +pub extern fn archive_entry_pathname(*struct_archive_entry) [*c]const u8; +pub extern fn archive_entry_pathname_utf8(*struct_archive_entry) [*c]const u8; +pub extern fn archive_entry_pathname_w(*struct_archive_entry) [*c]const wchar_t; +pub extern fn archive_entry_perm(*struct_archive_entry) mode_t; +pub extern fn archive_entry_rdev(*struct_archive_entry) dev_t; +pub extern fn archive_entry_rdevmajor(*struct_archive_entry) dev_t; +pub extern fn archive_entry_rdevminor(*struct_archive_entry) dev_t; +pub extern fn archive_entry_sourcepath(*struct_archive_entry) [*c]const u8; +pub extern fn archive_entry_sourcepath_w(*struct_archive_entry) [*c]const wchar_t; +pub extern fn archive_entry_size(*struct_archive_entry) la_int64_t; +pub extern fn archive_entry_size_is_set(*struct_archive_entry) c_int; +pub extern fn archive_entry_strmode(*struct_archive_entry) [*c]const u8; +pub extern fn archive_entry_symlink(*struct_archive_entry) [*c]const u8; +pub extern fn archive_entry_symlink_utf8(*struct_archive_entry) [*c]const u8; +pub extern fn archive_entry_symlink_type(*struct_archive_entry) SymlinkType; +pub extern fn archive_entry_symlink_w(*struct_archive_entry) [*c]const wchar_t; +pub extern fn archive_entry_uid(*struct_archive_entry) la_int64_t; +pub extern fn archive_entry_uname(*struct_archive_entry) [*c]const u8; +pub extern fn archive_entry_uname_utf8(*struct_archive_entry) [*c]const u8; +pub extern fn archive_entry_uname_w(*struct_archive_entry) [*c]const wchar_t; +pub extern fn archive_entry_is_data_encrypted(*struct_archive_entry) c_int; +pub extern fn archive_entry_is_metadata_encrypted(*struct_archive_entry) c_int; +pub extern fn archive_entry_is_encrypted(*struct_archive_entry) c_int; +pub extern fn archive_entry_set_atime(*struct_archive_entry, time_t, c_long) void; +pub extern fn archive_entry_unset_atime(*struct_archive_entry) void; +pub extern fn archive_entry_set_birthtime(*struct_archive_entry, time_t, c_long) void; +pub extern fn archive_entry_unset_birthtime(*struct_archive_entry) void; +pub extern fn archive_entry_set_ctime(*struct_archive_entry, time_t, c_long) void; +pub extern fn archive_entry_unset_ctime(*struct_archive_entry) void; +pub extern fn archive_entry_set_dev(*struct_archive_entry, dev_t) void; +pub extern fn archive_entry_set_devmajor(*struct_archive_entry, dev_t) void; +pub extern fn archive_entry_set_devminor(*struct_archive_entry, dev_t) void; +pub extern fn archive_entry_set_filetype(*struct_archive_entry, c_uint) void; +pub extern fn archive_entry_set_fflags(*struct_archive_entry, c_ulong, c_ulong) void; +pub extern fn archive_entry_copy_fflags_text(*struct_archive_entry, [*c]const u8) [*c]const u8; +pub extern fn archive_entry_copy_fflags_text_w(*struct_archive_entry, [*c]const wchar_t) [*c]const wchar_t; +pub extern fn archive_entry_set_gid(*struct_archive_entry, la_int64_t) void; +pub extern fn archive_entry_set_gname(*struct_archive_entry, [*c]const u8) void; +pub extern fn archive_entry_set_gname_utf8(*struct_archive_entry, [*c]const u8) void; +pub extern fn archive_entry_copy_gname(*struct_archive_entry, [*c]const u8) void; +pub extern fn archive_entry_copy_gname_w(*struct_archive_entry, [*c]const wchar_t) void; +pub extern fn archive_entry_update_gname_utf8(*struct_archive_entry, [*c]const u8) c_int; +pub extern fn archive_entry_set_hardlink(*struct_archive_entry, [*c]const u8) void; +pub extern fn archive_entry_set_hardlink_utf8(*struct_archive_entry, [*c]const u8) void; +pub extern fn archive_entry_copy_hardlink(*struct_archive_entry, [*c]const u8) void; +pub extern fn archive_entry_copy_hardlink_w(*struct_archive_entry, [*c]const wchar_t) void; +pub extern fn archive_entry_update_hardlink_utf8(*struct_archive_entry, [*c]const u8) c_int; +pub extern fn archive_entry_set_ino(*struct_archive_entry, la_int64_t) void; +pub extern fn archive_entry_set_ino64(*struct_archive_entry, la_int64_t) void; +pub extern fn archive_entry_set_link(*struct_archive_entry, [*c]const u8) void; +pub extern fn archive_entry_set_link_utf8(*struct_archive_entry, [*c]const u8) void; +pub extern fn archive_entry_copy_link(*struct_archive_entry, [*c]const u8) void; +pub extern fn archive_entry_copy_link_w(*struct_archive_entry, [*c]const wchar_t) void; +pub extern fn archive_entry_update_link_utf8(*struct_archive_entry, [*c]const u8) c_int; +pub extern fn archive_entry_set_mode(*struct_archive_entry, mode_t) void; +pub extern fn archive_entry_set_mtime(*struct_archive_entry, time_t, c_long) void; +pub extern fn archive_entry_unset_mtime(*struct_archive_entry) void; +pub extern fn archive_entry_set_nlink(*struct_archive_entry, c_uint) void; +pub extern fn archive_entry_set_pathname(*struct_archive_entry, [*c]const u8) void; +pub extern fn archive_entry_set_pathname_utf8(*struct_archive_entry, [*c]const u8) void; +pub extern fn archive_entry_copy_pathname(*struct_archive_entry, [*c]const u8) void; +pub extern fn archive_entry_copy_pathname_w(*struct_archive_entry, [*c]const wchar_t) void; +pub extern fn archive_entry_update_pathname_utf8(*struct_archive_entry, [*c]const u8) c_int; +pub extern fn archive_entry_set_perm(*struct_archive_entry, mode_t) void; +pub extern fn archive_entry_set_rdev(*struct_archive_entry, dev_t) void; +pub extern fn archive_entry_set_rdevmajor(*struct_archive_entry, dev_t) void; +pub extern fn archive_entry_set_rdevminor(*struct_archive_entry, dev_t) void; +pub extern fn archive_entry_set_size(*struct_archive_entry, la_int64_t) void; +pub extern fn archive_entry_unset_size(*struct_archive_entry) void; +pub extern fn archive_entry_copy_sourcepath(*struct_archive_entry, [*c]const u8) void; +pub extern fn archive_entry_copy_sourcepath_w(*struct_archive_entry, [*c]const wchar_t) void; +pub extern fn archive_entry_set_symlink(*struct_archive_entry, [*c]const u8) void; +pub extern fn archive_entry_set_symlink_type(*struct_archive_entry, c_int) void; +pub extern fn archive_entry_set_symlink_utf8(*struct_archive_entry, [*c]const u8) void; +pub extern fn archive_entry_copy_symlink(*struct_archive_entry, [*c]const u8) void; +pub extern fn archive_entry_copy_symlink_w(*struct_archive_entry, [*c]const wchar_t) void; +pub extern fn archive_entry_update_symlink_utf8(*struct_archive_entry, [*c]const u8) c_int; +pub extern fn archive_entry_set_uid(*struct_archive_entry, la_int64_t) void; +pub extern fn archive_entry_set_uname(*struct_archive_entry, [*c]const u8) void; +pub extern fn archive_entry_set_uname_utf8(*struct_archive_entry, [*c]const u8) void; +pub extern fn archive_entry_copy_uname(*struct_archive_entry, [*c]const u8) void; +pub extern fn archive_entry_copy_uname_w(*struct_archive_entry, [*c]const wchar_t) void; +pub extern fn archive_entry_update_uname_utf8(*struct_archive_entry, [*c]const u8) c_int; +pub extern fn archive_entry_set_is_data_encrypted(*struct_archive_entry, is_encrypted: u8) void; +pub extern fn archive_entry_set_is_metadata_encrypted(*struct_archive_entry, is_encrypted: u8) void; +pub const struct_stat = opaque {}; +pub extern fn archive_entry_stat(*struct_archive_entry) ?*const struct_stat; +pub extern fn archive_entry_copy_stat(*struct_archive_entry, ?*const struct_stat) void; +pub extern fn archive_entry_mac_metadata(*struct_archive_entry, [*c]usize) ?*const c_void; +pub extern fn archive_entry_copy_mac_metadata(*struct_archive_entry, ?*const c_void, usize) void; +pub extern fn archive_entry_digest(*struct_archive_entry, c_int) [*c]const u8; +pub extern fn archive_entry_acl_clear(*struct_archive_entry) void; +pub extern fn archive_entry_acl_add_entry(*struct_archive_entry, c_int, c_int, c_int, c_int, [*c]const u8) c_int; +pub extern fn archive_entry_acl_add_entry_w(*struct_archive_entry, c_int, c_int, c_int, c_int, [*c]const wchar_t) c_int; +pub extern fn archive_entry_acl_reset(*struct_archive_entry, c_int) c_int; +pub extern fn archive_entry_acl_next(*struct_archive_entry, c_int, [*c]c_int, [*c]c_int, [*c]c_int, [*c]c_int, [*c][*c]const u8) c_int; +pub extern fn archive_entry_acl_to_text_w(*struct_archive_entry, [*c]la_ssize_t, c_int) [*c]wchar_t; +pub extern fn archive_entry_acl_to_text(*struct_archive_entry, [*c]la_ssize_t, c_int) [*c]u8; +pub extern fn archive_entry_acl_from_text_w(*struct_archive_entry, [*c]const wchar_t, c_int) c_int; +pub extern fn archive_entry_acl_from_text(*struct_archive_entry, [*c]const u8, c_int) c_int; +pub extern fn archive_entry_acl_text_w(*struct_archive_entry, c_int) [*c]const wchar_t; +pub extern fn archive_entry_acl_text(*struct_archive_entry, c_int) [*c]const u8; +pub extern fn archive_entry_acl_types(*struct_archive_entry) c_int; +pub extern fn archive_entry_acl_count(*struct_archive_entry, c_int) c_int; +pub const struct_archive_acl = opaque {}; +pub extern fn archive_entry_acl(*struct_archive_entry) *struct_archive_acl; +pub extern fn archive_entry_xattr_clear(*struct_archive_entry) void; +pub extern fn archive_entry_xattr_add_entry(*struct_archive_entry, [*c]const u8, ?*const c_void, usize) void; +pub extern fn archive_entry_xattr_count(*struct_archive_entry) c_int; +pub extern fn archive_entry_xattr_reset(*struct_archive_entry) c_int; +pub extern fn archive_entry_xattr_next(*struct_archive_entry, [*c][*c]const u8, [*c]?*const c_void, [*c]usize) c_int; +pub extern fn archive_entry_sparse_clear(*struct_archive_entry) void; +pub extern fn archive_entry_sparse_add_entry(*struct_archive_entry, la_int64_t, la_int64_t) void; +pub extern fn archive_entry_sparse_count(*struct_archive_entry) c_int; +pub extern fn archive_entry_sparse_reset(*struct_archive_entry) c_int; +pub extern fn archive_entry_sparse_next(*struct_archive_entry, [*c]la_int64_t, [*c]la_int64_t) c_int; +pub const struct_archive_entry_linkresolver = opaque {}; +pub extern fn archive_entry_linkresolver_new() *struct_archive_entry_linkresolver; +pub extern fn archive_entry_linkresolver_set_strategy(*struct_archive_entry_linkresolver, c_int) void; +pub extern fn archive_entry_linkresolver_free(*struct_archive_entry_linkresolver) void; +pub extern fn archive_entry_linkify(*struct_archive_entry_linkresolver, [*c]*struct_archive_entry, [*c]*struct_archive_entry) void; +pub extern fn archive_entry_partial_links(res: *struct_archive_entry_linkresolver, links: [*c]c_uint) *struct_archive_entry; + +pub const archive_acl = struct_archive_acl; +pub const archive_entry_linkresolver = struct_archive_entry_linkresolver; + +pub const AE_SYMLINK_TYPE_UNDEFINED = @as(c_int, 0); +pub const AE_SYMLINK_TYPE_FILE = @as(c_int, 1); +pub const AE_SYMLINK_TYPE_DIRECTORY = @as(c_int, 2); +pub const ARCHIVE_ENTRY_DIGEST_MD5 = @as(c_int, 0x00000001); +pub const ARCHIVE_ENTRY_DIGEST_RMD160 = @as(c_int, 0x00000002); +pub const ARCHIVE_ENTRY_DIGEST_SHA1 = @as(c_int, 0x00000003); +pub const ARCHIVE_ENTRY_DIGEST_SHA256 = @as(c_int, 0x00000004); +pub const ARCHIVE_ENTRY_DIGEST_SHA384 = @as(c_int, 0x00000005); +pub const ARCHIVE_ENTRY_DIGEST_SHA512 = @as(c_int, 0x00000006); +pub const ARCHIVE_ENTRY_ACL_EXECUTE = @as(c_int, 0x00000001); +pub const ARCHIVE_ENTRY_ACL_WRITE = @as(c_int, 0x00000002); +pub const ARCHIVE_ENTRY_ACL_READ = @as(c_int, 0x00000004); +pub const ARCHIVE_ENTRY_ACL_READ_DATA = @as(c_int, 0x00000008); +pub const ARCHIVE_ENTRY_ACL_LIST_DIRECTORY = @as(c_int, 0x00000008); +pub const ARCHIVE_ENTRY_ACL_WRITE_DATA = @as(c_int, 0x00000010); +pub const ARCHIVE_ENTRY_ACL_ADD_FILE = @as(c_int, 0x00000010); +pub const ARCHIVE_ENTRY_ACL_APPEND_DATA = @as(c_int, 0x00000020); +pub const ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY = @as(c_int, 0x00000020); +pub const ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS = @as(c_int, 0x00000040); +pub const ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS = @as(c_int, 0x00000080); +pub const ARCHIVE_ENTRY_ACL_DELETE_CHILD = @as(c_int, 0x00000100); +pub const ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES = @as(c_int, 0x00000200); +pub const ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES = @as(c_int, 0x00000400); +pub const ARCHIVE_ENTRY_ACL_DELETE = @as(c_int, 0x00000800); +pub const ARCHIVE_ENTRY_ACL_READ_ACL = @as(c_int, 0x00001000); +pub const ARCHIVE_ENTRY_ACL_WRITE_ACL = @as(c_int, 0x00002000); +pub const ARCHIVE_ENTRY_ACL_WRITE_OWNER = @as(c_int, 0x00004000); +pub const ARCHIVE_ENTRY_ACL_SYNCHRONIZE = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x00008000, .hexadecimal); +pub const ARCHIVE_ENTRY_ACL_PERMS_POSIX1E = (ARCHIVE_ENTRY_ACL_EXECUTE | ARCHIVE_ENTRY_ACL_WRITE) | ARCHIVE_ENTRY_ACL_READ; +pub const ARCHIVE_ENTRY_ACL_PERMS_NFS4 = (((((((((((((((ARCHIVE_ENTRY_ACL_EXECUTE | ARCHIVE_ENTRY_ACL_READ_DATA) | ARCHIVE_ENTRY_ACL_LIST_DIRECTORY) | ARCHIVE_ENTRY_ACL_WRITE_DATA) | ARCHIVE_ENTRY_ACL_ADD_FILE) | ARCHIVE_ENTRY_ACL_APPEND_DATA) | ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY) | ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS) | ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS) | ARCHIVE_ENTRY_ACL_DELETE_CHILD) | ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES) | ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES) | ARCHIVE_ENTRY_ACL_DELETE) | ARCHIVE_ENTRY_ACL_READ_ACL) | ARCHIVE_ENTRY_ACL_WRITE_ACL) | ARCHIVE_ENTRY_ACL_WRITE_OWNER) | ARCHIVE_ENTRY_ACL_SYNCHRONIZE; +pub const ARCHIVE_ENTRY_ACL_ENTRY_INHERITED = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x01000000, .hexadecimal); +pub const ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x02000000, .hexadecimal); +pub const ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x04000000, .hexadecimal); +pub const ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x08000000, .hexadecimal); +pub const ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x10000000, .hexadecimal); +pub const ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x20000000, .hexadecimal); +pub const ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x40000000, .hexadecimal); +pub const ARCHIVE_ENTRY_ACL_INHERITANCE_NFS4 = (((((ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT | ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT) | ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT) | ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY) | ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS) | ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS) | ARCHIVE_ENTRY_ACL_ENTRY_INHERITED; +pub const ARCHIVE_ENTRY_ACL_TYPE_ACCESS = @as(c_int, 0x00000100); +pub const ARCHIVE_ENTRY_ACL_TYPE_DEFAULT = @as(c_int, 0x00000200); +pub const ARCHIVE_ENTRY_ACL_TYPE_ALLOW = @as(c_int, 0x00000400); +pub const ARCHIVE_ENTRY_ACL_TYPE_DENY = @as(c_int, 0x00000800); +pub const ARCHIVE_ENTRY_ACL_TYPE_AUDIT = @as(c_int, 0x00001000); +pub const ARCHIVE_ENTRY_ACL_TYPE_ALARM = @as(c_int, 0x00002000); +pub const ARCHIVE_ENTRY_ACL_TYPE_POSIX1E = ARCHIVE_ENTRY_ACL_TYPE_ACCESS | ARCHIVE_ENTRY_ACL_TYPE_DEFAULT; +pub const ARCHIVE_ENTRY_ACL_TYPE_NFS4 = ((ARCHIVE_ENTRY_ACL_TYPE_ALLOW | ARCHIVE_ENTRY_ACL_TYPE_DENY) | ARCHIVE_ENTRY_ACL_TYPE_AUDIT) | ARCHIVE_ENTRY_ACL_TYPE_ALARM; +pub const ARCHIVE_ENTRY_ACL_USER = @as(c_int, 10001); +pub const ARCHIVE_ENTRY_ACL_USER_OBJ = @as(c_int, 10002); +pub const ARCHIVE_ENTRY_ACL_GROUP = @as(c_int, 10003); +pub const ARCHIVE_ENTRY_ACL_GROUP_OBJ = @as(c_int, 10004); +pub const ARCHIVE_ENTRY_ACL_MASK = @as(c_int, 10005); +pub const ARCHIVE_ENTRY_ACL_OTHER = @as(c_int, 10006); +pub const ARCHIVE_ENTRY_ACL_EVERYONE = @as(c_int, 10107); +pub const ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID = @as(c_int, 0x00000001); +pub const ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT = @as(c_int, 0x00000002); +pub const ARCHIVE_ENTRY_ACL_STYLE_SOLARIS = @as(c_int, 0x00000004); +pub const ARCHIVE_ENTRY_ACL_STYLE_SEPARATOR_COMMA = @as(c_int, 0x00000008); +pub const ARCHIVE_ENTRY_ACL_STYLE_COMPACT = @as(c_int, 0x00000010); +pub const OLD_ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID = @as(c_int, 1024); +pub const OLD_ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT = @as(c_int, 2048); diff --git a/src/libarchive/libarchive.zig b/src/libarchive/libarchive.zig new file mode 100644 index 000000000..ef8a2acfa --- /dev/null +++ b/src/libarchive/libarchive.zig @@ -0,0 +1,634 @@ +// @link "../deps/libarchive.a" + +const lib = @import("./libarchive-bindings.zig"); +usingnamespace @import("../global.zig"); +const std = @import("std"); +const struct_archive = lib.struct_archive; +pub const Seek = enum(c_int) { + set = std.os.SEEK_SET, + current = std.os.SEEK_CUR, + end = std.os.SEEK_END, +}; + +pub const Flags = struct { + pub const Extract = enum(c_int) { + owner = lib.ARCHIVE_EXTRACT_OWNER, + perm = lib.ARCHIVE_EXTRACT_PERM, + time = lib.ARCHIVE_EXTRACT_TIME, + no_overwrite = lib.ARCHIVE_EXTRACT_NO_OVERWRITE, + unlink = lib.ARCHIVE_EXTRACT_UNLINK, + acl = lib.ARCHIVE_EXTRACT_ACL, + fflags = lib.ARCHIVE_EXTRACT_FFLAGS, + xattr = lib.ARCHIVE_EXTRACT_XATTR, + secure_symlinks = lib.ARCHIVE_EXTRACT_SECURE_SYMLINKS, + secure_nodotdot = lib.ARCHIVE_EXTRACT_SECURE_NODOTDOT, + no_autodir = lib.ARCHIVE_EXTRACT_NO_AUTODIR, + no_overwrite_newer = lib.ARCHIVE_EXTRACT_NO_OVERWRITE_NEWER, + sparse = lib.ARCHIVE_EXTRACT_SPARSE, + mac_metadata = lib.ARCHIVE_EXTRACT_MAC_METADATA, + no_hfs_compression = lib.ARCHIVE_EXTRACT_NO_HFS_COMPRESSION, + hfs_compression_forced = lib.ARCHIVE_EXTRACT_HFS_COMPRESSION_FORCED, + secure_noabsolutepaths = lib.ARCHIVE_EXTRACT_SECURE_NOABSOLUTEPATHS, + clear_nochange_fflags = lib.ARCHIVE_EXTRACT_CLEAR_NOCHANGE_FFLAGS, + safe_writes = lib.ARCHIVE_EXTRACT_SAFE_WRITES, + }; + + pub const Compression = enum(c_int) { + none = lib.ARCHIVE_COMPRESSION_NONE, + gzip = lib.ARCHIVE_COMPRESSION_GZIP, + bzip2 = lib.ARCHIVE_COMPRESSION_BZIP2, + compress = lib.ARCHIVE_COMPRESSION_COMPRESS, + program = lib.ARCHIVE_COMPRESSION_PROGRAM, + lzma = lib.ARCHIVE_COMPRESSION_LZMA, + xz = lib.ARCHIVE_COMPRESSION_XZ, + uu = lib.ARCHIVE_COMPRESSION_UU, + rpm = lib.ARCHIVE_COMPRESSION_RPM, + lzip = lib.ARCHIVE_COMPRESSION_LZIP, + lrzip = lib.ARCHIVE_COMPRESSION_LRZIP, + }; + + pub const Format = enum(c_int) { + base_mask = lib.ARCHIVE_FORMAT_BASE_MASK, + cpio = lib.ARCHIVE_FORMAT_CPIO, + cpio_posix = lib.ARCHIVE_FORMAT_CPIO_POSIX, + cpio_bin_le = lib.ARCHIVE_FORMAT_CPIO_BIN_LE, + cpio_bin_be = lib.ARCHIVE_FORMAT_CPIO_BIN_BE, + cpio_svr4_nocrc = lib.ARCHIVE_FORMAT_CPIO_SVR4_NOCRC, + cpio_svr4_crc = lib.ARCHIVE_FORMAT_CPIO_SVR4_CRC, + cpio_afio_large = lib.ARCHIVE_FORMAT_CPIO_AFIO_LARGE, + cpio_pwb = lib.ARCHIVE_FORMAT_CPIO_PWB, + shar = lib.ARCHIVE_FORMAT_SHAR, + shar_base = lib.ARCHIVE_FORMAT_SHAR_BASE, + shar_dump = lib.ARCHIVE_FORMAT_SHAR_DUMP, + tar = lib.ARCHIVE_FORMAT_TAR, + tar_ustar = lib.ARCHIVE_FORMAT_TAR_USTAR, + tar_pax_interchange = lib.ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE, + tar_pax_restricted = lib.ARCHIVE_FORMAT_TAR_PAX_RESTRICTED, + tar_gnutar = lib.ARCHIVE_FORMAT_TAR_GNUTAR, + iso9660 = lib.ARCHIVE_FORMAT_ISO9660, + iso9660_rockridge = lib.ARCHIVE_FORMAT_ISO9660_ROCKRIDGE, + zip = lib.ARCHIVE_FORMAT_ZIP, + empty = lib.ARCHIVE_FORMAT_EMPTY, + ar = lib.ARCHIVE_FORMAT_AR, + ar_gnu = lib.ARCHIVE_FORMAT_AR_GNU, + ar_bsd = lib.ARCHIVE_FORMAT_AR_BSD, + mtree = lib.ARCHIVE_FORMAT_MTREE, + raw = lib.ARCHIVE_FORMAT_RAW, + xar = lib.ARCHIVE_FORMAT_XAR, + lha = lib.ARCHIVE_FORMAT_LHA, + cab = lib.ARCHIVE_FORMAT_CAB, + rar = lib.ARCHIVE_FORMAT_RAR, + @"7zip" = lib.ARCHIVE_FORMAT_7ZIP, + warc = lib.ARCHIVE_FORMAT_WARC, + rar_v5 = lib.ARCHIVE_FORMAT_RAR_V5, + }; + + pub const Filter = enum(c_int) { + none = lib.ARCHIVE_FILTER_NONE, + gzip = lib.ARCHIVE_FILTER_GZIP, + bzip2 = lib.ARCHIVE_FILTER_BZIP2, + compress = lib.ARCHIVE_FILTER_COMPRESS, + program = lib.ARCHIVE_FILTER_PROGRAM, + lzma = lib.ARCHIVE_FILTER_LZMA, + xz = lib.ARCHIVE_FILTER_XZ, + uu = lib.ARCHIVE_FILTER_UU, + rpm = lib.ARCHIVE_FILTER_RPM, + lzip = lib.ARCHIVE_FILTER_LZIP, + lrzip = lib.ARCHIVE_FILTER_LRZIP, + lzop = lib.ARCHIVE_FILTER_LZOP, + grzip = lib.ARCHIVE_FILTER_GRZIP, + lz4 = lib.ARCHIVE_FILTER_LZ4, + zstd = lib.ARCHIVE_FILTER_ZSTD, + }; + + pub const EntryDigest = enum(c_int) { + md5 = lib.ARCHIVE_ENTRY_DIGEST_MD5, + rmd160 = lib.ARCHIVE_ENTRY_DIGEST_RMD160, + sha1 = lib.ARCHIVE_ENTRY_DIGEST_SHA1, + sha256 = lib.ARCHIVE_ENTRY_DIGEST_SHA256, + sha384 = lib.ARCHIVE_ENTRY_DIGEST_SHA384, + sha512 = lib.ARCHIVE_ENTRY_DIGEST_SHA512, + }; + + pub const EntryACL = enum(c_int) { + entry_acl_execute = lib.ARCHIVE_ENTRY_ACL_EXECUTE, + write = lib.ARCHIVE_ENTRY_ACL_WRITE, + read = lib.ARCHIVE_ENTRY_ACL_READ, + read_data = lib.ARCHIVE_ENTRY_ACL_READ_DATA, + list_directory = lib.ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, + write_data = lib.ARCHIVE_ENTRY_ACL_WRITE_DATA, + add_file = lib.ARCHIVE_ENTRY_ACL_ADD_FILE, + append_data = lib.ARCHIVE_ENTRY_ACL_APPEND_DATA, + add_subdirectory = lib.ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY, + read_named_attrs = lib.ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS, + write_named_attrs = lib.ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS, + delete_child = lib.ARCHIVE_ENTRY_ACL_DELETE_CHILD, + read_attributes = lib.ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, + write_attributes = lib.ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES, + delete = lib.ARCHIVE_ENTRY_ACL_DELETE, + read_acl = lib.ARCHIVE_ENTRY_ACL_READ_ACL, + write_acl = lib.ARCHIVE_ENTRY_ACL_WRITE_ACL, + write_owner = lib.ARCHIVE_ENTRY_ACL_WRITE_OWNER, + synchronize = lib.ARCHIVE_ENTRY_ACL_SYNCHRONIZE, + perms_posix1_e = lib.ARCHIVE_ENTRY_ACL_PERMS_POSIX1E, + perms_nfs4 = lib.ARCHIVE_ENTRY_ACL_PERMS_NFS4, + entry_inherited = lib.ARCHIVE_ENTRY_ACL_ENTRY_INHERITED, + entry_file_inherit = lib.ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, + entry_directory_inherit = lib.ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, + entry_no_propagate_inherit = lib.ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, + entry_inherit_only = lib.ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, + entry_successful_access = lib.ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS, + entry_failed_access = lib.ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS, + inheritance_nfs4 = lib.ARCHIVE_ENTRY_ACL_INHERITANCE_NFS4, + type_access = lib.ARCHIVE_ENTRY_ACL_TYPE_ACCESS, + type_default = lib.ARCHIVE_ENTRY_ACL_TYPE_DEFAULT, + type_allow = lib.ARCHIVE_ENTRY_ACL_TYPE_ALLOW, + type_deny = lib.ARCHIVE_ENTRY_ACL_TYPE_DENY, + type_audit = lib.ARCHIVE_ENTRY_ACL_TYPE_AUDIT, + type_alarm = lib.ARCHIVE_ENTRY_ACL_TYPE_ALARM, + type_posix1_e = lib.ARCHIVE_ENTRY_ACL_TYPE_POSIX1E, + type_nfs4 = lib.ARCHIVE_ENTRY_ACL_TYPE_NFS4, + user = lib.ARCHIVE_ENTRY_ACL_USER, + user_obj = lib.ARCHIVE_ENTRY_ACL_USER_OBJ, + group = lib.ARCHIVE_ENTRY_ACL_GROUP, + group_obj = lib.ARCHIVE_ENTRY_ACL_GROUP_OBJ, + mask = lib.ARCHIVE_ENTRY_ACL_MASK, + other = lib.ARCHIVE_ENTRY_ACL_OTHER, + everyone = lib.ARCHIVE_ENTRY_ACL_EVERYONE, + style_extra_id = lib.ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID, + style_mark_default = lib.ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT, + style_solaris = lib.ARCHIVE_ENTRY_ACL_STYLE_SOLARIS, + style_separator_comma = lib.ARCHIVE_ENTRY_ACL_STYLE_SEPARATOR_COMMA, + style_compact = lib.ARCHIVE_ENTRY_ACL_STYLE_COMPACT, + }; +}; + +pub const Status = enum(c_int) { + eof = lib.ARCHIVE_EOF, + ok = lib.ARCHIVE_OK, + retry = lib.ARCHIVE_RETRY, + warn = lib.ARCHIVE_WARN, + failed = lib.ARCHIVE_FAILED, + fatal = lib.ARCHIVE_FATAL, +}; + +pub fn NewStream(comptime SeekableStream: type) type { + return struct { + const Stream = @This(); + source: SeekableStream, + + pub inline fn fromCtx(ctx: *c_void) *Stream { + return @ptrCast(*Stream, @alignCast(@alignOf(*Stream), ctx)); + } + + pub fn archive_read_callback( + archive: *struct_archive, + ctx_: *c_void, + buffer: [*c]*const c_void, + ) callconv(.C) lib.la_ssize_t { + var this = fromCtx(ctx_); + } + + pub fn archive_skip_callback( + archive: *struct_archive, + ctx_: *c_void, + offset: lib.la_int64_, + ) callconv(.C) lib.la_int64_t { + var this = fromCtx(ctx_); + } + + pub fn archive_seek_callback( + archive: *struct_archive, + ctx_: *c_void, + offset: lib.la_int64_t, + whence: c_int, + ) callconv(.C) lib.la_int64_t { + var this = fromCtx(ctx_); + } + + pub fn archive_write_callback( + archive: *struct_archive, + ctx_: *c_void, + buffer: *const c_void, + len: usize, + ) callconv(.C) lib.la_ssize_t { + var this = fromCtx(ctx_); + } + pub fn archive_open_callback( + archive: *struct_archive, + ctx_: *c_void, + ) callconv(.C) c_int { + var this = fromCtx(ctx_); + } + + pub fn archive_close_callback( + archive: *struct_archive, + ctx_: *c_void, + ) callconv(.C) c_int { + var this = fromCtx(ctx_); + } + pub fn archive_free_callback( + archive: *struct_archive, + ctx_: *c_void, + ) callconv(.C) c_int { + var this = fromCtx(ctx_); + } + + pub fn archive_switch_callback( + archive: *struct_archive, + ctx1: *c_void, + ctx2: *c_void, + ) callconv(.C) c_int { + var this = fromCtx(ctx1); + var that = fromCtx(ctx2); + } + }; +} + +pub const BufferReadStream = struct { + const Stream = @This(); + buf: []const u8, + pos: usize = 0, + + block_size: usize = 16384, + + archive: *struct_archive, + reading: bool = false, + + pub fn init(this: *BufferReadStream, buf: []const u8) void { + this.* = BufferReadStream{ + .buf = buf, + .pos = 0, + .archive = lib.archive_read_new(), + .reading = false, + }; + } + + pub fn deinit(this: *BufferReadStream) void { + _ = lib.archive_read_close(this.archive); + _ = lib.archive_read_free(this.archive); + } + + pub fn openRead(this: *BufferReadStream) c_int { + // lib.archive_read_set_open_callback(this.archive, this.); + // _ = lib.archive_read_set_read_callback(this.archive, archive_read_callback); + // _ = lib.archive_read_set_seek_callback(this.archive, archive_seek_callback); + // _ = lib.archive_read_set_skip_callback(this.archive, archive_skip_callback); + // _ = lib.archive_read_set_close_callback(this.archive, archive_close_callback); + // // lib.archive_read_set_switch_callback(this.archive, this.archive_s); + // _ = lib.archive_read_set_callback_data(this.archive, this); + + this.reading = true; + + _ = lib.archive_read_support_format_tar(this.archive); + _ = lib.archive_read_support_format_gnutar(this.archive); + _ = lib.archive_read_support_filter_gzip(this.archive); + _ = lib.archive_read_support_filter_none(this.archive); + + const rc = lib.archive_read_open_memory(this.archive, this.buf.ptr, this.buf.len); + + // _ = lib.archive_read_support_compression_all(this.archive); + + return rc; + } + + pub inline fn bufLeft(this: BufferReadStream) []const u8 { + return this.buf[this.pos..]; + } + + pub inline fn fromCtx(ctx: *c_void) *Stream { + return @ptrCast(*Stream, @alignCast(@alignOf(*Stream), ctx)); + } + + pub fn archive_close_callback( + archive: *struct_archive, + ctx_: *c_void, + ) callconv(.C) c_int { + return 0; + } + + pub fn archive_read_callback( + archive: *struct_archive, + ctx_: *c_void, + buffer: [*c]*const c_void, + ) callconv(.C) lib.la_ssize_t { + var this = fromCtx(ctx_); + const remaining = this.bufLeft(); + if (remaining.len == 0) return 0; + + const diff = std.math.min(remaining.len, this.block_size); + buffer.* = remaining[0..diff].ptr; + this.pos += diff; + return @intCast(isize, diff); + } + + pub fn archive_skip_callback( + archive: *struct_archive, + ctx_: *c_void, + offset: lib.la_int64_t, + ) callconv(.C) lib.la_int64_t { + var this = fromCtx(ctx_); + + const buflen = @intCast(isize, this.buf.len); + const pos = @intCast(isize, this.pos); + + const proposed = pos + offset; + const new_pos = std.math.min(std.math.max(proposed, 0), buflen - 1); + this.pos = @intCast(usize, this.pos); + return new_pos - pos; + } + + pub fn archive_seek_callback( + archive: *struct_archive, + ctx_: *c_void, + offset: lib.la_int64_t, + whence: c_int, + ) callconv(.C) lib.la_int64_t { + var this = fromCtx(ctx_); + + const buflen = @intCast(isize, this.buf.len); + const pos = @intCast(isize, this.pos); + + switch (@intToEnum(Seek, whence)) { + Seek.current => { + const new_pos = std.math.max(std.math.min(pos + offset, buflen - 1), 0); + this.pos = @intCast(usize, new_pos); + return new_pos; + }, + Seek.end => { + const new_pos = std.math.max(std.math.min(buflen - offset, buflen), 0); + this.pos = @intCast(usize, new_pos); + return new_pos; + }, + Seek.set => { + const new_pos = std.math.max(std.math.min(offset, buflen - 1), 0); + this.pos = @intCast(usize, new_pos); + return new_pos; + }, + } + } + + // pub fn archive_write_callback( + // archive: *struct_archive, + // ctx_: *c_void, + // buffer: *const c_void, + // len: usize, + // ) callconv(.C) lib.la_ssize_t { + // var this = fromCtx(ctx_); + // } + + // pub fn archive_close_callback( + // archive: *struct_archive, + // ctx_: *c_void, + // ) callconv(.C) c_int { + // var this = fromCtx(ctx_); + // } + // pub fn archive_free_callback( + // archive: *struct_archive, + // ctx_: *c_void, + // ) callconv(.C) c_int { + // var this = fromCtx(ctx_); + // } + + // pub fn archive_switch_callback( + // archive: *struct_archive, + // ctx1: *c_void, + // ctx2: *c_void, + // ) callconv(.C) c_int { + // var this = fromCtx(ctx1); + // var that = fromCtx(ctx2); + // } +}; + +pub const Archive = struct { + // impl: *lib.archive = undefined, + // buf: []const u8 = undefined, + // dir: FileDescriptorType = 0, + + pub const Context = struct { + pluckers: []Plucker = &[_]Plucker{}, + overwrite_list: std.StringArrayHashMap(void), + all_files: EntryMap, + pub const EntryMap = std.ArrayHashMap(u64, [*c]u8, U64Context, false); + + pub const U64Context = struct { + pub fn hash(ctx: @This(), k: u64) u32 { + return @truncate(u32, k); + } + pub fn eql(ctx: @This(), a: u64, b: u64) bool { + return a == b; + } + }; + }; + + pub const Plucker = struct { + contents: MutableString, + filename_hash: u64 = 0, + found: bool = false, + fd: FileDescriptorType = 0, + pub fn init(filepath: string, estimated_size: usize, allocator: *std.mem.Allocator) !Plucker { + return Plucker{ + .contents = try MutableString.init(allocator, estimated_size), + .filename_hash = std.hash.Wyhash.hash(0, filepath), + .fd = 0, + .found = false, + }; + } + }; + + pub fn getOverwritingFileList( + file_buffer: []const u8, + root: []const u8, + ctx: *Archive.Context, + comptime FilePathAppender: type, + appender: FilePathAppender, + comptime depth_to_skip: usize, + ) !void { + var entry: *lib.archive_entry = undefined; + var ext: *lib.archive = undefined; + + const flags = @enumToInt(Flags.Extract.time) | @enumToInt(Flags.Extract.perm) | @enumToInt(Flags.Extract.acl) | @enumToInt(Flags.Extract.fflags); + var stream: BufferReadStream = undefined; + stream.init(file_buffer); + defer stream.deinit(); + _ = stream.openRead(); + var archive = stream.archive; + const dir: std.fs.Dir = brk: { + const cwd = std.fs.cwd(); + + // if the destination doesn't exist, we skip the whole thing since nothing can overwrite it. + if (std.fs.path.isAbsolute(root)) { + break :brk std.fs.openDirAbsolute(root, .{ .iterate = true }) catch return; + } else { + break :brk cwd.openDir(root, .{ .iterate = true }) catch return; + } + }; + + loop: while (true) { + const r = @intToEnum(Status, lib.archive_read_next_header(archive, &entry)); + + switch (r) { + Status.eof => break :loop, + Status.failed, Status.fatal, Status.retry => return error.Fail, + else => { + // do not use the utf8 name there + // it will require us to pull in libiconv + // though we should probably validate the utf8 here nonetheless + var pathname: [:0]const u8 = std.mem.sliceTo(lib.archive_entry_pathname(entry).?, 0); + var tokenizer = std.mem.tokenize(u8, std.mem.span(pathname), std.fs.path.sep_str); + comptime var depth_i: usize = 0; + inline while (depth_i < depth_to_skip) : (depth_i += 1) { + if (tokenizer.next() == null) continue :loop; + } + + var pathname_ = tokenizer.rest(); + pathname = std.mem.sliceTo(pathname_.ptr[0..pathname_.len :0], 0); + const dirname = std.mem.trim(u8, std.fs.path.dirname(std.mem.span(pathname)) orelse "", std.fs.path.sep_str); + + const size = @intCast(usize, std.math.max(lib.archive_entry_size(entry), 0)); + if (size > 0) { + var opened = dir.openFileZ(pathname, .{ .write = true }) catch continue :loop; + var stat = try opened.stat(); + + if (stat.size > 0) { + const is_already_top_level = dirname.len == 0; + const path_to_use_: string = brk: { + const __pathname: string = std.mem.span(pathname); + + if (is_already_top_level) break :brk __pathname; + + const index = std.mem.indexOfScalar(u8, __pathname, std.fs.path.sep).?; + break :brk __pathname[0..index]; + }; + var temp_buf: [1024]u8 = undefined; + std.mem.copy(u8, &temp_buf, path_to_use_); + var path_to_use: string = temp_buf[0..path_to_use_.len]; + if (!is_already_top_level) { + temp_buf[path_to_use_.len] = std.fs.path.sep; + path_to_use = temp_buf[0 .. path_to_use_.len + 1]; + } + + var overwrite_entry = try ctx.overwrite_list.getOrPut(path_to_use); + if (!overwrite_entry.found_existing) { + overwrite_entry.key_ptr.* = try appender.append(@TypeOf(path_to_use), path_to_use); + } + } + } + }, + } + } + } + + pub fn extractToDisk( + file_buffer: []const u8, + root: []const u8, + ctx: ?*Archive.Context, + comptime FilePathAppender: type, + appender: FilePathAppender, + comptime depth_to_skip: usize, + comptime close_handles: bool, + comptime log: bool, + ) !u32 { + var entry: *lib.archive_entry = undefined; + var ext: *lib.archive = undefined; + + const flags = @enumToInt(Flags.Extract.time) | @enumToInt(Flags.Extract.perm) | @enumToInt(Flags.Extract.acl) | @enumToInt(Flags.Extract.fflags); + var stream: BufferReadStream = undefined; + stream.init(file_buffer); + defer stream.deinit(); + _ = stream.openRead(); + var archive = stream.archive; + var count: u32 = 0; + + const dir: std.fs.Dir = brk: { + const cwd = std.fs.cwd(); + cwd.makePath( + root, + ) catch {}; + + if (std.fs.path.isAbsolute(root)) { + break :brk try std.fs.openDirAbsolute(root, .{ .iterate = true }); + } else { + break :brk try cwd.openDir(root, .{ .iterate = true }); + } + }; + + defer if (comptime close_handles) dir.close(); + + loop: while (true) { + const r = @intToEnum(Status, lib.archive_read_next_header(archive, &entry)); + + switch (r) { + Status.eof => break :loop, + Status.failed, Status.fatal, Status.retry => return error.Fail, + else => { + var pathname: [:0]const u8 = std.mem.sliceTo(lib.archive_entry_pathname(entry).?, 0); + var tokenizer = std.mem.tokenize(u8, std.mem.span(pathname), std.fs.path.sep_str); + comptime var depth_i: usize = 0; + + inline while (depth_i < depth_to_skip) : (depth_i += 1) { + if (tokenizer.next() == null) continue :loop; + } + + var pathname_ = tokenizer.rest(); + pathname = @intToPtr([*]const u8, @ptrToInt(pathname_.ptr))[0..pathname_.len :0]; + + const mask = lib.archive_entry_filetype(entry); + const size = @intCast(usize, std.math.max(lib.archive_entry_size(entry), 0)); + if (size > 0) { + const slice = std.mem.span(pathname); + + if (comptime log) { + Output.prettyln(" {s}", .{pathname}); + } + + const file = dir.createFileZ(pathname, .{ .truncate = true }) catch |err| brk: { + switch (err) { + error.FileNotFound => { + try dir.makePath(std.fs.path.dirname(slice) orelse return err); + break :brk try dir.createFileZ(pathname, .{ .truncate = true }); + }, + else => { + return err; + }, + } + }; + count += 1; + + _ = C.fchmod(file.handle, lib.archive_entry_perm(entry)); + + if (ctx) |ctx_| { + const hash: u64 = if (ctx_.pluckers.len > 0) + std.hash.Wyhash.hash(0, slice) + else + @as(u64, 0); + + if (comptime FilePathAppender != void) { + var result = ctx.?.all_files.getOrPutAdapted(hash, Context.U64Context{}) catch unreachable; + if (!result.found_existing) { + result.value_ptr.* = (try appender.appendMutable(@TypeOf(slice), slice)).ptr; + } + } + + for (ctx_.pluckers) |*plucker_| { + if (plucker_.filename_hash == hash) { + try plucker_.contents.inflate(size); + plucker_.contents.list.expandToCapacity(); + var read = lib.archive_read_data(archive, plucker_.contents.list.items.ptr, size); + try plucker_.contents.inflate(@intCast(usize, read)); + plucker_.found = read > 0; + plucker_.fd = file.handle; + continue :loop; + } + } + } + + _ = lib.archive_read_data_into_fd(archive, file.handle); + } + }, + } + } + + return count; + } +}; diff --git a/src/main.zig b/src/main.zig index 7b86f7360..1635f5ad1 100644 --- a/src/main.zig +++ b/src/main.zig @@ -37,7 +37,19 @@ pub fn main() anyerror!void { Output.Source.set(&output_source); defer Output.flush(); - try cli.Cli.start(default_allocator, stdout, stderr, MainPanicHandler); + cli.Cli.start(default_allocator, stdout, stderr, MainPanicHandler) catch |err| { + switch (err) { + error.CurrentWorkingDirectoryUnlinked => { + Output.prettyError( + "\n<r><red>error: <r>The current working directory was deleted, so that command didn't work. Please cd into a different directory and try again.", + .{}, + ); + Output.flush(); + std.os.exit(1); + }, + else => return err, + } + }; std.mem.doNotOptimizeAway(JavaScriptVirtualMachine.fetch); std.mem.doNotOptimizeAway(JavaScriptVirtualMachine.init); diff --git a/src/router.zig b/src/router.zig index 16e947248..38ddcc7a9 100644 --- a/src/router.zig +++ b/src/router.zig @@ -14,6 +14,7 @@ const Fs = @import("./fs.zig"); const Options = @import("./options.zig"); const allocators = @import("./allocators.zig"); const URLPath = @import("./http/url_path.zig"); +const PathnameScanner = @import("./query_string_map.zig").PathnameScanner; const index_route_hash = @truncate(u32, std.hash.Wyhash.hash(0, "index")); const arbitrary_max_route = 4096; @@ -598,6 +599,7 @@ pub const RouteMap = struct { .matched_route_buf = file_path_buf, }; + // iterate over the top-level routes if (ctx.matchDynamicRoute(0, 0)) |_dynamic_route| { // route name == the filesystem path relative to the pages dir excluding the file extension var dynamic_route = _dynamic_route; @@ -738,6 +740,10 @@ pub const Match = struct { redirect_path: ?string = null, query_string: string = "", + pub fn paramsIterator(this: *const Match) PathnameScanner { + return PathnameScanner.init(this.pathname, this.name, this.params); + } + pub fn nameWithBasename(file_path: string, dir: string) string { var name = file_path; if (strings.indexOf(name, dir)) |i| { @@ -751,3 +757,209 @@ pub const Match = struct { return std.mem.trimLeft(u8, this.pathname, "/"); } }; + +const FileSystem = Fs.FileSystem; + +const MockRequestContextType = struct { + controlled: bool = false, + url: URLPath, + match_file_path_buf: [1024]u8 = undefined, + + handle_request_called: bool = false, + redirect_called: bool = false, + matched_route: ?Match = null, + has_called_done: bool = false, + + pub fn handleRequest(this: *MockRequestContextType) !void { + this.handle_request_called = true; + } + + pub fn handleRedirect(this: *MockRequestContextType, pathname: string) !void { + this.redirect_called = true; + } + + pub const JavaScriptHandler = struct { + pub fn enqueue(ctx: *MockRequestContextType, server: *MockServer, filepath_buf: []u8, params: *Router.Param.List) !void {} + }; +}; + +pub const MockServer = struct { + watchloop_handle: ?StoredFileDescriptorType = null, + watcher: Watcher = Watcher{}, + + pub const Watcher = struct { + watchloop_handle: ?StoredFileDescriptorType = null, + pub fn start(this: *Watcher) anyerror!void {} + }; +}; + +fn makeTest(cwd_path: string, data: anytype) !void { + std.debug.assert(cwd_path.len > 1 and !strings.eql(cwd_path, "/") and !strings.endsWith(cwd_path, "bun")); + const bun_tests_dir = try std.fs.cwd().makeOpenPath("bun-test-scratch", .{ .iterate = true }); + bun_tests_dir.deleteTree(cwd_path) catch {}; + + const cwd = try bun_tests_dir.makeOpenPath(cwd_path, .{ .iterate = true }); + try cwd.setAsCwd(); + + const Data = @TypeOf(data); + const fields: []const std.builtin.TypeInfo.StructField = comptime std.meta.fields(Data); + inline for (fields) |field| { + const value = @field(data, field.name); + + if (std.fs.path.dirname(field.name)) |dir| { + try cwd.makePath(dir); + } + var file = try cwd.createFile(field.name, .{ .truncate = true }); + try file.writeAll(std.mem.span(value)); + file.close(); + } +} + +const expect = std.testing.expect; +const expectEqual = std.testing.expectEqual; +const expectEqualStrings = std.testing.expectEqualStrings; +const Logger = @import("./logger.zig"); + +pub const Test = struct { + pub fn make(comptime testName: string, data: anytype) !Router { + try makeTest(testName, data); + const JSAst = @import("./js_ast.zig"); + JSAst.Expr.Data.Store.create(default_allocator); + JSAst.Stmt.Data.Store.create(default_allocator); + var fs = try FileSystem.init1(default_allocator, null); + var top_level_dir = fs.top_level_dir; + + var pages_parts = [_]string{ top_level_dir, "pages" }; + var pages_dir = try Fs.FileSystem.instance.absAlloc(default_allocator, &pages_parts); + // _ = try std.fs.makeDirAbsolute( + // pages_dir, + // ); + var router = try Router.init(&FileSystem.instance, default_allocator, Options.RouteConfig{ + .dir = pages_dir, + .routes_enabled = true, + .extensions = &.{"js"}, + }); + Output.initTest(); + + const Resolver = @import("./resolver/resolver.zig").Resolver; + var logger = Logger.Log.init(default_allocator); + errdefer { + logger.printForLogLevel(Output.errorWriter()) catch {}; + } + + var opts = Options.BundleOptions{ + .resolve_mode = .lazy, + .platform = .browser, + .loaders = undefined, + .define = undefined, + .log = &logger, + .entry_points = &.{}, + .out_extensions = std.StringHashMap(string).init(default_allocator), + .transform_options = std.mem.zeroes(Api.TransformOptions), + .external = Options.ExternalModules.init( + default_allocator, + &FileSystem.instance.fs, + FileSystem.instance.top_level_dir, + &.{}, + &logger, + .browser, + ), + }; + + var resolver = Resolver.init1(default_allocator, &logger, &FileSystem.instance, opts); + + var root_dir = (try resolver.readDirInfo(pages_dir)).?; + var entries = root_dir.getEntries().?; + try router.loadRoutes(root_dir, Resolver, &resolver, 0, true); + var entry_points = try router.getEntryPoints(default_allocator); + + try expectEqual(std.meta.fieldNames(@TypeOf(data)).len, entry_points.len); + return router; + } +}; + +test "Routes basic" { + var server = MockServer{}; + var ctx = MockRequestContextType{ + .url = try URLPath.parse("/hi"), + }; + var router = try Test.make("routes-basic", .{ + .@"pages/hi.js" = "//hi", + .@"pages/index.js" = "//index", + .@"pages/blog/hi.js" = "//blog/hi", + }); + try router.match(&server, MockRequestContextType, &ctx); + try expectEqualStrings(ctx.matched_route.?.name, "/hi"); + + ctx = MockRequestContextType{ + .url = try URLPath.parse("/"), + }; + + try router.match(&server, MockRequestContextType, &ctx); + try expectEqualStrings(ctx.matched_route.?.name, "/index"); + + ctx = MockRequestContextType{ + .url = try URLPath.parse("/blog/hi"), + }; + + try router.match(&server, MockRequestContextType, &ctx); + try expectEqualStrings(ctx.matched_route.?.name, "/blog/hi"); + + ctx = MockRequestContextType{ + .url = try URLPath.parse("/blog/hey"), + }; + + try router.match(&server, MockRequestContextType, &ctx); + try expect(ctx.matched_route == null); + + ctx = MockRequestContextType{ + .url = try URLPath.parse("/blog/"), + }; + + try router.match(&server, MockRequestContextType, &ctx); + try expect(ctx.matched_route == null); + + ctx = MockRequestContextType{ + .url = try URLPath.parse("/pages/hi"), + }; + + try router.match(&server, MockRequestContextType, &ctx); + try expect(ctx.matched_route == null); +} + +test "Dynamic routes" { + var server = MockServer{}; + var ctx = MockRequestContextType{ + .url = try URLPath.parse("/blog/hi"), + }; + var filepath_buf: [std.fs.MAX_PATH_BYTES]u8 = undefined; + var router = try Test.make("routes-dynamic", .{ + .@"pages/index.js" = "//index.js", + .@"pages/blog/hi.js" = "//blog-hi", + .@"pages/posts/[id].js" = "//hi", + // .@"pages/blog/posts/bacon.js" = "//index", + }); + + try router.match(&server, MockRequestContextType, &ctx); + try expectEqualStrings(ctx.matched_route.?.name, "/blog/hi"); + + var params = ctx.matched_route.?.paramsIterator(); + try expect(params.next() == null); + + ctx.matched_route = null; + + ctx.url = try URLPath.parse("/posts/123"); + try router.match(&server, MockRequestContextType, &ctx); + + params = ctx.matched_route.?.paramsIterator(); + + try expectEqualStrings(ctx.matched_route.?.name, "/posts/[id]"); + try expectEqualStrings(params.next().?.rawValue(ctx.matched_route.?.pathname), "123"); + + // ctx = MockRequestContextType{ + // .url = try URLPath.parse("/"), + // }; + + // try router.match(&server, MockRequestContextType, &ctx); + // try expectEqualStrings(ctx.matched_route.name, "index"); +} diff --git a/src/runtime.version b/src/runtime.version index 57659652b..8456f0e52 100644 --- a/src/runtime.version +++ b/src/runtime.version @@ -1 +1 @@ -35057197d4ad54bc
\ No newline at end of file +4865dbe641dca1de
\ No newline at end of file diff --git a/src/runtime/hmr.ts b/src/runtime/hmr.ts index 4a8ccca43..77873a34c 100644 --- a/src/runtime/hmr.ts +++ b/src/runtime/hmr.ts @@ -189,9 +189,11 @@ if (typeof window !== "undefined") { let count = 0; let match: CSSHMRInsertionPoint = null; + const adoptedStyles = document.adoptedStyleSheets; + if (this.updateMethod === CSSUpdateMethod.cssObjectModel) { - if (document.adoptedStyleSheets.length > 0) { - count = document.adoptedStyleSheets.length; + if (adoptedStyles.length > 0) { + count = adoptedStyles.length; for (let i = 0; i < count && match === null; i++) { let cssRules: CSSRuleList; @@ -200,7 +202,7 @@ if (typeof window !== "undefined") { // Non-same origin stylesheets will potentially throw "Security error" // We will ignore those stylesheets and look at others. try { - sheet = document.adoptedStyleSheets[i]; + sheet = adoptedStyles[i]; cssRules = sheet.rules; ruleCount = sheet.rules.length; } catch (exception) { diff --git a/src/s2n.zig b/src/s2n.zig new file mode 100644 index 000000000..1ac8436af --- /dev/null +++ b/src/s2n.zig @@ -0,0 +1,792 @@ +pub usingnamespace @import("std").zig.c_builtins; +const std = @import("std"); + +const Output = @import("./global.zig").Output; + +const alpn_protocols = "http/1.1"; + +pub inline fn s2nassert(value: c_int) void { + std.debug.assert(value == 0); +} + +pub fn boot(allcoator: *std.mem.Allocator) void { + if (booted) return; + booted = true; + Allocator.allocator = allcoator; + CacheStore.instance = CacheStore{ .allocator = allcoator, .map = @TypeOf(CacheStore.instance.map).init(allcoator) }; + + // Important for any website using Cloudflare. + // Do to our modifications in the library, this must be called _first_ + // Before we initialize s2n. + // It can never be changed after initialization or we risk undefined memory bugs. + if (s2n_get_highest_fully_supported_tls_version() == S2N_TLS13) { + // This conditional should always return true since we statically compile libCrypto. + // _ = s2n_enable_tls13(); + + // Sadly, this TLS 1.3 implementation is slower than TLS 1.2. + // ❯ hyperfine "./fetch https://example.com" "./fetchtls13 https://example.com" + // Benchmark #1: ./fetch https://example.com + // Time (mean ± σ): 83.6 ms ± 5.4 ms [User: 15.1 ms, System: 4.7 ms] + // Range (min … max): 73.5 ms … 97.5 ms 35 runs + + // Benchmark #2: ./fetchtls13 https://example.com + // Time (mean ± σ): 94.9 ms ± 3.2 ms [User: 15.8 ms, System: 4.8 ms] + // Range (min … max): 90.7 ms … 104.6 ms 29 runs + + // Summary + // './fetch https://example.com' ran + // 1.14 ± 0.08 times faster than './fetchtls13 https://example.com' + + } + + // We don't actually need the memory allocator, it will automatically use mimalloc...I don't know how! + // Also, the implementation + // s2nassert(s2n_mem_set_callbacks(Allocator.initCallback, Allocator.deinitCallback, Allocator.mallocCallback, Allocator.freeCallback)); + + s2nassert(s2n_disable_atexit()); + s2nassert(s2n_init()); + global_s2n_config = s2n_fetch_default_config(); + // s2nassert(s2n_config_set_verify_host_callback(global_s2n_config, verify_host_callback, null)); + // s2nassert(s2n_config_set_check_stapled_ocsp_response(global_s2n_config, 0)); + // s2nassert(s2n_config_set_cipher_preferences(global_s2n_config, "default")); + // s2nassert(s2n_config_disable_x509_verification(global_s2n_config)); + var protocol: [*c]const u8 = "http/1.1"; + var protocols = &protocol; + s2nassert(s2n_config_set_protocol_preferences(global_s2n_config, protocols, 1)); + s2nassert(s2n_config_send_max_fragment_length(global_s2n_config, S2N_TLS_MAX_FRAG_LEN_4096)); + s2nassert(s2n_config_set_cipher_preferences(global_s2n_config, "default_tls13")); + // s2n_config_set_ticket_decrypt_key_lifetime(global_s2n_config, 9999999); + + s2nassert( + s2n_config_set_cache_store_callback(global_s2n_config, CacheStore.store, &CacheStore.instance), + ); + s2nassert( + s2n_config_set_cache_retrieve_callback(global_s2n_config, CacheStore.retrieve, &CacheStore.instance), + ); + s2nassert( + s2n_config_set_cache_delete_callback(global_s2n_config, CacheStore.delete, &CacheStore.instance), + ); + s2nassert( + s2n_config_set_session_cache_onoff(global_s2n_config, 1), + ); + + // s2nassert(s2n_config_init_session_ticket_keys()); + // s2nassert(s2n_config_set_client_auth_type(global_s2n_config, S2N_STATUS_REQUEST_NONE)); +} + +pub const CacheStore = struct { + const CacheEntry = struct { + key: []u8, + value: []u8, + seconds: u64, + + pub fn init( + allocator: *std.mem.Allocator, + key: *const c_void, + size: u64, + value: *const c_void, + value_size: u64, + seconds: u64, + ) CacheEntry { + const key_bytes = keyBytes(key, size); + const value_bytes = keyBytes(key, value_size); + + var total_bytes = allocator.alloc(u8, key_bytes.len + value_bytes.len) catch unreachable; + @memcpy(total_bytes.ptr, key_bytes.ptr, key_bytes.len); + @memcpy(total_bytes[key_bytes.len..].ptr, value_bytes.ptr, value_bytes.len); + + return CacheEntry{ .key = total_bytes[0..key_bytes.len], .value = total_bytes[key_bytes.len..], .seconds = seconds }; + } + }; + + const Context = struct { + pub fn hash(this: @This(), key: u64) u64 { + return key; + } + + pub fn eql(this: @This(), a: u64, b: u64) bool { + return a == b; + } + }; + + allocator: *std.mem.Allocator, + map: std.HashMap(u64, CacheEntry, Context, 80), + + pub inline fn keyBytes(key: *const c_void, size: u64) []u8 { + const ptr = @intToPtr([*]u8, @ptrToInt(key)); + + return ptr[0..size]; + } + + inline fn hashKey(key: *const c_void, size: u64) u64 { + const bytes = keyBytes(key, size); + return std.hash.Wyhash.hash(0, bytes); + } + + pub fn retrieve( + conn: *s2n_connection, + ctx: ?*c_void, + key: *const c_void, + key_size: u64, + value: *c_void, + value_size: *u64, + ) callconv(.C) c_int { + const hash = hashKey(key, key_size); + + if (instance.map.getAdapted(hash, Context{})) |entry| { + const now = @intCast(usize, std.time.timestamp()); + if (now > entry.seconds) { + _ = instance.map.removeAdapted(hash, Context{}); + return 0; + } + + var value_bytes = keyBytes(value, value_size.*); + if (value_bytes.len < entry.value.len) return -1; + std.mem.copy(u8, value_bytes, entry.value); + value_size.* = entry.value.len; + return 0; + } + + return 0; + } + + pub fn store( + conn: *s2n_connection, + ctx: ?*c_void, + seconds: u64, + key: *const c_void, + key_size: u64, + value: *const c_void, + value_size: u64, + ) callconv(.C) c_int { + var map_entry = instance.map.getOrPutAdapted(hashKey(key, key_size), Context{}) catch unreachable; + + if (!map_entry.found_existing) { + map_entry.value_ptr.* = CacheEntry.init(instance.allocator, key, key_size, value, value_size, @intCast(usize, std.time.timestamp()) + seconds); + } + + return S2N_SUCCESS; + } + + pub fn delete( + conn: *s2n_connection, + ctx: ?*c_void, + key: *const c_void, + key_size: u64, + ) callconv(.C) c_int { + _ = instance.map.remove(hashKey(key, key_size)); + return 0; + } + + pub var instance: CacheStore = undefined; +}; + +pub fn verify_host_callback(ptr: [*c]const u8, len: usize, ctx: ?*c_void) callconv(.C) u8 { + return 1; +} + +pub extern fn s2n_enable_tls13() c_int; +pub extern fn s2n_fetch_default_config() *s2n_config; +pub extern fn s2n_get_highest_fully_supported_tls_version() c_int; +pub extern fn s2n_errno_location() [*c]c_int; +pub const S2N_ERR_T_OK: c_int = 0; +pub const S2N_ERR_T_IO: c_int = 1; +pub const S2N_ERR_T_CLOSED: c_int = 2; +pub const S2N_ERR_T_BLOCKED: c_int = 3; +pub const S2N_ERR_T_ALERT: c_int = 4; +pub const S2N_ERR_T_PROTO: c_int = 5; +pub const S2N_ERR_T_INTERNAL: c_int = 6; +pub const S2N_ERR_T_USAGE: c_int = 7; +pub const s2n_error_type = c_uint; +pub extern fn s2n_error_get_type(@"error": c_int) c_int; +pub const struct_s2n_config = opaque {}; +pub const struct_s2n_connection = opaque {}; +pub extern fn s2n_crypto_disable_init() c_int; +pub extern fn s2n_disable_atexit() c_int; +pub extern fn s2n_get_openssl_version() c_ulong; +pub extern fn s2n_init() c_int; +pub extern fn s2n_cleanup() c_int; +pub extern fn s2n_config_new() *struct_s2n_config; +pub extern fn s2n_config_free(config: *struct_s2n_config) c_int; +pub extern fn s2n_config_free_dhparams(config: *struct_s2n_config) c_int; +pub extern fn s2n_config_free_cert_chain_and_key(config: *struct_s2n_config) c_int; +pub const s2n_clock_time_nanoseconds = ?fn (?*c_void, [*c]u64) callconv(.C) c_int; +pub const s2n_cache_retrieve_callback = ?fn (*struct_s2n_connection, ?*c_void, *const c_void, u64, *c_void, *u64) callconv(.C) c_int; +pub const s2n_cache_store_callback = ?fn (*struct_s2n_connection, ?*c_void, u64, *const c_void, u64, *const c_void, u64) callconv(.C) c_int; +pub const s2n_cache_delete_callback = ?fn (*struct_s2n_connection, ?*c_void, *const c_void, u64) callconv(.C) c_int; +pub extern fn s2n_config_set_wall_clock(config: *struct_s2n_config, clock_fn: s2n_clock_time_nanoseconds, ctx: ?*c_void) c_int; +pub extern fn s2n_config_set_monotonic_clock(config: *struct_s2n_config, clock_fn: s2n_clock_time_nanoseconds, ctx: ?*c_void) c_int; +pub extern fn s2n_strerror(@"error": c_int, lang: [*c]const u8) [*c]const u8; +pub extern fn s2n_strerror_debug(@"error": c_int, lang: [*c]const u8) [*c]const u8; +pub extern fn s2n_strerror_name(@"error": c_int) [*c]const u8; +pub const struct_s2n_stacktrace = opaque {}; +pub extern fn s2n_stack_traces_enabled() bool; +pub extern fn s2n_stack_traces_enabled_set(newval: bool) c_int; +pub extern fn s2n_calculate_stacktrace() c_int; +// pub extern fn s2n_print_stacktrace(fptr: [*c]FILE) c_int; +pub extern fn s2n_free_stacktrace() c_int; +pub extern fn s2n_get_stacktrace(trace: *struct_s2n_stacktrace) c_int; +pub extern fn s2n_config_set_cache_store_callback(config: *struct_s2n_config, cache_store_callback: s2n_cache_store_callback, data: ?*c_void) c_int; +pub extern fn s2n_config_set_cache_retrieve_callback(config: *struct_s2n_config, cache_retrieve_callback: s2n_cache_retrieve_callback, data: ?*c_void) c_int; +pub extern fn s2n_config_set_cache_delete_callback(config: *struct_s2n_config, cache_delete_callback: s2n_cache_delete_callback, data: ?*c_void) c_int; +pub const s2n_mem_init_callback = ?fn () callconv(.C) c_int; +pub const s2n_mem_cleanup_callback = ?fn () callconv(.C) c_int; +pub const s2n_mem_malloc_callback = ?fn (**c_void, u32, *u32) callconv(.C) c_int; +pub const s2n_mem_free_callback = ?fn (?*c_void, u32) callconv(.C) c_int; +pub extern fn s2n_mem_set_callbacks(mem_init_callback: s2n_mem_init_callback, mem_cleanup_callback: s2n_mem_cleanup_callback, mem_malloc_callback: s2n_mem_malloc_callback, mem_free_callback: s2n_mem_free_callback) c_int; +pub const s2n_rand_init_callback = ?fn () callconv(.C) c_int; +pub const s2n_rand_cleanup_callback = ?fn () callconv(.C) c_int; +pub const s2n_rand_seed_callback = ?fn (?*c_void, u32) callconv(.C) c_int; +pub const s2n_rand_mix_callback = ?fn (?*c_void, u32) callconv(.C) c_int; +pub extern fn s2n_rand_set_callbacks(rand_init_callback: s2n_rand_init_callback, rand_cleanup_callback: s2n_rand_cleanup_callback, rand_seed_callback: s2n_rand_seed_callback, rand_mix_callback: s2n_rand_mix_callback) c_int; +pub const S2N_EXTENSION_SERVER_NAME: c_int = 0; +pub const S2N_EXTENSION_MAX_FRAG_LEN: c_int = 1; +pub const S2N_EXTENSION_OCSP_STAPLING: c_int = 5; +pub const S2N_EXTENSION_SUPPORTED_GROUPS: c_int = 10; +pub const S2N_EXTENSION_EC_POINT_FORMATS: c_int = 11; +pub const S2N_EXTENSION_SIGNATURE_ALGORITHMS: c_int = 13; +pub const S2N_EXTENSION_ALPN: c_int = 16; +pub const S2N_EXTENSION_CERTIFICATE_TRANSPARENCY: c_int = 18; +pub const S2N_EXTENSION_RENEGOTIATION_INFO: c_int = 65281; +pub const s2n_tls_extension_type = c_uint; +pub const S2N_TLS_MAX_FRAG_LEN_512: c_int = 1; +pub const S2N_TLS_MAX_FRAG_LEN_1024: c_int = 2; +pub const S2N_TLS_MAX_FRAG_LEN_2048: c_int = 3; +pub const S2N_TLS_MAX_FRAG_LEN_4096: c_int = 4; +pub const s2n_max_frag_len = c_uint; +pub const struct_s2n_cert = opaque {}; +pub const struct_s2n_cert_chain_and_key = opaque {}; +pub const struct_s2n_pkey = opaque {}; +pub const s2n_cert_public_key = struct_s2n_pkey; +pub const s2n_cert_private_key = struct_s2n_pkey; +pub extern fn s2n_cert_chain_and_key_new() *struct_s2n_cert_chain_and_key; +pub extern fn s2n_cert_chain_and_key_load_pem(chain_and_key: *struct_s2n_cert_chain_and_key, chain_pem: [*c]const u8, private_key_pem: [*c]const u8) c_int; +pub extern fn s2n_cert_chain_and_key_load_pem_bytes(chain_and_key: *struct_s2n_cert_chain_and_key, chain_pem: [*c]u8, chain_pem_len: u32, private_key_pem: [*c]u8, private_key_pem_len: u32) c_int; +pub extern fn s2n_cert_chain_and_key_load_public_pem_bytes(chain_and_key: *struct_s2n_cert_chain_and_key, chain_pem: [*c]u8, chain_pem_len: u32) c_int; +pub extern fn s2n_cert_chain_and_key_free(cert_and_key: *struct_s2n_cert_chain_and_key) c_int; +pub extern fn s2n_cert_chain_and_key_set_ctx(cert_and_key: *struct_s2n_cert_chain_and_key, ctx: ?*c_void) c_int; +pub extern fn s2n_cert_chain_and_key_get_ctx(cert_and_key: *struct_s2n_cert_chain_and_key) ?*c_void; +pub extern fn s2n_cert_chain_and_key_get_private_key(cert_and_key: *struct_s2n_cert_chain_and_key) ?*s2n_cert_private_key; +pub const s2n_cert_tiebreak_callback = ?fn (*struct_s2n_cert_chain_and_key, *struct_s2n_cert_chain_and_key, [*c]u8, u32) callconv(.C) *struct_s2n_cert_chain_and_key; +pub extern fn s2n_config_set_cert_tiebreak_callback(config: *struct_s2n_config, cert_tiebreak_cb: s2n_cert_tiebreak_callback) c_int; +pub extern fn s2n_config_add_cert_chain_and_key(config: *struct_s2n_config, cert_chain_pem: [*c]const u8, private_key_pem: [*c]const u8) c_int; +pub extern fn s2n_config_add_cert_chain_and_key_to_store(config: *struct_s2n_config, cert_key_pair: *struct_s2n_cert_chain_and_key) c_int; +pub extern fn s2n_config_set_cert_chain_and_key_defaults(config: *struct_s2n_config, cert_key_pairs: [*c]*struct_s2n_cert_chain_and_key, num_cert_key_pairs: u32) c_int; +pub extern fn s2n_config_set_verification_ca_location(config: *struct_s2n_config, ca_pem_filename: [*c]const u8, ca_dir: [*c]const u8) c_int; +pub extern fn s2n_config_add_pem_to_trust_store(config: *struct_s2n_config, pem: [*c]const u8) c_int; +pub extern fn s2n_config_wipe_trust_store(config: *struct_s2n_config) c_int; +pub const s2n_verify_host_fn = ?fn ([*c]const u8, usize, ?*c_void) callconv(.C) u8; +pub extern fn s2n_config_set_verify_host_callback(config: *struct_s2n_config, s2n_verify_host_fn, data: ?*c_void) c_int; +pub extern fn s2n_config_set_check_stapled_ocsp_response(config: *struct_s2n_config, check_ocsp: u8) c_int; +pub extern fn s2n_config_disable_x509_verification(config: *struct_s2n_config) c_int; +pub extern fn s2n_config_set_max_cert_chain_depth(config: *struct_s2n_config, max_depth: u16) c_int; +pub extern fn s2n_config_add_dhparams(config: *struct_s2n_config, dhparams_pem: [*c]const u8) c_int; +pub extern fn s2n_config_set_cipher_preferences(config: *struct_s2n_config, version: [*c]const u8) c_int; +pub extern fn s2n_config_append_protocol_preference(config: *struct_s2n_config, protocol: [*c]const u8, protocol_len: u8) c_int; +pub extern fn s2n_config_set_protocol_preferences(config: *struct_s2n_config, protocols: [*c]const [*c]const u8, protocol_count: c_int) c_int; +pub const S2N_STATUS_REQUEST_NONE: c_int = 0; +pub const S2N_STATUS_REQUEST_OCSP: c_int = 1; +pub const s2n_status_request_type = c_uint; +pub extern fn s2n_config_set_status_request_type(config: *struct_s2n_config, @"type": s2n_status_request_type) c_int; +pub const S2N_CT_SUPPORT_NONE: c_int = 0; +pub const S2N_CT_SUPPORT_REQUEST: c_int = 1; +pub const s2n_ct_support_level = c_uint; +pub extern fn s2n_config_set_ct_support_level(config: *struct_s2n_config, level: s2n_ct_support_level) c_int; +pub const S2N_ALERT_FAIL_ON_WARNINGS: c_int = 0; +pub const S2N_ALERT_IGNORE_WARNINGS: c_int = 1; +pub const s2n_alert_behavior = c_uint; +pub extern fn s2n_config_set_alert_behavior(config: *struct_s2n_config, alert_behavior: s2n_alert_behavior) c_int; +pub extern fn s2n_config_set_extension_data(config: *struct_s2n_config, @"type": s2n_tls_extension_type, data: [*c]const u8, length: u32) c_int; +pub extern fn s2n_config_send_max_fragment_length(config: *struct_s2n_config, mfl_code: s2n_max_frag_len) c_int; +pub extern fn s2n_config_accept_max_fragment_length(config: *struct_s2n_config) c_int; +pub extern fn s2n_config_set_session_state_lifetime(config: *struct_s2n_config, lifetime_in_secs: u64) c_int; +pub extern fn s2n_config_set_session_tickets_onoff(config: *struct_s2n_config, enabled: u8) c_int; +pub extern fn s2n_config_set_session_cache_onoff(config: *struct_s2n_config, enabled: u8) c_int; +pub extern fn s2n_config_set_ticket_encrypt_decrypt_key_lifetime(config: *struct_s2n_config, lifetime_in_secs: u64) c_int; +pub extern fn s2n_config_set_ticket_decrypt_key_lifetime(config: *struct_s2n_config, lifetime_in_secs: u64) c_int; +pub extern fn s2n_config_add_ticket_crypto_key(config: *struct_s2n_config, name: [*c]const u8, name_len: u32, key: [*c]u8, key_len: u32, intro_time_in_seconds_from_epoch: u64) c_int; +pub const S2N_SERVER: c_int = 0; +pub const S2N_CLIENT: c_int = 1; +pub const s2n_mode = c_uint; +pub extern fn s2n_connection_new(mode: s2n_mode) *struct_s2n_connection; +pub extern fn s2n_connection_set_config(conn: *struct_s2n_connection, config: *struct_s2n_config) c_int; +pub extern fn s2n_connection_set_ctx(conn: *struct_s2n_connection, ctx: ?*c_void) c_int; +pub extern fn s2n_connection_get_ctx(conn: *struct_s2n_connection) ?*c_void; +pub const s2n_client_hello_fn = fn (*struct_s2n_connection, ?*c_void) callconv(.C) c_int; +pub const S2N_CLIENT_HELLO_CB_BLOCKING: c_int = 0; +pub const S2N_CLIENT_HELLO_CB_NONBLOCKING: c_int = 1; +pub const s2n_client_hello_cb_mode = c_uint; +pub extern fn s2n_config_set_client_hello_cb(config: *struct_s2n_config, client_hello_callback: ?s2n_client_hello_fn, ctx: ?*c_void) c_int; +pub extern fn s2n_config_set_client_hello_cb_mode(config: *struct_s2n_config, cb_mode: s2n_client_hello_cb_mode) c_int; +pub extern fn s2n_client_hello_cb_done(conn: *struct_s2n_connection) c_int; +pub extern fn s2n_connection_server_name_extension_used(conn: *struct_s2n_connection) c_int; +pub const struct_s2n_client_hello = opaque {}; +pub extern fn s2n_connection_get_client_hello(conn: *struct_s2n_connection) *struct_s2n_client_hello; +pub extern fn s2n_client_hello_get_raw_message_length(ch: *struct_s2n_client_hello) isize; +pub extern fn s2n_client_hello_get_raw_message(ch: *struct_s2n_client_hello, out: [*c]u8, max_length: u32) isize; +pub extern fn s2n_client_hello_get_cipher_suites_length(ch: *struct_s2n_client_hello) isize; +pub extern fn s2n_client_hello_get_cipher_suites(ch: *struct_s2n_client_hello, out: [*c]u8, max_length: u32) isize; +pub extern fn s2n_client_hello_get_extensions_length(ch: *struct_s2n_client_hello) isize; +pub extern fn s2n_client_hello_get_extensions(ch: *struct_s2n_client_hello, out: [*c]u8, max_length: u32) isize; +pub extern fn s2n_client_hello_get_extension_length(ch: *struct_s2n_client_hello, extension_type: s2n_tls_extension_type) isize; +pub extern fn s2n_client_hello_get_extension_by_id(ch: *struct_s2n_client_hello, extension_type: s2n_tls_extension_type, out: [*c]u8, max_length: u32) isize; +pub extern fn s2n_client_hello_get_session_id_length(ch: *struct_s2n_client_hello, out_length: [*c]u32) c_int; +pub extern fn s2n_client_hello_get_session_id(ch: *struct_s2n_client_hello, out: [*c]u8, out_length: [*c]u32, max_length: u32) c_int; +pub extern fn s2n_connection_set_fd(conn: *struct_s2n_connection, fd: c_int) c_int; +pub extern fn s2n_connection_set_read_fd(conn: *struct_s2n_connection, readfd: c_int) c_int; +pub extern fn s2n_connection_set_write_fd(conn: *struct_s2n_connection, writefd: c_int) c_int; +pub extern fn s2n_connection_get_read_fd(conn: *struct_s2n_connection, readfd: [*c]c_int) c_int; +pub extern fn s2n_connection_get_write_fd(conn: *struct_s2n_connection, writefd: [*c]c_int) c_int; +pub extern fn s2n_connection_use_corked_io(conn: *struct_s2n_connection) c_int; +pub const s2n_recv_fn = fn (*s2n_connection, [*c]u8, u32) callconv(.C) c_int; +pub const s2n_send_fn = fn (*s2n_connection, [*c]const u8, u32) callconv(.C) c_int; +pub extern fn s2n_connection_set_recv_ctx(conn: *struct_s2n_connection, ctx: ?*c_void) c_int; +pub extern fn s2n_connection_set_send_ctx(conn: *struct_s2n_connection, ctx: ?*c_void) c_int; +pub extern fn s2n_connection_set_recv_cb(conn: *struct_s2n_connection, recv: ?s2n_recv_fn) c_int; +pub extern fn s2n_connection_set_send_cb(conn: *struct_s2n_connection, send: ?s2n_send_fn) c_int; +pub extern fn s2n_connection_prefer_throughput(conn: *struct_s2n_connection) c_int; +pub extern fn s2n_connection_prefer_low_latency(conn: *struct_s2n_connection) c_int; +pub extern fn s2n_connection_set_dynamic_record_threshold(conn: *struct_s2n_connection, resize_threshold: u32, timeout_threshold: u16) c_int; +pub extern fn s2n_connection_set_verify_host_callback(config: *struct_s2n_connection, host_fn: s2n_verify_host_fn, data: ?*c_void) c_int; +pub const S2N_BUILT_IN_BLINDING: c_int = 0; +pub const S2N_SELF_SERVICE_BLINDING: c_int = 1; +pub const s2n_blinding = c_uint; +pub extern fn s2n_connection_set_blinding(conn: *struct_s2n_connection, blinding: s2n_blinding) c_int; +pub extern fn s2n_connection_get_delay(conn: *struct_s2n_connection) u64; +pub extern fn s2n_connection_set_cipher_preferences(conn: *struct_s2n_connection, version: [*c]const u8) c_int; +pub extern fn s2n_connection_append_protocol_preference(conn: *struct_s2n_connection, protocol: [*c]const u8, protocol_len: u8) c_int; +pub extern fn s2n_connection_set_protocol_preferences(conn: *struct_s2n_connection, protocols: [*c]const [*c]const u8, protocol_count: c_int) c_int; +pub extern fn s2n_set_server_name(conn: *struct_s2n_connection, server_name: [*c]const u8) c_int; +pub extern fn s2n_get_server_name(conn: *struct_s2n_connection) [*c]const u8; +pub extern fn s2n_get_application_protocol(conn: *struct_s2n_connection) [*c]const u8; +pub extern fn s2n_connection_get_ocsp_response(conn: *struct_s2n_connection, length: [*c]u32) [*c]const u8; +pub extern fn s2n_connection_get_sct_list(conn: *struct_s2n_connection, length: [*c]u32) [*c]const u8; +pub const S2N_NOT_BLOCKED: c_int = 0; +pub const S2N_BLOCKED_ON_READ: c_int = 1; +pub const S2N_BLOCKED_ON_WRITE: c_int = 2; +pub const S2N_BLOCKED_ON_APPLICATION_INPUT: c_int = 3; +pub const S2N_BLOCKED_ON_EARLY_DATA: c_int = 4; +pub const s2n_blocked_status = c_uint; +pub extern fn s2n_negotiate(conn: *struct_s2n_connection, blocked: [*c]s2n_blocked_status) c_int; +pub extern fn s2n_send(conn: *struct_s2n_connection, buf: *const c_void, size: isize, blocked: [*c]s2n_blocked_status) isize; +// pub extern fn s2n_sendv(conn: *struct_s2n_connection, bufs: [*c]const struct_iovec, count: isize, blocked: [*c]s2n_blocked_status) isize; +// pub extern fn s2n_sendv_with_offset(conn: *struct_s2n_connection, bufs: [*c]const struct_iovec, count: isize, offs: isize, blocked: [*c]s2n_blocked_status) isize; +pub extern fn s2n_recv(conn: *struct_s2n_connection, buf: *c_void, size: isize, blocked: [*c]s2n_blocked_status) isize; +pub extern fn s2n_peek(conn: *struct_s2n_connection) u32; +pub extern fn s2n_connection_free_handshake(conn: *struct_s2n_connection) c_int; +pub extern fn s2n_connection_release_buffers(conn: *struct_s2n_connection) c_int; +pub extern fn s2n_connection_wipe(conn: *struct_s2n_connection) c_int; +pub extern fn s2n_connection_free(conn: *struct_s2n_connection) c_int; +pub extern fn s2n_shutdown(conn: *struct_s2n_connection, blocked: [*c]s2n_blocked_status) c_int; +pub const S2N_CERT_AUTH_NONE: c_int = 0; +pub const S2N_CERT_AUTH_REQUIRED: c_int = 1; +pub const S2N_CERT_AUTH_OPTIONAL: c_int = 2; +pub const s2n_cert_auth_type = c_uint; +pub extern fn s2n_config_get_client_auth_type(config: *struct_s2n_config, client_auth_type: [*c]s2n_cert_auth_type) c_int; +pub extern fn s2n_config_set_client_auth_type(config: *struct_s2n_config, client_auth_type: s2n_cert_auth_type) c_int; +pub extern fn s2n_connection_get_client_auth_type(conn: *struct_s2n_connection, client_auth_type: [*c]s2n_cert_auth_type) c_int; +pub extern fn s2n_connection_set_client_auth_type(conn: *struct_s2n_connection, client_auth_type: s2n_cert_auth_type) c_int; +pub extern fn s2n_connection_get_client_cert_chain(conn: *struct_s2n_connection, der_cert_chain_out: [*c][*c]u8, cert_chain_len: [*c]u32) c_int; +pub extern fn s2n_config_set_initial_ticket_count(config: *struct_s2n_config, num: u8) c_int; +pub extern fn s2n_connection_add_new_tickets_to_send(conn: *struct_s2n_connection, num: u8) c_int; +pub extern fn s2n_connection_get_tickets_sent(conn: *struct_s2n_connection, num: [*c]u16) c_int; +pub extern fn s2n_connection_set_server_keying_material_lifetime(conn: *struct_s2n_connection, lifetime_in_secs: u32) c_int; +pub const struct_s2n_session_ticket = opaque {}; +pub const s2n_session_ticket_fn = ?fn (*struct_s2n_connection, ?*c_void, *struct_s2n_session_ticket) callconv(.C) c_int; +pub extern fn s2n_config_set_session_ticket_cb(config: *struct_s2n_config, callback: s2n_session_ticket_fn, ctx: ?*c_void) c_int; +pub extern fn s2n_session_ticket_get_data_len(ticket: *struct_s2n_session_ticket, data_len: [*c]usize) c_int; +pub extern fn s2n_session_ticket_get_data(ticket: *struct_s2n_session_ticket, max_data_len: usize, data: [*c]u8) c_int; +pub extern fn s2n_session_ticket_get_lifetime(ticket: *struct_s2n_session_ticket, session_lifetime: [*c]u32) c_int; +pub extern fn s2n_connection_set_session(conn: *struct_s2n_connection, session: [*c]const u8, length: usize) c_int; +pub extern fn s2n_connection_get_session(conn: *struct_s2n_connection, session: [*c]u8, max_length: usize) c_int; +pub extern fn s2n_connection_get_session_ticket_lifetime_hint(conn: *struct_s2n_connection) c_int; +pub extern fn s2n_connection_get_session_length(conn: *struct_s2n_connection) c_int; +pub extern fn s2n_connection_get_session_id_length(conn: *struct_s2n_connection) c_int; +pub extern fn s2n_connection_get_session_id(conn: *struct_s2n_connection, session_id: [*c]u8, max_length: usize) c_int; +pub extern fn s2n_connection_is_session_resumed(conn: *struct_s2n_connection) c_int; +pub extern fn s2n_connection_is_ocsp_stapled(conn: *struct_s2n_connection) c_int; +pub const S2N_TLS_SIGNATURE_ANONYMOUS: c_int = 0; +pub const S2N_TLS_SIGNATURE_RSA: c_int = 1; +pub const S2N_TLS_SIGNATURE_ECDSA: c_int = 3; +pub const S2N_TLS_SIGNATURE_RSA_PSS_RSAE: c_int = 224; +pub const S2N_TLS_SIGNATURE_RSA_PSS_PSS: c_int = 225; +pub const s2n_tls_signature_algorithm = c_uint; +pub const S2N_TLS_HASH_NONE: c_int = 0; +pub const S2N_TLS_HASH_MD5: c_int = 1; +pub const S2N_TLS_HASH_SHA1: c_int = 2; +pub const S2N_TLS_HASH_SHA224: c_int = 3; +pub const S2N_TLS_HASH_SHA256: c_int = 4; +pub const S2N_TLS_HASH_SHA384: c_int = 5; +pub const S2N_TLS_HASH_SHA512: c_int = 6; +pub const S2N_TLS_HASH_MD5_SHA1: c_int = 224; +pub const s2n_tls_hash_algorithm = c_uint; +pub extern fn s2n_connection_get_selected_signature_algorithm(conn: *struct_s2n_connection, chosen_alg: [*c]s2n_tls_signature_algorithm) c_int; +pub extern fn s2n_connection_get_selected_digest_algorithm(conn: *struct_s2n_connection, chosen_alg: [*c]s2n_tls_hash_algorithm) c_int; +pub extern fn s2n_connection_get_selected_client_cert_signature_algorithm(conn: *struct_s2n_connection, chosen_alg: [*c]s2n_tls_signature_algorithm) c_int; +pub extern fn s2n_connection_get_selected_client_cert_digest_algorithm(conn: *struct_s2n_connection, chosen_alg: [*c]s2n_tls_hash_algorithm) c_int; +pub extern fn s2n_connection_get_selected_cert(conn: *struct_s2n_connection) *struct_s2n_cert_chain_and_key; +pub extern fn s2n_cert_chain_get_length(chain_and_key: ?*const struct_s2n_cert_chain_and_key, cert_length: [*c]u32) c_int; +pub extern fn s2n_cert_chain_get_cert(chain_and_key: ?*const struct_s2n_cert_chain_and_key, out_cert: [*c]*struct_s2n_cert, cert_idx: u32) c_int; +pub extern fn s2n_cert_get_der(cert: ?*const struct_s2n_cert, out_cert_der: [*c][*c]const u8, cert_length: [*c]u32) c_int; +pub extern fn s2n_connection_get_peer_cert_chain(conn: *const struct_s2n_connection, cert_chain: *struct_s2n_cert_chain_and_key) c_int; +pub extern fn s2n_cert_get_x509_extension_value_length(cert: *struct_s2n_cert, oid: [*c]const u8, ext_value_len: [*c]u32) c_int; +pub extern fn s2n_cert_get_x509_extension_value(cert: *struct_s2n_cert, oid: [*c]const u8, ext_value: [*c]u8, ext_value_len: [*c]u32, critical: [*c]bool) c_int; +pub extern fn s2n_cert_get_utf8_string_from_extension_data_length(extension_data: [*c]const u8, extension_len: u32, utf8_str_len: [*c]u32) c_int; +pub extern fn s2n_cert_get_utf8_string_from_extension_data(extension_data: [*c]const u8, extension_len: u32, out_data: [*c]u8, out_len: [*c]u32) c_int; +pub const S2N_PSK_HMAC_SHA256: c_int = 0; +pub const S2N_PSK_HMAC_SHA384: c_int = 1; +pub const s2n_psk_hmac = c_uint; +pub const struct_s2n_psk = opaque {}; +pub extern fn s2n_external_psk_new() *struct_s2n_psk; +pub extern fn s2n_psk_free(psk: [*c]*struct_s2n_psk) c_int; +pub extern fn s2n_psk_set_identity(psk: *struct_s2n_psk, identity: [*c]const u8, identity_size: u16) c_int; +pub extern fn s2n_psk_set_secret(psk: *struct_s2n_psk, secret: [*c]const u8, secret_size: u16) c_int; +pub extern fn s2n_psk_set_hmac(psk: *struct_s2n_psk, hmac: s2n_psk_hmac) c_int; +pub extern fn s2n_connection_append_psk(conn: *struct_s2n_connection, psk: *struct_s2n_psk) c_int; +pub const S2N_PSK_MODE_RESUMPTION: c_int = 0; +pub const S2N_PSK_MODE_EXTERNAL: c_int = 1; +pub const s2n_psk_mode = c_uint; +pub extern fn s2n_config_set_psk_mode(config: *struct_s2n_config, mode: s2n_psk_mode) c_int; +pub extern fn s2n_connection_set_psk_mode(conn: *struct_s2n_connection, mode: s2n_psk_mode) c_int; +pub extern fn s2n_connection_get_negotiated_psk_identity_length(conn: *struct_s2n_connection, identity_length: [*c]u16) c_int; +pub extern fn s2n_connection_get_negotiated_psk_identity(conn: *struct_s2n_connection, identity: [*c]u8, max_identity_length: u16) c_int; +pub const struct_s2n_offered_psk = opaque {}; +pub extern fn s2n_offered_psk_new() *struct_s2n_offered_psk; +pub extern fn s2n_offered_psk_free(psk: [*c]*struct_s2n_offered_psk) c_int; +pub extern fn s2n_offered_psk_get_identity(psk: *struct_s2n_offered_psk, identity: [*c][*c]u8, size: [*c]u16) c_int; +pub const struct_s2n_offered_psk_list = opaque {}; +pub extern fn s2n_offered_psk_list_has_next(psk_list: *struct_s2n_offered_psk_list) bool; +pub extern fn s2n_offered_psk_list_next(psk_list: *struct_s2n_offered_psk_list, psk: *struct_s2n_offered_psk) c_int; +pub extern fn s2n_offered_psk_list_reread(psk_list: *struct_s2n_offered_psk_list) c_int; +pub extern fn s2n_offered_psk_list_choose_psk(psk_list: *struct_s2n_offered_psk_list, psk: *struct_s2n_offered_psk) c_int; +pub const s2n_psk_selection_callback = ?fn (*struct_s2n_connection, ?*c_void, *struct_s2n_offered_psk_list) callconv(.C) c_int; +pub extern fn s2n_config_set_psk_selection_callback(config: *struct_s2n_config, cb: s2n_psk_selection_callback, context: ?*c_void) c_int; +pub extern fn s2n_connection_get_wire_bytes_in(conn: *struct_s2n_connection) u64; +pub extern fn s2n_connection_get_wire_bytes_out(conn: *struct_s2n_connection) u64; +pub extern fn s2n_connection_get_client_protocol_version(conn: *struct_s2n_connection) c_int; +pub extern fn s2n_connection_get_server_protocol_version(conn: *struct_s2n_connection) c_int; +pub extern fn s2n_connection_get_actual_protocol_version(conn: *struct_s2n_connection) c_int; +pub extern fn s2n_connection_get_client_hello_version(conn: *struct_s2n_connection) c_int; +pub extern fn s2n_connection_client_cert_used(conn: *struct_s2n_connection) c_int; +pub extern fn s2n_connection_get_cipher(conn: *struct_s2n_connection) [*c]const u8; +pub extern fn s2n_connection_get_cipher_iana_value(conn: *struct_s2n_connection, first: [*c]u8, second: [*c]u8) c_int; +pub extern fn s2n_connection_is_valid_for_cipher_preferences(conn: *struct_s2n_connection, version: [*c]const u8) c_int; +pub extern fn s2n_connection_get_curve(conn: *struct_s2n_connection) [*c]const u8; +pub extern fn s2n_connection_get_kem_name(conn: *struct_s2n_connection) [*c]const u8; +pub extern fn s2n_connection_get_kem_group_name(conn: *struct_s2n_connection) [*c]const u8; +pub extern fn s2n_connection_get_alert(conn: *struct_s2n_connection) c_int; +pub extern fn s2n_connection_get_handshake_type_name(conn: *struct_s2n_connection) [*c]const u8; +pub extern fn s2n_connection_get_last_message_name(conn: *struct_s2n_connection) [*c]const u8; +pub const struct_s2n_async_pkey_op = opaque {}; +pub const S2N_ASYNC_PKEY_VALIDATION_FAST: c_int = 0; +pub const S2N_ASYNC_PKEY_VALIDATION_STRICT: c_int = 1; +pub const s2n_async_pkey_validation_mode = c_uint; +pub const S2N_ASYNC_DECRYPT: c_int = 0; +pub const S2N_ASYNC_SIGN: c_int = 1; +pub const s2n_async_pkey_op_type = c_uint; +pub const s2n_async_pkey_fn = ?fn (*struct_s2n_connection, *struct_s2n_async_pkey_op) callconv(.C) c_int; +pub extern fn s2n_config_set_async_pkey_callback(config: *struct_s2n_config, @"fn": s2n_async_pkey_fn) c_int; +pub extern fn s2n_async_pkey_op_perform(op: *struct_s2n_async_pkey_op, key: ?*s2n_cert_private_key) c_int; +pub extern fn s2n_async_pkey_op_apply(op: *struct_s2n_async_pkey_op, conn: *struct_s2n_connection) c_int; +pub extern fn s2n_async_pkey_op_free(op: *struct_s2n_async_pkey_op) c_int; +pub extern fn s2n_config_set_async_pkey_validation_mode(config: *struct_s2n_config, mode: s2n_async_pkey_validation_mode) c_int; +pub extern fn s2n_async_pkey_op_get_op_type(op: *struct_s2n_async_pkey_op, @"type": [*c]s2n_async_pkey_op_type) c_int; +pub extern fn s2n_async_pkey_op_get_input_size(op: *struct_s2n_async_pkey_op, data_len: [*c]u32) c_int; +pub extern fn s2n_async_pkey_op_get_input(op: *struct_s2n_async_pkey_op, data: [*c]u8, data_len: u32) c_int; +pub extern fn s2n_async_pkey_op_set_output(op: *struct_s2n_async_pkey_op, data: [*c]const u8, data_len: u32) c_int; +pub const s2n_key_log_fn = ?fn (?*c_void, *struct_s2n_connection, [*c]u8, usize) callconv(.C) c_int; +pub extern fn s2n_config_set_key_log_cb(config: *struct_s2n_config, callback: s2n_key_log_fn, ctx: ?*c_void) c_int; +pub extern fn s2n_config_enable_cert_req_dss_legacy_compat(config: *struct_s2n_config) c_int; +pub extern fn s2n_config_set_server_max_early_data_size(config: *struct_s2n_config, max_early_data_size: u32) c_int; +pub extern fn s2n_connection_set_server_max_early_data_size(conn: *struct_s2n_connection, max_early_data_size: u32) c_int; +pub extern fn s2n_connection_set_server_early_data_context(conn: *struct_s2n_connection, context: [*c]const u8, context_size: u16) c_int; +pub extern fn s2n_psk_configure_early_data(psk: *struct_s2n_psk, max_early_data_size: u32, cipher_suite_first_byte: u8, cipher_suite_second_byte: u8) c_int; +pub extern fn s2n_psk_set_application_protocol(psk: *struct_s2n_psk, application_protocol: [*c]const u8, size: u8) c_int; +pub extern fn s2n_psk_set_early_data_context(psk: *struct_s2n_psk, context: [*c]const u8, size: u16) c_int; +pub const S2N_EARLY_DATA_STATUS_OK: c_int = 0; +pub const S2N_EARLY_DATA_STATUS_NOT_REQUESTED: c_int = 1; +pub const S2N_EARLY_DATA_STATUS_REJECTED: c_int = 2; +pub const S2N_EARLY_DATA_STATUS_END: c_int = 3; +pub const s2n_early_data_status_t = c_uint; +pub extern fn s2n_connection_get_early_data_status(conn: *struct_s2n_connection, status: [*c]s2n_early_data_status_t) c_int; +pub extern fn s2n_connection_get_remaining_early_data_size(conn: *struct_s2n_connection, allowed_early_data_size: [*c]u32) c_int; +pub extern fn s2n_connection_get_max_early_data_size(conn: *struct_s2n_connection, max_early_data_size: [*c]u32) c_int; +pub extern fn s2n_send_early_data(conn: *struct_s2n_connection, data: [*c]const u8, data_len: isize, data_sent: [*c]isize, blocked: [*c]s2n_blocked_status) c_int; +pub extern fn s2n_recv_early_data(conn: *struct_s2n_connection, data: [*c]u8, max_data_len: isize, data_received: [*c]isize, blocked: [*c]s2n_blocked_status) c_int; +pub const struct_s2n_offered_early_data = opaque {}; +pub const s2n_early_data_cb = ?fn (*struct_s2n_connection, *struct_s2n_offered_early_data) callconv(.C) c_int; +pub extern fn s2n_config_set_early_data_cb(config: *struct_s2n_config, cb: s2n_early_data_cb) c_int; +pub extern fn s2n_offered_early_data_get_context_length(early_data: *struct_s2n_offered_early_data, context_len: [*c]u16) c_int; +pub extern fn s2n_offered_early_data_get_context(early_data: *struct_s2n_offered_early_data, context: [*c]u8, max_len: u16) c_int; +pub extern fn s2n_offered_early_data_reject(early_data: *struct_s2n_offered_early_data) c_int; +pub extern fn s2n_offered_early_data_accept(early_data: *struct_s2n_offered_early_data) c_int; +pub const S2N_SUCCESS = @as(c_int, 0); +pub const S2N_FAILURE = -@as(c_int, 1); +pub const S2N_CALLBACK_BLOCKED = -@as(c_int, 2); +pub const S2N_MINIMUM_SUPPORTED_TLS_RECORD_MAJOR_VERSION = @as(c_int, 2); +pub const S2N_MAXIMUM_SUPPORTED_TLS_RECORD_MAJOR_VERSION = @as(c_int, 3); +pub const S2N_SSLv2 = @as(c_int, 20); +pub const S2N_SSLv3 = @as(c_int, 30); +pub const S2N_TLS10 = @as(c_int, 31); +pub const S2N_TLS11 = @as(c_int, 32); +pub const S2N_TLS12 = @as(c_int, 33); +pub const S2N_TLS13 = @as(c_int, 34); +pub const S2N_UNKNOWN_PROTOCOL_VERSION = @as(c_int, 0); +pub const s2n_config = struct_s2n_config; +pub const s2n_connection = struct_s2n_connection; +pub const s2n_stacktrace = struct_s2n_stacktrace; +pub const s2n_cert = struct_s2n_cert; +pub const s2n_cert_chain_and_key = struct_s2n_cert_chain_and_key; +pub const s2n_pkey = struct_s2n_pkey; +pub const s2n_client_hello = struct_s2n_client_hello; +pub const s2n_session_ticket = struct_s2n_session_ticket; +pub const s2n_psk = struct_s2n_psk; +pub const s2n_offered_psk = struct_s2n_offered_psk; +pub const s2n_offered_psk_list = struct_s2n_offered_psk_list; +pub const s2n_async_pkey_op = struct_s2n_async_pkey_op; +pub const s2n_offered_early_data = struct_s2n_offered_early_data; + +var booted = false; +pub var global_s2n_config: *s2n_config = undefined; +const unexpectedErrno = std.os.unexpectedErrno; +const S2NError = error{ Closed, WouldBlock, Alert, Protocol, Internal, Usage }; +pub inline fn s2nErrorNo(rc: c_int) S2NError!std.os.system.E { + switch (s2n_error_get_type(rc)) { + -1 => return error.Internal, + S2N_ERR_T_OK => return .SUCCESS, + S2N_ERR_T_IO => return std.os.errno(rc), + S2N_ERR_T_CLOSED => return error.Closed, + S2N_ERR_T_BLOCKED => return error.WouldBlock, + S2N_ERR_T_ALERT => return error.Alert, + S2N_ERR_T_PROTO => return error.Protocol, + S2N_ERR_T_INTERNAL => return error.Internal, + S2N_ERR_T_USAGE => return error.Usage, + else => return std.os.errno(rc), + } +} + +pub const Connection = struct { + conn: *s2n_connection = undefined, + fd: std.os.socket_t, + node: *Pool.List.Node, + disable_shutdown: bool = false, + + pub const Pool = struct { + pub const List = std.SinglyLinkedList(*s2n_connection); + pub var list = List{}; + + pub fn get() *Pool.List.Node { + if (list.first) |first| { + return first; + } else { + var node = Allocator.allocator.create(Pool.List.Node) catch unreachable; + node.* = Pool.List.Node{ .data = s2n_connection_new(S2N_CLIENT) }; + return node; + } + } + + pub fn put(conn: *Pool.List.Node) void { + _ = s2n_connection_wipe(conn.data); + list.prepend(conn); + } + }; + + // var pool = std.SinglyLinkedList(); + // var pool_used: std.atomic.Atomic(u32) = std.atomic.Atomic(u32).init(0); + + pub fn init(fd: std.os.socket_t) Connection { + return Connection{ + .fd = fd, + .conn = undefined, + .node = undefined, + }; + } + + const errno = s2nErrorNo; + + // pub fn s2n_recv_function(conn: *s2n_connection, buf: [*c]u8, len: u32) callconv(.C) c_int { + // if (buf == null) return 0; + // var fd: c_int = 0; + // _ = s2n_connection_get_read_fd(conn, &fd); + // return @intCast(c_int, std.os.system.recvfrom(fd, buf, len, std.os.SOCK_CLOEXEC, null, null)); + // } + // pub fn s2n_send_function(conn: *s2n_connection, buf: [*c]const u8, len: u32) callconv(.C) c_int { + // if (buf == null) return 0; + // var fd: c_int = 0; + // _ = s2n_connection_get_write_fd(conn, &fd); + + // return @intCast(c_int, std.os.system.sendto(fd, buf.?, len, std.os.SOCK_CLOEXEC, null, 0)); + // } + + pub fn start(this: *Connection, server_name: [:0]const u8) !void { + this.node = Pool.get(); + this.conn = this.node.data; + s2nassert(s2n_connection_set_ctx(this.conn, this)); + s2nassert(s2n_connection_set_config(this.conn, global_s2n_config)); + s2nassert(s2n_connection_set_read_fd(this.conn, @intCast(c_int, this.fd))); + s2nassert(s2n_connection_set_write_fd(this.conn, @intCast(c_int, this.fd))); + s2nassert(s2n_connection_set_blinding(this.conn, S2N_SELF_SERVICE_BLINDING)); + // s2nassert(s2n_connection_set_dynamic_record(this.conn)); + s2nassert(s2n_set_server_name(this.conn, server_name.ptr)); + + // _ = s2n_connection_set_recv_cb(this.conn, s2n_recv_function); + // _ = s2n_connection_set_send_cb(this.conn, s2n_send_function); + const rc = s2n_negotiate(this.conn, &blocked_status); + if (rc < 0) { + Output.printErrorln("Alert: {d}", .{s2n_connection_get_alert(this.conn)}); + Output.prettyErrorln("ERROR: {s}", .{s2n_strerror_debug(rc, "EN")}); + } + + defer s2nassert(s2n_connection_free_handshake(this.conn)); + + switch (try s2nErrorNo(rc)) { + .SUCCESS => return, + .BADF => unreachable, // always a race condition + .FAULT => unreachable, + .INVAL => unreachable, + .NOTCONN => unreachable, + .NOTSOCK => unreachable, + .INTR => return error.Interrupted, + .AGAIN => return error.WouldBlock, + .NOMEM => return error.SystemResources, + .CONNREFUSED => return error.ConnectionRefused, + .CONNRESET => return error.ConnectionResetByPeer, + else => |err| return unexpectedErrno(err), + } + } + + pub fn close(this: *Connection) !void { + if (!this.disable_shutdown) { + _ = s2n_shutdown(this.conn, &blocked_status); + Pool.put(this.node); + } + std.os.closeSocket(this.fd); + } + + pub const Writer = std.io.Writer(*Connection, WriteError, write); + pub const Reader = std.io.Reader(*Connection, ReadError, read); + + pub fn writer(this: *Connection) Writer { + return Writer{ .context = this }; + } + + pub fn reader(this: *Connection) Reader { + return Reader{ .context = this }; + } + + pub const ReadError = error{ + WouldBlock, + SystemResources, + ConnectionRefused, + ConnectionResetByPeer, + Unexpected, + Interrupted, + } || S2NError; + + pub fn read(this: *Connection, buf: []u8) ReadError!usize { + const rc = s2n_recv(this.conn, buf.ptr, @intCast(isize, buf.len), &blocked_status); + + switch (try errno(@intCast(c_int, rc))) { + .SUCCESS => return @intCast(usize, rc), + .BADF => unreachable, // always a race condition + .FAULT => unreachable, + .INVAL => unreachable, + .NOTCONN => unreachable, + .NOTSOCK => unreachable, + .INTR => return error.Interrupted, + .AGAIN => return error.WouldBlock, + .NOMEM => return error.SystemResources, + .CONNREFUSED => return error.ConnectionRefused, + .CONNRESET => return error.ConnectionResetByPeer, + else => |err| return unexpectedErrno(err), + } + } + + pub fn peek(this: *Connection) u32 { + return s2n_peek(this.conn); + } + + var blocked_status: s2n_blocked_status = 0; + pub const WriteError = error{ + AccessDenied, + AddressFamilyNotSupported, + BrokenPipe, + ConnectionResetByPeer, + FastOpenAlreadyInProgress, + FileNotFound, + MessageTooBig, + NameTooLong, + NetworkSubsystemFailed, + NetworkUnreachable, + NotDir, + SocketNotConnected, + SymLinkLoop, + SystemResources, + WouldBlock, + Unexpected, + } || S2NError; + pub fn write(this: *Connection, buf: []const u8) WriteError!usize { + const rc = s2n_send(this.conn, buf.ptr, @intCast(isize, buf.len), &blocked_status); + // std.os.sendto( + switch (try errno(@intCast(c_int, rc))) { + .SUCCESS => return buf.len, + .ACCES => return error.AccessDenied, + .AGAIN => return error.WouldBlock, + .ALREADY => return error.FastOpenAlreadyInProgress, + .BADF => unreachable, // always a race condition + .CONNRESET => return error.ConnectionResetByPeer, + .DESTADDRREQ => unreachable, // The socket is not connection-mode, and no peer address is set. + .FAULT => unreachable, // An invalid user space address was specified for an argument. + .INTR => unreachable, + .INVAL => unreachable, // Invalid argument passed. + .ISCONN => unreachable, // connection-mode socket was connected already but a recipient was specified + .MSGSIZE => return error.MessageTooBig, + .NOBUFS => return error.SystemResources, + .NOMEM => return error.SystemResources, + .NOTSOCK => unreachable, // The file descriptor sockfd does not refer to a socket. + .OPNOTSUPP => unreachable, // Some bit in the flags argument is inappropriate for the socket type. + .PIPE => return error.BrokenPipe, + .AFNOSUPPORT => return error.AddressFamilyNotSupported, + .LOOP => return error.SymLinkLoop, + .NAMETOOLONG => return error.NameTooLong, + .NOENT => return error.FileNotFound, + .NOTDIR => return error.NotDir, + .HOSTUNREACH => return error.NetworkUnreachable, + .NETUNREACH => return error.NetworkUnreachable, + .NOTCONN => return error.SocketNotConnected, + .NETDOWN => return error.NetworkSubsystemFailed, + else => |err| return std.os.unexpectedErrno(err), + } + } +}; + +pub const Allocator = struct { + pub var allocator: *std.mem.Allocator = undefined; + + pub fn initCallback() callconv(.C) c_int { + return S2N_SUCCESS; + } + + pub fn deinitCallback() callconv(.C) c_int { + return S2N_SUCCESS; + } + + pub fn mallocCallback(ptr: **c_void, requested: u32, allocated: *u32) callconv(.C) c_int { + const bytes = allocator.allocAdvanced(u8, null, requested, .at_least) catch return S2N_FAILURE; + @memset(bytes.ptr, 0, bytes.len); + allocated.* = @intCast(u32, bytes.len); + ptr.* = bytes.ptr; + return S2N_SUCCESS; + } + + pub fn freeCallback(ptr_: ?*c_void, size: u32) callconv(.C) c_int { + var ptr = ptr_ orelse return S2N_SUCCESS; + if (size == 0) + return S2N_SUCCESS; + + var slice_ptr = @ptrCast([*]u8, ptr); + var slice = slice_ptr[0..size]; + allocator.free(slice); + return S2N_SUCCESS; + } +}; diff --git a/src/string_immutable.zig b/src/string_immutable.zig index bbdea59cf..c9168d336 100644 --- a/src/string_immutable.zig +++ b/src/string_immutable.zig @@ -388,6 +388,14 @@ inline fn eqlComptimeCheckLen(self: string, comptime alt: anytype, comptime chec const second = comptime std.mem.readIntNative(u64, alt[8..16]); return ((comptime !check_len) or self.len == alt.len) and first == std.mem.readIntNative(u64, self[0..8]) and second == std.mem.readIntNative(u64, self[8..16]); }, + 17 => { + const first = comptime std.mem.readIntNative(u64, alt[0..8]); + const second = comptime std.mem.readIntNative(u64, alt[8..16]); + return ((comptime !check_len) or self.len == alt.len) and + first == std.mem.readIntNative(u64, self[0..8]) and second == + std.mem.readIntNative(u64, self[8..16]) and + alt[16] == self[16]; + }, 23 => { const first = comptime std.mem.readIntNative(u64, alt[0..8]); const second = comptime std.mem.readIntNative(u64, alt[8..15]); diff --git a/src/walker_skippable.zig b/src/walker_skippable.zig new file mode 100644 index 000000000..3ce72889c --- /dev/null +++ b/src/walker_skippable.zig @@ -0,0 +1,151 @@ +const std = @import("std"); +const Allocator = std.mem.Allocator; +const Walker = @This(); +const path = std.fs.path; + +stack: std.ArrayList(StackItem), +name_buffer: std.ArrayList(u8), +skip_filenames: []const u64 = &[_]u64{}, +skip_dirnames: []const u64 = &[_]u64{}, +skip_all: []const u64 = &[_]u64{}, +seed: u64 = 0, + +const Dir = std.fs.Dir; + +pub const WalkerEntry = struct { + /// The containing directory. This can be used to operate directly on `basename` + /// rather than `path`, avoiding `error.NameTooLong` for deeply nested paths. + /// The directory remains open until `next` or `deinit` is called. + dir: Dir, + basename: []const u8, + path: []const u8, + kind: Dir.Entry.Kind, +}; + +const StackItem = struct { + iter: Dir.Iterator, + dirname_len: usize, +}; + +/// After each call to this function, and on deinit(), the memory returned +/// from this function becomes invalid. A copy must be made in order to keep +/// a reference to the path. +pub fn next(self: *Walker) !?WalkerEntry { + while (self.stack.items.len != 0) { + // `top` becomes invalid after appending to `self.stack` + var top = &self.stack.items[self.stack.items.len - 1]; + var dirname_len = top.dirname_len; + if (try top.iter.next()) |base| { + switch (base.kind) { + .Directory => { + if (std.mem.indexOfScalar(u64, self.skip_dirnames, std.hash.Wyhash.hash(self.seed, base.name)) != null) continue; + }, + .File => { + if (std.mem.indexOfScalar(u64, self.skip_filenames, std.hash.Wyhash.hash(self.seed, base.name)) != null) continue; + }, + + // we don't know what it is for a symlink + .SymLink => { + if (std.mem.indexOfScalar(u64, self.skip_all, std.hash.Wyhash.hash(self.seed, base.name)) != null) continue; + }, + + else => {}, + } + + self.name_buffer.shrinkRetainingCapacity(dirname_len); + if (self.name_buffer.items.len != 0) { + try self.name_buffer.append(path.sep); + dirname_len += 1; + } + try self.name_buffer.appendSlice(base.name); + const cur_len = self.name_buffer.items.len; + try self.name_buffer.append(0); + self.name_buffer.shrinkRetainingCapacity(cur_len); + + if (base.kind == .Directory) { + var new_dir = top.iter.dir.openDir(base.name, .{ .iterate = true }) catch |err| switch (err) { + error.NameTooLong => unreachable, // no path sep in base.name + else => |e| return e, + }; + { + errdefer new_dir.close(); + try self.stack.append(StackItem{ + .iter = new_dir.iterate(), + .dirname_len = self.name_buffer.items.len, + }); + top = &self.stack.items[self.stack.items.len - 1]; + } + } + return WalkerEntry{ + .dir = top.iter.dir, + .basename = self.name_buffer.items[dirname_len..], + .path = self.name_buffer.items, + .kind = base.kind, + }; + } else { + var item = self.stack.pop(); + if (self.stack.items.len != 0) { + item.iter.dir.close(); + } + } + } + return null; +} + +pub fn deinit(self: *Walker) void { + while (self.stack.popOrNull()) |*item| { + if (self.stack.items.len != 0) { + item.iter.dir.close(); + } + } + self.stack.deinit(); + self.name_buffer.allocator.free(self.skip_all); + self.name_buffer.deinit(); +} + +/// Recursively iterates over a directory. +/// `self` must have been opened with `OpenDirOptions{.iterate = true}`. +/// Must call `Walker.deinit` when done. +/// The order of returned file system entries is undefined. +/// `self` will not be closed after walking it. +pub fn walk( + self: Dir, + allocator: *Allocator, + skip_filenames: []const []const u8, + skip_dirnames: []const []const u8, +) !Walker { + var name_buffer = std.ArrayList(u8).init(allocator); + errdefer name_buffer.deinit(); + + var stack = std.ArrayList(Walker.StackItem).init(allocator); + errdefer stack.deinit(); + + var skip_names = try allocator.alloc(u64, skip_filenames.len + skip_dirnames.len); + const seed = skip_filenames.len + skip_dirnames.len; + var skip_name_i: usize = 0; + + for (skip_filenames) |name| { + skip_names[skip_name_i] = std.hash.Wyhash.hash(seed, name); + skip_name_i += 1; + } + var skip_filenames_ = skip_names[0..skip_name_i]; + var skip_dirnames_ = skip_names[skip_name_i..]; + + for (skip_dirnames) |name, i| { + skip_dirnames_[i] = std.hash.Wyhash.hash(seed, name); + } + + try stack.append(Walker.StackItem{ + .iter = self.iterate(), + .dirname_len = 0, + }); + + return Walker{ + .stack = stack, + .name_buffer = name_buffer, + .skip_all = skip_names, + .seed = seed, + .skip_filenames = skip_filenames_, + .skip_dirnames = skip_dirnames_, + }; +} diff --git a/src/which.zig b/src/which.zig new file mode 100644 index 000000000..0b8e5f1f8 --- /dev/null +++ b/src/which.zig @@ -0,0 +1,40 @@ +const std = @import("std"); + +fn isValid(buf: *[std.fs.MAX_PATH_BYTES]u8, segment: []const u8, bin: []const u8) ?u16 { + std.mem.copy(u8, buf, segment); + buf[segment.len] = std.fs.path.sep; + std.mem.copy(u8, buf[segment.len + 1 ..], bin); + buf[segment.len + 1 + bin.len ..][0] = 0; + const filepath = buf[0 .. segment.len + 1 + bin.len :0]; + + std.os.accessZ(filepath, std.os.X_OK) catch return null; + return @intCast(u16, filepath.len); +} + +// Like /usr/bin/which but without needing to exec a child process +// Remember to resolve the symlink if necessary +pub fn which(buf: *[std.fs.MAX_PATH_BYTES]u8, path: []const u8, cwd: []const u8, bin: []const u8) ?[:0]const u8 { + if (isValid(buf, std.mem.trimRight(u8, cwd, std.fs.path.sep_str), bin)) |len| { + return buf[0..len :0]; + } + + var path_iter = std.mem.tokenize(u8, path, ":"); + while (path_iter.next()) |segment| { + if (isValid(buf, segment, bin)) |len| { + return buf[0..len :0]; + } + } + + return null; +} + +test "which" { + var buf: [std.fs.MAX_PATH_BYTES]u8 = undefined; + var realpath = std.os.getenv("PATH") orelse unreachable; + var whichbin = which(&buf, realpath, try std.process.getCwdAlloc(std.heap.c_allocator), "which"); + try std.testing.expectEqualStrings(whichbin orelse return std.debug.assert(false), "/usr/bin/which"); + try std.testing.expect(null == which(&buf, realpath, try std.process.getCwdAlloc(std.heap.c_allocator), "baconnnnnn")); + try std.testing.expect(null != which(&buf, realpath, try std.process.getCwdAlloc(std.heap.c_allocator), "zig")); + try std.testing.expect(null == which(&buf, realpath, try std.process.getCwdAlloc(std.heap.c_allocator), "bin")); + try std.testing.expect(null == which(&buf, realpath, try std.process.getCwdAlloc(std.heap.c_allocator), "usr")); +} diff --git a/src/which_npm_client.zig b/src/which_npm_client.zig new file mode 100644 index 000000000..25e5b2ea1 --- /dev/null +++ b/src/which_npm_client.zig @@ -0,0 +1,102 @@ +usingnamespace @import("./global.zig"); + +const which = @import("./which.zig").which; +const std = @import("std"); + +pub const NPMClient = struct { + bin: string, + tag: Tag, + + pub const Tag = enum { + npm, + yarn, + pnpm, + }; + + // This check adds around 150ms + // so...if we do do this, we should do it in a separate thread + pub fn isYarnBerry(allocator: *std.mem.Allocator, cwd_dir: string, yarn_path: string) bool { + var args = [_]string{ yarn_path, "--version" }; + var term = std.ChildProcess.exec(.{ + .argv = &args, + .allocator = allocator, + .cwd = if (cwd_dir.len > 1) std.mem.trimRight(u8, cwd_dir, "/") else cwd_dir, + }) catch return true; + defer allocator.free(term.stderr); + defer allocator.free(term.stdout); + + if (term.stdout.len == 0) return true; + return term.stdout[0] != '1'; + } + + pub fn detect(allocator: *std.mem.Allocator, realpath_buf: *[std.fs.MAX_PATH_BYTES]u8, PATH: string, cwd: string, comptime allow_yarn: bool) !?NPMClient { + + // We say: + // - pnpm if it exists, is the default. its most esoteric, so if you have it installed, you prob want it. + // - yarn if it exists and it is yarn 1, its the default (yarn 2 or later is not supported) + // - else npm + + const out_path = brk: { + var path_buf: [std.fs.MAX_PATH_BYTES]u8 = undefined; + + const path: [:0]const u8 = if (comptime allow_yarn) + which( + &path_buf, + PATH, + cwd, + "pnpm", + ) orelse which( + &path_buf, + PATH, + cwd, + "yarn", + ) orelse which( + &path_buf, + PATH, + cwd, + "npm", + ) orelse "" + else + which( + &path_buf, + PATH, + cwd, + "pnpm", + ) orelse which( + &path_buf, + PATH, + cwd, + "npm", + ) orelse ""; + + var file = std.fs.openFileAbsoluteZ(path, .{ .read = true }) catch return null; + defer file.close(); + break :brk std.os.getFdPath(file.handle, realpath_buf) catch return null; + }; + + const basename = std.fs.path.basename(std.mem.span(out_path)); + if (basename.len == 0) return null; + + // if (comptime allow_yarn) { + // if (std.mem.indexOf(u8, basename, "yarn") != null) { + // if (isYarnBerry(allocator, cwd, out_path)) { + // return try detect(allocator, realpath_buf, PATH, cwd, false); + // } + // } + // } + + if (strings.contains(basename, "pnpm")) { + return NPMClient{ .bin = out_path, .tag = .pnpm }; + } + + if (strings.contains(basename, "yarn")) { + return NPMClient{ .bin = out_path, .tag = .yarn }; + } + + if (strings.contains(basename, "npm")) { + return NPMClient{ .bin = out_path, .tag = .npm }; + } + + return null; + } +}; |