Browse Source
* Build binary release for each commit and pull request * Codesign macOS releasepull/1718/head
committed by
GitHub
20 changed files with 1923 additions and 4 deletions
@ -0,0 +1,76 @@ |
|||||
|
name: Build binaries and source distribution |
||||
|
|
||||
|
on: [push, pull_request] |
||||
|
|
||||
|
jobs: |
||||
|
build_windows: |
||||
|
name: Build ${{ matrix.name }} binary |
||||
|
runs-on: ${{ matrix.os }} |
||||
|
strategy: |
||||
|
matrix: |
||||
|
include: |
||||
|
- name: macOS |
||||
|
os: macos-latest |
||||
|
python-version: 3.9 |
||||
|
- name: Windows |
||||
|
os: windows-latest |
||||
|
python-version: 3.9 |
||||
|
|
||||
|
steps: |
||||
|
- uses: actions/checkout@v2 |
||||
|
- name: Set up Python ${{ matrix.python-version }} |
||||
|
uses: actions/setup-python@v2 |
||||
|
with: |
||||
|
python-version: ${{ matrix.python-version }} |
||||
|
- name: Install Python dependencies |
||||
|
run: | |
||||
|
python --version |
||||
|
pip install --upgrade pip wheel |
||||
|
pip install --upgrade -r requirements.txt |
||||
|
pip install --upgrade -r builder/requirements.txt |
||||
|
- name: Build source distribution |
||||
|
if: runner.os == 'Windows' |
||||
|
run: python builder/package.py source |
||||
|
- name: Upload source distribution |
||||
|
if: runner.os == 'Windows' |
||||
|
uses: actions/upload-artifact@v2 |
||||
|
with: |
||||
|
path: "*-src.tar.gz" |
||||
|
name: Source distribution |
||||
|
- name: Build Windows standalone binary and installer |
||||
|
if: runner.os == 'Windows' |
||||
|
run: python builder/package.py installer |
||||
|
- name: Upload Windows standalone binary (64bit) |
||||
|
if: runner.os == 'Windows' |
||||
|
uses: actions/upload-artifact@v2 |
||||
|
with: |
||||
|
path: "*-win64-bin.zip" |
||||
|
name: Windows Windows standalone binary (64bit) |
||||
|
- name: Upload Windows installer |
||||
|
if: runner.os == 'Windows' |
||||
|
uses: actions/upload-artifact@v2 |
||||
|
with: |
||||
|
path: "*-win-setup.exe" |
||||
|
name: Windows installer |
||||
|
- name: Import codesign certificates |
||||
|
uses: apple-actions/import-codesign-certs@v1 |
||||
|
if: runner.os == 'macOS' |
||||
|
with: |
||||
|
p12-file-base64: ${{ secrets.CERTIFICATES_P12 }} |
||||
|
p12-password: ${{ secrets.CERTIFICATES_P12_PASSWORD }} |
||||
|
- name: Build macOS binary |
||||
|
if: runner.os == 'macOS' |
||||
|
run: | |
||||
|
python builder/package.py app |
||||
|
python builder/make_dmg.py |
||||
|
env: |
||||
|
SIGNING_AUTH: ${{ secrets.SIGNING_AUTH }} |
||||
|
- name: Upload macOS binary |
||||
|
if: runner.os == 'macOS' |
||||
|
uses: actions/upload-artifact@v2 |
||||
|
with: |
||||
|
path: "*-osx.dmg" |
||||
|
name: macOS binary (not notarized) |
||||
|
|
||||
|
|
||||
|
|
@ -0,0 +1,184 @@ |
|||||
|
# -*- mode: python -*- |
||||
|
import re |
||||
|
import sys |
||||
|
import pkginfo |
||||
|
|
||||
|
from PyInstaller.building.api import EXE, COLLECT, PYZ |
||||
|
from PyInstaller.building.build_main import Analysis |
||||
|
from PyInstaller.building.osx import BUNDLE |
||||
|
|
||||
|
# Add extra files in the PyInstaller-spec |
||||
|
extra_pyinstaller_files = [] |
||||
|
|
||||
|
# Also modify these in "package.py"! |
||||
|
extra_files = [ |
||||
|
"README.txt", |
||||
|
"INSTALL.txt", |
||||
|
"LICENSE.txt", |
||||
|
"GPL2.txt", |
||||
|
"GPL3.txt", |
||||
|
"COPYRIGHT.txt", |
||||
|
"ISSUES.txt", |
||||
|
"PKG-INFO", |
||||
|
] |
||||
|
|
||||
|
extra_folders = [ |
||||
|
"scripts/", |
||||
|
"licenses/", |
||||
|
"locale/", |
||||
|
"email/", |
||||
|
"interfaces/Plush/", |
||||
|
"interfaces/Glitter/", |
||||
|
"interfaces/wizard/", |
||||
|
"interfaces/Config/", |
||||
|
"scripts/", |
||||
|
"icons/", |
||||
|
] |
||||
|
|
||||
|
# Get the version |
||||
|
RELEASE_VERSION = pkginfo.Develop(".").version |
||||
|
|
||||
|
# Add hidden imports |
||||
|
extra_hiddenimports = ["Cheetah.DummyTransaction", "cheroot.ssl.builtin", "certifi"] |
||||
|
|
||||
|
# Add platform specific stuff |
||||
|
if sys.platform == "darwin": |
||||
|
extra_hiddenimports.extend(["pyobjc", "objc", "PyObjCTools"]) |
||||
|
# macOS folders |
||||
|
extra_folders += ["osx/par2/", "osx/unrar/", "osx/7zip/"] |
||||
|
# Add NZB-icon file |
||||
|
extra_pyinstaller_files.append(("builder/osx/image/nzbfile.icns", ".")) |
||||
|
# Version information is set differently on macOS |
||||
|
version_info = None |
||||
|
else: |
||||
|
# Build would fail on non-Windows |
||||
|
from PyInstaller.utils.win32.versioninfo import ( |
||||
|
VSVersionInfo, |
||||
|
FixedFileInfo, |
||||
|
StringFileInfo, |
||||
|
StringTable, |
||||
|
StringStruct, |
||||
|
VarFileInfo, |
||||
|
VarStruct, |
||||
|
) |
||||
|
|
||||
|
# Windows |
||||
|
extra_hiddenimports.append("win32timezone") |
||||
|
extra_folders += ["win/multipar/", "win/unrar/", "win/7zip/"] |
||||
|
|
||||
|
# Parse the version info |
||||
|
version_regexed = re.search(r"(\d+)\.(\d+)\.(\d+)([a-zA-Z]*)(\d*)", RELEASE_VERSION) |
||||
|
version_tuple = (int(version_regexed.group(1)), int(version_regexed.group(2)), int(version_regexed.group(3)), 0) |
||||
|
|
||||
|
# Detailed instructions are in the PyInstaller documentation |
||||
|
# We don't include the alpha/beta/rc in the counters |
||||
|
version_info = VSVersionInfo( |
||||
|
ffi=FixedFileInfo( |
||||
|
filevers=version_tuple, |
||||
|
prodvers=version_tuple, |
||||
|
mask=0x3F, |
||||
|
flags=0x0, |
||||
|
OS=0x40004, |
||||
|
fileType=0x1, |
||||
|
subtype=0x0, |
||||
|
date=(0, 0), |
||||
|
), |
||||
|
kids=[ |
||||
|
StringFileInfo( |
||||
|
[ |
||||
|
StringTable( |
||||
|
"040904B0", |
||||
|
[ |
||||
|
StringStruct("Comments", f"SABnzbd {RELEASE_VERSION}"), |
||||
|
StringStruct("CompanyName", "The SABnzbd-Team"), |
||||
|
StringStruct("FileDescription", f"SABnzbd {RELEASE_VERSION}"), |
||||
|
StringStruct("FileVersion", RELEASE_VERSION), |
||||
|
StringStruct("LegalCopyright", "The SABnzbd-Team"), |
||||
|
StringStruct("ProductName", f"SABnzbd {RELEASE_VERSION}"), |
||||
|
StringStruct("ProductVersion", RELEASE_VERSION), |
||||
|
], |
||||
|
) |
||||
|
] |
||||
|
), |
||||
|
VarFileInfo([VarStruct("Translation", [1033, 1200])]), |
||||
|
], |
||||
|
) |
||||
|
|
||||
|
# Process the extra-files and folders |
||||
|
for file_item in extra_files: |
||||
|
extra_pyinstaller_files.append((file_item, ".")) |
||||
|
for folder_item in extra_folders: |
||||
|
extra_pyinstaller_files.append((folder_item, folder_item)) |
||||
|
|
||||
|
pyi_analysis = Analysis( |
||||
|
["SABnzbd.py"], |
||||
|
datas=extra_pyinstaller_files, |
||||
|
hiddenimports=extra_hiddenimports, |
||||
|
excludes=["FixTk", "tcl", "tk", "_tkinter", "tkinter", "Tkinter"], |
||||
|
) |
||||
|
|
||||
|
pyz = PYZ(pyi_analysis.pure, pyi_analysis.zipped_data) |
||||
|
|
||||
|
exe = EXE( |
||||
|
pyz, |
||||
|
pyi_analysis.scripts, |
||||
|
[], |
||||
|
exclude_binaries=True, |
||||
|
name="SABnzbd", |
||||
|
upx=True, |
||||
|
console=False, |
||||
|
append_pkg=False, |
||||
|
icon="icons/sabnzbd.ico", |
||||
|
version=version_info, |
||||
|
) |
||||
|
|
||||
|
coll = COLLECT(exe, pyi_analysis.binaries, pyi_analysis.zipfiles, pyi_analysis.datas, name="SABnzbd") |
||||
|
|
||||
|
# We need to run again for the console-app |
||||
|
if sys.platform == "win32": |
||||
|
# Enable console=True for this one |
||||
|
console_exe = EXE( |
||||
|
pyz, |
||||
|
pyi_analysis.scripts, |
||||
|
[], |
||||
|
exclude_binaries=True, |
||||
|
name="SABnzbd-console", |
||||
|
upx=True, |
||||
|
append_pkg=False, |
||||
|
icon="icons/sabnzbd.ico", |
||||
|
version=version_info, |
||||
|
) |
||||
|
|
||||
|
console_coll = COLLECT( |
||||
|
console_exe, |
||||
|
pyi_analysis.binaries, |
||||
|
pyi_analysis.zipfiles, |
||||
|
pyi_analysis.datas, |
||||
|
upx=True, |
||||
|
name="SABnzbd-console", |
||||
|
) |
||||
|
|
||||
|
# Build the APP on macOS |
||||
|
if sys.platform == "darwin": |
||||
|
info_plist = { |
||||
|
"NSUIElement": 1, |
||||
|
"NSPrincipalClass": "NSApplication", |
||||
|
"CFBundleShortVersionString": RELEASE_VERSION, |
||||
|
"NSHumanReadableCopyright": "The SABnzbd-Team", |
||||
|
"CFBundleIdentifier": "org.sabnzbd.sabnzbd", |
||||
|
"CFBundleDocumentTypes": [ |
||||
|
{ |
||||
|
"CFBundleTypeExtensions": ["nzb"], |
||||
|
"CFBundleTypeIconFile": "nzbfile.icns", |
||||
|
"CFBundleTypeMIMETypes": ["text/nzb"], |
||||
|
"CFBundleTypeName": "NZB File", |
||||
|
"CFBundleTypeRole": "Viewer", |
||||
|
"LSTypeIsPackage": 0, |
||||
|
"NSPersistentStoreTypeKey": "Binary", |
||||
|
} |
||||
|
], |
||||
|
"LSMinimumSystemVersion": "10.9", |
||||
|
"LSEnvironment": {"LANG": "en_US.UTF-8", "LC_ALL": "en_US.UTF-8"}, |
||||
|
} |
||||
|
|
||||
|
app = BUNDLE(coll, name="SABnzbd.app", icon="builder/osx/image/sabnzbdplus.icns", info_plist=info_plist) |
@ -0,0 +1,206 @@ |
|||||
|
#!/usr/bin/python3 -OO |
||||
|
# Copyright 2008-2017 The SABnzbd-Team <team@sabnzbd.org> |
||||
|
# |
||||
|
# This program is free software; you can redistribute it and/or |
||||
|
# modify it under the terms of the GNU General Public License |
||||
|
# as published by the Free Software Foundation; either version 2 |
||||
|
# of the License, or (at your option) any later version. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU General Public License for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU General Public License |
||||
|
# along with this program; if not, write to the Free Software |
||||
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
||||
|
|
||||
|
import os |
||||
|
import pkginfo |
||||
|
|
||||
|
|
||||
|
# We need to call dmgbuild from command-line, so here we can setup how |
||||
|
if __name__ == "__main__": |
||||
|
# Check for DMGBuild |
||||
|
try: |
||||
|
import dmgbuild |
||||
|
except: |
||||
|
print("Requires dmgbuild-module, use pip install dmgbuild") |
||||
|
exit() |
||||
|
|
||||
|
# Make sure we are in the src folder |
||||
|
if not os.path.exists("builder"): |
||||
|
raise FileNotFoundError("Run from the main SABnzbd source folder: python builder/package.py") |
||||
|
|
||||
|
# Check if signing is possible |
||||
|
authority = os.environ.get("SIGNING_AUTH") |
||||
|
|
||||
|
# Extract version info and set DMG path |
||||
|
# Create sub-folder to upload later |
||||
|
release = pkginfo.Develop(".").version |
||||
|
prod = "SABnzbd-" + release |
||||
|
fileDmg = prod + "-osx.dmg" |
||||
|
|
||||
|
# Path to app file |
||||
|
apppath = "dist/SABnzbd.app" |
||||
|
|
||||
|
# Copy Readme |
||||
|
readmepath = os.path.join(apppath, "Contents/Resources/README.txt") |
||||
|
|
||||
|
# Path to background and the icon |
||||
|
backgroundpath = "builder/osx/image/sabnzbd_new_bg.png" |
||||
|
iconpath = "builder/osx/image/sabnzbdplus.icns" |
||||
|
|
||||
|
# Make DMG |
||||
|
print("Building DMG") |
||||
|
dmgbuild.build_dmg( |
||||
|
filename=fileDmg, |
||||
|
volume_name=prod, |
||||
|
settings_file="builder/make_dmg.py", |
||||
|
defines={"app": apppath, "readme": readmepath, "background": backgroundpath, "iconpath": iconpath}, |
||||
|
) |
||||
|
|
||||
|
# Resign APP |
||||
|
if authority: |
||||
|
print("Siging DMG") |
||||
|
os.system('codesign --deep -f -i "org.sabnzbd.SABnzbd" -s "%s" "%s"' % (authority, fileDmg)) |
||||
|
print("Signed!") |
||||
|
else: |
||||
|
print("Signing skipped, missing SIGNING_AUTH.") |
||||
|
exit() |
||||
|
|
||||
|
|
||||
|
### START OF DMGBUILD SETTINGS |
||||
|
### COPIED AND MODIFIED FROM THE EXAMPLE ONLINE |
||||
|
application = defines.get("app", "AppName.app") |
||||
|
readme = defines.get("readme", "ReadMe.rtf") |
||||
|
appname = os.path.basename(application) |
||||
|
|
||||
|
# .. Basics .................................................................... |
||||
|
|
||||
|
# Volume format (see hdiutil create -help) |
||||
|
format = defines.get("format", "UDBZ") |
||||
|
|
||||
|
# Volume size (must be large enough for your files) |
||||
|
size = defines.get("size", "100M") |
||||
|
|
||||
|
# Files to include |
||||
|
files = [application, readme] |
||||
|
|
||||
|
# Symlinks to create |
||||
|
symlinks = {"Applications": "/Applications"} |
||||
|
|
||||
|
# Volume icon |
||||
|
# |
||||
|
# You can either define icon, in which case that icon file will be copied to the |
||||
|
# image, *or* you can define badge_icon, in which case the icon file you specify |
||||
|
# will be used to badge the system's Removable Disk icon |
||||
|
# |
||||
|
badge_icon = defines.get("iconpath", "") |
||||
|
|
||||
|
# Where to put the icons |
||||
|
icon_locations = {readme: (70, 160), appname: (295, 220), "Applications": (510, 220)} |
||||
|
|
||||
|
# .. Window configuration ...................................................... |
||||
|
|
||||
|
# Window position in ((x, y), (w, h)) format |
||||
|
window_rect = ((100, 100), (660, 360)) |
||||
|
|
||||
|
# Background |
||||
|
# |
||||
|
# This is a STRING containing any of the following: |
||||
|
# |
||||
|
# #3344ff - web-style RGB color |
||||
|
# #34f - web-style RGB color, short form (#34f == #3344ff) |
||||
|
# rgb(1,0,0) - RGB color, each value is between 0 and 1 |
||||
|
# hsl(120,1,.5) - HSL (hue saturation lightness) color |
||||
|
# hwb(300,0,0) - HWB (hue whiteness blackness) color |
||||
|
# cmyk(0,1,0,0) - CMYK color |
||||
|
# goldenrod - X11/SVG named color |
||||
|
# builtin-arrow - A simple built-in background with a blue arrow |
||||
|
# /foo/bar/baz.png - The path to an image file |
||||
|
# |
||||
|
# Other color components may be expressed either in the range 0 to 1, or |
||||
|
# as percentages (e.g. 60% is equivalent to 0.6). |
||||
|
background = defines.get("background", "builtin-arrow") |
||||
|
|
||||
|
show_status_bar = False |
||||
|
show_tab_view = False |
||||
|
show_toolbar = False |
||||
|
show_pathbar = False |
||||
|
show_sidebar = False |
||||
|
sidebar_width = 0 |
||||
|
|
||||
|
# Select the default view; must be one of |
||||
|
# |
||||
|
# 'icon-view' |
||||
|
# 'list-view' |
||||
|
# 'column-view' |
||||
|
# 'coverflow' |
||||
|
# |
||||
|
default_view = "icon-view" |
||||
|
|
||||
|
# General view configuration |
||||
|
show_icon_preview = False |
||||
|
|
||||
|
# Set these to True to force inclusion of icon/list view settings (otherwise |
||||
|
# we only include settings for the default view) |
||||
|
include_icon_view_settings = "auto" |
||||
|
include_list_view_settings = "auto" |
||||
|
|
||||
|
# .. Icon view configuration ................................................... |
||||
|
|
||||
|
arrange_by = None |
||||
|
grid_offset = (0, 0) |
||||
|
grid_spacing = 50 |
||||
|
scroll_position = (0, 0) |
||||
|
label_pos = "bottom" # or 'right' |
||||
|
text_size = 16 |
||||
|
icon_size = 64 |
||||
|
|
||||
|
# .. List view configuration ................................................... |
||||
|
|
||||
|
# Column names are as follows: |
||||
|
# |
||||
|
# name |
||||
|
# date-modified |
||||
|
# date-created |
||||
|
# date-added |
||||
|
# date-last-opened |
||||
|
# size |
||||
|
# kind |
||||
|
# label |
||||
|
# version |
||||
|
# comments |
||||
|
# |
||||
|
list_icon_size = 16 |
||||
|
list_text_size = 12 |
||||
|
list_scroll_position = (0, 0) |
||||
|
list_sort_by = "name" |
||||
|
list_use_relative_dates = True |
||||
|
list_calculate_all_sizes = (False,) |
||||
|
list_columns = ("name", "date-modified", "size", "kind", "date-added") |
||||
|
list_column_widths = { |
||||
|
"name": 300, |
||||
|
"date-modified": 181, |
||||
|
"date-created": 181, |
||||
|
"date-added": 181, |
||||
|
"date-last-opened": 181, |
||||
|
"size": 97, |
||||
|
"kind": 115, |
||||
|
"label": 100, |
||||
|
"version": 75, |
||||
|
"comments": 300, |
||||
|
} |
||||
|
list_column_sort_directions = { |
||||
|
"name": "ascending", |
||||
|
"date-modified": "descending", |
||||
|
"date-created": "descending", |
||||
|
"date-added": "descending", |
||||
|
"date-last-opened": "descending", |
||||
|
"size": "descending", |
||||
|
"kind": "ascending", |
||||
|
"label": "ascending", |
||||
|
"version": "ascending", |
||||
|
"comments": "ascending", |
||||
|
} |
@ -0,0 +1,8 @@ |
|||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> |
||||
|
<plist version="1.0"> |
||||
|
<dict> |
||||
|
<key>com.apple.security.cs.allow-unsigned-executable-memory</key> |
||||
|
<true/> |
||||
|
</dict> |
||||
|
</plist> |
Binary file not shown.
After Width: | Height: | Size: 39 KiB |
Binary file not shown.
Binary file not shown.
@ -0,0 +1,545 @@ |
|||||
|
#!/usr/bin/python3 -OO |
||||
|
# Copyright 2008-2017 The SABnzbd-Team <team@sabnzbd.org> |
||||
|
# |
||||
|
# This program is free software; you can redistribute it and/or |
||||
|
# modify it under the terms of the GNU General Public License |
||||
|
# as published by the Free Software Foundation; either version 2 |
||||
|
# of the License, or (at your option) any later version. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU General Public License for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU General Public License |
||||
|
# along with this program; if not, write to the Free Software |
||||
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
||||
|
|
||||
|
import glob |
||||
|
import platform |
||||
|
import re |
||||
|
import sys |
||||
|
import os |
||||
|
import time |
||||
|
import shutil |
||||
|
import subprocess |
||||
|
import tarfile |
||||
|
import pkginfo |
||||
|
import github |
||||
|
from distutils.dir_util import copy_tree |
||||
|
|
||||
|
|
||||
|
VERSION_FILE = "sabnzbd/version.py" |
||||
|
SPEC_FILE = "SABnzbd.spec" |
||||
|
|
||||
|
# Also modify these in "SABnzbd.spec"! |
||||
|
extra_files = [ |
||||
|
"README.mkd", |
||||
|
"INSTALL.txt", |
||||
|
"LICENSE.txt", |
||||
|
"GPL2.txt", |
||||
|
"GPL3.txt", |
||||
|
"COPYRIGHT.txt", |
||||
|
"ISSUES.txt", |
||||
|
"PKG-INFO", |
||||
|
] |
||||
|
|
||||
|
extra_folders = [ |
||||
|
"scripts/", |
||||
|
"licenses/", |
||||
|
"locale/", |
||||
|
"email/", |
||||
|
"interfaces/Plush/", |
||||
|
"interfaces/Glitter/", |
||||
|
"interfaces/wizard/", |
||||
|
"interfaces/Config/", |
||||
|
"scripts/", |
||||
|
"icons/", |
||||
|
] |
||||
|
|
||||
|
|
||||
|
# Support functions |
||||
|
def safe_remove(path): |
||||
|
"""Remove file without erros if the file doesn't exist |
||||
|
Can also handle folders |
||||
|
""" |
||||
|
if os.path.exists(path): |
||||
|
if os.path.isdir(path): |
||||
|
shutil.rmtree(path) |
||||
|
else: |
||||
|
os.remove(path) |
||||
|
|
||||
|
|
||||
|
def delete_files_glob(name): |
||||
|
""" Delete one file or set of files from wild-card spec """ |
||||
|
for f in glob.glob(name): |
||||
|
if os.path.exists(f): |
||||
|
os.remove(f) |
||||
|
|
||||
|
|
||||
|
def run_external_command(command): |
||||
|
""" Wrapper to ease the use of calling external programs """ |
||||
|
process = subprocess.Popen(command, text=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) |
||||
|
output, _ = process.communicate() |
||||
|
ret = process.wait() |
||||
|
if output: |
||||
|
print(output) |
||||
|
if ret != 0: |
||||
|
raise RuntimeError("Command returned non-zero exit code %s!" % ret) |
||||
|
return output |
||||
|
|
||||
|
|
||||
|
def run_git_command(parms): |
||||
|
""" Run git command, raise error if it failed """ |
||||
|
return run_external_command(["git"] + parms) |
||||
|
|
||||
|
|
||||
|
def patch_version_file(release_name): |
||||
|
"""Patch in the Git commit hash, but only when this is |
||||
|
an unmodified checkout |
||||
|
""" |
||||
|
git_output = run_git_command(["log", "-1"]) |
||||
|
for line in git_output.split("\n"): |
||||
|
if "commit " in line: |
||||
|
commit = line.split(" ")[1].strip() |
||||
|
break |
||||
|
else: |
||||
|
raise TypeError("Commit hash not found") |
||||
|
|
||||
|
with open(VERSION_FILE, "r") as ver: |
||||
|
version_file = ver.read() |
||||
|
|
||||
|
version_file = re.sub(r'__baseline__\s*=\s*"[^"]*"', '__baseline__ = "%s"' % commit, version_file) |
||||
|
version_file = re.sub(r'__version__\s*=\s*"[^"]*"', '__version__ = "%s"' % release_name, version_file) |
||||
|
|
||||
|
with open(VERSION_FILE, "w") as ver: |
||||
|
ver.write(version_file) |
||||
|
|
||||
|
|
||||
|
if __name__ == "__main__": |
||||
|
# Was any option supplied? |
||||
|
if len(sys.argv) < 2: |
||||
|
raise TypeError("Please specify what to do") |
||||
|
|
||||
|
# Make sure we are in the src folder |
||||
|
if not os.path.exists("builder"): |
||||
|
raise FileNotFoundError("Run from the main SABnzbd source folder: python builder/package.py") |
||||
|
|
||||
|
# Extract version info |
||||
|
RELEASE_VERSION = pkginfo.Develop(".").version |
||||
|
|
||||
|
# Check if we have the needed certificates |
||||
|
try: |
||||
|
import certifi |
||||
|
except ImportError: |
||||
|
raise FileNotFoundError("Need certifi module") |
||||
|
|
||||
|
# Define release name |
||||
|
RELEASE_NAME = "SABnzbd-%s" % RELEASE_VERSION |
||||
|
RELEASE_TITLE = "SABnzbd %s" % RELEASE_VERSION |
||||
|
RELEASE_SRC = RELEASE_NAME + "-src.tar.gz" |
||||
|
RELEASE_BINARY_32 = RELEASE_NAME + "-win32-bin.zip" |
||||
|
RELEASE_BINARY_64 = RELEASE_NAME + "-win64-bin.zip" |
||||
|
RELEASE_INSTALLER = RELEASE_NAME + "-win-setup.exe" |
||||
|
RELEASE_MACOS = RELEASE_NAME + "-osx.dmg" |
||||
|
RELEASE_README = "README.mkd" |
||||
|
|
||||
|
# Patch release file |
||||
|
patch_version_file(RELEASE_VERSION) |
||||
|
|
||||
|
# Rename release notes file |
||||
|
safe_remove("README.txt") |
||||
|
shutil.copyfile(RELEASE_README, "README.txt") |
||||
|
|
||||
|
# Compile translations |
||||
|
if not os.path.exists("locale"): |
||||
|
run_external_command([sys.executable, "tools/make_mo.py"]) |
||||
|
|
||||
|
# Check again if translations exist, fail otherwise |
||||
|
if not os.path.exists("locale"): |
||||
|
raise FileNotFoundError("Failed to compile language files") |
||||
|
|
||||
|
# Make sure we remove any existing build-folders |
||||
|
safe_remove("build") |
||||
|
safe_remove("dist") |
||||
|
safe_remove(RELEASE_NAME) |
||||
|
|
||||
|
# Copy the specification |
||||
|
shutil.copyfile("builder/%s" % SPEC_FILE, SPEC_FILE) |
||||
|
|
||||
|
if "binary" in sys.argv or "installer" in sys.argv: |
||||
|
# Must be run on Windows |
||||
|
if sys.platform != "win32": |
||||
|
raise RuntimeError("Binary should be created on Windows") |
||||
|
|
||||
|
# Check what architecture we are on |
||||
|
RELEASE_BINARY = RELEASE_BINARY_32 |
||||
|
if platform.architecture()[0] == "64bit": |
||||
|
RELEASE_BINARY = RELEASE_BINARY_64 |
||||
|
|
||||
|
# Remove any leftovers |
||||
|
safe_remove(RELEASE_BINARY) |
||||
|
|
||||
|
# Run PyInstaller and check output |
||||
|
run_external_command([sys.executable, "-O", "-m", "PyInstaller", "SABnzbd.spec"]) |
||||
|
|
||||
|
# Use special distutils function to merge the main and console directories |
||||
|
copy_tree("dist/SABnzbd-console", "dist/SABnzbd") |
||||
|
safe_remove("dist/SABnzbd-console") |
||||
|
|
||||
|
# Remove unwanted DLL's |
||||
|
delete_files_glob("dist/SABnzbd/api-ms-win*.dll") |
||||
|
delete_files_glob("dist/SABnzbd/mfc140u.dll") |
||||
|
delete_files_glob("dist/SABnzbd/ucrtbase.dll") |
||||
|
|
||||
|
# Remove other files we don't need |
||||
|
delete_files_glob("dist/SABnzbd/PKG-INFO") |
||||
|
delete_files_glob("dist/SABnzbd/win32ui.pyd") |
||||
|
delete_files_glob("dist/SABnzbd/winxpgui.pyd") |
||||
|
|
||||
|
if "installer" in sys.argv: |
||||
|
# Needs to be run on 64 bit |
||||
|
if RELEASE_BINARY != RELEASE_BINARY_64: |
||||
|
raise RuntimeError("Installer should be created on 64bit Python") |
||||
|
|
||||
|
# Compile NSIS translations |
||||
|
safe_remove("NSIS_Installer.nsi") |
||||
|
safe_remove("NSIS_Installer.nsi.tmp") |
||||
|
shutil.copyfile("builder/win/NSIS_Installer.nsi", "NSIS_Installer.nsi") |
||||
|
run_external_command([sys.executable, "tools/make_mo.py", "nsis"]) |
||||
|
|
||||
|
# Remove 32bit external executables |
||||
|
delete_files_glob("dist/SABnzbd/win/par2/multipar/par2j.exe") |
||||
|
delete_files_glob("dist/SABnzbd/win/unrar/UnRAR.exe") |
||||
|
|
||||
|
# Run NSIS to build installer |
||||
|
run_external_command( |
||||
|
[ |
||||
|
"makensis.exe", |
||||
|
"/V3", |
||||
|
"/DSAB_PRODUCT=%s" % RELEASE_NAME, |
||||
|
"/DSAB_VERSION=%s" % RELEASE_VERSION, |
||||
|
"/DSAB_FILE=%s" % RELEASE_INSTALLER, |
||||
|
"NSIS_Installer.nsi.tmp", |
||||
|
] |
||||
|
) |
||||
|
|
||||
|
# Rename the folder |
||||
|
os.rename("dist/SABnzbd", RELEASE_NAME) |
||||
|
|
||||
|
# Create the archive |
||||
|
run_external_command(["win/7zip/7za.exe", "a", RELEASE_BINARY, RELEASE_NAME]) |
||||
|
|
||||
|
if "app" in sys.argv: |
||||
|
# Must be run on macOS |
||||
|
if sys.platform != "darwin": |
||||
|
raise RuntimeError("App should be created on macOS") |
||||
|
|
||||
|
# Who will sign and notarize this? |
||||
|
authority = os.environ.get("SIGNING_AUTH") |
||||
|
notarization_user = os.environ.get("NOTARIZATION_USER") |
||||
|
notarization_pass = os.environ.get("NOTARIZATION_PASS") |
||||
|
|
||||
|
# Run PyInstaller and check output |
||||
|
run_external_command([sys.executable, "-O", "-m", "PyInstaller", "SABnzbd.spec"]) |
||||
|
|
||||
|
# Only continue if we can sign |
||||
|
if authority: |
||||
|
files_to_sign = [ |
||||
|
"dist/SABnzbd.app/Contents/MacOS/osx/par2/par2-sl64", |
||||
|
"dist/SABnzbd.app/Contents/MacOS/osx/7zip/7za", |
||||
|
"dist/SABnzbd.app/Contents/MacOS/osx/unrar/unrar", |
||||
|
"dist/SABnzbd.app/Contents/MacOS/SABnzbd", |
||||
|
"dist/SABnzbd.app", |
||||
|
] |
||||
|
|
||||
|
for file_to_sign in files_to_sign: |
||||
|
print("Signing %s with hardended runtime" % file_to_sign) |
||||
|
run_external_command( |
||||
|
[ |
||||
|
"codesign", |
||||
|
"--deep", |
||||
|
"--force", |
||||
|
"--timestamp", |
||||
|
"--options", |
||||
|
"runtime", |
||||
|
"--entitlements", |
||||
|
"builder/osx/entitlements.plist", |
||||
|
"-i", |
||||
|
"org.sabnzbd.sabnzbd", |
||||
|
"-s", |
||||
|
authority, |
||||
|
file_to_sign, |
||||
|
], |
||||
|
) |
||||
|
print("Signed %s!" % file_to_sign) |
||||
|
|
||||
|
# Only notarize for real builds that we want to deploy |
||||
|
if notarization_user and notarization_pass and "release" in os.environ.get("TRAVIS_TAG", ""): |
||||
|
# Prepare zip to upload to notarization service |
||||
|
print("Creating zip to send to Apple notarization service") |
||||
|
# We need to use ditto, otherwise the signature gets lost! |
||||
|
notarization_zip = RELEASE_NAME + ".zip" |
||||
|
run_external_command( |
||||
|
["ditto", "-c", "-k", "--sequesterRsrc", "--keepParent", "dist/SABnzbd.app", notarization_zip] |
||||
|
) |
||||
|
|
||||
|
# Upload to Apple |
||||
|
print("Sending zip to Apple notarization service") |
||||
|
upload_process = run_external_command( |
||||
|
[ |
||||
|
"xcrun", |
||||
|
"altool", |
||||
|
"--notarize-app", |
||||
|
"-t", |
||||
|
"osx", |
||||
|
"-f", |
||||
|
notarization_zip, |
||||
|
"--primary-bundle-id", |
||||
|
"org.sabnzbd.sabnzbd", |
||||
|
"-u", |
||||
|
notarization_user, |
||||
|
"-p", |
||||
|
notarization_pass, |
||||
|
], |
||||
|
) |
||||
|
|
||||
|
# Extract the notarization ID |
||||
|
m = re.match(".*RequestUUID = (.*?)\n", upload_process, re.S) |
||||
|
if not m: |
||||
|
raise RuntimeError("No UUID created") |
||||
|
uuid = m.group(1) |
||||
|
|
||||
|
print("Checking notarization of UUID: %s (every 30 seconds)" % uuid) |
||||
|
notarization_in_progress = True |
||||
|
while notarization_in_progress: |
||||
|
time.sleep(30) |
||||
|
check_status = run_external_command( |
||||
|
[ |
||||
|
"xcrun", |
||||
|
"altool", |
||||
|
"--notarization-info", |
||||
|
uuid, |
||||
|
"-u", |
||||
|
notarization_user, |
||||
|
"-p", |
||||
|
notarization_pass, |
||||
|
], |
||||
|
) |
||||
|
notarization_in_progress = "Status: in progress" in check_status |
||||
|
|
||||
|
# Check if success |
||||
|
if "Status: success" not in check_status: |
||||
|
raise RuntimeError("Failed to notarize..") |
||||
|
|
||||
|
# Staple the notarization! |
||||
|
print("Approved! Stapling the result to the app") |
||||
|
run_external_command(["xcrun", "stapler", "staple", "dist/SABnzbd.app"]) |
||||
|
elif notarization_user and notarization_pass: |
||||
|
print("Notarization skipped, include 'release' in the name of the tag to trigger notarization!") |
||||
|
else: |
||||
|
print("Notarization skipped, NOTARIZATION_USER or NOTARIZATION_PASS missing.") |
||||
|
else: |
||||
|
print("Signing skipped, missing SIGNING_AUTH.") |
||||
|
|
||||
|
if "source" in sys.argv: |
||||
|
# Prepare Source distribution package. |
||||
|
# We assume the sources are freshly cloned from the repo |
||||
|
# Make sure all source files are Unix format |
||||
|
src_folder = "srcdist" |
||||
|
safe_remove(src_folder) |
||||
|
os.mkdir(src_folder) |
||||
|
|
||||
|
# Remove any leftovers |
||||
|
safe_remove(RELEASE_SRC) |
||||
|
|
||||
|
# Add extra files and folders need for source dist |
||||
|
extra_folders.extend(["sabnzbd/", "po/", "linux/", "tools/", "tests/"]) |
||||
|
extra_files.extend(["SABnzbd.py", "requirements.txt"]) |
||||
|
|
||||
|
# Copy all folders and files to the new folder |
||||
|
for source_folder in extra_folders: |
||||
|
copy_tree(source_folder, os.path.join(src_folder, source_folder)) |
||||
|
|
||||
|
# Copy all files |
||||
|
for source_file in extra_files: |
||||
|
shutil.copyfile(source_file, os.path.join(src_folder, source_file)) |
||||
|
|
||||
|
# Make sure all line-endings are correct |
||||
|
for input_filename in glob.glob("%s/**/*.*" % src_folder, recursive=True): |
||||
|
base, ext = os.path.splitext(input_filename) |
||||
|
if ext.lower() not in (".py", ".txt", ".css", ".js", ".tmpl", ".sh", ".cmd"): |
||||
|
continue |
||||
|
print(input_filename) |
||||
|
|
||||
|
with open(input_filename, "rb") as input_data: |
||||
|
data = input_data.read() |
||||
|
data = data.replace(b"\r", b"") |
||||
|
with open(input_filename, "wb") as output_data: |
||||
|
output_data.write(data) |
||||
|
|
||||
|
# Create tar.gz file for source distro |
||||
|
with tarfile.open(RELEASE_SRC, "w:gz") as tar_output: |
||||
|
for root, dirs, files in os.walk(src_folder): |
||||
|
for _file in files: |
||||
|
input_path = os.path.join(root, _file) |
||||
|
if sys.platform == "win32": |
||||
|
tar_path = input_path.replace("srcdist\\", RELEASE_NAME + "/").replace("\\", "/") |
||||
|
else: |
||||
|
tar_path = input_path.replace("srcdist/", RELEASE_NAME + "/") |
||||
|
tarinfo = tar_output.gettarinfo(input_path, tar_path) |
||||
|
tarinfo.uid = 0 |
||||
|
tarinfo.gid = 0 |
||||
|
if _file in ("SABnzbd.py", "Sample-PostProc.sh", "make_mo.py", "msgfmt.py"): |
||||
|
# Force Linux/OSX scripts as executable |
||||
|
tarinfo.mode = 0o755 |
||||
|
else: |
||||
|
tarinfo.mode = 0o644 |
||||
|
|
||||
|
with open(input_path, "rb") as f: |
||||
|
tar_output.addfile(tarinfo, f) |
||||
|
|
||||
|
# Remove source folder |
||||
|
safe_remove(src_folder) |
||||
|
|
||||
|
# Release to github |
||||
|
if "release" in sys.argv: |
||||
|
# Check if tagged as release |
||||
|
if "release" in os.environ.get("TRAVIS_TAG", "") + os.environ.get("APPVEYOR_REPO_TAG_NAME", ""): |
||||
|
# Check for token |
||||
|
gh_token = os.environ.get("GITHUB_TOKEN", "") |
||||
|
if gh_token: |
||||
|
gh_obj = github.Github(gh_token) |
||||
|
gh_repo = gh_obj.get_repo("sabnzbd/sabnzbd") |
||||
|
|
||||
|
# Read the release notes |
||||
|
with open(RELEASE_README, "r") as readme_file: |
||||
|
readme_data = readme_file.read() |
||||
|
|
||||
|
# Pre-releases are longer than 6 characters (e.g. 3.1.0Beta1 vs 3.1.0, but also 3.0.11) |
||||
|
prerelease = len(RELEASE_VERSION) > 5 |
||||
|
|
||||
|
# We have to manually check if we already created this release |
||||
|
for release in gh_repo.get_releases(): |
||||
|
if release.tag_name == RELEASE_VERSION: |
||||
|
gh_release = release |
||||
|
print("Found existing release %s" % gh_release.title) |
||||
|
break |
||||
|
else: |
||||
|
# Did not find it, so create the release |
||||
|
print("Creating GitHub release SABnzbd %s" % RELEASE_VERSION) |
||||
|
gh_release = gh_repo.create_git_release( |
||||
|
tag=RELEASE_VERSION, name=RELEASE_TITLE, message=readme_data, draft=True, prerelease=prerelease |
||||
|
) |
||||
|
|
||||
|
# Fetch existing assets, as overwriting is not allowed by GitHub |
||||
|
gh_assets = gh_release.get_assets() |
||||
|
|
||||
|
# Upload the assets |
||||
|
files_to_check = ( |
||||
|
RELEASE_SRC, |
||||
|
RELEASE_BINARY_32, |
||||
|
RELEASE_BINARY_64, |
||||
|
RELEASE_INSTALLER, |
||||
|
RELEASE_MACOS, |
||||
|
RELEASE_README, |
||||
|
) |
||||
|
for file_to_check in files_to_check: |
||||
|
if os.path.exists(file_to_check): |
||||
|
# Check if this file was previously uploaded |
||||
|
for gh_asset in gh_assets: |
||||
|
if gh_asset.name == file_to_check: |
||||
|
print("Removing existing asset %s for release %s" % (gh_asset.name, gh_release.title)) |
||||
|
gh_asset.delete_asset() |
||||
|
# Upload the new one |
||||
|
print("Uploading %s to release %s" % (file_to_check, gh_release.title)) |
||||
|
gh_release.upload_asset(file_to_check) |
||||
|
|
||||
|
# Update the website |
||||
|
gh_repo_web = gh_obj.get_repo("sabnzbd/sabnzbd.github.io") |
||||
|
# Check if the branch already exists, only create one if it doesn't |
||||
|
skip_website_update = False |
||||
|
try: |
||||
|
gh_repo_web.get_branch(RELEASE_VERSION) |
||||
|
print("Branch %s on sabnzbd/sabnzbd.github.io already exists, skipping update" % RELEASE_VERSION) |
||||
|
skip_website_update = True |
||||
|
except github.GithubException: |
||||
|
# Create a new branch to have the changes |
||||
|
sb = gh_repo_web.get_branch("master") |
||||
|
print("Creating branch %s on sabnzbd/sabnzbd.github.io" % RELEASE_VERSION) |
||||
|
new_branch = gh_repo_web.create_git_ref(ref="refs/heads/" + RELEASE_VERSION, sha=sb.commit.sha) |
||||
|
|
||||
|
# Update the files |
||||
|
if not skip_website_update: |
||||
|
# We need bytes version to interact with GitHub |
||||
|
RELEASE_VERSION_BYTES = RELEASE_VERSION.encode() |
||||
|
|
||||
|
# Get all the version files |
||||
|
latest_txt = gh_repo_web.get_contents("latest.txt") |
||||
|
latest_txt_items = latest_txt.decoded_content.split() |
||||
|
new_latest_txt_items = latest_txt_items[:2] |
||||
|
config_yml = gh_repo_web.get_contents("_config.yml") |
||||
|
if prerelease: |
||||
|
# If it's a pre-release, we append to current version in latest.txt |
||||
|
new_latest_txt_items.extend([RELEASE_VERSION_BYTES, latest_txt_items[1]]) |
||||
|
# And replace in _config.yml |
||||
|
new_config_yml = re.sub( |
||||
|
b"latest_testing: '[^']*'", |
||||
|
b"latest_testing: '%s'" % RELEASE_VERSION_BYTES, |
||||
|
config_yml.decoded_content, |
||||
|
) |
||||
|
else: |
||||
|
# New stable release, replace the version |
||||
|
new_latest_txt_items[0] = RELEASE_VERSION_BYTES |
||||
|
# And replace in _config.yml |
||||
|
new_config_yml = re.sub( |
||||
|
b"latest_testing: '[^']*'", |
||||
|
b"latest_testing: ''", |
||||
|
config_yml.decoded_content, |
||||
|
) |
||||
|
new_config_yml = re.sub( |
||||
|
b"latest_stable: '[^']*'", |
||||
|
b"latest_stable: '%s'" % RELEASE_VERSION_BYTES, |
||||
|
new_config_yml, |
||||
|
) |
||||
|
# Also update the wiki-settings, these only use x.x notation |
||||
|
new_config_yml = re.sub( |
||||
|
b"wiki_version: '[^']*'", |
||||
|
b"wiki_version: '%s'" % RELEASE_VERSION_BYTES[:3], |
||||
|
new_config_yml, |
||||
|
) |
||||
|
|
||||
|
# Update the files |
||||
|
print("Updating latest.txt") |
||||
|
gh_repo_web.update_file( |
||||
|
"latest.txt", |
||||
|
"Release %s: latest.txt" % RELEASE_VERSION, |
||||
|
b"\n".join(new_latest_txt_items), |
||||
|
latest_txt.sha, |
||||
|
RELEASE_VERSION, |
||||
|
) |
||||
|
print("Updating _config.yml") |
||||
|
gh_repo_web.update_file( |
||||
|
"_config.yml", |
||||
|
"Release %s: _config.yml" % RELEASE_VERSION, |
||||
|
new_config_yml, |
||||
|
config_yml.sha, |
||||
|
RELEASE_VERSION, |
||||
|
) |
||||
|
|
||||
|
# Create pull-request |
||||
|
print("Creating pull request in sabnzbd/sabnzbd.github.io for the update") |
||||
|
gh_repo_web.create_pull( |
||||
|
title=RELEASE_VERSION, |
||||
|
base="master", |
||||
|
body="Automated update of release files", |
||||
|
head=RELEASE_VERSION, |
||||
|
) |
||||
|
else: |
||||
|
print("Missing GITHUB_TOKEN, cannot push to GitHub!") |
||||
|
else: |
||||
|
print("To push release to GitHub, include 'release' in the name of the tag") |
||||
|
|
||||
|
# Reset! |
||||
|
run_git_command(["reset", "--hard"]) |
||||
|
run_git_command(["clean", "-f"]) |
@ -0,0 +1,9 @@ |
|||||
|
# Basic build requirements |
||||
|
pyinstaller |
||||
|
setuptools |
||||
|
pkginfo |
||||
|
certifi |
||||
|
pygithub |
||||
|
|
||||
|
# For the OSX build specific |
||||
|
dmgbuild; sys_platform == 'darwin' |
@ -0,0 +1,396 @@ |
|||||
|
; -*- coding: utf-8 -*- |
||||
|
; |
||||
|
; Copyright 2008-2015 The SABnzbd-Team <team@sabnzbd.org> |
||||
|
; |
||||
|
; This program is free software; you can redistribute it and/or |
||||
|
; modify it under the terms of the GNU General Public License |
||||
|
; as published by the Free Software Foundation; either version 2 |
||||
|
; of the License, or (at your option) any later version. |
||||
|
; |
||||
|
; This program is distributed in the hope that it will be useful, |
||||
|
; but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
; GNU General Public License for more details. |
||||
|
; |
||||
|
; You should have received a copy of the GNU General Public License |
||||
|
; along with this program; if not, write to the Free Software |
||||
|
; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
||||
|
|
||||
|
Unicode true |
||||
|
|
||||
|
!addplugindir builder\win\nsis\Plugins |
||||
|
!addincludedir builder\win\nsis\Include |
||||
|
|
||||
|
!include "MUI2.nsh" |
||||
|
!include "registerExtension.nsh" |
||||
|
!include "FileFunc.nsh" |
||||
|
!include "LogicLib.nsh" |
||||
|
!include "WinVer.nsh" |
||||
|
!include "nsProcess.nsh" |
||||
|
!include "x64.nsh" |
||||
|
!include "servicelib.nsh" |
||||
|
|
||||
|
;------------------------------------------------------------------ |
||||
|
; |
||||
|
; Marco for removing existing and the current installation |
||||
|
; It shared by the installer and the uninstaller. |
||||
|
; |
||||
|
!define RemovePrev "!insertmacro RemovePrev" |
||||
|
!macro RemovePrev idir |
||||
|
; Remove the whole dir |
||||
|
; Users should not be putting stuff here! |
||||
|
RMDir /r "${idir}" |
||||
|
!macroend |
||||
|
|
||||
|
;------------------------------------------------------------------ |
||||
|
; Define names of the product |
||||
|
Name "${SAB_PRODUCT}" |
||||
|
OutFile "${SAB_FILE}" |
||||
|
InstallDir "$PROGRAMFILES\SABnzbd" |
||||
|
|
||||
|
|
||||
|
;------------------------------------------------------------------ |
||||
|
; Some default compiler settings (uncomment and change at will): |
||||
|
SetCompress auto ; (can be off or force) |
||||
|
SetDatablockOptimize on ; (can be off) |
||||
|
CRCCheck on ; (can be off) |
||||
|
AutoCloseWindow false ; (can be true for the window go away automatically at end) |
||||
|
ShowInstDetails hide ; (can be show to have them shown, or nevershow to disable) |
||||
|
SetDateSave off ; (can be on to have files restored to their orginal date) |
||||
|
WindowIcon on |
||||
|
SpaceTexts none |
||||
|
|
||||
|
|
||||
|
;------------------------------------------------------------------ |
||||
|
; Vista/Win7 redirects $SMPROGRAMS to all users without this |
||||
|
RequestExecutionLevel admin |
||||
|
FileErrorText "If you have no admin rights, try to install into a user directory." |
||||
|
|
||||
|
|
||||
|
;------------------------------------------------------------------ |
||||
|
;Variables |
||||
|
Var MUI_TEMP |
||||
|
Var STARTMENU_FOLDER |
||||
|
Var PREV_INST_DIR |
||||
|
|
||||
|
;------------------------------------------------------------------ |
||||
|
;Interface Settings |
||||
|
|
||||
|
!define MUI_ABORTWARNING |
||||
|
|
||||
|
;Show all languages, despite user's codepage |
||||
|
!define MUI_LANGDLL_ALLLANGUAGES |
||||
|
|
||||
|
!define MUI_ICON "dist\SABnzbd\icons\sabnzbd.ico" |
||||
|
|
||||
|
|
||||
|
;-------------------------------- |
||||
|
;Pages |
||||
|
|
||||
|
!insertmacro MUI_PAGE_LICENSE "dist\SABnzbd\LICENSE.txt" |
||||
|
!define MUI_COMPONENTSPAGE_NODESC |
||||
|
!insertmacro MUI_PAGE_COMPONENTS |
||||
|
|
||||
|
!insertmacro MUI_PAGE_DIRECTORY |
||||
|
|
||||
|
;Start Menu Folder Page Configuration |
||||
|
!define MUI_STARTMENUPAGE_REGISTRY_ROOT "HKCU" |
||||
|
!define MUI_STARTMENUPAGE_REGISTRY_KEY "Software\SABnzbd" |
||||
|
!define MUI_STARTMENUPAGE_REGISTRY_VALUENAME "Start Menu Folder" |
||||
|
!define MUI_STARTMENUPAGE_DEFAULTFOLDER "SABnzbd" |
||||
|
;Remember the installer language |
||||
|
!define MUI_LANGDLL_REGISTRY_ROOT "HKCU" |
||||
|
!define MUI_LANGDLL_REGISTRY_KEY "Software\SABnzbd" |
||||
|
!define MUI_LANGDLL_REGISTRY_VALUENAME "Installer Language" |
||||
|
|
||||
|
!insertmacro MUI_PAGE_STARTMENU Application $STARTMENU_FOLDER |
||||
|
|
||||
|
!insertmacro MUI_PAGE_INSTFILES |
||||
|
; !define MUI_FINISHPAGE_RUN |
||||
|
; !define MUI_FINISHPAGE_RUN_FUNCTION PageFinishRun |
||||
|
; !define MUI_FINISHPAGE_RUN_TEXT $(MsgRunSAB) |
||||
|
!define MUI_FINISHPAGE_SHOWREADME "$INSTDIR\README.txt" |
||||
|
!define MUI_FINISHPAGE_SHOWREADME_TEXT $(MsgShowRelNote) |
||||
|
!define MUI_FINISHPAGE_LINK $(MsgSupportUs) |
||||
|
!define MUI_FINISHPAGE_LINK_LOCATION "https://sabnzbd.org/donate" |
||||
|
|
||||
|
!insertmacro MUI_PAGE_FINISH |
||||
|
|
||||
|
!insertmacro MUI_UNPAGE_CONFIRM |
||||
|
!define MUI_UNPAGE_COMPONENTSPAGE_NODESC |
||||
|
!insertmacro MUI_UNPAGE_COMPONENTS |
||||
|
!insertmacro MUI_UNPAGE_INSTFILES |
||||
|
|
||||
|
;------------------------------------------------------------------ |
||||
|
; Run as user-level at end of install |
||||
|
; DOES NOT WORK |
||||
|
; Function PageFinishRun |
||||
|
; !insertmacro UAC_AsUser_ExecShell "" "$INSTDIR\SABnzbd.exe" "" "" "" |
||||
|
; FunctionEnd |
||||
|
|
||||
|
|
||||
|
;------------------------------------------------------------------ |
||||
|
; Set supported languages |
||||
|
; |
||||
|
; If you edit this list you also need to edit apireg.py in SABnzbd! |
||||
|
; |
||||
|
!insertmacro MUI_LANGUAGE "English" ;first language is the default language |
||||
|
!insertmacro MUI_LANGUAGE "French" |
||||
|
!insertmacro MUI_LANGUAGE "German" |
||||
|
!insertmacro MUI_LANGUAGE "Dutch" |
||||
|
!insertmacro MUI_LANGUAGE "Finnish" |
||||
|
!insertmacro MUI_LANGUAGE "Polish" |
||||
|
!insertmacro MUI_LANGUAGE "Swedish" |
||||
|
!insertmacro MUI_LANGUAGE "Danish" |
||||
|
!insertmacro MUI_LANGUAGE "Norwegian" |
||||
|
!insertmacro MUI_LANGUAGE "Romanian" |
||||
|
!insertmacro MUI_LANGUAGE "Spanish" |
||||
|
!insertmacro MUI_LANGUAGE "PortugueseBR" |
||||
|
!insertmacro MUI_LANGUAGE "Serbian" |
||||
|
!insertmacro MUI_LANGUAGE "Hebrew" |
||||
|
!insertmacro MUI_LANGUAGE "Russian" |
||||
|
!insertmacro MUI_LANGUAGE "Czech" |
||||
|
!insertmacro MUI_LANGUAGE "SimpChinese" |
||||
|
|
||||
|
|
||||
|
|
||||
|
;------------------------------------------------------------------ |
||||
|
;Reserve Files |
||||
|
;If you are using solid compression, files that are required before |
||||
|
;the actual installation should be stored first in the data block, |
||||
|
;because this will make your installer start faster. |
||||
|
|
||||
|
!insertmacro MUI_RESERVEFILE_LANGDLL |
||||
|
|
||||
|
|
||||
|
;------------------------------------------------------------------ |
||||
|
; SECTION main program |
||||
|
; |
||||
|
Section "SABnzbd" SecDummy |
||||
|
|
||||
|
SetOutPath "$INSTDIR" |
||||
|
|
||||
|
;------------------------------------------------------------------ |
||||
|
; Make sure old versions are gone (reg-key already read in onInt) |
||||
|
StrCmp $PREV_INST_DIR "" noPrevInstallRemove |
||||
|
${RemovePrev} "$PREV_INST_DIR" |
||||
|
noPrevInstallRemove: |
||||
|
|
||||
|
; add files / whatever that need to be installed here. |
||||
|
File /r "dist\SABnzbd\*" |
||||
|
|
||||
|
;------------------------------------------------------------------ |
||||
|
; Add firewall rules |
||||
|
liteFirewallW::AddRule "$INSTDIR\SABnzbd.exe" "SABnzbd" |
||||
|
liteFirewallW::AddRule "$INSTDIR\SABnzbd-console.exe" "SABnzbd-console" |
||||
|
|
||||
|
;------------------------------------------------------------------ |
||||
|
; Add to registery |
||||
|
WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\SABnzbd" "" "$INSTDIR" |
||||
|
WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\SABnzbd" "Installer Language" "$(MsgLangCode)" |
||||
|
WriteRegStr HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\SABnzbd" "DisplayName" "SABnzbd ${SAB_VERSION}" |
||||
|
WriteRegStr HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\SABnzbd" "UninstallString" '"$INSTDIR\uninstall.exe"' |
||||
|
WriteRegStr HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\SABnzbd" "DisplayVersion" '${SAB_VERSION}' |
||||
|
WriteRegStr HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\SABnzbd" "Publisher" 'The SABnzbd Team' |
||||
|
WriteRegStr HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\SABnzbd" "HelpLink" 'https://forums.sabnzbd.org/' |
||||
|
WriteRegStr HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\SABnzbd" "URLInfoAbout" 'https://sabnzbd.org/wiki/' |
||||
|
WriteRegStr HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\SABnzbd" "URLUpdateInfo" 'https://sabnzbd.org/' |
||||
|
WriteRegStr HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\SABnzbd" "Comments" 'The automated Usenet download tool' |
||||
|
WriteRegStr HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\SABnzbd" "DisplayIcon" '$INSTDIR\icons\sabnzbd.ico' |
||||
|
WriteRegDWORD HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\SABnzbd" "EstimatedSize" 25674 |
||||
|
WriteRegDWORD HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\SABnzbd" "NoRepair" -1 |
||||
|
WriteRegDWORD HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\SABnzbd" "NoModify" -1 |
||||
|
; write out uninstaller |
||||
|
WriteUninstaller "$INSTDIR\Uninstall.exe" |
||||
|
|
||||
|
!insertmacro MUI_STARTMENU_WRITE_BEGIN Application |
||||
|
;Create shortcuts |
||||
|
CreateDirectory "$SMPROGRAMS\$STARTMENU_FOLDER" |
||||
|
CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\SABnzbd.lnk" "$INSTDIR\SABnzbd.exe" |
||||
|
CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\SABnzbd - SafeMode.lnk" "$INSTDIR\SABnzbd.exe" "--server 127.0.0.1:8080 -b1 --no-login" |
||||
|
WriteINIStr "$SMPROGRAMS\$STARTMENU_FOLDER\SABnzbd - Documentation.url" "InternetShortcut" "URL" "https://sabnzbd.org/wiki/" |
||||
|
CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\Uninstall.lnk" "$INSTDIR\Uninstall.exe" |
||||
|
!insertmacro MUI_STARTMENU_WRITE_END |
||||
|
SectionEnd ; end of default section |
||||
|
|
||||
|
Section $(MsgIcon) desktop |
||||
|
CreateShortCut "$DESKTOP\SABnzbd.lnk" "$INSTDIR\SABnzbd.exe" |
||||
|
SectionEnd ; end of desktop icon section |
||||
|
|
||||
|
Section $(MsgAssoc) assoc |
||||
|
${registerExtension} "$INSTDIR\icons\nzb.ico" "$INSTDIR\SABnzbd.exe" ".nzb" "NZB File" |
||||
|
${RefreshShellIcons} |
||||
|
SectionEnd ; end of file association section |
||||
|
|
||||
|
Section /o $(MsgRunAtStart) startup |
||||
|
CreateShortCut "$SMPROGRAMS\Startup\SABnzbd.lnk" "$INSTDIR\SABnzbd.exe" "-b0" |
||||
|
SectionEnd ; |
||||
|
|
||||
|
;------------------------------------------------------------------ |
||||
|
Function .onInit |
||||
|
; We need to modify the dir here for X64 |
||||
|
${If} ${RunningX64} |
||||
|
StrCpy $INSTDIR "$PROGRAMFILES64\SABnzbd" |
||||
|
${Else} |
||||
|
MessageBox MB_OK $(MsgOnly64bit) |
||||
|
ExecShell "open" "https://sabnzbd.org/downloads" |
||||
|
Abort |
||||
|
${EndIf} |
||||
|
|
||||
|
;------------------------------------------------------------------ |
||||
|
; Change settings based on if SAB was already installed |
||||
|
ReadRegStr $PREV_INST_DIR HKEY_LOCAL_MACHINE "SOFTWARE\SABnzbd" "" |
||||
|
StrCmp $PREV_INST_DIR "" noPrevInstall |
||||
|
; We want to use the user's costom dir if he used one |
||||
|
StrCmp $PREV_INST_DIR "$PROGRAMFILES\SABnzbd" noSpecialDir |
||||
|
StrCmp $PREV_INST_DIR "$PROGRAMFILES64\SABnzbd" noSpecialDir |
||||
|
; Set what the user had before |
||||
|
StrCpy $INSTDIR "$PREV_INST_DIR" |
||||
|
noSpecialDir: |
||||
|
|
||||
|
;------------------------------------------------------------------ |
||||
|
; Check what the user has currently set for install options |
||||
|
IfFileExists "$SMPROGRAMS\Startup\SABnzbd.lnk" 0 endCheckStartup |
||||
|
SectionSetFlags ${startup} 1 |
||||
|
endCheckStartup: |
||||
|
|
||||
|
IfFileExists "$DESKTOP\SABnzbd.lnk" endCheckDesktop 0 |
||||
|
SectionSetFlags ${desktop} 0 ; SAB is installed but desktop-icon not, so uncheck it |
||||
|
endCheckDesktop: |
||||
|
|
||||
|
Push $1 |
||||
|
ReadRegStr $1 HKCR ".nzb" "" ; read current file association |
||||
|
StrCmp "$1" "NZB File" noPrevInstall 0 |
||||
|
SectionSetFlags ${assoc} 0 ; Uncheck it when it wasn't checked before |
||||
|
noPrevInstall: |
||||
|
|
||||
|
;-------------------------------- |
||||
|
; Display language chooser |
||||
|
!insertmacro MUI_LANGDLL_DISPLAY |
||||
|
|
||||
|
;------------------------------------------------------------------ |
||||
|
; make sure user terminates sabnzbd.exe or else abort |
||||
|
; |
||||
|
loop: |
||||
|
${nsProcess::FindProcess} "SABnzbd.exe" $R0 |
||||
|
StrCmp $R0 0 0 endcheck |
||||
|
MessageBox MB_OKCANCEL|MB_ICONEXCLAMATION $(MsgCloseSab) IDOK loop IDCANCEL exitinstall |
||||
|
exitinstall: |
||||
|
${nsProcess::Unload} |
||||
|
Abort |
||||
|
endcheck: |
||||
|
|
||||
|
;------------------------------------------------------------------ |
||||
|
; make sure both services aren't running |
||||
|
; |
||||
|
!insertmacro SERVICE "running" "SABnzbd" "" |
||||
|
Pop $0 ;response |
||||
|
!insertmacro SERVICE "running" "SABHelper" "" |
||||
|
Pop $1 |
||||
|
${If} $0 == true |
||||
|
${OrIf} $1 == true |
||||
|
MessageBox MB_OKCANCEL|MB_ICONEXCLAMATION $(MsgCloseSab) IDOK loop IDCANCEL exitinstall |
||||
|
; exitinstall already defined above |
||||
|
${EndIf} |
||||
|
|
||||
|
;------------------------------------------------------------------ |
||||
|
; Tell users about the service change |
||||
|
; |
||||
|
!insertmacro SERVICE "installed" "SABHelper" "" |
||||
|
Pop $0 ;response |
||||
|
${If} $0 == true |
||||
|
MessageBox MB_OKCANCEL|MB_ICONEXCLAMATION $(MsgServChange) IDOK removeservices IDCANCEL exitinstall |
||||
|
; exitinstall already defined above |
||||
|
removeservices: |
||||
|
!insertmacro SERVICE "delete" "SABHelper" "" |
||||
|
!insertmacro SERVICE "delete" "SABnzbd" "" |
||||
|
${EndIf} |
||||
|
|
||||
|
FunctionEnd |
||||
|
|
||||
|
;------------------------------------------------------------------ |
||||
|
; Show the shortcuts at end of install so user can start SABnzbd |
||||
|
; This is instead of us trying to run SAB from the installer |
||||
|
; |
||||
|
Function .onInstSuccess |
||||
|
ExecShell "open" "$SMPROGRAMS\$STARTMENU_FOLDER" |
||||
|
FunctionEnd |
||||
|
|
||||
|
;-------------------------------- |
||||
|
; begin uninstall settings/section |
||||
|
UninstallText $(MsgUninstall) |
||||
|
|
||||
|
Section "un.$(MsgDelProgram)" Uninstall |
||||
|
;make sure sabnzbd.exe isnt running..if so shut it down |
||||
|
${nsProcess::KillProcess} "SABnzbd.exe" $R0 |
||||
|
${nsProcess::Unload} |
||||
|
DetailPrint "Process Killed" |
||||
|
|
||||
|
|
||||
|
; add delete commands to delete whatever files/registry keys/etc you installed here. |
||||
|
Delete "$INSTDIR\uninstall.exe" |
||||
|
DeleteRegKey HKEY_LOCAL_MACHINE "SOFTWARE\SABnzbd" |
||||
|
DeleteRegKey HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\SABnzbd" |
||||
|
|
||||
|
${RemovePrev} "$INSTDIR" |
||||
|
|
||||
|
!insertmacro MUI_STARTMENU_GETFOLDER Application $MUI_TEMP |
||||
|
|
||||
|
Delete "$SMPROGRAMS\$MUI_TEMP\SABnzbd.lnk" |
||||
|
Delete "$SMPROGRAMS\$MUI_TEMP\Uninstall.lnk" |
||||
|
Delete "$SMPROGRAMS\$MUI_TEMP\SABnzbd - SafeMode.lnk" |
||||
|
Delete "$SMPROGRAMS\$MUI_TEMP\SABnzbd - Documentation.url" |
||||
|
RMDir "$SMPROGRAMS\$MUI_TEMP" |
||||
|
|
||||
|
Delete "$SMPROGRAMS\Startup\SABnzbd.lnk" |
||||
|
|
||||
|
Delete "$DESKTOP\SABnzbd.lnk" |
||||
|
|
||||
|
DeleteRegKey HKEY_CURRENT_USER "Software\SABnzbd" |
||||
|
|
||||
|
${unregisterExtension} ".nzb" "NZB File" |
||||
|
${RefreshShellIcons} |
||||
|
|
||||
|
SectionEnd ; end of uninstall section |
||||
|
|
||||
|
Section /o "un.$(MsgDelSettings)" DelSettings |
||||
|
DetailPrint "Uninstall settings $LOCALAPPDATA" |
||||
|
Delete "$LOCALAPPDATA\sabnzbd\sabnzbd.ini" |
||||
|
RMDir /r "$LOCALAPPDATA\sabnzbd" |
||||
|
SectionEnd |
||||
|
|
||||
|
; eof |
||||
|
|
||||
|
;-------------------------------- |
||||
|
;Language strings |
||||
|
LangString MsgShowRelNote ${LANG_ENGLISH} "Show Release Notes" |
||||
|
|
||||
|
LangString MsgSupportUs ${LANG_ENGLISH} "Support the project, Donate!" |
||||
|
|
||||
|
LangString MsgCloseSab ${LANG_ENGLISH} "Please close $\"SABnzbd.exe$\" first" |
||||
|
|
||||
|
LangString MsgServChange ${LANG_ENGLISH} "The SABnzbd Windows Service changed in SABnzbd 3.0.0. $\nYou will need to reinstall the SABnzbd service. $\n$\nClick `OK` to remove the existing services or `Cancel` to cancel this upgrade." |
||||
|
|
||||
|
LangString MsgOnly64bit ${LANG_ENGLISH} "The installer only supports 64-bit Windows, use the standalone version to run on 32-bit Windows." |
||||
|
|
||||
|
LangString MsgUninstall ${LANG_ENGLISH} "This will uninstall SABnzbd from your system" |
||||
|
|
||||
|
LangString MsgRunAtStart ${LANG_ENGLISH} "Run at startup" |
||||
|
|
||||
|
LangString MsgIcon ${LANG_ENGLISH} "Desktop Icon" |
||||
|
|
||||
|
LangString MsgAssoc ${LANG_ENGLISH} "NZB File association" |
||||
|
|
||||
|
LangString MsgDelProgram ${LANG_ENGLISH} "Delete Program" |
||||
|
|
||||
|
LangString MsgDelSettings ${LANG_ENGLISH} "Delete Settings" |
||||
|
|
||||
|
LangString MsgRemoveOld ${LANG_ENGLISH} "You cannot overwrite an existing installation. $\n$\nClick `OK` to remove the previous version or `Cancel` to cancel this upgrade." |
||||
|
|
||||
|
LangString MsgRemoveOld2 ${LANG_ENGLISH} "Your settings and data will be preserved." |
||||
|
|
||||
|
LangString MsgLangCode ${LANG_ENGLISH} "en" |
||||
|
|
||||
|
Function un.onInit |
||||
|
!insertmacro MUI_UNGETLANGUAGE |
||||
|
FunctionEnd |
@ -0,0 +1,28 @@ |
|||||
|
!define nsProcess::FindProcess `!insertmacro nsProcess::FindProcess` |
||||
|
|
||||
|
!macro nsProcess::FindProcess _FILE _ERR |
||||
|
nsProcess::_FindProcess /NOUNLOAD `${_FILE}` |
||||
|
Pop ${_ERR} |
||||
|
!macroend |
||||
|
|
||||
|
|
||||
|
!define nsProcess::KillProcess `!insertmacro nsProcess::KillProcess` |
||||
|
|
||||
|
!macro nsProcess::KillProcess _FILE _ERR |
||||
|
nsProcess::_KillProcess /NOUNLOAD `${_FILE}` |
||||
|
Pop ${_ERR} |
||||
|
!macroend |
||||
|
|
||||
|
!define nsProcess::CloseProcess `!insertmacro nsProcess::CloseProcess` |
||||
|
|
||||
|
!macro nsProcess::CloseProcess _FILE _ERR |
||||
|
nsProcess::_CloseProcess /NOUNLOAD `${_FILE}` |
||||
|
Pop ${_ERR} |
||||
|
!macroend |
||||
|
|
||||
|
|
||||
|
!define nsProcess::Unload `!insertmacro nsProcess::Unload` |
||||
|
|
||||
|
!macro nsProcess::Unload |
||||
|
nsProcess::_Unload |
||||
|
!macroend |
@ -0,0 +1,53 @@ |
|||||
|
!define registerExtension "!insertmacro registerExtension" |
||||
|
!define unregisterExtension "!insertmacro unregisterExtension" |
||||
|
!define SHCNE_ASSOCCHANGED 0x8000000 |
||||
|
!define SHCNF_IDLIST 0 |
||||
|
|
||||
|
; Source = http://nsis.sourceforge.net/File_Association |
||||
|
; Patched for SABnzbd by swi-tch |
||||
|
|
||||
|
!macro registerExtension icon executable extension description |
||||
|
Push "${icon}" ; "full path to icon.ico" |
||||
|
Push "${executable}" ; "full path to my.exe" |
||||
|
Push "${extension}" ; ".mkv" |
||||
|
Push "${description}" ; "MKV File" |
||||
|
Call registerExtension |
||||
|
!macroend |
||||
|
|
||||
|
; back up old value of .opt |
||||
|
Function registerExtension |
||||
|
!define Index "Line${__LINE__}" |
||||
|
pop $R0 ; ext name |
||||
|
pop $R1 |
||||
|
pop $R2 |
||||
|
pop $R3 |
||||
|
push $1 |
||||
|
push $0 |
||||
|
DeleteRegKey HKEY_CURRENT_USER "Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\$R1" |
||||
|
WriteRegStr HKCR $R1 "" $R0 |
||||
|
WriteRegStr HKCR $R0 "" $R0 |
||||
|
WriteRegStr HKCR "$R0\shell" "" "open" |
||||
|
WriteRegStr HKCR "$R0\DefaultIcon" "" "$R3,0" |
||||
|
WriteRegStr HKCR "$R0\shell\open\command" "" '"$R2" "%1"' |
||||
|
WriteRegStr HKCR "$R0\shell\edit" "" "Edit $R0" |
||||
|
WriteRegStr HKCR "$R0\shell\edit\command" "" '"$R2" "%1"' |
||||
|
pop $0 |
||||
|
pop $1 |
||||
|
!undef Index |
||||
|
System::Call 'Shell32::SHChangeNotify(i ${SHCNE_ASSOCCHANGED}, i ${SHCNF_IDLIST}, i 0, i 0)' |
||||
|
FunctionEnd |
||||
|
|
||||
|
!macro unregisterExtension extension description |
||||
|
Push "${extension}" ; ".mkv" |
||||
|
Push "${description}" ; "MKV File" |
||||
|
Call un.unregisterExtension |
||||
|
!macroend |
||||
|
|
||||
|
Function un.unregisterExtension |
||||
|
pop $R1 ; description |
||||
|
pop $R0 ; extension |
||||
|
!define Index "Line${__LINE__}" |
||||
|
DeleteRegKey HKCR $R0 |
||||
|
!undef Index |
||||
|
System::Call 'Shell32::SHChangeNotify(i ${SHCNE_ASSOCCHANGED}, i ${SHCNF_IDLIST}, i 0, i 0)' |
||||
|
FunctionEnd |
@ -0,0 +1,411 @@ |
|||||
|
; NSIS SERVICE LIBRARY - servicelib.nsh |
||||
|
; Version 1.8.1 - Jun 21th, 2013 |
||||
|
; Questions/Comments - dselkirk@hotmail.com |
||||
|
; |
||||
|
; Description: |
||||
|
; Provides an interface to window services |
||||
|
; |
||||
|
; Inputs: |
||||
|
; action - systemlib action ie. create, delete, start, stop, pause, |
||||
|
; continue, installed, running, status |
||||
|
; name - name of service to manipulate |
||||
|
; param - action parameters; usage: var1=value1;var2=value2;...etc. |
||||
|
; (don't forget to add a ';' after the last value!) |
||||
|
; |
||||
|
; Actions: |
||||
|
; create - creates a new windows service |
||||
|
; Parameters: |
||||
|
; path - path to service executable |
||||
|
; autostart - automatically start with system ie. 1|0 |
||||
|
; interact - interact with the desktop ie. 1|0 |
||||
|
; depend - service dependencies |
||||
|
; user - user that runs the service |
||||
|
; password - password of the above user |
||||
|
; display - display name in service's console |
||||
|
; description - Description of service |
||||
|
; starttype - start type (supersedes autostart) |
||||
|
; servicetype - service type (supersedes interact) |
||||
|
; |
||||
|
; delete - deletes a windows service |
||||
|
; start - start a stopped windows service |
||||
|
; stop - stops a running windows service |
||||
|
; pause - pauses a running windows service |
||||
|
; continue - continues a paused windows service |
||||
|
; installed - is the provided service installed |
||||
|
; Parameters: |
||||
|
; action - if true then invokes the specified action |
||||
|
; running - is the provided service running |
||||
|
; Parameters: |
||||
|
; action - if true then invokes the specified action |
||||
|
; status - check the status of the provided service |
||||
|
; |
||||
|
; Usage: |
||||
|
; Method 1: |
||||
|
; Push "action" |
||||
|
; Push "name" |
||||
|
; Push "param" |
||||
|
; Call Service |
||||
|
; Pop $0 ;response |
||||
|
; |
||||
|
; Method 2: |
||||
|
; !insertmacro SERVICE "action" "name" "param" |
||||
|
; |
||||
|
; History: |
||||
|
; 1.0 - 09/15/2003 - Initial release |
||||
|
; 1.1 - 09/16/2003 - Changed &l to i, thx brainsucker |
||||
|
; 1.2 - 02/29/2004 - Fixed documentation. |
||||
|
; 1.3 - 01/05/2006 - Fixed interactive flag and pop order (Kichik) |
||||
|
; 1.4 - 12/07/2006 - Added display and depend, fixed datatypes (Vitoco) |
||||
|
; 1.5 - 06/25/2008 - Added description of service.(DeSafe.com/liuqixing#gmail.com) |
||||
|
; 1.5.1 - 06/12/2009 - Added use of __UNINSTALL__ |
||||
|
; 1.6 - 08/02/2010 - Fixed description implementation (Anders) |
||||
|
; 1.7 - 04/11/2010 - Added get running service process id (Nico) |
||||
|
; 1.8 - 24/03/2011 - Added starttype and servicetype (Sergius) |
||||
|
; 1.8.1 - 21/06/2013 - Added dynamic ASCII & Unicode support (Zinthose) |
||||
|
|
||||
|
!ifndef SERVICELIB |
||||
|
!define SERVICELIB |
||||
|
|
||||
|
!define SC_MANAGER_ALL_ACCESS 0x3F |
||||
|
!define SC_STATUS_PROCESS_INFO 0x0 |
||||
|
!define SERVICE_ALL_ACCESS 0xF01FF |
||||
|
|
||||
|
!define SERVICE_CONTROL_STOP 1 |
||||
|
!define SERVICE_CONTROL_PAUSE 2 |
||||
|
!define SERVICE_CONTROL_CONTINUE 3 |
||||
|
|
||||
|
!define SERVICE_STOPPED 0x1 |
||||
|
!define SERVICE_START_PENDING 0x2 |
||||
|
!define SERVICE_STOP_PENDING 0x3 |
||||
|
!define SERVICE_RUNNING 0x4 |
||||
|
!define SERVICE_CONTINUE_PENDING 0x5 |
||||
|
!define SERVICE_PAUSE_PENDING 0x6 |
||||
|
!define SERVICE_PAUSED 0x7 |
||||
|
|
||||
|
!define SERVICE_KERNEL_DRIVER 0x00000001 |
||||
|
!define SERVICE_FILE_SYSTEM_DRIVER 0x00000002 |
||||
|
!define SERVICE_WIN32_OWN_PROCESS 0x00000010 |
||||
|
!define SERVICE_WIN32_SHARE_PROCESS 0x00000020 |
||||
|
!define SERVICE_INTERACTIVE_PROCESS 0x00000100 |
||||
|
|
||||
|
|
||||
|
!define SERVICE_BOOT_START 0x00000000 |
||||
|
!define SERVICE_SYSTEM_START 0x00000001 |
||||
|
!define SERVICE_AUTO_START 0x00000002 |
||||
|
!define SERVICE_DEMAND_START 0x00000003 |
||||
|
!define SERVICE_DISABLED 0x00000004 |
||||
|
|
||||
|
## Added by Zinthose for Native Unicode Support |
||||
|
!ifdef NSIS_UNICODE |
||||
|
!define APITAG "W" |
||||
|
!else |
||||
|
!define APITAG "A" |
||||
|
!endif |
||||
|
|
||||
|
!macro SERVICE ACTION NAME PARAM |
||||
|
Push '${ACTION}' |
||||
|
Push '${NAME}' |
||||
|
Push '${PARAM}' |
||||
|
!ifdef __UNINSTALL__ |
||||
|
Call un.Service |
||||
|
!else |
||||
|
Call Service |
||||
|
!endif |
||||
|
!macroend |
||||
|
|
||||
|
!macro FUNC_GETPARAM |
||||
|
Push $0 |
||||
|
Push $1 |
||||
|
Push $2 |
||||
|
Push $3 |
||||
|
Push $4 |
||||
|
Push $5 |
||||
|
Push $6 |
||||
|
Push $7 |
||||
|
Exch 8 |
||||
|
Pop $1 ;name |
||||
|
Exch 8 |
||||
|
Pop $2 ;source |
||||
|
StrCpy $0 "" |
||||
|
StrLen $7 $2 |
||||
|
StrCpy $3 0 |
||||
|
lbl_loop: |
||||
|
IntCmp $3 $7 0 0 lbl_done |
||||
|
StrLen $4 "$1=" |
||||
|
StrCpy $5 $2 $4 $3 |
||||
|
StrCmp $5 "$1=" 0 lbl_next |
||||
|
IntOp $5 $3 + $4 |
||||
|
StrCpy $3 $5 |
||||
|
lbl_loop2: |
||||
|
IntCmp $3 $7 0 0 lbl_done |
||||
|
StrCpy $6 $2 1 $3 |
||||
|
StrCmp $6 ";" 0 lbl_next2 |
||||
|
IntOp $6 $3 - $5 |
||||
|
StrCpy $0 $2 $6 $5 |
||||
|
Goto lbl_done |
||||
|
lbl_next2: |
||||
|
IntOp $3 $3 + 1 |
||||
|
Goto lbl_loop2 |
||||
|
lbl_next: |
||||
|
IntOp $3 $3 + 1 |
||||
|
Goto lbl_loop |
||||
|
lbl_done: |
||||
|
Pop $5 |
||||
|
Pop $4 |
||||
|
Pop $3 |
||||
|
Pop $2 |
||||
|
Pop $1 |
||||
|
Exch 2 |
||||
|
Pop $6 |
||||
|
Pop $7 |
||||
|
Exch $0 |
||||
|
!macroend |
||||
|
|
||||
|
!macro CALL_GETPARAM VAR NAME DEFAULT LABEL |
||||
|
Push $1 |
||||
|
Push ${NAME} |
||||
|
Call ${UN}GETPARAM |
||||
|
Pop $6 |
||||
|
StrCpy ${VAR} "${DEFAULT}" |
||||
|
StrCmp $6 "" "${LABEL}" 0 |
||||
|
StrCpy ${VAR} $6 |
||||
|
!macroend |
||||
|
|
||||
|
!macro FUNC_SERVICE UN |
||||
|
Push $0 |
||||
|
Push $1 |
||||
|
Push $2 |
||||
|
Push $3 |
||||
|
Push $4 |
||||
|
Push $5 |
||||
|
Push $6 |
||||
|
Push $7 |
||||
|
Exch 8 |
||||
|
Pop $1 ;param |
||||
|
Exch 8 |
||||
|
Pop $2 ;name |
||||
|
Exch 8 |
||||
|
Pop $3 ;action |
||||
|
;$0 return |
||||
|
;$4 OpenSCManager |
||||
|
;$5 OpenService |
||||
|
|
||||
|
StrCpy $0 "false" |
||||
|
System::Call 'advapi32::OpenSCManager${APITAG}(n, n, i ${SC_MANAGER_ALL_ACCESS}) i.r4' |
||||
|
IntCmp $4 0 lbl_done |
||||
|
StrCmp $3 "create" lbl_create |
||||
|
System::Call 'advapi32::OpenService${APITAG}(i r4, t r2, i ${SERVICE_ALL_ACCESS}) i.r5' |
||||
|
IntCmp $5 0 lbl_done |
||||
|
|
||||
|
lbl_select: |
||||
|
StrCmp $3 "delete" lbl_delete |
||||
|
StrCmp $3 "start" lbl_start |
||||
|
StrCmp $3 "stop" lbl_stop |
||||
|
StrCmp $3 "pause" lbl_pause |
||||
|
StrCmp $3 "continue" lbl_continue |
||||
|
StrCmp $3 "installed" lbl_installed |
||||
|
StrCmp $3 "running" lbl_running |
||||
|
StrCmp $3 "status" lbl_status |
||||
|
StrCmp $3 "processid" lbl_processid |
||||
|
Goto lbl_done |
||||
|
|
||||
|
; create service |
||||
|
lbl_create: |
||||
|
Push $R1 ;depend |
||||
|
Push $R2 ;user |
||||
|
Push $R3 ;password |
||||
|
Push $R4 ;servicetype/interact |
||||
|
Push $R5 ;starttype/autostart |
||||
|
Push $R6 ;path |
||||
|
Push $R7 ;display |
||||
|
Push $R8 ;description |
||||
|
|
||||
|
!insertmacro CALL_GETPARAM $R1 "depend" "n" "lbl_depend" |
||||
|
StrCpy $R1 't "$R1"' |
||||
|
lbl_depend: |
||||
|
StrCmp $R1 "n" 0 lbl_machine ;old name of depend param |
||||
|
!insertmacro CALL_GETPARAM $R1 "machine" "n" "lbl_machine" |
||||
|
StrCpy $R1 't "$R1"' |
||||
|
lbl_machine: |
||||
|
|
||||
|
!insertmacro CALL_GETPARAM $R2 "user" "n" "lbl_user" |
||||
|
StrCpy $R2 't "$R2"' |
||||
|
lbl_user: |
||||
|
|
||||
|
!insertmacro CALL_GETPARAM $R3 "password" "n" "lbl_password" |
||||
|
StrCpy $R3 't "$R3"' |
||||
|
lbl_password: |
||||
|
|
||||
|
!insertmacro CALL_GETPARAM $R4 "interact" "${SERVICE_WIN32_OWN_PROCESS}" "lbl_interact" |
||||
|
StrCpy $6 ${SERVICE_WIN32_OWN_PROCESS} |
||||
|
IntCmp $R4 0 +2 |
||||
|
IntOp $6 $6 | ${SERVICE_INTERACTIVE_PROCESS} |
||||
|
StrCpy $R4 $6 |
||||
|
lbl_interact: |
||||
|
|
||||
|
!insertmacro CALL_GETPARAM $R4 "servicetype" "$R4" "lbl_servicetype" |
||||
|
lbl_servicetype: |
||||
|
|
||||
|
!insertmacro CALL_GETPARAM $R5 "autostart" "${SERVICE_DEMAND_START}" "lbl_autostart" |
||||
|
StrCpy $6 ${SERVICE_DEMAND_START} |
||||
|
IntCmp $R5 0 +2 |
||||
|
StrCpy $6 ${SERVICE_AUTO_START} |
||||
|
StrCpy $R5 $6 |
||||
|
lbl_autostart: |
||||
|
|
||||
|
!insertmacro CALL_GETPARAM $R5 "starttype" "$R5" "lbl_starttype" |
||||
|
lbl_starttype: |
||||
|
|
||||
|
!insertmacro CALL_GETPARAM $R6 "path" "n" "lbl_path" |
||||
|
lbl_path: |
||||
|
|
||||
|
!insertmacro CALL_GETPARAM $R7 "display" "$2" "lbl_display" |
||||
|
lbl_display: |
||||
|
|
||||
|
!insertmacro CALL_GETPARAM $R8 "description" "$2" "lbl_description" |
||||
|
lbl_description: |
||||
|
|
||||
|
System::Call 'advapi32::CreateService${APITAG}(i r4, t r2, t R7, i ${SERVICE_ALL_ACCESS}, \ |
||||
|
i R4, i R5, i 0, t R6, n, n, $R1, $R2, $R3) i.r6' |
||||
|
|
||||
|
; write description of service (SERVICE_CONFIG_DESCRIPTION) |
||||
|
System::Call 'advapi32::ChangeServiceConfig2${APITAG}(ir6,i1,*t "$R8")i.R7' |
||||
|
strcmp $R7 "error" 0 lbl_descriptioncomplete |
||||
|
WriteRegStr HKLM "SYSTEM\CurrentControlSet\Services\$2" "Description" $R8 |
||||
|
lbl_descriptioncomplete: |
||||
|
|
||||
|
Pop $R8 |
||||
|
Pop $R7 |
||||
|
Pop $R6 |
||||
|
Pop $R5 |
||||
|
Pop $R4 |
||||
|
Pop $R3 |
||||
|
Pop $R2 |
||||
|
Pop $R1 |
||||
|
StrCmp $6 0 lbl_done lbl_good |
||||
|
|
||||
|
; delete service |
||||
|
lbl_delete: |
||||
|
System::Call 'advapi32::DeleteService(i r5) i.r6' |
||||
|
StrCmp $6 0 lbl_done lbl_good |
||||
|
|
||||
|
; start service |
||||
|
lbl_start: |
||||
|
System::Call 'advapi32::StartService${APITAG}(i r5, i 0, i 0) i.r6' |
||||
|
StrCmp $6 0 lbl_done lbl_good |
||||
|
|
||||
|
; stop service |
||||
|
lbl_stop: |
||||
|
Push $R1 |
||||
|
System::Call '*(i,i,i,i,i,i,i) i.R1' |
||||
|
System::Call 'advapi32::ControlService(i r5, i ${SERVICE_CONTROL_STOP}, i $R1) i' |
||||
|
System::Free $R1 |
||||
|
Pop $R1 |
||||
|
StrCmp $6 0 lbl_done lbl_good |
||||
|
|
||||
|
; pause service |
||||
|
lbl_pause: |
||||
|
Push $R1 |
||||
|
System::Call '*(i,i,i,i,i,i,i) i.R1' |
||||
|
System::Call 'advapi32::ControlService(i r5, i ${SERVICE_CONTROL_PAUSE}, i $R1) i' |
||||
|
System::Free $R1 |
||||
|
Pop $R1 |
||||
|
StrCmp $6 0 lbl_done lbl_good |
||||
|
|
||||
|
; continue service |
||||
|
lbl_continue: |
||||
|
Push $R1 |
||||
|
System::Call '*(i,i,i,i,i,i,i) i.R1' |
||||
|
System::Call 'advapi32::ControlService(i r5, i ${SERVICE_CONTROL_CONTINUE}, i $R1) i' |
||||
|
System::Free $R1 |
||||
|
Pop $R1 |
||||
|
StrCmp $6 0 lbl_done lbl_good |
||||
|
|
||||
|
; is installed |
||||
|
lbl_installed: |
||||
|
!insertmacro CALL_GETPARAM $7 "action" "" "lbl_good" |
||||
|
StrCpy $3 $7 |
||||
|
Goto lbl_select |
||||
|
|
||||
|
; is service running |
||||
|
lbl_running: |
||||
|
Push $R1 |
||||
|
System::Call '*(i,i,i,i,i,i,i) i.R1' |
||||
|
System::Call 'advapi32::QueryServiceStatus(i r5, i $R1) i' |
||||
|
System::Call '*$R1(i, i.r6)' |
||||
|
System::Free $R1 |
||||
|
Pop $R1 |
||||
|
IntFmt $6 "0x%X" $6 |
||||
|
StrCmp $6 ${SERVICE_RUNNING} 0 lbl_done |
||||
|
!insertmacro CALL_GETPARAM $7 "action" "" "lbl_good" |
||||
|
StrCpy $3 $7 |
||||
|
Goto lbl_select |
||||
|
|
||||
|
lbl_status: |
||||
|
Push $R1 |
||||
|
System::Call '*(i,i,i,i,i,i,i) i.R1' |
||||
|
System::Call 'advapi32::QueryServiceStatus(i r5, i $R1) i' |
||||
|
System::Call '*$R1(i, i .r6)' |
||||
|
System::Free $R1 |
||||
|
Pop $R1 |
||||
|
IntFmt $6 "0x%X" $6 |
||||
|
StrCpy $0 "running" |
||||
|
IntCmp $6 ${SERVICE_RUNNING} lbl_done |
||||
|
StrCpy $0 "stopped" |
||||
|
IntCmp $6 ${SERVICE_STOPPED} lbl_done |
||||
|
StrCpy $0 "start_pending" |
||||
|
IntCmp $6 ${SERVICE_START_PENDING} lbl_done |
||||
|
StrCpy $0 "stop_pending" |
||||
|
IntCmp $6 ${SERVICE_STOP_PENDING} lbl_done |
||||
|
StrCpy $0 "running" |
||||
|
IntCmp $6 ${SERVICE_RUNNING} lbl_done |
||||
|
StrCpy $0 "continue_pending" |
||||
|
IntCmp $6 ${SERVICE_CONTINUE_PENDING} lbl_done |
||||
|
StrCpy $0 "pause_pending" |
||||
|
IntCmp $6 ${SERVICE_PAUSE_PENDING} lbl_done |
||||
|
StrCpy $0 "paused" |
||||
|
IntCmp $6 ${SERVICE_PAUSED} lbl_done |
||||
|
StrCpy $0 "unknown" |
||||
|
Goto lbl_done |
||||
|
|
||||
|
lbl_processid: |
||||
|
Push $R1 |
||||
|
Push $R2 |
||||
|
System::Call '*(i,i,i,i,i,i,i,i,i) i.R1' |
||||
|
System::Call '*(i 0) i.R2' |
||||
|
System::Call "advapi32::QueryServiceStatusEx(i r5, i ${SC_STATUS_PROCESS_INFO}, i $R1, i 36, i $R2) i" |
||||
|
System::Call "*$R1(i,i,i,i,i,i,i, i .r0)" |
||||
|
System::Free $R2 |
||||
|
System::Free $R1 |
||||
|
Pop $R2 |
||||
|
Pop $R1 |
||||
|
Goto lbl_done |
||||
|
|
||||
|
lbl_good: |
||||
|
StrCpy $0 "true" |
||||
|
lbl_done: |
||||
|
IntCmp $5 0 +2 |
||||
|
System::Call 'advapi32::CloseServiceHandle(i r5) n' |
||||
|
IntCmp $4 0 +2 |
||||
|
System::Call 'advapi32::CloseServiceHandle(i r4) n' |
||||
|
Pop $4 |
||||
|
Pop $3 |
||||
|
Pop $2 |
||||
|
Pop $1 |
||||
|
Exch 3 |
||||
|
Pop $5 |
||||
|
Pop $7 |
||||
|
Pop $6 |
||||
|
Exch $0 |
||||
|
!macroend |
||||
|
|
||||
|
Function Service |
||||
|
!insertmacro FUNC_SERVICE "" |
||||
|
FunctionEnd |
||||
|
|
||||
|
Function GetParam |
||||
|
!insertmacro FUNC_GETPARAM |
||||
|
FunctionEnd |
||||
|
|
||||
|
!undef APITAG |
||||
|
!endif |
Binary file not shown.
Binary file not shown.
Loading…
Reference in new issue