-
Notifications
You must be signed in to change notification settings - Fork 2.4k
#5186 env var expansion #5434
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
base: master
Are you sure you want to change the base?
#5186 env var expansion #5434
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
*** Settings *** | ||
Documentation Tests for environment variable expansion in argument files | ||
Library OperatingSystem | ||
Library Process | ||
|
||
*** Variables *** | ||
${ARGDIR} ${EXECDIR}${/}atest/testdata/cli/argumentfile | ||
|
||
*** Test Cases *** | ||
No Expansion By Default | ||
${result}= Run Process python -m robot --argumentfile ${ARGDIR}${/}test_default.args shell=True | ||
Log ${result.stdout} | ||
Log ${result.stderr} | ||
${combined_output}= Catenate SEPARATOR=\n ${result.stdout} ${result.stderr} | ||
Should Contain ${combined_output} Example | ||
Should Not Contain ${combined_output} $TEST_DIR/output.xml | ||
Should Not Contain ${combined_output} \${TEST_DIR}/log.html | ||
|
||
Expansion With Pragma True | ||
Set Environment Variable TEST_DIR test_output | ||
${result}= Run Process python -m robot --argumentfile ${ARGDIR}${/}test_expandtrue.args shell=True | ||
Log ${result.stdout} | ||
Log ${result.stderr} | ||
${combined_output}= Catenate SEPARATOR=\n ${result.stdout} ${result.stderr} | ||
Should Contain ${combined_output} Example | ||
Should Contain ${combined_output} test_output/output.xml | ||
Should Contain ${combined_output} test_output/log.html | ||
|
||
|
||
Double Expansion With Pragma True | ||
Set Environment Variable TEST_DIR test_output | ||
Set Environment Variable TEST_DIR2 test_output2 | ||
${result}= Run Process python -m robot --argumentfile ${ARGDIR}${/}test_doubleexpandtrue.args shell=True | ||
Log ${result.stdout} | ||
Log ${result.stderr} | ||
${combined_output}= Catenate SEPARATOR=\n ${result.stdout} ${result.stderr} | ||
Should Contain ${combined_output} Example | ||
Should Contain ${combined_output} test_output/test_output2/output.xml | ||
Should Contain ${combined_output} test_output/test_output2/log.html | ||
|
||
Expansion With Pragma False | ||
Set Environment Variable TEST_DIR test_output | ||
${result}= Run Process python -m robot --argumentfile ${ARGDIR}${/}test_expandfalse.args shell=True | ||
Log ${result.stdout} | ||
Log ${result.stderr} | ||
${combined_output}= Catenate SEPARATOR=\n ${result.stdout} ${result.stderr} | ||
Should Contain ${combined_output} Example | ||
Should Contain ${combined_output} $TEST_DIR/output.xml | ||
Should Contain ${combined_output} \${TEST_DIR}/log.html |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
--output output.xml | ||
--log log.html | ||
atest/testdata/cli/argumentfile/testfile.robot |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
# expandvars: true | ||
--output $TEST_DIR/$TEST_DIR2/output.xml | ||
--log ${TEST_DIR}/${TEST_DIR2}/log.html | ||
atest/testdata/cli/argumentfile/testfile.robot |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
# expandvars: false | ||
--output $TEST_DIR/output.xml | ||
--log ${TEST_DIR}/log.html | ||
atest/testdata/cli/argumentfile/testfile.robot |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
# expandvars: true | ||
--output $TEST_DIR/output.xml | ||
--log ${TEST_DIR}/log.html | ||
atest/testdata/cli/argumentfile/testfile.robot |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
*** Test Cases *** | ||
Example | ||
Log Example test | ||
|
||
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -22,6 +22,7 @@ | |
import sys | ||
import warnings | ||
from pathlib import Path | ||
from string import Template | ||
|
||
from robot.errors import DataError, FrameworkError, Information | ||
from robot.version import get_full_version | ||
|
@@ -361,7 +362,8 @@ def _raise_invalid_args(self, min_args, max_args, arg_count): | |
raise DataError(f"{expectation}, got {arg_count}.") | ||
|
||
|
||
class ArgFileParser: | ||
class ArgFileParser: | ||
|
||
def __init__(self, options): | ||
self._options = options | ||
|
||
|
@@ -407,23 +409,61 @@ def _read_from_stdin(self): | |
|
||
def _process_file(self, content): | ||
args = [] | ||
for line in content.splitlines(): | ||
lines = content.splitlines() | ||
|
||
# Extract pragma handling to dedicated function | ||
expand_vars = self._parse_expandvars_pragma(lines) | ||
|
||
hassineabd marked this conversation as resolved.
Show resolved
Hide resolved
|
||
for line in lines: | ||
line = line.strip() | ||
if line.startswith("-"): | ||
args.extend(self._split_option(line)) | ||
args.extend(self._split_option(line, expand_vars)) | ||
elif line and not line.startswith("#"): | ||
args.append(line) | ||
args.append(self._expand_vars(line) if expand_vars else line) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It would be simpler to expand variables from the whole file before even splitting it into lines than doing that for each line. It would make it impossible to expand variables only from some parts of the lines, but I actually don't think that's a good idea in general. I'll comment that separately later. |
||
return args | ||
|
||
def _split_option(self, line): | ||
|
||
def _parse_expandvars_pragma(self, lines): | ||
# | ||
# | ||
# design resume: | ||
# - must be on the first line | ||
# - default is off (False) | ||
# - values 'false', 'no', 'off' are considered False | ||
# - empty values are considered False | ||
# - all other values are considered True | ||
hassineabd marked this conversation as resolved.
Show resolved
Hide resolved
|
||
if not lines: | ||
return False | ||
|
||
first_line = lines[0].strip().lower() | ||
if not first_line.startswith('# expandvars:'): | ||
return False | ||
|
||
pragma_value = first_line.split(':', 1)[1].strip().lower() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we also support match = re.fullmatch('#\s*expandvars:\s*(.*?)\s*', lines[0], flags=re.IGNORECASE)
if not match:
return False
value = match.group(1).lower()
return value not in ("false", "no", "off", "") There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i think that would be : .upper() if we are goind to use FALSE_STRINGS instead of ("false", "no", "off", "") |
||
|
||
if not pragma_value: | ||
return False | ||
|
||
if pragma_value in ('false', 'no', 'off'): | ||
return False | ||
|
||
return True | ||
hassineabd marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
def _split_option(self, line, expand_vars=False): | ||
separator = self._get_option_separator(line) | ||
if not separator: | ||
return [line] | ||
option, value = line.split(separator, 1) | ||
if separator == " ": | ||
value = value.strip() | ||
if expand_vars: | ||
value = self._expand_vars(value) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This implementation expands variable only from option values, not from option names. I don't think that's a good idea for the following reasons:
|
||
return [option, value] | ||
|
||
def _expand_vars(self, value): | ||
# Handle escaping with Template.safe_substitute | ||
# (fail gracefully without raising errors for missing variable | ||
return Template(value).safe_substitute(os.environ) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. thanks for the review i see the trade-oof between using Template.safe_substitute and os.path.expandvars 1- i thought a bit about extending Template to support both ${var} and %var% formats, the solution i saw is : 2- i' am considering adding this support ( ${name=default} ) but i don't see another solution other then this :
3- intended to make a comment for design reminder |
||
|
||
def _get_option_separator(self, line): | ||
if " " not in line and "=" not in line: | ||
return None | ||
|
Uh oh!
There was an error while loading. Please reload this page.