added a text spinner while installing/uninstalling
This commit is contained in:
parent
be2f7e1cae
commit
1cadf8362f
1 changed files with 109 additions and 68 deletions
111
tasks.py
111
tasks.py
|
@ -1,9 +1,14 @@
|
||||||
import inspect
|
import inspect
|
||||||
|
import itertools
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
import threading
|
||||||
|
import time
|
||||||
|
from contextlib import contextmanager
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from tempfile import NamedTemporaryFile
|
from tempfile import NamedTemporaryFile
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
from invoke import task, Context
|
from invoke import task, Context
|
||||||
|
|
||||||
|
@ -11,6 +16,40 @@ DAEMON_DIR: str = "daemon"
|
||||||
DEFAULT_PREFIX: str = "/usr/local"
|
DEFAULT_PREFIX: str = "/usr/local"
|
||||||
|
|
||||||
|
|
||||||
|
class Progress:
|
||||||
|
cycles = itertools.cycle(["-", "/", "|", "\\"])
|
||||||
|
|
||||||
|
def __init__(self, verbose: bool) -> None:
|
||||||
|
self.verbose: bool = verbose
|
||||||
|
self.thread: Optional[threading.Thread] = None
|
||||||
|
self.running: bool = False
|
||||||
|
|
||||||
|
@contextmanager
|
||||||
|
def start(self, message: str) -> None:
|
||||||
|
if not self.verbose:
|
||||||
|
print(f"{message} ... ", end="")
|
||||||
|
self.running = True
|
||||||
|
self.thread = threading.Thread(target=self.run, daemon=True)
|
||||||
|
self.thread.start()
|
||||||
|
yield
|
||||||
|
self.stop()
|
||||||
|
|
||||||
|
def run(self) -> None:
|
||||||
|
while self.running:
|
||||||
|
sys.stdout.write(next(self.cycles))
|
||||||
|
sys.stdout.flush()
|
||||||
|
sys.stdout.write("\b")
|
||||||
|
time.sleep(0.1)
|
||||||
|
|
||||||
|
def stop(self) -> None:
|
||||||
|
if not self.verbose:
|
||||||
|
print("done")
|
||||||
|
if self.thread:
|
||||||
|
self.running = False
|
||||||
|
self.thread.join()
|
||||||
|
self.thread = None
|
||||||
|
|
||||||
|
|
||||||
class OsName(Enum):
|
class OsName(Enum):
|
||||||
UBUNTU = "ubuntu"
|
UBUNTU = "ubuntu"
|
||||||
CENTOS = "centos"
|
CENTOS = "centos"
|
||||||
|
@ -52,7 +91,7 @@ def get_os() -> OsInfo:
|
||||||
if not line:
|
if not line:
|
||||||
continue
|
continue
|
||||||
key, value = line.split("=")
|
key, value = line.split("=")
|
||||||
d[key] = value.strip('"')
|
d[key] = value.strip("\"")
|
||||||
name_value = d["ID"]
|
name_value = d["ID"]
|
||||||
like_value = d["ID_LIKE"]
|
like_value = d["ID_LIKE"]
|
||||||
version_value = d["VERSION_ID"]
|
version_value = d["VERSION_ID"]
|
||||||
|
@ -69,27 +108,28 @@ def get_os() -> OsInfo:
|
||||||
|
|
||||||
|
|
||||||
def install_system(c: Context, os_info: OsInfo, hide: bool) -> None:
|
def install_system(c: Context, os_info: OsInfo, hide: bool) -> None:
|
||||||
print("installing system dependencies...")
|
|
||||||
if os_info.like == OsLike.DEBIAN:
|
if os_info.like == OsLike.DEBIAN:
|
||||||
c.run(
|
c.run(
|
||||||
"sudo apt install -y automake pkg-config gcc libev-dev ebtables iproute2 "
|
"sudo apt install -y automake pkg-config gcc libev-dev ebtables "
|
||||||
"ethtool tk python3-tk",
|
"iproute2 ethtool tk python3-tk",
|
||||||
hide=hide
|
hide=hide
|
||||||
)
|
)
|
||||||
elif os_info.like == OsLike.REDHAT:
|
elif os_info.like == OsLike.REDHAT:
|
||||||
c.run(
|
c.run(
|
||||||
"sudo yum install -y automake pkgconf-pkg-config gcc gcc-c++ libev-devel "
|
"sudo yum install -y automake pkgconf-pkg-config gcc gcc-c++ "
|
||||||
"iptables-ebtables iproute python3-devel python3-tkinter tk ethtool make",
|
"libev-devel iptables-ebtables iproute python3-devel python3-tkinter "
|
||||||
|
"tk ethtool make",
|
||||||
hide=hide
|
hide=hide
|
||||||
)
|
)
|
||||||
# centos 8+ does not support netem by default
|
# centos 8+ does not support netem by default
|
||||||
if os_info.name == OsName.CENTOS and os_info.version >= 8:
|
if os_info.name == OsName.CENTOS and os_info.version >= 8:
|
||||||
c.run("sudo yum install -y kernel-modules-extra", hide=hide)
|
c.run("sudo yum install -y kernel-modules-extra", hide=hide)
|
||||||
if not c.run("sudo modprobe sch_netem", warn=True, hide=hide):
|
if not c.run("sudo modprobe sch_netem", warn=True, hide=hide):
|
||||||
print("ERROR: you need to install the latest kernel")
|
print("\nERROR: you need to install the latest kernel")
|
||||||
print("run the following, restart, and try again")
|
print("run the following, restart, and try again")
|
||||||
print("sudo yum update")
|
print("sudo yum update")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
# attempt to setup legacy ebtables when an nftables based version is found
|
# attempt to setup legacy ebtables when an nftables based version is found
|
||||||
r = c.run("ebtables -V", hide=hide)
|
r = c.run("ebtables -V", hide=hide)
|
||||||
if "nf_tables" in r.stdout:
|
if "nf_tables" in r.stdout:
|
||||||
|
@ -99,35 +139,31 @@ def install_system(c: Context, os_info: OsInfo, hide: bool) -> None:
|
||||||
hide=hide
|
hide=hide
|
||||||
):
|
):
|
||||||
print(
|
print(
|
||||||
"WARNING: unable to setup required ebtables-legacy, WLAN will not work"
|
"\nWARNING: unable to setup ebtables-legacy, WLAN will not work"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def install_grpcio(c: Context, hide: bool) -> None:
|
def install_grpcio(c: Context, hide: bool) -> None:
|
||||||
print("installing grpcio-tools...")
|
|
||||||
c.run(
|
c.run(
|
||||||
"python3 -m pip install --user grpcio==1.27.2 grpcio-tools==1.27.2", hide=hide
|
"python3 -m pip install --user grpcio==1.27.2 grpcio-tools==1.27.2",
|
||||||
|
hide=hide,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def build(c: Context, hide: bool, prefix: str = DEFAULT_PREFIX) -> None:
|
def build_core(c: Context, hide: bool, prefix: str = DEFAULT_PREFIX) -> None:
|
||||||
print("building core...")
|
|
||||||
c.run("./bootstrap.sh", hide=hide)
|
c.run("./bootstrap.sh", hide=hide)
|
||||||
c.run(f"./configure --prefix={prefix}", hide=hide)
|
c.run(f"./configure --prefix={prefix}", hide=hide)
|
||||||
c.run("make -j$(nproc)", hide=hide)
|
c.run("make -j$(nproc)", hide=hide)
|
||||||
|
|
||||||
|
|
||||||
def install_core(c: Context, hide: bool) -> None:
|
def install_core(c: Context, hide: bool) -> None:
|
||||||
print("installing core vcmd...")
|
|
||||||
c.run("sudo make install", hide=hide)
|
c.run("sudo make install", hide=hide)
|
||||||
|
|
||||||
|
|
||||||
def install_poetry(c: Context, dev: bool, hide: bool) -> None:
|
def install_poetry(c: Context, dev: bool, hide: bool) -> None:
|
||||||
print("installing poetry...")
|
|
||||||
c.run("pipx install poetry", hide=hide)
|
c.run("pipx install poetry", hide=hide)
|
||||||
args = "" if dev else "--no-dev"
|
args = "" if dev else "--no-dev"
|
||||||
with c.cd(DAEMON_DIR):
|
with c.cd(DAEMON_DIR):
|
||||||
print("installing core environment using poetry...")
|
|
||||||
c.run(f"poetry install {args}", hide=hide)
|
c.run(f"poetry install {args}", hide=hide)
|
||||||
if dev:
|
if dev:
|
||||||
c.run("poetry run pre-commit install", hide=hide)
|
c.run("poetry run pre-commit install", hide=hide)
|
||||||
|
@ -135,21 +171,20 @@ def install_poetry(c: Context, dev: bool, hide: bool) -> None:
|
||||||
|
|
||||||
def install_ospf_mdr(c: Context, os_info: OsInfo, hide: bool) -> None:
|
def install_ospf_mdr(c: Context, os_info: OsInfo, hide: bool) -> None:
|
||||||
if c.run("which zebra", warn=True, hide=hide):
|
if c.run("which zebra", warn=True, hide=hide):
|
||||||
print("quagga already installed, skipping ospf mdr")
|
print("\nquagga already installed, skipping ospf mdr")
|
||||||
return
|
return
|
||||||
print("installing ospf mdr dependencies...")
|
p = Progress(not hide)
|
||||||
|
with p.start("installing ospf mdr dependencies"):
|
||||||
if os_info.like == OsLike.DEBIAN:
|
if os_info.like == OsLike.DEBIAN:
|
||||||
c.run("sudo apt install -y libtool gawk libreadline-dev git", hide=hide)
|
c.run("sudo apt install -y libtool gawk libreadline-dev git", hide=hide)
|
||||||
elif os_info.like == OsLike.REDHAT:
|
elif os_info.like == OsLike.REDHAT:
|
||||||
c.run("sudo yum install -y libtool gawk readline-devel git", hide=hide)
|
c.run("sudo yum install -y libtool gawk readline-devel git", hide=hide)
|
||||||
print("cloning ospf mdr...")
|
|
||||||
clone_dir = "/tmp/ospf-mdr"
|
clone_dir = "/tmp/ospf-mdr"
|
||||||
c.run(
|
c.run(
|
||||||
f"git clone https://github.com/USNavalResearchLaboratory/ospf-mdr {clone_dir}",
|
f"git clone https://github.com/USNavalResearchLaboratory/ospf-mdr {clone_dir}",
|
||||||
hide=hide
|
hide=hide
|
||||||
)
|
)
|
||||||
with c.cd(clone_dir):
|
with c.cd(clone_dir):
|
||||||
print("building ospf mdr...")
|
|
||||||
c.run("./bootstrap.sh", hide=hide)
|
c.run("./bootstrap.sh", hide=hide)
|
||||||
c.run(
|
c.run(
|
||||||
"./configure --disable-doc --enable-user=root --enable-group=root "
|
"./configure --disable-doc --enable-user=root --enable-group=root "
|
||||||
|
@ -158,7 +193,6 @@ def install_ospf_mdr(c: Context, os_info: OsInfo, hide: bool) -> None:
|
||||||
hide=hide
|
hide=hide
|
||||||
)
|
)
|
||||||
c.run("make -j$(nproc)", hide=hide)
|
c.run("make -j$(nproc)", hide=hide)
|
||||||
print("installing ospf mdr...")
|
|
||||||
c.run("sudo make install", hide=hide)
|
c.run("sudo make install", hide=hide)
|
||||||
|
|
||||||
|
|
||||||
|
@ -172,7 +206,6 @@ def install_service(c, verbose=False, prefix=DEFAULT_PREFIX):
|
||||||
systemd_dir = Path("/lib/systemd/system/")
|
systemd_dir = Path("/lib/systemd/system/")
|
||||||
service_file = systemd_dir.joinpath("core-daemon.service")
|
service_file = systemd_dir.joinpath("core-daemon.service")
|
||||||
if systemd_dir.exists():
|
if systemd_dir.exists():
|
||||||
print(f"installing core-daemon.service for systemd to {service_file}")
|
|
||||||
service_data = inspect.cleandoc(f"""
|
service_data = inspect.cleandoc(f"""
|
||||||
[Unit]
|
[Unit]
|
||||||
Description=Common Open Research Emulator Service
|
Description=Common Open Research Emulator Service
|
||||||
|
@ -204,7 +237,6 @@ def install_scripts(c, verbose=False, prefix=DEFAULT_PREFIX):
|
||||||
bin_dir = Path(prefix).joinpath("bin")
|
bin_dir = Path(prefix).joinpath("bin")
|
||||||
for script in Path("daemon/scripts").iterdir():
|
for script in Path("daemon/scripts").iterdir():
|
||||||
dest = bin_dir.joinpath(script.name)
|
dest = bin_dir.joinpath(script.name)
|
||||||
print(f"installing {script} to {dest}")
|
|
||||||
with open(script, "r") as f:
|
with open(script, "r") as f:
|
||||||
lines = f.readlines()
|
lines = f.readlines()
|
||||||
first = lines[0].strip()
|
first = lines[0].strip()
|
||||||
|
@ -224,7 +256,6 @@ def install_scripts(c, verbose=False, prefix=DEFAULT_PREFIX):
|
||||||
|
|
||||||
# install core configuration file
|
# install core configuration file
|
||||||
config_dir = "/etc/core"
|
config_dir = "/etc/core"
|
||||||
print(f"installing core configuration files under {config_dir}")
|
|
||||||
c.run(f"sudo mkdir -p {config_dir}", hide=hide)
|
c.run(f"sudo mkdir -p {config_dir}", hide=hide)
|
||||||
c.run(f"sudo cp -n daemon/data/core.conf {config_dir}", hide=hide)
|
c.run(f"sudo cp -n daemon/data/core.conf {config_dir}", hide=hide)
|
||||||
c.run(f"sudo cp -n daemon/data/logging.conf {config_dir}", hide=hide)
|
c.run(f"sudo cp -n daemon/data/logging.conf {config_dir}", hide=hide)
|
||||||
|
@ -235,22 +266,28 @@ def install(c, dev=False, verbose=False, prefix=DEFAULT_PREFIX):
|
||||||
"""
|
"""
|
||||||
install core, poetry, scripts, service, and ospf mdr
|
install core, poetry, scripts, service, and ospf mdr
|
||||||
"""
|
"""
|
||||||
|
c.run("sudo -v", hide=True)
|
||||||
print(f"installing core with prefix: {prefix}")
|
print(f"installing core with prefix: {prefix}")
|
||||||
|
p = Progress(verbose)
|
||||||
hide = not verbose
|
hide = not verbose
|
||||||
os_info = get_os()
|
os_info = get_os()
|
||||||
|
with p.start("installing system dependencies"):
|
||||||
install_system(c, os_info, hide)
|
install_system(c, os_info, hide)
|
||||||
|
with p.start("installing system grpcio-tools"):
|
||||||
install_grpcio(c, hide)
|
install_grpcio(c, hide)
|
||||||
build(c, hide, prefix)
|
with p.start("building core"):
|
||||||
|
build_core(c, hide, prefix)
|
||||||
|
with p.start("installing vcmd/gui"):
|
||||||
install_core(c, hide)
|
install_core(c, hide)
|
||||||
|
with p.start("installing poetry virtual environment"):
|
||||||
install_poetry(c, dev, hide)
|
install_poetry(c, dev, hide)
|
||||||
|
with p.start("installing scripts and /etc/core"):
|
||||||
install_scripts(c, hide, prefix)
|
install_scripts(c, hide, prefix)
|
||||||
|
with p.start("installing systemd service"):
|
||||||
install_service(c, hide, prefix)
|
install_service(c, hide, prefix)
|
||||||
|
with p.start("installing ospf mdr"):
|
||||||
install_ospf_mdr(c, os_info, hide)
|
install_ospf_mdr(c, os_info, hide)
|
||||||
print("please open a new terminal or re-login to leverage invoke for running core")
|
print("\nyou may need to open a new terminal to leverage invoke for running core")
|
||||||
print("# run daemon")
|
|
||||||
print("inv daemon")
|
|
||||||
print("# run gui")
|
|
||||||
print("inv gui")
|
|
||||||
|
|
||||||
|
|
||||||
@task
|
@task
|
||||||
|
@ -259,25 +296,29 @@ def uninstall(c, dev=False, verbose=False, prefix=DEFAULT_PREFIX):
|
||||||
uninstall core
|
uninstall core
|
||||||
"""
|
"""
|
||||||
hide = not verbose
|
hide = not verbose
|
||||||
print("uninstalling core")
|
p = Progress(verbose)
|
||||||
|
c.run("sudo -v", hide=True)
|
||||||
|
with p.start("uninstalling core"):
|
||||||
c.run("sudo make uninstall", hide=hide)
|
c.run("sudo make uninstall", hide=hide)
|
||||||
print("cleaning build directory")
|
|
||||||
|
with p.start("cleaning build directory"):
|
||||||
c.run("make clean", hide=hide)
|
c.run("make clean", hide=hide)
|
||||||
c.run("./bootstrap.sh clean", hide=hide)
|
c.run("./bootstrap.sh clean", hide=hide)
|
||||||
|
|
||||||
python = get_python(c, warn=True)
|
python = get_python(c, warn=True)
|
||||||
if python:
|
if python:
|
||||||
with c.cd(DAEMON_DIR):
|
with c.cd(DAEMON_DIR):
|
||||||
if dev:
|
if dev:
|
||||||
print("uninstalling pre-commit")
|
with p.start("uninstalling pre-commit"):
|
||||||
c.run("poetry run pre-commit uninstall", hide=hide)
|
c.run("poetry run pre-commit uninstall", hide=hide)
|
||||||
print("uninstalling poetry virtual environment")
|
with p.start("uninstalling poetry virtual environment"):
|
||||||
c.run(f"poetry env remove {python}", hide=hide)
|
c.run(f"poetry env remove {python}", hide=hide)
|
||||||
|
|
||||||
# remove installed files
|
# remove installed files
|
||||||
bin_dir = Path(prefix).joinpath("bin")
|
bin_dir = Path(prefix).joinpath("bin")
|
||||||
|
with p.start("uninstalling script files"):
|
||||||
for script in Path("daemon/scripts").iterdir():
|
for script in Path("daemon/scripts").iterdir():
|
||||||
dest = bin_dir.joinpath(script.name)
|
dest = bin_dir.joinpath(script.name)
|
||||||
print(f"uninstalling {dest}")
|
|
||||||
c.run(f"sudo rm -f {dest}", hide=hide)
|
c.run(f"sudo rm -f {dest}", hide=hide)
|
||||||
|
|
||||||
# install service
|
# install service
|
||||||
|
@ -285,7 +326,7 @@ def uninstall(c, dev=False, verbose=False, prefix=DEFAULT_PREFIX):
|
||||||
service_name = "core-daemon.service"
|
service_name = "core-daemon.service"
|
||||||
service_file = systemd_dir.joinpath(service_name)
|
service_file = systemd_dir.joinpath(service_name)
|
||||||
if service_file.exists():
|
if service_file.exists():
|
||||||
print(f"uninstalling service {service_file}")
|
with p.start(f"uninstalling service {service_file}"):
|
||||||
c.run(f"sudo systemctl disable {service_name}", hide=hide)
|
c.run(f"sudo systemctl disable {service_name}", hide=hide)
|
||||||
c.run(f"sudo rm -f {service_file}", hide=hide)
|
c.run(f"sudo rm -f {service_file}", hide=hide)
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue