2021-10-22 15:22:10 +00:00
|
|
|
#!/usr/bin/env python3
|
|
|
|
|
2022-01-28 06:52:26 +00:00
|
|
|
# SPDX-FileCopyrightText: 2021-2022 Citadel and contributors
|
2021-10-22 15:22:10 +00:00
|
|
|
#
|
2022-01-21 20:37:48 +00:00
|
|
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
2021-10-22 15:22:10 +00:00
|
|
|
|
|
|
|
import json
|
2022-02-02 18:13:20 +00:00
|
|
|
from lib.manage import compose, createDataDir, deleteData, getUserData, setInstalled, setRemoved, startInstalled, stopInstalled, update, deriveEntropy, updateRepos, download, getAvailableUpdates
|
2021-10-22 15:22:10 +00:00
|
|
|
from lib.validate import findAndValidateApps
|
|
|
|
import os
|
|
|
|
import argparse
|
|
|
|
|
|
|
|
# Print an error if user is not root
|
|
|
|
if os.getuid() != 0:
|
|
|
|
print('This script must be run as root!')
|
|
|
|
exit(1)
|
|
|
|
|
|
|
|
# The directory with this script
|
|
|
|
scriptDir = os.path.dirname(os.path.realpath(__file__))
|
|
|
|
nodeRoot = os.path.join(scriptDir, "..")
|
|
|
|
appsDir = os.path.join(nodeRoot, "apps")
|
|
|
|
appDataDir = os.path.join(nodeRoot, "app-data")
|
|
|
|
userFile = os.path.join(nodeRoot, "db", "user.json")
|
|
|
|
legacyScript = os.path.join(nodeRoot, "scripts", "app")
|
|
|
|
|
|
|
|
parser = argparse.ArgumentParser(description="Manage apps on your Citadel")
|
|
|
|
parser.add_argument('action', help='What to do with the app database.', choices=[
|
2022-02-02 08:51:13 +00:00
|
|
|
"list", "download", "generate", "update", "list-updates", "ls-installed", "install", "uninstall", "stop", "start", "compose", "restart", "entropy"])
|
2021-10-22 15:22:10 +00:00
|
|
|
# Add the --invoked-by-configure option, which is hidden from the user in --help
|
|
|
|
parser.add_argument('--invoked-by-configure',
|
|
|
|
action='store_true', help=argparse.SUPPRESS)
|
|
|
|
parser.add_argument('--verbose', '-v', action='store_true')
|
|
|
|
parser.add_argument(
|
|
|
|
'app', help='Optional, the app to perform an action on. (For install, uninstall, stop, start and compose)', nargs='?')
|
|
|
|
parser.add_argument(
|
|
|
|
'other', help='Anything else (For compose)', nargs="*")
|
|
|
|
args = parser.parse_args()
|
|
|
|
|
|
|
|
# If no action is specified, the list action is used
|
|
|
|
if args.action is None:
|
|
|
|
args.action = 'list'
|
|
|
|
|
|
|
|
if args.action == 'list':
|
|
|
|
apps = findAndValidateApps(appsDir)
|
|
|
|
for app in apps:
|
|
|
|
print(app)
|
2022-02-02 08:51:13 +00:00
|
|
|
exit(0)
|
|
|
|
elif args.action == "list-updates":
|
|
|
|
availableUpdates = getAvailableUpdates()
|
2022-02-02 18:13:20 +00:00
|
|
|
print(json.dumps(availableUpdates))
|
2021-10-22 15:22:10 +00:00
|
|
|
exit(0)
|
|
|
|
elif args.action == 'download':
|
|
|
|
updateRepos()
|
|
|
|
exit(0)
|
2022-02-01 17:50:59 +00:00
|
|
|
elif args.action == 'generate':
|
2021-11-17 18:04:06 +00:00
|
|
|
if args.invoked_by_configure:
|
2021-10-22 15:22:10 +00:00
|
|
|
update(args.app)
|
|
|
|
else:
|
|
|
|
os.system(os.path.join(nodeRoot, "scripts", "configure"))
|
|
|
|
os.chdir(nodeRoot)
|
2022-01-19 09:00:11 +00:00
|
|
|
os.system("docker compose stop app-tor")
|
|
|
|
os.system("docker compose start app-tor")
|
|
|
|
os.system("docker compose stop app-2-tor")
|
|
|
|
os.system("docker compose start app-2-tor")
|
|
|
|
os.system("docker compose stop app-3-tor")
|
|
|
|
os.system("docker compose start app-3-tor")
|
2021-10-22 15:22:10 +00:00
|
|
|
exit(0)
|
2022-02-01 17:50:59 +00:00
|
|
|
elif args.action == 'update':
|
|
|
|
if args.app is None:
|
|
|
|
updateRepos()
|
|
|
|
print("Downloaded all updates")
|
|
|
|
else:
|
|
|
|
download(args.app)
|
|
|
|
print("Downloaded latest {} version".format(args.app))
|
2021-11-17 18:04:06 +00:00
|
|
|
if args.invoked_by_configure:
|
2022-02-01 17:50:59 +00:00
|
|
|
update(args.verbose)
|
2021-10-22 15:22:10 +00:00
|
|
|
else:
|
|
|
|
os.system(os.path.join(nodeRoot, "scripts", "configure"))
|
|
|
|
os.chdir(nodeRoot)
|
2022-01-19 09:00:11 +00:00
|
|
|
os.system("docker compose stop app-tor")
|
|
|
|
os.system("docker compose start app-tor")
|
|
|
|
os.system("docker compose stop app-2-tor")
|
|
|
|
os.system("docker compose start app-2-tor")
|
|
|
|
os.system("docker compose stop app-3-tor")
|
|
|
|
os.system("docker compose start app-3-tor")
|
2021-10-22 15:22:10 +00:00
|
|
|
exit(0)
|
|
|
|
elif args.action == 'ls-installed':
|
|
|
|
# Load the userFile as JSON, check if installedApps is in it, and if so, print the apps
|
|
|
|
with open(userFile, "r") as f:
|
|
|
|
userData = json.load(f)
|
|
|
|
if "installedApps" in userData:
|
|
|
|
print("\n".join(userData["installedApps"]))
|
|
|
|
else:
|
|
|
|
# To match the behavior of the old script, print a newline if there are no apps installed
|
|
|
|
print("\n")
|
|
|
|
elif args.action == 'install':
|
|
|
|
if not args.app:
|
|
|
|
print("No app provided")
|
|
|
|
exit(1)
|
|
|
|
createDataDir(args.app)
|
|
|
|
compose(args.app, "pull")
|
|
|
|
compose(args.app, "up --detach")
|
|
|
|
setInstalled(args.app)
|
|
|
|
elif args.action == 'uninstall':
|
|
|
|
if not args.app:
|
|
|
|
print("No app provided")
|
|
|
|
exit(1)
|
|
|
|
userData = getUserData()
|
|
|
|
if not "installedApps" in userData or args.app not in userData["installedApps"]:
|
|
|
|
print("App {} is not installed".format(args.app))
|
|
|
|
exit(1)
|
|
|
|
print("Stopping app {}...".format(args.app))
|
2022-05-17 17:16:31 +00:00
|
|
|
try:
|
|
|
|
compose(args.app, "rm --force --stop")
|
|
|
|
print("Deleting data...")
|
|
|
|
deleteData(args.app)
|
|
|
|
except:
|
|
|
|
pass
|
2021-10-22 15:22:10 +00:00
|
|
|
print("Removing from the list of installed apps...")
|
|
|
|
setRemoved(args.app)
|
|
|
|
elif args.action == 'stop':
|
|
|
|
if not args.app:
|
|
|
|
print("No app provided")
|
|
|
|
exit(1)
|
|
|
|
userData = getUserData()
|
2021-11-17 18:04:06 +00:00
|
|
|
if args.app == "installed":
|
2021-10-22 15:22:10 +00:00
|
|
|
if "installedApps" in userData:
|
|
|
|
stopInstalled()
|
|
|
|
exit(0)
|
|
|
|
print("Stopping app {}...".format(args.app))
|
|
|
|
compose(args.app, "rm --force --stop")
|
|
|
|
elif args.action == 'start':
|
|
|
|
if not args.app:
|
|
|
|
print("No app provided")
|
|
|
|
exit(1)
|
|
|
|
|
|
|
|
userData = getUserData()
|
2021-11-17 18:04:06 +00:00
|
|
|
if args.app == "installed":
|
2021-10-22 15:22:10 +00:00
|
|
|
if "installedApps" in userData:
|
|
|
|
startInstalled()
|
|
|
|
exit(0)
|
|
|
|
|
|
|
|
if not "installedApps" in userData or args.app not in userData["installedApps"]:
|
|
|
|
print("App {} is not yet installed".format(args.app))
|
|
|
|
exit(1)
|
|
|
|
compose(args.app, "up --detach")
|
|
|
|
|
|
|
|
elif args.action == 'restart':
|
|
|
|
if not args.app:
|
|
|
|
print("No app provided")
|
|
|
|
exit(1)
|
2021-10-29 22:02:40 +00:00
|
|
|
if args.app == "installed":
|
2021-10-22 15:22:10 +00:00
|
|
|
stopInstalled()
|
|
|
|
startInstalled()
|
|
|
|
exit(0)
|
2021-10-29 22:02:40 +00:00
|
|
|
|
2021-10-22 15:22:10 +00:00
|
|
|
userData = getUserData()
|
|
|
|
if not "installedApps" in userData or args.app not in userData["installedApps"]:
|
|
|
|
print("App {} is not yet installed".format(args.app))
|
|
|
|
exit(1)
|
|
|
|
compose(args.app, "rm --force --stop")
|
|
|
|
compose(args.app, "up --detach")
|
|
|
|
|
|
|
|
elif args.action == 'compose':
|
|
|
|
if not args.app:
|
|
|
|
print("No app provided")
|
|
|
|
exit(1)
|
|
|
|
compose(args.app, " ".join(args.other))
|
|
|
|
|
|
|
|
elif args.action == "entropy":
|
2021-10-29 22:02:40 +00:00
|
|
|
if args.app == "":
|
2021-10-22 15:22:10 +00:00
|
|
|
print("Missing identifier for entropy")
|
|
|
|
exit(1)
|
|
|
|
print(deriveEntropy(args.app))
|
|
|
|
|
|
|
|
else:
|
|
|
|
print("Error: Unknown action")
|
|
|
|
print("See --help for usage")
|
|
|
|
exit(1)
|