mirror of
https://github.com/acemod/ACE3.git
synced 2024-08-30 18:23:18 +00:00
a146be57f2
Should work on last release of mikero's tools (because that version of rapify struggles with some CBA macros) Runs config.cpp though cfgConvert twice to "demacro" config.cpp Then restores backup when finished
776 lines
24 KiB
Python
776 lines
24 KiB
Python
#!/usr/bin/env python
|
|
# vim: set fileencoding=utf-8 :
|
|
|
|
# make.py
|
|
# An Arma 3 addon build system
|
|
|
|
###############################################################################
|
|
|
|
# The MIT License (MIT)
|
|
|
|
# Copyright (c) 2013-2014 Ryan Schultz
|
|
|
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
# of this software and associated documentation files (the "Software"), to deal
|
|
# in the Software without restriction, including without limitation the rights
|
|
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
# copies of the Software, and to permit persons to whom the Software is
|
|
# furnished to do so, subject to the following conditions:
|
|
|
|
# The above copyright notice and this permission notice shall be included in
|
|
# all copies or substantial portions of the Software.
|
|
|
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
# THE SOFTWARE.
|
|
|
|
###############################################################################
|
|
|
|
__version__ = "0.3dev"
|
|
|
|
import sys
|
|
|
|
if sys.version_info[0] == 2:
|
|
print("Python 3 is required.")
|
|
sys.exit(1)
|
|
|
|
import os
|
|
import os.path
|
|
import shutil
|
|
import platform
|
|
import glob
|
|
import subprocess
|
|
import hashlib
|
|
import configparser
|
|
import json
|
|
import traceback
|
|
|
|
if sys.platform == "win32":
|
|
import winreg
|
|
|
|
###############################################################################
|
|
# http://akiscode.com/articles/sha-1directoryhash.shtml
|
|
# Copyright (c) 2009 Stephen Akiki
|
|
# MIT License (Means you can do whatever you want with this)
|
|
# See http://www.opensource.org/licenses/mit-license.php
|
|
# Error Codes:
|
|
# -1 -> Directory does not exist
|
|
# -2 -> General error (see stack traceback)
|
|
def get_directory_hash(directory):
|
|
directory_hash = hashlib.sha1()
|
|
if not os.path.exists (directory):
|
|
return -1
|
|
|
|
try:
|
|
for root, dirs, files in os.walk(directory):
|
|
for names in files:
|
|
path = os.path.join(root, names)
|
|
try:
|
|
f = open(path, 'rb')
|
|
except:
|
|
# You can't open the file for some reason
|
|
f.close()
|
|
continue
|
|
|
|
while 1:
|
|
# Read file in as little chunks
|
|
buf = f.read(4096)
|
|
if not buf: break
|
|
new = hashlib.sha1(buf)
|
|
directory_hash.update(new.digest())
|
|
f.close()
|
|
|
|
except:
|
|
# Print the stack traceback
|
|
traceback.print_exc()
|
|
return -2
|
|
|
|
return directory_hash.hexdigest()
|
|
|
|
# Copyright (c) André Burgaud
|
|
# http://www.burgaud.com/bring-colors-to-the-windows-console-with-python/
|
|
if sys.platform == "win32":
|
|
from ctypes import windll, Structure, c_short, c_ushort, byref
|
|
|
|
SHORT = c_short
|
|
WORD = c_ushort
|
|
|
|
class COORD(Structure):
|
|
"""struct in wincon.h."""
|
|
_fields_ = [
|
|
("X", SHORT),
|
|
("Y", SHORT)]
|
|
|
|
class SMALL_RECT(Structure):
|
|
"""struct in wincon.h."""
|
|
_fields_ = [
|
|
("Left", SHORT),
|
|
("Top", SHORT),
|
|
("Right", SHORT),
|
|
("Bottom", SHORT)]
|
|
|
|
class CONSOLE_SCREEN_BUFFER_INFO(Structure):
|
|
"""struct in wincon.h."""
|
|
_fields_ = [
|
|
("dwSize", COORD),
|
|
("dwCursorPosition", COORD),
|
|
("wAttributes", WORD),
|
|
("srWindow", SMALL_RECT),
|
|
("dwMaximumWindowSize", COORD)]
|
|
|
|
# winbase.h
|
|
STD_INPUT_HANDLE = -10
|
|
STD_OUTPUT_HANDLE = -11
|
|
STD_ERROR_HANDLE = -12
|
|
|
|
# wincon.h
|
|
FOREGROUND_BLACK = 0x0000
|
|
FOREGROUND_BLUE = 0x0001
|
|
FOREGROUND_GREEN = 0x0002
|
|
FOREGROUND_CYAN = 0x0003
|
|
FOREGROUND_RED = 0x0004
|
|
FOREGROUND_MAGENTA = 0x0005
|
|
FOREGROUND_YELLOW = 0x0006
|
|
FOREGROUND_GREY = 0x0007
|
|
FOREGROUND_INTENSITY = 0x0008 # foreground color is intensified.
|
|
|
|
BACKGROUND_BLACK = 0x0000
|
|
BACKGROUND_BLUE = 0x0010
|
|
BACKGROUND_GREEN = 0x0020
|
|
BACKGROUND_CYAN = 0x0030
|
|
BACKGROUND_RED = 0x0040
|
|
BACKGROUND_MAGENTA = 0x0050
|
|
BACKGROUND_YELLOW = 0x0060
|
|
BACKGROUND_GREY = 0x0070
|
|
BACKGROUND_INTENSITY = 0x0080 # background color is intensified.
|
|
|
|
stdout_handle = windll.kernel32.GetStdHandle(STD_OUTPUT_HANDLE)
|
|
SetConsoleTextAttribute = windll.kernel32.SetConsoleTextAttribute
|
|
GetConsoleScreenBufferInfo = windll.kernel32.GetConsoleScreenBufferInfo
|
|
|
|
def get_text_attr():
|
|
"""Returns the character attributes (colors) of the console screen
|
|
buffer."""
|
|
csbi = CONSOLE_SCREEN_BUFFER_INFO()
|
|
GetConsoleScreenBufferInfo(stdout_handle, byref(csbi))
|
|
return csbi.wAttributes
|
|
|
|
def set_text_attr(color):
|
|
"""Sets the character attributes (colors) of the console screen
|
|
buffer. Color is a combination of foreground and background color,
|
|
foreground and background intensity."""
|
|
SetConsoleTextAttribute(stdout_handle, color)
|
|
###############################################################################
|
|
|
|
def find_bi_tools(work_drive):
|
|
"""Find BI tools."""
|
|
|
|
reg = winreg.ConnectRegistry(None, winreg.HKEY_CURRENT_USER)
|
|
try:
|
|
k = winreg.OpenKey(reg, r"Software\bohemia interactive\arma 3 tools")
|
|
arma3tools_path = winreg.QueryValueEx(k, "path")[0]
|
|
winreg.CloseKey(k)
|
|
except:
|
|
raise Exception("BadTools","Arma 3 Tools are not installed correctly or the P: drive needs to be created.")
|
|
|
|
addonbuilder_path = os.path.join(arma3tools_path, "AddonBuilder", "AddonBuilder.exe")
|
|
dssignfile_path = os.path.join(arma3tools_path, "DSSignFile", "DSSignFile.exe")
|
|
dscreatekey_path = os.path.join(arma3tools_path, "DSSignFile", "DSCreateKey.exe")
|
|
|
|
if os.path.isfile(addonbuilder_path) and os.path.isfile(dssignfile_path) and os.path.isfile(dscreatekey_path):
|
|
return [addonbuilder_path, dssignfile_path, dscreatekey_path]
|
|
else:
|
|
raise Exception("BadTools","Arma 3 Tools are not installed correctly or the P: drive needs to be created.")
|
|
|
|
def find_depbo_tools():
|
|
"""Use registry entries to find DePBO-based tools."""
|
|
|
|
reg = winreg.ConnectRegistry(None, winreg.HKEY_CURRENT_USER)
|
|
try:
|
|
k = winreg.OpenKey(reg, r"Software\Mikero\pboProject")
|
|
try:
|
|
pboproject_path = winreg.QueryValueEx(k, "exe")[0]
|
|
winreg.CloseKey(k)
|
|
print("Found pboproject.")
|
|
except:
|
|
print_error("ERROR: Could not find pboProject.")
|
|
|
|
k = winreg.OpenKey(reg, r"Software\Mikero\rapify")
|
|
try:
|
|
rapify_path = winreg.QueryValueEx(k, "exe")[0]
|
|
winreg.CloseKey(k)
|
|
print("Found rapify.")
|
|
except:
|
|
print_error("Could not find rapify.")
|
|
|
|
k = winreg.OpenKey(reg, r"Software\Mikero\MakePbo")
|
|
try:
|
|
makepbo_path = winreg.QueryValueEx(k, "exe")[0]
|
|
winreg.CloseKey(k)
|
|
print("Found makepbo.")
|
|
except:
|
|
print_error("Could not find makepbo.")
|
|
except:
|
|
raise Exception("BadDePBO", "DePBO tools not installed correctly")
|
|
|
|
#Strip any quotations from the path due to a MikeRo tool bug which leaves a trailing space in some of its registry paths.
|
|
return [pboproject_path.strip('"'),rapify_path.strip('"'),makepbo_path.strip('"')]
|
|
|
|
def color(color):
|
|
"""Set the color. Works on Win32 and normal terminals."""
|
|
if sys.platform == "win32":
|
|
if color == "green":
|
|
set_text_attr(FOREGROUND_GREEN | get_text_attr() & 0x0070 | FOREGROUND_INTENSITY)
|
|
elif color == "red":
|
|
set_text_attr(FOREGROUND_RED | get_text_attr() & 0x0070 | FOREGROUND_INTENSITY)
|
|
elif color == "blue":
|
|
set_text_attr(FOREGROUND_BLUE | get_text_attr() & 0x0070 | FOREGROUND_INTENSITY)
|
|
elif color == "reset":
|
|
set_text_attr(FOREGROUND_GREY | get_text_attr() & 0x0070)
|
|
elif color == "grey":
|
|
set_text_attr(FOREGROUND_GREY | get_text_attr() & 0x0070)
|
|
else :
|
|
if color == "green":
|
|
sys.stdout.write('\033[92m')
|
|
elif color == "red":
|
|
sys.stdout.write('\033[91m')
|
|
elif color == "blue":
|
|
sys.stdout.write('\033[94m')
|
|
elif color == "reset":
|
|
sys.stdout.write('\033[0m')
|
|
|
|
def print_error(msg):
|
|
color("red")
|
|
print ("ERROR: " + msg)
|
|
color("reset")
|
|
|
|
def print_green(msg):
|
|
color("green")
|
|
print(msg)
|
|
color("reset")
|
|
|
|
def print_blue(msg):
|
|
color("blue")
|
|
print(msg)
|
|
color("reset")
|
|
|
|
def print_yellow(msg):
|
|
color("yellow")
|
|
print(msg)
|
|
color("reset")
|
|
|
|
###############################################################################
|
|
|
|
def main(argv):
|
|
"""Build an Arma addon suite in a directory from rules in a make.cfg file."""
|
|
print_blue(("\nmake.py for Arma, v" + __version__))
|
|
|
|
if sys.platform != "win32":
|
|
print_error("Non-Windows platform (Cygwin?). Please re-run from cmd.")
|
|
sys.exit(1)
|
|
|
|
reg = winreg.ConnectRegistry(None, winreg.HKEY_CURRENT_USER)
|
|
try:
|
|
k = winreg.OpenKey(reg, r"Software\bohemia interactive\arma 3 tools")
|
|
arma3tools_path = winreg.QueryValueEx(k, "path")[0]
|
|
winreg.CloseKey(k)
|
|
except:
|
|
raise Exception("BadTools","Arma 3 Tools are not installed correctly or the P: drive needs to be created.")
|
|
|
|
# Default behaviors
|
|
test = False # Copy to Arma 3 directory?
|
|
arg_modules = False # Only build modules on command line?
|
|
make_release = False # Make zip file from the release?
|
|
release_version = 0 # Version of release
|
|
use_pboproject = True # Default to pboProject build tool
|
|
make_target = "DEFAULT" # Which section in make.cfg to use for the build
|
|
new_key = False # Make a new key and use it to sign?
|
|
quiet = False # Suppress output from build tool?
|
|
|
|
# Parse arguments
|
|
if "help" in argv or "-h" in argv or "--help" in argv:
|
|
print ("""
|
|
make.py [help] [test] [force] [key <name>] [target <name>] [release <version>]
|
|
[module name] [module name] [...]
|
|
|
|
test -- Copy result to Arma 3.
|
|
release <version> -- Make archive with <version>.
|
|
force -- Ignore cache and build all.
|
|
target <name> -- Use rules in make.cfg under heading [<name>] rather than
|
|
default [Make]
|
|
key <name> -- Use key in working directory with <name> to sign. If it does not
|
|
exist, create key.
|
|
quiet -- Suppress command line output from build tool.
|
|
|
|
If module names are specified, only those modules will be built.
|
|
|
|
Examples:
|
|
make.py force test
|
|
Build all modules (ignoring cache) and copy the mod folder to the Arma 3
|
|
directory.
|
|
make.py mymodule_gun
|
|
Only build the module named 'mymodule_gun'.
|
|
make.py force key MyNewKey release 1.0
|
|
Build all modules (ignoring cache), sign them with NewKey, and pack them
|
|
into a zip file for release with version 1.0.
|
|
|
|
|
|
If a file called $NOBIN$ is found in the module directory, that module will not be binarized.
|
|
|
|
See the make.cfg file for additional build options.
|
|
""")
|
|
sys.exit(0)
|
|
|
|
if "force" in argv:
|
|
argv.remove("force")
|
|
force_build = True
|
|
else:
|
|
force_build = False
|
|
|
|
if "test" in argv:
|
|
test = True
|
|
argv.remove("test")
|
|
|
|
if "release" in argv:
|
|
make_release = True
|
|
release_version = argv[argv.index("release") + 1]
|
|
argv.remove(release_version)
|
|
argv.remove("release")
|
|
|
|
if "target" in argv:
|
|
make_target = argv[argv.index("target") + 1]
|
|
argv.remove("target")
|
|
argv.remove(make_target)
|
|
force_build = True
|
|
|
|
if "key" in argv:
|
|
new_key = True
|
|
key_name = argv[argv.index("key") + 1]
|
|
argv.remove("key")
|
|
argv.remove(key_name)
|
|
|
|
if "quiet" in argv:
|
|
quiet = True
|
|
argv.remove("quiet")
|
|
|
|
# Get the directory the make script is in.
|
|
make_root = os.path.dirname(os.path.realpath(__file__))
|
|
make_root_parent = os.path.abspath(os.path.join(os.getcwd(), os.pardir))
|
|
os.chdir(make_root)
|
|
|
|
cfg = configparser.ConfigParser();
|
|
try:
|
|
cfg.read(os.path.join(make_root, "make.cfg"))
|
|
|
|
# Project name (with @ symbol)
|
|
project = cfg.get(make_target, "project", fallback="@"+os.path.basename(os.getcwd()))
|
|
|
|
# Private key path
|
|
key = cfg.get(make_target, "key", fallback=None)
|
|
|
|
# Project prefix (folder path)
|
|
prefix = cfg.get(make_target, "prefix", fallback="")
|
|
|
|
# Should we autodetect modules on a complete build?
|
|
module_autodetect = cfg.getboolean(make_target, "module_autodetect", fallback=True)
|
|
|
|
# Manual list of modules to build for a complete build
|
|
modules = cfg.get(make_target, "modules", fallback=None)
|
|
# Parse it out
|
|
if modules:
|
|
modules = [x.strip() for x in modules.split(',')]
|
|
else:
|
|
modules = []
|
|
|
|
# List of directories to ignore when detecting
|
|
ignore = [x.strip() for x in cfg.get(make_target, "ignore", fallback="release").split(',')]
|
|
|
|
# BI Tools work drive on Windows
|
|
work_drive = cfg.get(make_target, "work_drive", fallback="P:\\")
|
|
|
|
# Which build tool should we use?
|
|
build_tool = "pboproject"
|
|
|
|
# Release/build directory, relative to script dir
|
|
release_dir = cfg.get(make_target, "release_dir", fallback="release")
|
|
|
|
# Project PBO file prefix (files are renamed to prefix_name.pbo)
|
|
pbo_name_prefix = cfg.get(make_target, "pbo_name_prefix", fallback=None)
|
|
|
|
# Project module Root
|
|
module_root_parent = os.path.abspath(os.path.join(os.path.join(work_drive, prefix), os.pardir))
|
|
module_root = cfg.get(make_target, "module_root", fallback=os.path.join(make_root_parent, "addons"))
|
|
print_green ("module_root: " + module_root)
|
|
if (os.path.isdir(module_root)):
|
|
os.chdir(module_root)
|
|
else:
|
|
print_error ("Directory " + module_root + " does not exist.")
|
|
sys.exit()
|
|
|
|
except:
|
|
raise
|
|
print_error("Could not parse make.cfg.")
|
|
sys.exit(1)
|
|
|
|
|
|
|
|
# See if we have been given specific modules to build from command line.
|
|
if len(argv) > 1 and not make_release:
|
|
arg_modules = True
|
|
modules = argv[1:]
|
|
|
|
# Find the tools we need.
|
|
try:
|
|
tools = find_bi_tools(work_drive)
|
|
addonbuilder = tools[0]
|
|
dssignfile = tools[1]
|
|
dscreatekey = tools[2]
|
|
|
|
except:
|
|
print_error("Arma 3 Tools are not installed correctly or the P: drive has not been created.")
|
|
sys.exit(1)
|
|
|
|
if build_tool == "pboproject":
|
|
try:
|
|
depbo_tools = find_depbo_tools()
|
|
pboproject = depbo_tools[0]
|
|
rapifyTool = depbo_tools[1]
|
|
makepboTool = depbo_tools[2]
|
|
except:
|
|
raise
|
|
print_error("Could not find dePBO tools. Download the needed tools from: https://dev.withsix.com/projects/mikero-pbodll/files")
|
|
sys.exit(1)
|
|
|
|
# Try to open and deserialize build cache file.
|
|
try:
|
|
cache = {}
|
|
with open(os.path.join(make_root, "make.cache"), 'r') as f:
|
|
cache_raw = f.read()
|
|
|
|
cache = json.loads(cache_raw)
|
|
|
|
except:
|
|
print ("No cache found.")
|
|
cache = {}
|
|
|
|
# Get list of subdirs in make root.
|
|
dirs = next(os.walk(module_root))[1]
|
|
|
|
# Autodetect what directories to build.
|
|
if module_autodetect and not arg_modules:
|
|
modules = []
|
|
for path in dirs:
|
|
# Any dir that has a config.cpp in its root is an addon to build.
|
|
config_path = os.path.join(path, 'config.cpp')
|
|
if os.path.isfile(config_path) and not path in ignore:
|
|
modules.append(path)
|
|
|
|
# Make the key specified from command line if necessary.
|
|
if new_key:
|
|
if not os.path.isfile(os.path.join(module_root, key_name + ".biprivatekey")):
|
|
print_green("\nRequested key does not exist.")
|
|
ret = subprocess.call([dscreatekey, key_name]) # Created in make_root
|
|
if ret == 0:
|
|
print_blue("Created: " + os.path.join(module_root, key_name + ".biprivatekey"))
|
|
else:
|
|
print_error("Failed to create key!")
|
|
|
|
try:
|
|
print_blue("Copying public key to release directory.")
|
|
|
|
try:
|
|
os.makedirs(os.path.join(module_root, release_dir, "Keys"))
|
|
except:
|
|
pass
|
|
|
|
shutil.copyfile(os.path.join(module_root, key_name + ".bikey"), os.path.join(module_root, release_dir, "Keys", key_name + ".bikey"))
|
|
|
|
except:
|
|
raise
|
|
print_error("Could not copy key to release directory.")
|
|
|
|
else:
|
|
print_green("\nNOTE: Using key " + os.path.join(module_root, key_name + ".biprivatekey"))
|
|
|
|
key = os.path.join(module_root, key_name + ".biprivatekey")
|
|
|
|
|
|
# For each module, prep files and then build.
|
|
for module in modules:
|
|
print_green("\nMaking " + module + "-"*max(1, (60-len(module))))
|
|
|
|
# Cache check
|
|
if module in cache:
|
|
old_sha = cache[module]
|
|
else:
|
|
old_sha = ""
|
|
|
|
# Hash the module
|
|
new_sha = get_directory_hash(os.path.join(module_root, module))
|
|
|
|
# Check if it needs rebuilt
|
|
# print ("Hash:", new_sha)
|
|
if old_sha == new_sha:
|
|
if not force_build:
|
|
print("Module has not changed.")
|
|
# Skip everything else
|
|
continue
|
|
|
|
# Only do this if the project isn't stored directly on the work drive.
|
|
# Split the path at the drive name and see if they are on the same drive (usually P:)
|
|
if os.path.splitdrive(module_root)[0] != os.path.splitdrive(work_drive)[0]:
|
|
try:
|
|
# Remove old work drive version (ignore errors)
|
|
shutil.rmtree(os.path.join(work_drive, prefix, module), True)
|
|
|
|
# Copy module to the work drive
|
|
shutil.copytree(module, os.path.join(work_drive, prefix, module))
|
|
|
|
except:
|
|
raise
|
|
print_error("ERROR: Could not copy module to work drive. Does the module exist?")
|
|
input("Press Enter to continue...")
|
|
print("Resuming build...")
|
|
continue
|
|
else:
|
|
print("WARNING: Module is stored on work drive (" + work_drive + ").")
|
|
|
|
try:
|
|
# Remove the old pbo, key, and log
|
|
old = os.path.join(module_root, release_dir, project, "Addons", module) + "*"
|
|
files = glob.glob(old)
|
|
for f in files:
|
|
os.remove(f)
|
|
|
|
if pbo_name_prefix:
|
|
old = os.path.join(module_root, release_dir, project, "Addons", pbo_name_prefix+module) + "*"
|
|
files = glob.glob(old)
|
|
for f in files:
|
|
os.remove(f)
|
|
except:
|
|
raise
|
|
print_error("ERROR: Could not copy module to work drive. Does the module exist?")
|
|
input("Press Enter to continue...")
|
|
print("Resuming build...")
|
|
continue
|
|
|
|
# Build the module into a pbo
|
|
print_blue("Building: " + os.path.join(work_drive, prefix, module))
|
|
print_blue("Destination: " + os.path.join(module_root, release_dir, project, "Addons"))
|
|
|
|
# Make destination folder (if needed)
|
|
try:
|
|
os.makedirs(os.path.join(module_root, release_dir, project, "Addons"))
|
|
except:
|
|
pass
|
|
|
|
# Run build tool
|
|
build_successful = False
|
|
if build_tool == "pboproject":
|
|
try:
|
|
#PABST: Convert config (run the macro'd config.cpp through CfgConvert twice to produce a de-macro'd cpp that pboProject can read without fucking up:
|
|
os.chdir("P:\\CfgConvert")
|
|
shutil.copyfile(os.path.join(work_drive, prefix, module, "config.cpp"), os.path.join(work_drive, prefix, module, "config.backup"))
|
|
print_green("\Pabst (double converting):" + "cfgConvertGUI.exe " + os.path.join(work_drive, prefix, module, "config.cpp"))
|
|
ret = subprocess.call(["cfgConvertGUI.exe", os.path.join(work_drive, prefix, module, "config.cpp")])
|
|
ret = subprocess.call(["cfgConvertGUI.exe", os.path.join(work_drive, prefix, module, "config.bin")])
|
|
|
|
# Call pboProject
|
|
os.chdir("P:\\")
|
|
|
|
if os.path.isfile(os.path.join(work_drive, prefix, module, "$NOBIN$")):
|
|
print_green("$NOBIN$ Found. Proceeding with non-binarizing!")
|
|
cmd = [makepboTool, "-P","-A","-L","-N","-G", os.path.join(work_drive, prefix, module),os.path.join(module_root, release_dir, project,"Addons")]
|
|
|
|
else:
|
|
cmd = [pboproject, "-P", os.path.join(work_drive, prefix, module), "+Engine=Arma3", "-S","+Noisy", "+X", "+Clean", "+Mod="+os.path.join(module_root, release_dir, project), "-Key"]
|
|
|
|
color("grey")
|
|
if quiet:
|
|
devnull = open(os.devnull, 'w')
|
|
ret = subprocess.call(cmd, stdout=devnull)
|
|
devnull.close()
|
|
else:
|
|
ret = subprocess.call(cmd)
|
|
color("reset")
|
|
|
|
if ret == 0:
|
|
print_green("pboProject return code == " + str(ret))
|
|
# Prettyprefix rename the PBO if requested.
|
|
if pbo_name_prefix:
|
|
try:
|
|
os.rename(os.path.join(module_root, release_dir, project, "Addons", module+".pbo"), os.path.join(module_root, release_dir, project, "Addons", pbo_name_prefix+module+".pbo"))
|
|
except:
|
|
raise
|
|
print_error("Could not rename built PBO with prefix.")
|
|
# Sign result
|
|
if key:
|
|
print("Signing with " + key + ".")
|
|
if pbo_name_prefix:
|
|
ret = subprocess.call([dssignfile, key, os.path.join(module_root, release_dir, project, "Addons", pbo_name_prefix + module + ".pbo")])
|
|
else:
|
|
ret = subprocess.call([dssignfile, key, os.path.join(module_root, release_dir, project, "Addons", module + ".pbo")])
|
|
|
|
if ret == 0:
|
|
build_successful = True
|
|
else:
|
|
build_successful = True
|
|
|
|
if not build_successful:
|
|
print_error("pboProject return code == " + str(ret))
|
|
print_error("Module not successfully built/signed.")
|
|
#input("Press Enter to continue...")
|
|
print ("Resuming build...")
|
|
continue
|
|
|
|
#PABST: cleanup config BS (you could comment this out to see the "de-macroed" cpp
|
|
print_green("\Pabst (restoring): " + os.path.join(work_drive, prefix, module, "config.cpp"))
|
|
os.remove(os.path.join(work_drive, prefix, module, "config.cpp"))
|
|
os.remove(os.path.join(work_drive, prefix, module, "config.bin"))
|
|
os.rename(os.path.join(work_drive, prefix, module, "config.backup"), os.path.join(work_drive, prefix, module, "config.cpp"))
|
|
|
|
# Back to the root
|
|
os.chdir(module_root)
|
|
|
|
except:
|
|
raise
|
|
print_error("Could not run Addon Builder.")
|
|
input("Press Enter to continue...")
|
|
print ("Resuming build...")
|
|
continue
|
|
|
|
elif build_tool== "addonbuilder":
|
|
# Detect $NOBIN$ and do not binarize if found.
|
|
if os.path.isfile(os.path.join(work_drive, prefix, module, "$NOBIN$")):
|
|
do_binarize = False
|
|
print("$NOBIN$ file found in module, packing only.")
|
|
else:
|
|
do_binarize = True
|
|
try:
|
|
# Call AddonBuilder
|
|
os.chdir("P:\\")
|
|
|
|
cmd = [addonbuilder, os.path.join(work_drive, prefix, module), os.path.join(make_root, release_dir, project, "Addons"), "-clear", "-project="+work_drive]
|
|
if not do_binarize:
|
|
cmd.append("-packonly")
|
|
|
|
if quiet:
|
|
previousDirectory = os.getcwd()
|
|
os.chdir(arma3tools_path)
|
|
devnull = open(os.devnull, 'w')
|
|
ret = subprocess.call(cmd, stdout=devnull)
|
|
devnull.close()
|
|
os.chdir(previousDirectory)
|
|
else:
|
|
previousDirectory = os.getcwd()
|
|
os.chdir(arma3tools_path)
|
|
print_error("Current directory - " + os.getcwd())
|
|
ret = subprocess.call(cmd)
|
|
os.chdir(previousDirectory)
|
|
print_error("Current directory - " + os.getcwd())
|
|
color("reset")
|
|
print_green("completed")
|
|
# Prettyprefix rename the PBO if requested.
|
|
if pbo_name_prefix:
|
|
try:
|
|
os.rename(os.path.join(make_root, release_dir, project, "Addons", module+".pbo"), os.path.join(make_root, release_dir, project, "Addons", pbo_name_prefix+module+".pbo"))
|
|
except:
|
|
raise
|
|
print_error("Could not rename built PBO with prefix.")
|
|
|
|
if ret == 0:
|
|
# Sign result
|
|
if key:
|
|
print("Signing with " + key + ".")
|
|
if pbo_name_prefix:
|
|
ret = subprocess.call([dssignfile, key, os.path.join(make_root, release_dir, project, "Addons", pbo_name_prefix + module + ".pbo")])
|
|
else:
|
|
ret = subprocess.call([dssignfile, key, os.path.join(make_root, release_dir, project, "Addons", module + ".pbo")])
|
|
|
|
if ret == 0:
|
|
build_successful = True
|
|
else:
|
|
build_successful = True
|
|
|
|
if not build_successful:
|
|
print_error("Module not successfully built.")
|
|
|
|
# Back to the root
|
|
os.chdir(make_root)
|
|
|
|
except:
|
|
raise
|
|
print_error("Could not run Addon Builder.")
|
|
input("Press Enter to continue...")
|
|
print ("Resuming build...")
|
|
continue
|
|
|
|
else:
|
|
print_error("Unknown build_tool " + build_tool + "!")
|
|
|
|
# Update the hash for a successfully built module
|
|
if build_successful:
|
|
cache[module] = new_sha
|
|
|
|
# Done building all modules!
|
|
|
|
# Write out the cache state
|
|
cache_out = json.dumps(cache)
|
|
with open(os.path.join(make_root, "make.cache"), 'w') as f:
|
|
f.write(cache_out)
|
|
|
|
# Delete the pboproject temp files if building a release.
|
|
if make_release and build_tool == "pboproject":
|
|
try:
|
|
shutil.rmtree(os.path.join(module_root, release_dir, project, "temp"), True)
|
|
except:
|
|
print_error("ERROR: Could not delete pboProject temp files.")
|
|
|
|
print_green("\nDone.")
|
|
|
|
# Make release
|
|
if make_release:
|
|
print_blue("\nMaking release: " + project + "-" + release_version + ".zip")
|
|
|
|
try:
|
|
# Delete all log files
|
|
for root, dirs, files in os.walk(os.path.join(module_root, release_dir, project, "Addons")):
|
|
for currentFile in files:
|
|
if currentFile.lower().endswith("log"):
|
|
os.remove(os.path.join(root, currentFile))
|
|
|
|
# Create a zip with the contents of release/ in it
|
|
shutil.make_archive(project + "-" + release_version, "zip", os.path.join(module_root, release_dir))
|
|
except:
|
|
raise
|
|
print_error("Could not make release.")
|
|
|
|
# Copy to Arma 3 folder for testing
|
|
if test:
|
|
print_blue("\nCopying to Arma 3.")
|
|
|
|
if sys.platform == "win32":
|
|
reg = winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE)
|
|
try:
|
|
k = winreg.OpenKey(reg, r"SOFTWARE\Wow6432Node\Bohemia Interactive\Arma 3")
|
|
a3_path = winreg.EnumValue(k, 1)[1]
|
|
winreg.CloseKey(k)
|
|
except:
|
|
print_error("Could not find Arma 3's directory in the registry.")
|
|
else:
|
|
a3_path = cygwin_a3path
|
|
|
|
if os.path.exists(a3_path):
|
|
try:
|
|
shutil.rmtree(os.path.join(a3_path, project), True)
|
|
shutil.copytree(os.path.join(module_root, release_dir, project), os.path.join(a3_path, project))
|
|
except:
|
|
print_error("Could not copy files. Is Arma 3 running?")
|
|
|
|
if __name__ == "__main__":
|
|
main(sys.argv)
|
|
input("Press Enter to continue...") |