Skip to content

Commit

Permalink
Merge pull request #23 from dwyl/install
Browse files Browse the repository at this point in the history
Automatic install scripts for #11
  • Loading branch information
th0mas authored Oct 2, 2020
2 parents c867228 + 82e0fe1 commit 7e94861
Show file tree
Hide file tree
Showing 2 changed files with 301 additions and 0 deletions.
25 changes: 25 additions & 0 deletions go.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#!/bin/bash

MANAGE_SCRIPT_URL="https://raw.githubusercontent.com/dwyl/smart-home-security-system/install/manage.py"

check_for_python() {
if ! command -v python3 >/dev/null
then
echo "Can't find a Python 3 install, which is needed for the setup script."
exit 1
else
echo "Python3 found, continuing..."
fi

}

install() {
check_for_python
echo "Downloading install manager..."
curl -sL $MANAGE_SCRIPT_URL -o manage.py
chmod +x manage.py
echo "Running installer..."
python3 manage.py install
}

install
276 changes: 276 additions & 0 deletions manage.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,276 @@
#!/usr/bin/python3
# Management script for dwyl smart home

import argparse
import subprocess
import os
import sys
import shlex

from contextlib import contextmanager

# Global verbose flag to toggle on/off verbose output
VERBOSE=True

# Declare global constants
HUB_SERVER_REPO="https://github.com/dwyl/smart-home-auth-server.git"
FIRMWARE_REPO="https://github.com/dwyl/smart-home-firmware.git"

# Declare the start message here so we don't clog up the rest of the code
START_MESSAGE="""
Smart home is now setup for development.
To setup your development evironment:
source .env
To run the hub server:
cd smart-home-auth-server
mix phx.server
To run the firmware development build:
cd smart-home-firmware
iex -S mix
If these error, please run:
./manage.py clean
./manage.py --verbose install
and file and issue with the output.
"""

# Emulate a shells `cd`
# https://stackoverflow.com/questions/431684/
@contextmanager
def cd(newdir):
prevdir = os.getcwd()
os.chdir(os.path.expanduser(newdir))
try:
yield
finally:
os.chdir(prevdir)

# Helper function to allow for same line I/O without repeating ourselves
def out(line):
print(line, end="", flush=True)

# Run a command, and display the result based on wether VERBOSE is set or not
def run(cmd):
return subprocess.run(shlex.split(cmd), capture_output=not VERBOSE)

def write_env(key):
lines = []
try:
with open(".env", "r+") as f:
keys = filter(
lambda x: not "AUTH_API_KEY=" in x,
f.readlines()
)
lines = [x for x in keys]
except FileNotFoundError:
pass

lines.append("AUTH_API_KEY=" + key + "\n")

with open(".env", "w") as f:
f.writelines(lines)

# Dowload required files from github.
def download():
out("Downloading Hub Server...")
process = run("git clone " + HUB_SERVER_REPO)
out("OK\n")

out("Downloading firmware...")
process = run("git clone " + FIRMWARE_REPO)
out("OK\n")

# Prompt user for an auth API key so we can finish setup
def get_api_key():
print("AUTH_API_KEY not set!\n")
print("No Auth API key set, found out how at:")
print("https://git.io/JJ6sS")
print("")
print("Please enter your API key once your done to continue setup")
key = input(">")
os.environ["AUTH_API_KEY"] = key

return key

# Check if we have an auth API key set before continuing
def check_for_api_key():
key = os.environ.get("AUTH_API_KEY", None)
if key:
pass
else:
key = get_api_key()

write_env(key)

# Get and display a local API development token for the user
def gen_token():
with cd("./smart-home-auth-server"):
proc = subprocess.run(["mix", "smart_home.gen_token"], capture_output=True)
print("Your development API Bearer token: \n")
print(proc.stdout.decode(sys.stdout.encoding))
print("\nSet this as the authorization header in your favourite API development tool.")

# Install brew, otherwise exit
def must_install_brew():
if input("Homebrew is needed to install dependencies, install? (y/N)")[0] == "y":
run("/bin/bash -c \"$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)\"")
else:
exit(1)

def check_software(software):
exists = True
try:
subprocess.run(shlex.split(software), capture_output=True)
except FileNotFoundError:
exists = False
return exists

# Check that necessary dependencies are installed
def check_deps():
deps = {"elixir": False, "brew": False, "psql": False, "node": False}
# Check for brew
out("Checking for homebrew (to install dependencies)...")
if check_software("brew"):
out("OK\n")
deps["brew"]=True
else:
out("Error - You may need to install dependencies manually!\n")

# Check for elixir
out("Checking for Elixir...")
if check_software("elixir -v"):
out("OK!\n")
deps["elixir"] = True
else:
out("ERROR\n")

# check for postgres
out("Checking for PostgreSQL...")
if check_software("postgres -V"):
out("OK\n")
deps["psql"] = True
else:
out("ERROR\n")

out("Checking for node.js...")
if check_software("node --version"):
out("OK\n")
deps["node"] = True
else:
out("ERROR")

return deps

def install_deps(brew, missing):
if not brew:
must_install_brew()

if input("Do you want to install missing dependencies using brew? (y/N)")[0] == "y":
out("Attempting to install...\n")
else:
out("\nPlease ensure dependenices are installed or there could be errors!\n")
return # Implicit return seems nicer here...

if missing["elixir"]:
out("Installing Elixir...\n")
run("brew install elixir")

if missing["psql"]:
out("Installing PostgreSQL...\n")
run("brew install postgres")

if missing["node"]:
out("Installing node...\n")
run("brew install node")

def install_nerves_dependencies():
if input("Do you want to install build dependencies for nerves? (fwup squashfs coreutils xz pkg-config)? (y/N)")[0] == "y":
run("brew install fwup squashfs coreutils xz pkg-config")
else:
out("NERVES WILL FAIL TO BUILD WITHOUT DEPS INSTALLED \n")
out("https://hexdocs.pm/nerves/installation.html#content\n")

def pre_install():
deps = check_deps()
brew = deps["brew"]

del deps["brew"]

missing = [ key for key in deps if deps[key] == False ]

if len(missing) > 0:
out("Missing dependencies!\n Would you like to install them now?")

if input("(y/N)")[0] == "y":
install_deps(brew, missing)
else:
out("Please install: " + " ,".join(missing) + "\n Then continue with download.")
exit(1)


# Setup deps etc. for firmware
def setup():
# Setup firmware
with cd("./smart-home-firmware"):
out("Installing firmware deps...")
install_nerves_dependencies()
run("mix archive.install hex nerves_bootstrap")
run("mix deps.get")
out("OK\n")

with cd("./smart-home-auth-server"):
out("Installing hub server deps...")
run("mix setup")
out("OK\n")


# Run necessary install functions
def install():
download()
pre_install()
check_for_api_key()
setup()
gen_token()

print(START_MESSAGE)

# Clean up everything we've installed
def clean():
out("Cleaning up...")
run("rm -rf ./smart-home-firmware")
run("rm -rf ./smart-home-auth-server")
run("rm .env")
out("OK\n")

# Declare our command parsers and run the intended function
def main():
parser = argparse.ArgumentParser(description="Manage Dwyl smart home install")
subparsers = parser.add_subparsers(help="Commands")
subparsers.default = "help"

install_parser = subparsers.add_parser("install", help="Install the smart home system")
install_parser.set_defaults(func=install)

clean_parser = subparsers.add_parser("clean", help="Clean up everything")
clean_parser.set_defaults(func=clean)

gen_token_parser = subparsers.add_parser("gen-token", help="Genereate a JWT token for development")
gen_token_parser.set_defaults(func=gen_token)

if len(sys.argv)==1:
parser.print_usage(sys.stderr)
sys.exit(1)

args = parser.parse_args()


if args.func:
args.func()

# Don't run main if we're called from another script.
if __name__ == "__main__":
main()

0 comments on commit 7e94861

Please sign in to comment.