Skip to content

Commit

Permalink
WIP implement package management module
Browse files Browse the repository at this point in the history
  • Loading branch information
richteer committed Oct 3, 2018
1 parent ba150da commit 513872a
Show file tree
Hide file tree
Showing 3 changed files with 189 additions and 130 deletions.
166 changes: 37 additions & 129 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,24 @@
import sys
import os
import shutil
import tarfile
import urllib.request
import io
import argparse
import code

DEFAULT_CONFIG = {
"package-path": [
"packages",
os.path.join(os.path.abspath(os.path.dirname(__file__)), "packages")
],
"repos": ["https://halibot.fish:4842"],
"agent-instances": {},
"module-instances": {},
"cli-instances": {
"pm": {
"of": "core:PackageManager"
}
}
}

def h_init(args):
confpath = os.path.join(args.path, "config.json")
pkgpath = os.path.join(args.path, "packages")
Expand All @@ -30,18 +42,8 @@ def h_init(args):
if not r.lower() in ("y", "yes", "yolo"):
return

config = {
"package-path": [
"packages",
os.path.join(os.path.abspath(os.path.dirname(__file__)), "packages")
],
"repos": ["https://halibot.fish:4842"],
"agent-instances": {},
"module-instances": {}
}

with open(confpath, "w") as f:
f.write(json.dumps(config, sort_keys=True, indent=4))
f.write(json.dumps(DEFAULT_CONFIG, sort_keys=True, indent=4))

if not os.path.exists(permpath):
with open(permpath, "w") as f:
Expand Down Expand Up @@ -113,103 +115,6 @@ def h_run(args):
bot.shutdown()
print("Halibot bides you farewell.")

def h_fetch(args):
# In order to access the config easily
bot = halibot.Halibot()
bot._load_config()

# Error checking
if not "repos" in bot.config:
print("There are no repos specified in the config.json.")
print("I have nothing to fetch from!")
return

# Try to fetch each requested package
for name in args.packages:
# Install to the first package path by default
dst = os.path.join(bot.config["package-path"][0], name)

success = False
for r in bot.config["repos"]:
src = r + "/fetch/" + name
try:
print("Trying to fetch package from '{}'...".format(r))
bio = io.BytesIO(urllib.request.urlopen(src).read())
tar = tarfile.open(mode="r:*", fileobj=bio)
os.mkdir(dst)
tar.extractall(dst)

print("\033[92mSuccessfully fetched '{}' into '{}'.\033[0m".format(name, dst))
success = True
break
except Exception as e:
print(e)

if not success:
print("\033[91mFailed to fetch '{}'!\033[0m".format(name))

def h_search(args):
# In order to access the config easily
bot = halibot.Halibot()
bot._load_config()

# Error checking
if not "repos" in bot.config:
print("There are no repos specified in the config.json.")
print("I have nowhere to search!")
return

# Query all listed repositories
results = {}
for r in bot.config["repos"]:
url = r + "/search/"
if args.term != None:
url += args.term

data = urllib.request.urlopen(url).read().decode('utf-8')
subres = json.loads(data)
results = dict(list(subres.items()) + list(results.items()))

# Output results
sorted_keys = list(results.keys())
sorted_keys.sort()
for name in sorted_keys:
print(name, "-", results[name]['description'])


def h_unfetch(args):
# In order to access the config easily
bot = halibot.Halibot()
bot._load_config()

# Remove each requested package
for name in args.packages:
# Install to the first package path by default
success = False
for pkgpath in bot.config["package-path"]:
path = os.path.join(pkgpath, name)
if os.path.exists(path):
shutil.rmtree(path)
print("Removed '{}' installed to '{}'.".format(name, path))
success = True

if not success:
print("Could not find package '{}'".format(name))


def h_list_packages(args):
bot = halibot.Halibot()
bot._load_config()

pkgs = []
for path in bot.config.get("package-path"):
pkgs = pkgs + os.listdir(path)
pkgs.sort()

print("\nInstalled packages:")
for p in pkgs:
print(" {}".format(p))
print("")

def h_add(args):
# In order to access the config easily
Expand Down Expand Up @@ -364,12 +269,8 @@ def h_config(args):
subcmds = {
"init": h_init,
"run": h_run,
"fetch": h_fetch,
"unfetch": h_unfetch,
"add": h_add,
"rm": h_rm,
"packages": h_list_packages,
"search": h_search,
"config": h_config,
}

Expand All @@ -386,12 +287,6 @@ def h_config(args):
run.add_argument("-f", "--log-file", help="file to output logs to, none by default")
run.add_argument("-l", "--log-level", help="level of logs, DEBUG by default")

fetch = sub.add_parser("fetch", help="fetch remote packages")
fetch.add_argument("packages", help="name of package to fetch", nargs="+", metavar="package")

unfetch = sub.add_parser("unfetch", help="as if you never fetched them at all")
unfetch.add_argument("packages", help="name of package to unfetch", nargs="+", metavar="package")

add = sub.add_parser("add", help="add agents or modules to the local halibot instance")
add.add_argument("things", help="path to class to add", nargs="+", metavar="class")
addtype = add.add_mutually_exclusive_group()
Expand All @@ -401,22 +296,35 @@ def h_config(args):
rm = sub.add_parser("rm", help="remove agents or modules from the local halibot instance")
rm.add_argument("names", help="names of agents or modules to remove", nargs="+", metavar="name")

list_packages = sub.add_parser("packages", help="list all installed packages")

search = sub.add_parser("search", help="search for packages")
search.add_argument("term", help="what to search for", nargs="?", metavar="term")

config_cmd = sub.add_parser("config", help="configure or reconfigure a module or agent")
config_cmd.add_argument("name", help="name of the module or agent to show or reconfigure")
config_cmd.add_argument("-s", "--show", action="store_true", help="show the configuration rather than set it", required=False)
config_cmd.add_argument("-k", "--key", help="key to set or key to display with -s", required=False)
config_cmd.add_argument("-v", "--value", help="value to set key to", required=False)
config_cmd.add_argument("-t", "--type", choices=["string", "number", "boolean"], help="the type used while setting a config value with -k. If not given, it uses the type of the existing value")

hal = halibot.Halibot(config=DEFAULT_CONFIG)
try:
hal._load_config("config.json")
except Exception as e:
pass

if "cli-instances" in hal.config.keys():
hal._instantiate_objects("cli")
for o in hal.objects.values():
o.cli(sub)

args = parser.parse_args()

# Try to run a subcommand
if args.cmd != None:
subcmds[args.cmd](args)
func = subcmds.get(args.cmd)
if func:
func(args)
else:
parser.print_help()
for i in hal.objects.values():
if i.cli_receive(args):
break
else:
parser.print_help()

hal.shutdown()
3 changes: 2 additions & 1 deletion packages/core/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@

from .pm import PackageManager
from .help import Help
Default = None
150 changes: 150 additions & 0 deletions packages/core/pm.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
import urllib.request
import tarfile
import io
import os
import argparse
import json
from halibot import HalModule

class PackageManager(HalModule):

VERSION = "0.3.0"
HAL_MINIMUM = "0.2.0"

def init(self):
self.commands = {
"fetch": self.h_fetch,
"unfetch": self.h_unfetch,
"search": self.h_search,
"packages": self.h_list_packages
}

self.parser = argparse.ArgumentParser(description="PackageManager")
self.cli(self.parser.add_subparsers(title="Package Management"))

def receive(self, msg):
if not msg.body.startswith("!"):
return

ls = msg.body[1:].split(" ")
args = self.parser.parse_args(ls)

func = self.commands.get(args.cmd)
if not func:
self.reply(msg, body="Command '{}' not found".format(args.cmd))
return

func(args, output=lambda x: output(x))

def cli_receive(self, args):
func = self.commands.get(args.cmd)
if not func:
return False

func(args, output=print)
return True

# Expose the CLI argument logic
def cli(self, parser):
fetch = parser.add_parser("fetch", help="fetch remote packages")
fetch.add_argument("packages", help="name of package to fetch", nargs="+", metavar="package")

unfetch = parser.add_parser("unfetch", help="as if you never fetched them at all")
unfetch.add_argument("packages", help="name of package to unfetch", nargs="+", metavar="package")

search = parser.add_parser("search", help="search for packages")
search.add_argument("term", help="what to search for", nargs="?", metavar="term")

list_packages = parser.add_parser("packages", help="list all installed packages")


def h_fetch(self, args, output):
# In order to access the config easily
bot = self._hal

# Error checking
if not "repos" in bot.config:
output("There are no repos specified in the config.json.")
output("I have nothing to fetch from!")
return

# Try to fetch each requested package
for name in args.packages:
# Install to the first package path by default
dst = os.path.join(bot.config["package-path"][0], name)

success = False
for r in bot.config["repos"]:
src = r + "/fetch/" + name
try:
output("Trying to fetch package from '{}'...".format(r))
bio = io.BytesIO(urllib.request.urlopen(src).read())
tar = tarfile.open(mode="r:*", fileobj=bio)
os.mkdir(dst)
tar.extractall(dst)

output("\033[92mSuccessfully fetched '{}' into '{}'.\033[0m".format(name, dst))
success = True
break
except Exception as e:
output("Exception in pm: {}".format(e))

if not success:
output("\033[91mFailed to fetch '{}'!\033[0m".format(name))

def h_search(self, args, output):
# In order to access the config easily
bot = self._hal

# Error checking
if not "repos" in bot.config:
print("There are no repos specified in the config.json.")
print("I have nowhere to search!")
return

# Query all listed repositories
results = {}
for r in bot.config["repos"]:
url = r + "/search/"
if args.term != None:
url += args.term

data = urllib.request.urlopen(url).read().decode('utf-8')
subres = json.loads(data)
results = dict(list(subres.items()) + list(results.items()))

# Output results
sorted_keys = list(results.keys())
sorted_keys.sort()
for name in sorted_keys:
print(name, "-", results[name]['description'])


def h_unfetch(self, args, output):
# In order to access the config easily
bot = self._hal

# Remove each requested package
for name in args.packages:
# Install to the first package path by default
success = False
for pkgpath in bot.config["package-path"]:
path = os.path.join(pkgpath, name)
if os.path.exists(path):
shutil.rmtree(path)
output("Removed '{}' installed to '{}'.".format(name, path))
success = True

if not success:
output("Could not find package '{}'".format(name))


def h_list_packages(self, args, output):
bot = self._hal

pkgs = []
for path in bot.config.get("package-path"):
pkgs = pkgs + os.listdir(path)
pkgs.sort()

output("Installed packages: " + ", ".join(pkgs))

0 comments on commit 513872a

Please sign in to comment.