diff --git a/src/makei/build.py b/src/makei/build.py index 6f3fc26..78d7752 100644 --- a/src/makei/build.py +++ b/src/makei/build.py @@ -4,6 +4,7 @@ from datetime import datetime import shutil import sys +import os from pathlib import Path from tempfile import mkstemp from typing import Any, Dict, List, Optional @@ -109,9 +110,28 @@ def _create_build_vars(self): target_file_path = self.build_vars_path rules_mk_paths = list(Path(".").rglob("Rules.mk")) + real_targets = [] # Create Rules.mk.build for each Rules.mk for rules_mk_path in rules_mk_paths: rules_mk = RulesMk.from_file(rules_mk_path, self.src_dir, map(Path, self.iproj_json.include_path)) + rules_mk_src_obj_mapping = rules_mk.src_obj_mapping.copy() + if self.targets and self.targets[0] != "all": + for target in self.targets: + if target.startswith("dir_") and target not in real_targets: + real_targets.append(target) + else: + # Target is relative path. i.e. QRPGLESRC/TEST.RPGLE + if len(Path(target).parts) > 1: + tgt_dir = os.path.dirname(target) + tgt = os.path.basename(target) + # Target is a file name + else: + tgt_dir = "." + tgt = target + + # Target exist in the current Rules.mk and target's rule exists + if tgt_dir == str(rules_mk.containing_dir) and tgt.upper() in rules_mk_src_obj_mapping: + real_targets.extend(rules_mk_src_obj_mapping.pop(tgt.upper())) rules_mk.build_context = self rules_mk_build_path = rules_mk_path.parent / ".Rules.mk.build" rules_mk_build_path.write_text(str(rules_mk)) diff --git a/src/makei/cli/makei_entry.py b/src/makei/cli/makei_entry.py index 4a7b501..1996040 100755 --- a/src/makei/cli/makei_entry.py +++ b/src/makei/cli/makei_entry.py @@ -10,7 +10,7 @@ from makei import init_project from makei.build import BuildEnv from makei.cvtsrcpf import CvtSrcPf -from makei.utils import Colors, colored, get_compile_targets_from_filenames,decompose_filename +from makei.utils import Colors, colored,decompose_filename from pathlib import Path from makei.const import FILE_TARGET_MAPPING @@ -251,12 +251,8 @@ def handle_compile(args): if args.file: filenames = [args.file] elif args.files: - name=args.files.split(':') - for i in name: - if os.path.isdir(i): - filenames.append(i) - else: - filenames = map(os.path.basename, args.files.split(':')) + # Ensures all paths are relative to the project root + filenames = map(lambda f: (str(Path(f).resolve().relative_to(Path.cwd()))), args.files.split(':')) else: filenames = [] targets = [] @@ -266,19 +262,19 @@ def handle_compile(args): targets.append(make_dir_target(name)) else: source_names.append(name) + targets = read_and_filter_rules_mk(source_names) # print("source:"+' '.join(source_names)) # print("compile targets:"+' '.join(get_compile_targets_from_filenames(source_names))) - build_targets = read_and_filter_rules_mk(source_names) - if build_targets: - print(colored("targets: " + ', '.join(build_targets), Colors.OKBLUE)) - build_env = BuildEnv(build_targets, args.make_options, get_override_vars(args),trace=args.trace) - if args.trace: - build_env.dump_resolved_makefile() + # targets.extend(source_names) + print(colored("targets: " + ', '.join(targets), Colors.OKBLUE)) + build_env = BuildEnv(targets, args.make_options, get_override_vars(args),trace=args.log) + if args.log: + build_env.dump_resolved_makefile() + else: + if build_env.make(): + sys.exit(0) else: - if build_env.make(): - sys.exit(0) - else: - sys.exit(1) + sys.exit(1) def handle_build(args): @@ -341,4 +337,4 @@ def set_environment_vars(args): if __name__ == '__main__': - cli() + cli() \ No newline at end of file diff --git a/src/makei/rules_mk.py b/src/makei/rules_mk.py index 86abb27..08ede48 100644 --- a/src/makei/rules_mk.py +++ b/src/makei/rules_mk.py @@ -147,19 +147,24 @@ class RulesMk: targets: Dict[str, List[str]] rules: List[MKRule] build_context: Optional['BuildEnv'] = None + src_obj_mapping: Dict[str, str] def __init__(self, subdirs: List[str], rules: List[MKRule], containing_dir: Path) -> None: self.targets = {tgt_group + 's': [] for tgt_group in TARGET_GROUPS} + self.src_obj_mapping = {} for rule in rules: if rule.source_file is not None: decomposed_src = decompose_filename(rule.source_file) - + src = f"{decomposed_src[0].upper()}.{decomposed_src[2].upper()}" + if src not in self.src_obj_mapping: + self.src_obj_mapping[src] = [rule.target] + else: + self.src_obj_mapping[src].append(rule.target) tgt_group_list = FILE_TARGETGROUPS_MAPPING[decomposed_src[-2].upper()] # If only 1 target mapping exists, use it, otherwise use target's extension tgt_group = (next(iter(tgt_group_list)).upper() if len(tgt_group_list) == 1 else rule.target.split('.')[-1].upper()) - if tgt_group not in TARGET_GROUPS: print(f"Warning: Target '{rule.target}' is not supported") sys.exit(1) diff --git a/src/makei/utils.py b/src/makei/utils.py index 74c106e..b4a7d48 100644 --- a/src/makei/utils.py +++ b/src/makei/utils.py @@ -12,7 +12,7 @@ from pathlib import Path from shutil import move, copymode from tempfile import mkstemp, gettempdir -from typing import Callable, List, Optional, Tuple, Union +from typing import Callable, Optional, Tuple, Union from makei.const import FILE_MAX_EXT_LENGTH, FILE_TARGET_MAPPING, COMMENT_STYLES @@ -281,30 +281,6 @@ def get_target_from_filename(filename: str) -> str: return f'{name.upper()}.{FILE_TARGET_MAPPING[ext]}' -def get_compile_targets_from_filenames(filenames: List[str]) -> List[str]: - """ Returns the possible target name for the given filename - - >>> get_compile_targets_from_filenames(["test.PGM.RPGLE"]) - ['TEST.PGM'] - >>> get_compile_targets_from_filenames(["test.pgm.rpgle"]) - ['TEST.PGM'] - >>> get_compile_targets_from_filenames(["test.RPGLE"]) - ['TEST.MODULE'] - >>> get_compile_targets_from_filenames(["vat300.rpgle"]) - ['VAT300.MODULE'] - >>> get_compile_targets_from_filenames(["functionsVAT/VAT300.RPGLE", "test.RPGLE"]) - ['VAT300.MODULE', 'TEST.MODULE'] - >>> get_compile_targets_from_filenames(["ART200-Work_with_article.PGM.SQLRPGLE", "SGSMSGF.MSGF"]) - ['ART200.PGM', 'SGSMSGF.MSGF'] - >>> get_compile_targets_from_filenames(["SAMPLE.BNDDIR"]) - ['SAMPLE.BNDDIR'] - """ - result = [] - for filename in filenames: - result.append(get_target_from_filename(filename)) - return result - - def format_datetime(d: datetime) -> str: # 2022-03-25-09.33.34.064676 return d.strftime("%Y-%m-%d-%H.%M.%S.%f") diff --git a/tests/data/build_env/sample_project1/innerdir2/Rules.mk b/tests/data/build_env/sample_project1/innerdir2/Rules.mk index 338b75f..94a3e71 100644 --- a/tests/data/build_env/sample_project1/innerdir2/Rules.mk +++ b/tests/data/build_env/sample_project1/innerdir2/Rules.mk @@ -1 +1,2 @@ -HELLOp.PGM: HELLO.PGM.RPGLE \ No newline at end of file +HELLOp.PGM: HELLO.PGM.RPGLE +TEST2.PGM: TEST.SQLRPGLE \ No newline at end of file diff --git a/tests/data/build_env/sample_project1/innerdir2/TEST.SQLRPGLE b/tests/data/build_env/sample_project1/innerdir2/TEST.SQLRPGLE new file mode 100644 index 0000000..da046a0 --- /dev/null +++ b/tests/data/build_env/sample_project1/innerdir2/TEST.SQLRPGLE @@ -0,0 +1,3 @@ +**free +dsply 'Hello World'; +return; diff --git a/tests/data/rules_mks/mapping.rules.mk b/tests/data/rules_mks/mapping.rules.mk new file mode 100644 index 0000000..c862f4c --- /dev/null +++ b/tests/data/rules_mks/mapping.rules.mk @@ -0,0 +1,6 @@ +OBSCURE.MODULE: LONGSOURCEFILENAME.RPGLE + +HELLO.PGM: HELLO.RPGLE +HELLO.MODULE: HELLO.RPGLE + +WORLD.PGM: WORLD.PGM.RPGLE \ No newline at end of file diff --git a/tests/unit/test_rules_mk.py b/tests/unit/test_rules_mk.py index 4064207..a24f8bf 100644 --- a/tests/unit/test_rules_mk.py +++ b/tests/unit/test_rules_mk.py @@ -128,6 +128,8 @@ def test_from_file(): 'private VARIMMED ::= IMMED', 'private VARESCAPE :::= ESCAPE'] mkrule1 = MKRule('VAT300.MODULE', ['vat300.rpgle', 'some.rpgleinc'], [], variables1, data_dir, []) expected_rules = [mkrule1] + + assert rules_mk.src_obj_mapping['VAT300.RPGLE'] == ['VAT300.MODULE'] assert rules_mk.containing_dir == data_dir assert rules_mk.subdirs == ['adir', 'bdir'] assert rules_mk.targets == expected_targets @@ -203,9 +205,11 @@ def test_dtaara_recipe(): 'LFs': [], 'DSPFs': [], 'PRTFs': [], 'CMDs': [], 'MODULEs': [], 'SRVPGMs': [], 'PGMs': [], 'MENUs': [], 'PNLGRPs': [], 'QMQRYs': [], 'WSCSTs': [], 'MSGs': []} + assert rules_mk.src_obj_mapping['LASTORDNO.DTAARA'] == ['LASTORDNO.DTAARA'] assert rules_mk.containing_dir == data_dir assert rules_mk.subdirs == [] assert rules_mk.targets == expected_targets + assert rules_mk.rules[0].variables == [] assert rules_mk.rules[0].commands == [] assert rules_mk.rules[0].dependencies == [] @@ -229,9 +233,11 @@ def test_dtaq_recipe(): 'LFs': [], 'DSPFs': [], 'PRTFs': [], 'CMDs': [], 'MODULEs': [], 'SRVPGMs': [], 'PGMs': [], 'MENUs': [], 'PNLGRPs': [], 'QMQRYs': [], 'WSCSTs': [], 'MSGs': []} + assert rules_mk.src_obj_mapping['ORDERS.DTAQ'] == ['ORDERS.DTAQ'] assert rules_mk.containing_dir == data_dir assert rules_mk.subdirs == [] assert rules_mk.targets == expected_targets + assert rules_mk.rules[0].variables == [] assert rules_mk.rules[0].commands == [] assert rules_mk.rules[0].dependencies == [] @@ -288,7 +294,10 @@ def test_dds_recipe(): 'DETORD.FILE', 'TMPDETORD.FILE'], 'LFs': [], 'DSPFs': ['ART301D.FILE'], 'PRTFs': ['ORD500O.FILE'], 'CMDs': [], 'MODULEs': [], 'SRVPGMs': [], 'PGMs': [], 'MENUs': [], 'PNLGRPs': [], 'QMQRYs': [], 'WSCSTs': [], 'MSGs': []} - + assert rules_mk.src_obj_mapping['ARTICLE.PF'] == ['ARTICLE.FILE'] + assert rules_mk.src_obj_mapping['ART301D.DSPF'] == ['ART301D.FILE'] + assert rules_mk.src_obj_mapping['DETORD.PF'] == ['DETORD.FILE'] + assert rules_mk.src_obj_mapping['ORD500O.PRTF'] == ['ORD500O.FILE'] assert rules_mk.containing_dir == data_dir assert rules_mk.subdirs == [] assert rules_mk.targets == expected_targets @@ -345,6 +354,137 @@ def test_dds_recipe(): ''' +def test_src_obj_mapping(): + rules_mk = RulesMk.from_file(data_dir / "mapping.rules.mk", data_dir) + expected_targets = {'TRGs': [], 'DTAARAs': [], 'DTAQs': [], 'SQLs': [], 'BNDDs': [], 'PFs': [], 'LFs': [], + 'DSPFs': [], 'PRTFs': [], 'CMDs': [], 'MODULEs': ['OBSCURE.MODULE', 'HELLO.MODULE'], + 'SRVPGMs': [], 'PGMs': ['HELLO.PGM', 'WORLD.PGM'], 'MENUs': [], 'PNLGRPs': [], + 'QMQRYs': [], 'WSCSTs': [], 'MSGs': []} + assert rules_mk.src_obj_mapping['LONGSOURCEFILENAME.RPGLE'] == ['OBSCURE.MODULE'] + assert rules_mk.src_obj_mapping['HELLO.RPGLE'] == ['HELLO.PGM', 'HELLO.MODULE'] + assert rules_mk.src_obj_mapping['WORLD.PGM.RPGLE'] == ['WORLD.PGM'] + assert rules_mk.containing_dir == data_dir + assert rules_mk.subdirs == [] + assert rules_mk.targets == expected_targets + + assert rules_mk.rules[0].variables == [] + assert rules_mk.rules[0].commands == [] + assert rules_mk.rules[0].dependencies == [] + assert rules_mk.rules[0].include_dirs == [] + assert rules_mk.rules[0].target == 'OBSCURE.MODULE' + assert rules_mk.rules[0].source_file == 'LONGSOURCEFILENAME.RPGLE' + assert str(rules_mk.rules[0]) == '''OBSCURE.MODULE_SRC=LONGSOURCEFILENAME.RPGLE +OBSCURE.MODULE_DEP=\nOBSCURE.MODULE_RECIPE=RPGLE_TO_MODULE_RECIPE\n''' + + assert rules_mk.rules[1].variables == [] + assert rules_mk.rules[1].commands == [] + assert rules_mk.rules[1].dependencies == [] + assert rules_mk.rules[1].include_dirs == [] + assert rules_mk.rules[1].target == 'HELLO.PGM' + assert rules_mk.rules[1].source_file == 'HELLO.RPGLE' + # assert str(rules_mk.rules[1]) == '''HELLO.PGM_SRC=HELLO.RPGLE\nHELLO.PGM_DEP= +# HELLO.PGM_RECIPE=PGM.RPGLE_TO_PGM_RECIPE\n''' + assert rules_mk.rules[2].variables == [] + assert rules_mk.rules[2].commands == [] + assert rules_mk.rules[2].dependencies == [] + assert rules_mk.rules[2].include_dirs == [] + assert rules_mk.rules[2].target == 'HELLO.MODULE' + assert rules_mk.rules[2].source_file == 'HELLO.RPGLE' + assert str(rules_mk.rules[2]) == '''HELLO.MODULE_SRC=HELLO.RPGLE\nHELLO.MODULE_DEP= +HELLO.MODULE_RECIPE=RPGLE_TO_MODULE_RECIPE\n''' + + assert rules_mk.rules[3].variables == [] + assert rules_mk.rules[3].commands == [] + assert rules_mk.rules[3].dependencies == [] + assert rules_mk.rules[3].include_dirs == [] + assert rules_mk.rules[3].target == 'WORLD.PGM' + assert rules_mk.rules[3].source_file == 'WORLD.PGM.RPGLE' + assert str(rules_mk.rules[3]) == '''WORLD.PGM_SRC=WORLD.PGM.RPGLE\nWORLD.PGM_DEP= +WORLD.PGM_RECIPE=PGM.RPGLE_TO_PGM_RECIPE\n''' + +def test_src_obj_mapping_from_root_folder(): + # Test loading from a valid file + test_dir = DATA_PATH / "build_env"/ "sample_project1" + rules_mk = RulesMk.from_file(test_dir / "Rules.mk", test_dir) + expected_targets = {'TRGs': [], 'DTAARAs': [], 'DTAQs': [], 'SQLs': [], 'BNDDs': [], + 'PFs': [], 'LFs': [], 'DSPFs': [], 'PRTFs': [], 'CMDs': [], + 'MODULEs': ['HELLO.MODULE'], 'SRVPGMs': [], 'PGMs': [], + 'MENUs': [], 'PNLGRPs': [], 'QMQRYs': [], 'WSCSTs': [], 'MSGs': []} + assert rules_mk.src_obj_mapping['HELLOP.RPGLE'] == ['HELLO.MODULE'] + assert rules_mk.containing_dir == test_dir + assert rules_mk.subdirs == ['inner'] + assert rules_mk.targets == expected_targets + + assert rules_mk.rules[0].variables == [] + assert rules_mk.rules[0].commands == [] + assert rules_mk.rules[0].dependencies == [] + assert rules_mk.rules[0].include_dirs == [] + assert rules_mk.rules[0].target == 'HELLO.MODULE' + assert str(rules_mk) == '''SUBDIRS := inner + +MODULEs := HELLO.MODULE + + +HELLO.MODULE_SRC=$(d)/HELLOP.RPGLE +HELLO.MODULE_DEP= +HELLO.MODULE_RECIPE=RPGLE_TO_MODULE_RECIPE +''' + +def test_src_obj_mapping_from_subfolder(): + # Test loading from a valid file + test_dir = DATA_PATH / "build_env"/ "sample_project1" / "innerdir1" + rules_mk = RulesMk.from_file(test_dir / "Rules.mk", test_dir) + expected_targets = {'TRGs': [], 'DTAARAs': [], 'DTAQs': [], 'SQLs': [], 'BNDDs': [], + 'PFs': [], 'LFs': [], 'DSPFs': [], 'PRTFs': [], 'CMDs': [], + 'MODULEs': ['TESTX.MODULE'], 'SRVPGMs': [], 'PGMs': [], + 'MENUs': [], 'PNLGRPs': [], 'QMQRYs': [], 'WSCSTs': [], 'MSGs': []} + assert rules_mk.src_obj_mapping['TEST.SQLRPGLE'] == ['TESTX.MODULE'] + assert rules_mk.containing_dir == test_dir + assert rules_mk.subdirs == [] + assert rules_mk.targets == expected_targets + + assert rules_mk.rules[0].variables == [] + assert rules_mk.rules[0].commands == [] + assert rules_mk.rules[0].dependencies == [] + assert rules_mk.rules[0].include_dirs == [] + assert rules_mk.rules[0].target == 'TESTX.MODULE' + assert str(rules_mk) == '''MODULEs := TESTX.MODULE + + +TESTX.MODULE_SRC=$(d)/TEST.SQLRPGLE +TESTX.MODULE_DEP= +TESTX.MODULE_RECIPE=SQLRPGLE_TO_MODULE_RECIPE +''' + +def test_src_obj_mapping_from_subfolder1(): + # Test loading from a valid file + test_dir = DATA_PATH / "build_env"/ "sample_project1" / "innerdir2" + rules_mk = RulesMk.from_file(test_dir / "Rules.mk", test_dir) + expected_targets = {'TRGs': [], 'DTAARAs': [], 'DTAQs': [], 'SQLs': [], 'BNDDs': [], + 'PFs': [], 'LFs': [], 'DSPFs': [], 'PRTFs': [], 'CMDs': [], + 'MODULEs': [], 'SRVPGMs': [], 'PGMs': ['HELLOP.PGM', 'TEST2.PGM'], + 'MENUs': [], 'PNLGRPs': [], 'QMQRYs': [], 'WSCSTs': [], 'MSGs': []} + assert rules_mk.src_obj_mapping['TEST.SQLRPGLE'] == ['TEST2.PGM'] + assert rules_mk.containing_dir == test_dir + assert rules_mk.subdirs == [] + assert rules_mk.targets == expected_targets + + assert rules_mk.rules[0].variables == [] + assert rules_mk.rules[0].commands == [] + assert rules_mk.rules[0].dependencies == [] + assert rules_mk.rules[0].include_dirs == [] + assert rules_mk.rules[0].target == 'HELLOP.PGM' + assert str(rules_mk) == '''PGMs := HELLOP.PGM TEST2.PGM + + +HELLOP.PGM_SRC=$(d)/HELLO.PGM.RPGLE +HELLOP.PGM_DEP= +HELLOP.PGM_RECIPE=PGM.RPGLE_TO_PGM_RECIPE +TEST2.PGM_SRC=$(d)/TEST.SQLRPGLE +TEST2.PGM_DEP= +TEST2.PGM_RECIPE=PGM.SQLRPGLE_TO_PGM_RECIPE +''' + def test_pgm_recipe(): # Test loading from a valid file rules_mk = RulesMk.from_file(data_dir / "pgm.rules.mk", data_dir) diff --git a/tests/unit/test_utils.py b/tests/unit/test_utils.py index 23a1eab..55f7e6d 100644 --- a/tests/unit/test_utils.py +++ b/tests/unit/test_utils.py @@ -1,4 +1,4 @@ -from makei.utils import make_include_dirs_absolute, get_compile_targets_from_filenames,decompose_filename +from makei.utils import make_include_dirs_absolute,decompose_filename # flake8: noqa: E501 @@ -51,11 +51,6 @@ def test_joblob_not_found(): expected = " INCDIR( ''/a/b/dir1'' ''dir2'')" assert make_include_dirs_absolute(path, parameters) == expected -def test_compile_targets_from_filenames(): - expected = ['TEST.DTAARA'] - assert get_compile_targets_from_filenames(['test.DTAARA']) == expected - expected = ['TEST.FILE'] - assert get_compile_targets_from_filenames(['test.index']) == expected def test_decompose_filename(): expected = ('custinfo1', None, 'PFSQL', '')