def apply_patch(stage, patch_path, level=1, working_dir='.'): """Apply the patch at patch_path to code in the stage. Args: stage (spack.stage.Stage): stage with code that will be patched patch_path (str): filesystem location for the patch to apply level (int or None): patch level (default 1) working_dir (str): relative path *within* the stage to change to (default '.') """ git_utils_path = os.environ.get('PATH', '') if sys.platform == 'win32': git = which_string('git', required=True) git_root = git.split('\\')[:-2] git_root.extend(['usr', 'bin']) git_utils_path = os.sep.join(git_root) # TODO: Decouple Spack's patch support on Windows from Git # for Windows, and instead have Spack directly fetch, install, and # utilize that patch. # Note for future developers: The GNU port of patch to windows # has issues handling CRLF line endings unless the --binary # flag is passed. patch = which("patch", required=True, path=git_utils_path) with llnl.util.filesystem.working_dir(stage.source_path): patch('-s', '-p', str(level), '-i', patch_path, '-d', working_dir)
def _find_exe_from_env_var(var): """Find an executable from an environment variable. Args: var (str): environment variable name Returns: (str or None, list): executable string (or None if not found) and arguments parsed from the env var """ # try to get the environment variable exe = os.environ.get(var) if not exe: return None, [] # split env var into executable and args if needed args = shlex.split(str(exe)) if not args: return None, [] exe = which_string(args[0]) args = [exe] + args[1:] return exe, args
def editor(*args, **kwargs): """Invoke the user's editor. This will try to execute the following, in order: 1. $VISUAL <args> # the "visual" editor (per POSIX) 2. $EDITOR <args> # the regular editor (per POSIX) 3. some default editor (see ``_default_editors``) with <args> If an environment variable isn't defined, it is skipped. If it points to something that can't be executed, we'll print a warning. And if we can't find anything that can be executed after searching the full list above, we'll raise an error. Arguments: args (list of str): args to pass to editor Optional Arguments: _exec_func (function): invoke this function instead of ``os.execv()`` """ # allow this to be customized for testing _exec_func = kwargs.get('_exec_func', os.execv) def try_exec(exe, args, var=None): """Try to execute an editor with execv, and warn if it fails. Returns: (bool) False if the editor failed, ideally does not return if ``execv`` succeeds, and ``True`` if the ``_exec_func`` does return successfully. """ try: _exec_func(exe, args) return True except OSError as e: if spack.config.get('config:debug'): raise # Show variable we were trying to use, if it's from one if var: exe = '$%s (%s)' % (var, exe) tty.warn('Could not execute %s due to error:' % exe, str(e)) return False def try_env_var(var): """Find an editor from an environment variable and try to exec it. This will warn if the variable points to something is not executable, or if there is an error when trying to exec it. """ if var not in os.environ: return False exe, editor_args = _find_exe_from_env_var(var) if not exe: tty.warn('$%s is not an executable:' % var, os.environ[var]) return False full_args = editor_args + list(args) return try_exec(exe, full_args, var) # try standard environment variables if try_env_var('VISUAL'): return if try_env_var('EDITOR'): return # nothing worked -- try the first default we can find don't bother # trying them all -- if we get here and one fails, something is # probably much more deeply wrong with the environment. exe = which_string(*_default_editors) if try_exec(exe, [exe] + list(args)): return # Fail if nothing could be found raise EnvironmentError( 'No text editor found! Please set the VISUAL and/or EDITOR ' 'environment variable(s) to your preferred text editor.')