Add environment code satisfying unit test

This commit is contained in:
Joe Rickerby
2017-09-01 13:24:12 +01:00
parent fd385a9bf8
commit 5ae4da631f
4 changed files with 131 additions and 7 deletions
+39
View File
@@ -0,0 +1,39 @@
import subprocess, shlex
def evaluate_node(node, environment):
if node.kind == 'word':
return evaluate_word_node(node, environment=environment)
elif node.kind == 'commandsubstitution':
return evaluate_command_node(node.command, environment=environment)
elif node.kind == 'parameter':
return evaluate_parameter_node(node, environment=environment)
else:
raise ValueError('Unsupported bash construct: "%s"' % node.word)
def evaluate_word_node(node, environment):
letters = list(node.word)
for part in node.parts:
part_start = part.pos[0]
part_end = part.pos[1]
# Set all the characters in the part to None
for i in range(part_start, part_end):
letters[i] = None
letters[part_start] = evaluate_node(part, environment=environment)
# remove the None letters and concat
return ''.join(l for l in letters if l is not None)
def evaluate_command_node(node, environment):
words = [evaluate_node(part, environment=environment) for part in node.parts]
command = ' '.join(words)
return subprocess.check_output(shlex.split(command), env=environment)
def evaluate_parameter_node(node, environment):
return environment.get(node.value, '')
+73
View File
@@ -0,0 +1,73 @@
import bashlex
from . import bashlex_eval
class EnvironmentParseError(Exception):
pass
def parse_environment(env_string):
env_items = split_env_items(env_string)
assignments = [EnvironmentAssignment(item) for item in env_items]
return ParsedEnvironment(assignments=assignments)
def split_env_items(env_string):
'''Splits space-separated variable assignments into a list of individual assignments.
>>> split_env_items('VAR=abc')
['VAR=abc']
>>> split_env_items('VAR="a string" THING=3')
['VAR="a string"', 'THING=3']
>>> split_env_items('VAR="a string" THING=\\'single "quotes"\\'')
['VAR="a string"', 'THING=\\'single "quotes"\\'']
>>> split_env_items('VAR="dont \\\\"forget\\\\" about backslashes"')
['VAR="dont \\\\"forget\\\\" about backslashes"']
'''
return list(bashlex.split(env_string))
class EnvironmentAssignment(object):
def __init__(self, assignment):
name, equals, value = assignment.partition('=')
if not equals:
raise EnvironmentParseError(assignment)
self.name = name
self.value = value
if value:
command_node = bashlex.parsesingle(value)
if len(command_node.parts) != 1:
raise ValueError('"%s" has too many parts' % value)
self.value_word_node = command_node.parts[0]
else:
self.value_word_node = None
def evaluated_value(self, environment):
'''Returns the value of this assignment, as evaluated in the environment'''
if self.value_word_node:
return bashlex_eval.evaluate_node(self.value_word_node, environment=environment)
else:
return ''
def as_shell_assignment(self):
return 'export %s=%s' % (self.name, self.value)
class ParsedEnvironment(object):
def __init__(self, assignments):
self.assignments = assignments
def as_dictionary(self, prev_environment):
environment = prev_environment.copy()
for assignment in self.assignments:
value = assignment.evaluated_value(environment=environment)
environment[assignment.name] = value
return environment
def as_shell_commands(self):
return [a.as_shell_assignment() for a in self.assignments]