Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,23 @@
# Change Log

## 2.40.4 (2019-12-11)

**Notes**

- Enable support for the --rcfile argument for powershell.
The file specified after this flag is injected right before the info "You are now in a rez-configured environment." in the target_file
- Enable support for the --stdin argument for powershell.

Testing this new feature has been activated by doing the following changes:
- the test test_shells.test_rcfile now adds an extension to the rcfile created

- the function rez.util.create_executable_script has been changed to work on linux and windows

- the binding rez.bind.hello_world.py has been changed to work on linux and windows

- the decorator rez.tests.utils.shell_dependent, has been edited to stop skipping everything once a shell has been excluded
(replaced self.skipTest by continue)

## 2.40.3 (2019-08-15)
[Source](https://github.com/nerdvegas/rez/tree/2.40.3) | [Diff](https://github.com/nerdvegas/rez/compare/2.40.2...2.40.3)

Expand Down
72 changes: 59 additions & 13 deletions src/rez/bind/hello_world.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@
from rez.utils.lint_helper import env
from rez.util import create_executable_script
from rez.bind._utils import make_dirs, check_version
from rez.system import system
import os
import os.path
import inspect


def commands():
Expand All @@ -21,19 +24,59 @@ def commands():


def hello_world_source():
import sys
from optparse import OptionParser
if os.name == "nt":
code = \
"""
@echo off

p = OptionParser()
p.add_option("-q", dest="quiet", action="store_true",
help="quiet mode")
p.add_option("-r", dest="retcode", type="int", default=0,
help="exit with a non-zero return code")
opts,args = p.parse_args()
set quiet=0
set retcode=0

:loop
IF NOT "%1"=="" (
IF "%1"=="-q" (
set quiet=1
SHIFT
)
IF "%1"=="-r" (
set retcode=%2
SHIFT
SHIFT
)
GOTO :loop
)

IF %quiet%==0 (
echo Hello Rez World!
)
exit %retcode%
"""
return inspect.cleandoc(code)

if not opts.quiet:
print("Hello Rez World!")
sys.exit(opts.retcode)
else:
code = \
"""
set -e

retcode=0

while [ "$1" != "" ]; do
case $1 in
-q | --quiet ) quiet=1
;;
-r | --retcode ) retcode="$2"
shift
;;
esac
shift
done

if [ -z $quiet ]; then
echo Hello Rez World!
fi
exit $retcode
"""
return inspect.cleandoc(code)


def bind(path, version_range=None, opts=None, parser=None):
Expand All @@ -43,8 +86,11 @@ def bind(path, version_range=None, opts=None, parser=None):
def make_root(variant, root):
binpath = make_dirs(root, "bin")
filepath = os.path.join(binpath, "hello_world")
create_executable_script(filepath, hello_world_source)

program = "bash"
if os.name == "nt":
program = "cmd"
create_executable_script(filepath, hello_world_source(), program=program)

with make_package("hello_world", path, make_root=make_root) as pkg:
pkg.version = version
pkg.tools = ["hello_world"]
Expand Down
3 changes: 2 additions & 1 deletion src/rez/tests/test_shells.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,8 @@ def test_rcfile(self):
rcfile, _, _, command = sh.startup_capabilities(rcfile=True, command=True)

if rcfile and command:
f, path = tempfile.mkstemp()
# Force extension (mainly needed for windows)
f, path = tempfile.mkstemp(prefix="rcfile_", suffix=".{}".format(sh.file_extension()))
os.write(f, "hello_world\n")
os.close(f)

Expand Down
3 changes: 2 additions & 1 deletion src/rez/tests/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,8 @@ def wrapper(self, *args, **kwargs):

for shell in shells:
if exclude and shell in exclude:
self.skipTest("This test does not run on %s shell." % shell)
print("This test does not run on %s shell." % shell)
continue
print("\ntesting in shell: %s..." % shell)
config.override("default_shell", shell)
func(self, *args, **kwargs)
Expand Down
10 changes: 8 additions & 2 deletions src/rez/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,16 @@ def create_executable_script(filepath, body, program=None):

if not body.endswith('\n'):
body += '\n'

if os.name == "nt":
if program == "cmd" and not filepath.endswith(".bat"):
filepath += ".bat"
if program == "powershell" and not filepath.endswith(".ps1"):
filepath += ".ps1"

with open(filepath, 'w') as f:
# TODO: make cross platform
f.write("#!/usr/bin/env %s\n" % program)
if os.name == "posix":
f.write("#!/usr/bin/env %s\n" % program)
f.write(body)

# TODO: Although Windows supports os.chmod you can only set the readonly
Expand Down
2 changes: 1 addition & 1 deletion src/rez/utils/_version.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@


# Update this value to version up Rez. Do not place anything else in this file.
_rez_version = "2.40.3"
_rez_version = "2.40.4"


# Copyright 2013-2016 Allan Johns.
Expand Down
80 changes: 72 additions & 8 deletions src/rezplugins/shell/powershell.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
class PowerShell(CMD):
syspaths = None
_executable = None
stdin_arg_name = "in_stdin"

@property
def executable(cls):
Expand All @@ -36,28 +37,64 @@ def file_extension(cls):
@classmethod
def startup_capabilities(cls, rcfile=False, norc=False, stdin=False,
command=False):
cls._unsupported_option('rcfile', rcfile)
cls._unsupported_option('norc', norc)
cls._unsupported_option('stdin', stdin)
rcfile = False
norc = False
stdin = False

if command not in (None, False):
cls._overruled_option('stdin', 'command', stdin)
cls._overruled_option('rcfile', 'command', rcfile)
stdin = False
rcfile = False
if stdin:
cls._overruled_option('rcfile', 'stdin', rcfile)
rcfile = False

return (rcfile, norc, stdin, command)

@classmethod
def get_startup_sequence(cls, rcfile, norc, stdin, command):
rcfile, norc, stdin, command = \
cls.startup_capabilities(rcfile, norc, stdin, command)

files = []
do_rcfile = False

if rcfile:
do_rcfile = True
if rcfile and os.path.exists(os.path.expanduser(rcfile)) and rcfile.endswith(".ps1"):
files.append(rcfile)

return dict(
stdin=stdin,
command=command,
do_rcfile=False,
do_rcfile=do_rcfile,
envvar=None,
files=[],
files=files,
bind_files=[],
source_bind_files=(not norc)
)

def add_argument_parser(self, arg_dict={}):
"""
dict is of form:
arg_dict= { argument1: {"type": type,
"default_value": default_value
},
argument2: {"type": type,
"default_value": default_value
}
}
"""
self._addline('param (')
for arg in arg_dict:
self._addline('\t[{}]${}={}'.format( arg_dict[arg]["type"],
arg,
arg_dict[arg]["default_value"])
)
self._addline(')')

def invoke(self, expr):
self._addline('Invoke-Expression {}'.format(expr))

def _bind_interactive_rez(self):
if config.set_prompt and self.settings.prompt:
Expand All @@ -71,11 +108,18 @@ def spawn_shell(self, context_file, tmpdir, rcfile=None, norc=False,
shell_command = None

def _record_shell(ex, files, bind_rez=True, print_msg=False):
if startup_sequence["stdin"]:
# prepare the script for $input argument
arg_data = {self.stdin_arg_name:{"type":"string", "default_value":'""'}}
ex.interpreter.add_argument_parser(arg_data)
ex.source(context_file)
if startup_sequence["envvar"]:
ex.unsetenv(startup_sequence["envvar"])
if bind_rez:
ex.interpreter._bind_interactive_rez()
# The "files" item can only be fed by the rcfile argument, it should contain only one element
for f in startup_sequence["files"]:
ex.source(f)
if print_msg and not quiet:
ex.info('You are now in a rez-configured environment.')

Expand All @@ -84,6 +128,9 @@ def _record_shell(ex, files, bind_rez=True, print_msg=False):
# available, in which case the command will succeed
# but output to stderr, muted with 2>$null
ex.command("Try { rez context 2>$null } Catch { }")
if startup_sequence["stdin"]:
# Invoke what was passed to stdin
ex.interpreter.invoke("${}".format(self.stdin_arg_name))

executor = RexExecutor(interpreter=self.new_shell(),
parent_environ={},
Expand All @@ -92,6 +139,9 @@ def _record_shell(ex, files, bind_rez=True, print_msg=False):
if startup_sequence["command"] is not None:
_record_shell(executor, files=startup_sequence["files"])
shell_command = startup_sequence["command"]
elif startup_sequence["stdin"]:
_record_shell(executor,
files=startup_sequence["files"])
else:
_record_shell(executor,
files=startup_sequence["files"],
Expand All @@ -117,6 +167,17 @@ def _record_shell(ex, files, bind_rez=True, print_msg=False):

if not isinstance(cmd, (tuple, list)):
cmd = pre_command.rstrip().split()


target_file_execute_string = '. "{}"'.format(target_file)
if startup_sequence["stdin"]:
target_file_execute_string += " -in_stdin $input"
if shell_command or startup_sequence["stdin"]:
# We force powershell to return the exit code of the target file
# Without this, the return code is the one from powershell.exe
# For "stdin" if we don't force to quit, the shell will never end.
# That also means that stdin will work only once
target_file_execute_string += ";exit $LASTEXITCODE"

cmd += [
self.executable,
Expand All @@ -131,11 +192,14 @@ def _record_shell(ex, files, bind_rez=True, print_msg=False):
"-ExecutionPolicy", "Unrestricted",

# Start from this script
'. "{}"'.format(target_file)
target_file_execute_string
]

if shell_command is None:
if shell_command is None or startup_sequence["stdin"] is None:
cmd.insert(1, "-NoExit")

if startup_sequence["stdin"] and stdin and (stdin is not True):
Popen_args["stdin"] = stdin

# No environment was explicity passed
if not env and not config.inherit_parent_environment:
Expand Down