aboutsummaryrefslogtreecommitdiff
path: root/go/runfiles/manifest.go
diff options
context:
space:
mode:
Diffstat (limited to 'go/runfiles/manifest.go')
-rw-r--r--go/runfiles/manifest.go91
1 files changed, 91 insertions, 0 deletions
diff --git a/go/runfiles/manifest.go b/go/runfiles/manifest.go
new file mode 100644
index 00000000..4d8e8798
--- /dev/null
+++ b/go/runfiles/manifest.go
@@ -0,0 +1,91 @@
+// Copyright 2020, 2021 Google LLC
+//
+// 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
+//
+// https://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.
+
+package runfiles
+
+import (
+ "bufio"
+ "fmt"
+ "os"
+ "path"
+ "path/filepath"
+ "strings"
+)
+
+// ManifestFile specifies the location of the runfile manifest file. You can
+// pass this as an option to New. If unset or empty, use the value of the
+// environmental variable RUNFILES_MANIFEST_FILE.
+type ManifestFile string
+
+func (f ManifestFile) new(sourceRepo SourceRepo) (*Runfiles, error) {
+ m, err := f.parse()
+ if err != nil {
+ return nil, err
+ }
+ r := &Runfiles{
+ impl: m,
+ env: manifestFileVar + "=" + string(f),
+ sourceRepo: string(sourceRepo),
+ }
+ err = r.loadRepoMapping()
+ return r, err
+}
+
+type manifest map[string]string
+
+func (f ManifestFile) parse() (manifest, error) {
+ r, err := os.Open(string(f))
+ if err != nil {
+ return nil, fmt.Errorf("runfiles: can’t open manifest file: %w", err)
+ }
+ defer r.Close()
+
+ s := bufio.NewScanner(r)
+ m := make(manifest)
+ for s.Scan() {
+ fields := strings.SplitN(s.Text(), " ", 2)
+ if len(fields) != 2 || fields[0] == "" {
+ return nil, fmt.Errorf("runfiles: bad manifest line %q in file %s", s.Text(), f)
+ }
+ m[fields[0]] = filepath.FromSlash(fields[1])
+ }
+
+ if err := s.Err(); err != nil {
+ return nil, fmt.Errorf("runfiles: error parsing manifest file %s: %w", f, err)
+ }
+
+ return m, nil
+}
+
+func (m manifest) path(s string) (string, error) {
+ r, ok := m[s]
+ if ok && r == "" {
+ return "", ErrEmpty
+ }
+ if ok {
+ return r, nil
+ }
+
+ // If path references a runfile that lies under a directory that itself is a
+ // runfile, then only the directory is listed in the manifest. Look up all
+ // prefixes of path in the manifest.
+ for prefix := s; prefix != ""; prefix, _ = path.Split(prefix) {
+ prefix = strings.TrimSuffix(prefix, "/")
+ if prefixMatch, ok := m[prefix]; ok {
+ return prefixMatch + filepath.FromSlash(strings.TrimPrefix(s, prefix)), nil
+ }
+ }
+
+ return "", os.ErrNotExist
+}