Skip to content

Commit

Permalink
feat: add list command (#4)
Browse files Browse the repository at this point in the history
  • Loading branch information
ivansantiagojr authored Jan 7, 2025
1 parent ed81d2d commit 395dd2f
Show file tree
Hide file tree
Showing 8 changed files with 161 additions and 105 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/cd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ jobs:
version: 0.13.0

- name: Build
run: zig build -Dtarget=${{ matrix.TARGET }}
run: zig build -Dtarget=${{ matrix.TARGET }} --release

- name: Renaming the binary
run: mv zig-out/bin/zignr zig-out/bin/binary-${{ env.RELEASE_VERSION }}-${{ matrix.TARGET }}
Expand Down
6 changes: 2 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,10 @@ on:

jobs:
build:
name: "Build with args: '${{ matrix.OPTIMIZE }}'"
name: "Building Test"
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
OPTIMIZE: [""]
steps:
- name: Checkout the repository
uses: actions/checkout@v3
Expand All @@ -26,7 +24,7 @@ jobs:
version: 0.13.0

- name: Build
run: zig build ${{ matrix.OPTIMIZE }}
run: zig build --release

- name: Check formatting
run: zig fmt --check .
Expand Down
39 changes: 24 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,6 @@
This is a CLI tool to generate `.gitgnore` files written in zig.


zignr is not finished, and is just a project I develop to learn zig. I will link my references below.

First of all, zignr is heavily inspired by [ignr.py](https://github.com/Antrikshy/ignr.py), which uses the [gitignore.io](https://www.toptal.com/developers/gitignore) API.

Zig references I used:

- [Zig Cookbook](https://zigcc.github.io/zig-cookbook/)
- [Zig documentation](https://ziglang.org/documentation/master/)
- [Zig Common Tasks](https://renatoathaydes.github.io/zig-common-tasks/)
- [Ziglings](https://codeberg.org/ziglings)
- [Zig Guides](https://github.com/tr1ckydev/zig_guides)


# Installation

Expand All @@ -28,9 +16,30 @@ curl -sSL https://raw.githubusercontent.com/brasilisclub/zignr/main/install.sh |
# Usage

To create a .gitgnore file you can simply use `zignr <language> >> .gitnore`. This command will overwrite your .gitignore file. Example:
To create a .gitgnore file you can simply use `zignr <language> > .gitnore`. This command will overwrite your .gitignore file. Example:
```bash
zignr zig > .gitgnore
```
zignr zig >> .gitgnore

Multi language example:
```bash
zignr zig,python,lua > .gitgnore
```

To see the list of all .gitignore templates just use `zignr list`, but I did not implemented that yet.
To see the list of all .gitignore templates you can call `zignr` with, just use:
```bash
zignr list
```

# References
This project started as a Zig learning experience (and still is), so I will link my references below:
First of all, zignr is heavily inspired by [ignr.py](https://github.com/Antrikshy/ignr.py), which uses the [gitignore.io](https://www.toptal.com/developers/gitignore) API.

Zig references I used:

- [Zig Cookbook](https://zigcc.github.io/zig-cookbook/)
- [Zig documentation](https://ziglang.org/documentation/master/)
- [Zig Common Tasks](https://renatoathaydes.github.io/zig-common-tasks/)
- [Ziglings](https://codeberg.org/ziglings)
- [Zig Guides](https://github.com/tr1ckydev/zig_guides)
- [Introduction to Zig](https://pedropark99.github.io/zig-book/)
31 changes: 3 additions & 28 deletions build.zig
Original file line number Diff line number Diff line change
@@ -1,54 +1,29 @@
const std = @import("std");

// 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 optimize = b.standardOptimizeOption(.{ .preferred_optimize_mode = .ReleaseSafe });

const exe = b.addExecutable(.{
.name = "zignr",
// In this case the main source file is merely a path, however, in more
// complicated build scripts, this could be a generated file.
.root_source_file = b.path("src/main.zig"),
.target = target,
.optimize = optimize,
.strip = true,
.single_threaded = true,
});

// 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);

// 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);
}
88 changes: 60 additions & 28 deletions install.sh
Original file line number Diff line number Diff line change
@@ -1,30 +1,62 @@
#!/bin/bash

binary_url="https://github.com/ivansantiagojr/zignr/releases/download/v0.1.1/binary-0.1.1-x86_64-linux"
binary_name="zignr"

echo "Downloading zignr..."
wget -q "$binary_url" -O "$binary_name"

if [ $? -ne 0 ]; then
echo "Failed to download zignr."
exit 1
fi

echo "Making zignr executable..."
chmod +x "$binary_name"

echo "Moving zignr to ~/.local/bin..."
mv "$binary_name" "$HOME/.local/bin/$binary_name"

# Verify installation
if [ $? -eq 0 ]; then
echo "zignr installed successfully!"
else
echo "Failed to move zignr to ~/.local/bin. You might need sudo privileges."
exit 1
fi

echo
echo "add ~/.local/bin to you PATH so you can run zignr from anywhere"
echo "then use run zignr"
APP_VERSION="v0.1.2"
BASE_URL="https://github.com/brasilisclub/zignr/releases/download/$APP_VERSION"

BINARY_URL_LINUX="$BASE_URL/BINARY-0.1.2-X86_64-LINUX"
BINARY_URL_MACOS_ARM="$BASE_URL/BINARY-0.1.2-AARCH64-MACOS"
BINARY_URL_MACOS="$BASE_URL/binary-0.1.2-x86_64-macos"
APP_NAME="zignr"
OS_TYPE=$OSTYPE
CPU_TYPE=$CPUTYPE


download_and_create_executable() {
echo "Downloading zignr..."
wget -q "$binary_url" -O "$APP_NAME"

if [ $? -ne 0 ]; then
echo "Failed to download zignr."
exit 1
fi

echo "Making zignr executable..."
chmod +x "$APP_NAME"
}

linux_install () {
echo "Moving zignr to ~/.local/bin..."
mv "$APP_NAME" "$HOME/.local/bin/$APP_NAME"

# Verify installation
if [ $? -eq 0 ]; then
echo "zignr installed successfully!"
else
echo "Failed to move zignr to ~/.local/bin. You might need sudo privileges."
exit 1
fi

echo
echo "Add ~/.local/bin to you PATH so you can run zignr from anywhere"
echo "Then use run zignr"
}

macos_install(){
echo "Mac installation will be supported soon"
}

case "$OSTYPE" in
linux-gnu)
binary_url=$BINARY_URL_LINUX
download_and_create_executable
linux_install
;;
darwin)
if [[ $CPU_TYPE == "x86_64" ]]; then
binary_url=$BINARY_URL_MACOS
fi
binary_url=$BINARY_URL_MACOS_ARM
download_and_create_executable
macos_install
;;
esac
40 changes: 40 additions & 0 deletions src/api.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
const std = @import("std");
const http = std.http;

const base_url = "https://www.toptal.com/developers/gitignore/api/";

const RequestError = error{NotFound};

pub fn request(allocator: std.mem.Allocator, args: [][:0]u8, path: []const u8) ![]u8 {
var client = http.Client{ .allocator = allocator };
defer client.deinit();
var url_buffer: [256]u8 = undefined;
const url_to_request = std.fmt.bufPrint(&url_buffer, "{s}{s}", .{ base_url, path }) catch |err| {
return err;
};

const uri = try std.Uri.parse(url_to_request);
const buf = try allocator.alloc(u8, 1024 * 1014 * 4);
defer allocator.free(buf);

var req = try client.open(.GET, uri, .{ .server_header_buffer = buf });
defer req.deinit();

try req.send();
try req.finish();
try req.wait();

if (req.response.status != .ok) {
std.debug.print(
\\Something went wrong. Check you passed only valid languages/templates.
\\Use: '{s}' to see the available languages/templates
, .{args[0]});
return RequestError.NotFound;
}

var rdr = req.reader();
const body = try rdr.readAllAlloc(allocator, 1024 * 1024 * 4);
//defer allocator.free(body);

return body;
}
27 changes: 27 additions & 0 deletions src/commands.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
const std = @import("std");
const print = std.io.getStdOut().writer();
const request = @import("api.zig").request;

// get language .gitgnore command
pub fn getGitignoreContent(args: [][:0]u8, languages: []const u8) !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();

const allocator = gpa.allocator();
const body = try request(allocator, args, languages);
defer allocator.free(body);

try print.print("{s}\n", .{body});
}

// list command
pub fn listAvailableLanguages(args: [][:0]u8) !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();

const body = try request(allocator, args, "list");
defer allocator.free(body);

try print.print("{s}\n", .{body});
}
33 changes: 4 additions & 29 deletions src/main.zig
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
const std = @import("std");
const print = std.io.getStdOut().writer();
const http = std.http;
const commands = @import("commands.zig");

pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
Expand All @@ -16,36 +17,10 @@ pub fn main() !void {
}

if (std.mem.eql(u8, args[1], "list")) {
std.debug.print("Not implemented yet\n", .{});
try commands.listAvailableLanguages(args);
return;
}
const language = std.mem.sliceTo(args[1], 0);

var client = http.Client{ .allocator = allocator };
defer client.deinit();
const base_url = "https://www.toptal.com/developers/gitignore/api/";
var url_buffer: [256]u8 = undefined;
const url_to_request = try std.fmt.bufPrint(&url_buffer, "{s}{s}", .{ base_url, language });

const uri = try std.Uri.parse(url_to_request);
const buf = try allocator.alloc(u8, 1024 * 1014 * 4);
defer allocator.free(buf);

var req = try client.open(.GET, uri, .{ .server_header_buffer = buf });
defer req.deinit();

try req.send();
try req.finish();
try req.wait();

if (req.response.status != .ok) {
std.debug.print("Probably not a valid language, use: '{s} list' to see the available languages\n", .{args[0]});
return;
}

var rdr = req.reader();
const body = try rdr.readAllAlloc(allocator, 1024 * 1024 * 4);
defer allocator.free(body);

try print.print("{s}\n", .{body});
const language = std.mem.sliceTo(args[1], 0);
try commands.getGitignoreContent(args, language);
}

0 comments on commit 395dd2f

Please sign in to comment.