Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue/3901 #1

Merged
merged 4 commits into from
Apr 14, 2020
Merged
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
77 changes: 74 additions & 3 deletions pipenv/cmdparse.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,61 @@
import itertools
import re
import shlex

import os
import six


class UnixShellEnvironmentVariable(object):
"""
This class provides an abstraction on
unix shell environment variables assignments.

It uses a set of regular expressions:

# ENV_VAR_NAME_REGEX matches the env var name, which requires:
- must not start with a number
- only letters, numbers and underscore allowed

# ENV_VAR_VALUE_REGEX matches a correct value for an env var:
- A value not enclosed in quote characters, must not start with "="
- A value enclosed in quotes, must end with the same quote character used to open.
- Carriage return and Newline are not allowed into the value.

# ENV_VAR_REGEX is a composition of the two previous regex:
- No spacing allowed before and after the equal sign.
"""

ENV_VAR_NAME_REGEX = r"([a-zA-Z_]+[a-zA-Z_0-9]*)"
ENV_VAR_VALUE_REGEX = r"((\"((?:[^\r\n\"\\]|\\.)*)\")|('((?:[^\r\n'\\]|\\.)*)')|([^=\"\'\r\n][^\"\'\r\n]*))"
ENV_VAR_REGEX = r"^{name_rgx}={value_rgx}".format(
name_rgx=ENV_VAR_NAME_REGEX,
value_rgx=ENV_VAR_VALUE_REGEX
)

def __init__(self, full_expr, name, value):
self.full_expr = full_expr
self.name = name
self.value = value

@classmethod
def parse(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))
)

def name(self):
return self.name

def value(self):
return self.value


class ScriptEmptyError(ValueError):
pass

Expand All @@ -21,18 +72,38 @@ class Script(object):
This always works in POSIX mode, even on Windows.
"""

def __init__(self, command, args=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:
os.environ.putenv(
env_var.name(),
env_var.value()
)

@classmethod
def parse(cls, value):
if isinstance(value, six.string_types):
value = shlex.split(value)
if not value:
raise ScriptEmptyError(value)
return cls(value[0], value[1:])

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:],
env_vars=env_vars,
)

def __repr__(self):
return "Script({0!r})".format(self._parts)
Expand Down