blob: 28528bec9203b247370c547662f19baaa1493adc [file] [log] [blame] [edit]
#!/usr/bin/env python3
# Copyright (c) 2023 The Regents of the University of California
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import json
from pymongo import MongoClient
from api.create_resources_json import ResourceJsonCreator
import os
from dotenv import load_dotenv
import argparse
from itertools import cycle
from shutil import get_terminal_size
from threading import Thread
from time import sleep
load_dotenv()
# read MONGO_URI from environment variable
MONGO_URI = os.getenv("MONGO_URI")
class Loader:
def __init__(self, desc="Loading...", end="Done!", timeout=0.1):
"""
A loader-like context manager
Args:
desc (str, optional): The loader's description.
Defaults to "Loading...".
end (str, optional): Final print. Defaults to "Done!".
timeout (float, optional): Sleep time between prints.
Defaults to 0.1.
"""
self.desc = desc
self.end = end
self.timeout = timeout
self._thread = Thread(target=self._animate, daemon=True)
self.steps = ["⢿", "⣻", "⣽", "⣾", "⣷", "⣯", "⣟", "⡿"]
self.done = False
def start(self):
self._thread.start()
return self
def _animate(self):
for c in cycle(self.steps):
if self.done:
break
print(f"\r{self.desc} {c}", flush=True, end="")
sleep(self.timeout)
def __enter__(self):
self.start()
def stop(self):
self.done = True
cols = get_terminal_size((80, 20)).columns
print("\r" + " " * cols, end="", flush=True)
print(f"\r{self.end}", flush=True)
def __exit__(self, exc_type, exc_value, tb):
# handle exceptions with those variables ^
self.stop()
def get_database(collection="versions_test", uri=MONGO_URI, db="gem5-vision"):
"""
Retrieves the MongoDB database for gem5-vision.
"""
CONNECTION_STRING = uri
try:
client = MongoClient(CONNECTION_STRING)
client.server_info()
except:
print("\nCould not connect to MongoDB")
exit(1)
return client[db][collection]
collection = None
def cli():
parser = argparse.ArgumentParser(
description="CLI for gem5-resources.",
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
)
parser.add_argument(
"-u",
"--uri",
help="The URI of the MongoDB database.",
type=str,
default=MONGO_URI,
)
parser.add_argument(
"-d",
"--database",
help="The MongoDB database to use.",
type=str,
default="gem5-vision",
)
parser.add_argument(
"-c",
"--collection",
help="The MongoDB collection to use.",
type=str,
default="versions_test",
)
subparsers = parser.add_subparsers(
help="The command to run.", dest="command", required=True
)
parser_get_resource = subparsers.add_parser(
"get_resource",
help=(
"Retrieves a resource from the collection based on the given ID."
"\n if a resource version is provided, it will retrieve the "
"resource with the given ID and version."
),
)
req_group = parser_get_resource.add_argument_group(
title="required arguments"
)
req_group.add_argument(
"-i",
"--id",
help="The ID of the resource to retrieve.",
type=str,
required=True,
)
parser_get_resource.add_argument(
"-v",
"--version",
help="The version of the resource to retrieve.",
type=str,
required=False,
)
parser_get_resource.set_defaults(func=get_resource)
parser_backup_mongodb = subparsers.add_parser(
"backup_mongodb",
help="Backs up the MongoDB collection to a JSON file.",
)
req_group = parser_backup_mongodb.add_argument_group(
title="required arguments"
)
req_group.add_argument(
"-f",
"--file",
help="The JSON file to back up the MongoDB collection to.",
type=str,
required=True,
)
parser_backup_mongodb.set_defaults(func=backup_mongodb)
parser_update_mongodb = subparsers.add_parser(
"restore_backup",
help="Restores a backup of the MongoDB collection from a JSON file.",
)
req_group = parser_update_mongodb.add_argument_group(
title="required arguments"
)
req_group.add_argument(
"-f",
"--file",
help="The JSON file to restore the MongoDB collection from.",
type=str,
)
parser_update_mongodb.set_defaults(func=restore_backup)
parser_create_resources_json = subparsers.add_parser(
"create_resources_json",
help="Creates a JSON file of all the resources in the collection.",
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
)
parser_create_resources_json.add_argument(
"-v",
"--version",
help="The version of the resources to create the JSON file for.",
type=str,
default="dev",
)
parser_create_resources_json.add_argument(
"-o",
"--output",
help="The JSON file to create.",
type=str,
default="resources.json",
)
parser_create_resources_json.add_argument(
"-s",
"--source",
help="The path to the gem5 source code.",
type=str,
default="",
)
parser_create_resources_json.set_defaults(func=create_resources_json)
args = parser.parse_args()
if args.collection:
global collection
with Loader("Connecting to MongoDB...", end="Connected to MongoDB"):
collection = get_database(args.collection, args.uri, args.database)
args.func(args)
def get_resource(args):
# set the end after the loader is created
loader = Loader("Retrieving resource...").start()
resource = None
if args.version:
resource = collection.find_one(
{"id": args.id, "resource_version": args.version}, {"_id": 0}
)
else:
resource = collection.find({"id": args.id}, {"_id": 0})
resource = list(resource)
if resource:
loader.end = json.dumps(resource, indent=4)
else:
loader.end = "Resource not found"
loader.stop()
def backup_mongodb(args):
"""
Backs up the MongoDB collection to a JSON file.
:param file: The JSON file to back up the MongoDB collection to.
"""
with Loader(
"Backing up the database...",
end="Backed up the database to " + args.file,
):
# get all the data from the collection
resources = collection.find({}, {"_id": 0})
# write to resources.json
with open(args.file, "w") as f:
json.dump(list(resources), f, indent=4)
def restore_backup(args):
with Loader("Restoring backup...", end="Updated the database\n"):
with open(args.file) as f:
resources = json.load(f)
# clear the collection
collection.delete_many({})
# push the new data
collection.insert_many(resources)
def create_resources_json(args):
with Loader("Creating resources JSON...", end="Created " + args.output):
creator = ResourceJsonCreator()
creator.create_json(args.version, args.source, args.output)
if __name__ == "__main__":
cli()