Cmdr/install.py

372 lines
13 KiB
Python
Raw Normal View History

#!/usr/bin/python3
import os
import subprocess
import shutil
import platform
import sys
import zipfile
import binascii
import tempfile
def cd():
current_dir = os.path.dirname(__file__)
if current_dir != "":
os.chdir(current_dir)
def get_default_install_dir(app_target, app_name):
if platform.system() == "Linux":
return "/opt/" + app_target
else:
return os.environ['ProgramFiles'] + "\\" + app_name
def get_default_installer_path(app_ver, app_name):
return os.path.expanduser("~") + os.sep + app_name + "-" + app_ver + ".py"
def get_install_dir(app_target, app_name):
path = get_default_install_dir(app_target, app_name)
print("The default install directory is: " + path)
while(True):
ans = input("Do you want to change it? (y/n): ")
if ans == "y" or ans == "Y":
path = input("Enter a new install directory (leave blank to go back to the default): ")
path = os.path.normpath(path)
break
elif ans == "n" or ans == "N":
break
if path == "":
return get_default_install_dir(app_target, app_name)
else:
return path
def get_installer_path(app_ver, app_name):
path = get_default_installer_path(app_ver, app_name)
print("The built .py installer will placed here: " + path)
while(True):
ans = input("Do you want to change the path? (y/n): ")
if ans == "y" or ans == "Y":
path = input("Enter a new path (leave blank to go back to the default): ")
path = os.path.normpath(path)
break
elif ans == "n" or ans == "N":
break
if path == "":
return get_default_installer_path(app_ver, app_name)
else:
return path
def make_install_dir(path):
try:
if not os.path.exists(path):
os.makedirs(path)
return True
except:
print("Failed to create the install directory, please make sure you are runnning this script with admin rights.")
return 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):
if platform.system() == "Linux":
if not os.path.exists("app_dir/linux"):
print("An app_dir for the Linux platform could not be found.")
else:
install_dir = get_install_dir(app_target, app_name)
if os.path.exists(install_dir + "/uninstall.sh"):
subprocess.run([install_dir + "/uninstall.sh"])
if make_install_dir(install_dir):
if not os.path.exists("/var/opt/" + app_target):
os.makedirs("/var/opt/" + app_target)
text_template_deploy("app_dir/linux/" + app_target + ".sh", install_dir + "/" + app_target + ".sh", install_dir, app_name, app_target)
text_template_deploy("app_dir/linux/uninstall.sh", install_dir + "/uninstall.sh", install_dir, app_name, app_target)
text_template_deploy("app_dir/linux/" + app_target + ".desktop", "/usr/share/applications/" + app_target + ".desktop", install_dir, app_name, app_target)
for image_res in ["8x8", "16x16", "22x22", "24x24", "32x32", "36x36", "42x42", "48x48", "64x64", "192x192", "256x256", "512x512"]:
src = "app_dir/icons/" + image_res + ".png"
dst = "/usr/share/icons/hicolor/" + image_res
if os.path.exists(dst):
verbose_copy(src, dst + "/apps/" + app_target + ".png")
subprocess.run(["chmod", "644", dst + "/apps/" + app_target + ".png"])
verbose_copy("app_dir/icons/scalable.svg", "/usr/share/icons/hicolor/scalable/apps/" + app_target + ".svg")
verbose_copy("app_dir/linux/" + app_target, install_dir + "/" + app_target)
verbose_copy("app_dir/linux/lib", install_dir + "/lib")
verbose_copy("app_dir/linux/platforms", install_dir + "/platforms")
verbose_copy("app_dir/linux/xcbglintegrations", install_dir + "/xcbglintegrations")
verbose_create_symmlink(install_dir + "/" + app_target + ".sh", "/usr/bin/" + app_target)
subprocess.run(["chmod", "644", "/usr/share/icons/hicolor/scalable/apps/" + app_target + ".svg"])
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"])
print("Installation finished. If you ever need to uninstall this application, run this command with root rights:")
print(" sh " + install_dir + "/uninstall.sh\n")
elif platform.system() == "Windows":
if not os.path.exists("app_dir\\windows"):
print("An app_dir for the Windows platform could not be found.")
else:
install_dir = get_install_dir(app_target, app_name)
if os.path.exists(install_dir + "\\uninstall.bat"):
subprocess.run([install_dir + "\\uninstall.bat"])
if os.path.exists(install_dir):
# this block is here to make sure the install_dir is deleted
# if/when the uninstall.bat fails to do so. in my test machine,
# the .bat script will delete install_dir if run directly but
# not when called through subprocess.run() for some reason.
shutil.rmtree(install_dir)
if make_install_dir(install_dir):
verbose_copy("app_dir\\windows", install_dir)
verbose_copy("app_dir\\icons\\win_icon.ico", install_dir + "\\icon.ico")
text_template_deploy("app_dir\\windows\\uninstall.bat", install_dir + "\\uninstall.bat", install_dir, app_name, app_target)
text_template_deploy("app_dir\\windows\\icon.vbs", install_dir + "\\icon.vbs", install_dir, app_name, app_target)
text_sub_copy_file(install_dir + "\\icon.vbs", install_dir + "\\icon.vbs", "%SystemDrive%", os.environ['SystemDrive'], 0)
os.system("\"" + install_dir + "\\icon.vbs\"")
print("Installation finished. If you ever need to uninstall this application, run this batch file with admin rights:")
print(" " + install_dir + "\\uninstall.bat\n")
else:
print("The platform you are running in is not compatible.")
print(" output from platform.system() = " + platform.system())
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_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", 7700)
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")
print("Finished.")
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 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:
sfx()
elif "-local" in sys.argv:
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":
local_install(app_target, app_name)
break
elif opt == "2":
make_install(app_ver, app_name)
break
elif opt == "3":
break
if __name__ == "__main__":
main(is_sfx=False)