From ed5f62887ca990d149eff2dd7d28806927d26b73 Mon Sep 17 00:00:00 2001 From: Dan Anglin Date: Sat, 12 Oct 2024 21:38:53 +0100 Subject: [PATCH] checkpoint: skeleton code --- .golangci.yaml | 8 +++++ cmd/indieauth-server/main.go | 32 ++++++++++++++++++ go.mod | 3 ++ internal/executors/command.go | 27 +++++++++++++++ internal/executors/errors.go | 9 +++++ internal/executors/executors.go | 17 ++++++++++ internal/executors/help.go | 1 + internal/executors/serve.go | 55 +++++++++++++++++++++++++++++++ internal/executors/version.go | 58 +++++++++++++++++++++++++++++++++ internal/info/info.go | 12 +++++++ internal/router/router.go | 9 +++++ magefiles/go.mod | 5 +++ magefiles/go.sum | 2 ++ magefiles/mage.go | 19 ++++++++--- main.go | 24 -------------- 15 files changed, 253 insertions(+), 28 deletions(-) create mode 100644 cmd/indieauth-server/main.go create mode 100644 go.mod create mode 100644 internal/executors/command.go create mode 100644 internal/executors/errors.go create mode 100644 internal/executors/executors.go create mode 100644 internal/executors/help.go create mode 100644 internal/executors/serve.go create mode 100644 internal/executors/version.go create mode 100644 internal/info/info.go create mode 100644 internal/router/router.go create mode 100644 magefiles/go.mod create mode 100644 magefiles/go.sum delete mode 100644 main.go diff --git a/.golangci.yaml b/.golangci.yaml index 059f5bc..5861113 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -13,6 +13,14 @@ output: sort-results: true linters-settings: + depguard: + rules: + main: + files: + - $all + allow: + - $gostd + - codeflow.dananglin.me.uk/apollo/indieauth-server lll: line-length: 140 diff --git a/cmd/indieauth-server/main.go b/cmd/indieauth-server/main.go new file mode 100644 index 0000000..327bb4b --- /dev/null +++ b/cmd/indieauth-server/main.go @@ -0,0 +1,32 @@ +package main + +import ( + "log/slog" + "os" + + "codeflow.dananglin.me.uk/apollo/indieauth-server/internal/executors" +) + +var ( + binaryVersion string + buildTime string + goVersion string + gitCommit string +) + +func main() { + // Set up logging + loggingLevel := new(slog.LevelVar) + + slogOpts := slog.HandlerOptions{ + Level: loggingLevel, + } + + logger := slog.New(slog.NewTextHandler(os.Stdout, &slogOpts)) + slog.SetDefault(logger) + loggingLevel.Set(slog.LevelInfo) + + if err := executors.Execute(os.Args[1:]); err != nil { + slog.Error(err.Error()) + } +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..df0e4ee --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module codeflow.dananglin.me.uk/apollo/indieauth-server + +go 1.23.2 diff --git a/internal/executors/command.go b/internal/executors/command.go new file mode 100644 index 0000000..3c6b434 --- /dev/null +++ b/internal/executors/command.go @@ -0,0 +1,27 @@ +package executors + +type command struct { + name string + args []string +} + +func newCommand(args []string) command { + if len(args) == 0 { + return command{ + name: "help", + args: make([]string, 0), + } + } + + if len(args) == 1 { + return command{ + name: args[0], + args: make([]string, 0), + } + } + + return command{ + name: args[0], + args: args[1:], + } +} diff --git a/internal/executors/errors.go b/internal/executors/errors.go new file mode 100644 index 0000000..a6aaeed --- /dev/null +++ b/internal/executors/errors.go @@ -0,0 +1,9 @@ +package executors + +type UnrecognisedCommandError struct { + command string +} + +func (e UnrecognisedCommandError) Error() string { + return "unrecognised command: "+ e.command +} diff --git a/internal/executors/executors.go b/internal/executors/executors.go new file mode 100644 index 0000000..b83af61 --- /dev/null +++ b/internal/executors/executors.go @@ -0,0 +1,17 @@ +package executors + +func Execute(args []string) error { + command := newCommand(args) + + executorFuncMap := map[string]func(args []string) error{ + "serve": executeServeCommand, + "version": executeVersionCommand, + } + + executeFunc, ok := executorFuncMap[command.name] + if !ok { + return UnrecognisedCommandError{command.name} + } + + return executeFunc(command.args) +} diff --git a/internal/executors/help.go b/internal/executors/help.go new file mode 100644 index 0000000..240f649 --- /dev/null +++ b/internal/executors/help.go @@ -0,0 +1 @@ +package executors diff --git a/internal/executors/serve.go b/internal/executors/serve.go new file mode 100644 index 0000000..e79f57c --- /dev/null +++ b/internal/executors/serve.go @@ -0,0 +1,55 @@ +package executors + +import ( + "flag" + "fmt" + "log/slog" + "net/http" + "time" + + "codeflow.dananglin.me.uk/apollo/indieauth-server/internal/info" + "codeflow.dananglin.me.uk/apollo/indieauth-server/internal/router" +) + +type serveExecutor struct { + *flag.FlagSet + + address string +} + +func executeServeCommand(args []string) error { + executorName := "serve" + + executor := serveExecutor{ + FlagSet: flag.NewFlagSet(executorName, flag.ExitOnError), + } + + executor.StringVar(&executor.address, "address", "0.0.0.0:8080", "The address that the server will listen on") + + if err := executor.Parse(args); err != nil { + return fmt.Errorf("(%s) flag parsing error: %w", executorName, err) + } + + if err := executor.execute(); err != nil { + return fmt.Errorf("(%s) execution error: %w", executorName, err) + } + + return nil +} + +func (e *serveExecutor) execute() error { + server := http.Server{ + Addr: e.address, + Handler: router.NewServeMux(), + ReadHeaderTimeout: 1 * time.Second, + } + + slog.Info(info.ApplicationName + " is listening for web requests", "address", e.address) + + err := server.ListenAndServe() + if err != nil { + return fmt.Errorf("error running the server: %w", err) + } + + return nil +} diff --git a/internal/executors/version.go b/internal/executors/version.go new file mode 100644 index 0000000..e26435c --- /dev/null +++ b/internal/executors/version.go @@ -0,0 +1,58 @@ +package executors + +import ( + "flag" + "fmt" + "os" + "strings" + "text/tabwriter" + + "codeflow.dananglin.me.uk/apollo/indieauth-server/internal/info" +) + +type versionExecutor struct { + *flag.FlagSet + + showFullVersion bool +} + +func executeVersionCommand(args []string) error { + executorName := "version" + + executor := versionExecutor{ + FlagSet: flag.NewFlagSet(executorName, flag.ExitOnError), + } + + executor.BoolVar(&executor.showFullVersion, "full", false, "Print the applications full build information") + + if err := executor.Parse(args); err != nil { + return fmt.Errorf("(%s) flag parsing error: %w", executorName, err) + } + + executor.printVersion() + + return nil +} + +func (e *versionExecutor) printVersion() { + if !e.showFullVersion { + fmt.Fprintf(os.Stdout, "%s %s\n", info.ApplicationName, info.BinaryVersion) + + return + } + + var builder strings.Builder + + builder.WriteString(info.ApplicationName + "\n\n") + + tableWriter := tabwriter.NewWriter(&builder, 0, 4, 1, ' ', 0) + + _, _ = tableWriter.Write([]byte("Version:" + "\t" + info.BinaryVersion + "\n")) + _, _ = tableWriter.Write([]byte("Git commit:" + "\t" + info.GitCommit + "\n")) + _, _ = tableWriter.Write([]byte("Go version:" + "\t" + info.GoVersion + "\n")) + _, _ = tableWriter.Write([]byte("Build date:" + "\t" + info.BuildTime + "\n")) + + tableWriter.Flush() + + os.Stdout.WriteString(builder.String()) +} diff --git a/internal/info/info.go b/internal/info/info.go new file mode 100644 index 0000000..266537b --- /dev/null +++ b/internal/info/info.go @@ -0,0 +1,12 @@ +package info + +const ( + ApplicationName string = "indieauth-server" +) + +var ( + BinaryVersion string //nolint:gochecknoglobals + BuildTime string //nolint:gochecknoglobals + GoVersion string //nolint:gochecknoglobals + GitCommit string //nolint:gochecknoglobals +) diff --git a/internal/router/router.go b/internal/router/router.go new file mode 100644 index 0000000..0c2cae6 --- /dev/null +++ b/internal/router/router.go @@ -0,0 +1,9 @@ +package router + +import "net/http" + +func NewServeMux() *http.ServeMux { + mux := http.NewServeMux() + + return mux +} diff --git a/magefiles/go.mod b/magefiles/go.mod new file mode 100644 index 0000000..dd5a3b1 --- /dev/null +++ b/magefiles/go.mod @@ -0,0 +1,5 @@ +module codeflow.dananglin.me.uk/apollo/indieauth-server/magefiles + +go 1.23.2 + +require github.com/magefile/mage v1.15.0 diff --git a/magefiles/go.sum b/magefiles/go.sum new file mode 100644 index 0000000..4ee1b87 --- /dev/null +++ b/magefiles/go.sum @@ -0,0 +1,2 @@ +github.com/magefile/mage v1.15.0 h1:BvGheCMAsG3bWUDbZ8AyXXpCNwU9u5CB6sM+HNb9HYg= +github.com/magefile/mage v1.15.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A= diff --git a/magefiles/mage.go b/magefiles/mage.go index 1a12267..75cccf4 100644 --- a/magefiles/mage.go +++ b/magefiles/mage.go @@ -14,7 +14,7 @@ import ( ) const ( - app = "binary" + app = "indieauth-server" defaultInstallPrefix = "/usr/local" envInstallPrefix = "PROJECT_INSTALL_PREFIX" envTestVerbose = "PROJECT_TEST_VERBOSE" @@ -56,7 +56,7 @@ func Lint() error { // To rebuild packages that are already up-to-date set PROJECT_BUILD_REBUILD_ALL=1 // To enable verbose mode set PROJECT_BUILD_VERBOSE=1 func Build() error { - main := "main.go" + main := "./cmd/" + app flags := ldflags() build := sh.RunCmd("go", "build") args := []string{"-ldflags=" + flags, "-o", binary} @@ -110,10 +110,21 @@ func Clean() error { // ldflags returns the build flags. func ldflags() string { - ldflagsfmt := "-s -w -X main.binaryVersion=%s -X main.gitCommit=%s -X main.goVersion=%s -X main.buildTime=%s" + versionPackage := "codeflow.dananglin.me.uk/apollo/indieauth-server/internal/info" + binaryVersionVar := versionPackage + "." + "BinaryVersion" + gitCommitVar := versionPackage + "." + "GitCommit" + goVersionVar := versionPackage + "." + "GoVersion" + buildTimeVar := versionPackage + "." + "BuildTime" + ldflagsfmt := "-s -w -X %s=%s -X %s=%s -X %s=%s -X %s=%s" buildTime := time.Now().UTC().Format(time.RFC3339) - return fmt.Sprintf(ldflagsfmt, version(), gitCommit(), runtime.Version(), buildTime) + return fmt.Sprintf( + ldflagsfmt, + binaryVersionVar, version(), + gitCommitVar, gitCommit(), + goVersionVar, runtime.Version(), + buildTimeVar, buildTime, + ) } // version returns the latest git tag using git describe. diff --git a/main.go b/main.go deleted file mode 100644 index a3255e8..0000000 --- a/main.go +++ /dev/null @@ -1,24 +0,0 @@ -package main - -import ( - "fmt" - "os" -) - -var ( - binaryVersion string - buildTime string - goVersion string - gitCommit string -) - -func main() { - if err := run(); err != nil { - fmt.Printf("ERROR: %v.\n", err) - os.Exit(1) - } -} - -func run() error { - return nil -}