| OLD | NEW |
| 1 // Copyright 2015 The LUCI Authors. All rights reserved. | 1 // Copyright 2015 The LUCI Authors. All rights reserved. |
| 2 // Use of this source code is governed under the Apache License, Version 2.0 | 2 // Use of this source code is governed under the Apache License, Version 2.0 |
| 3 // that can be found in the LICENSE file. | 3 // that can be found in the LICENSE file. |
| 4 | 4 |
| 5 package isolate | 5 package isolate |
| 6 | 6 |
| 7 import ( | 7 import ( |
| 8 "bytes" | 8 "bytes" |
| 9 "encoding/json" | 9 "encoding/json" |
| 10 "errors" | 10 "errors" |
| 11 "fmt" | 11 "fmt" |
| 12 "io" | 12 "io" |
| 13 "io/ioutil" | 13 "io/ioutil" |
| 14 "log" | 14 "log" |
| 15 "os" | 15 "os" |
| 16 "path" | 16 "path" |
| 17 "path/filepath" | 17 "path/filepath" |
| 18 "regexp" | 18 "regexp" |
| 19 "sort" | 19 "sort" |
| 20 "strconv" | 20 "strconv" |
| 21 "strings" | 21 "strings" |
| 22 | 22 |
| 23 "go/ast" | 23 "go/ast" |
| 24 "go/parser" | 24 "go/parser" |
| 25 "go/token" | 25 "go/token" |
| 26 | 26 |
| 27 "github.com/luci/luci-go/client/internal/common" | |
| 28 "github.com/luci/luci-go/common/isolated" | 27 "github.com/luci/luci-go/common/isolated" |
| 29 "github.com/yosuke-furukawa/json5/encoding/json5" | 28 "github.com/yosuke-furukawa/json5/encoding/json5" |
| 30 ) | 29 ) |
| 31 | 30 |
| 32 var osPathSeparator = string(os.PathSeparator) | 31 var osPathSeparator = string(os.PathSeparator) |
| 33 | 32 |
| 34 // ReadOnlyValue defines permissions on isolated files. | 33 // ReadOnlyValue defines permissions on isolated files. |
| 35 type ReadOnlyValue int | 34 type ReadOnlyValue int |
| 36 | 35 |
| 37 // Possible kinds of read only values. | 36 // Possible kinds of read only values. |
| (...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 195 relDir = strings.Replace(relDir, "/", osPathSeparator, -1) | 194 relDir = strings.Replace(relDir, "/", osPathSeparator, -1) |
| 196 } | 195 } |
| 197 return config.Command, dependencies, config.ReadOnly, relDir, nil | 196 return config.Command, dependencies, config.ReadOnly, relDir, nil |
| 198 } | 197 } |
| 199 | 198 |
| 200 func loadIncludedIsolate(isolateDir, include string) (*Configs, error) { | 199 func loadIncludedIsolate(isolateDir, include string) (*Configs, error) { |
| 201 if filepath.IsAbs(include) { | 200 if filepath.IsAbs(include) { |
| 202 return nil, fmt.Errorf("failed to load configuration; absolute i
nclude path %s", include) | 201 return nil, fmt.Errorf("failed to load configuration; absolute i
nclude path %s", include) |
| 203 } | 202 } |
| 204 includedIsolate := filepath.Clean(filepath.Join(isolateDir, include)) | 203 includedIsolate := filepath.Clean(filepath.Join(isolateDir, include)) |
| 205 » if common.IsWindows() && (strings.ToLower(includedIsolate)[0] != strings
.ToLower(isolateDir)[0]) { | 204 » if IsWindows() && (strings.ToLower(includedIsolate)[0] != strings.ToLowe
r(isolateDir)[0]) { |
| 206 return nil, errors.New("can't reference a .isolate file from ano
ther drive") | 205 return nil, errors.New("can't reference a .isolate file from ano
ther drive") |
| 207 } | 206 } |
| 208 content, err := ioutil.ReadFile(includedIsolate) | 207 content, err := ioutil.ReadFile(includedIsolate) |
| 209 if err != nil { | 208 if err != nil { |
| 210 return nil, err | 209 return nil, err |
| 211 } | 210 } |
| 212 return LoadIsolateAsConfig(filepath.Dir(includedIsolate), content) | 211 return LoadIsolateAsConfig(filepath.Dir(includedIsolate), content) |
| 213 } | 212 } |
| 214 | 213 |
| 215 // Configs represents a processed .isolate file. | 214 // Configs represents a processed .isolate file. |
| (...skipping 189 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 405 // a path variable, e.g. the characters '<('. | 404 // a path variable, e.g. the characters '<('. |
| 406 func (lhs *ConfigSettings) union(rhs *ConfigSettings) (*ConfigSettings, error) { | 405 func (lhs *ConfigSettings) union(rhs *ConfigSettings) (*ConfigSettings, error) { |
| 407 // When an object has IsolateDir == "", it means it is the empty object. | 406 // When an object has IsolateDir == "", it means it is the empty object. |
| 408 if lhs.IsolateDir == "" { | 407 if lhs.IsolateDir == "" { |
| 409 return rhs, nil | 408 return rhs, nil |
| 410 } | 409 } |
| 411 if rhs.IsolateDir == "" { | 410 if rhs.IsolateDir == "" { |
| 412 return lhs, nil | 411 return lhs, nil |
| 413 } | 412 } |
| 414 | 413 |
| 415 » if common.IsWindows() && strings.ToLower(lhs.IsolateDir)[0] != strings.T
oLower(rhs.IsolateDir)[0] { | 414 » if IsWindows() && strings.ToLower(lhs.IsolateDir)[0] != strings.ToLower(
rhs.IsolateDir)[0] { |
| 416 return nil, errors.New("All .isolate files must be on same drive
") | 415 return nil, errors.New("All .isolate files must be on same drive
") |
| 417 } | 416 } |
| 418 | 417 |
| 419 // Takes the difference between the two isolateDir. Note that while | 418 // Takes the difference between the two isolateDir. Note that while |
| 420 // isolateDir is in native path case, all other references are in posix. | 419 // isolateDir is in native path case, all other references are in posix. |
| 421 useRHS := false | 420 useRHS := false |
| 422 var command []string | 421 var command []string |
| 423 if len(lhs.Command) > 0 { | 422 if len(lhs.Command) > 0 { |
| 424 useRHS = false | 423 useRHS = false |
| 425 command = lhs.Command | 424 command = lhs.Command |
| (...skipping 356 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 782 } | 781 } |
| 783 if err != nil { | 782 if err != nil { |
| 784 return false | 783 return false |
| 785 } | 784 } |
| 786 switch n := n.(type) { | 785 switch n := n.(type) { |
| 787 case *ast.BinaryExpr: | 786 case *ast.BinaryExpr: |
| 788 if n.Op == token.LAND || n.Op == token.LOR { | 787 if n.Op == token.LAND || n.Op == token.LOR { |
| 789 return true | 788 return true |
| 790 } | 789 } |
| 791 if n.Op != token.EQL { | 790 if n.Op != token.EQL { |
| 792 » » » » err = fmt.Errorf("unknown binary operator %s\n",
n.Op) | 791 » » » » err = fmt.Errorf("unknown binary operator %s", n
.Op) |
| 793 return false | 792 return false |
| 794 } | 793 } |
| 795 id, value, tmpErr := verifyIDEqualValue(n) | 794 id, value, tmpErr := verifyIDEqualValue(n) |
| 796 if tmpErr != nil { | 795 if tmpErr != nil { |
| 797 err = tmpErr | 796 err = tmpErr |
| 798 return false | 797 return false |
| 799 } | 798 } |
| 800 equalityValues[n.Pos()] = value | 799 equalityValues[n.Pos()] = value |
| 801 if _, exists := varsAndValues[id]; !exists { | 800 if _, exists := varsAndValues[id]; !exists { |
| 802 varsAndValues[id] = map[variableValueKey]variabl
eValue{} | 801 varsAndValues[id] = map[variableValueKey]variabl
eValue{} |
| 803 } | 802 } |
| 804 varsAndValues[id][value.key()] = value | 803 varsAndValues[id][value.key()] = value |
| 805 return false | 804 return false |
| 806 case *ast.ParenExpr: | 805 case *ast.ParenExpr: |
| 807 return true | 806 return true |
| 808 default: | 807 default: |
| 809 » » » err = fmt.Errorf("unknown expression type %T\n", n) | 808 » » » err = fmt.Errorf("unknown expression type %T", n) |
| 810 return false | 809 return false |
| 811 } | 810 } |
| 812 // unreachable | 811 // unreachable |
| 813 }) | 812 }) |
| 814 if err != nil { | 813 if err != nil { |
| 815 return nil, fmt.Errorf("invalid Condition: %s", err) | 814 return nil, fmt.Errorf("invalid Condition: %s", err) |
| 816 } | 815 } |
| 817 return equalityValues, nil | 816 return equalityValues, nil |
| 818 } | 817 } |
| 819 | 818 |
| (...skipping 246 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1066 return len(c) | 1065 return len(c) |
| 1067 } | 1066 } |
| 1068 | 1067 |
| 1069 func (c configPairs) Less(i, j int) bool { | 1068 func (c configPairs) Less(i, j int) bool { |
| 1070 return c[i].key.compare(c[j].key) > 0 | 1069 return c[i].key.compare(c[j].key) > 0 |
| 1071 } | 1070 } |
| 1072 | 1071 |
| 1073 func (c configPairs) Swap(i, j int) { | 1072 func (c configPairs) Swap(i, j int) { |
| 1074 c[i], c[j] = c[j], c[i] | 1073 c[i], c[j] = c[j], c[i] |
| 1075 } | 1074 } |
| OLD | NEW |