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

Side by Side Diff: vpython/application/probe.go

Issue 2925723004: [vpython] Implement smart probing. (Closed)
Patch Set: move to system 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
OLDNEW
(Empty)
1 // Copyright 2017 The LUCI Authors. All rights reserved.
2 // Use of this source code is governed under the Apache License, Version 2.0
3 // that can be found in the LICENSE file.
4
5 package application
6
7 import (
8 "os/exec"
9
10 "golang.org/x/net/context"
11
12 "github.com/luci/luci-go/vpython/python"
13
14 "github.com/luci/luci-go/common/errors"
15 "github.com/luci/luci-go/common/logging"
16 "github.com/luci/luci-go/common/system/environ"
17 "github.com/luci/luci-go/common/system/exitcode"
18 "github.com/luci/luci-go/common/system/prober"
19 )
20
21 const (
22 // CheckWrapperENV is an environment variable that is used to detect if a
23 // given binary is a "vpython" wrapper instance. The "vpython" Main func tion
24 // will immediately exit with a non-zero return code if this environment
25 // variable is set.
26 //
27 // See checkWrapper for more details.
28 CheckWrapperENV = "VPYTHON_CHECK_WRAPPER"
29 )
30
31 type lookPath struct {
32 // probeBase is a base prober whose Self and SelfStat fields will be use d
33 // during a lookPathImpl call. This ensures that we only have to call
34 // ResolveSelf once for any given application.
35 probeBase prober.Probe
36
37 env environ.Env
38 lastPath string
39 lastVersionOutput []byte
40 }
41
42 func (lp *lookPath) look(c context.Context, target string) (*python.LookPathResu lt, error) {
43 // Construct our probe, derived it from our "probeBase" and tailored to the
44 // specific "target" we're looking for.
45 probe := lp.probeBase
46 probe.Target = target
47 probe.CheckWrapper = lp.checkWrapper
48
49 var result python.LookPathResult
50 var err error
51 if result.Path, err = probe.Locate(c, "", lp.env.Clone()); err != nil {
52 return nil, err
53 }
54
55 // During probing, we try and capture the output of "--version". If we d o,
56 // and if we confirm that the "path" returned by the probe matches "last Path",
57 // return this version along with the resolution.
58 if result.Path == lp.lastPath {
59 var err error
60 if result.Version, err = python.ParseVersionOutput(lp.lastVersio nOutput); err == nil {
61 logging.Debugf(c, "Detected Python version %q from probe candidate [%s]", result.Version, result.Path)
62 } else {
63 logging.Debugf(c, "Failed to parse version from probe ca ndidate [%s]: %s", result.Path, err)
64 }
65 }
66
67 return &result, nil
68 }
69
70 // checkWrapper is a prober.CheckWrapperFunc that detects if a given path is a
71 // "vpython" instance.
72 //
73 // It does this by running it "path --version" with CheckWrapperENV set. If
74 // the target is a "vpython" wrapper, it will immediately exit with a non-zero
75 // value (see Main). If it is not a valid Python program, its behavior is
76 // undefined. If it is a valid Pytohn instance, it will exit with a Python
77 // version string.
78 //
79 // As a side effect, the text output of the last version probe will be stored
80 // in lp.lastVersionOutput. The "look" function can pass this value on to
81 // the LookPathResult.
82 func (lp *lookPath) checkWrapper(c context.Context, path string, env environ.Env ) (isWrapper bool, err error) {
83 lp.lastPath = path
84 env.Set(CheckWrapperENV, "1")
85
86 cmd := exec.CommandContext(c, path, "--version")
87 cmd.Env = env.Sorted()
88
89 lp.lastVersionOutput, err = cmd.CombinedOutput()
90 rc, ok := exitcode.Get(err)
91 if !ok {
92 err = errors.Annotate(err).Reason("failed to check if %(path)q i s a wrapper").
93 D("path", path).
94 Err()
95 return
96 }
97
98 // If "--version" didn't return "0", we determine that this is a wrapper ,
99 // since no Python interpreter would return non-zero for "--version".
iannucci 2017/06/07 17:40:26 it might if it failed to load properly though, rig
dnj 2017/06/07 17:43:26 If it fails to load properly, we should not use it
dnj 2017/06/07 17:45:51 OTOH if Python is broken, I don't want "vpython" t
100 isWrapper, err = (rc != 0), nil
101 return
102 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698