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 `)))