Skip to content

Commit

Permalink
Merge pull request #8 from Hammond95/issue/3901
Browse files Browse the repository at this point in the history
Issue/3901
  • Loading branch information
Hammond95 authored May 3, 2020
2 parents 22eade3 + 85bd47b commit e1321ff
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 26 deletions.
4 changes: 2 additions & 2 deletions pipenv/cli/command.py
Original file line number Diff line number Diff line change
Expand Up @@ -397,15 +397,15 @@ def shell(
short_help="Spawns a command installed into the virtualenv.",
context_settings=subcommand_context_no_interspersion,
)
@common_options
#@common_options
@argument("command")
@argument("args", nargs=-1)
@pass_state
def run(state, command, args):
"""Spawns a command installed into the virtualenv."""
from ..core import do_run
do_run(
command=command, args=args, three=state.three, python=state.python, pypi_mirror=state.pypi_mirror
command=command, args=args, state=state,
)


Expand Down
75 changes: 55 additions & 20 deletions pipenv/cmdparse.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import shlex
import os
import six
import click
import crayons


class UnixShellEnvironmentVariable(object):
Expand Down Expand Up @@ -35,26 +37,39 @@ class UnixShellEnvironmentVariable(object):
value_rgx=ENV_VAR_VALUE_REGEX
)

def __init__(self, full_expr, name, value):
self.full_expr = full_expr
def __init__(self, name, value, full_expr=None):
m = re.match(self.ENV_VAR_NAME_REGEX, name)
if not m:
raise ValueError("The value '{}' didn't match the ENV_VAR_NAME_REGEX!".format(name))

m = re.match(self.ENV_VAR_NAME_REGEX, value)
if not m:
raise ValueError("The value '{}' didn't match the ENV_VAR_VALUE_REGEX!".format(value))

self._name = name
self._value = value
if full_expr:
self.full_expr = full_expr
else:
self.full_expr = '{}=\'{}\''.format(name, value)

@classmethod
def parse(cls, env_var_assignment):
def parse_inline(cls, env_var_assignment):
m = re.match(cls.ENV_VAR_REGEX, env_var_assignment)
if not m:
raise ValueError("The value '{}' didn't match the ENV_VAR_REGEX!".format(env_var_assignment))

return cls(
m.group(0),
m.group(1),
(m.group(4) or m.group(6) or m.group(7))
(m.group(4) or m.group(6) or m.group(7)),
full_expr=m.group(0),
)

@property
def name(self):
return self._name

@property
def value(self):
return self._value

Expand All @@ -75,36 +90,56 @@ class Script(object):
This always works in POSIX mode, even on Windows.
"""

def __init__(self, command, args=None, env_vars=None):
def __init__(
self,
command,
args=None,
env_vars=None
):
self._parts = [command]
if args:
self._parts.extend(args)

for env_var in (env_vars or []):
os.environ.putenv(
env_var.name(),
env_var.value()
env_var.name,
env_var.value
)

@classmethod
def parse(cls, value):
env_vars = []
if isinstance(value, six.string_types):
value = shlex.split(value)
command = shlex.split(value)

for el in command:
try:
env_var = UnixShellEnvironmentVariable.parse_inline(el)
env_vars.append(env_var)
command.remove(el)
click.echo(
crayons.yellow(
"WARNING: Found environment variable '{}' in command. ".format(env_var.full_expr) +
"Use env property in Pipfile instead!"
)
)
except ValueError:
pass

if isinstance(value, dict):
command = shlex.split(value['cmd'])

for k, v in (value.get('env') or {}).items():
env_vars.append(
UnixShellEnvironmentVariable(k, v)
)

if not value:
raise ScriptEmptyError(value)

env_vars = []
for el in value:
try:
env_var = UnixShellEnvironmentVariable.parse(el)
env_vars.append(env_var)
value.remove(el)
except ValueError:
pass

return cls(
value[0],
args=value[1:],
command[0],
args=command[1:],
env_vars=env_vars,
)

Expand Down
9 changes: 6 additions & 3 deletions pipenv/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -2499,7 +2499,7 @@ def do_run_posix(script, command):
)


def do_run(command, args, three=None, python=False, pypi_mirror=None):
def do_run(command, args, state):
"""Attempt to run command either pulling from project or interpreting as executable.
Args are appended to the command in [scripts] section of project if found.
Expand All @@ -2508,7 +2508,10 @@ def do_run(command, args, three=None, python=False, pypi_mirror=None):

# Ensure that virtualenv is available.
ensure_project(
three=three, python=python, validate=False, pypi_mirror=pypi_mirror,
three=state.three,
python=state.python,
validate=False,
pypi_mirror=state.pypi_mirror,
)

load_dot_env()
Expand All @@ -2528,7 +2531,7 @@ def do_run(command, args, three=None, python=False, pypi_mirror=None):
os.environ.pop("PIP_SHIMS_BASE_MODULE", None)

try:
script = project.build_script(command, args)
script = project.build_script(command, extra_args=args)
cmd_string = ' '.join([script.command] + script.args)
if environments.is_verbose():
click.echo(crayons.normal("$ {0}".format(cmd_string)), err=True)
Expand Down
4 changes: 3 additions & 1 deletion pipenv/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -557,9 +557,11 @@ def has_script(self, name):

def build_script(self, name, extra_args=None):
try:
# Case 1: Named execution with an alias.
script = Script.parse(self.parsed_pipfile["scripts"][name])
except KeyError:
script = Script(name)
# Case 2: A command directly provided to pipenv run.
script = Script.parse(name)
if extra_args:
script.extend(extra_args)
return script
Expand Down

0 comments on commit e1321ff

Please sign in to comment.