diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2024-03-06 16:36:29 -0700 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2024-03-10 17:51:06 -0700 |
| commit | 34faf9d12e3ce7b203a8e6e51e1652a985cfb626 (patch) | |
| tree | f8807b97ca9896af9dc93c7706be3b7c742c2df0 /lib/compiler/std-docs.zig | |
| parent | 33f3443243059ce7634dcddf8a87d6ed7837df06 (diff) | |
| download | zig-34faf9d12e3ce7b203a8e6e51e1652a985cfb626.tar.gz zig-34faf9d12e3ce7b203a8e6e51e1652a985cfb626.zip | |
add skeleton of `zig std` command impl
Diffstat (limited to 'lib/compiler/std-docs.zig')
| -rw-r--r-- | lib/compiler/std-docs.zig | 164 |
1 files changed, 164 insertions, 0 deletions
diff --git a/lib/compiler/std-docs.zig b/lib/compiler/std-docs.zig new file mode 100644 index 0000000000..e9961d0781 --- /dev/null +++ b/lib/compiler/std-docs.zig @@ -0,0 +1,164 @@ +const builtin = @import("builtin"); +const std = @import("std"); +const Allocator = std.mem.Allocator; + +pub fn main() !void { + var arena_instance = std.heap.ArenaAllocator.init(std.heap.page_allocator); + defer arena_instance.deinit(); + const arena = arena_instance.allocator(); + + var general_purpose_allocator: std.heap.GeneralPurposeAllocator(.{}) = .{}; + const gpa = general_purpose_allocator.allocator(); + + const args = try std.process.argsAlloc(arena); + const zig_lib_directory = args[1]; + const zig_exe_path = args[2]; + const global_cache_path = args[3]; + + const docs_path = try std.fs.path.join(arena, &.{ zig_lib_directory, "docs" }); + var docs_dir = try std.fs.cwd().openDir(docs_path, .{}); + defer docs_dir.close(); + + const listen_port: u16 = 0; + const address = std.net.Address.parseIp("127.0.0.1", listen_port) catch unreachable; + var http_server = try address.listen(.{}); + const port = http_server.listen_address.in.getPort(); + const url = try std.fmt.allocPrint(arena, "http://127.0.0.1:{d}/\n", .{port}); + std.io.getStdOut().writeAll(url) catch {}; + openBrowserTab(gpa, url[0 .. url.len - 1 :'\n']) catch |err| { + std.log.err("unable to open browser: {s}", .{@errorName(err)}); + }; + + var read_buffer: [8000]u8 = undefined; + accept: while (true) { + const connection = try http_server.accept(); + defer connection.stream.close(); + + var server = std.http.Server.init(connection, &read_buffer); + while (server.state == .ready) { + var request = server.receiveHead() catch |err| switch (err) { + error.HttpConnectionClosing => continue :accept, + else => { + std.log.err("closing http connection: {s}", .{@errorName(err)}); + continue :accept; + }, + }; + serveRequest(&request, gpa, docs_dir, zig_exe_path, global_cache_path) catch |err| { + std.log.err("unable to serve {s}: {s}", .{ request.head.target, @errorName(err) }); + continue :accept; + }; + } + } +} + +fn serveRequest( + request: *std.http.Server.Request, + gpa: Allocator, + docs_dir: std.fs.Dir, + zig_exe_path: []const u8, + global_cache_path: []const u8, +) !void { + if (std.mem.eql(u8, request.head.target, "/") or + std.mem.eql(u8, request.head.target, "/debug/")) + { + try serveDocsFile(request, gpa, docs_dir, "index.html", "text/html"); + } else if (std.mem.eql(u8, request.head.target, "/main.js") or + std.mem.eql(u8, request.head.target, "/debug/main.js")) + { + try serveDocsFile(request, gpa, docs_dir, "main.js", "application/javascript"); + } else if (std.mem.eql(u8, request.head.target, "/main.wasm")) { + try serveWasm(request, gpa, zig_exe_path, global_cache_path, .ReleaseFast); + } else if (std.mem.eql(u8, request.head.target, "/debug/main.wasm")) { + try serveWasm(request, gpa, zig_exe_path, global_cache_path, .Debug); + } else { + try request.respond("not found", .{ + .status = .not_found, + .extra_headers = &.{ + .{ .name = "content-type", .value = "text/plain" }, + }, + }); + } +} + +fn serveDocsFile( + request: *std.http.Server.Request, + gpa: Allocator, + docs_dir: std.fs.Dir, + name: []const u8, + content_type: []const u8, +) !void { + // The desired API is actually sendfile, which will require enhancing std.http.Server. + // We load the file with every request so that the user can make changes to the file + // and refresh the HTML page without restarting this server. + const file_contents = try docs_dir.readFileAlloc(gpa, name, 10 * 1024 * 1024); + defer gpa.free(file_contents); + try request.respond(file_contents, .{ + .status = .ok, + .extra_headers = &.{ + .{ .name = "content-type", .value = content_type }, + }, + }); +} + +fn serveWasm( + request: *std.http.Server.Request, + gpa: Allocator, + zig_exe_path: []const u8, + global_cache_path: []const u8, + optimize_mode: std.builtin.OptimizeMode, +) !void { + _ = request; + _ = gpa; + _ = zig_exe_path; + _ = global_cache_path; + _ = optimize_mode; + @panic("TODO serve wasm"); +} + +const BuildWasmBinaryOptions = struct { + zig_exe_path: []const u8, + global_cache_path: []const u8, + main_src_path: []const u8, +}; + +fn buildWasmBinary(arena: Allocator, options: BuildWasmBinaryOptions) ![]const u8 { + var argv: std.ArrayListUnmanaged([]const u8) = .{}; + try argv.appendSlice(arena, &.{ + options.zig_exe_path, + "build-exe", + "-fno-entry", + "-OReleaseSmall", + "-target", + "wasm32-freestanding", + "-mcpu", + "baseline+atomics+bulk_memory+multivalue+mutable_globals+nontrapping_fptoint+reference_types+sign_ext", + "--cache-dir", + options.global_cache_path, + "--global-cache-dir", + options.global_cache_path, + "--name", + "autodoc", + "-rdynamic", + options.main_src_path, + "--listen=-", + }); +} + +fn openBrowserTab(gpa: Allocator, url: []const u8) !void { + // Until https://github.com/ziglang/zig/issues/19205 is implemented, we + // spawn a thread for this child process. + _ = try std.Thread.spawn(.{}, openBrowserTabThread, .{ gpa, url }); +} + +fn openBrowserTabThread(gpa: Allocator, url: []const u8) !void { + const main_exe = switch (builtin.os.tag) { + .windows => "explorer", + else => "xdg-open", + }; + var child = std.ChildProcess.init(&.{ main_exe, url }, gpa); + child.stdin_behavior = .Ignore; + child.stdout_behavior = .Ignore; + child.stderr_behavior = .Ignore; + try child.spawn(); + _ = try child.wait(); +} |
