gioinit

Bootstrap Gio programs with a simple template to get you started.
Log | Files | Refs | README | LICENSE

main.go (4276B)


      1 // goinit spits out a templated gio program for bootstraping.
      2 package main
      3 
      4 import (
      5 	"fmt"
      6 	"os"
      7 	"os/exec"
      8 	"path/filepath"
      9 	"strings"
     10 	"text/template"
     11 )
     12 
     13 func main() {
     14 	// By default just spit out the templated file. Let the user
     15 	// pipe it and handle setup.
     16 	if len(os.Args) == 1 {
     17 		if err := t.Execute(os.Stdout, nil); err != nil {
     18 			panic(fmt.Errorf("executing template: %w", err))
     19 		}
     20 		return
     21 	}
     22 	if err := func() error {
     23 		var (
     24 			// path to the new project. All intermediate
     25 			// directories will be created and the final
     26 			// element will be used as the project name.
     27 			path = os.Args[1]
     28 			// project is treated as the name for this new project.
     29 			//
     30 			// If provided, we can do some of the init ritual for
     31 			// them.
     32 			//
     33 			// This can be a full file sytsem path, but that
     34 			// will cause the qualifier to also be a file path
     35 			// unless a unique qualifer is specified.
     36 			project = filepath.Base(path)
     37 			// qualifer is the module path used in "go.mod".
     38 			// Defaults to the path if not explicitly specified.
     39 			qualifier = project
     40 		)
     41 		if len(os.Args) > 2 {
     42 			qualifier = os.Args[2]
     43 		}
     44 		if err := os.MkdirAll(path, 0755); err != nil {
     45 			return fmt.Errorf("preparing directory: %w", err)
     46 		}
     47 		if err := writeTemplate(filepath.Join(path, "main.go")); err != nil {
     48 			return fmt.Errorf("writing template file: %w", err)
     49 		}
     50 		g := Go{Dir: path}
     51 		if err := g.Init(qualifier); err != nil {
     52 			return err
     53 		}
     54 		if err := g.Tidy(); err != nil {
     55 			return err
     56 		}
     57 		if err := g.Run(); err != nil {
     58 			return err
     59 		}
     60 		return nil
     61 	}(); err != nil {
     62 		fmt.Printf("error: %v", err)
     63 	}
     64 }
     65 
     66 // Go wraps the Go tool providing some common commands.
     67 type Go struct {
     68 	// Dir is the parent directory to execute the commands in.
     69 	Dir string
     70 }
     71 
     72 // Init runs "go mod init".
     73 func (g Go) Init(project string) error {
     74 	c := exec.Command("go", "mod", "init", project)
     75 	c.Dir = g.Dir
     76 	c.Stdout = os.Stdout
     77 	c.Stderr = os.Stderr
     78 	if err := c.Run(); err != nil {
     79 		return fmt.Errorf("go mod init %s: %w", project, err)
     80 	}
     81 	return nil
     82 }
     83 
     84 // Tidy runs "go mod tidy".
     85 func (g Go) Tidy() error {
     86 	c := exec.Command("go", "mod", "tidy")
     87 	c.Dir = g.Dir
     88 	c.Stdout = os.Stdout
     89 	c.Stderr = os.Stderr
     90 	if err := c.Run(); err != nil {
     91 		return fmt.Errorf("go mod tidy: %w", err)
     92 	}
     93 	return nil
     94 }
     95 
     96 // Run runs "go run .".
     97 func (g Go) Run() error {
     98 	c := exec.Command("go", "run", ".")
     99 	c.Dir = g.Dir
    100 	c.Stdout = os.Stdout
    101 	c.Stderr = os.Stderr
    102 	if err := c.Run(); err != nil {
    103 		return fmt.Errorf("go run: %w", err)
    104 	}
    105 	return nil
    106 }
    107 
    108 // writeTemplate writes the template source code out to disk.
    109 func writeTemplate(path string) error {
    110 	mainf, err := os.Create(path)
    111 	if err != nil {
    112 		return fmt.Errorf("creating file: %w", err)
    113 	}
    114 	defer mainf.Close()
    115 	if err := t.Execute(mainf, nil); err != nil {
    116 		return fmt.Errorf("executing template: %w", err)
    117 	}
    118 	return nil
    119 }
    120 
    121 var t = template.Must(template.New("").Parse(strings.TrimSpace(`
    122 package main
    123 
    124 import (
    125 	"log"
    126 	"os"
    127 
    128 	"gioui.org/app"
    129 	"gioui.org/font/gofont"
    130 	"gioui.org/io/system"
    131 	"gioui.org/layout"
    132 	"gioui.org/op"
    133 	"gioui.org/unit"
    134 	"gioui.org/widget/material"
    135 )
    136 
    137 func main() {
    138 	ui := UI{}
    139 	go func() {
    140 		if err := ui.Loop(); err != nil {
    141 			log.Printf("error: %v", err)
    142 		}
    143 		os.Exit(0)
    144 	}()
    145 	app.Main()
    146 }
    147 
    148 // UI maintains state for the entire user interface.
    149 type UI struct {
    150 	op.Ops
    151 	*app.Window
    152 }
    153 
    154 // Loop performs init and executes the event loop.
    155 func (ui *UI) Loop() error {
    156 	ui.Window = app.NewWindow(
    157 		app.Title("Gio"),
    158 		app.Size(unit.Dp(900), unit.Dp(500)),
    159 	)
    160 	for event := range ui.Window.Events() {
    161 		switch event := event.(type) {
    162 		case system.DestroyEvent:
    163 			return event.Err
    164 		case system.FrameEvent:
    165 			ui.Frame(event)
    166 		}
    167 	}
    168 	return nil
    169 }
    170 
    171 // Frame computes the frame and draws them into the window.
    172 func (ui *UI) Frame(event system.FrameEvent) {
    173 	ui.Layout(layout.NewContext(&ui.Ops, event))
    174 	event.Frame(&ui.Ops)
    175 }
    176 
    177 type (
    178 	// C convenience alias for "layout.Context".
    179 	C = layout.Context
    180 	// D convenience alias for "layout.Dimensions".
    181 	D = layout.Dimensions
    182 )
    183 
    184 var th = material.NewTheme(gofont.Collection())
    185 
    186 // Layout shows the UI.
    187 func (ui *UI) Layout(gtx C) D {
    188 	return layout.Center.Layout(gtx, func(gtx C) D {
    189 		return material.Label(th, unit.Sp(32), "Hello Gio").Layout(gtx)
    190 	})
    191 }
    192 `)))