main.zig (2582B)
1 const std = @import("std"); 2 const Zip = @import("zip"); 3 const SeekableHttpRange = @import("seekable_http_range.zig"); 4 5 pub fn main() !void { 6 var gpa = std.heap.GeneralPurposeAllocator(.{}){}; 7 defer _ = gpa.deinit(); 8 const a = gpa.allocator(); 9 10 var args = try std.process.argsAlloc(a); 11 defer std.process.argsFree(a, args); 12 if (args.len < 2) { 13 try printHelpAndExit("No URL specified"); 14 return; 15 } 16 if (args.len < 3) { 17 try printHelpAndExit("No FILES specified"); 18 return; 19 } 20 const url = args[1]; 21 const files = args[2..]; 22 23 // TODO general purpose options handling 24 if (std.mem.eql(u8, url, "-h") or std.mem.eql(u8, url, "--help")) { 25 try printHelpAndExit(null); 26 return; 27 } 28 29 var client = std.http.Client{.allocator = a}; 30 defer client.deinit(); 31 32 var range = try SeekableHttpRange.init(.{ 33 .allocator = a, 34 .client = &client, 35 .url = url, 36 .buffer_size = 8192, 37 }); 38 defer range.deinit(); 39 40 var zip = try Zip.from(a, &range); 41 defer zip.deinit(); 42 43 var at_least_one_success = false; 44 for (files) |file| { 45 cdhlp: for (zip.central_directory_headers.items, 0..) |cdh, ix| { 46 if (std.mem.eql(u8, file, cdh.file_name)) { 47 const cwd = std.fs.cwd(); 48 if (std.fs.path.dirname(file)) |dirname| { 49 try cwd.makePath(dirname); 50 } 51 var outfile = try cwd.createFile(cdh.file_name, .{}); 52 defer outfile.close(); 53 try zip.extract(ix, &range, outfile.writer()); 54 at_least_one_success = true; 55 break :cdhlp; 56 } 57 } else { 58 try std.fmt.format(std.io.getStdErr().writer(), "File {s} not found in zip\n", .{file}); 59 } 60 } 61 if (!at_least_one_success) { 62 try std.io.getStdErr().writeAll("No files successfully downloded\n"); 63 std.os.exit(1); 64 } 65 } 66 67 fn printHelpAndExit(comptime errmsg: ?[]const u8) !void { 68 const usage = \\Usage: 69 \\zipdl URL FILES... 70 \\ URL is the http(s) URL of a ZIP file 71 \\ FILES are the files to be extracted from the remote ZIP 72 \\ 73 ; 74 if (errmsg) |err| { 75 try std.io.getStdErr().writeAll(err); 76 try std.io.getStdErr().writeAll("\n\n"); 77 try std.io.getStdErr().writeAll(usage); 78 std.os.exit(2); 79 } else { 80 try std.io.getStdErr().writeAll(usage); 81 std.os.exit(0); 82 } 83 unreachable; 84 } 85 86 test { 87 _ = SeekableHttpRange; 88 }