-updated ramdisk class so the project is compilable on older qt builds < v6.5. -more fixes to build.py to work with newer versions of qt and less manual steps to take.
356 lines
11 KiB
Python
Executable File
356 lines
11 KiB
Python
Executable File
#!/usr/bin/python3
|
|
|
|
import os
|
|
import subprocess
|
|
import shutil
|
|
import platform
|
|
import sys
|
|
import zipfile
|
|
import binascii
|
|
import tempfile
|
|
import pwd
|
|
|
|
def cd():
|
|
current_dir = os.path.dirname(__file__)
|
|
|
|
if current_dir != "":
|
|
os.chdir(current_dir)
|
|
|
|
def get_default_installer_path(app_ver, app_name):
|
|
if not os.path.exists("installers"):
|
|
os.makedirs("installers")
|
|
|
|
return "installers/" + app_name + "-" + app_ver + "-" + platform.system() + "-" + platform.machine() + ".run"
|
|
|
|
def make_install_dir(path, false_on_fail):
|
|
try:
|
|
if not os.path.exists(path):
|
|
os.makedirs(path)
|
|
|
|
return True
|
|
|
|
except:
|
|
if false_on_fail:
|
|
print("Failed to create directory: " + path + ", please make sure you are runnning this script with admin rights.")
|
|
|
|
return False
|
|
|
|
else:
|
|
return True
|
|
|
|
def make_app_dirs(app_target):
|
|
return make_install_dir("/etc/" + app_target, True) and make_install_dir("/opt/" + app_target, True) and make_install_dir("/var/local/" + app_target, False)
|
|
|
|
def replace_bin(binary, old_bin, new_bin, offs):
|
|
while(True):
|
|
try:
|
|
index = binary.index(old_bin, offs)
|
|
binary = binary[:index] + new_bin + binary[index + len(old_bin):]
|
|
|
|
except ValueError:
|
|
break
|
|
|
|
return binary
|
|
|
|
def bin_sub_copy_file(src, dst, old_bin, new_bin, offs):
|
|
binary = bytearray()
|
|
|
|
with open(src, "rb") as rd_file:
|
|
binary = rd_file.read()
|
|
binary = replace_bin(binary, old_bin, new_bin, offs)
|
|
|
|
with open(dst, "wb") as wr_file:
|
|
wr_file.write(binary)
|
|
|
|
def text_sub_copy_file(src, dst, old_text, new_text, offs):
|
|
bin_sub_copy_file(src, dst, old_text.encode("utf-8"), new_text.encode("utf-8"), offs)
|
|
|
|
def text_template_deploy(src, dst, install_dir, app_name, app_target):
|
|
print("dep: " + dst)
|
|
|
|
text_sub_copy_file(src, dst, "$install_dir", install_dir, 0)
|
|
text_sub_copy_file(dst, dst, "$app_name", app_name, 0)
|
|
text_sub_copy_file(dst, dst, "$app_target", app_target, 0)
|
|
|
|
def verbose_copy(src, dst):
|
|
print("cpy: " + src + " --> " + dst)
|
|
|
|
if os.path.isdir(src):
|
|
files = os.listdir(src)
|
|
|
|
if not os.path.exists(dst):
|
|
os.makedirs(dst)
|
|
|
|
for file in files:
|
|
tree_src = src + os.path.sep + file
|
|
tree_dst = dst + os.path.sep + file
|
|
|
|
if os.path.isdir(tree_src):
|
|
if not os.path.exists(tree_dst):
|
|
os.makedirs(tree_dst)
|
|
|
|
verbose_copy(tree_src, tree_dst)
|
|
|
|
else:
|
|
shutil.copyfile(src, dst)
|
|
|
|
def verbose_create_symmlink(src, dst):
|
|
print("lnk: " + src + " --> " + dst)
|
|
|
|
if os.path.exists(dst):
|
|
os.remove(dst)
|
|
|
|
os.symlink(src, dst)
|
|
|
|
def local_install(app_target, app_name):
|
|
install_dir = "/opt/" + app_target
|
|
|
|
if os.path.exists(install_dir + "/uninstall.sh"):
|
|
subprocess.run([install_dir + "/uninstall.sh"])
|
|
|
|
if make_app_dirs(app_target):
|
|
text_template_deploy("app_dir/" + app_target + ".sh", install_dir + "/" + app_target + ".sh", install_dir, app_name, app_target)
|
|
text_template_deploy("app_dir/" + app_target + ".service", "/lib/systemd/system/" + app_target + ".service", install_dir, app_name, app_target)
|
|
text_template_deploy("app_dir/uninstall.sh", install_dir + "/uninstall.sh", install_dir, app_name, app_target)
|
|
|
|
verbose_copy("app_dir/" + app_target, install_dir + "/" + app_target)
|
|
verbose_copy("app_dir/lib", install_dir + "/lib")
|
|
|
|
verbose_create_symmlink(install_dir + "/" + app_target + ".sh", "/usr/bin/" + app_target)
|
|
|
|
subprocess.run(["chmod", "755", install_dir + "/" + app_target + ".sh"])
|
|
subprocess.run(["chmod", "755", install_dir + "/" + app_target])
|
|
subprocess.run(["chmod", "755", install_dir + "/uninstall.sh"])
|
|
subprocess.run(["chmod", "644", "/lib/systemd/system/" + app_target + ".service"])
|
|
|
|
if not user_exists(app_target):
|
|
subprocess.run(["sudo", "useradd", "-r", app_target])
|
|
subprocess.run(["sudo", "usermod", "-aG", "video", app_target])
|
|
|
|
subprocess.run(["chown", app_target + ":" + app_target, "/var/local/" + app_target])
|
|
|
|
subprocess.run(["systemctl", "start", app_target])
|
|
subprocess.run(["systemctl", "enable", app_target])
|
|
|
|
print("Installation finished. If you ever need to uninstall this application, run this command with root rights:")
|
|
print(" sh " + install_dir + "/uninstall.sh\n")
|
|
|
|
def dir_tree(path):
|
|
ret = []
|
|
|
|
if os.path.isdir(path):
|
|
for entry in os.listdir(path):
|
|
full_path = os.path.join(path, entry)
|
|
|
|
if os.path.isdir(full_path):
|
|
for sub_dir_file in dir_tree(full_path):
|
|
ret.append(sub_dir_file)
|
|
|
|
else:
|
|
ret.append(full_path)
|
|
|
|
return ret
|
|
|
|
def to_hex(data):
|
|
return str(binascii.hexlify(data))[2:-1]
|
|
|
|
def from_hex(text_line):
|
|
return binascii.unhexlify(text_line)
|
|
|
|
def make_install(app_ver, app_name):
|
|
path = get_default_installer_path(app_ver, app_name)
|
|
|
|
with zipfile.ZipFile("app_dir.zip", "w", compression=zipfile.ZIP_DEFLATED) as zip_file:
|
|
print("Compressing app_dir --")
|
|
|
|
for file in dir_tree("app_dir"):
|
|
print("adding file: " + file)
|
|
zip_file.write(file)
|
|
|
|
text_sub_copy_file(__file__, path, "main(is_sfx=False)", "main(is_sfx=True)\n\n\n", 10322)
|
|
|
|
with open(path, "a") as dst_file, open("app_dir.zip", "rb") as src_file:
|
|
print("Packing the compressed app_dir into the sfx script file --")
|
|
|
|
dst_file.write("# APP_DIR\n")
|
|
|
|
stat = os.stat("app_dir.zip")
|
|
|
|
while(True):
|
|
buffer = src_file.read(4000000)
|
|
|
|
if len(buffer) != 0:
|
|
dst_file.write("# " + to_hex(buffer) + "\n")
|
|
|
|
print(str(src_file.tell()) + "/" + str(stat.st_size))
|
|
|
|
if len(buffer) < 4000000:
|
|
break
|
|
|
|
os.remove("app_dir.zip")
|
|
|
|
subprocess.run(["chmod", "+x", path])
|
|
|
|
print("Finished packing the app.")
|
|
print("Installer: " + path)
|
|
|
|
def sfx():
|
|
abs_sfx_path = os.path.abspath(__file__)
|
|
mark_found = False
|
|
|
|
os.chdir(tempfile.gettempdir())
|
|
|
|
with open(abs_sfx_path) as packed_file, open("app_dir.zip", "wb") as zip_file:
|
|
stat = os.stat(abs_sfx_path)
|
|
|
|
print("Unpacking the app_dir compressed file from the sfx script.")
|
|
|
|
while(True):
|
|
line = packed_file.readline()
|
|
|
|
if not line:
|
|
break
|
|
|
|
elif mark_found:
|
|
zip_file.write(from_hex(line[2:-1]))
|
|
|
|
print(str(packed_file.tell()) + "/" + str(stat.st_size))
|
|
|
|
else:
|
|
if line == "# APP_DIR\n":
|
|
mark_found = True
|
|
|
|
print("Done.")
|
|
|
|
if not mark_found:
|
|
print("The app_dir mark was not found, unable to continue.")
|
|
|
|
else:
|
|
with zipfile.ZipFile("app_dir.zip", "r", compression=zipfile.ZIP_DEFLATED) as zip_file:
|
|
print("De-compressing app_dir --")
|
|
|
|
zip_file.extractall()
|
|
|
|
print("Preparing for installation.")
|
|
|
|
os.remove("app_dir.zip")
|
|
|
|
with open("app_dir" + os.sep + "info.txt") as info_file:
|
|
info = info_file.read().split("\n")
|
|
|
|
local_install(info[0], info[2])
|
|
shutil.rmtree("app_dir")
|
|
|
|
def get_like_distro():
|
|
info = platform.freedesktop_os_release()
|
|
ids = [info["ID"]]
|
|
|
|
if "ID_LIKE" in info:
|
|
# ids are space separated and ordered by precedence
|
|
ids.extend(info["ID_LIKE"].split())
|
|
|
|
return ids
|
|
|
|
def list_installed_packages():
|
|
like_distro = get_like_distro()
|
|
|
|
if ("ubuntu" in like_distro) or ("debian" in like_distro) or ("linuxmint" in like_distro):
|
|
return str(subprocess.check_output(["apt", "list", "--installed"]), 'utf-8')
|
|
|
|
elif ("fedora" in like_distro) or ("rhel" in like_distro):
|
|
return str(subprocess.check_output(["dnf", "list", "installed"]), 'utf-8')
|
|
|
|
elif ("arch" in like_distro):
|
|
return str(subprocess.check_output(["pacman", "-Q"]), 'utf-8')
|
|
|
|
else:
|
|
print("Warning: unable to determine a package manager for this platform.")
|
|
|
|
return []
|
|
|
|
|
|
def list_of_words_in_text(list_of_words, text_body):
|
|
for word in list_of_words:
|
|
if not word in text_body:
|
|
return False
|
|
|
|
return True
|
|
|
|
def user_exists(user_name):
|
|
try:
|
|
pwd.getpwnam(user_name)
|
|
|
|
return True
|
|
|
|
except KeyError:
|
|
return False
|
|
|
|
def platform_setup():
|
|
ins_packages = list_installed_packages()
|
|
like_distro = get_like_distro()
|
|
dep_pkgs_a = ["pkg-config"]
|
|
dep_pkgs_b = ["ffmpeg", "libfuse-dev", "fuse3", "imagemagick"]
|
|
|
|
if not list_of_words_in_text(dep_pkgs_a, ins_packages) or not list_of_words_in_text(dep_pkgs_b, ins_packages):
|
|
if ("ubuntu" in like_distro) or ("debian" in like_distro) or ("linuxmint" in like_distro):
|
|
subprocess.run(["sudo", "apt", "update", "-y"])
|
|
subprocess.run(["sudo", "apt", "install", "-y"] + dep_pkgs_a)
|
|
subprocess.run(["sudo", "apt", "install", "-y"] + dep_pkgs_b)
|
|
|
|
elif ("fedora" in like_distro) or ("rhel" in like_distro):
|
|
subprocess.run(["sudo", "dnf", "install", "-y"] + dep_pkgs_a)
|
|
subprocess.run(["sudo", "dnf", "install", "-y"] + dep_pkgs_b)
|
|
|
|
elif ("arch" in like_distro):
|
|
subprocess.run(["sudo", "pacman", "-S", "--noconfirm"] + dep_pkgs_a)
|
|
subprocess.run(["sudo", "pacman", "-S", "--noconfirm"] + dep_pkgs_b)
|
|
|
|
def main(is_sfx):
|
|
cd()
|
|
|
|
app_target = ""
|
|
app_ver = ""
|
|
app_name = ""
|
|
|
|
if not is_sfx:
|
|
with open("app_dir" + os.sep + "info.txt") as info_file:
|
|
info = info_file.read().split("\n")
|
|
|
|
app_target = info[0]
|
|
app_ver = info[1]
|
|
app_name = info[2]
|
|
|
|
if is_sfx:
|
|
platform_setup()
|
|
sfx()
|
|
|
|
elif "--local" in sys.argv:
|
|
platform_setup()
|
|
local_install(app_target, app_name)
|
|
|
|
elif "--installer" in sys.argv:
|
|
make_install(app_ver, app_name)
|
|
|
|
else:
|
|
print("Do you want to install onto this machine or create an installer?")
|
|
print("[1] local machine")
|
|
print("[2] create installer")
|
|
print("[3] exit")
|
|
|
|
while(True):
|
|
opt = input("select an option: ")
|
|
|
|
if opt == "1":
|
|
subprocess.run(["sudo", "python3", "install.py", "--local"])
|
|
break
|
|
|
|
elif opt == "2":
|
|
subprocess.run(["python3", "install.py", "--installer"])
|
|
break
|
|
|
|
elif opt == "3":
|
|
break
|
|
|
|
if __name__ == "__main__":
|
|
main(is_sfx=False)
|