From 6a65efc40dcf29aa72b9f0617dfaa642b13aeaf6 Mon Sep 17 00:00:00 2001 From: Jeff Carr Date: Wed, 29 May 2019 09:54:28 -0700 Subject: [PATCH] some more examples Signed-off-by: Jeff Carr --- .gitignore | 1 + example-aminal/Makefile | 7 +++ example-aminal/config.go | 122 +++++++++++++++++++++++++++++++++++++++ example-aminal/logger.go | 25 ++++++++ example-aminal/main.go | 80 +++++++++++++++++++++++++ example-test/Makefile | 2 + example-test/ex_test.go | 21 +++++++ 7 files changed, 258 insertions(+) create mode 100644 example-aminal/Makefile create mode 100644 example-aminal/config.go create mode 100644 example-aminal/logger.go create mode 100644 example-aminal/main.go create mode 100644 example-test/Makefile create mode 100644 example-test/ex_test.go diff --git a/.gitignore b/.gitignore index 079a882..540d4a3 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ example-systray/example-systray example-UI-table/example-UI-table example-dnssecsocket/example-dnssecsocket example-table/example-table +example-aminal/example-aminal test1/test1 test2/test2 diff --git a/example-aminal/Makefile b/example-aminal/Makefile new file mode 100644 index 0000000..21397e9 --- /dev/null +++ b/example-aminal/Makefile @@ -0,0 +1,7 @@ +build: + go build + example-aminal + + +build-windows: + env GOOS=windows GOARCH=amd64 go build diff --git a/example-aminal/config.go b/example-aminal/config.go new file mode 100644 index 0000000..8a18793 --- /dev/null +++ b/example-aminal/config.go @@ -0,0 +1,122 @@ +package main + +import ( + "flag" + "fmt" + "io/ioutil" + "os" + "os/user" + "path/filepath" + + "github.com/liamg/aminal/config" + "github.com/liamg/aminal/version" +) + +func getActuallyProvidedFlags() map[string]bool { + result := make(map[string]bool) + + flag.Visit(func(f *flag.Flag) { + result[f.Name] = true + }) + + return result +} + +func getConfig() *config.Config { + showVersion := false + ignoreConfig := false + shell := "" + debugMode := false + slomo := false + + if flag.Parsed() == false { + flag.BoolVar(&showVersion, "version", showVersion, "Output version information") + flag.BoolVar(&ignoreConfig, "ignore-config", ignoreConfig, "Ignore user config files and use defaults") + flag.StringVar(&shell, "shell", shell, "Specify the shell to use") + flag.BoolVar(&debugMode, "debug", debugMode, "Enable debug logging") + flag.BoolVar(&slomo, "slomo", slomo, "Render in slow motion (useful for debugging)") + + flag.Parse() // actual parsing and fetching flags from the command line + } + actuallyProvidedFlags := getActuallyProvidedFlags() + + if showVersion { + v := version.Version + if v == "" { + v = "development" + } + fmt.Println(v) + os.Exit(0) + } + + var conf *config.Config + if ignoreConfig { + conf = &config.DefaultConfig + } else { + conf = loadConfigFile() + } + + // Override values in the configuration file with the values specified in the command line, if any. + if actuallyProvidedFlags["shell"] { + conf.Shell = shell + } + + if actuallyProvidedFlags["debug"] { + conf.DebugMode = debugMode + } + + if actuallyProvidedFlags["slomo"] { + conf.Slomo = slomo + } + + return conf +} + +func loadConfigFile() *config.Config { + + usr, err := user.Current() + if err != nil { + fmt.Printf("Failed to get current user information: %s\n", err) + return &config.DefaultConfig + } + + home := usr.HomeDir + if home == "" { + return &config.DefaultConfig + } + + places := []string{} + + xdgHome := os.Getenv("XDG_CONFIG_HOME") + if xdgHome != "" { + places = append(places, filepath.Join(xdgHome, "aminal/config.toml")) + } + + places = append(places, filepath.Join(home, ".config/aminal/config.toml")) + places = append(places, filepath.Join(home, ".aminal.toml")) + + for _, place := range places { + if b, err := ioutil.ReadFile(place); err == nil { + if c, err := config.Parse(b); err == nil { + return c + } + + fmt.Printf("Invalid config at %s: %s\n", place, err) + } + } + + if b, err := config.DefaultConfig.Encode(); err != nil { + fmt.Printf("Failed to encode config file: %s\n", err) + } else { + err = os.MkdirAll(filepath.Dir(places[0]), 0744) + if err != nil { + fmt.Printf("Failed to create config file directory: %s\n", err) + } else { + if err = ioutil.WriteFile(places[0], b, 0644); err != nil { + fmt.Printf("Failed to encode config file: %s\n", err) + } + } + } + + return &config.DefaultConfig +} diff --git a/example-aminal/logger.go b/example-aminal/logger.go new file mode 100644 index 0000000..aa9b6eb --- /dev/null +++ b/example-aminal/logger.go @@ -0,0 +1,25 @@ +package main + +import ( + "fmt" + + "github.com/liamg/aminal/config" + "go.uber.org/zap" +) + +func getLogger(conf *config.Config) (*zap.SugaredLogger, error) { + + var logger *zap.Logger + var err error + if conf.DebugMode { + logger, err = zap.NewDevelopment() + } else { + loggerConfig := zap.NewProductionConfig() + loggerConfig.Encoding = "console" + logger, err = loggerConfig.Build() + } + if err != nil { + return nil, fmt.Errorf("Failed to create logger: %s", err) + } + return logger.Sugar(), nil +} diff --git a/example-aminal/main.go b/example-aminal/main.go new file mode 100644 index 0000000..aff7af0 --- /dev/null +++ b/example-aminal/main.go @@ -0,0 +1,80 @@ +package main + +import ( + "fmt" + "github.com/liamg/aminal/gui" + "github.com/liamg/aminal/platform" + "github.com/liamg/aminal/terminal" + "github.com/riywo/loginshell" + "os" + "runtime" +) + +type callback func(terminal *terminal.Terminal, g *gui.GUI) + +func init() { + runtime.LockOSThread() +} + +func main() { + initialize(nil) +} + +func initialize(unitTestfunc callback) { + conf := getConfig() + logger, err := getLogger(conf) + if err != nil { + fmt.Printf("Failed to create logger: %s\n", err) + os.Exit(1) + } + defer logger.Sync() + + logger.Infof("Allocating pty...") + + pty, err := platform.NewPty(80, 25) + if err != nil { + logger.Fatalf("Failed to allocate pty: %s", err) + } + + shellStr := conf.Shell + if shellStr == "" { + loginShell, err := loginshell.Shell() + if err != nil { + logger.Fatalf("Failed to ascertain your shell: %s", err) + } + shellStr = loginShell + } + + os.Setenv("TERM", "xterm-256color") // controversial! easier than installing terminfo everywhere, but obviously going to be slightly different to xterm functionality, so we'll see... + os.Setenv("COLORTERM", "truecolor") + + guestProcess, err := pty.CreateGuestProcess(shellStr) + if err != nil { + pty.Close() + logger.Fatalf("Failed to start your shell: %s", err) + } + defer guestProcess.Close() + + logger.Infof("Creating terminal...") + terminal := terminal.New(pty, logger, conf) + + g, err := gui.New(conf, terminal, logger) + if err != nil { + logger.Fatalf("Cannot start: %s", err) + } + + if unitTestfunc != nil { + go unitTestfunc(terminal, g) + } else { + go func() { + if err := guestProcess.Wait(); err != nil { + logger.Fatalf("Failed to wait for guest process: %s", err) + } + g.Close() + }() + } + + if err := g.Render(); err != nil { + logger.Fatalf("Render error: %s", err) + } +} diff --git a/example-test/Makefile b/example-test/Makefile new file mode 100644 index 0000000..35d7804 --- /dev/null +++ b/example-test/Makefile @@ -0,0 +1,2 @@ +all: + go test --race diff --git a/example-test/ex_test.go b/example-test/ex_test.go new file mode 100644 index 0000000..fb6ab1b --- /dev/null +++ b/example-test/ex_test.go @@ -0,0 +1,21 @@ +package ex + +import "sync" +import "testing" + +type Item struct{} + +func TestAppend(t *testing.T) { + var list []Item + + n := 2 + wg := sync.WaitGroup{} + wg.Add(n) + for i := 0; i < n; i++ { + go func() { + defer wg.Done() + list = append(list, Item{}) + }() + } + wg.Wait() +}