build: factor out build flags

We currently have all flags related to build options defined in the cmd
package. These flags are as a side-effect to the CommandLine
flagset. This commit factors it out into the build package and allows
setting it on a different flagset.

This is working towards creating command line arguments from a
BuildOptions struct. This can be used by indexserver.

Change-Id: Ibb711b3620d68571325d52f5507f99b7fab234e3
diff --git a/build/builder.go b/build/builder.go
index fa8d905..1c41bc7 100644
--- a/build/builder.go
+++ b/build/builder.go
@@ -18,6 +18,7 @@
 
 import (
 	"crypto/sha1"
+	"flag"
 	"fmt"
 	"io"
 	"io/ioutil"
@@ -95,6 +96,29 @@
 	return fmt.Sprintf("%x", hasher.Sum(nil))
 }
 
+type largeFilesFlag struct{ *Options }
+
+func (f largeFilesFlag) String() string {
+	s := append([]string{""}, f.LargeFiles...)
+	return strings.Join(s, "-large_file ")
+}
+
+func (f largeFilesFlag) Set(value string) error {
+	f.LargeFiles = append(f.LargeFiles, value)
+	return nil
+}
+
+// Flags adds flags for build options to fs.
+func (o *Options) Flags(fs *flag.FlagSet) {
+	fs.IntVar(&o.SizeMax, "file_limit", 2<<20, "maximum file size")
+	fs.IntVar(&o.TrigramMax, "max_trigram_count", 20000, "maximum number of trigrams per document")
+	fs.IntVar(&o.ShardMax, "shard_limit", 100<<20, "maximum corpus size for a shard")
+	fs.IntVar(&o.Parallelism, "parallelism", 4, "maximum number of parallel indexing processes.")
+	fs.StringVar(&o.IndexDir, "index", DefaultDir, "directory for search indices")
+	fs.BoolVar(&o.CTagsMustSucceed, "require_ctags", false, "If set, ctags calls must succeed.")
+	fs.Var(largeFilesFlag{o}, "large_file", "A glob pattern where matching files are to be index regardless of their size. You can add multiple patterns by setting this more than once.")
+}
+
 // Builder manages (parallel) creation of uniformly sized shards. The
 // builder buffers up documents until it collects enough documents and
 // then builds a shard and writes.
diff --git a/cmd/flags.go b/cmd/flags.go
index 27cca86..e0b9005 100644
--- a/cmd/flags.go
+++ b/cmd/flags.go
@@ -19,37 +19,18 @@
 	"fmt"
 	"os"
 	"path/filepath"
-	"strings"
 
 	"github.com/google/zoekt"
 	"github.com/google/zoekt/build"
 )
 
-type largeFilesFlag []string
-
-func (f *largeFilesFlag) String() string {
-	s := append([]string{""}, *f...)
-	return strings.Join(s, "-large_file ")
-}
-
-func (f *largeFilesFlag) Set(value string) error {
-	*f = append(*f, value)
-	return nil
-}
-
 var (
-	sizeMax     = flag.Int("file_limit", 2<<20, "maximum file size")
-	trigramMax  = flag.Int("max_trigram_count", 20000, "maximum number of trigrams per document")
-	shardLimit  = flag.Int("shard_limit", 100<<20, "maximum corpus size for a shard")
-	parallelism = flag.Int("parallelism", 4, "maximum number of parallel indexing processes.")
-	indexDir    = flag.String("index", build.DefaultDir, "directory for search indices")
-	version     = flag.Bool("version", false, "Print version number")
-	ctags       = flag.Bool("require_ctags", false, "If set, ctags calls must succeed.")
-	largeFiles  = largeFilesFlag{}
+	version = flag.Bool("version", false, "Print version number")
+	opts    = &build.Options{}
 )
 
 func init() {
-	flag.Var(&largeFiles, "large_file", "A glob pattern where matching files are to be index regardless of their size. You can add multiple patterns by setting this more than once.")
+	opts.Flags(flag.CommandLine)
 }
 
 func OptionsFromFlags() *build.Options {
@@ -59,15 +40,6 @@
 		os.Exit(0)
 	}
 
-	opts := &build.Options{
-		Parallelism:      *parallelism,
-		SizeMax:          *sizeMax,
-		ShardMax:         *shardLimit,
-		IndexDir:         *indexDir,
-		CTagsMustSucceed: *ctags,
-		LargeFiles:       largeFiles,
-		TrigramMax:       *trigramMax,
-	}
 	opts.SetDefaults()
 	return opts
 }