Working progress categories & type fixes
This commit is contained in:
parent
50fdffe5be
commit
0427fd1e1d
26
configure.py
26
configure.py
|
@ -16,14 +16,7 @@ import argparse
|
||||||
import sys
|
import sys
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, Dict, List
|
from typing import Any, Dict, List
|
||||||
|
from tools.project import *
|
||||||
from tools.project import (
|
|
||||||
Object,
|
|
||||||
ProjectConfig,
|
|
||||||
calculate_progress,
|
|
||||||
generate_build,
|
|
||||||
is_windows,
|
|
||||||
)
|
|
||||||
|
|
||||||
# Game versions
|
# Game versions
|
||||||
DEFAULT_VERSION = 0
|
DEFAULT_VERSION = 0
|
||||||
|
@ -138,7 +131,7 @@ if not config.non_matching:
|
||||||
config.binutils_tag = "2.42-1"
|
config.binutils_tag = "2.42-1"
|
||||||
config.compilers_tag = "20240706"
|
config.compilers_tag = "20240706"
|
||||||
config.dtk_tag = "v0.9.4"
|
config.dtk_tag = "v0.9.4"
|
||||||
config.objdiff_tag = "v2.0.0-beta.3"
|
config.objdiff_tag = "v2.0.0-beta.5"
|
||||||
config.sjiswrap_tag = "v1.1.1"
|
config.sjiswrap_tag = "v1.1.1"
|
||||||
config.wibo_tag = "0.6.11"
|
config.wibo_tag = "0.6.11"
|
||||||
|
|
||||||
|
@ -218,7 +211,7 @@ def DolphinLib(lib_name: str, objects: List[Object]) -> Dict[str, Any]:
|
||||||
"lib": lib_name,
|
"lib": lib_name,
|
||||||
"mw_version": "GC/1.2.5n",
|
"mw_version": "GC/1.2.5n",
|
||||||
"cflags": cflags_base,
|
"cflags": cflags_base,
|
||||||
"host": False,
|
"progress_category": "sdk",
|
||||||
"objects": objects,
|
"objects": objects,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -229,7 +222,7 @@ def Rel(lib_name: str, objects: List[Object]) -> Dict[str, Any]:
|
||||||
"lib": lib_name,
|
"lib": lib_name,
|
||||||
"mw_version": "GC/1.3.2",
|
"mw_version": "GC/1.3.2",
|
||||||
"cflags": cflags_rel,
|
"cflags": cflags_rel,
|
||||||
"host": True,
|
"progress_category": "game",
|
||||||
"objects": objects,
|
"objects": objects,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -245,7 +238,7 @@ config.libs = [
|
||||||
"lib": "Runtime.PPCEABI.H",
|
"lib": "Runtime.PPCEABI.H",
|
||||||
"mw_version": config.linker_version,
|
"mw_version": config.linker_version,
|
||||||
"cflags": cflags_runtime,
|
"cflags": cflags_runtime,
|
||||||
"host": False,
|
"progress_category": "sdk", # str | List[str]
|
||||||
"objects": [
|
"objects": [
|
||||||
Object(NonMatching, "Runtime.PPCEABI.H/global_destructor_chain.c"),
|
Object(NonMatching, "Runtime.PPCEABI.H/global_destructor_chain.c"),
|
||||||
Object(NonMatching, "Runtime.PPCEABI.H/__init_cpp_exceptions.cpp"),
|
Object(NonMatching, "Runtime.PPCEABI.H/__init_cpp_exceptions.cpp"),
|
||||||
|
@ -253,12 +246,19 @@ config.libs = [
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
# Optional extra categories for progress tracking
|
||||||
|
# Adjust as desired for your project
|
||||||
|
config.progress_categories = [
|
||||||
|
ProgressCategory("game", "Game Code"),
|
||||||
|
ProgressCategory("sdk", "SDK Code"),
|
||||||
|
]
|
||||||
|
config.progress_each_module = args.verbose
|
||||||
|
|
||||||
if args.mode == "configure":
|
if args.mode == "configure":
|
||||||
# Write build.ninja and objdiff.json
|
# Write build.ninja and objdiff.json
|
||||||
generate_build(config)
|
generate_build(config)
|
||||||
elif args.mode == "progress":
|
elif args.mode == "progress":
|
||||||
# Print progress and write progress.json
|
# Print progress and write progress.json
|
||||||
config.progress_each_module = args.verbose
|
|
||||||
calculate_progress(config)
|
calculate_progress(config)
|
||||||
else:
|
else:
|
||||||
sys.exit("Unknown mode: " + args.mode)
|
sys.exit("Unknown mode: " + args.mode)
|
||||||
|
|
139
tools/project.py
139
tools/project.py
|
@ -17,7 +17,7 @@ import os
|
||||||
import platform
|
import platform
|
||||||
import sys
|
import sys
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, Dict, List, Optional, Set, Tuple, Union
|
from typing import Any, Dict, List, Optional, Set, Tuple, Union, cast
|
||||||
|
|
||||||
from . import ninja_syntax
|
from . import ninja_syntax
|
||||||
from .ninja_syntax import serialize_path
|
from .ninja_syntax import serialize_path
|
||||||
|
@ -72,6 +72,7 @@ class Object:
|
||||||
def set_default(key: str, value: Any) -> None:
|
def set_default(key: str, value: Any) -> None:
|
||||||
if obj.options[key] is None:
|
if obj.options[key] is None:
|
||||||
obj.options[key] = value
|
obj.options[key] = value
|
||||||
|
|
||||||
set_default("add_to_all", True)
|
set_default("add_to_all", True)
|
||||||
set_default("asflags", config.asflags)
|
set_default("asflags", config.asflags)
|
||||||
set_default("asm_dir", config.asm_dir)
|
set_default("asm_dir", config.asm_dir)
|
||||||
|
@ -156,11 +157,11 @@ class ProjectConfig:
|
||||||
None # Custom build steps, types are ["pre-compile", "post-compile", "post-link", "post-build"]
|
None # Custom build steps, types are ["pre-compile", "post-compile", "post-link", "post-build"]
|
||||||
)
|
)
|
||||||
|
|
||||||
# Progress output and progress.json config
|
# Progress output, progress.json and report.json config
|
||||||
self.progress_all: bool = True # Include combined "all" category
|
self.progress_all: bool = True # Include combined "all" category
|
||||||
self.progress_modules: bool = True # Include combined "modules" category
|
self.progress_modules: bool = True # Include combined "modules" category
|
||||||
self.progress_each_module: bool = (
|
self.progress_each_module: bool = (
|
||||||
True # Include individual modules, disable for large numbers of modules
|
False # Include individual modules, disable for large numbers of modules
|
||||||
)
|
)
|
||||||
self.progress_categories: List[ProgressCategory] = [] # Additional categories
|
self.progress_categories: List[ProgressCategory] = [] # Additional categories
|
||||||
|
|
||||||
|
@ -567,8 +568,8 @@ def generate_build_ninja(
|
||||||
n.comment("Custom project build rules (pre/post-processing)")
|
n.comment("Custom project build rules (pre/post-processing)")
|
||||||
for rule in config.custom_build_rules or {}:
|
for rule in config.custom_build_rules or {}:
|
||||||
n.rule(
|
n.rule(
|
||||||
name=rule.get("name"),
|
name=cast(str, rule.get("name")),
|
||||||
command=rule.get("command"),
|
command=cast(str, rule.get("command")),
|
||||||
description=rule.get("description", None),
|
description=rule.get("description", None),
|
||||||
depfile=rule.get("depfile", None),
|
depfile=rule.get("depfile", None),
|
||||||
generator=rule.get("generator", False),
|
generator=rule.get("generator", False),
|
||||||
|
@ -580,12 +581,12 @@ def generate_build_ninja(
|
||||||
)
|
)
|
||||||
n.newline()
|
n.newline()
|
||||||
|
|
||||||
def write_custom_step(step: str) -> List[str]:
|
def write_custom_step(step: str) -> List[str | Path]:
|
||||||
implicit = []
|
implicit: List[str | Path] = []
|
||||||
if config.custom_build_steps and step in config.custom_build_steps:
|
if config.custom_build_steps and step in config.custom_build_steps:
|
||||||
n.comment(f"Custom build steps ({step})")
|
n.comment(f"Custom build steps ({step})")
|
||||||
for custom_step in config.custom_build_steps[step]:
|
for custom_step in config.custom_build_steps[step]:
|
||||||
outputs = custom_step.get("outputs")
|
outputs = cast(List[str | Path], custom_step.get("outputs"))
|
||||||
|
|
||||||
if isinstance(outputs, list):
|
if isinstance(outputs, list):
|
||||||
implicit.extend(outputs)
|
implicit.extend(outputs)
|
||||||
|
@ -594,7 +595,7 @@ def generate_build_ninja(
|
||||||
|
|
||||||
n.build(
|
n.build(
|
||||||
outputs=outputs,
|
outputs=outputs,
|
||||||
rule=custom_step.get("rule"),
|
rule=cast(str, custom_step.get("rule")),
|
||||||
inputs=custom_step.get("inputs", None),
|
inputs=custom_step.get("inputs", None),
|
||||||
implicit=custom_step.get("implicit", None),
|
implicit=custom_step.get("implicit", None),
|
||||||
order_only=custom_step.get("order_only", None),
|
order_only=custom_step.get("order_only", None),
|
||||||
|
@ -734,7 +735,7 @@ def generate_build_ninja(
|
||||||
used_compiler_versions.add(obj.options["mw_version"])
|
used_compiler_versions.add(obj.options["mw_version"])
|
||||||
|
|
||||||
# Avoid creating duplicate build rules
|
# Avoid creating duplicate build rules
|
||||||
if obj.src_obj_path in source_added:
|
if obj.src_obj_path is None or obj.src_obj_path in source_added:
|
||||||
return obj.src_obj_path
|
return obj.src_obj_path
|
||||||
source_added.add(obj.src_obj_path)
|
source_added.add(obj.src_obj_path)
|
||||||
|
|
||||||
|
@ -757,6 +758,7 @@ def generate_build_ninja(
|
||||||
)
|
)
|
||||||
|
|
||||||
# Add ctx build rule
|
# Add ctx build rule
|
||||||
|
if obj.ctx_path is not None:
|
||||||
n.build(
|
n.build(
|
||||||
outputs=obj.ctx_path,
|
outputs=obj.ctx_path,
|
||||||
rule="decompctx",
|
rule="decompctx",
|
||||||
|
@ -765,7 +767,7 @@ def generate_build_ninja(
|
||||||
)
|
)
|
||||||
|
|
||||||
# Add host build rule
|
# Add host build rule
|
||||||
if obj.options["host"]:
|
if obj.options["host"] and obj.host_obj_path is not None:
|
||||||
n.build(
|
n.build(
|
||||||
outputs=obj.host_obj_path,
|
outputs=obj.host_obj_path,
|
||||||
rule="host_cc" if src_path.suffix == ".c" else "host_cpp",
|
rule="host_cc" if src_path.suffix == ".c" else "host_cpp",
|
||||||
|
@ -784,7 +786,9 @@ def generate_build_ninja(
|
||||||
|
|
||||||
return obj.src_obj_path
|
return obj.src_obj_path
|
||||||
|
|
||||||
def asm_build(obj: Object, src_path: Path, obj_path: Path) -> Optional[Path]:
|
def asm_build(
|
||||||
|
obj: Object, src_path: Path, obj_path: Optional[Path]
|
||||||
|
) -> Optional[Path]:
|
||||||
if obj.options["asflags"] is None:
|
if obj.options["asflags"] is None:
|
||||||
sys.exit("ProjectConfig.asflags missing")
|
sys.exit("ProjectConfig.asflags missing")
|
||||||
asflags_str = make_flags_str(obj.options["asflags"])
|
asflags_str = make_flags_str(obj.options["asflags"])
|
||||||
|
@ -793,7 +797,7 @@ def generate_build_ninja(
|
||||||
asflags_str += " " + extra_asflags_str
|
asflags_str += " " + extra_asflags_str
|
||||||
|
|
||||||
# Avoid creating duplicate build rules
|
# Avoid creating duplicate build rules
|
||||||
if obj_path in source_added:
|
if obj_path is None or obj_path in source_added:
|
||||||
return obj_path
|
return obj_path
|
||||||
source_added.add(obj_path)
|
source_added.add(obj_path)
|
||||||
|
|
||||||
|
@ -825,7 +829,7 @@ def generate_build_ninja(
|
||||||
|
|
||||||
link_built_obj = obj.completed
|
link_built_obj = obj.completed
|
||||||
built_obj_path: Optional[Path] = None
|
built_obj_path: Optional[Path] = None
|
||||||
if obj.src_path.exists():
|
if obj.src_path is not None and obj.src_path.exists():
|
||||||
if obj.src_path.suffix in (".c", ".cp", ".cpp"):
|
if obj.src_path.suffix in (".c", ".cp", ".cpp"):
|
||||||
# Add MWCC & host build rules
|
# Add MWCC & host build rules
|
||||||
built_obj_path = c_build(obj, obj.src_path)
|
built_obj_path = c_build(obj, obj.src_path)
|
||||||
|
@ -932,7 +936,7 @@ def generate_build_ninja(
|
||||||
rspfile="$rspfile",
|
rspfile="$rspfile",
|
||||||
rspfile_content="$in_newline",
|
rspfile_content="$in_newline",
|
||||||
)
|
)
|
||||||
generated_rels = []
|
generated_rels: List[str] = []
|
||||||
for idx, link in enumerate(build_config["links"]):
|
for idx, link in enumerate(build_config["links"]):
|
||||||
# Map module names to link steps
|
# Map module names to link steps
|
||||||
link_steps_local = list(
|
link_steps_local = list(
|
||||||
|
@ -1048,10 +1052,11 @@ def generate_build_ninja(
|
||||||
command=f"{objdiff} report generate -o $out",
|
command=f"{objdiff} report generate -o $out",
|
||||||
description="REPORT",
|
description="REPORT",
|
||||||
)
|
)
|
||||||
|
report_implicit: List[str | Path] = [objdiff, "all_source"]
|
||||||
n.build(
|
n.build(
|
||||||
outputs=report_path,
|
outputs=report_path,
|
||||||
rule="report",
|
rule="report",
|
||||||
implicit=[objdiff, "all_source"],
|
implicit=report_implicit,
|
||||||
)
|
)
|
||||||
|
|
||||||
###
|
###
|
||||||
|
@ -1169,7 +1174,7 @@ def generate_objdiff_config(
|
||||||
return
|
return
|
||||||
|
|
||||||
objdiff_config: Dict[str, Any] = {
|
objdiff_config: Dict[str, Any] = {
|
||||||
"min_version": "1.0.0",
|
"min_version": "2.0.0-beta.5",
|
||||||
"custom_make": "ninja",
|
"custom_make": "ninja",
|
||||||
"build_target": False,
|
"build_target": False,
|
||||||
"watch_patterns": [
|
"watch_patterns": [
|
||||||
|
@ -1185,6 +1190,7 @@ def generate_objdiff_config(
|
||||||
"*.json",
|
"*.json",
|
||||||
],
|
],
|
||||||
"units": [],
|
"units": [],
|
||||||
|
"progress_categories": [],
|
||||||
}
|
}
|
||||||
|
|
||||||
# decomp.me compiler name mapping
|
# decomp.me compiler name mapping
|
||||||
|
@ -1220,22 +1226,21 @@ def generate_objdiff_config(
|
||||||
"Wii/1.7": "mwcc_43_213",
|
"Wii/1.7": "mwcc_43_213",
|
||||||
}
|
}
|
||||||
|
|
||||||
build_path = config.out_path()
|
def add_unit(
|
||||||
|
build_obj: Dict[str, Any], module_name: str, progress_categories: List[str]
|
||||||
def add_unit(build_obj: Dict[str, Any], module_name: str) -> None:
|
) -> None:
|
||||||
if build_obj["autogenerated"]:
|
|
||||||
# Skip autogenerated objects
|
|
||||||
return
|
|
||||||
|
|
||||||
obj_path, obj_name = build_obj["object"], build_obj["name"]
|
obj_path, obj_name = build_obj["object"], build_obj["name"]
|
||||||
base_object = Path(obj_name).with_suffix("")
|
base_object = Path(obj_name).with_suffix("")
|
||||||
unit_config: Dict[str, Any] = {
|
unit_config: Dict[str, Any] = {
|
||||||
"name": Path(module_name) / base_object,
|
"name": Path(module_name) / base_object,
|
||||||
"target_path": obj_path,
|
"target_path": obj_path,
|
||||||
|
"metadata": {
|
||||||
|
"auto_generated": build_obj["autogenerated"],
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
obj = objects.get(obj_name)
|
obj = objects.get(obj_name)
|
||||||
if obj is None or not obj.src_path.exists():
|
if obj is None or not obj.src_path or not obj.src_path.exists():
|
||||||
objdiff_config["units"].append(unit_config)
|
objdiff_config["units"].append(unit_config)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -1264,8 +1269,6 @@ def generate_objdiff_config(
|
||||||
cflags.insert(0, "-lang=c")
|
cflags.insert(0, "-lang=c")
|
||||||
|
|
||||||
unit_config["base_path"] = obj.src_obj_path
|
unit_config["base_path"] = obj.src_obj_path
|
||||||
unit_config["reverse_fn_order"] = reverse_fn_order
|
|
||||||
unit_config["complete"] = obj.completed
|
|
||||||
compiler_version = COMPILER_MAP.get(obj.options["mw_version"])
|
compiler_version = COMPILER_MAP.get(obj.options["mw_version"])
|
||||||
if compiler_version is None:
|
if compiler_version is None:
|
||||||
print(f"Missing scratch compiler mapping for {obj.options['mw_version']}")
|
print(f"Missing scratch compiler mapping for {obj.options['mw_version']}")
|
||||||
|
@ -1281,25 +1284,56 @@ def generate_objdiff_config(
|
||||||
"ctx_path": obj.ctx_path,
|
"ctx_path": obj.ctx_path,
|
||||||
"build_ctx": True,
|
"build_ctx": True,
|
||||||
}
|
}
|
||||||
metadata = {
|
category_opt: List[str] | str = obj.options["progress_category"]
|
||||||
|
if isinstance(category_opt, list):
|
||||||
|
progress_categories.extend(category_opt)
|
||||||
|
elif category_opt is not None:
|
||||||
|
progress_categories.append(category_opt)
|
||||||
|
unit_config["metadata"].update({
|
||||||
|
"complete": obj.completed,
|
||||||
|
"reverse_fn_order": reverse_fn_order,
|
||||||
"source_path": obj.src_path,
|
"source_path": obj.src_path,
|
||||||
}
|
"progress_categories": progress_categories,
|
||||||
if obj.options["progress_category"] is not None:
|
})
|
||||||
if isinstance(obj.options["progress_category"], list):
|
|
||||||
metadata["progress_categories"] = obj.options["progress_category"]
|
|
||||||
else:
|
|
||||||
metadata["progress_categories"] = [obj.options["progress_category"]]
|
|
||||||
unit_config["metadata"] = metadata
|
|
||||||
objdiff_config["units"].append(unit_config)
|
objdiff_config["units"].append(unit_config)
|
||||||
|
|
||||||
# Add DOL units
|
# Add DOL units
|
||||||
for unit in build_config["units"]:
|
for unit in build_config["units"]:
|
||||||
add_unit(unit, build_config["name"])
|
progress_categories = []
|
||||||
|
# Only include a "dol" category if there are any modules
|
||||||
|
# Otherwise it's redundant with the global report measures
|
||||||
|
if len(build_config["modules"]) > 0:
|
||||||
|
progress_categories.append("dol")
|
||||||
|
add_unit(unit, build_config["name"], progress_categories)
|
||||||
|
|
||||||
# Add REL units
|
# Add REL units
|
||||||
for module in build_config["modules"]:
|
for module in build_config["modules"]:
|
||||||
for unit in module["units"]:
|
for unit in module["units"]:
|
||||||
add_unit(unit, module["name"])
|
progress_categories = []
|
||||||
|
if config.progress_modules:
|
||||||
|
progress_categories.append("modules")
|
||||||
|
if config.progress_each_module:
|
||||||
|
progress_categories.append(module["name"])
|
||||||
|
add_unit(unit, module["name"], progress_categories)
|
||||||
|
|
||||||
|
# Add progress categories
|
||||||
|
def add_category(id: str, name: str):
|
||||||
|
objdiff_config["progress_categories"].append(
|
||||||
|
{
|
||||||
|
"id": id,
|
||||||
|
"name": name,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
if len(build_config["modules"]) > 0:
|
||||||
|
add_category("dol", "DOL")
|
||||||
|
if config.progress_modules:
|
||||||
|
add_category("modules", "Modules")
|
||||||
|
if config.progress_each_module:
|
||||||
|
for module in build_config["modules"]:
|
||||||
|
add_category(module["name"], module["name"])
|
||||||
|
for category in config.progress_categories:
|
||||||
|
add_category(category.id, category.name)
|
||||||
|
|
||||||
# Write objdiff.json
|
# Write objdiff.json
|
||||||
with open("objdiff.json", "w", encoding="utf-8") as w:
|
with open("objdiff.json", "w", encoding="utf-8") as w:
|
||||||
|
@ -1364,16 +1398,15 @@ def calculate_progress(config: ProjectConfig) -> None:
|
||||||
return self.data_progress / self.data_total
|
return self.data_progress / self.data_total
|
||||||
|
|
||||||
progress_units: Dict[str, ProgressUnit] = {}
|
progress_units: Dict[str, ProgressUnit] = {}
|
||||||
if len(config.progress_categories) > 0:
|
|
||||||
for category in config.progress_categories:
|
|
||||||
progress_units[category.id] = ProgressUnit(category.name)
|
|
||||||
else:
|
|
||||||
if config.progress_all:
|
if config.progress_all:
|
||||||
progress_units["all"] = ProgressUnit("All")
|
progress_units["all"] = ProgressUnit("All")
|
||||||
progress_units["dol"] = ProgressUnit("DOL")
|
progress_units["dol"] = ProgressUnit("DOL")
|
||||||
if len(build_config["modules"]) > 0:
|
if len(build_config["modules"]) > 0:
|
||||||
if config.progress_modules:
|
if config.progress_modules:
|
||||||
progress_units["modules"] = ProgressUnit("Modules")
|
progress_units["modules"] = ProgressUnit("Modules")
|
||||||
|
if len(config.progress_categories) > 0:
|
||||||
|
for category in config.progress_categories:
|
||||||
|
progress_units[category.id] = ProgressUnit(category.name)
|
||||||
if config.progress_each_module:
|
if config.progress_each_module:
|
||||||
for module in build_config["modules"]:
|
for module in build_config["modules"]:
|
||||||
progress_units[module["name"]] = ProgressUnit(module["name"])
|
progress_units[module["name"]] = ProgressUnit(module["name"])
|
||||||
|
@ -1389,12 +1422,12 @@ def calculate_progress(config: ProjectConfig) -> None:
|
||||||
add_unit("dol", unit)
|
add_unit("dol", unit)
|
||||||
obj = objects.get(unit["name"])
|
obj = objects.get(unit["name"])
|
||||||
if obj is not None:
|
if obj is not None:
|
||||||
category = obj.options["progress_category"]
|
category_opt = obj.options["progress_category"]
|
||||||
if isinstance(category, list):
|
if isinstance(category_opt, list):
|
||||||
for category in category:
|
for id in category_opt:
|
||||||
add_unit(category, unit)
|
add_unit(id, unit)
|
||||||
elif category is not None:
|
elif category_opt is not None:
|
||||||
add_unit(category, unit)
|
add_unit(category_opt, unit)
|
||||||
|
|
||||||
# Add REL units
|
# Add REL units
|
||||||
for module in build_config["modules"]:
|
for module in build_config["modules"]:
|
||||||
|
@ -1404,12 +1437,12 @@ def calculate_progress(config: ProjectConfig) -> None:
|
||||||
add_unit(module["name"], unit)
|
add_unit(module["name"], unit)
|
||||||
obj = objects.get(unit["name"])
|
obj = objects.get(unit["name"])
|
||||||
if obj is not None:
|
if obj is not None:
|
||||||
category = obj.options["progress_category"]
|
category_opt = obj.options["progress_category"]
|
||||||
if isinstance(category, list):
|
if isinstance(category_opt, list):
|
||||||
for category in category:
|
for id in category_opt:
|
||||||
add_unit(category, unit)
|
add_unit(id, unit)
|
||||||
elif category is not None:
|
elif category_opt is not None:
|
||||||
add_unit(category, unit)
|
add_unit(category_opt, unit)
|
||||||
|
|
||||||
# Print human-readable progress
|
# Print human-readable progress
|
||||||
print("Progress:")
|
print("Progress:")
|
||||||
|
|
Loading…
Reference in New Issue