def test_case_insensitive_windows_style(self): parser = ArgumentParserEx(prefix_chars="/") parser.add_argument("/nologo", action="store_true", ignore_case=True) ns = parser.parse_args(["/NOLOGO"]) self.assertTrue(ns.nologo) ns = parser.parse_args(["/nologo"]) self.assertTrue(ns.nologo)
def test_msvc_flag_with_value(self): parser = ArgumentParserEx(prefix_chars="/-") parser.set(ignore_case=True) parser.add_argument("/flag", action="msvc_flag_with_value") parser.add_argument("/ENABLE", action="msvc_flag_with_value", append=True, dest="list") ns, remaining = parser.parse_known_args(["/FLAG"]) self.assertListEqual(["/FLAG"], remaining) self.assertIsNone(vars(ns).get("flag")) ns, remaining = parser.parse_known_args(["/flag"]) self.assertListEqual(["/flag"], remaining) self.assertIsNone(vars(ns).get("flag")) ns, remaining = parser.parse_known_args(["/flag:"]) self.assertListEqual(["/flag:"], remaining) self.assertIsNone(vars(ns).get("flag")) ns = parser.parse_args(["/flag:value"]) self.assertEqual("value", ns.flag) ns = parser.parse_args(["-FLAG:1,2,3"]) self.assertEqual("1,2,3", ns.flag) ns = parser.parse_args(["/ENABLE:1", "-FlAg:2", "-enable:3"]) self.assertEqual("2", ns.flag) self.assertEqual(["1", "3"], ns.list)
def test_raw_dest(self): parser = ArgumentParserEx() parser.add_argument("-arg1", action="store_true", raw_dest="args") parser.add_argument("--arg2", "-f", dest=None, raw_dest="args") parser.add_argument("file", raw_dest="args") parser.add_argument("files", nargs="*", dest=None, raw_dest="args") parser.add_argument("-D", dest=None, raw_dest="args", raw_format="".join) ns = parser.parse_args(["--arg2", "1", "2"]) self.assertListEqual([["--arg2", "1"], "2"], ns.args) ns = parser.parse_args(["--arg2=1", "1", "-arg1", "2", "3"]) self.assertListEqual(["--arg2=1", "1", "-arg1", "2", "3"], ns.args) ns, remaining = parser.parse_known_args( ["1", "-fvalue", "2", "-unknown"]) self.assertListEqual(["-unknown"], remaining) self.assertListEqual(["1", "-fvalue", "2"], ns.args) ns, remaining = parser.parse_known_args( ["1", "-unknown", "-fvalue", "2"]) self.assertListEqual(["-unknown"], remaining) self.assertListEqual(["1", "-fvalue", "2"], ns.args) ns = parser.parse_args(["1", "-D", "2", "3", "-D4"]) self.assertListEqual(["1", "-D2", "3", "-D4"], ns.args)
def test_values_starting_with_prefix(self): # standard ArgumentParser does not accept values starting with prefix_chars parser = ArgumentParserEx() parser.add_argument("-Xclang") ns = parser.parse_args(["-Xclang", "-no-color-output"]) self.assertEqual("-no-color-output", ns.Xclang) parser = ArgumentParserEx() parser.add_argument("-f", nargs="2") ns = parser.parse_args(["-f", "-1", "-2"]) self.assertListEqual(["-1", "-2"], ns.f) parser = ArgumentParserEx() parser.add_argument("-f", nargs="2", action="append") parser.add_argument("--enable", action="store_true") ns = parser.parse_args(["-f", "-1", "-2"]) self.assertListEqual([["-1", "-2"]], ns.f) parser.add_argument("-f", nargs="2", action="append") ns = parser.parse_args(["-f", "-1", "-2", "-f", "-3", "-4"]) self.assertListEqual([["-1", "-2"], ["-3", "-4"]], ns.f) ns, remaining = parser.parse_known_args(["-f", "-1", "-2", "-f", "-3"]) self.assertListEqual(["-f", "-3"], remaining) self.assertListEqual([["-1", "-2"]], ns.f) ns, remaining = parser.parse_known_args( ["-f", "-1", "-2", "-f", "-3", "--enable", "-4"]) self.assertListEqual(["-4"], remaining) self.assertListEqual([["-1", "-2"], ["-3", "--enable"]], ns.f) self.assertFalse(ns.enable) self.assertRaisesRegexp( ValueError, "Unparsed tokens", parser.parse_args, ["-f", "-1", "-2", "-f", "-3"], ) parser = ArgumentParserEx() parser.add_argument("f", nargs="*") ns, remaining = parser.parse_known_args(["-1"]) self.assertListEqual(["-1"], remaining) ns, remaining = parser.parse_known_args(["1", "2", "-3"]) self.assertListEqual(["-3"], remaining) self.assertListEqual(["1", "2"], ns.f) ns, remaining = parser.parse_known_args(["1", "-2", "3"]) self.assertListEqual(["-2"], remaining) self.assertListEqual(["1", "3"], ns.f) parser = ArgumentParserEx() parser.add_argument("f", nargs="+") ns, remaining = parser.parse_known_args(["-1", "-2"]) self.assertListEqual(["-1", "-2"], remaining) parser = ArgumentParserEx() parser.add_argument("-f", nargs="+") ns, remaining = parser.parse_known_args(["-f", "-1", "-2"]) self.assertListEqual(["-2"], remaining) self.assertListEqual(["-1"], ns.f)
def test_single_hyphen_multichar_flag(self): parser = ArgumentParserEx() parser.add_argument("-flag") ns = parser.parse_args(["-flag", "value"]) self.assertEqual("value", ns.flag) ns = parser.parse_args(["-flag=value"]) self.assertEqual("value", ns.flag)
def test_force_suffix_value(self): parser = ArgumentParserEx() parser.add_argument(prefixes=["-Xclang"]) ns = parser.parse_args(["-Xclangvalue"]) self.assertEqual("value", ns.Xclang) parser = ArgumentParserEx() parser.add_argument("-Xclang", prefix=True) ns = parser.parse_args(["-Xclangvalue"]) self.assertEqual("value", ns.Xclang)
def test_optional_positional_argument(self): parser = ArgumentParserEx() parser.add_argument("infile") parser.add_argument("outfile", nargs="?") ns = parser.parse_args(["inout.txt"]) self.assertEqual("inout.txt", ns.infile) ns = parser.parse_args(["in.txt", "out.txt"]) self.assertEqual("in.txt", ns.infile) self.assertEqual(["out.txt"], ns.outfile)
def test_conditional_arguments(self): self.skipTest("not implemented yet") parser = ArgumentParserEx() arg = parser.add_argument("-a") parser.add_argument("-b", after=[arg]) ns = parser.parse_args(["-a", "1", "-b", "2"]) self.assertEqual("1", ns.a) self.assertEqual("2", ns.b) ns = parser.parse_args(["-a", "1"]) self.assertEqual("1", ns.a) ns, remaining = parser.parse_known_args(["-b", "1"]) self.assertListEqual(["-b", "1"], remaining) self.assertIsNone(vars(ns).get("b"))
def test_strict_parsing(self): parser = ArgumentParserEx() parser.add_argument("arg1") self.assertRaisesRegexp(ValueError, "Required attribute not found", parser.parse_args, []) self.assertRaisesRegexp(ValueError, "Unparsed tokens", parser.parse_args, ["--option"]) ns = parser.parse_args(["val"]) self.assertEqual("val", ns.arg1) parser = ArgumentParserEx() parser.add_argument("--arg1", "-a", required=True) self.assertRaisesRegexp(ValueError, "Required attribute not found", parser.parse_args, []) self.assertRaisesRegexp(ValueError, "Unparsed tokens", parser.parse_args, ["--arg1="]) self.assertRaisesRegexp(ValueError, "Unparsed tokens", parser.parse_args, ["-a"]) ns = parser.parse_args(["-aval"]) self.assertEqual("val", ns.arg1) parser = ArgumentParserEx() parser.add_argument("arg1", nargs=2) self.assertRaisesRegexp(ValueError, "Required attribute not found", parser.parse_args, []) self.assertRaisesRegexp(ValueError, "Not enough values", parser.parse_args, ["a"]) self.assertRaisesRegexp(ValueError, "Unparsed tokens", parser.parse_args, ["a", "b", "c"]) ns = parser.parse_args(["a", "b"]) self.assertEqual(["a", "b"], ns.arg1) parser = ArgumentParserEx() parser.add_argument("--arg1", "-a", required=True, nargs=2) self.assertRaisesRegexp(ValueError, "Required attribute not found", parser.parse_args, []) self.assertRaisesRegexp(ValueError, "Unparsed tokens", parser.parse_args, ["--arg1", "val"]) self.assertRaisesRegexp(ValueError, "Unparsed tokens", parser.parse_args, ["-a", "val"]) ns = parser.parse_args(["--arg1", "a", "b"]) self.assertEqual(["a", "b"], ns.arg1)
def test_intermixed_args(self): parser = ArgumentParserEx() parser.add_argument("files", action="append") parser.add_argument("-D", action="append", dest="definitions") ns = parser.parse_args(["-DA=1", "a.cpp", "-DB=2", "b.cpp"]) # standard ArgumentParser won't append 'b.cpp' here self.assertListEqual(["a.cpp", "b.cpp"], ns.files) self.assertListEqual(["A=1", "B=2"], ns.definitions)
def test_concatenate_flags(self): self.skipTest("not implemented yet") parser = ArgumentParserEx() parser.add_argument("-a", action="store_true") parser.add_argument("-b", action="store_true") ns = parser.parse_args(["-ab"]) self.assertTrue(ns.a) self.assertTrue(ns.b)
def test_disable_concatenation(self): self.skipTest("not implemented yet") parser = ArgumentParserEx() parser.enable_flag_concatenation(False) parser.add_argument("-a", action="store_true") parser.add_argument("-b", action="store_true") ns, remaining = parser.parse_args(["-ab"]) self.assertListEqual(["-ab"], remaining)
def test_deepcopy_1(self): parser = ArgumentParserEx() parser.add_argument("-a") parser = deepcopy(parser) ns = parser.parse_args(["-a", "1"]) self.assertEqual("1", ns.a)
class MsvcMc(ParserBase): priority = 7 @staticmethod def add_arguments(arg_parser): pass def __init__(self, context, platform=None): ParserBase.__init__(self, context) self.platform = get_platform(platform) self.program_re = self.platform.get_program_path_re("mc") # https://docs.microsoft.com/en-us/windows/windows/wes/message-compiler--mc-exe- # Currently, only small subset of flags is supported self.parser = ArgumentParserEx() self.parser.set(raw_dest="args") self.parser.add_argument("-h", raw_handler=self.input_dir, dest="header_dir") self.parser.add_argument("-r", raw_handler=self.input_dir, dest="resource_dir") self.parser.add_argument("manifest_file", raw_handler=self.input_file, dest="manifest_file") def parse(self, target): tokens = target.get("tokens") or [] if not tokens: return target if not self.program_re.match(tokens[0]): return target tokens.pop(0) namespace = self.parser.parse_args(tokens) if namespace.header_dir is None: namespace.header_dir = target["working_dir"] header_dir = self.context.get_dir_arg( self.context.normalize_path(namespace.header_dir)) if namespace.resource_dir is None: namespace.resource_dir = target["working_dir"] resource_dir = self.context.get_dir_arg( self.context.normalize_path(namespace.resource_dir)) filename_no_ext = os.path.basename(namespace.manifest_file) filename_no_ext = os.path.splitext(filename_no_ext)[0] output = [ header_dir + "/" + filename_no_ext + ".h", resource_dir + "/" + filename_no_ext + ".rc", ] return get_command_target(None, "mc", namespace.args, output, namespace.dependencies)
def test_msvc_flag_with_value_with_append(self): parser = ArgumentParserEx(prefix_chars="/-") parser.set(ignore_case=True) parser.add_argument("/flag", action="msvc_flag_with_value", dest="flags", append=True) ns = parser.parse_args(["/flag:a", "/flag:b"]) self.assertListEqual(["a", "b"], ns.flags)
def test_correct_list_order(self): parser = ArgumentParserEx(prefix_chars="-/") parser.set_defaults(definitions=[]) parser.add_argument("/c", action="store_true", dest="compile_only") parser.add_argument("-D", action="append", dest="definitions") parser.add_argument("-I", action="append", dest="include_dirs") parser.add_argument("-U", action="append", dest="definitions") parser.add_argument("files", nargs="*") ns = parser.parse_args( ["/c", "-D1", "/U", "2", "/D3", "-I.", "-U4", "a.cpp"]) self.assertListEqual(["1", "2", "3", "4"], ns.definitions)
class CMake(Parser): priority = 7 @staticmethod def add_arguments(arg_parser): pass @staticmethod def is_applicable(project=None, log_type=None): return True def __init__(self, context, platform=None): self.context = context self.platform = get_platform(platform) self.program_re = self.platform.get_program_path_re("cmake") self.parser = ArgumentParserEx(prog="cmake") self.parser.add_argument("-E", dest="command", nargs="+") def parse(self, target): tokens = target.get("tokens") if not tokens: return target if not self.program_re.match(tokens[0]): return target namespace = self.parser.parse_args(tokens[1:]) if not namespace.command: return target command = namespace.command[0] args = namespace.command[1:] dependencies = [] targets = [] if command == "cmake_symlink_library": # on Mac source = self.context.get_file_arg( self.context.platform.normalize_path(args[0]), dependencies) destinations = args[1:] for dest in destinations: target_dependencies = copy(dependencies) output = self.context.get_output(dest, target_dependencies) targets.append( get_copy_target(None, source, output, target_dependencies)) else: logger.warning("Unsupported CMake command: {}".format(command)) return targets
def test_default_values(self): parser = ArgumentParserEx() parser.add_argument("arg1", default="default") ns = parser.parse_args([]) self.assertEqual("default", ns.arg1) ns = parser.parse_args(["value"]) self.assertEqual("value", ns.arg1) parser = ArgumentParserEx() parser.add_argument("-a", default=[], action="append") ns = parser.parse_args([]) self.assertEqual([], ns.a) ns.a.append("value") ns = parser.parse_args([]) self.assertEqual([], ns.a) ns = parser.parse_args(["-aval"]) self.assertEqual(["val"], ns.a)
def test_no_prefix_chars(self): parser = ArgumentParserEx() parser.add_argument("-D", action="append", dest="definitions") parser.add_argument( flags=["cmd"], action="append", nargs="+", dest="commands", args_regexp=re.compile(r"^(?!cmd)"), ) ns = parser.parse_args( ["-DA=1", "cmd", "cl.exe", "cmd", "gcc", "/c", "a.cpp"]) self.assertListEqual(["A=1"], ns.definitions) self.assertListEqual([["cl.exe"], ["gcc", "/c", "a.cpp"]], ns.commands)
class Icupkg(ParserBase): priority = 7 def __init__(self, context, platform=platform.system().lower()): ParserBase.__init__(self, context) self.platform = get_platform(platform) self.program_re = self.platform.get_program_path_re("icupkg") # https://helpmanual.io/help/icupkg/ self.parser = ArgumentParserEx() self.parser.set(dest=None, raw_dest="args") self.parser.add_argument("--type", "-t", choices=["l", "b", "e"]) self.parser.add_argument("--copyright", "-c") self.parser.add_argument("--comment", "-C") self.parser.add_argument("--add", "-a") self.parser.add_argument("--remove", "-r") self.parser.add_argument("--extract", "-x") self.parser.add_argument("--writepkg", "-w", action="store_true") self.parser.add_argument("--matchmode", "-m") self.parser.add_argument("--auto_toc_prefix", action="store_true") self.parser.add_argument("--auto_toc_prefix_with_type", action="store_true") self.parser.add_argument("--sourcedir", "-s", raw_handler=self.input_dir) self.parser.add_argument("--destdir", "-d", raw_handler=self.input_dir) self.parser.add_argument("--list", "-l", action="store_true") self.parser.add_argument("--outlist", "-o", raw_handler=self.output_file) self.parser.add_argument("infilename", raw_handler=self.input_file) self.parser.add_argument("outfilename", nargs="?", raw_handler=self.output_file) def parse(self, target): tokens = target.get("tokens") or [] if not tokens: return target if not self.program_re.match(tokens[0]): return target tokens.pop(0) namespace = self.parser.parse_args(tokens) return get_command_target( None, program="icupkg", args=namespace.args, output=namespace.output, dependencies=namespace.dependencies, )
def test_mutually_exclusive_group(self): self.skipTest("not implemented yet") parser = ArgumentParserEx() group = parser.add_mutually_exclusive_group() group.add_argument("-a", action="store_const", const="a", dest="mode") group.add_argument("-b", action="store_const", const="b", dest="mode") ns, remaining = parser.parse_known_args(["-ab"]) self.assertListEqual(["-ab"], remaining) self.assertIsNone(vars(ns).get("mode")) ns, remaining = parser.parse_known_args(["-a", "-b"]) self.assertListEqual(["-b"], remaining) self.assertEqual("a", ns.mode) ns = parser.parse_args(["-b"]) self.assertEqual("b", ns.mode)
def test_compatiblity_arguments(self): # test ArgumentParser interface compatibility # these arguments are simply ignored parser = ArgumentParserEx( prog="test", usage="usage", description="description", epilog="epilog", parents=[], formatter_class=object, fromfile_prefix_chars="fromfile_prefix_chars", argument_default=None, conflict_handler="error", add_help=True, ) parser.add_argument("-a", help="help", metavar="metavar") ns = parser.parse_args(["-a1"]) self.assertEqual("1", ns.a)
def test_msvc_flag(self): parser = ArgumentParserEx(prefix_chars="/") parser.add_argument("/GR", action="msvc_flag", dest="rtti") parser.add_argument( "/INCREMENTAL", action="msvc_flag", msvc_false_suffix=":NO", dest="incremental", ) parser.add_argument( "/flag", action="msvc_flag", msvc_true_suffix=":on", msvc_false_suffix=":off", ignore_case=True, ) ns = parser.parse_args(["/GR-"]) self.assertFalse(ns.rtti) ns = parser.parse_args(["/GR"]) self.assertTrue(ns.rtti) ns = parser.parse_args(["/INCREMENTAL"]) self.assertTrue(ns.incremental) ns = parser.parse_args(["/INCREMENTAL:NO"]) self.assertFalse(ns.incremental) ns = parser.parse_args(["/FLAG:ON"]) self.assertTrue(ns.flag) ns = parser.parse_args(["/flag:off"]) self.assertFalse(ns.flag) ns = parser.parse_args([]) self.assertIsNone(vars(ns).get("flag")) self.assertIsNone(vars(ns).get("rtti")) self.assertIsNone(vars(ns).get("incremental")) ns, remaining = parser.parse_known_args(["/flag:unknown"]) self.assertListEqual(["/flag:unknown"], remaining) self.assertIsNone(vars(ns).get("flag")) parser.set_defaults(flag=False) ns = parser.parse_args([]) self.assertFalse(ns.flag)
def test_dest_is_none(self): parser = ArgumentParserEx() parser.add_argument("-opt", dest=None, required=True) parser.add_argument("pos", dest=None) ns = parser.parse_args(["-opt", "1", "2"]) self.assertIsNone(vars(ns).get("opt")) self.assertIsNone(vars(ns).get("pos")) ns, remaining = parser.parse_known_args(["-opt"]) self.assertListEqual(["-opt"], remaining) ns, remaining = parser.parse_known_args(["1"]) self.assertListEqual([], remaining) self.assertIsNone(vars(ns).get("opt")) self.assertIsNone(vars(ns).get("pos")) self.assertRaisesRegexp(ValueError, "Required attribute not found", parser.parse_args, ["1"])
def test_dest_naming(self): parser = ArgumentParserEx(prefix_chars="/-") parser.add_argument("-a-b", action="store_true") parser.add_argument("-++", action="store_true") parser.add_argument("/b:c", dest="_f", action="store_true") parser.add_argument("--c~d", action="store_true") parser.add_argument("-UPPER", action="store_true") self.assertRaisesRegexp( ValueError, "Invalid dest: '@flag'", parser.add_argument, "-flag", dest="@flag", action="store_true", ) ns = parser.parse_args(["-a-b", "-++", "/b:c", "--c~d", "-UPPER"]) self.assertTrue(ns.a_b) self.assertTrue(ns.__) self.assertTrue(ns._f) self.assertTrue(ns.c_d) self.assertTrue(ns.UPPER)
def test_gnu_ar_parser(self): self.skipTest("not implemented yet") # GNU ar has a surprisingly complex syntax, # it's a good test-case for ArgumentParserEx parser = ArgumentParserEx() operation = parser.add_mutually_exclusive_group() arg_r = operation.add_argument(flags=["-r", "r"], action="store_true") arg_q = operation.add_argument(flags=["-q", "q"], action="store_true") arg_a = parser.add_argument("-a", after=[arg_r, arg_q], action="store_true") arg_b = parser.add_argument("-b", after=[arg_r, arg_q], action="store_true") arg_N = parser.add_argument("-N", after=[arg_r, arg_q], action="store_true") parser.add_argument("relpos", after=[arg_a, arg_b]) parser.add_argument("count", after=[arg_N], type=int) parser.add_argument("archive") parser.add_argument("member", nargs="*", dest="members") ns = parser.parse_args(["-q", "lib.a", "a.o", "b.o"]) self.assertTrue(ns.q) self.assertEqual("lib.a", ns.archive) self.assertListEqual(["a.o", "b.o"], ns.members) ns = parser.parse_args(["-qa", "a.o", "lib.a", "b.o", "c.o"]) self.assertTrue(ns.q) self.assertTrue(ns.a) self.assertEqual("a.o", ns.relpos) self.assertEqual("lib.a", ns.archive) self.assertListEqual(["a.o", "b.o"], ns.members) ns = parser.parse_args(["-qN", "1", "lib.a", "a.o", "b.o"]) self.assertTrue(ns.q) self.assertTrue(ns.N) self.assertEqual(1, ns.count) self.assertEqual("lib.a", ns.archive) self.assertListEqual(["a.o", "b.o"], ns.members) ns = parser.parse_args(["-raN", "a.o", "1", "lib.a", "b.o", "c.o"]) self.assertTrue(ns.r) self.assertTrue(ns.a) self.assertTrue(ns.N) self.assertEqual("a.o", ns.relpos) self.assertEqual(1, ns.count) self.assertEqual("lib.a", ns.archive) self.assertListEqual(["b.o", "c.o"], ns.members) ns = parser.parse_args(["raN", "a.o", "1", "lib.a", "b.o", "c.o"]) self.assertTrue(ns.r) self.assertTrue(ns.a) self.assertTrue(ns.N) self.assertEqual("a.o", ns.relpos) self.assertEqual(1, ns.count) self.assertEqual("lib.a", ns.archive) self.assertListEqual(["b.o", "c.o"], ns.members) self.assertRaisesRegexp(ValueError, "doot", parser.parse_args, ["rq", "lib.a", "a.o"]) self.assertRaisesRegexp(ValueError, "doot", parser.parse_args, ["-ar", "lib.a", "a.o"])
class MsvcMl(CompilerParser): filename_re = os_ext.Windows.get_program_path_re("ml", "ml64") priority = 7 def __init__(self, context, ignore_compile_flags=None): CompilerParser.__init__(self, context, ignore_compile_flags=ignore_compile_flags) # Visual Studio ml.exe arguments # https://docs.microsoft.com/en-us/cpp/assembler/masm/ml-and-ml64-command-line-reference?view=vs-2017 self.parser = ArgumentParserEx(prefix_chars="-/") self.parser.set_defaults(compile_flags=[], link_flags=[], include_dirs=[], infiles=[]) # TODO: publish all meaningful flags self.parser.set(dest=None, raw_dest="compile_flags") self.parser.add_argument("/c", action="store_true", raw_dest=None, dest="compile_only") # Generates common object file format (COFF) type of object module self.parser.add_argument("/coff", action="store_true") # Preserves case of all user identifiers self.parser.add_argument("/Cp", action="store_true") # Maps all identifiers to upper case self.parser.add_argument("/Cu", action="store_true") # Preserves case in public and extern symbols self.parser.add_argument("/Cx", action="store_true") self.parser.add_argument("/D", raw_format=format_flag_gnu) self.parser.add_argument("/errorreport", prefix=True, nargs="?", ignore_case=True) self.parser.add_argument("/Fo", prefix=True, raw_dest=None, dest="output") # stack size self.parser.add_argument("/F", prefix=True) # Generates emulator fix-ups for floating-point arithmetic self.parser.add_argument("/FPi", action="store_true") # Specifies use of C-style function calling and naming conventions self.parser.add_argument("/Gd", action="store_true") # Specifies use of __stdcall function calling and naming conventions self.parser.add_argument("/GZ", action="store_true") self.parser.add_argument("/I", action="append", raw_dest=None, dest="include_dirs") self.parser.add_argument("/nologo", action="store_true", ignore_case=True) # Generates object module file format (OMF) type of object module self.parser.add_argument("/omf", action="store_true") self.parser.add_argument("/Ta", prefix=True, action="append", raw_dest=None, dest="infiles") self.parser.add_argument("/safeseh", action="store_true", ignore_case=True) # Warning flags self.parser.add_argument(flags=["/W", "/WX"], action="store_true") self.parser.add_argument("/W", choices="0123") # line-number information in object file self.parser.add_argument("/Zd", action="store_true") # Generate CodeView information in object file self.parser.add_argument("/Zi", action="store_true") # Makes all symbols public self.parser.add_argument("/Zf", action="store_true") # Packs structures on the specified byte boundary self.parser.add_argument("/Zp", prefix=True, type=int) self.parser.add_argument("infiles", nargs="*", dest="infiles", raw_dest=None) include_re = re.compile(r"(?:\b|%)include\s+(?P<path>[^\s\n][^\n]*)", re.IGNORECASE) def parse(self, target): tokens = target.get("tokens") or [] if not tokens: return target if not self.filename_re.match(tokens[0]): return target if len(tokens) < 2 or tokens[1] == ":": # skip warning message return target tokens.pop(0) namespace = self.parser.parse_args(tokens) assert namespace.compile_only dependencies = [] self.process_namespace(namespace) # ml.exe doesn't support /showIncludes or anything similar add_included_dependencies( self.context, self.include_re, dependencies, namespace.include_dirs, namespace.infiles, self.context.working_dir, ) include_dirs = [] for dir in namespace.include_dirs: dir = self.context.normalize_path(dir) arg = self.context.get_dir_arg(dir, dependencies) if arg: include_dirs.append(arg) sources = [] for infile in namespace.infiles: sources.append( get_source_file_reference( self.context.get_file_arg( self.context.normalize_path(infile), dependencies), "MASM", )) output = self.context.get_output( self.context.normalize_path(namespace.output)) return get_module_target( ModuleTypes.object_lib, None, output, compile_flags=namespace.compile_flags, include_dirs=include_dirs, dependencies=dependencies, sources=sources, )
class MsvcLib(Parser): filename_re = os_ext.Windows.get_program_path_re("lib") link_re = os_ext.Windows.get_program_path_re("link") lld_link_re = os_ext.Windows.get_program_path_re("lld-link") priority = 7 @staticmethod def add_arguments(arg_parser): pass @staticmethod def is_applicable(project=None, log_type=None): return True def __init__(self, context, project_version=None): self.context = context self.project_version = project_version # Visual Studio lib.exe arguments # https://docs.microsoft.com/en-us/cpp/build/reference/running-lib?view=vs-2019 self.parser = ArgumentParserEx(prefix_chars="-/") self.parser.set_defaults(compile_flags=[], link_flags=[], include_dirs=[], infiles=[]) # TODO: publish all meaningful flags self.parser.set(ignore_case=True, dest=None, raw_dest="link_flags") self.parser.add_argument("/ignore", action="msvc_flag_with_value") self.parser.add_argument("/libpath", action="msvc_flag_with_value", append=True, raw_dest=None) self.parser.add_argument("/ltcg", action="store_true") self.parser.add_argument("/machine", action="msvc_flag_with_value") self.parser.add_argument("/out", action="msvc_flag_with_value", dest="output", raw_dest=None) self.parser.add_argument("/nologo", action="store_true") self.parser.add_argument("/wx", action="msvc_flag", msvc_false_suffix=":no") self.parser.add_argument("infiles", dest="infiles", nargs="*", raw_dest=None) # lld-link.exe arguments (/lib mode) # Cannot find documentation online self.lld_link_parser = deepcopy(self.parser) self.lld_link_parser.add_argument("/llvmlibthin", action="store_true") self.lld_link_parser.set(prefix_chars="-") self.lld_link_parser.add_argument("--color-diagnostics", action="store_true") def parse(self, target): tokens = target.get("tokens") or [] if not tokens: return target is_lld_link = False if self.link_re.match(tokens[0]) and is_lib_shim(tokens): is_lld_link = bool(self.lld_link_re.match(tokens[0])) tokens = tokens[2:] elif not self.filename_re.match(tokens[0]): return target else: tokens.pop(0) if len(tokens) > 0: if tokens[0] == ":": # skipping parsing output of utilities, like: `lib : warning ...` return target if is_lld_link: namespace = self.lld_link_parser.parse_args(tokens) else: namespace = self.parser.parse_args(tokens) dependencies = [] libs = [] objects = [] for infile in namespace.infiles: if os_ext.is_static_lib(infile): libs.append(self.context.get_lib_arg(infile, dependencies, [])) else: path = next( os_ext.Windows.get_obj_file_locations( infile, [], self.context.working_dir)) if self.context.find_target(self.context.get_file_arg( path)) or os.path.exists(path): objects.append( self.context.get_file_arg(path, dependencies)) else: # System object file, treat it as a linker flag # https://docs.microsoft.com/en-us/cpp/c-runtime-library/link-options objects.append(infile) output = self.context.normalize_path(namespace.output) descr = os_ext.parse_static_lib(output) module_name = descr["module_name"] name = descr["target_name"] version = descr["version"] or self.project_version output = self.context.get_output(output, dependencies) return get_module_target( ModuleTypes.static_lib, name, output, dependencies=dependencies, module_name=module_name, libs=libs, objects=objects, version=version, link_flags=namespace.link_flags, )
def test_nargs(self): parser = ArgumentParserEx() parser.add_argument("--attr2", action="store", nargs="1") parser.add_argument("attr1", action="store", nargs="1") ns, remaining = parser.parse_known_args( ["--attr2", "val1", "val2", "--attr2", "val3"]) self.assertListEqual([], remaining) self.assertEqual(["val2"], ns.attr1) self.assertEqual(["val3"], ns.attr2) parser = ArgumentParserEx() parser.add_argument("--attr2", action="store", nargs="2") parser.add_argument("attr1", action="store", nargs="2") ns, remaining = parser.parse_known_args( ["--attr2", "val1", "val2", "val3", "val4"]) self.assertListEqual([], remaining) self.assertEqual(["val3", "val4"], ns.attr1) self.assertEqual(["val1", "val2"], ns.attr2) ns, remaining = parser.parse_known_args( ["val1", "val2", "--attr2", "val3", "val4", "val5"]) self.assertListEqual(["val5"], remaining) self.assertEqual(["val1", "val2"], ns.attr1) self.assertEqual(["val3", "val4"], ns.attr2) ns, remaining = parser.parse_known_args(["val1", "--attr2", "val2"]) self.assertListEqual(["--attr2"], remaining) self.assertEqual(["val1", "val2"], ns.attr1) self.assertIsNone(vars(ns).get("attr2")) ns, remaining = parser.parse_known_args( ["val1", "--attr2", "val2", "val3", "val4"]) self.assertListEqual([], remaining) self.assertEqual(["val1", "val4"], ns.attr1) self.assertEqual(["val2", "val3"], ns.attr2) ns, remaining = parser.parse_known_args( ["val1", "--attr2", "val2", "val3"]) self.assertListEqual([], remaining) self.assertEqual(["val1"], ns.attr1) self.assertEqual(["val2", "val3"], ns.attr2) parser = ArgumentParserEx() parser.add_argument("attr1", action="store", nargs="?") parser.add_argument("--attr2", action="store", nargs="?") ns, remaining = parser.parse_known_args(["val1", "--attr2"]) self.assertListEqual([], remaining) self.assertEqual(["val1"], ns.attr1) self.assertEqual([], ns.attr2) ns, remaining = parser.parse_known_args(["--attr2", "val1"]) self.assertListEqual([], remaining) self.assertEqual(None, ns.attr1) self.assertEqual(["val1"], ns.attr2) parser = ArgumentParserEx() parser.add_argument("--attr2", action="store", nargs="+") parser.add_argument("attr1", action="store", nargs="+") ns, remaining = parser.parse_known_args(["val1", "val2", "--attr2"]) self.assertListEqual(["--attr2"], remaining) self.assertEqual(["val1", "val2"], ns.attr1) self.assertIsNone(vars(ns).get("attr2")) ns, remaining = parser.parse_known_args(["--attr2", "val1", "val2"]) self.assertListEqual([], remaining) self.assertIsNone(vars(ns).get("attr1")) self.assertEqual(["val1", "val2"], ns.attr2) ns, remaining = parser.parse_known_args( ["val1", "val2", "--attr2", "val3"]) self.assertListEqual([], remaining) self.assertEqual(["val1", "val2"], ns.attr1) self.assertEqual(["val3"], ns.attr2) parser = ArgumentParserEx() parser.add_argument("attr1", action="store", nargs="*") parser.add_argument("--attr2", action="store", nargs="*") ns, remaining = parser.parse_known_args(["val1", "val2", "--attr2"]) self.assertListEqual([], remaining) self.assertEqual(["val1", "val2"], ns.attr1) self.assertEqual([], ns.attr2) ns, remaining = parser.parse_known_args(["--attr2", "val1", "val2"]) self.assertListEqual([], remaining) self.assertEqual([], ns.attr1) self.assertEqual(["val1", "val2"], ns.attr2) ns, remaining = parser.parse_known_args(["val1", "--attr2", "val2"]) self.assertListEqual([], remaining) self.assertEqual(["val1"], ns.attr1) self.assertEqual(["val2"], ns.attr2) parser = ArgumentParserEx() parser.add_argument("-C", action="append", nargs="?") ns = parser.parse_args(["-C", "a1", "-C"]) self.assertListEqual([["a1"], []], ns.C) parser = ArgumentParserEx() parser.add_argument("-C", action="append", nargs="*") ns = parser.parse_args(["-C", "a1", "-C", "b1", "b2", "-C"]) self.assertListEqual([["a1"], ["b1", "b2"], []], ns.C) parser = ArgumentParserEx() parser.add_argument("-C", action="append", nargs="+") ns = parser.parse_args(["-C", "a1", "-C", "b1", "b2"]) self.assertListEqual([["a1"], ["b1", "b2"]], ns.C) parser = ArgumentParserEx() parser.add_argument("C", action="append", nargs="?") ns = parser.parse_args(["1"]) self.assertListEqual([["1"]], ns.C) ns, remaining = parser.parse_known_args(["1", "2"]) self.assertListEqual(["2"], remaining) self.assertListEqual([["1"]], ns.C) ns = parser.parse_args([]) self.assertIsNone(ns.C) parser = ArgumentParserEx() parser.add_argument("C", action="append", nargs="*") ns = parser.parse_args(["1"]) self.assertListEqual([["1"]], ns.C) ns = parser.parse_args(["1", "2"]) self.assertListEqual([["1", "2"]], ns.C) ns, _remaining = parser.parse_known_args(["1", "2", "-a", "3"]) self.assertListEqual([["1", "2"], ["3"]], ns.C) ns, _remaining = parser.parse_known_args(["1", "2", "-a"]) self.assertListEqual([["1", "2"]], ns.C) # Check that empty list does not raise an Exception parser.parse_args([]) parser = ArgumentParserEx() parser.add_argument("C", action="append", nargs="+") ns = parser.parse_args(["1"]) self.assertListEqual([["1"]], ns.C) ns = parser.parse_args(["1", "2"]) self.assertListEqual([["1", "2"]], ns.C) ns, _remaining = parser.parse_known_args(["1", "2", "-a", "3"]) self.assertListEqual([["1", "2"], ["3"]], ns.C) ns, _remaining = parser.parse_known_args(["1", "2", "-a"]) self.assertListEqual([["1", "2"]], ns.C) self.assertRaisesRegexp(ValueError, "Required attribute not found", parser.parse_args, [])
def test_implicit_default_values(self): parser = ArgumentParserEx() parser.add_argument("-a") parser.add_argument("-b", dest="dest_b") parser.add_argument("-c", nargs=2) parser.add_argument("-d", action="append") parser.add_argument("-e", action="store") parser.add_argument("-f", nargs="*") parser.add_argument("-g", nargs="+") parser.add_argument("-i", nargs="?") parser.add_argument("-j", nargs="*", action="append") parser.add_argument("-k", nargs="+", action="append") parser.add_argument("-l", nargs="?", action="append") ns = parser.parse_args([]) self.assertIsNone(getattr(ns, "a", "default")) self.assertIsNone(getattr(ns, "dest_b", "default")) self.assertIsNone(getattr(ns, "c", "default")) self.assertIsNone(getattr(ns, "d", "default")) self.assertIsNone(getattr(ns, "e", "default")) self.assertIsNone(getattr(ns, "f", "default")) self.assertIsNone(getattr(ns, "g", "default")) self.assertIsNone(getattr(ns, "i", "default")) self.assertIsNone(getattr(ns, "j", "default")) self.assertIsNone(getattr(ns, "k", "default")) self.assertIsNone(getattr(ns, "l", "default")) parser = ArgumentParserEx() parser.add_argument("a") self.assertRaisesRegexp(ValueError, "Required attribute not found", parser.parse_args, []) parser = ArgumentParserEx() parser.add_argument("b", nargs=2) self.assertRaisesRegexp(ValueError, "Required attribute not found", parser.parse_args, []) parser = ArgumentParserEx() parser.add_argument("c", action="append") self.assertRaisesRegexp(ValueError, "Required attribute not found", parser.parse_args, []) parser = ArgumentParserEx() parser.add_argument("d", action="store") self.assertRaisesRegexp(ValueError, "Required attribute not found", parser.parse_args, []) parser = ArgumentParserEx() parser.add_argument("e", nargs="*") ns = parser.parse_args([]) self.assertEqual([], getattr(ns, "e", "default")) parser = ArgumentParserEx() parser.add_argument("f", nargs="?") ns = parser.parse_args([]) self.assertIsNone(getattr(ns, "f", "default")) parser = ArgumentParserEx() parser.add_argument("g", nargs="*", action="append") ns = parser.parse_args([]) # ArgumentParser: [[]] self.assertEqual([], getattr(ns, "g", "default")) parser = ArgumentParserEx() parser.add_argument("h", nargs="?", action="append") ns = parser.parse_args([]) # ArgumentParser: [None] self.assertIsNone(getattr(ns, "h", "default"))