Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor all generators #13

Merged
merged 5 commits into from
Jul 4, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,16 @@ For contributing guidelines, see [CONTRIBUTING.md](./CONTRIBUTING.md).
- I wish I used a registry of converted model types with their respective Go
names to ease translation
- I wish I used common struct types that share names and such.

## License

`gotk4` contains 3 directories licensed differently:

- `gotk4/gir` is licensed under the [GNU Affero General Public License v3][AGPLv3].
This license does not apply to the code generated by itself.
- `gotk4/pkg` is licensed under the [Mozilla Public License v2][MPLv2].
- `gotk4/core` is licensed under the permissive [ISC][ISC] license.

[AGPLv3]: https://www.gnu.org/licenses/agpl-3.0.en.html
[MPLv2]: https://www.mozilla.org/en-US/MPL/
[ISC]: https://choosealicense.com/licenses/isc/
113 changes: 59 additions & 54 deletions cmd/gir_generate/config.go
Original file line number Diff line number Diff line change
@@ -1,82 +1,87 @@
package main

import "github.com/diamondburned/gotk4/gir/girgen"
import . "github.com/diamondburned/gotk4/gir/girgen/types"

// packages lists pkg-config packages and optionally the namespaces to be
// generated. If the list of namespaces is nil, then everything is generated.
var packages = []Package{
{"gobject-introspection-1.0", []string{
"GLib-2.0",
"GObject-2.0",
"Gio-2.0",
"cairo-1.0",
"GLib-2",
"GObject-2",
"Gio-2",
"cairo-1",
}},
{"gdk-pixbuf-2.0", nil},
{"graphene-1.0", nil},
{"pango", []string{
"Pango-1.0",
"PangoCairo-1.0",
"Pango-1",
"PangoCairo-1",
}},
{"gtk4", nil}, // includes Gdk
{"gtk+-3.0", nil}, // includes Gdk
}

// preprocessors defines a list of preprocessors that the main generator will
// use. It's mostly used for renaming colliding types/identifiers.
var preprocessors = []Preprocessor{
// Collision due to case conversions.
TypeRenamer("GLib-2.file_test", "test_file"),
}

// filters defines a list of GIR types to be filtered. The map key is the
// namespace, and the values are list of names.
var filters = []girgen.FilterMatcher{
girgen.AbsoluteFilter("C.cairo_image_surface_create"),
var filters = []FilterMatcher{
AbsoluteFilter("C.cairo_image_surface_create"),

// Broadway is not included, so we don't generate code for it.
girgen.FileFilter("../gsk/broadway/gskbroadwayrenderer.h"),
FileFilter("gsk/broadway/gskbroadwayrenderer.h"),
// Output buffer parameter is not actually array.
girgen.AbsoluteFilter("GLib.unichar_to_utf8"),
// Collision due to case conversions.
girgen.TypeRenamer("GLib.file_test", "test_file"),
AbsoluteFilter("GLib.unichar_to_utf8"),
// Requires special header, is optional function.
girgen.AbsoluteFilter("Gio.networking_init"),
AbsoluteFilter("Gio.networking_init"),
// Not an array type but expects an array.
girgen.AbsoluteFilter("Gio.SimpleProxyResolver.set_ignore_hosts"),
AbsoluteFilter("Gio.SimpleProxyResolver.set_ignore_hosts"),
// These are not found.
girgen.AbsoluteFilter("GdkPixbuf.PixbufNonAnim"),
girgen.AbsoluteFilter("GdkPixbuf.PixbufModulePattern"),
girgen.AbsoluteFilter("C.gdk_pixbuf_non_anim_get_type"),
AbsoluteFilter("GdkPixbuf.PixbufNonAnim"),
AbsoluteFilter("GdkPixbuf.PixbufModulePattern"),
AbsoluteFilter("C.gdk_pixbuf_non_anim_get_type"),

girgen.FileFilter("garray.h"),
girgen.FileFilter("gasyncqueue.h"),
girgen.FileFilter("gatomic.h"),
girgen.FileFilter("gbacktrace.h"),
girgen.FileFilter("gbitlock.h"),
girgen.FileFilter("gbytes.h"),
girgen.FileFilter("gdataset.h"),
girgen.FileFilter("gdate.h"),
girgen.FileFilter("gdatetime.h"),
girgen.FileFilter("gerror.h"), // already handled internally
girgen.FileFilter("ghook.h"),
girgen.FileFilter("glib-unix.h"),
girgen.FileFilter("glist.h"),
girgen.FileFilter("gmacros.h"),
girgen.FileFilter("gmem.h"),
girgen.FileFilter("gnetworking.h"), // needs header
girgen.FileFilter("gprintf.h"),
girgen.FileFilter("grcbox.h"),
girgen.FileFilter("grefcount.h"),
girgen.FileFilter("grefstring.h"),
girgen.FileFilter("gsettingsbackend.h"),
girgen.FileFilter("gslice.h"),
girgen.FileFilter("gslist.h"),
girgen.FileFilter("gstdio.h"),
girgen.FileFilter("gstrfuncs.h"),
girgen.FileFilter("gstringchunk.h"),
girgen.FileFilter("gstring.h"),
girgen.FileFilter("gstrvbuilder.h"),
girgen.FileFilter("gtestutils.h"),
girgen.FileFilter("gthread.h"),
girgen.FileFilter("gthreadpool.h"),
girgen.FileFilter("gtrashstack.h"),
FileFilter("garray.h"),
FileFilter("gasyncqueue.h"),
FileFilter("gatomic.h"),
FileFilter("gbacktrace.h"),
FileFilter("gbitlock.h"),
FileFilter("gbytes.h"),
FileFilter("gdataset.h"),
FileFilter("gdate.h"),
FileFilter("gdatetime.h"),
FileFilter("gerror.h"), // already handled internally
FileFilter("ghook.h"),
FileFilter("glib-unix.h"),
FileFilter("glist.h"),
FileFilter("gmacros.h"),
FileFilter("gmem.h"),
FileFilter("gnetworking.h"), // needs header
FileFilter("gprintf.h"),
FileFilter("grcbox.h"),
FileFilter("grefcount.h"),
FileFilter("grefstring.h"),
FileFilter("gsettingsbackend.h"),
FileFilter("gslice.h"),
FileFilter("gslist.h"),
FileFilter("gstdio.h"),
FileFilter("gstrfuncs.h"),
FileFilter("gstringchunk.h"),
FileFilter("gstring.h"),
FileFilter("gstrvbuilder.h"),
FileFilter("gtestutils.h"),
FileFilter("gthread.h"),
FileFilter("gthreadpool.h"),
FileFilter("gtrashstack.h"),

// These are missing on build for some reason.
girgen.AbsoluteFilter("C.g_array_get_type"),
girgen.AbsoluteFilter("C.g_byte_array_get_type"),
girgen.AbsoluteFilter("C.g_bytes_get_type"),
girgen.AbsoluteFilter("C.g_ptr_array_get_type"),
AbsoluteFilter("C.g_array_get_type"),
AbsoluteFilter("C.g_byte_array_get_type"),
AbsoluteFilter("C.g_bytes_get_type"),
AbsoluteFilter("C.g_ptr_array_get_type"),
}
41 changes: 25 additions & 16 deletions cmd/gir_generate/main.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package main

import (
"context"
"flag"
"fmt"
"log"
Expand All @@ -13,21 +14,25 @@ import (

"github.com/diamondburned/gotk4/gir"
"github.com/diamondburned/gotk4/gir/girgen"
"github.com/diamondburned/gotk4/gir/girgen/logger"
"github.com/pkg/errors"
"golang.org/x/sync/semaphore"
)

var (
output string
module string
verbose bool
listPkg bool
output string
module string
verbose bool
listPkg bool
parallel = int64(runtime.GOMAXPROCS(-1))
)

func init() {
flag.StringVar(&output, "o", "", "output directory to mkdir in")
flag.StringVar(&module, "m", "github.com/diamondburned/gotk4", "go module name")
flag.BoolVar(&verbose, "v", verbose, "log verbosely (debug mode)")
flag.BoolVar(&listPkg, "l", listPkg, "only list packages and exit")
flag.Int64Var(&parallel, "p", parallel, "number of generator goroutines to spawn")
flag.Parse()

if !listPkg && output == "" {
Expand Down Expand Up @@ -79,27 +84,29 @@ func main() {
var errMut sync.Mutex
var errors []error

sema := make(chan struct{}, runtime.GOMAXPROCS(-1))

gen := girgen.NewGenerator(repos, modulePath)
gen.Color = true
gen.Logger = log.New(os.Stderr, "girgen: ", log.Lmsgprefix)
gen.AddFilters(filters)

if verbose {
gen.LogLevel = girgen.LogDebug
gen.LogLevel = logger.Debug
}

// Do a clean-up of the target directory.
if err := os.RemoveAll(output); err != nil {
log.Println("non-fatal: failed to rm -rf output dir:", err)
}

sema := semaphore.NewWeighted(parallel)

for _, repo := range repos {
for _, namespace := range repo.Namespaces {
ng := gen.UseNamespace(namespace.Name, namespace.Version)
if ng == nil {
log.Fatalln("cannot find namespace", namespace.Name, "v"+namespace.Version)
}

sema <- struct{}{}
sema.Acquire(context.Background(), 1)
wg.Add(1)

go func() {
Expand All @@ -109,7 +116,7 @@ func main() {
errMut.Unlock()
}

<-sema
sema.Release(1)
wg.Done()
}()
}
Expand All @@ -127,8 +134,7 @@ func main() {
}

func writeNamespace(ng *girgen.NamespaceGenerator) error {
pkg := ng.PackageName()
dir := filepath.Join(output, pkg)
dir := filepath.Join(output, ng.PkgName)

if version := majorVer(ng.Namespace().Namespace); version > 1 {
// Follow Go's convention of a versioned package, so we can generate
Expand All @@ -140,14 +146,17 @@ func writeNamespace(ng *girgen.NamespaceGenerator) error {
return errors.Wrapf(err, "failed to mkdir -p %q", dir)
}

b, genErr := ng.Generate()
files, err := ng.Generate()

if err := os.WriteFile(filepath.Join(dir, pkg+".go"), b, 0666); err != nil {
return errors.Wrapf(err, "failed to write pkg %q", pkg)
for name, file := range files {
dst := filepath.Join(dir, name)
if err := os.WriteFile(dst, file, 0666); err != nil {
return errors.Wrapf(err, "failed to write to %s", dst)
}
}

// Preserve the generation error, but give it last priority.
return genErr
return err
}

func modulePath(namespace *gir.Namespace) string {
Expand Down
4 changes: 2 additions & 2 deletions LICENSE → core/LICENSE
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Copyright 2021 diamondburned
Copyright (c) 2021 diamondburned

Permission to use, copy, modify, and/or distribute this software for any purpose
with or without fee is hereby granted, provided that the above copyright notice
Expand All @@ -10,4 +10,4 @@ FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
THIS SOFTWARE.
THIS SOFTWARE
31 changes: 29 additions & 2 deletions core/pen/pen.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"fmt"
"io"
"log"
"strings"
"text/template"
)

Expand All @@ -12,28 +13,54 @@ type Pen struct {
PenWriter
}

// PenWriter describes an interface that a pen can write to.
type PenWriter interface {
io.Writer
io.ByteWriter
io.StringWriter
}

type noopWriter struct{}

func (noopWriter) Write(b []byte) (int, error) { return len(b), nil }
func (noopWriter) WriteByte(b byte) error { return nil }
func (noopWriter) WriteString(s string) (int, error) { return len(s), nil }

// NewPen creates a new Pen that preallocates 1KB.
func NewPen(w PenWriter) *Pen {
return &Pen{w}
}

// NoopPen is a pen that does nothing.
var NoopPen = NewPen(noopWriter{})

// Words writes a list of words into a single line.
func (p *Pen) Words(words ...string) {
func (p *Pen) Words(words ...interface{}) {
for i, word := range words {
if i != 0 {
p.WriteByte(' ')
}
p.WriteString(word)

switch word := word.(type) {
case string:
p.WriteString(word)
case []string:
p.WriteString(strings.Join(word, " "))
default:
log.Panicf("unknown type %T given", word)
}
}

p.EmptyLine()
}

// Lines writes multiple lines.
func (p *Pen) Lines(lines []string) {
for _, line := range lines {
p.Line(line)
}
}

// Line writes a single line.
func (p *Pen) Line(line string) { p.Linef(line) }

Expand Down
Loading