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

Side by Side Diff: recipe_engine/step_runner.py

Issue 2727553005: [step_runner] add logic to resolve absolute path of argv[0] on windows. (Closed)
Patch Set: Created 3 years, 9 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 2016 The LUCI Authors. All rights reserved. 1 # Copyright 2016 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 import calendar 5 import calendar
6 import collections 6 import collections
7 import contextlib 7 import contextlib
8 import datetime 8 import datetime
9 import itertools
9 import json 10 import json
10 import os 11 import os
11 import re 12 import re
12 import StringIO 13 import StringIO
13 import sys 14 import sys
14 import tempfile 15 import tempfile
15 import time 16 import time
16 import traceback 17 import traceback
17 18
18 from . import recipe_api 19 from . import recipe_api
(...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after
169 def stream(inner): 170 def stream(inner):
170 return step_stream 171 return step_stream
171 172
172 return EmptyOpenStep() 173 return EmptyOpenStep()
173 174
174 rendered_step = render_step( 175 rendered_step = render_step(
175 step_config, recipe_test_api.DisabledTestData() 176 step_config, recipe_test_api.DisabledTestData()
176 ) 177 )
177 step_config = None # Make sure we use rendered step config. 178 step_config = None # Make sure we use rendered step config.
178 179
179 rendered_step = rendered_step._replace(
180 config=rendered_step.config._replace(
181 cmd=map(str, rendered_step.config.cmd),
182 ),
183 )
184
185 step_env = _merge_envs(os.environ, (rendered_step.config.env or {})) 180 step_env = _merge_envs(os.environ, (rendered_step.config.env or {}))
181 # Now that the step's environment is all sorted, evaluate PATH and PATHEXT
182 # on windows to find the actual intended executable.
183 rendered_step = _hunt_path(rendered_step, step_env)
186 self._print_step(step_stream, rendered_step, step_env) 184 self._print_step(step_stream, rendered_step, step_env)
187 185
188 class ReturnOpenStep(OpenStep): 186 class ReturnOpenStep(OpenStep):
189 def run(inner): 187 def run(inner):
190 step_config = rendered_step.config 188 step_config = rendered_step.config
191 try: 189 try:
192 # Open file handles for IO redirection based on file names in 190 # Open file handles for IO redirection based on file names in
193 # step_config. 191 # step_config.
194 handles = { 192 handles = {
195 'stdout': step_stream, 193 'stdout': step_stream,
(...skipping 336 matching lines...) Expand 10 before | Expand all | Expand 10 after
532 # This assert ensures that: 530 # This assert ensures that:
533 # no two placeholders have the same name 531 # no two placeholders have the same name
534 # at most one placeholder has the default name 532 # at most one placeholder has the default name
535 assert item.name not in output_phs[module_name][placeholder_name], ( 533 assert item.name not in output_phs[module_name][placeholder_name], (
536 'Step "%s" has multiple output placeholders of %s.%s. Please ' 534 'Step "%s" has multiple output placeholders of %s.%s. Please '
537 'specify explicit and different names for them.' % ( 535 'specify explicit and different names for them.' % (
538 step_config.name, module_name, placeholder_name)) 536 step_config.name, module_name, placeholder_name))
539 output_phs[module_name][placeholder_name][item.name] = (item, tdata) 537 output_phs[module_name][placeholder_name][item.name] = (item, tdata)
540 else: 538 else:
541 new_cmd.append(item) 539 new_cmd.append(item)
542 step_config = step_config._replace(cmd=new_cmd) 540 step_config = step_config._replace(cmd=map(str, new_cmd))
543 541
544 # Process 'stdout', 'stderr' and 'stdin' placeholders, if given. 542 # Process 'stdout', 'stderr' and 'stdin' placeholders, if given.
545 stdio_placeholders = {} 543 stdio_placeholders = {}
546 for key in ('stdout', 'stderr', 'stdin'): 544 for key in ('stdout', 'stderr', 'stdin'):
547 placeholder = getattr(step_config, key) 545 placeholder = getattr(step_config, key)
548 tdata = None 546 tdata = None
549 if placeholder: 547 if placeholder:
550 if key == 'stdin': 548 if key == 'stdin':
551 assert isinstance(placeholder, util.InputPlaceholder), ( 549 assert isinstance(placeholder, util.InputPlaceholder), (
552 '%s(%r) should be an InputPlaceholder.' % (key, placeholder)) 550 '%s(%r) should be an InputPlaceholder.' % (key, placeholder))
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after
643 return result 641 return result
644 for k, v in override.items(): 642 for k, v in override.items():
645 if v is None: 643 if v is None:
646 if k in result: 644 if k in result:
647 del result[k] 645 del result[k]
648 else: 646 else:
649 result[str(k)] = str(v) % original 647 result[str(k)] = str(v) % original
650 return result 648 return result
651 649
652 650
651 if sys.platform == "win32":
Vadim Sh. 2017/03/01 19:40:45 nit: the rest of the file seems to be using ' for
652 def _hunt_path(rendered_step, step_env):
653 """This takes the lazy cross-product of PATH and PATHEXT to find what
654 cmd.exe would have found for the command if we used shell=True.
655
656 This must be called on the render_step AFTER _merge_envs has produced
657 step_env to pick up any changes to PATH or PATHEXT.
658
659 If it succeeds, it returns a new rendered_step. If it fails, it returns the
660 same rendered_step, and subprocess will run as normal (and likely fail).
661
662 This will not attempt to do any evaluations for commands where the program
663 already has an explicit extension (.exe, .bat, etc.), and it will not
664 attempt to do any evaluations for commands where the program is an absolute
665 path.
666 """
667 cmd = rendered_step.cmd
668 cmd0 = cmd[0]
669 if '.' in cmd0: # something.ext will work fine with subprocess.
670 return rendered_step
671 if os.path.abspath(cmd0): # PATH isn't even used
672 return rendered_step
673
674 # begin the hunt
675 full_path = step_env.get("PATH", "").split(os.path.pathsep)
676 full_pathext = step_env.get("PATHEXT", ".EXE;.BAT").split(os.path.pathsep)
Vadim Sh. 2017/03/01 19:40:45 nit: let's lower them, or we'll have ugly "cipd.EX
677 if not (full_path and full_pathext):
678 return rendered_step
679
680 # try every extension for each path
681 for path, ext in itertools.product(path, ext):
Vadim Sh. 2017/03/01 19:40:45 er.. what?.. Should it be itertools.product(full_p
682 candidate = os.path.join(path, cmd0+ext)
683 if os.path.exists(candidate):
684 return rendered_step._replace(
685 config=rendered_step.config._replace(
686 cmd=[candidate]+cmd[1:],
687 ),
688 )
689 return rendered_step
690 else:
691 def _hunt_path(rendered_step, _step_env):
692 return rendered_step
693
694
653 def _shell_quote(arg): 695 def _shell_quote(arg):
654 """Shell-quotes a string with minimal noise. 696 """Shell-quotes a string with minimal noise.
655 697
656 Such that it is still reproduced exactly in a bash/zsh shell. 698 Such that it is still reproduced exactly in a bash/zsh shell.
657 """ 699 """
658 700
659 arg = arg.encode('utf-8') 701 arg = arg.encode('utf-8')
660 702
661 if arg == '': 703 if arg == '':
662 return "''" 704 return "''"
(...skipping 15 matching lines...) Expand all
678 supplied command, and only uses the |env| kwarg for modifying the environment 720 supplied command, and only uses the |env| kwarg for modifying the environment
679 of the child process. 721 of the child process.
680 """ 722 """
681 saved_path = os.environ['PATH'] 723 saved_path = os.environ['PATH']
682 try: 724 try:
683 if path is not None: 725 if path is not None:
684 os.environ['PATH'] = path 726 os.environ['PATH'] = path
685 yield 727 yield
686 finally: 728 finally:
687 os.environ['PATH'] = saved_path 729 os.environ['PATH'] = saved_path
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