OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 package datastore | 5 package datastore |
6 | 6 |
7 import ( | 7 import ( |
8 "fmt" | 8 "fmt" |
| 9 "io" |
| 10 "io/ioutil" |
| 11 "os" |
| 12 "path/filepath" |
9 "reflect" | 13 "reflect" |
| 14 "runtime" |
| 15 "strings" |
10 | 16 |
11 "github.com/luci/luci-go/common/errors" | 17 "github.com/luci/luci-go/common/errors" |
| 18 |
| 19 "gopkg.in/yaml.v2" |
12 ) | 20 ) |
13 | 21 |
14 type datastoreImpl struct { | 22 type datastoreImpl struct { |
15 RawInterface | 23 RawInterface |
16 | 24 |
17 aid string | 25 aid string |
18 ns string | 26 ns string |
19 } | 27 } |
20 | 28 |
21 var _ Interface = (*datastoreImpl)(nil) | 29 var _ Interface = (*datastoreImpl)(nil) |
(...skipping 319 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
341 err = lme.Get() | 349 err = lme.Get() |
342 if err == nil { | 350 if err == nil { |
343 err = extErr | 351 err = extErr |
344 } | 352 } |
345 return | 353 return |
346 } | 354 } |
347 | 355 |
348 func (d *datastoreImpl) Raw() RawInterface { | 356 func (d *datastoreImpl) Raw() RawInterface { |
349 return d.RawInterface | 357 return d.RawInterface |
350 } | 358 } |
| 359 |
| 360 // ParseIndexYAML parses the contents of a index YAML file into a list of |
| 361 // IndexDefinitions. |
| 362 func ParseIndexYAML(content io.Reader) ([]*IndexDefinition, error) { |
| 363 serialized, err := ioutil.ReadAll(content) |
| 364 if err != nil { |
| 365 return nil, err |
| 366 } |
| 367 |
| 368 var m map[string][]*IndexDefinition |
| 369 if err := yaml.Unmarshal(serialized, &m); err != nil { |
| 370 return nil, err |
| 371 } |
| 372 |
| 373 if _, ok := m["indexes"]; !ok { |
| 374 return nil, fmt.Errorf("datastore: missing key `indexes`: %v", m
) |
| 375 } |
| 376 return m["indexes"], nil |
| 377 } |
| 378 |
| 379 // getCallingTestFilePath looks up the call stack until the specified |
| 380 // maxStackDepth and returns the absolute path of the first source filename |
| 381 // ending with `_test.go`. If no test file is found, getCallingTestFilePath |
| 382 // returns a non-nil error. |
| 383 func getCallingTestFilePath(maxStackDepth int) (string, error) { |
| 384 pcs := make([]uintptr, maxStackDepth) |
| 385 |
| 386 for _, pc := range pcs[:runtime.Callers(0, pcs)] { |
| 387 path, _ := runtime.FuncForPC(pc - 1).FileLine(pc - 1) |
| 388 if filename := filepath.Base(path); strings.HasSuffix(filename,
"_test.go") { |
| 389 return path, nil |
| 390 } |
| 391 } |
| 392 |
| 393 return "", fmt.Errorf("datastore: failed to determine source file name") |
| 394 } |
| 395 |
| 396 // FindAndParseIndexYAML walks up from the directory specified by path until it |
| 397 // finds a `index.yaml` or `index.yml` file. If an index YAML file |
| 398 // is found, it opens and parses the file, and returns all the indexes found. |
| 399 // If path is a relative path, it is converted into an absolute path |
| 400 // relative to the calling test file. To determine the path of the calling test |
| 401 // file, FindAndParseIndexYAML walks upto a maximum of 100 call stack frames |
| 402 // looking for a file ending with `_test.go`. |
| 403 // |
| 404 // FindAndParseIndexYAML returns a non-nil error if the root of the drive is |
| 405 // reached without finding an index YAML file, if there was |
| 406 // an error reading the found index YAML file, or if the calling test file could |
| 407 // not be located in the case of a relative path argument. |
| 408 func FindAndParseIndexYAML(path string) ([]*IndexDefinition, error) { |
| 409 var currentDir string |
| 410 |
| 411 if filepath.IsAbs(path) { |
| 412 currentDir = path |
| 413 } else { |
| 414 testPath, err := getCallingTestFilePath(100) |
| 415 if err != nil { |
| 416 return nil, err |
| 417 } |
| 418 currentDir = filepath.Join(filepath.Dir(testPath), path) |
| 419 } |
| 420 |
| 421 isRoot := func(dir string) bool { |
| 422 parentDir := filepath.Dir(dir) |
| 423 return os.IsPathSeparator(dir[len(dir)-1]) && os.IsPathSeparator
(parentDir[len(parentDir)-1]) |
| 424 } |
| 425 |
| 426 for { |
| 427 for _, filename := range []string{"index.yml", "index.yaml"} { |
| 428 file, err := os.Open(filepath.Join(currentDir, filename)
) |
| 429 if err == nil { |
| 430 defer file.Close() |
| 431 return ParseIndexYAML(file) |
| 432 } |
| 433 } |
| 434 |
| 435 if isRoot(currentDir) { |
| 436 return nil, fmt.Errorf("datastore: failed to find index
YAML file") |
| 437 } |
| 438 |
| 439 currentDir = filepath.Dir(currentDir) |
| 440 } |
| 441 } |
OLD | NEW |