Skip to content

Commit 8ef5c29

Browse files
authored
test: update examples to use latest chomp combinators and test through nix (#91)
Closes #90 Signed-off-by: purpleclay <purpleclaygh@gmail.com>
1 parent 7661a47 commit 8ef5c29

File tree

8 files changed

+204
-29
lines changed

8 files changed

+204
-29
lines changed

.github/workflows/nix.yml

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
name: nix
2+
on:
3+
push:
4+
branches:
5+
- main
6+
paths:
7+
- "**.go"
8+
- "**.nix"
9+
- "flake.lock"
10+
- "examples/**"
11+
pull_request:
12+
branches:
13+
- main
14+
paths:
15+
- "**.go"
16+
- "**.nix"
17+
- "flake.lock"
18+
- "examples/**"
19+
20+
concurrency:
21+
group: ${{ github.workflow }}-${{ github.ref }}
22+
cancel-in-progress: true
23+
24+
permissions:
25+
contents: read
26+
27+
jobs:
28+
examples:
29+
runs-on: ${{ matrix.os }}
30+
name: examples (${{ matrix.os }})
31+
strategy:
32+
matrix:
33+
os: [ubuntu-24.04, macos-latest]
34+
steps:
35+
- name: Checkout
36+
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6
37+
38+
- name: Install Nix
39+
uses: cachix/install-nix-action@4e002c8ec80594ecd40e759629461e26c8abed15 # v31
40+
with:
41+
github_access_token: ${{ secrets.GITHUB_TOKEN }}
42+
43+
- name: Setup Cachix
44+
uses: cachix/cachix-action@3ba601ff5bbb07c7220846facfa2cd81eeee15a1 # v16
45+
with:
46+
name: purpleclay
47+
authToken: "${{ secrets.GH_CACHIX }}"
48+
skipPush: true
49+
useDaemon: false
50+
51+
- name: Build and run git-diff example
52+
run: |
53+
nix build .#git-diff
54+
./result/bin/git-diff
55+
56+
- name: Build and run gpg example
57+
run: |
58+
nix build .#gpg
59+
./result/bin/gpg

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,13 @@
1919
!.envrc
2020
!flake.nix
2121
!flake.lock
22+
!*.nix
2223

2324
# Allow Go files
2425
!*.go
2526
!go.sum
2627
!go.mod
28+
!govendor.toml
2729

2830
# Recurse through sub-directories applying the same patterns
2931
!*/

default.nix

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
{
2+
lib,
3+
buildGoApplication,
4+
go-bin,
5+
}: let
6+
examples = [
7+
"git-diff"
8+
"gpg"
9+
];
10+
11+
mkExample = name:
12+
buildGoApplication {
13+
pname = "chomp-example-${name}";
14+
version = "0.1.0";
15+
src = ./examples;
16+
go = go-bin.fromGoMod ./examples/go.mod;
17+
modules = ./examples/govendor.toml;
18+
subPackages = [name];
19+
20+
# Provide the chomp library source for the local replace directive
21+
# (go.mod has: replace github.com/purpleclay/chomp => ../)
22+
localReplaces = {
23+
"github.com/purpleclay/chomp" = ./.;
24+
};
25+
26+
meta = with lib; {
27+
description = "Chomp parser combinator example: ${name}";
28+
homepage = "https://github.com/purpleclay/chomp";
29+
license = licenses.mit;
30+
};
31+
};
32+
in
33+
lib.genAttrs examples mkExample

examples/git-diff/main.go

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -95,21 +95,27 @@ func Parse(in string) (FileDiff, error) {
9595
}, nil
9696
}
9797

98+
// diffPath parses the diff header line and extracts the file path.
99+
// Uses Recognize to capture the raw path text from "a/path" format.
98100
func diffPath() chomp.Combinator[string] {
99101
return func(s string) (string, string, error) {
100102
// diff --git a/scan/scanner.go b/scan/scanner.go
101-
var rem string
102-
var err error
103-
104-
if rem, _, err = chomp.Tag("diff --git ")(s); err != nil {
105-
return rem, "", err
103+
rem, _, err := chomp.Tag("diff --git ")(s)
104+
if err != nil {
105+
return s, "", err
106106
}
107107

108-
var path string
109-
if rem, path, err = chomp.Until(" ")(rem); err != nil {
108+
// Use Recognize to capture "a/path" as raw text, then extract path after "/"
109+
var rawPath string
110+
rem, rawPath, err = chomp.Recognize(
111+
chomp.Pair(chomp.Tag("a/"), chomp.Until(" ")),
112+
)(rem)
113+
if err != nil {
110114
return rem, "", err
111115
}
112-
path = path[strings.Index(path, "/")+1:]
116+
117+
// Strip the "a/" prefix
118+
path := rawPath[2:]
113119

114120
rem, _, err = chomp.Eol()(rem)
115121
return rem, path, err
@@ -166,11 +172,7 @@ func diffChunk() chomp.Combinator[[]string] {
166172
+ "bytes"
167173
+)
168174
*/
169-
var rem string
170-
var err error
171-
172-
var changes []string
173-
rem, changes, err = chomp.Delimited(
175+
rem, changes, err := chomp.Delimited(
174176
chomp.Tag(hdrDelim+" "),
175177
chomp.SepPair(diffChunkHeaderChange(remPrefix), chomp.Tag(" "), diffChunkHeaderChange(addPrefix)),
176178
chomp.Eol(),
@@ -201,16 +203,24 @@ func diffChunk() chomp.Combinator[[]string] {
201203
}
202204
}
203205

206+
// diffChunkHeaderChange parses line number and optional count from chunk header.
207+
// Uses Verify to ensure line numbers are valid positive integers.
204208
func diffChunkHeaderChange(prefix string) chomp.Combinator[[]string] {
205209
return func(s string) (string, []string, error) {
210+
// Matches patterns like "-25" or "+3,3"
206211
rem, _, err := chomp.Tag(prefix)(s)
207212
if err != nil {
208213
return rem, nil, err
209214
}
210215

211216
return chomp.All(
212-
chomp.While(chomp.IsDigit),
213-
chomp.Opt(chomp.Prefixed(chomp.While(chomp.IsDigit), chomp.Tag(","))),
217+
// Line number - verify it's a valid positive integer
218+
chomp.Verify(chomp.Digit(), func(s string) bool {
219+
n, err := strconv.Atoi(s)
220+
return err == nil && n >= 0
221+
}),
222+
// Optional count (,N) - defaults to empty string if not present
223+
chomp.Opt(chomp.Prefixed(chomp.Digit(), chomp.Tag(","))),
214224
)(rem)
215225
}
216226
}

examples/govendor.toml

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# Generated by govendor. DO NOT EDIT.
2+
3+
schema = 2
4+
hash = "sha256-yYymUduCjOVIgSynlI/pyuLsq8JO57L4CYiuq/do7nk="
5+
6+
[mod]
7+
[mod."github.com/aymanbagabas/go-osc52/v2"]
8+
version = "v2.0.1"
9+
hash = "sha256-6Bp0jBZ6npvsYcKZGHHIUSVSTAMEyieweAX2YAKDjjg="
10+
go = "1.16"
11+
packages = ["github.com/aymanbagabas/go-osc52/v2"]
12+
[mod."github.com/charmbracelet/lipgloss"]
13+
version = "v0.12.1"
14+
hash = "sha256-Uqv5hbHAxe7u94iBbAhR/de4VwWbIAw+t89We4ufiss="
15+
go = "1.18"
16+
packages = ["github.com/charmbracelet/lipgloss"]
17+
[mod."github.com/charmbracelet/x/ansi"]
18+
version = "v0.1.4"
19+
hash = "sha256-hfyC3QY43qeXJGngTKdCDMoawfIJHeAC3BW4Wj461KQ="
20+
go = "1.18"
21+
packages = ["github.com/charmbracelet/x/ansi", "github.com/charmbracelet/x/ansi/parser"]
22+
[mod."github.com/lucasb-eyer/go-colorful"]
23+
version = "v1.2.0"
24+
hash = "sha256-Gg9dDJFCTaHrKHRR1SrJgZ8fWieJkybljybkI9x0gyE="
25+
go = "1.12"
26+
packages = ["github.com/lucasb-eyer/go-colorful"]
27+
[mod."github.com/mattn/go-isatty"]
28+
version = "v0.0.20"
29+
hash = "sha256-qhw9hWtU5wnyFyuMbKx+7RB8ckQaFQ8D+8GKPkN3HHQ="
30+
go = "1.15"
31+
packages = ["github.com/mattn/go-isatty"]
32+
[mod."github.com/mattn/go-runewidth"]
33+
version = "v0.0.15"
34+
hash = "sha256-WP39EU2UrQbByYfnwrkBDoKN7xzXsBssDq3pNryBGm0="
35+
go = "1.9"
36+
packages = ["github.com/mattn/go-runewidth"]
37+
[mod."github.com/muesli/termenv"]
38+
version = "v0.15.2"
39+
hash = "sha256-Eum/SpyytcNIchANPkG4bYGBgcezLgej7j/+6IhqoMU="
40+
go = "1.17"
41+
packages = ["github.com/muesli/termenv"]
42+
[mod."github.com/purpleclay/chomp"]
43+
version = "v0.0.0-20240108065605-b5889a9b1ff2"
44+
hash = "sha256-F5lIAlrnoWNlRq6mNMmgEK+zXTtQLFZhDTyoWF7nSHc="
45+
go = "1.22.12"
46+
packages = ["github.com/purpleclay/chomp"]
47+
replaced = "github.com/purpleclay/chomp"
48+
local = "../"
49+
[mod."github.com/rivo/uniseg"]
50+
version = "v0.4.7"
51+
hash = "sha256-rDcdNYH6ZD8KouyyiZCUEy8JrjOQoAkxHBhugrfHjFo="
52+
go = "1.18"
53+
packages = ["github.com/rivo/uniseg"]
54+
[mod."golang.org/x/sys"]
55+
version = "v0.19.0"
56+
hash = "sha256-cmuL31TYLJmDm/fDnI2Sn0wB88cpdOHV1+urorsJWx4="
57+
go = "1.18"
58+
packages = ["golang.org/x/sys/unix", "golang.org/x/sys/windows"]

examples/gpg/main.go

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -133,18 +133,13 @@ func key() chomp.Combinator[[]string] {
133133
}
134134
}
135135

136+
// colon parses a colon-delimited field, using Suffixed to consume the trailing colon.
136137
func colon() chomp.Combinator[string] {
137-
return func(s string) (string, string, error) {
138-
// <any>:
139-
rem, ext, err := chomp.Pair(chomp.Until(":"), chomp.Tag(":"))(s)
140-
if err != nil {
141-
return rem, "", err
142-
}
143-
144-
return rem, ext[0], nil
145-
}
138+
return chomp.Suffixed(chomp.Until(":"), chomp.Tag(":"))
146139
}
147140

141+
// fingerprint parses the fingerprint line (fpr) and validates it is 40 hex characters.
142+
// Uses Verify to ensure the fingerprint has the correct format.
148143
func fingerprint() chomp.Combinator[string] {
149144
return func(s string) (string, string, error) {
150145
// fpr:::::::::28BF65E18407FD2966565284AAC7E54CBD73F690:
@@ -155,8 +150,12 @@ func fingerprint() chomp.Combinator[string] {
155150
return rem, "", err
156151
}
157152

153+
// Use Verify to ensure fingerprint is exactly 40 hex characters
158154
var fpr string
159-
if rem, fpr, err = chomp.Until(":")(rem); err != nil {
155+
if rem, fpr, err = chomp.Verify(
156+
chomp.HexDigit(),
157+
func(s string) bool { return len(s) == 40 },
158+
)(rem); err != nil {
160159
return rem, "", err
161160
}
162161

@@ -167,6 +166,8 @@ func fingerprint() chomp.Combinator[string] {
167166
}
168167
}
169168

169+
// keygrip parses the keygrip line (grp) and validates it is 40 hex characters.
170+
// Uses Verify to ensure the keygrip has the correct format.
170171
func keygrip() chomp.Combinator[string] {
171172
return func(s string) (string, string, error) {
172173
// grp:::::::::12E86CE47CEB942D2A65B4D02106657BA8D0C92B:
@@ -177,8 +178,12 @@ func keygrip() chomp.Combinator[string] {
177178
return rem, "", err
178179
}
179180

181+
// Use Verify to ensure keygrip is exactly 40 hex characters
180182
var grp string
181-
if rem, grp, err = chomp.Until(":")(rem); err != nil {
183+
if rem, grp, err = chomp.Verify(
184+
chomp.HexDigit(),
185+
func(s string) bool { return len(s) == 40 },
186+
)(rem); err != nil {
182187
return rem, "", err
183188
}
184189

flake.lock

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

flake.nix

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,15 @@
5151
};
5252
};
5353
};
54+
examples = pkgs.callPackage ./default.nix {};
5455
in
5556
with pkgs; {
57+
packages =
58+
examples
59+
// {
60+
default = examples.git-diff;
61+
};
62+
5663
devShells.default = mkShell {
5764
inherit (pre-commit-check) shellHook;
5865

@@ -62,6 +69,7 @@
6269
(go-bin.fromGoMod "${self}/go.mod")
6370
gofumpt
6471
golangci-lint
72+
go-overlay.packages.${system}.govendor
6573
nil
6674
typos
6775
]

0 commit comments

Comments
 (0)