Add stub `shac check` command

I chose to use the posix-style "pflag" library instead of the stdlib
"flag" since posix-style flags are much more common in command line
tools outside Google and in languages other than Go, and we'd like for
shac to be friendly to projects outside Google.

Unfortunately I couldn't find any reputable "subcommands" libraries that
use pflag, so I implemented my own simple subcommands framework,
emulating github.com/google/subcommands. It's pretty rudimentary for now
(no help text or anything) but can easily be extended later as UX
becomes more important.

Change-Id: I366642d70c32fe573ae6d2a014658068100011cd
Reviewed-on: https://fuchsia-review.googlesource.com/c/shac-project/shac/+/820747
Reviewed-by: Marc-Antoine Ruel <maruel@google.com>
Commit-Queue: Marc-Antoine Ruel <maruel@google.com>
diff --git a/go.mod b/go.mod
index d4a6e7e..6965cab 100644
--- a/go.mod
+++ b/go.mod
@@ -1,3 +1,5 @@
 module go.fuchsia.dev/shac-project/shac
 
 go 1.20
+
+require github.com/spf13/pflag v1.0.5
diff --git a/go.sum b/go.sum
new file mode 100644
index 0000000..287f6fa
--- /dev/null
+++ b/go.sum
@@ -0,0 +1,2 @@
+github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
+github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
diff --git a/internal/cli/check.go b/internal/cli/check.go
new file mode 100644
index 0000000..3467997
--- /dev/null
+++ b/internal/cli/check.go
@@ -0,0 +1,30 @@
+// Copyright 2023 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cli
+
+import (
+	"context"
+	"fmt"
+
+	flag "github.com/spf13/pflag"
+)
+
+type checkCmd struct{}
+
+func (*checkCmd) Name() string {
+	return "check"
+}
+
+func (*checkCmd) Description() string {
+	return "Run checks in a file."
+}
+
+func (*checkCmd) SetFlags(*flag.FlagSet) {
+}
+
+func (*checkCmd) Execute(context.Context, *flag.FlagSet) error {
+	fmt.Println("hello world")
+	return nil
+}
diff --git a/internal/cli/main.go b/internal/cli/main.go
new file mode 100644
index 0000000..31f11d2
--- /dev/null
+++ b/internal/cli/main.go
@@ -0,0 +1,51 @@
+// Copyright 2023 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cli
+
+import (
+	"context"
+	"fmt"
+	"os"
+
+	flag "github.com/spf13/pflag"
+)
+
+type app struct {
+	topLevelFlags *flag.FlagSet
+	subcommands   []*flag.FlagSet
+}
+
+type subcommand interface {
+	Name() string
+	Description() string
+	SetFlags(*flag.FlagSet)
+	Execute(context.Context, *flag.FlagSet) error
+}
+
+func Main() error {
+	ctx := context.Background()
+
+	if len(os.Args) < 2 {
+		return fmt.Errorf("subcommand required")
+	}
+
+	subcommands := []subcommand{
+		&checkCmd{},
+	}
+
+	name := os.Args[1]
+	for _, s := range subcommands {
+		if s.Name() != name {
+			continue
+		}
+		fs := flag.NewFlagSet(s.Name(), flag.ContinueOnError)
+		s.SetFlags(fs)
+		if err := fs.Parse(os.Args[2:]); err != nil {
+			return err
+		}
+		return s.Execute(ctx, fs)
+	}
+	return fmt.Errorf("no such command %q", name)
+}
diff --git a/main.go b/main.go
index 670c88e..953fd9c 100644
--- a/main.go
+++ b/main.go
@@ -6,8 +6,14 @@
 
 import (
 	"fmt"
+	"os"
+
+	"go.fuchsia.dev/shac-project/shac/internal/cli"
 )
 
 func main() {
-	fmt.Println("hello world!")
+	if err := cli.Main(); err != nil {
+		fmt.Fprintf(os.Stderr, "shac: %s\n", err)
+		os.Exit(1)
+	}
 }