cmd/zoekt-hg-index: barebones mercurial indexing

Change-Id: I42063215dfe913944bfed4ddea313a2394179b73
diff --git a/cmd/zoekt-hg-index/main.go b/cmd/zoekt-hg-index/main.go
new file mode 100644
index 0000000..dd782a6
--- /dev/null
+++ b/cmd/zoekt-hg-index/main.go
@@ -0,0 +1,89 @@
+// Copyright 2020 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// zoekt-hg-index provides bare-bones Mercurial indexing
+package main
+
+import (
+	"flag"
+	"fmt"
+	"log"
+	"path/filepath"
+
+	"github.com/google/zoekt"
+	"github.com/google/zoekt/build"
+	"github.com/google/zoekt/cmd"
+
+	"go.uber.org/automaxprocs/maxprocs"
+	"humungus.tedunangst.com/r/gerc"
+)
+
+func main() {
+	revisionStr := flag.String("revision", "", "hg revision to index")
+	flag.Parse()
+	maxprocs.Set()
+	opts := cmd.OptionsFromFlags()
+
+	if len(flag.Args()) < 1 {
+		log.Fatal("hg repo directory argument missing")
+	}
+	dir, err := filepath.Abs(flag.Arg(0))
+	if err != nil {
+		log.Fatal(err)
+	}
+	opts.RepositoryDescription.Name = dir
+
+	if err := indexHg(dir, *revisionStr, opts); err != nil {
+		log.Fatal(err)
+	}
+}
+
+func indexHg(dir, rev string, opts *build.Options) error {
+	r, err := gerc.Open(dir)
+	if err != nil {
+		log.Fatal(err)
+	}
+	defer r.Close()
+
+	builder, err := build.NewBuilder(*opts)
+	if err != nil {
+		return err
+	}
+	defer builder.Finish()
+
+	mfs, err := r.GetFiles(gerc.FilesArgs{
+		Revision: rev,
+	})
+	if err != nil {
+		return fmt.Errorf("GetFiles %v", err)
+	}
+
+	for _, mf := range mfs {
+		fd := gerc.FileDataArgs{
+			Filename: mf.Name,
+			Revision: rev,
+		}
+		content, err := r.GetFileData(fd)
+		if err != nil {
+			return fmt.Errorf("GetFileData %v", err)
+		}
+		if err := builder.Add(zoekt.Document{
+			Name:    mf.Name,
+			Content: content,
+		}); err != nil {
+			return err
+		}
+	}
+	return builder.Finish()
+}
diff --git a/go.mod b/go.mod
index b4a0ade..0069800 100644
--- a/go.mod
+++ b/go.mod
@@ -22,4 +22,5 @@
 	golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e
 	google.golang.org/appengine v1.6.5 // indirect
 	gopkg.in/yaml.v2 v2.2.8 // indirect
+	humungus.tedunangst.com/r/gerc v0.1.2
 )
diff --git a/go.sum b/go.sum
index 8b763e7..6544ddf 100644
--- a/go.sum
+++ b/go.sum
@@ -215,3 +215,5 @@
 gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
 gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
+humungus.tedunangst.com/r/gerc v0.1.2 h1:eW5yTbRLFFWSu/RpTdkLxaVPlNlFUzxc02VQsftzg64=
+humungus.tedunangst.com/r/gerc v0.1.2/go.mod h1:tuYnDVV3WEGI9NEX5/3Iz5xVNimFzN4+83qZvFf/GUg=