Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(13)

Side by Side Diff: vpython/python/find.go

Issue 2943513002: [vpython] Fix intolerant lookup logic. (Closed)
Patch Set: Created 3 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2017 The LUCI Authors. All rights reserved. 1 // Copyright 2017 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 python 5 package python
6 6
7 import ( 7 import (
8 "os/exec" 8 "os/exec"
9 9
10 "github.com/luci/luci-go/common/errors" 10 "github.com/luci/luci-go/common/errors"
11 "github.com/luci/luci-go/common/logging"
11 12
12 "golang.org/x/net/context" 13 "golang.org/x/net/context"
13 ) 14 )
14 15
15 // LookPathResult is the result of LookPathFunc. 16 // LookPathResult is the result of LookPathFunc.
16 type LookPathResult struct { 17 type LookPathResult struct {
17 // Path, if not zero, is the absolute path to the identified target 18 // Path, if not zero, is the absolute path to the identified target
18 // executable. 19 // executable.
19 Path string 20 Path string
20 21
(...skipping 14 matching lines...) Expand all
35 // 36 //
36 // A nil LookPathFunc will use exec.LookPath. 37 // A nil LookPathFunc will use exec.LookPath.
37 type LookPathFunc func(c context.Context, target string) (*LookPathResult, error ) 38 type LookPathFunc func(c context.Context, target string) (*LookPathResult, error )
38 39
39 // Find attempts to find a Python interpreter matching the supplied version 40 // Find attempts to find a Python interpreter matching the supplied version
40 // using PATH. 41 // using PATH.
41 // 42 //
42 // In order to accommodate multiple configurations on operating systems, Find 43 // In order to accommodate multiple configurations on operating systems, Find
43 // will attempt to identify versions that appear on the path 44 // will attempt to identify versions that appear on the path
44 func Find(c context.Context, vers Version, lookPath LookPathFunc) (*Interpreter, error) { 45 func Find(c context.Context, vers Version, lookPath LookPathFunc) (*Interpreter, error) {
45 if lookPath == nil {
46 lookPath = func(c context.Context, target string) (*LookPathResu lt, error) {
47 v, err := exec.LookPath(target)
48 if err != nil {
49 return nil, err
50 }
51 return &LookPathResult{Path: v}, nil
52 }
53 }
54
55 // pythonM.m, pythonM, python 46 // pythonM.m, pythonM, python
56 searches := make([]string, 0, 3) 47 searches := make([]string, 0, 3)
57 pv := vers 48 pv := vers
58 pv.Patch = 0 49 pv.Patch = 0
59 if pv.Minor > 0 { 50 if pv.Minor > 0 {
60 searches = append(searches, pv.PythonBase()) 51 searches = append(searches, pv.PythonBase())
61 pv.Minor = 0 52 pv.Minor = 0
62 } 53 }
63 if pv.Major > 0 { 54 if pv.Major > 0 {
64 searches = append(searches, pv.PythonBase()) 55 searches = append(searches, pv.PythonBase())
65 pv.Major = 0 56 pv.Major = 0
66 } 57 }
67 searches = append(searches, pv.PythonBase()) 58 searches = append(searches, pv.PythonBase())
68 59
69 » for _, s := range searches { 60 » lookErrs := errors.NewLazyMultiError(len(searches))
70 » » lpr, err := lookPath(c, s) 61 » for i, s := range searches {
71 » » if err != nil { 62 » » interp, err := findInterpreter(c, s, vers, lookPath)
72 » » » if e, ok := err.(*exec.Error); ok && e.Err == exec.ErrNo tFound { 63 » » if err == nil {
73 » » » » // Not found is okay. 64 » » » return interp, nil
74 » » » » continue
75 » » » }
76 » » » return nil, errors.Annotate(err).Reason("failed to searc h PATH for: %(interp)q").
77 » » » » D("interp", s).
78 » » » » Err()
79 } 65 }
80 66
81 » » i := Interpreter{ 67 » » logging.WithError(err).Debugf(c, "Could not find Python for: %q. ", s)
82 » » » Python: lpr.Path, 68 » » lookErrs.Assign(i, err)
83 » » }
84
85 » » // If our LookPathResult included a target version, install that into the
86 » » // Interpreter, allowing it to use this cached value when GetVer sion is
87 » » // called instead of needing to perform an additional lookup.
88 » » //
89 » » // Note that our LookPathResult may not populate Version, in whi ch case we
90 » » // will not pre-cache it.
91 » » if !lpr.Version.IsZero() {
92 » » » i.cachedVersion = &lpr.Version
93 » » }
94 » » if err := i.Normalize(); err != nil {
95 » » » return nil, err
96 » » }
97
98 » » iv, err := i.GetVersion(c)
99 » » if err != nil {
100 » » » return nil, errors.Annotate(err).Reason("failed to get v ersion for: %(interp)q").
101 » » » » D("interp", i.Python).
102 » » » » Err()
103 » » }
104 » » if vers.IsSatisfiedBy(iv) {
105 » » » return &i, nil
106 » » }
107 } 69 }
108 70
109 » return nil, errors.New("no Python found") 71 » // No Python interpreter could be identified.
72 » return nil, errors.Annotate(lookErrs.Get()).Reason("no Python found").Er r()
110 } 73 }
74
75 func findInterpreter(c context.Context, name string, vers Version, lookPath Look PathFunc) (*Interpreter, error) {
76 if lookPath == nil {
77 lookPath = osExecLookPath
78 }
79 lpr, err := lookPath(c, name)
80 if err != nil {
81 return nil, errors.Annotate(err).Reason("could not find executab le for: %(name)q").
82 D("name", name).
83 Err()
84 }
85
86 i := Interpreter{
87 Python: lpr.Path,
88 }
89
90 // If our LookPathResult included a target version, install that into th e
91 // Interpreter, allowing it to use this cached value when GetVersion is
92 // called instead of needing to perform an additional lookup.
93 //
94 // Note that our LookPathResult may not populate Version, in which case we
95 // will not pre-cache it.
96 if !lpr.Version.IsZero() {
97 i.cachedVersion = &lpr.Version
98 }
99 if err := i.Normalize(); err != nil {
100 return nil, err
101 }
102
103 iv, err := i.GetVersion(c)
104 if err != nil {
105 return nil, errors.Annotate(err).Reason("failed to get version f or: %(interp)q").
106 D("interp", i.Python).
107 Err()
108 }
109 if !vers.IsSatisfiedBy(iv) {
110 return nil, errors.Reason("interpreter %(interp)q version %(inte rpVersion)q does not satisfy %(version)q").
111 D("interp", i.Python).
112 D("interpVersion", iv).
113 D("version", vers).
114 Err()
115 }
116
117 return &i, nil
118 }
119
120 func osExecLookPath(c context.Context, target string) (*LookPathResult, error) {
121 v, err := exec.LookPath(target)
122 if err != nil {
123 return nil, err
124 }
125 return &LookPathResult{Path: v}, nil
126 }
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698