├── .gitignore ├── .gitmodules ├── LICENSE ├── README.md ├── build.zig └── src └── main.zig /.gitignore: -------------------------------------------------------------------------------- 1 | # Zig programming language 2 | 3 | zig-cache/ 4 | zig-out/ 5 | build/ 6 | build-*/ 7 | docgen_tmp/ 8 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "gitignore"] 2 | path = gitignore 3 | url = git@github.com:toptal/gitignore.git 4 | 5 | [submodule "src/zdf"] 6 | path = src/zdf 7 | url = git@github.com:dmbfm/zdf.git 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Daniel Fortes 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # gi 2 | 3 | Small program that generates .gitignore files. The templates are taken from 4 | [toptal/gitignore](https://github.com/toptal/gitignore). They are all bundled 5 | in the compiled binary, so there is no need to keep a folder with the templates, making it easier to install. 6 | 7 | ## Building and installation 8 | Make sure you have the [zig](https://ziglang.org) compiler [installed](https://ziglang.org/download/) on your machine. Then: 9 | ``` 10 | git clone --recurse-submodules https://github.com/dmbfm/gi.git 11 | cd gi 12 | zig build -Drelease-safe --prefix ~/.local 13 | ``` 14 | 15 | to install `gi` to `~/.local/bin` (or replace this with any other location on your PATH). 16 | 17 | 18 | ## Usage 19 | 20 | ``` 21 | Usage: gi [...] 22 | ``` 23 | 24 | Just call `gi` followed by one ore more template names. 25 | 26 | ``` 27 | $ gi zig > .gitignore 28 | $ cat .gitignore 29 | # Zig programming language 30 | 31 | zig-cache/ 32 | zig-out/ 33 | build/ 34 | build-*/ 35 | docgen_tmp/ 36 | ``` 37 | 38 | To list all the avilable templates, call `gi --list` or `gi -l`. 39 | 40 | -------------------------------------------------------------------------------- /build.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | const zdf = @import("./src/zdf/src/main.zig"); 3 | 4 | const templatesPath = "./gitignore/templates"; 5 | const filenameWithoutExtension = zdf.utils.filenameWithoutExtension; 6 | 7 | fn countFiles(path: []const u8) !usize { 8 | var dir = try std.fs.cwd().openDir(path, .{ .iterate = true }); 9 | defer dir.close(); 10 | 11 | var walker = try dir.walk(std.heap.page_allocator); 12 | defer walker.deinit(); 13 | 14 | var n: usize = 0; 15 | 16 | while (try walker.next()) |entry| { 17 | if (std.mem.eql(u8, std.fs.path.extension(entry.path), ".gitignore")) { 18 | n += 1; 19 | } 20 | } 21 | 22 | return n; 23 | } 24 | 25 | pub fn build(b: *std.build.Builder) !void { 26 | var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); 27 | defer arena.deinit(); 28 | const allocator = &arena.allocator; 29 | 30 | // Standard target options allows the person running `zig build` to choose 31 | // what target to build for. Here we do not override the defaults, which 32 | // means any target is allowed, and the default is native. Other options 33 | // for restricting supported target set are available. 34 | const target = b.standardTargetOptions(.{}); 35 | 36 | // Standard release options allow the person running `zig build` to select 37 | // between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. 38 | const mode = b.standardReleaseOptions(); 39 | 40 | const exe = b.addExecutable("gi", "src/main.zig"); 41 | // b.addUserInputOption 42 | exe.addPackagePath("zdf", "./src/zdf/src/main.zig"); 43 | exe.setTarget(target); 44 | exe.setBuildMode(mode); 45 | exe.install(); 46 | 47 | const run_cmd = exe.run(); 48 | run_cmd.step.dependOn(b.getInstallStep()); 49 | if (b.args) |args| { 50 | run_cmd.addArgs(args); 51 | } 52 | 53 | const run_step = b.step("run", "Run the app"); 54 | run_step.dependOn(&run_cmd.step); 55 | 56 | var numFiles = try countFiles(templatesPath); 57 | 58 | var dir = try std.fs.cwd().openDir(templatesPath, .{ .iterate = true }); 59 | var walker = try dir.walk(allocator); 60 | defer walker.deinit(); 61 | 62 | // var opts = b.addOptions(); 63 | // opts.addOption() 64 | 65 | // _ = numFiles; 66 | var files: [][]const u8 = try allocator.alloc([]const u8, numFiles); 67 | var contents: [][]const u8 = try allocator.alloc([]const u8, numFiles); 68 | 69 | defer allocator.free(files); 70 | defer allocator.free(contents); 71 | 72 | var i: usize = 0; 73 | while (try walker.next()) |entry| { 74 | if (std.mem.eql(u8, std.fs.path.extension(entry.path), ".gitignore")) { 75 | files[i] = try std.mem.dupe(allocator, u8, filenameWithoutExtension(entry.path)); 76 | var f = try dir.openFile(entry.basename, .{}); 77 | defer f.close(); 78 | 79 | var content = try f.readToEndAlloc(allocator, 1024 * 1024 * 1024); 80 | contents[i] = content; 81 | 82 | i += 1; 83 | } 84 | } 85 | 86 | var opts = b.addOptions(); 87 | opts.addOption([]const []const u8, "filenames", files); 88 | opts.addOption([]const []const u8, "contents", contents); 89 | exe.addOptions("data", opts); 90 | } 91 | -------------------------------------------------------------------------------- /src/main.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | const zdf = @import("zdf"); 3 | const data = @import("data"); 4 | 5 | const stdout = std.io.getStdOut().writer(); 6 | 7 | fn usage() !void { 8 | try stdout.writeAll("Usage: gi [-l, --list] [...]\n"); 9 | } 10 | 11 | fn printAvailable() !void { 12 | const templateNames = data.filenames; 13 | 14 | try stdout.writeAll("Available templates:\n"); 15 | for (templateNames) |name| { 16 | try stdout.print("\t{s}\n", .{name}); 17 | } 18 | } 19 | 20 | pub fn main() anyerror!void { 21 | var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); 22 | defer arena.deinit(); 23 | const allocator = &arena.allocator; 24 | 25 | var args = try zdf.Args.init(allocator); 26 | defer args.deinit(); 27 | 28 | if (args.argc < 2) { 29 | try usage(); 30 | return; 31 | } 32 | 33 | if (args.has("-l") or args.has("--list")) { 34 | try printAvailable(); 35 | return; 36 | } 37 | 38 | const filenames = data.filenames; 39 | const contents = data.contents; 40 | 41 | for (filenames) |filename, i| { 42 | for (args.argv[1..]) |arg| { 43 | if (std.ascii.eqlIgnoreCase(arg, filename)) { 44 | try stdout.writeAll(contents[i]); 45 | break; 46 | } 47 | } 48 | } 49 | } 50 | --------------------------------------------------------------------------------