diff --git a/debian/postinst b/debian/postinst index dffcc5d..53f0afa 100755 --- a/debian/postinst +++ b/debian/postinst @@ -10,14 +10,13 @@ def col(id): return "\033[0m" # Import required modules +import fileinput import subprocess -import time import sys import os import re -import signal -import fileinput -import urllib.parse +import tarfile +from shutil import rmtree, which # Don't run unless we need to configure the install # Will also happen on upgrade but we will catch that later on @@ -35,6 +34,7 @@ def handleStatus(status): print(col(3) + "Error while running last command" + col(0)) sys.exit(1) +sc = subprocess.call # We're not in fresh configuration mode so don't continue the setup if not os.path.exists("/tmp/howdy_picked_device"): @@ -78,64 +78,108 @@ picked = in_file.read() in_file.close() # Remove the temporary file -subprocess.call(["rm /tmp/howdy_picked_device"], shell=True) +os.unlink("/tmp/howdy_picked_device") log("Upgrading pip to the latest version") # Update pip -handleStatus(subprocess.call(["pip3 install --upgrade pip"], shell=True)) +handleStatus(sc(["pip3", "install", "--upgrade", "pip"])) -log("Cloning dlib") +dlib_archive = '/tmp/dlib_latest.tar.gz' -# Clone the dlib git to /tmp, but only the last commit -handleStatus(subprocess.call(["git", "clone", "--depth", "1", "https://github.com/davisking/dlib.git", "/tmp/dlib_clone"])) +log('Downloading dlib') + +loader = which('curl') +LOADER_CMD = None +if loader: + LOADER_CMD = [loader, '--silent', '--retry', '5', '--location', '--output'] +else: + loader = which('wget') + LOADER_CMD = [loader, '--quiet', '--tries', '5', '--output-document'] + +cmd = LOADER_CMD + [dlib_archive, 'https://api.github.com/repos/davisking/dlib/tarball/latest'] + +handleStatus(sc(cmd)) + +DLIB_DIR = None + +excludes = re.compile( + 'davisking-dlib-\w+/(dlib/(http_client|java|matlab|test/)|' + '(docs|examples|python_examples)|' + 'tools/(archive|convert_dlib_nets_to_caffe|htmlify|imglab|python/test|visual_studio_natvis))' +) +with tarfile.open(dlib_archive) as tf: + for item in tf: + # tarball contains directory davisking-dlib-, so peek into archive for the name + if not DLIB_DIR: + DLIB_DIR = item.name + + # extract only files sufficent for building + if not excludes.match(item.name): + tf.extract(item, '/tmp') + +os.unlink(dlib_archive) log("Building dlib") -# Start the build without GPU -handleStatus(subprocess.call(["cd /tmp/dlib_clone/; python3 setup.py install --yes USE_AVX_INSTRUCTIONS --no DLIB_USE_CUDA"], shell=True)) +# Start the build +cmd = ["python3", "setup.py", "install"] + +flags = '' +with open('/proc/cpuinfo') as info: + for line in info: + if 'flags' in line: + flags = line + break + +if 'avx' in flags: + cmd += ["--yes", "USE_AVX_INSTRUCTIONS"] +elif 'sse4' in flags: + cmd += ["--yes", "USE_SSE4_INSTRUCTIONS"] +elif 'sse3' in flags: + cmd += ["--yes", "USE_SSE3_INSTRUCTIONS"] +elif 'sse2' in flags: + cmd += ["--yes", "USE_SSE2_INSTRUCTIONS"] + +sp = subprocess.run(cmd, cwd=DLIB_DIR, stderr=subprocess.STDOUT) +handleStatus(sp.returncode) + +# simple check for CUDA +cuda_used = 'DLIB WILL USE CUDA' in sp.stdout log("Cleaning up dlib") # Remove the no longer needed git clone -handleStatus(subprocess.call(["rm", "-rf", "/tmp/dlib_clone"])) -print("Temporary dlib files removed") +del sp +rmtree(DLIB_DIR) -log("Installing python dependencies") +log("Temporary dlib files removed") -# Install direct dependencies so pip does not freak out with the manual dlib install -handleStatus(subprocess.call(["pip3", "install", "--cache-dir", "/tmp/pip_howdy", "face_recognition_models==0.3.0", "Click>=6.0", "numpy", "Pillow"])) - -log("Installing face_recognition") - -# Install face_recognition though pip -handleStatus(subprocess.call(["pip3", "install", "--cache-dir", "/tmp/pip_howdy", "--no-deps", "face_recognition==1.2.2"])) - -try: - import cv2 -except Exception as e: - log("Reinstalling opencv2") - handleStatus(subprocess.call(["pip3", "install", "opencv-python"])) log("Configuring howdy") # Manually change the camera id to the one picked -for line in fileinput.input(["/lib/security/howdy/config.ini"], inplace = 1): - print(line.replace("device_path = none", "device_path = " + picked), end="") +for line in fileinput.input(["/lib/security/howdy/config.ini"], inplace=1): + print( + line + .replace("device_path = none", "device_path = " + picked) + .replace("use_cnn = false", "use_cnn = " + str(cuda_used).lower()), + end="" + ) print("Camera ID saved") # Secure the howdy folder -handleStatus(subprocess.call(["chmod 744 -R /lib/security/howdy/"], shell=True)) +handleStatus(sc(["chmod 744 -R /lib/security/howdy/"], shell=True)) # Allow anyone to execute the python CLI -handleStatus(subprocess.call(["chmod 755 /lib/security/howdy"], shell=True)) -handleStatus(subprocess.call(["chmod 755 /lib/security/howdy/cli.py"], shell=True)) -handleStatus(subprocess.call(["chmod 755 -R /lib/security/howdy/cli"], shell=True)) +os.chmod('/lib/security/howdy', 0o755) +os.chmod('/lib/security/howdy/cli.py', 0o755) +handleStatus(sc(["chmod 755 -R /lib/security/howdy/cli"], shell=True)) print("Permissions set") # Make the CLI executable as howdy -handleStatus(subprocess.call(["ln -s /lib/security/howdy/cli.py /usr/local/bin/howdy"], shell=True)) -handleStatus(subprocess.call(["chmod +x /usr/local/bin/howdy"], shell=True)) +os.symlink("/lib/security/howdy/cli.py", "/usr/local/bin/howdy") +os.chmod("/usr/local/bin/howdy", 0o755) print("Howdy command installed") log("Adding howdy as PAM module") @@ -149,10 +193,7 @@ inserted = False # Open the PAM config file with open("/etc/pam.d/common-auth") as fp: - # Read the first line - line = fp.readline() - - while line: + for line in fp.readline(): # Add the line to the output directly, we're not deleting anything outlines.append(line) @@ -179,9 +220,6 @@ with open("/etc/pam.d/common-auth") as fp: # Mark as inserted inserted = True - # Go to the next line - line = fp.readline() - # Print a file Header print("\033[33m" + ">>> START OF /etc/pam.d/common-auth" + "\033[0m") @@ -196,19 +234,18 @@ print("\033[33m" + ">>> END OF /etc/pam.d/common-auth" + "\033[0m" + "\n") if "HOWDY_NO_PROMPT" not in os.environ: # Ask the user if this change is okay print("Lines will be insterted in /etc/pam.d/common-auth as shown above") - ans = input("Apply this change? [y/N]: ") + ans = input("Apply this change? [y/N]: ").strip().lower() # Abort the whole thing if it's not - if ans.lower().strip() != "y" or ans.lower().strip() == "yes": + if ans not in ("y", "yes"): print("Interpreting as a \"NO\", aborting") sys.exit(1) print("Adding lines to PAM\n") # Write to PAM -common_auth = open("/etc/pam.d/common-auth", "w") -common_auth.write("".join(outlines)) -common_auth.close() +with open("/etc/pam.d/common-auth", "w") as common_auth: + common_auth.write("".join(outlines)) # Sign off print("Installation complete.")