From 320c2706ae8266a4936a49bd3db33d939a878663 Mon Sep 17 00:00:00 2001 From: Bob Farrell Date: Tue, 5 Nov 2024 17:52:23 +0000 Subject: [PATCH] WIP --- cli/commands/generate/migration.zig | 11 ++++- cli/util.zig | 3 +- src/commands/database.zig | 15 +++++- src/compile_static_routes.zig | 2 +- src/jetzig/util.zig | 74 +++++++++++++++++++++++++++++ 5 files changed, 100 insertions(+), 5 deletions(-) diff --git a/cli/commands/generate/migration.zig b/cli/commands/generate/migration.zig index 34b20e4..0d6194c 100644 --- a/cli/commands/generate/migration.zig +++ b/cli/commands/generate/migration.zig @@ -4,7 +4,7 @@ const jetquery = @import("jetquery"); /// Run the migration generator. Create a migration in `src/app/database/migrations/` pub fn run(allocator: std.mem.Allocator, cwd: std.fs.Dir, args: [][]const u8, help: bool) !void { - if (help or args.len != 1) { + if (help or args.len < 1) { std.debug.print( \\Generate a new Migration. Migrations modify the application's database schema. \\ @@ -20,6 +20,10 @@ pub fn run(allocator: std.mem.Allocator, cwd: std.fs.Dir, args: [][]const u8, he } const name = args[0]; + const command = if (args.len > 1) + try std.mem.join(allocator, " ", args[1..]) + else + null; const migrations_dir = try cwd.makeOpenPath( try std.fs.path.join(allocator, &.{ "src", "app", "database", "migrations" }), @@ -28,7 +32,10 @@ pub fn run(allocator: std.mem.Allocator, cwd: std.fs.Dir, args: [][]const u8, he const migration = jetquery.Migration.init( allocator, name, - .{ .migrations_path = try migrations_dir.realpathAlloc(allocator, ".") }, + .{ + .migrations_path = try migrations_dir.realpathAlloc(allocator, "."), + .command = command, + }, ); try migration.save(); } diff --git a/cli/util.zig b/cli/util.zig index f0b2d22..7376521 100644 --- a/cli/util.zig +++ b/cli/util.zig @@ -26,7 +26,8 @@ pub fn printFailure() void { std.debug.print(" ❌\n", .{}); } -/// Verifies that cwd is the root of a Jetzig project +/// Detects a Jetzig project directory either in the current directory or one of its parent +/// directories. pub fn detectJetzigProjectDir() !std.fs.Dir { var dir = try std.fs.cwd().openDir(".", .{}); const max_parent_dirs: usize = 100; // Prevent symlink loops or other weird stuff. diff --git a/src/commands/database.zig b/src/commands/database.zig index 28a6ff4..957dad6 100644 --- a/src/commands/database.zig +++ b/src/commands/database.zig @@ -81,6 +81,9 @@ pub fn main() !void { } }, .schema => { + var cwd = try jetzig.util.detectJetzigProjectDir(); + defer cwd.close(); + const Repo = jetquery.Repo(config.adapter, Schema); var repo = try Repo.loadConfig( allocator, @@ -90,9 +93,19 @@ pub fn main() !void { const reflect = @import("jetquery_reflect").Reflect(config.adapter, Schema).init( allocator, &repo, + .{ + .import_jetquery = + \\@import("jetzig").jetquery + , + }, ); const schema = try reflect.generateSchema(); - std.debug.print("{s}\n", .{schema}); + const path = try cwd.realpathAlloc( + allocator, + try std.fs.path.join(allocator, &.{ "src", "app", "database", "Schema.zig" }), + ); + try jetzig.util.createFile(path, schema); + std.log.info("Database schema written to `{s}`.", .{path}); }, } } diff --git a/src/compile_static_routes.zig b/src/compile_static_routes.zig index e451de8..cbbbca4 100644 --- a/src/compile_static_routes.zig +++ b/src/compile_static_routes.zig @@ -11,7 +11,7 @@ else pub const database_lazy_connect = true; pub const jetzig_options = struct { - pub const Schema = @import("jetquery_schema"); + pub const Schema = @import("Schema"); }; pub fn main() !void { diff --git a/src/jetzig/util.zig b/src/jetzig/util.zig index 1e8994e..f60535d 100644 --- a/src/jetzig/util.zig +++ b/src/jetzig/util.zig @@ -125,3 +125,77 @@ pub fn writeAnsi(file: std.fs.File, writer: anytype, text: []const u8) !void { } } } + +/// Create a file at the given location and write content. Creates subpaths if not present. +pub fn createFile(path: []const u8, content: []const u8) !void { + if (std.fs.path.dirname(path)) |dirname| { + std.fs.makeDirAbsolute(dirname) catch |err| { + switch (err) { + error.PathAlreadyExists => {}, + else => return err, + } + }; + } + + const file = try std.fs.createFileAbsolute(path, .{ .truncate = true }); + try file.writeAll(content); + file.close(); +} + +/// Detects a Jetzig project directory either in the current directory or one of its parent +/// directories. +pub fn detectJetzigProjectDir() !std.fs.Dir { + var dir = try std.fs.cwd().openDir(".", .{}); + const max_parent_dirs: usize = 100; // Prevent symlink loops or other weird stuff. + + for (0..max_parent_dirs) |_| { + if (try isPath(dir, "build.zig", .file) and try isPath(dir, "src/app/views", .dir)) return dir; + + dir = dir.openDir("..", .{}) catch |err| { + switch (err) { + error.FileNotFound, error.NotDir => { + std.debug.print( + "Encountered unexpected detecting Jetzig project directory: {s}\n", + .{@errorName(err)}, + ); + return error.JetzigCommandError; + }, + else => return err, + } + }; + continue; + } + + std.debug.print( + \\Exceeded maximum parent directory depth. + \\Unable to detect Jetzig project directory. + \\ + , + .{}, + ); + return error.JetzigCommandError; +} + +fn isPath(dir: std.fs.Dir, sub_path: []const u8, path_type: enum { file, dir }) !bool { + switch (path_type) { + .file => { + _ = dir.statFile(sub_path) catch |err| { + switch (err) { + error.FileNotFound => return false, + else => return err, + } + }; + return true; + }, + .dir => { + var test_dir = dir.openDir(sub_path, .{}) catch |err| { + switch (err) { + error.FileNotFound, error.NotDir => return false, + else => return err, + } + }; + test_dir.close(); + return true; + }, + } +}