diff --git a/atest/testdata/cli/argumentfile/expandvarsinargfile.robot b/atest/testdata/cli/argumentfile/expandvarsinargfile.robot new file mode 100644 index 00000000000..5f9482a667a --- /dev/null +++ b/atest/testdata/cli/argumentfile/expandvarsinargfile.robot @@ -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 diff --git a/atest/testdata/cli/argumentfile/test_default.args b/atest/testdata/cli/argumentfile/test_default.args new file mode 100644 index 00000000000..3c1812043f5 --- /dev/null +++ b/atest/testdata/cli/argumentfile/test_default.args @@ -0,0 +1,3 @@ +--output output.xml +--log log.html +atest/testdata/cli/argumentfile/testfile.robot diff --git a/atest/testdata/cli/argumentfile/test_doubleexpandtrue.args b/atest/testdata/cli/argumentfile/test_doubleexpandtrue.args new file mode 100644 index 00000000000..07f4e90278b --- /dev/null +++ b/atest/testdata/cli/argumentfile/test_doubleexpandtrue.args @@ -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 diff --git a/atest/testdata/cli/argumentfile/test_expandfalse.args b/atest/testdata/cli/argumentfile/test_expandfalse.args new file mode 100644 index 00000000000..365ceb22c32 --- /dev/null +++ b/atest/testdata/cli/argumentfile/test_expandfalse.args @@ -0,0 +1,4 @@ +# expandvars: false +--output $TEST_DIR/output.xml +--log ${TEST_DIR}/log.html +atest/testdata/cli/argumentfile/testfile.robot diff --git a/atest/testdata/cli/argumentfile/test_expandtrue.args b/atest/testdata/cli/argumentfile/test_expandtrue.args new file mode 100644 index 00000000000..7d6a8695f93 --- /dev/null +++ b/atest/testdata/cli/argumentfile/test_expandtrue.args @@ -0,0 +1,4 @@ +# expandvars: true +--output $TEST_DIR/output.xml +--log ${TEST_DIR}/log.html +atest/testdata/cli/argumentfile/testfile.robot diff --git a/atest/testdata/cli/argumentfile/testfile.robot b/atest/testdata/cli/argumentfile/testfile.robot new file mode 100644 index 00000000000..153e0def158 --- /dev/null +++ b/atest/testdata/cli/argumentfile/testfile.robot @@ -0,0 +1,4 @@ +*** Test Cases *** +Example + Log Example test + \ No newline at end of file diff --git a/src/robot/utils/application.py b/src/robot/utils/application.py index fd66b3deeab..75b89730f51 100644 --- a/src/robot/utils/application.py +++ b/src/robot/utils/application.py @@ -147,4 +147,4 @@ def __enter__(self): pass def __exit__(self, *exc_info): - pass + pass \ No newline at end of file diff --git a/src/robot/utils/argumentparser.py b/src/robot/utils/argumentparser.py index 877f850e662..b402129af00 100644 --- a/src/robot/utils/argumentparser.py +++ b/src/robot/utils/argumentparser.py @@ -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) + + 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) 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 + 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() + + if not pragma_value: + return False + + if pragma_value in ('false', 'no', 'off'): + return False + + return True + + 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) 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) + def _get_option_separator(self, line): if " " not in line and "=" not in line: return None