def main(): """Try to load the tool and launch it. If it can't be loaded, try to install all required things first.""" try: from isomer.tool.tool import isotool except ImportError as import_exception: print( "\033[1;33;41mIsomer startup error! Please check your Isomer/Python installation.\033[0m" ) print(type(import_exception), ":", import_exception, "\n") if not ask( "Maybe the dependencies not installed, do you want to try to install them", default=False, data_type="bool", show_hint=True, ): abort(EXIT_CANNOT_IMPORT_TOOL) install_isomer() print("Please restart the tool now.") sys.exit() isotool(obj={}, auto_envvar_prefix="ISOMER")
def delete_user(ctx, yes): """Delete a local user""" if ctx.obj["username"] is None: username = ask("Please enter username:"******"username"] del_user = ctx.obj["db"].objectmodels["user"].find_one({"name": username}) if yes or ask("Confirm deletion", default=False, data_type="bool"): try: del_user.delete() finish(ctx) except AttributeError: log("User not found", lvl=warn) else: log("Cancelled")
def uninstall(): """Uninstall data and resource locations""" response = ask( "This will delete all data of your Isomer installations! Type" "YES to continue:", default="N", show_hint=False, ) if response == "YES": shutil.rmtree("/var/lib/isomer") shutil.rmtree("/var/cache/isomer")
def remove(ctx, clear, no_archive): """Irrevocably remove a whole instance""" if clear: log("Destructively removing instance:", ctx.obj["instance"], lvl=warn) if not ask("Are you sure", default=False, data_type="bool"): abort(EXIT_USER_BAILED_OUT) if clear: _clear_instance(ctx, force=True, clear=clear, no_archive=no_archive) remove_instance(ctx.obj["instance"]) finish(ctx)
def _ask_questionnaire(): """Asks questions to fill out a Isomer plugin template""" answers = {} print(info_header) pprint(questions.items()) for question, default in questions.items(): response = ask(question, default, str(type(default)), show_hint=True) if type(default) == bytes and type(response) != str: response = response.decode("utf-8") answers[question] = response return answers
def delete_database(db_host, db_name, force): """Actually delete a database""" if force: response = True else: response = ask( 'Are you sure you want to delete database "%s"' % db_name, default="N", data_type="bool", ) if response is True: host, port = db_host.split(":") client = pymongo.MongoClient(host=host, port=int(port)) if db_name in client.list_database_names(): log("Dropping database", db_name, lvl=warn) client.drop_database(db_name) else: log("Database does not exist")
def clear(ctx, schema): """Clears an entire database collection irrevocably. Use with caution!""" response = ask( 'Are you sure you want to delete the collection "%s"' % schema, default="N", data_type="bool", ) if response is True: host, port = ctx.obj["dbhost"].split(":") client = pymongo.MongoClient(host=host, port=int(port)) database = client[ctx.obj["dbname"]] log("Clearing collection for", schema, lvl=warn, emitter="MANAGE") result = database.drop_collection(schema) if not result["ok"]: log("Could not drop collection:", lvl=error) log(result, pretty=True, lvl=error) else: finish(ctx)
def drop(ctx, schema, yes): """Delete a whole collection of stored objects (CAUTION!)""" database = ctx.obj["db"] if schema is None: log("No schema given. Read the help", lvl=warn) return if not yes and not ask( "Are you sure you want to drop the whole collection", default=False, data_type="bool", show_hint=True, ): return model = database.objectmodels[schema] collection = model.collection() collection.drop() finish(ctx)
def create_module(clear_target, target): """Creates a new template Isomer plugin module""" if os.path.exists(target): if clear_target: shutil.rmtree(target) else: log("Target exists! Use --clear to delete it first.", emitter="MANAGE") abort(2) done = False info = None while not done: info = _ask_questionnaire() pprint(info) done = ask("Is the above correct", default="y", data_type="bool") augmented_info = _augment_info(info) log("Constructing module %(plugin_name)s" % info) _construct_module(augmented_info, target)
def merge(a, b, path=None): """merges b into a""" if path is None: path = [] for key in b: if key in a: if isinstance(a[key], dict) and isinstance(b[key], dict): merge(a[key], b[key], path + [str(key)]) elif a[key] == b[key]: pass # same leaf value else: log("Conflict at", path, key, ":", a[key], "<->", b[key]) resolve = "" while resolve not in ("a", "b"): resolve = ask("Choose? (a or b)") if resolve == "a": b[key] = a[key] else: a[key] = b[key] else: a[key] = b[key] return a
def delete(ctx, schema, uuid, object_filter, yes): """Delete stored objects (CAUTION!)""" database = ctx.obj["db"] if schema is None: log("No schema given. Read the help", lvl=warn) return model = database.objectmodels[schema] if uuid: count = model.count({"uuid": uuid}) obj = model.find({"uuid": uuid}, validation=False) elif object_filter: count = model.count(literal_eval(object_filter)) obj = model.find(literal_eval(object_filter), validation=False) else: count = model.count() obj = model.find(validation=False) if count == 0: log("No objects to delete found") return if not yes and not ask( "Are you sure you want to delete %i objects" % count, default=False, data_type="bool", show_hint=True, ): return for item in obj: item.delete() finish(ctx)
def handle_schema(check_schema): dupes = {} dupe_count = 0 count = 0 for item in database.objectmodels[check_schema].find(): if item.uuid in dupes: dupes[item.uuid].append(item) dupe_count += 1 else: dupes[item.uuid] = [item] count += 1 if len(dupes) > 0: log( dupe_count, "duplicates of", count, "items total of type", check_schema, "found:", ) log(dupes.keys(), pretty=True, lvl=verbose) if delete_duplicates: log("Deleting duplicates") for item in dupes: database.objectmodels[check_schema].find_one({"uuid": item}).delete() log("Done for schema", check_schema) elif do_merge: def merge(a, b, path=None): """merges b into a""" if path is None: path = [] for key in b: if key in a: if isinstance(a[key], dict) and isinstance(b[key], dict): merge(a[key], b[key], path + [str(key)]) elif a[key] == b[key]: pass # same leaf value else: log("Conflict at", path, key, ":", a[key], "<->", b[key]) resolve = "" while resolve not in ("a", "b"): resolve = ask("Choose? (a or b)") if resolve == "a": b[key] = a[key] else: a[key] = b[key] else: a[key] = b[key] return a log(dupes, pretty=True, lvl=verbose) for item in dupes: if len(dupes[item]) == 1: continue ignore = False while len(dupes[item]) > 1 or ignore is False: log(len(dupes[item]), "duplicates found:") for index, dupe in enumerate(dupes[item]): log("Candidate #", index, ":") log(dupe._fields, pretty=True) request = ask("(d)iff, (m)erge, (r)emove, (i)gnore, (q)uit?") if request == "q": log("Done") return elif request == "i": ignore = True break elif request == "r": delete_request = -2 while delete_request == -2 or -1 > delete_request > len( dupes[item] ): delete_request = ask( "Which one? (0-%i or -1 to cancel)" % (len(dupes[item]) - 1), data_type="int", ) if delete_request == -1: continue else: log("Deleting candidate #", delete_request) dupes[item][delete_request].delete() break elif request in ("d", "m"): merge_request_a = -2 merge_request_b = -2 while merge_request_a == -2 or -1 > merge_request_a > len( dupes[item] ): merge_request_a = ask( "Merge from? (0-%i or -1 to cancel)" % (len(dupes[item]) - 1), data_type="int", ) if merge_request_a == -1: continue while merge_request_b == -2 or -1 > merge_request_b > len( dupes[item] ): merge_request_b = ask( "Merge into? (0-%i or -1 to cancel)" % (len(dupes[item]) - 1), data_type="int", ) if merge_request_b == -1: continue log( deepdiff.DeepDiff( dupes[item][merge_request_a]._fields, dupes[item][merge_request_b]._fields, ), pretty=True, ) if request == "m": log( "Merging candidates", merge_request_a, "and", merge_request_b, ) _id = dupes[item][merge_request_b]._fields["_id"] if not isinstance(_id, bson.objectid.ObjectId): _id = bson.objectid.ObjectId(_id) dupes[item][merge_request_a]._fields["_id"] = _id merge( dupes[item][merge_request_b]._fields, dupes[item][merge_request_a]._fields, ) log( "Candidate after merge:", dupes[item][merge_request_b]._fields, pretty=True, ) store = "" while store not in ("n", "y"): store = ask("Store?") if store == "y": dupes[item][merge_request_b].save() dupes[item][merge_request_a].delete() break
def find_field(ctx, search, by_type, obj): """Find fields in registered data models.""" # TODO: Fix this to work recursively on all possible subschemes if search is None: search = ask("Enter search term") database = ctx.obj["db"] def find(search_schema, search_field, find_result=None, key=""): """Examine a schema to find fields by type or name""" if find_result is None: find_result = [] fields = search_schema["properties"] if not by_type: if search_field in fields: find_result.append(key) # log("Found queried fieldname in ", model) else: for field in fields: try: if "type" in fields[field]: # log(fields[field], field) if fields[field]["type"] == search_field: find_result.append((key, field)) # log("Found field", field, "in", model) except KeyError as e: log("Field access error:", e, type(e), exc=True, lvl=debug) if "properties" in fields: # log('Sub properties checking:', fields['properties']) find_result.append( find( fields["properties"], search_field, find_result, key=fields["name"] ) ) for field in fields: if "items" in fields[field]: if "properties" in fields[field]["items"]: # log('Sub items checking:', fields[field]) find_result.append( find( fields[field]["items"], search_field, find_result, key=field ) ) else: pass # log('Items without proper definition!') return find_result if obj is not None: schema = database.objectmodels[obj]._schema result = find(schema, search, [], key="top") if result: # log(args.object, result) print(obj) pprint(result) else: for model, thing in database.objectmodels.items(): schema = thing._schema result = find(schema, search, [], key="top") if result: print(model) # log(model, result) print(result) finish(ctx)