From d3a3582136187072fa00e5c19d6ea791686cdbdb Mon Sep 17 00:00:00 2001 From: Bob Farrell Date: Sun, 3 Mar 2024 20:48:25 +0000 Subject: [PATCH] Implement init command, get rid of old init script/artifacts Remove old bash script for setting up a new project, do everything in Zig to make it platform agnostic and give us an easy place to add scaffolding commands in future. --- .gitignore | 5 - archive.tar.gz | Bin 0 -> 14909 bytes build.zig | 3 +- build.zig.zon | 8 +- cli/build.zig | 33 ++ cli/build.zig.zon | 15 + cli/cli.zig | 60 +++ cli/compile.zig | 71 ++++ cli/init.zig | 427 +++++++++++++++++++++ demo/build.zig.zon | 2 +- demo/public/styles.css | 10 + demo/src/DemoMiddleware.zig | 26 -- demo/src/app/middleware/DemoMiddleware.zig | 53 +++ demo/src/app/views/init.zig | 43 +++ demo/src/app/views/init/_content.zmpl | 18 + demo/src/app/views/init/index.zmpl | 20 + demo/src/app/views/quotes.zig | 4 +- demo/src/main.zig | 2 +- init.bash | 79 ---- src/init/.gitignore | 2 - src/init/build.zig | 86 ----- src/init/build.zig.zon | 14 - src/init/public/jetzig.png | Bin 22828 -> 0 bytes src/init/src/app/views/index.zig | 11 - src/init/src/app/views/quotes.zig | 34 -- src/init/src/app/views/quotes/get.zmpl | 2 - src/init/src/main.zig | 15 - 27 files changed, 763 insertions(+), 280 deletions(-) create mode 100644 archive.tar.gz create mode 100644 cli/build.zig create mode 100644 cli/build.zig.zon create mode 100644 cli/cli.zig create mode 100644 cli/compile.zig create mode 100644 cli/init.zig delete mode 100644 demo/src/DemoMiddleware.zig create mode 100644 demo/src/app/middleware/DemoMiddleware.zig create mode 100644 demo/src/app/views/init.zig create mode 100644 demo/src/app/views/init/_content.zmpl create mode 100644 demo/src/app/views/init/index.zmpl delete mode 100644 init.bash delete mode 100644 src/init/.gitignore delete mode 100644 src/init/build.zig delete mode 100644 src/init/build.zig.zon delete mode 100644 src/init/public/jetzig.png delete mode 100644 src/init/src/app/views/index.zig delete mode 100644 src/init/src/app/views/quotes.zig delete mode 100644 src/init/src/app/views/quotes/get.zmpl delete mode 100644 src/init/src/main.zig diff --git a/.gitignore b/.gitignore index 7d38e30..05a3a49 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,4 @@ -TODO.md -main -get/ zig-out/ zig-cache/ *.core -src/app/views/**/*.compiled.zig -archive.tar.gz static/ diff --git a/archive.tar.gz b/archive.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..b288267a86f12c187cfc1ac5d785b74539b232cb GIT binary patch literal 14909 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 |opts| return init.run( + allocator, + opts, + writer, + options.positionals, + .{ .help = options.options.help }, + ), + } + } + + if (options.options.help) { + try args.printHelp(Options, "jetzig", writer); + try writer.writeAll( + \\ + \\Commands: + \\ + \\ init Initialize a new project. + \\ + \\ Pass --help to any command for more information, e.g. `jetzig init --help` + \\ + ); + } +} diff --git a/cli/compile.zig b/cli/compile.zig new file mode 100644 index 0000000..b1bb2ef --- /dev/null +++ b/cli/compile.zig @@ -0,0 +1,71 @@ +const std = @import("std"); + +fn base64Encode(allocator: std.mem.Allocator, input: []const u8) []const u8 { + const encoder = std.base64.Base64Encoder.init( + std.base64.url_safe_no_pad.alphabet_chars, + std.base64.url_safe_no_pad.pad_char, + ); + const size = encoder.calcSize(input.len); + const ptr = allocator.alloc(u8, size) catch @panic("OOM"); + _ = encoder.encode(ptr, input); + return ptr; +} + +pub fn initDataModule(build: *std.Build) !*std.Build.Module { + const root_path = build.pathFromRoot(".."); + + var buf = std.ArrayList(u8).init(build.allocator); + defer buf.deinit(); + + const writer = buf.writer(); + + const paths = .{ + "demo/build.zig", + "demo/src/main.zig", + "demo/src/app/middleware/DemoMiddleware.zig", + "demo/src/app/views/init.zig", + "demo/src/app/views/init/index.zmpl", + "demo/src/app/views/init/_content.zmpl", + "demo/public/jetzig.png", + "demo/public/zmpl.png", + "demo/public/favicon.ico", + "demo/public/styles.css", + ".gitignore", + }; + + try writer.writeAll( + \\pub const init_data = .{ + \\ + ); + + var dir = try std.fs.openDirAbsolute(root_path, .{}); + defer dir.close(); + + inline for (paths) |path| { + const stat = try dir.statFile(path); + const encoded = base64Encode( + build.allocator, + try dir.readFileAlloc(build.allocator, path, stat.size), + ); + defer build.allocator.free(encoded); + + const output = try std.fmt.allocPrint( + build.allocator, + \\.{{ .path = "{s}", .data = "{s}" }}, + , + .{ path, encoded }, + ); + defer build.allocator.free(output); + + try writer.writeAll(output); + } + + try writer.writeAll( + \\}; + \\ + ); + + const write_files = build.addWriteFiles(); + const init_data_source = write_files.add("init_data.zig", buf.items); + return build.createModule(.{ .root_source_file = init_data_source }); +} diff --git a/cli/init.zig b/cli/init.zig new file mode 100644 index 0000000..2be0815 --- /dev/null +++ b/cli/init.zig @@ -0,0 +1,427 @@ +const std = @import("std"); +const args = @import("args"); +const init_data = @import("init_data").init_data; + +fn base64Decode(allocator: std.mem.Allocator, input: []const u8) ![]const u8 { + const decoder = std.base64.Base64Decoder.init( + std.base64.url_safe_no_pad.alphabet_chars, + std.base64.url_safe_no_pad.pad_char, + ); + const size = try decoder.calcSizeForSlice(input); + const ptr = try allocator.alloc(u8, size); + try decoder.decode(ptr, input); + return ptr; +} + +pub const Options = struct { + path: ?[]const u8 = null, + + pub const shorthands = .{ + .p = "path", + }; + + pub const meta = .{ + .usage_summary = "[--path PATH]", + .full_text = + \\Initializes a new Jetzig project in the current directory or attempts to + \\create a new directory specified by PATH + \\ + \\Creates build.zig, build.zig.zon, src/main.zig, and an example view with a template. + \\ + \\Run `zig build run` to launch a development server when complete. + , + .option_docs = .{ + .path = "Set the output path relative to the current directory (default: current directory)", + }, + }; +}; + +/// Run the `jetzig init` command. +pub fn run( + allocator: std.mem.Allocator, + options: Options, + writer: anytype, + positionals: [][]const u8, + other_options: struct { help: bool }, +) !void { + _ = options; + var install_path: ?[]const u8 = null; + + for (positionals) |arg| { + if (install_path != null) { + std.debug.print("Unexpected positional argument: {s}\n", .{arg}); + return error.JetzigUnexpectedPositionalArgumentsError; + } + install_path = arg; + } + + const github_url = try githubUrl(allocator); + defer allocator.free(github_url); + + if (other_options.help) { + try args.printHelp(Options, "jetzig init", writer); + return; + } + + var install_dir: std.fs.Dir = undefined; + defer install_dir.close(); + + var project_name: []const u8 = undefined; + defer allocator.free(project_name); + + if (install_path) |path| { + install_dir = try std.fs.cwd().makeOpenPath(path, .{}); + project_name = try allocator.dupe(u8, std.fs.path.basename(path)); + } else { + const cwd_realpath = try std.fs.cwd().realpathAlloc(allocator, "."); + defer allocator.free(cwd_realpath); + + const default_project_name = std.fs.path.basename(cwd_realpath); + project_name = try promptInput(allocator, "Project name", .{ .default = default_project_name }); + const sub_path = if (std.mem.eql(u8, project_name, default_project_name)) "" else project_name; + + const default_install_path = try std.fs.path.join( + allocator, + &[_][]const u8{ cwd_realpath, sub_path }, + ); + defer allocator.free(default_install_path); + + const input_install_path = try promptInput( + allocator, + "Install path", + .{ .default = default_install_path }, + ); + defer allocator.free(input_install_path); + install_dir = try std.fs.cwd().makeOpenPath(input_install_path, .{}); + } + + const real_path = try install_dir.realpathAlloc(allocator, "."); + defer allocator.free(real_path); + + const output = try std.fmt.allocPrint(allocator, "Creating new project in {s}\n\n", .{real_path}); + defer allocator.free(output); + try writer.writeAll(output); + + try copySourceFile( + allocator, + install_dir, + "demo/build.zig", + "build.zig", + &[_]Replace{.{ .from = "jetzig-demo", .to = project_name }}, + ); + + try copySourceFile( + allocator, + install_dir, + "demo/src/main.zig", + "src/main.zig", + null, + ); + + try copySourceFile( + allocator, + install_dir, + "demo/src/app/middleware/DemoMiddleware.zig", + "src/app/middleware/DemoMiddleware.zig", + null, + ); + + try copySourceFile( + allocator, + install_dir, + "demo/src/app/views/init.zig", + "src/app/views/root.zig", + null, + ); + + try copySourceFile( + allocator, + install_dir, + "demo/src/app/views/init/index.zmpl", + "src/app/views/root/index.zmpl", + &[_]Replace{ + .{ .from = "init/", .to = "root/" }, + }, + ); + + try copySourceFile( + allocator, + install_dir, + "demo/src/app/views/init/_content.zmpl", + "src/app/views/root/_content.zmpl", + null, + ); + + try copySourceFile( + allocator, + install_dir, + "demo/public/jetzig.png", + "public/jetzig.png", + null, + ); + + try copySourceFile( + allocator, + install_dir, + "demo/public/zmpl.png", + "public/zmpl.png", + null, + ); + + try copySourceFile( + allocator, + install_dir, + "demo/public/favicon.ico", + "public/favicon.ico", + null, + ); + + try copySourceFile( + allocator, + install_dir, + "demo/public/styles.css", + "public/styles.css", + null, + ); + + try copySourceFile( + allocator, + install_dir, + ".gitignore", + ".gitignore", + null, + ); + + try runCommand(allocator, install_dir, &[_][]const u8{ + "zig", + "fetch", + "--save", + github_url, + }); + + // TODO: Use arg or interactive prompt to do Git setup in net project, default to no. + // const git_setup = false; + // if (git_setup) try gitSetup(allocator, install_dir); + + std.debug.print( + \\ + \\Setup complete! ✈️ 🦎 + \\ + \\Launch your new application: + \\ + \\ $ cd {s} + \\ + \\ $ zig build run + \\ + \\And then browse to http://localhost:8080/ + \\ + \\ + , .{real_path}); +} + +fn runCommand(allocator: std.mem.Allocator, install_dir: std.fs.Dir, argv: []const []const u8) !void { + const result = try std.process.Child.run(.{ .allocator = allocator, .argv = argv, .cwd_dir = install_dir }); + defer allocator.free(result.stdout); + defer allocator.free(result.stderr); + + const command = try std.mem.join(allocator, " ", argv); + defer allocator.free(command); + + std.debug.print("[exec] {s}", .{command}); + + if (result.term.Exited != 0) { + printFailure(); + std.debug.print( + \\ + \\Error running command: {s} + \\ + \\[stdout]: + \\ + \\{s} + \\ + \\[stderr]: + \\ + \\{s} + \\ + , .{ command, result.stdout, result.stderr }); + return error.JetzigRunCommandError; + } else { + printSuccess(); + } +} + +const Replace = struct { + from: []const u8, + to: []const u8, +}; + +fn copySourceFile( + allocator: std.mem.Allocator, + install_dir: std.fs.Dir, + src: []const u8, + dest: []const u8, + replace: ?[]const Replace, +) !void { + std.debug.print("[create] {s}", .{dest}); + + var content: []const u8 = undefined; + if (replace) |capture| { + const initial = readSourceFile(allocator, src) catch |err| { + printFailure(); + return err; + }; + defer allocator.free(initial); + for (capture) |item| { + content = try std.mem.replaceOwned(u8, allocator, initial, item.from, item.to); + } + } else { + content = readSourceFile(allocator, src) catch |err| { + printFailure(); + return err; + }; + } + defer allocator.free(content); + + writeSourceFile(install_dir, dest, content) catch |err| { + printFailure(); + return err; + }; + printSuccess(); +} + +// Read a file from Jetzig source code. +fn readSourceFile(allocator: std.mem.Allocator, path: []const u8) ![]const u8 { + inline for (init_data) |file| { + if (std.mem.eql(u8, path, file.path)) return try base64Decode(allocator, file.data); + } + return error.SourceFileNotFound; +} + +// Write a file to the new project's directory. +fn writeSourceFile(install_dir: std.fs.Dir, path: []const u8, content: []const u8) !void { + // TODO: Detect presence and ask for confirmation if necessary. + if (std.fs.path.dirname(path)) |dirname| { + var dir = try install_dir.makeOpenPath(dirname, .{}); + defer dir.close(); + + const file = try dir.createFile(std.fs.path.basename(path), .{ .truncate = true }); + defer file.close(); + + try file.writeAll(content); + } else { + const file = try install_dir.createFile(path, .{ .truncate = true }); + defer file.close(); + + try file.writeAll(content); + } +} + +// Generate a full GitHub URL for passing to `zig fetch`. +fn githubUrl(allocator: std.mem.Allocator) ![]const u8 { + var client = std.http.Client{ .allocator = allocator }; + defer client.deinit(); + + const url = "https://api.github.com/repos/jetzig-framework/jetzig/branches/main"; + const extra_headers = &[_]std.http.Header{.{ .name = "X-GitHub-Api-Version", .value = "2022-11-28" }}; + + var response_storage = std.ArrayList(u8).init(allocator); + defer response_storage.deinit(); + + const fetch_result = try client.fetch(.{ + .location = .{ .url = url }, + .extra_headers = extra_headers, + .response_storage = .{ .dynamic = &response_storage }, + }); + + if (fetch_result.status != .ok) { + std.debug.print("Error fetching from GitHub: {s}\n", .{url}); + return error.JetzigGitHubFetchError; + } + + const parsed_response = try std.json.parseFromSlice( + struct { commit: struct { sha: []const u8 } }, + allocator, + response_storage.items, + .{ .ignore_unknown_fields = true }, + ); + defer parsed_response.deinit(); + + return try std.mem.concat( + allocator, + u8, + &[_][]const u8{ + "https://github.com/jetzig-framework/jetzig/archive/", + parsed_response.value.commit.sha, + ".tar.gz", + }, + ); +} + +// Prompt a user for input and return the result. Accepts an optional default value. +fn promptInput( + allocator: std.mem.Allocator, + prompt: []const u8, + options: struct { default: ?[]const u8 }, +) ![]const u8 { + const stdin = std.io.getStdIn(); + const reader = stdin.reader(); + + const max_read_bytes = 1024; + + while (true) { + if (options.default) |default| { + std.debug.print( + \\{s} [default: "{s}"]: + , .{ prompt, default }); + } else { + std.debug.print( + \\{s}: + , .{prompt}); + } + const input = try reader.readUntilDelimiterOrEofAlloc(allocator, '\n', max_read_bytes); + if (input) |capture| { + defer allocator.free(capture); + + if (std.mem.eql(u8, capture, "")) { + if (options.default) |default| return try allocator.dupe(u8, strip(default)); + } else return try allocator.dupe(u8, strip(capture)); + } + } +} + +// Strip leading and trailing whitespace from a u8 slice. +fn strip(input: []const u8) []const u8 { + return std.mem.trim(u8, input, &std.ascii.whitespace); +} + +// Initialize a new Git repository when setting up a new project (optional). +fn gitSetup(allocator: std.mem.Allocator, install_dir: *std.fs.Dir) !void { + try runCommand(allocator, install_dir, &[_][]const u8{ + "git", + "init", + ".", + }); + + try runCommand(allocator, install_dir, &[_][]const u8{ + "git", + "add", + ".", + }); + + try runCommand(allocator, install_dir, &[_][]const u8{ + "git", + "commit", + "-m", + "Initialize Jetzig project", + }); +} + +/// Print a success confirmation. +fn printSuccess() void { + std.debug.print(" ✅\n", .{}); +} + +/// Print a failure confirmation. +fn printFailure() void { + std.debug.print(" ❌\n", .{}); +} diff --git a/demo/build.zig.zon b/demo/build.zig.zon index 2e43c0f..321158c 100644 --- a/demo/build.zig.zon +++ b/demo/build.zig.zon @@ -1,5 +1,5 @@ .{ - .name = "sandbox-jetzig", + .name = "jetzig-demo", .version = "0.0.0", .minimum_zig_version = "0.12.0", .dependencies = .{ diff --git a/demo/public/styles.css b/demo/public/styles.css index e69de29..1755d47 100644 --- a/demo/public/styles.css +++ b/demo/public/styles.css @@ -0,0 +1,10 @@ +/* Root stylesheet. Load into your Zmpl template with: + * + * + * + */ + +.message { + font-weight: bold; + font-size: 3rem; +} diff --git a/demo/src/DemoMiddleware.zig b/demo/src/DemoMiddleware.zig deleted file mode 100644 index 2209795..0000000 --- a/demo/src/DemoMiddleware.zig +++ /dev/null @@ -1,26 +0,0 @@ -const std = @import("std"); -const jetzig = @import("jetzig"); - -my_data: u8, - -const Self = @This(); - -pub fn init(request: *jetzig.http.Request) !*Self { - var middleware = try request.allocator.create(Self); - middleware.my_data = 42; - return middleware; -} - -pub fn beforeRequest(self: *Self, request: *jetzig.http.Request) !void { - request.server.logger.debug("[DemoMiddleware] Before request, custom data: {d}", .{self.my_data}); - self.my_data = 43; -} - -pub fn afterRequest(self: *Self, request: *jetzig.http.Request, response: *jetzig.http.Response) !void { - request.server.logger.debug("[DemoMiddleware] After request, custom data: {d}", .{self.my_data}); - request.server.logger.debug("[DemoMiddleware] content-type: {s}", .{response.content_type}); -} - -pub fn deinit(self: *Self, request: *jetzig.http.Request) void { - request.allocator.destroy(self); -} diff --git a/demo/src/app/middleware/DemoMiddleware.zig b/demo/src/app/middleware/DemoMiddleware.zig new file mode 100644 index 0000000..06822c7 --- /dev/null +++ b/demo/src/app/middleware/DemoMiddleware.zig @@ -0,0 +1,53 @@ +/// Demo middleware. Assign middleware by declaring `pub const middleware` in the +/// `jetzig_options` defined in your application's `src/main.zig`. +/// +/// Middleware is called before and after the request, providing full access to the active +/// request, allowing you to execute any custom code for logging, tracking, inserting response +/// headers, etc. +/// +/// This middleware is configured in the demo app's `src/main.zig`: +/// +/// ``` +/// pub const jetzig_options = struct { +/// pub const middleware: []const type = &.{@import("app/middleware/DemoMiddleware.zig")}; +/// }; +/// ``` +const std = @import("std"); +const jetzig = @import("jetzig"); + +/// Define any custom data fields you want to store here. Assigning to these fields in the `init` +/// function allows you to access them in the `beforeRequest` and `afterRequest` functions, where +/// they can also be modified. +my_custom_value: []const u8, + +const Self = @This(); + +/// Initialize middleware. +pub fn init(request: *jetzig.http.Request) !*Self { + var middleware = try request.allocator.create(Self); + middleware.my_custom_value = "initial value"; + return middleware; +} + +/// Invoked immediately after the request head has been processed, before relevant view function +/// is processed. This gives you access to request headers but not the request body. +pub fn beforeRequest(self: *Self, request: *jetzig.http.Request) !void { + request.server.logger.debug("[DemoMiddleware] my_custom_value: {s}", .{self.my_custom_value}); + self.my_custom_value = @tagName(request.method); +} + +/// Invoked immediately after the request has finished responding. Provides full access to the +/// response as well as the request. +pub fn afterRequest(self: *Self, request: *jetzig.http.Request, response: *jetzig.http.Response) !void { + request.server.logger.debug( + "[DemoMiddleware] my_custom_value: {s}, response status: {s}", + .{ self.my_custom_value, @tagName(response.status_code) }, + ); +} + +/// Invoked after `afterRequest` is called, use this function to do any clean-up. +/// Note that `request.allocator` is an arena allocator, so any allocations are automatically +/// done before the next request starts processing. +pub fn deinit(self: *Self, request: *jetzig.http.Request) void { + request.allocator.destroy(self); +} diff --git a/demo/src/app/views/init.zig b/demo/src/app/views/init.zig new file mode 100644 index 0000000..0fa146c --- /dev/null +++ b/demo/src/app/views/init.zig @@ -0,0 +1,43 @@ +const jetzig = @import("jetzig"); + +/// `src/app/views/root.zig` represents the root URL `/` +/// The `index` view function is invoked when when the HTTP verb is `GET`. +/// Other view types are invoked either by passing a resource ID value (e.g. `/1234`) or by using +/// a different HTTP verb: +/// +/// GET / => index(request, data) +/// GET /1234 => get(id, request, data) +/// POST / => post(request, data) +/// PUT /1234 => put(id, request, data) +/// PATCH /1234 => patch(id, request, data) +/// DELETE /1234 => delete(id, request, data) +pub fn index(request: *jetzig.Request, data: *jetzig.Data) !jetzig.View { + // The first call to `data.object()` or `data.array()` sets the root response data value. + // JSON requests return a JSON string representation of the root data value. + // Zmpl templates can access all values in the root data value. + var root = try data.object(); + + // Add a string to the root object. + try root.put("message", data.string("Welcome to Jetzig!")); + + // Request params have the same type as a `data.object()` so they can be inserted them + // directly into the response data. Fetch `http://localhost:8080/?message=hello` to set the + // param. JSON data is also accepted when the `content-type: application/json` header is + // present. + const params = try request.params(); + + if (params.get("message")) |value| { + try root.put("message_param", value); + } + + // Set arbitrary response headers as required. `content-type` is automatically assigned for + // HTML, JSON responses. + // + // Static files located in `public/` in the root of your project directory are accessible + // from the root path (e.g. `public/jetzig.png`) is available at `/jetzig.png` and the + // content type is inferred from the extension using MIME types. + try request.response.headers.append("x-example-header", "example header value"); + + // Render the response and set the response code. + return request.render(.ok); +} diff --git a/demo/src/app/views/init/_content.zmpl b/demo/src/app/views/init/_content.zmpl new file mode 100644 index 0000000..08973a1 --- /dev/null +++ b/demo/src/app/views/init/_content.zmpl @@ -0,0 +1,18 @@ +// Renders the `message` response data value. +

{.message}

+ +
+ +
+ +
Visit jetzig.dev to get started.
+
Join our Discord server and introduce yourself:
+ + diff --git a/demo/src/app/views/init/index.zmpl b/demo/src/app/views/init/index.zmpl new file mode 100644 index 0000000..c7c3cb9 --- /dev/null +++ b/demo/src/app/views/init/index.zmpl @@ -0,0 +1,20 @@ + + + + + + + + + + +
+ // If present, renders the `message_param` response data value, add `?message=hello` to the + // URL to see the output: +

{.message_param}

+ + // Renders `src/app/views/init/_content.zmpl` with the same template data available: +
{^init/content}
+
+ + diff --git a/demo/src/app/views/quotes.zig b/demo/src/app/views/quotes.zig index 76eac25..27cace8 100644 --- a/demo/src/app/views/quotes.zig +++ b/demo/src/app/views/quotes.zig @@ -33,7 +33,9 @@ const Quote = struct { // Quotes taken from: https://gist.github.com/natebass/b0a548425a73bdf8ea5c618149fe1fce fn randomQuote(allocator: std.mem.Allocator) !Quote { - const json = try std.fs.cwd().readFileAlloc(allocator, "src/app/config/quotes.json", 12684); + const path = "src/app/config/quotes.json"; + const stat = try std.fs.cwd().statFile(path); + const json = try std.fs.cwd().readFileAlloc(allocator, path, stat.size); const quotes = try std.json.parseFromSlice([]Quote, allocator, json, .{}); return quotes.value[std.crypto.random.intRangeLessThan(usize, 0, quotes.value.len)]; } diff --git a/demo/src/main.zig b/demo/src/main.zig index 8159618..c73e865 100644 --- a/demo/src/main.zig +++ b/demo/src/main.zig @@ -4,7 +4,7 @@ pub const jetzig = @import("jetzig"); pub const routes = @import("routes").routes; pub const jetzig_options = struct { - pub const middleware: []const type = &.{@import("DemoMiddleware.zig")}; + pub const middleware: []const type = &.{@import("app/middleware/DemoMiddleware.zig")}; }; pub fn main() !void { diff --git a/init.bash b/init.bash deleted file mode 100644 index d2b17dd..0000000 --- a/init.bash +++ /dev/null @@ -1,79 +0,0 @@ -#!/bin/bash - -printf 'Enter project name (default: "jetzig-demo"): ' -read -a project -if [ -z "${project}" ] -then - project="jetzig-demo" -fi - -pwd="$(pwd)" -printf "Enter project parent directory (default: \"${pwd}\"): " -read -a dir -if [ -z "${dir}" ] -then - dir="${pwd}" -fi - - -set -eu - -project_path="${dir}/${project}" -echo -echo "Initializing new project in: ${project_path}" - -mkdir -p "${project_path}" - -do_exit () { - echo "Error fetching '$1':" - echo "$2" - echo "Exiting." - exit 1 -} - -remote_base=https://raw.githubusercontent.com/jetzig-framework/jetzig/main/src/init - -objects=( - 'build.zig' - 'build.zig.zon' - 'src/main.zig' - 'src/app/views/index.zig' - 'src/app/views/index.zmpl' - 'src/app/views/quotes.zig' - 'src/app/views/quotes/get.zmpl' - 'src/app/config/quotes.json' - 'public/jetzig.png' - '.gitignore' -) - -for object in "${objects[@]}" -do - printf "Creating output: ${object} " - url="${remote_base}/${object}" - mkdir -p "$(dirname "${project_path}/${object}")" - set +e - output=$(curl -s --fail --output "${project_path}/${object}" "${url}" 2>&1) - set -e - if (($?)) - then - do_exit "${url}" "${output}" - else - echo "✅" - fi -done - -sed -i.bak -e "s,%%project_name%%,${project},g" "${project_path}/build.zig" -rm "${project_path}/build.zig.bak" -sed -i.bak -e "s,%%project_name%%,${project},g" "${project_path}/build.zig.zon" -rm "${project_path}/build.zig.zon.bak" - -echo -echo "Finished creating new project in: ${project_path}" -echo -echo "Run your new project:" -echo -echo " cd '${project_path}'" -echo ' zig build run' -echo -echo "Welcome to Jetzig. ✈️🦎 " -echo diff --git a/src/init/.gitignore b/src/init/.gitignore deleted file mode 100644 index 7b36f9d..0000000 --- a/src/init/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -# Compiled Zmpl views: -src/app/views/**/*.compiled.zig diff --git a/src/init/build.zig b/src/init/build.zig deleted file mode 100644 index f60f3e4..0000000 --- a/src/init/build.zig +++ /dev/null @@ -1,86 +0,0 @@ -const std = @import("std"); -const jetzig_build = @import("jetzig"); -// Although this function looks imperative, note that its job is to -// declaratively construct a build graph that will be executed by an external -// runner. -pub fn build(b: *std.Build) void { - // Standard target options allows the person running `zig build` to choose - // what target to build for. Here we do not override the defaults, which - // means any target is allowed, and the default is native. Other options - // for restricting supported target set are available. - const target = b.standardTargetOptions(.{}); - - // Standard optimization options allow the person running `zig build` to select - // between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. Here we do not - // set a preferred release mode, allowing the user to decide how to optimize. - const optimize = b.standardOptimizeOption(.{}); - const jetzig_dep = b.dependency("jetzig", .{ .optimize = optimize, .target = target }); - const compile_view_step = jetzig_build.CompileViewsStep.create(b, .{ .template_path = "src/app/views/" }); - - // This declares intent for the library to be installed into the standard - // location when the user invokes the "install" step (the default step when - // running `zig build`). - - const exe = b.addExecutable(.{ - .name = "%%project_name%%", - .root_source_file = .{ .path = "src/main.zig" }, - .target = target, - .optimize = optimize, - }); - exe.root_module.addImport("jetzig", jetzig_dep.module("jetzig")); - - exe.root_module.addImport("zmpl", jetzig_dep.module("zmpl")); - // This declares intent for the executable to be installed into the - // standard location when the user invokes the "install" step (the default - // step when running `zig build`). - b.installArtifact(exe); - exe.step.dependOn(&compile_view_step.step); - - // This *creates* a Run step in the build graph, to be executed when another - // step is evaluated that depends on it. The next line below will establish - // such a dependency. - const run_cmd = b.addRunArtifact(exe); - - // By making the run step depend on the install step, it will be run from the - // installation directory rather than directly from within the cache directory. - // This is not necessary, however, if the application depends on other installed - // files, this ensures they will be present and in the expected location. - run_cmd.step.dependOn(b.getInstallStep()); - - // This allows the user to pass arguments to the application in the build - // command itself, like this: `zig build run -- arg1 arg2 etc` - if (b.args) |args| { - run_cmd.addArgs(args); - } - - // This creates a build step. It will be visible in the `zig build --help` menu, - // and can be selected like this: `zig build run` - // This will evaluate the `run` step rather than the default, which is "install". - const run_step = b.step("run", "Run the app"); - run_step.dependOn(&run_cmd.step); - - // Creates a step for unit testing. This only builds the test executable - // but does not run it. - const lib_unit_tests = b.addTest(.{ - .root_source_file = .{ .path = "src/root.zig" }, - .target = target, - .optimize = optimize, - }); - - const run_lib_unit_tests = b.addRunArtifact(lib_unit_tests); - - const exe_unit_tests = b.addTest(.{ - .root_source_file = .{ .path = "src/main.zig" }, - .target = target, - .optimize = optimize, - }); - - const run_exe_unit_tests = b.addRunArtifact(exe_unit_tests); - - // Similar to creating the run step earlier, this exposes a `test` step to - // the `zig build --help` menu, providing a way for the user to request - // running the unit tests. - const test_step = b.step("test", "Run unit tests"); - test_step.dependOn(&run_lib_unit_tests.step); - test_step.dependOn(&run_exe_unit_tests.step); -} diff --git a/src/init/build.zig.zon b/src/init/build.zig.zon deleted file mode 100644 index a326967..0000000 --- a/src/init/build.zig.zon +++ /dev/null @@ -1,14 +0,0 @@ -.{ - .name = "%%project_name%%", - .version = "0.0.0", - .dependencies = .{ - .jetzig = .{ - .url = "https://github.com/jetzig-framework/jetzig/archive/0395d00b4b0f9e87a4bfab62c73ac047abb2e5da.tar.gz", - .hash = "122016141c39005c2149b3c6029b702332c346e3305f52376e1edbc5ee0295318e4c", - }, - }, - - .paths = .{ - "", - }, -} diff --git a/src/init/public/jetzig.png b/src/init/public/jetzig.png deleted file mode 100644 index 314d70c06242be3c69f1c1f5e50d26d3e9eda56a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 22828 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 Oz~JfX=d#Wzp$P!v4s&7v diff --git a/src/init/src/app/views/index.zig b/src/init/src/app/views/index.zig deleted file mode 100644 index a7dbd34..0000000 --- a/src/init/src/app/views/index.zig +++ /dev/null @@ -1,11 +0,0 @@ -const std = @import("std"); -const jetzig = @import("jetzig"); -const Request = jetzig.http.Request; -const Data = jetzig.data.Data; -const View = jetzig.views.View; - -pub fn index(request: *jetzig.http.Request, data: *jetzig.data.Data) anyerror!jetzig.views.View { - var object = try data.object(); - try object.put("message", data.string("Welcome to Jetzig!")); - return request.render(.ok); -} diff --git a/src/init/src/app/views/quotes.zig b/src/init/src/app/views/quotes.zig deleted file mode 100644 index 3f68156..0000000 --- a/src/init/src/app/views/quotes.zig +++ /dev/null @@ -1,34 +0,0 @@ -const std = @import("std"); -const jetzig = @import("jetzig"); - -const Request = jetzig.http.Request; -const Data = jetzig.data.Data; -const View = jetzig.views.View; - -pub fn get(id: []const u8, request: *Request, data: *Data) anyerror!View { - var body = try data.object(); - - const random_quote = try randomQuote(request.allocator); - - if (std.mem.eql(u8, id, "random")) { - try body.put("quote", data.string(random_quote.quote)); - try body.put("author", data.string(random_quote.author)); - } else { - try body.put("quote", data.string("If you can dream it, you can achieve it.")); - try body.put("author", data.string("Zig Ziglar")); - } - - return request.render(.ok); -} - -const Quote = struct { - quote: []const u8, - author: []const u8, -}; - -// Quotes taken from: https://gist.github.com/natebass/b0a548425a73bdf8ea5c618149fe1fce -fn randomQuote(allocator: std.mem.Allocator) !Quote { - const json = try std.fs.cwd().readFileAlloc(allocator, "src/app/config/quotes.json", 12684); - const quotes = try std.json.parseFromSlice([]Quote, allocator, json, .{}); - return quotes.value[std.crypto.random.intRangeLessThan(usize, 0, quotes.value.len)]; -} diff --git a/src/init/src/app/views/quotes/get.zmpl b/src/init/src/app/views/quotes/get.zmpl deleted file mode 100644 index dca9318..0000000 --- a/src/init/src/app/views/quotes/get.zmpl +++ /dev/null @@ -1,2 +0,0 @@ -
"{.quote}"
-
--{.author}
diff --git a/src/init/src/main.zig b/src/init/src/main.zig deleted file mode 100644 index a434403..0000000 --- a/src/init/src/main.zig +++ /dev/null @@ -1,15 +0,0 @@ -const std = @import("std"); - -pub const jetzig = @import("jetzig"); -pub const routes = @import("routes").routes; - -pub fn main() !void { - var gpa = std.heap.GeneralPurposeAllocator(.{}){}; - defer std.debug.assert(gpa.deinit() == .ok); - const allocator = gpa.allocator(); - - const app = try jetzig.init(allocator); - defer app.deinit(); - - try app.start(comptime jetzig.route(routes)); -}