detached c274f18

feat: scaffold purego-pipewire generator repo

commit
c274f181da87d1239b326d991a62c31a6a093898
author
brice · · 2026-04-09 05:08 UTC
parent
none (root commit)
signature
GPG VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · arch-gpg Verified for the committer email
15 files · +187 -0
A .mockery.yml +21 -0
@@ -0,0 +1,21 @@
1+with-expecter: true
2+dir: "{{.InterfaceDir}}/mocks"
3+outpkg: mocks
4+packages:
5+ github.com/bnema/purego-pipewire/internal/ports/out:
6+ interfaces:
7+ CAPI:
8+ InitAPI:
9+ LoopAPI:
10+ ContextAPI:
11+ CoreAPI:
12+ RegistryAPI:
13+ StreamAPI:
14+ github.com/bnema/purego-pipewire/pipewire:
15+ interfaces:
16+ Runtime:
17+ MainLoop:
18+ Context:
19+ Core:
20+ Registry:
21+ Stream:
@@ -0,0 +1,21 @@
1+with-expecter: true
2+dir: "{{.InterfaceDir}}/mocks"
3+outpkg: mocks
4+packages:
5+ github.com/bnema/purego-pipewire/internal/ports/out:
6+ interfaces:
7+ CAPI:
8+ InitAPI:
9+ LoopAPI:
10+ ContextAPI:
11+ CoreAPI:
12+ RegistryAPI:
13+ StreamAPI:
14+ github.com/bnema/purego-pipewire/pipewire:
15+ interfaces:
16+ Runtime:
17+ MainLoop:
18+ Context:
19+ Core:
20+ Registry:
21+ Stream:
A README.md +31 -0
@@ -0,0 +1,31 @@
1+# purego-pipewire
2+
3+Pure Go bindings for PipeWire using [purego](https://github.com/ebitengine/purego).
4+
5+## Architecture
6+
7+This package follows the same layer split as other purego-* projects:
8+
9+- `internal/capi` — generated raw function types and registration helpers
10+- `internal/ports/{in,out}` — generated port interfaces
11+- `internal/core` — handwritten lifecycle logic
12+- `internal/loader` — `dlopen` for PipeWire and SPA libs
13+- `pipewire/` — public Go-facing wrappers
14+- `spa/` — public constants and helpers
15+
16+## Regenerating bindings
17+
18+Normal contributors should run:
19+
20+ go generate ./...
21+
22+This uses checked-in model files under `gen/` (e.g. `gen/pipewire.json`).
23+
24+Mocks are generated by [mockery](https://github.com/vektra/mockery):
25+
26+ mockery
27+
28+## Requirements
29+
30+- Go 1.24+
31+- Linux with PipeWire 0.3 runtime libraries
@@ -0,0 +1,31 @@
1+# purego-pipewire
2+
3+Pure Go bindings for PipeWire using [purego](https://github.com/ebitengine/purego).
4+
5+## Architecture
6+
7+This package follows the same layer split as other purego-* projects:
8+
9+- `internal/capi` — generated raw function types and registration helpers
10+- `internal/ports/{in,out}` — generated port interfaces
11+- `internal/core` — handwritten lifecycle logic
12+- `internal/loader` — `dlopen` for PipeWire and SPA libs
13+- `pipewire/` — public Go-facing wrappers
14+- `spa/` — public constants and helpers
15+
16+## Regenerating bindings
17+
18+Normal contributors should run:
19+
20+ go generate ./...
21+
22+This uses checked-in model files under `gen/` (e.g. `gen/pipewire.json`).
23+
24+Mocks are generated by [mockery](https://github.com/vektra/mockery):
25+
26+ mockery
27+
28+## Requirements
29+
30+- Go 1.24+
31+- Linux with PipeWire 0.3 runtime libraries
A cmd/pipewiregen/internal/emitter/emitter.go +2 -0
@@ -0,0 +1,2 @@
1+// Package emitter renders generated Go source files from the binding model.
2+package emitter
@@ -0,0 +1,2 @@
1+// Package emitter renders generated Go source files from the binding model.
2+package emitter
A cmd/pipewiregen/internal/emitter/emitter_test.go +1 -0
@@ -0,0 +1,1 @@
1+package emitter
@@ -0,0 +1,1 @@
1+package emitter
A cmd/pipewiregen/internal/emitter/templates/model_summary.tmpl +4 -0
@@ -0,0 +1,4 @@
1+{{- /* model_summary.tmpl: debugging template for model inspection */ -}}
2+Libraries: {{ len .Libraries }}
3+Groups: {{ len .Groups }}
4+Symbols: {{ len .Symbols }}
@@ -0,0 +1,4 @@
1+{{- /* model_summary.tmpl: debugging template for model inspection */ -}}
2+Libraries: {{ len .Libraries }}
3+Groups: {{ len .Groups }}
4+Symbols: {{ len .Symbols }}
A cmd/pipewiregen/internal/model/model.go +27 -0
@@ -0,0 +1,27 @@
1+package model
2+
3+// Model represents the checked-in binding model for PipeWire/SPA code generation.
4+type Model struct {
5+ Libraries []Library `json:"libraries"`
6+ Groups []Group `json:"groups"`
7+ Symbols []Symbol `json:"symbols"`
8+}
9+
10+// Library represents a shared library to load at runtime.
11+type Library struct {
12+ Name string `json:"name"`
13+ SOName string `json:"soname"`
14+}
15+
16+// Group represents a logical grouping of symbols.
17+type Group struct {
18+ Name string `json:"name"`
19+ Symbols []string `json:"symbols"`
20+}
21+
22+// Symbol represents a single C function to bind.
23+type Symbol struct {
24+ Name string `json:"name"`
25+ Library string `json:"library"`
26+ Signature string `json:"signature"`
27+}
@@ -0,0 +1,27 @@
1+package model
2+
3+// Model represents the checked-in binding model for PipeWire/SPA code generation.
4+type Model struct {
5+ Libraries []Library `json:"libraries"`
6+ Groups []Group `json:"groups"`
7+ Symbols []Symbol `json:"symbols"`
8+}
9+
10+// Library represents a shared library to load at runtime.
11+type Library struct {
12+ Name string `json:"name"`
13+ SOName string `json:"soname"`
14+}
15+
16+// Group represents a logical grouping of symbols.
17+type Group struct {
18+ Name string `json:"name"`
19+ Symbols []string `json:"symbols"`
20+}
21+
22+// Symbol represents a single C function to bind.
23+type Symbol struct {
24+ Name string `json:"name"`
25+ Library string `json:"library"`
26+ Signature string `json:"signature"`
27+}
A cmd/pipewiregen/internal/parser/parser.go +21 -0
@@ -0,0 +1,21 @@
1+package parser
2+
3+import (
4+ "encoding/json"
5+ "os"
6+
7+ "github.com/bnema/purego-pipewire/cmd/pipewiregen/internal/model"
8+)
9+
10+// Load reads and parses a binding model JSON file.
11+func Load(path string) (*model.Model, error) {
12+ b, err := os.ReadFile(path)
13+ if err != nil {
14+ return nil, err
15+ }
16+ var m model.Model
17+ if err := json.Unmarshal(b, &m); err != nil {
18+ return nil, err
19+ }
20+ return &m, nil
21+}
@@ -0,0 +1,21 @@
1+package parser
2+
3+import (
4+ "encoding/json"
5+ "os"
6+
7+ "github.com/bnema/purego-pipewire/cmd/pipewiregen/internal/model"
8+)
9+
10+// Load reads and parses a binding model JSON file.
11+func Load(path string) (*model.Model, error) {
12+ b, err := os.ReadFile(path)
13+ if err != nil {
14+ return nil, err
15+ }
16+ var m model.Model
17+ if err := json.Unmarshal(b, &m); err != nil {
18+ return nil, err
19+ }
20+ return &m, nil
21+}
A cmd/pipewiregen/internal/parser/parser_test.go +16 -0
@@ -0,0 +1,16 @@
1+package parser
2+
3+import "testing"
4+
5+func TestLoadParsesLibraryAndSymbolGroups(t *testing.T) {
6+ model, err := Load("testdata/minimal_pipewire.json")
7+ if err != nil {
8+ t.Fatalf("Load returned error: %v", err)
9+ }
10+ if got, want := len(model.Libraries), 1; got != want {
11+ t.Fatalf("libraries=%d want %d", got, want)
12+ }
13+ if got, want := model.Groups[0].Name, "init"; got != want {
14+ t.Fatalf("group=%q want %q", got, want)
15+ }
16+}
@@ -0,0 +1,16 @@
1+package parser
2+
3+import "testing"
4+
5+func TestLoadParsesLibraryAndSymbolGroups(t *testing.T) {
6+ model, err := Load("testdata/minimal_pipewire.json")
7+ if err != nil {
8+ t.Fatalf("Load returned error: %v", err)
9+ }
10+ if got, want := len(model.Libraries), 1; got != want {
11+ t.Fatalf("libraries=%d want %d", got, want)
12+ }
13+ if got, want := model.Groups[0].Name, "init"; got != want {
14+ t.Fatalf("group=%q want %q", got, want)
15+ }
16+}
A cmd/pipewiregen/internal/parser/testdata/minimal_pipewire.json +12 -0
@@ -0,0 +1,12 @@
1+{
2+ "libraries": [
3+ {"name": "pipewire", "soname": "libpipewire-0.3.so.0"}
4+ ],
5+ "groups": [
6+ {"name": "init", "symbols": ["pw_init", "pw_deinit"]}
7+ ],
8+ "symbols": [
9+ {"name": "pw_init", "library": "pipewire", "signature": "func(argc *int32, argv ***byte)"},
10+ {"name": "pw_deinit", "library": "pipewire", "signature": "func()"}
11+ ]
12+}
@@ -0,0 +1,12 @@
1+{
2+ "libraries": [
3+ {"name": "pipewire", "soname": "libpipewire-0.3.so.0"}
4+ ],
5+ "groups": [
6+ {"name": "init", "symbols": ["pw_init", "pw_deinit"]}
7+ ],
8+ "symbols": [
9+ {"name": "pw_init", "library": "pipewire", "signature": "func(argc *int32, argv ***byte)"},
10+ {"name": "pw_deinit", "library": "pipewire", "signature": "func()"}
11+ ]
12+}
A cmd/pipewiregen/internal/pipewiregen/normalize.go +3 -0
@@ -0,0 +1,3 @@
1+// Package pipewiregen contains PipeWire-specific naming and grouping rules
2+// for the code generator.
3+package pipewiregen
@@ -0,0 +1,3 @@
1+// Package pipewiregen contains PipeWire-specific naming and grouping rules
2+// for the code generator.
3+package pipewiregen
A cmd/pipewiregen/main.go +23 -0
@@ -0,0 +1,23 @@
1+package main
2+
3+import (
4+ "fmt"
5+ "os"
6+ "path/filepath"
7+
8+ "github.com/bnema/purego-pipewire/cmd/pipewiregen/internal/parser"
9+)
10+
11+func main() {
12+ root, err := os.Getwd()
13+ if err != nil {
14+ fmt.Fprintf(os.Stderr, "pipewiregen: %v\n", err)
15+ os.Exit(1)
16+ }
17+ _, err = parser.Load(filepath.Join(root, "gen", "pipewire.json"))
18+ if err != nil {
19+ fmt.Fprintf(os.Stderr, "pipewiregen: %v\n", err)
20+ os.Exit(1)
21+ }
22+ // Emit step will be added in Task 2.
23+}
@@ -0,0 +1,23 @@
1+package main
2+
3+import (
4+ "fmt"
5+ "os"
6+ "path/filepath"
7+
8+ "github.com/bnema/purego-pipewire/cmd/pipewiregen/internal/parser"
9+)
10+
11+func main() {
12+ root, err := os.Getwd()
13+ if err != nil {
14+ fmt.Fprintf(os.Stderr, "pipewiregen: %v\n", err)
15+ os.Exit(1)
16+ }
17+ _, err = parser.Load(filepath.Join(root, "gen", "pipewire.json"))
18+ if err != nil {
19+ fmt.Fprintf(os.Stderr, "pipewiregen: %v\n", err)
20+ os.Exit(1)
21+ }
22+ // Emit step will be added in Task 2.
23+}
A gen/pipewire.json +12 -0
@@ -0,0 +1,12 @@
1+{
2+ "libraries": [
3+ {"name": "pipewire", "soname": "libpipewire-0.3.so.0"}
4+ ],
5+ "groups": [
6+ {"name": "init", "symbols": ["pw_init", "pw_deinit"]}
7+ ],
8+ "symbols": [
9+ {"name": "pw_init", "library": "pipewire", "signature": "func(argc *int32, argv ***byte)"},
10+ {"name": "pw_deinit", "library": "pipewire", "signature": "func()"}
11+ ]
12+}
@@ -0,0 +1,12 @@
1+{
2+ "libraries": [
3+ {"name": "pipewire", "soname": "libpipewire-0.3.so.0"}
4+ ],
5+ "groups": [
6+ {"name": "init", "symbols": ["pw_init", "pw_deinit"]}
7+ ],
8+ "symbols": [
9+ {"name": "pw_init", "library": "pipewire", "signature": "func(argc *int32, argv ***byte)"},
10+ {"name": "pw_deinit", "library": "pipewire", "signature": "func()"}
11+ ]
12+}
A gen/spa.json +7 -0
@@ -0,0 +1,7 @@
1+{
2+ "libraries": [
3+ {"name": "spa", "soname": "libspa-0.2.so.0"}
4+ ],
5+ "groups": [],
6+ "symbols": []
7+}
@@ -0,0 +1,7 @@
1+{
2+ "libraries": [
3+ {"name": "spa", "soname": "libspa-0.2.so.0"}
4+ ],
5+ "groups": [],
6+ "symbols": []
7+}
A generate.go +4 -0
@@ -0,0 +1,4 @@
1+//go:generate go run ./cmd/pipewiregen
2+//go:generate mockery
3+
4+package puregopipewire
@@ -0,0 +1,4 @@
1+//go:generate go run ./cmd/pipewiregen
2+//go:generate mockery
3+
4+package puregopipewire
A go.mod +3 -0
@@ -0,0 +1,3 @@
1+module github.com/bnema/purego-pipewire
2+
3+go 1.24.0
@@ -0,0 +1,3 @@
1+module github.com/bnema/purego-pipewire
2+
3+go 1.24.0

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 1

Tags 8

↑↓ moveenter openesc close