2023-01-26 08:13:07 +08:00
|
|
|
#! /usr/bin/env python
|
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
#
|
|
|
|
# This file is part of npbackup
|
|
|
|
|
|
|
|
__intname__ = "npbackup.compile-and-package-for-windows"
|
|
|
|
__author__ = "Orsiris de Jong"
|
|
|
|
__copyright__ = "Copyright (C) 2023 NetInvent"
|
|
|
|
__license__ = "GPL-3.0-only"
|
2023-02-01 04:03:32 +08:00
|
|
|
__build__ = "2023013101"
|
|
|
|
__version__ = "1.5.0"
|
2023-01-26 08:13:07 +08:00
|
|
|
|
|
|
|
|
|
|
|
import sys
|
|
|
|
import os
|
2023-02-01 04:03:32 +08:00
|
|
|
import argparse
|
2023-02-01 08:28:25 +08:00
|
|
|
import atexit
|
2023-01-26 08:13:07 +08:00
|
|
|
from command_runner import command_runner
|
2023-01-29 01:07:32 +08:00
|
|
|
|
2023-02-01 08:51:15 +08:00
|
|
|
ARCHES = ["x86", "x64"]
|
|
|
|
AUDIENCES = ["public", "private"]
|
2023-02-01 04:03:32 +08:00
|
|
|
|
2023-01-29 01:07:32 +08:00
|
|
|
# Insert parent dir as path se we get to use npbackup as package
|
|
|
|
sys.path.insert(0, os.path.normpath(os.path.join(os.path.dirname(__file__), "..")))
|
|
|
|
|
2023-01-30 19:35:03 +08:00
|
|
|
from npbackup.__main__ import __version__ as npbackup_version
|
2023-01-29 01:07:32 +08:00
|
|
|
from bin.NPBackupInstaller import __version__ as installer_version
|
2023-01-27 18:30:06 +08:00
|
|
|
from npbackup.customization import (
|
2023-01-26 08:26:08 +08:00
|
|
|
COMPANY_NAME,
|
|
|
|
TRADEMARKS,
|
|
|
|
PRODUCT_NAME,
|
|
|
|
FILE_DESCRIPTION,
|
|
|
|
COPYRIGHT,
|
|
|
|
LICENSE_FILE,
|
|
|
|
)
|
2023-01-27 18:34:05 +08:00
|
|
|
from npbackup.core.restic_source_binary import get_restic_internal_binary
|
|
|
|
from npbackup.path_helper import BASEDIR
|
2023-02-01 04:03:32 +08:00
|
|
|
import glob
|
2023-01-26 08:13:07 +08:00
|
|
|
|
2023-01-29 01:07:32 +08:00
|
|
|
del sys.path[0]
|
2023-01-26 08:13:07 +08:00
|
|
|
|
2023-02-01 08:51:15 +08:00
|
|
|
|
2023-02-01 04:03:32 +08:00
|
|
|
def check_private_build(audience):
|
2023-01-26 08:13:07 +08:00
|
|
|
private = False
|
|
|
|
try:
|
2023-01-29 01:07:32 +08:00
|
|
|
import npbackup._private_secret_keys
|
2023-01-26 08:26:08 +08:00
|
|
|
|
2023-01-26 08:13:07 +08:00
|
|
|
print("WARNING: Building with private secret key")
|
|
|
|
private = True
|
|
|
|
except ImportError:
|
|
|
|
try:
|
2023-01-29 01:07:32 +08:00
|
|
|
import npbackup.secret_keys
|
2023-01-26 08:26:08 +08:00
|
|
|
|
2023-01-26 08:13:07 +08:00
|
|
|
print("Building with default secret key")
|
|
|
|
except ImportError:
|
|
|
|
print("Cannot find secret keys")
|
|
|
|
sys.exit()
|
2023-01-26 08:26:08 +08:00
|
|
|
|
2023-02-01 04:03:32 +08:00
|
|
|
dist_conf_file_path = get_conf_dist_file(audience)
|
2023-01-26 08:26:08 +08:00
|
|
|
if "_private" in dist_conf_file_path:
|
|
|
|
print("WARNING: Building with a private conf.dist file")
|
2023-01-26 08:13:07 +08:00
|
|
|
private = True
|
2023-01-26 08:26:08 +08:00
|
|
|
|
2023-01-26 08:13:07 +08:00
|
|
|
return private
|
|
|
|
|
2023-01-26 08:26:08 +08:00
|
|
|
|
2023-02-01 04:03:32 +08:00
|
|
|
def move_audience_files(audience):
|
2023-02-01 08:51:15 +08:00
|
|
|
for dir in [os.path.join(BASEDIR, os.pardir, "examples"), BASEDIR]:
|
|
|
|
if audience == "private":
|
|
|
|
possible_non_used_path = "_NOUSE_private_"
|
|
|
|
guessed_files = glob.glob(
|
|
|
|
os.path.join(dir, "{}*".format(possible_non_used_path))
|
|
|
|
)
|
2023-02-01 04:03:32 +08:00
|
|
|
for file in guessed_files:
|
2023-02-01 08:28:25 +08:00
|
|
|
os.rename(file, file.replace(possible_non_used_path, "_private_"))
|
2023-02-01 08:51:15 +08:00
|
|
|
elif audience == "public":
|
|
|
|
possible_non_used_path = "_private_"
|
|
|
|
guessed_files = glob.glob(
|
|
|
|
os.path.join(dir, "{}*".format(possible_non_used_path))
|
|
|
|
)
|
2023-02-01 04:03:32 +08:00
|
|
|
for file in guessed_files:
|
2023-02-01 08:51:15 +08:00
|
|
|
os.rename(
|
|
|
|
file,
|
|
|
|
file.replace(
|
|
|
|
possible_non_used_path,
|
|
|
|
"_NOUSE{}".format(possible_non_used_path),
|
|
|
|
),
|
|
|
|
)
|
2023-01-26 08:26:08 +08:00
|
|
|
|
2023-02-01 04:03:32 +08:00
|
|
|
|
|
|
|
def get_conf_dist_file(audience):
|
2023-02-01 08:51:15 +08:00
|
|
|
if audience == "private":
|
2023-02-01 04:03:32 +08:00
|
|
|
file = "_private_npbackup.conf.dist"
|
|
|
|
else:
|
|
|
|
file = "npbackup.conf.dist"
|
|
|
|
dist_conf_file_path = os.path.join(BASEDIR, os.pardir, "examples", file)
|
2023-02-01 08:51:15 +08:00
|
|
|
return dist_conf_file_path
|
2023-01-26 08:13:07 +08:00
|
|
|
|
|
|
|
|
2023-01-29 01:07:32 +08:00
|
|
|
def have_nuitka_commercial():
|
|
|
|
try:
|
|
|
|
import nuitka.plugins.commercial
|
2023-02-01 08:51:15 +08:00
|
|
|
|
2023-01-29 01:07:32 +08:00
|
|
|
print("Running with nuitka commercial")
|
|
|
|
return True
|
|
|
|
except ImportError:
|
|
|
|
print("Running with nuitka open source")
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
2023-02-01 04:03:32 +08:00
|
|
|
def compile(arch, audience):
|
2023-01-29 01:07:32 +08:00
|
|
|
if os.name == "nt":
|
|
|
|
program_executable = "npbackup.exe"
|
|
|
|
restic_executable = "restic.exe"
|
2023-02-01 04:03:32 +08:00
|
|
|
platform = "windows"
|
2023-01-29 01:07:32 +08:00
|
|
|
else:
|
|
|
|
program_executable = "npbackup"
|
|
|
|
restic_executable = "restic"
|
2023-02-01 04:03:32 +08:00
|
|
|
platform = "linux"
|
2023-01-29 01:07:32 +08:00
|
|
|
|
2023-02-01 08:51:15 +08:00
|
|
|
PACKAGE_DIR = "npbackup"
|
2023-01-29 01:07:32 +08:00
|
|
|
|
2023-02-01 04:03:32 +08:00
|
|
|
check_private_build(audience)
|
2023-02-01 06:39:09 +08:00
|
|
|
BUILDS_DIR = os.path.abspath(os.path.join(BASEDIR, os.pardir, "BUILDS"))
|
|
|
|
OUTPUT_DIR = os.path.join(BUILDS_DIR, audience, platform, arch)
|
2023-01-26 08:13:07 +08:00
|
|
|
|
|
|
|
if not os.path.isdir(OUTPUT_DIR):
|
|
|
|
os.makedirs(OUTPUT_DIR)
|
|
|
|
|
2023-01-26 08:26:08 +08:00
|
|
|
PYTHON_EXECUTABLE = sys.executable
|
2023-01-26 08:13:07 +08:00
|
|
|
|
|
|
|
# npbackup compilation
|
|
|
|
# Strip possible version suffixes '-dev'
|
2023-01-26 08:26:08 +08:00
|
|
|
_npbackup_version = npbackup_version.split("-")[0]
|
|
|
|
PRODUCT_VERSION = _npbackup_version + ".0"
|
|
|
|
FILE_VERSION = _npbackup_version + ".0"
|
2023-01-26 08:13:07 +08:00
|
|
|
|
2023-01-27 18:42:05 +08:00
|
|
|
file_description = "{} P{}-{}{}".format(
|
2023-02-01 08:51:15 +08:00
|
|
|
FILE_DESCRIPTION,
|
|
|
|
sys.version_info[1],
|
|
|
|
arch,
|
|
|
|
"priv" if audience == "private" else "",
|
2023-01-27 18:42:05 +08:00
|
|
|
)
|
2023-01-26 08:13:07 +08:00
|
|
|
|
|
|
|
restic_source_file = get_restic_internal_binary(arch)
|
|
|
|
if not restic_source_file:
|
2023-01-26 08:26:08 +08:00
|
|
|
print("Cannot find restic source file.")
|
2023-01-26 08:13:07 +08:00
|
|
|
return
|
2023-01-29 01:07:32 +08:00
|
|
|
restic_dest_file = os.path.join(PACKAGE_DIR, restic_executable)
|
|
|
|
|
2023-01-26 08:26:08 +08:00
|
|
|
translations_dir = "translations"
|
2023-01-29 01:07:32 +08:00
|
|
|
translations_dir_source = os.path.join(BASEDIR, translations_dir)
|
|
|
|
translations_dir_dest = os.path.join(PACKAGE_DIR, translations_dir)
|
2023-01-26 08:13:07 +08:00
|
|
|
|
2023-01-29 01:07:32 +08:00
|
|
|
license_dest_file = os.path.join(PACKAGE_DIR, os.path.basename(LICENSE_FILE))
|
2023-01-26 08:13:07 +08:00
|
|
|
|
2023-02-01 08:51:15 +08:00
|
|
|
icon_file = os.path.join(PACKAGE_DIR, "npbackup_icon.ico")
|
2023-01-29 01:07:32 +08:00
|
|
|
|
|
|
|
# Installer specific files, no need for a npbackup package directory here
|
2023-01-29 20:36:31 +08:00
|
|
|
|
2023-02-01 04:03:32 +08:00
|
|
|
program_executable_path = os.path.join(OUTPUT_DIR, program_executable)
|
2023-01-29 20:36:31 +08:00
|
|
|
|
2023-02-01 04:03:32 +08:00
|
|
|
dist_conf_file_source = get_conf_dist_file(audience)
|
2023-02-01 08:51:15 +08:00
|
|
|
dist_conf_file_dest = os.path.basename(
|
|
|
|
dist_conf_file_source.replace("_private_", "")
|
|
|
|
)
|
2023-01-26 08:13:07 +08:00
|
|
|
|
2023-01-29 01:07:32 +08:00
|
|
|
excludes_dir = "excludes"
|
2023-01-29 01:40:16 +08:00
|
|
|
excludes_dir_source = os.path.join(BASEDIR, os.pardir, excludes_dir)
|
2023-01-29 01:07:32 +08:00
|
|
|
excludes_dir_dest = excludes_dir
|
2023-01-29 20:36:31 +08:00
|
|
|
|
2023-02-01 08:51:15 +08:00
|
|
|
NUITKA_OPTIONS = "--enable-plugin=data-hiding" if have_nuitka_commercial() else ""
|
2023-01-29 20:36:31 +08:00
|
|
|
|
2023-01-26 08:26:08 +08:00
|
|
|
EXE_OPTIONS = '--company-name="{}" --product-name="{}" --file-version="{}" --product-version="{}" --copyright="{}" --file-description="{}" --trademarks="{}"'.format(
|
|
|
|
COMPANY_NAME,
|
|
|
|
PRODUCT_NAME,
|
|
|
|
FILE_VERSION,
|
|
|
|
PRODUCT_VERSION,
|
|
|
|
COPYRIGHT,
|
|
|
|
file_description,
|
|
|
|
TRADEMARKS,
|
|
|
|
)
|
2023-01-29 01:07:32 +08:00
|
|
|
|
|
|
|
CMD = '{} -m nuitka --python-flag=no_docstrings --python-flag=-O {} {} --onefile --plugin-enable=tk-inter --include-data-dir="{}"="{}" --include-data-file="{}"="{}" --include-data-file="{}"="{}" --windows-icon-from-ico="{}" --output-dir="{}" bin/npbackup'.format(
|
2023-01-26 08:26:08 +08:00
|
|
|
PYTHON_EXECUTABLE,
|
2023-01-29 01:07:32 +08:00
|
|
|
NUITKA_OPTIONS,
|
|
|
|
EXE_OPTIONS,
|
|
|
|
translations_dir_source,
|
|
|
|
translations_dir_dest,
|
2023-01-26 08:26:08 +08:00
|
|
|
LICENSE_FILE,
|
2023-01-29 01:07:32 +08:00
|
|
|
license_dest_file,
|
2023-01-26 08:26:08 +08:00
|
|
|
restic_source_file,
|
2023-01-29 01:07:32 +08:00
|
|
|
restic_dest_file,
|
|
|
|
icon_file,
|
2023-02-01 04:03:32 +08:00
|
|
|
OUTPUT_DIR,
|
2023-01-26 08:26:08 +08:00
|
|
|
)
|
2023-01-26 08:13:07 +08:00
|
|
|
|
|
|
|
print(CMD)
|
|
|
|
errors = False
|
|
|
|
exit_code, output = command_runner(CMD, timeout=0, live_output=True)
|
|
|
|
if exit_code != 0:
|
|
|
|
errors = True
|
|
|
|
|
|
|
|
# installer compilation
|
2023-01-26 08:26:08 +08:00
|
|
|
_installer_version = installer_version.split("-")[0]
|
|
|
|
PRODUCT_VERSION = _installer_version + ".0"
|
|
|
|
FILE_VERSION = _installer_version + ".0"
|
|
|
|
EXE_OPTIONS = '--company-name="{}" --product-name="{}" --file-version="{}" --product-version="{}" --copyright="{}" --file-description="{}" --trademarks="{}"'.format(
|
|
|
|
COMPANY_NAME,
|
|
|
|
PRODUCT_NAME,
|
|
|
|
FILE_VERSION,
|
|
|
|
PRODUCT_VERSION,
|
|
|
|
COPYRIGHT,
|
|
|
|
file_description,
|
|
|
|
TRADEMARKS,
|
|
|
|
)
|
2023-01-29 01:07:32 +08:00
|
|
|
CMD = '{} -m nuitka --python-flag=no_docstrings --python-flag=-O {} {} --onefile --plugin-enable=tk-inter --include-data-file="{}"="{}" --include-data-file="{}"="{}" --include-data-dir="{}"="{}" --windows-icon-from-ico="{}" --windows-uac-admin --output-dir="{}" bin/NPBackupInstaller.py'.format(
|
2023-01-26 08:26:08 +08:00
|
|
|
PYTHON_EXECUTABLE,
|
2023-02-01 08:51:15 +08:00
|
|
|
NUITKA_OPTIONS,
|
2023-01-29 01:07:32 +08:00
|
|
|
EXE_OPTIONS,
|
2023-01-26 08:26:08 +08:00
|
|
|
program_executable_path,
|
|
|
|
program_executable,
|
2023-01-29 01:07:32 +08:00
|
|
|
dist_conf_file_source,
|
|
|
|
dist_conf_file_dest,
|
|
|
|
excludes_dir_source,
|
|
|
|
excludes_dir_dest,
|
|
|
|
icon_file,
|
2023-02-01 04:03:32 +08:00
|
|
|
OUTPUT_DIR,
|
2023-01-26 08:26:08 +08:00
|
|
|
)
|
2023-01-26 08:13:07 +08:00
|
|
|
|
|
|
|
print(CMD)
|
|
|
|
exit_code, output = command_runner(CMD, timeout=0, live_output=True)
|
|
|
|
if exit_code != 0:
|
|
|
|
errors = True
|
2023-02-01 06:39:09 +08:00
|
|
|
else:
|
|
|
|
## Create version file
|
2023-02-01 08:51:15 +08:00
|
|
|
with open(os.path.join(BUILDS_DIR, audience, "VERSION"), "w") as fh:
|
2023-02-01 06:39:09 +08:00
|
|
|
fh.write(npbackup_version)
|
2023-01-26 08:13:07 +08:00
|
|
|
|
2023-01-29 01:07:32 +08:00
|
|
|
print("COMPILE ERRORS", errors)
|
2023-01-26 08:13:07 +08:00
|
|
|
|
2023-01-26 08:26:08 +08:00
|
|
|
|
2023-02-01 04:03:32 +08:00
|
|
|
class ArchAction(argparse.Action):
|
|
|
|
def __call__(self, parser, namespace, values, option_string=None):
|
|
|
|
if values not in ARCHES:
|
|
|
|
print("Got value:", values)
|
|
|
|
raise argparse.ArgumentError(self, "Not a valid arch")
|
|
|
|
setattr(namespace, self.dest, values)
|
|
|
|
|
|
|
|
|
|
|
|
class AudienceAction(argparse.Action):
|
|
|
|
def __call__(self, parser, namespace, values, option_string=None):
|
2023-02-01 08:51:15 +08:00
|
|
|
if values not in AUDIENCES + ["all"]:
|
2023-02-01 04:03:32 +08:00
|
|
|
print("Got value:", values)
|
|
|
|
raise argparse.ArgumentError(self, "Not a valid audience")
|
2023-02-01 08:51:15 +08:00
|
|
|
setattr(namespace, self.dest, values)
|
2023-02-01 04:03:32 +08:00
|
|
|
|
|
|
|
|
2023-01-26 08:13:07 +08:00
|
|
|
if __name__ == "__main__":
|
2023-02-01 04:03:32 +08:00
|
|
|
parser = argparse.ArgumentParser(
|
2023-02-01 08:51:15 +08:00
|
|
|
prog="npbackup compile.py", description="Compiler script for NPBackup"
|
2023-02-01 04:03:32 +08:00
|
|
|
)
|
|
|
|
|
|
|
|
parser.add_argument(
|
2023-02-01 08:51:15 +08:00
|
|
|
"--arch",
|
|
|
|
type=str,
|
|
|
|
dest="arch",
|
|
|
|
default=None,
|
|
|
|
required=True,
|
|
|
|
action=ArchAction,
|
|
|
|
help="Target arch, x64 or x86",
|
2023-02-01 04:03:32 +08:00
|
|
|
)
|
|
|
|
|
|
|
|
parser.add_argument(
|
|
|
|
"--audience",
|
|
|
|
type=str,
|
|
|
|
dest="audience",
|
2023-02-01 08:51:15 +08:00
|
|
|
default="private",
|
2023-02-01 04:03:32 +08:00
|
|
|
required=False,
|
|
|
|
help="Target audience, private or public",
|
|
|
|
)
|
|
|
|
|
|
|
|
args = parser.parse_args()
|
2023-02-01 08:28:25 +08:00
|
|
|
|
|
|
|
# Make sure we get out dev environment back when compilation ends / fails
|
2023-02-01 08:51:15 +08:00
|
|
|
atexit.register(
|
|
|
|
move_audience_files,
|
|
|
|
"private",
|
|
|
|
)
|
2023-02-01 08:28:25 +08:00
|
|
|
try:
|
2023-02-01 08:51:15 +08:00
|
|
|
if args.audience.lower() == "all":
|
2023-02-01 08:28:25 +08:00
|
|
|
audiences = AUDIENCES
|
|
|
|
else:
|
|
|
|
audiences = [args.audience]
|
2023-02-01 08:51:15 +08:00
|
|
|
|
2023-02-01 08:28:25 +08:00
|
|
|
for audience in audiences:
|
|
|
|
move_audience_files(audience)
|
|
|
|
compile(arch=args.arch, audience=audience)
|
|
|
|
check_private_build(audience)
|
|
|
|
except Exception:
|
|
|
|
print("COMPILATION FAILED")
|