diff options
-rw-r--r-- | .github/actions/mingw-cache/action.yml | 18 | ||||
-rw-r--r-- | .github/actions/openvic-build/action.yml | 32 | ||||
-rw-r--r-- | .github/actions/openvic-cache/action.yml | 22 | ||||
-rw-r--r-- | .github/actions/openvic-env/action.yml | 13 | ||||
-rw-r--r-- | .github/actions/openvic-env/commit-environment.js | 30 | ||||
-rwxr-xr-x | .github/actions/openvic-env/url-environment.sh | 57 | ||||
-rw-r--r-- | .github/workflows/builds.yml | 14 | ||||
-rw-r--r-- | .gitmodules | 3 | ||||
-rw-r--r-- | SConstruct | 77 | ||||
-rw-r--r-- | extension/deps/SCsub | 12 | ||||
m--------- | extension/deps/openvic-simulation | 0 | ||||
m--------- | scripts | 0 | ||||
-rw-r--r-- | scripts/build/cache.py | 127 | ||||
-rw-r--r-- | scripts/build/glob_recursive.py | 15 | ||||
-rw-r--r-- | scripts/build/option_handler.py | 39 |
15 files changed, 47 insertions, 412 deletions
diff --git a/.github/actions/mingw-cache/action.yml b/.github/actions/mingw-cache/action.yml deleted file mode 100644 index e92962d..0000000 --- a/.github/actions/mingw-cache/action.yml +++ /dev/null @@ -1,18 +0,0 @@ -name: Setup MinGW Cache -description: Setup MinGW Cache -inputs: - cache-key: - description: Name for MinGW cache key. - default: "mingw-cache" -runs: - using: "composite" - steps: - # Upload cache on completion and check it out now - - name: Load MinGW Cache - id: cache-mingw - uses: actions/cache@v3 - with: - path: C:\ProgramData\chocolatey\lib\mingw - key: ${{inputs.cache-key}} - - name: Setup MinGW for build - uses: egor-tensin/setup-mingw@v2
\ No newline at end of file diff --git a/.github/actions/openvic-build/action.yml b/.github/actions/openvic-build/action.yml deleted file mode 100644 index a4b3507..0000000 --- a/.github/actions/openvic-build/action.yml +++ /dev/null @@ -1,32 +0,0 @@ -name: Build OpenVic Extension -description: Build OpenVic Extension with provided options. -inputs: - target: - description: Build target (editor, template_release, template_debug). - default: "template_release" - platform: - description: Target platform. - required: false - sconsflags: - default: "" - scons-cache: - description: The scons cache path. - default: "${{ github.workspace }}/.scons-cache/" - scons-cache-limit: - description: The scons cache size limit. - # actions/cache has 10 GiB limit, and GitHub runners have a 14 GiB disk. - # Limit to 7 GiB to avoid having the extracted cache fill the disk. - default: 7168 -runs: - using: "composite" - steps: - - name: Scons Build - shell: sh - env: - SCONSFLAGS: ${{ inputs.sconsflags }} - SCONS_CACHE: ${{ inputs.scons-cache }} - SCONS_CACHE_LIMIT: ${{ inputs.scons-cache-limit }} - run: | - echo "Building with flags:" platform=${{ inputs.platform }} target=${{ inputs.target }} ${{ env.SCONSFLAGS }} - scons platform=${{ inputs.platform }} target=${{ inputs.target }} ${{ env.SCONSFLAGS }} - ls -l game/bin/openvic/
\ No newline at end of file diff --git a/.github/actions/openvic-cache/action.yml b/.github/actions/openvic-cache/action.yml deleted file mode 100644 index b4164eb..0000000 --- a/.github/actions/openvic-cache/action.yml +++ /dev/null @@ -1,22 +0,0 @@ -name: Setup OpenVic Build Cache -description: Setup OpenVic Build Cache -inputs: - cache-name: - description: The cache base name (job name by default). - default: "${{github.job}}" - scons-cache: - description: The scons cache path. - default: "${{github.workspace}}/.scons-cache/" -runs: - using: "composite" - steps: - # Upload cache on completion and check it out now - - name: Load .scons_cache directory - uses: actions/cache@v3 - with: - path: ${{inputs.scons-cache}} - key: ${{inputs.cache-name}}-${{env.OPENVIC_BASE_BRANCH}}-${{github.ref}}-${{github.sha}} - restore-keys: | - ${{inputs.cache-name}}-${{env.OPENVIC_BASE_BRANCH}}-${{github.ref}}-${{github.sha}} - ${{inputs.cache-name}}-${{env.OPENVIC_BASE_BRANCH}}-${{github.ref}} - ${{inputs.cache-name}}-${{env.OPENVIC_BASE_BRANCH}}
\ No newline at end of file diff --git a/.github/actions/openvic-env/action.yml b/.github/actions/openvic-env/action.yml deleted file mode 100644 index 7c8c4e3..0000000 --- a/.github/actions/openvic-env/action.yml +++ /dev/null @@ -1,13 +0,0 @@ -name: Setup OpenVic Environment -description: Setup OpenVic Environment -runs: - using: "composite" - steps: - - name: Setup URL Environment - shell: bash - run: ${GITHUB_ACTION_PATH}/url-environment.sh - - - name: Setup Commit Environment - uses: actions/github-script@v6 - with: - script: require(`${process.env.GITHUB_ACTION_PATH}/commit-environment.js`)({github, context, core}) diff --git a/.github/actions/openvic-env/commit-environment.js b/.github/actions/openvic-env/commit-environment.js deleted file mode 100644 index f6213c2..0000000 --- a/.github/actions/openvic-env/commit-environment.js +++ /dev/null @@ -1,30 +0,0 @@ -module.exports = async ({github, context, core}) => { - const commit_name = 'OPENVIC_COMMIT'; - const tag_name = 'OPENVIC_TAG'; - const release_name = 'OPENVIC_RELEASE'; - var commit_sha = process.env["GITHUB_SHA"]; - - if(context.eventName === 'pull_request') { - commit_sha = context.payload.pull_request.head.sha; - } - - core.exportVariable(commit_name, commit_sha); - - try { - const release = await github.rest.repos.getLatestRelease({owner: context.repo.owner, repo: context.repo.repo}); - core.exportVariable(tag_name, release.data["tag_name"]); - core.exportVariable(release_name, release.data["name"]); - } catch(error) { - if (error.response.status != 404) throw error; - - const tagList = await github.rest.repos.listTags({owner: context.repo.owner, repo: context.repo.repo}); - if (tagList.data.length == 0) { - core.warning("Could not list tags, this repo has no tags on it, setting tag_name and release_name environment variables to '<UserRepo-NoTag>' and '<UserRepo-NoRelease>', you can fetch tags with 'git fetch --tags' <remote-name>' and push tags with 'git push --tags"); - core.exportVariable(tag_name, `<${context.repo.owner}/${context.repo.repo}-NoTag>`); - core.exportVariable(release_name, `<${context.repo.owner}/${context.repo.repo}-NoRelease>`); - } else { - core.exportVariable(tag_name, tagList.data[0].name); - core.exportVariable(release_name, tagList.data[0].name); - } - } -}
\ No newline at end of file diff --git a/.github/actions/openvic-env/url-environment.sh b/.github/actions/openvic-env/url-environment.sh deleted file mode 100755 index 352218b..0000000 --- a/.github/actions/openvic-env/url-environment.sh +++ /dev/null @@ -1,57 +0,0 @@ -#!/bin/bash - -# $1 = environment name -# $2 = value to set environment -set_var() { - if [[ -z ${!1+set} ]]; then - export $1=$2 - fi -} - -# $1 = left side -# $2 = right side -# returns $1 and $2 joined together with a single '/'' -join_path() { - result=$1 - if [[ $result == *"/" && $2 == "/"* ]]; then - result=${result%/} - fi - if [[ $result != *"/" && $2 != "/"* ]]; then - result="$result/" - fi - echo "$result$2" -} - -# $1 = environment name -set_github_var() { - if [ "${!1}" == "" ]; then - echo "::error::$1 environment variable has not been set." - elif ! curl -o /dev/null --head --silent --fail "${!1}"; then - echo "::error::${!1} does not exist." - else - echo "$1=${!1}" >> $GITHUB_ENV - fi -} - -if [[ $GODOT_BASE_DOWNLOAD_URL == *"downloads.tuxfamily.org/godotengine"* ]]; then - if [[ $GODOT_BASE_DOWNLOAD_URL != *"${GODOT_VERSION}"* ]]; then - GODOT_BASE_DOWNLOAD_URL="$(join_path ${GODOT_BASE_DOWNLOAD_URL} ${GODOT_VERSION})" - fi - if [[ $GODOT_VERSION_TYPE != "stable" ]]; then - GODOT_BASE_DOWNLOAD_URL="$(join_path ${GODOT_BASE_DOWNLOAD_URL} ${GODOT_VERSION_TYPE})" - fi - set_var GODOT_LINUX_URL "$(join_path ${GODOT_BASE_DOWNLOAD_URL} "Godot_v${GODOT_VERSION}-${GODOT_VERSION_TYPE}_linux.x86_64.zip")" - set_var GODOT_TEMPLATE_URL "$(join_path ${GODOT_BASE_DOWNLOAD_URL} "Godot_v${GODOT_VERSION}-${GODOT_VERSION_TYPE}_export_templates.tpz")" -elif [[ $GODOT_BASE_DOWNLOAD_URL == *"github.com/godotengine"* ]]; then - if [[ $GODOT_BASE_DOWNLOAD_URL != *"/releases"* ]]; then - GODOT_BASE_DOWNLOAD_URL=$(join_path $GODOT_BASE_DOWNLOAD_URL "releases") - fi - if [[ $GODOT_BASE_DOWNLOAD_URL != *"/download"* ]]; then - GODOT_BASE_DOWNLOAD_URL=$(join_path $GODOT_BASE_DOWNLOAD_URL "download") - fi - set_var GODOT_LINUX_URL "$(join_path ${GODOT_BASE_DOWNLOAD_URL} "${GODOT_VERSION}-${GODOT_VERSION_TYPE}/Godot_v${GODOT_VERSION}-${GODOT_VERSION_TYPE}_linux.x86_64.zip")" - set_var GODOT_TEMPLATE_URL "$(join_path ${GODOT_BASE_DOWNLOAD_URL} "${GODOT_VERSION}-${GODOT_VERSION_TYPE}/Godot_v${GODOT_VERSION}-${GODOT_VERSION_TYPE}_export_templates.tpz")" -fi - -set_github_var GODOT_LINUX_URL -set_github_var GODOT_TEMPLATE_URL
\ No newline at end of file diff --git a/.github/workflows/builds.yml b/.github/workflows/builds.yml index 68da880..ce7265f 100644 --- a/.github/workflows/builds.yml +++ b/.github/workflows/builds.yml @@ -67,13 +67,14 @@ jobs: submodules: recursive - name: Setup OpenVic build cache - uses: ./.github/actions/openvic-cache + uses: OpenVicProject/openvic-cache@master with: cache-name: ${{ matrix.identifier }} + base-branch: ${{ env.OPENVIC_BASE_BRANCH }} continue-on-error: true - name: Setup Environment - uses: ./.github/actions/openvic-env + uses: OpenVicProject/openvic-env@master - name: Set up Python uses: actions/setup-python@v4 @@ -99,13 +100,14 @@ jobs: - name: Setup MinGW for Windows/MinGW build if: ${{ matrix.platform == 'windows' }} - uses: ./.github/actions/mingw-cache + uses: OpenVicProject/mingw-cache@master - name: Compile Extension - uses: ./.github/actions/openvic-build + uses: OpenVicProject/openvic-build@master with: platform: ${{ matrix.platform }} target: ${{ matrix.target }} + bin-dir: "game/bin/" sconsflags: arch=${{ matrix.arch }} - name: Delete compilation files @@ -148,7 +150,7 @@ jobs: uses: actions/checkout@v3.3.0 - name: Setup Environment - uses: ./.github/actions/openvic-env + uses: OpenVicProject/openvic-env@master - name: Download artifact uses: actions/download-artifact@v3 @@ -188,7 +190,7 @@ jobs: uses: actions/checkout@v3.3.0 - name: Setup Environment - uses: ./.github/actions/openvic-env + uses: OpenVicProject/openvic-env@master - name: Download artifact uses: actions/download-artifact@v3 diff --git a/.gitmodules b/.gitmodules index 26eca85..a11fda2 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,3 +4,6 @@ [submodule "extension/deps/openvic-simulation"] path = extension/deps/openvic-simulation url = https://github.com/OpenVicProject/OpenVic-Simulation +[submodule "scripts"] + path = scripts + url = git@github.com:OpenVicProject/scripts @@ -1,55 +1,31 @@ #!/usr/bin/env python + import os +import platform import sys -from glob import glob - -# Local -from scripts.build.option_handler import OptionsClass -from scripts.build.glob_recursive import GlobRecursive -from scripts.build.cache import show_progress - -opts = OptionsClass(ARGUMENTS) -opts.Add(BoolVariable("compiledb", "Generate compilation DB (`compile_commands.json`) for external tools", False)) -opts.Add(BoolVariable("verbose", "Enable verbose output for the compilation", False)) -opts.Add(BoolVariable("intermediate_delete", "Enables automatically deleting unassociated intermediate binary files.", True)) -opts.Add(BoolVariable("progress", "Show a progress indicator during compilation", True)) - - -# Needs Clone, else godot-cpp builds using our modified environment variables. eg: godot-cpp builds on C++20 -env = SConscript("godot-cpp/SConstruct").Clone() +import SCons -# Make LIBS into a list which is easier to deal with. -env["LIBS"] = [env["LIBS"]] +BINDIR = "game/bin" -# Require C++20 -if env.get("is_msvc", False): - env.Replace(CXXFLAGS=["/std:c++20"]) -else: - env.Replace(CXXFLAGS=["-std=c++20"]) +env = SConscript("scripts/SConstruct") -# Custom options and profile flags. -opts.Make(["custom.py"]) -opts.Finalize(env) -Help(opts.GenerateHelpText(env)) +env.PrependENVPath("PATH", os.getenv("PATH")) -scons_cache_path = os.environ.get("SCONS_CACHE") -if scons_cache_path != None: - CacheDir(scons_cache_path) - print("Scons cache enabled... (path: '" + scons_cache_path + "')") +opts = env.SetupOptions() -if env["compiledb"]: - # Generating the compilation DB (`compile_commands.json`) requires SCons 4.0.0 or later. - from SCons import __version__ as scons_raw_version +env.FinalizeOptions() - scons_ver = env._get_major_minor_revision(scons_raw_version) +# Needs Clone, else godot-cpp builds using our modified environment variables. eg: godot-cpp builds on C++20 +godot_env = SConscript("godot-cpp/SConstruct") - if scons_ver < (4, 0, 0): - print("The `compiledb=yes` option requires SCons 4.0 or later, but your version is %s." % scons_raw_version) - Exit(255) +# Make LIBS into a list which is easier to deal with. +godot_env["LIBS"] = [godot_env["LIBS"]] +env.Append(CPPPATH=godot_env["CPPPATH"]) +env.Append(LIBPATH=godot_env["LIBPATH"]) +env.Prepend(LIBS=godot_env["LIBS"]) - env.Tool("compilation_db") - env.Alias("compiledb", env.CompilationDatabase()) +SConscript("extension/deps/SCsub", "env") # For the reference: # - CCFLAGS are compilation flags shared between C and C++ @@ -59,20 +35,15 @@ if env["compiledb"]: # - CPPDEFINES are for pre-processor defines # - LINKFLAGS are for linking flags -ovsim_env = SConscript("extension/deps/openvic-simulation/SConstruct") - -env.Append(LIBPATH=ovsim_env.openvic_simulation["LIBPATH"]) -env.Append(LIBS=ovsim_env.openvic_simulation["LIBS"]) -env.Append(CPPPATH=ovsim_env.openvic_simulation["INCPATH"]) - # tweak this if you want to use different folders, or more folders, to store your source code in. -paths = ["extension/src/"] +paths = ["extension/src"] env.Append(CPPPATH=[[env.Dir(p) for p in paths]]) -sources = GlobRecursive("*.cpp", paths) +sources = env.GlobRecursive("*.cpp", paths) env.extension_sources = sources # Remove unassociated intermediate binary files if allowed, usually the result of a renamed or deleted source file if env["intermediate_delete"]: + from glob import glob def remove_extension(file : str): if file.find(".") == -1: return file return file[:file.rindex(".")] @@ -94,20 +65,20 @@ if env["intermediate_delete"]: if env["platform"] == "macos": library = env.SharedLibrary( - "game/bin/openvic/libopenvic.{}.{}.framework/libopenvic.{}.{}".format( - env["platform"], env["target"], env["platform"], env["target"] + BINDIR + "/openvic/libopenvic.{}.{}.framework/libopenvic.{}.{}".format( + godot_env["platform"], godot_env["target"], godot_env["platform"], godot_env["target"] ), source=sources, ) else: - suffix = ".{}.{}.{}".format(env["platform"], env["target"], env["arch"]) + suffix = ".{}.{}.{}".format(godot_env["platform"], godot_env["target"], godot_env["arch"]) library = env.SharedLibrary( - "game/bin/openvic/libopenvic{}{}".format(suffix, env["SHLIBSUFFIX"]), + BINDIR + "/openvic/libopenvic{}{}".format(suffix, godot_env["SHLIBSUFFIX"]), source=sources, ) if "env" in locals(): # FIXME: This method mixes both cosmetic progress stuff and cache handling... - show_progress(env) + env.show_progress(env) Default(library) diff --git a/extension/deps/SCsub b/extension/deps/SCsub new file mode 100644 index 0000000..25a3286 --- /dev/null +++ b/extension/deps/SCsub @@ -0,0 +1,12 @@ +#!/usr/bin/env python + +Import("env") + +def build_openvic_simulation(env): + ovsim_env = SConscript("openvic-simulation/SConstruct") + env.Append(LIBPATH=ovsim_env.openvic_simulation["LIBPATH"]) + env.Prepend(LIBS=ovsim_env.openvic_simulation["LIBS"]) + env.Append(CPPPATH=ovsim_env.openvic_simulation["INCPATH"]) + env.openvic_simulation = ovsim_env.openvic_simulation + +build_openvic_simulation(env)
\ No newline at end of file diff --git a/extension/deps/openvic-simulation b/extension/deps/openvic-simulation -Subproject 005a8026bb424779a146e00cc48621ff1d72b80 +Subproject b0b6264b83514be9f47f4e24b2e3bd8a02b33e9 diff --git a/scripts b/scripts new file mode 160000 +Subproject 925a38d4d8aef200823f50345dfa2570891454c diff --git a/scripts/build/cache.py b/scripts/build/cache.py deleted file mode 100644 index d48b0e0..0000000 --- a/scripts/build/cache.py +++ /dev/null @@ -1,127 +0,0 @@ -# Copied from https://github.com/godotengine/godot/blob/c3b0a92c3cd9a219c1b1776b48c147f1d0602f07/methods.py#L1049-L1172 -def show_progress(env): - import os - import sys - import glob - from SCons.Script import Progress, Command, AlwaysBuild - - screen = sys.stdout - # Progress reporting is not available in non-TTY environments since it - # messes with the output (for example, when writing to a file) - show_progress = env["progress"] and sys.stdout.isatty() - node_count = 0 - node_count_max = 0 - node_count_interval = 1 - node_count_fname = str(env.Dir("#")) + "/.scons_node_count" - - import time, math - - class cache_progress: - # The default is 1 GB cache and 12 hours half life - def __init__(self, path=None, limit=1073741824, half_life=43200): - self.path = path - self.limit = limit - self.exponent_scale = math.log(2) / half_life - if env["verbose"] and path != None: - screen.write( - "Current cache limit is {} (used: {})\n".format( - self.convert_size(limit), self.convert_size(self.get_size(path)) - ) - ) - self.delete(self.file_list()) - - def __call__(self, node, *args, **kw): - nonlocal node_count, node_count_max, node_count_interval, node_count_fname, show_progress - if show_progress: - # Print the progress percentage - node_count += node_count_interval - if node_count_max > 0 and node_count <= node_count_max: - screen.write("\r[%3d%%] " % (node_count * 100 / node_count_max)) - screen.flush() - elif node_count_max > 0 and node_count > node_count_max: - screen.write("\r[100%] ") - screen.flush() - else: - screen.write("\r[Initial build] ") - screen.flush() - - def delete(self, files): - if len(files) == 0: - return - if env["verbose"]: - # Utter something - screen.write("\rPurging %d %s from cache...\n" % (len(files), len(files) > 1 and "files" or "file")) - [os.remove(f) for f in files] - - def file_list(self): - if self.path is None: - # Nothing to do - return [] - # Gather a list of (filename, (size, atime)) within the - # cache directory - file_stat = [(x, os.stat(x)[6:8]) for x in glob.glob(os.path.join(self.path, "*", "*"))] - if file_stat == []: - # Nothing to do - return [] - # Weight the cache files by size (assumed to be roughly - # proportional to the recompilation time) times an exponential - # decay since the ctime, and return a list with the entries - # (filename, size, weight). - current_time = time.time() - file_stat = [(x[0], x[1][0], (current_time - x[1][1])) for x in file_stat] - # Sort by the most recently accessed files (most sensible to keep) first - file_stat.sort(key=lambda x: x[2]) - # Search for the first entry where the storage limit is - # reached - sum, mark = 0, None - for i, x in enumerate(file_stat): - sum += x[1] - if sum > self.limit: - mark = i - break - if mark is None: - return [] - else: - return [x[0] for x in file_stat[mark:]] - - def convert_size(self, size_bytes): - if size_bytes == 0: - return "0 bytes" - size_name = ("bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB") - i = int(math.floor(math.log(size_bytes, 1024))) - p = math.pow(1024, i) - s = round(size_bytes / p, 2) - return "%s %s" % (int(s) if i == 0 else s, size_name[i]) - - def get_size(self, start_path="."): - total_size = 0 - for dirpath, dirnames, filenames in os.walk(start_path): - for f in filenames: - fp = os.path.join(dirpath, f) - total_size += os.path.getsize(fp) - return total_size - - def progress_finish(target, source, env): - nonlocal node_count, progressor - try: - with open(node_count_fname, "w") as f: - f.write("%d\n" % node_count) - progressor.delete(progressor.file_list()) - except Exception: - pass - - try: - with open(node_count_fname) as f: - node_count_max = int(f.readline()) - except Exception: - pass - - cache_directory = os.environ.get("SCONS_CACHE") - # Simple cache pruning, attached to SCons' progress callback. Trim the - # cache directory to a size not larger than cache_limit. - cache_limit = float(os.getenv("SCONS_CACHE_LIMIT", 1024)) * 1024 * 1024 - progressor = cache_progress(cache_directory, cache_limit) - Progress(progressor, interval=node_count_interval) - - progress_finish_command = Command("progress_finish", [], progress_finish) - AlwaysBuild(progress_finish_command) diff --git a/scripts/build/glob_recursive.py b/scripts/build/glob_recursive.py deleted file mode 100644 index db6eb80..0000000 --- a/scripts/build/glob_recursive.py +++ /dev/null @@ -1,15 +0,0 @@ -def GlobRecursive(pattern, nodes=['.']): - import SCons - import glob - fs = SCons.Node.FS.get_default_fs() - Glob = fs.Glob - - results = [] - for node in nodes: - nnodes = [] - for f in Glob(str(node) + '/*', source=True): - if type(f) is SCons.Node.FS.Dir: - nnodes.append(f) - results += GlobRecursive(pattern, nnodes) - results += Glob(str(node) + '/' + pattern, source=True) - return results diff --git a/scripts/build/option_handler.py b/scripts/build/option_handler.py deleted file mode 100644 index 3cebc1a..0000000 --- a/scripts/build/option_handler.py +++ /dev/null @@ -1,39 +0,0 @@ -from typing import Tuple, Iterable -from SCons.Variables import Variables - -class OptionsClass: - def __init__(self, args): - self.opts = None - self.opt_list = [] - self.args = args - self.saved_args = args.copy() - - def Add(self, variableOrKey, *argv, **kwarg): - - self.opt_list.append([variableOrKey, argv, kwarg]) - # Neccessary to have our own build options without errors - if isinstance(variableOrKey, str): - self.args.pop(variableOrKey, True) - else: - self.args.pop(variableOrKey[0], True) - - def Make(self, customs : Iterable[str]): - self.args = self.saved_args - profile = self.args.get("profile", "") - if profile: - if os.path.isfile(profile): - customs.append(profile) - elif os.path.isfile(profile + ".py"): - customs.append(profile + ".py") - self.opts = Variables(customs, self.args) - for opt in self.opt_list: - if opt[1] == None and opt[2] == None: - self.opts.Add(opt[0]) - else: - self.opts.Add(opt[0], *opt[1], **opt[2]) - - def Finalize(self, env): - self.opts.Update(env) - - def GenerateHelpText(self, env): - return self.opts.GenerateHelpText(env) |