示例#1
0
async def switch_impl(ctx, name):
    project = ctx.system_config["project"]
    engine = ctx.engine
    dbenv = DbEnvironments(project, engine)
    db_name = dbenv.db_service["$name"]

    # 1. If running, stop database
    was_running = engine.status(project)[db_name]
    if was_running:
        await stop_project(ctx, [db_name], show_status=False)

    # 2. Switch environment
    try:
        dbenv.switch(name)
        echo()
        echo("Environment switched to: " + style(name, bold=True))
        echo()
    except FileNotFoundError:
        raise RiptideCliError("Environment does not exist. Create it with db-new or db-copy.", ctx)
    except Exception as ex:
        raise RiptideCliError("Error switching environments", ctx) from ex

    # 3. If was running: start database again
    if was_running:
        await start_project(ctx, [db_name])
示例#2
0
async def importt_impl(ctx, file):
    project = ctx.system_config["project"]
    engine = ctx.engine
    dbenv = DbEnvironments(project, engine)
    db_name = dbenv.db_service["$name"]
    env_name = dbenv.currently_selected_name()
    db_driver = db_driver_for_service.get(dbenv.db_service)

    if not file or file == "":
        raise RiptideCliError("Please specify a path.", ctx)

    if not os.path.exists(os.path.abspath(file)):
        raise RiptideCliError("The path does not exist.", ctx)

    # 1. If not running, start database
    was_running = engine.status(project)[db_name]
    if not was_running:
        await start_project(ctx, [db_name], show_status=False)
        # TODO: Some databases need a while. How to do this better? mysqladmin for example doesn't help :(
        await sleep(15)

    # 2. Import
    echo(f"Importing into database environment {env_name}... this may take a while...")
    try:
        db_driver.importt(engine, os.path.abspath(file))
        echo()
        echo(f"Database environment {env_name} imported.")
        echo()
        return True
    except FileNotFoundError:
        raise RiptideCliError("Environment does not exist. Create it first with db:create", ctx)
    except Exception as ex:
        raise RiptideCliError("Error importing database environment", ctx) from ex
示例#3
0
    async def export(ctx, file):
        """
        Export database dump from the current environment.
        The format of the dump depends on the database driver.
        """
        load_riptide_core(ctx)
        cmd_constraint_has_db(ctx)

        project = ctx.system_config["project"]
        engine = ctx.engine
        dbenv = DbEnvironments(project, engine)
        db_name = dbenv.db_service["$name"]
        env_name = dbenv.currently_selected_name()
        db_driver = db_driver_for_service.get(dbenv.db_service)

        # 1. If not running, start database
        was_running = engine.status(project)[db_name]
        if not was_running:
            await start_project(ctx, [db_name], show_status=False)

        # 2. Export
        echo(f"Exporting from {env_name}... this may take a while...")
        try:
            db_driver.export(engine, os.path.abspath(file))
            echo()
            echo(f"Environment {env_name} exported.")
            echo()
        except FileNotFoundError:
            raise RiptideCliError("Environment does not exist. Create it first with db-create", ctx)
        except Exception as ex:
            raise RiptideCliError("Error exporting environment", ctx) from ex
示例#4
0
    async def copy(ctx, stay, name_to_copy, name_new):
        """ Copy an existing database environment """
        load_riptide_core(ctx)
        cmd_constraint_has_db(ctx)

        project = ctx.system_config["project"]
        engine = ctx.engine
        dbenv = DbEnvironments(project, engine)

        echo("Copying... this may take a while...")
        try:
            dbenv.new(name_new, copy_from=name_to_copy)
            echo()
            echo("New environment created: " + style(name_new, bold=True))
            echo()
        except FileExistsError:
            raise RiptideCliError("Envrionment with this name already exists.", ctx)
        except FileNotFoundError:
            raise RiptideCliError("Envrionment to copy from not found.", ctx)
        except NameError:
            raise RiptideCliError("Invalid name for new environment, do not use special characters", ctx)
        except Exception as ex:
            raise RiptideCliError("Error creating environment", ctx) from ex

        if not stay:
            await switch_impl(ctx, name_new)
示例#5
0
    def lst(ctx, machine_readable, current):
        """ Lists database environments """
        load_riptide_core(ctx)
        cmd_constraint_has_db(ctx)

        project = ctx.system_config["project"]
        engine = ctx.engine
        dbenv = DbEnvironments(project, engine)

        cur = dbenv.currently_selected_name()

        if not machine_readable and not current:
            echo("Database environments: ")

            for env in dbenv.list():
                if env == cur:
                    echo(TAB + "- " + style(env, bold=True) + " [Current]")
                else:
                    echo(TAB + "- " + env)

            echo()
            echo("Use db-switch to switch environments.")
        elif not current:
            echo(json.dumps({
                "envs": dbenv.list(),
                "current": cur
            }))
        else:
            echo(cur)
示例#6
0
async def db_copy_impl(subject: ReplaySubject, project_name: str, source: str, target:str, switch: bool):
    project = try_loading_project(project_name, subject, 1, 4)
    if not project:
        return

    engine = registry().engine
    dbenv = DbEnvironments(project, engine)

    try:
        subject.on_next(ResultStep(
            steps=4,
            current_step=1,
            text=f"Copying database environment {source} to {target}..."
        ))
        dbenv.new(target, copy_from=source)
    except FileNotFoundError:
        subject.on_next(ResultStep(
            steps=4,
            current_step=1,
            text=f"Environment {source} not found.",
            is_end=True,
            is_error=True
        ))
    except FileExistsError:
        subject.on_next(ResultStep(
            steps=4,
            current_step=1,
            text=f"Environment with this name already exists.",
            is_end=True,
            is_error=True
        ))
    except NameError:
        subject.on_next(ResultStep(
            steps=4,
            current_step=1,
            text=f"Invalid name for new environment, do not use special characters.",
            is_end=True,
            is_error=True
        ))
    except Exception as ex:
        subject.on_next(ResultStep(
            steps=4,
            current_step=1,
            text=f"Error creating environment: {ex}",
            is_end=True,
            is_error=True
       ))
    else:
        if switch:
            await db_switch_impl(subject, project, target, 1, 1)
        else:
            subject.on_next(ResultStep(
                steps=4,
                current_step=4,
                text=f"Finished creating environment: {target}.",
                is_end=True
            ))
示例#7
0
async def db_drop_impl(subject: ReplaySubject,  project_name: str, name: str):
    project = try_loading_project(project_name, subject, 1, 4)
    if not project:
        return

    engine = registry().engine
    dbenv = DbEnvironments(project, engine)

    try:
        subject.on_next(ResultStep(
            steps=1,
            current_step=1,
            text=f"Deleting database environment {name}..."
        ))
        dbenv.drop(name)
    except FileNotFoundError:
        subject.on_next(ResultStep(
            steps=1,
            current_step=1,
            text=f"Environment with this name does not exist.",
            is_end=True,
            is_error=True
        ))
    except OSError:
        subject.on_next(ResultStep(
            steps=1,
            current_step=1,
            text=f"Can not delete the environment that is currently active.",
            is_end=True,
            is_error=True
        ))
    except Exception as ex:
        subject.on_next(ResultStep(
            steps=1,
            current_step=1,
            text=f"Error deleting environment: {ex}",
            is_end=True,
            is_error=True
        ))
    else:
        subject.on_next(ResultStep(
            steps=1,
            current_step=1,
            text=f"Finished deleting environment: {name}.",
            is_end=True
        ))
示例#8
0
    def drop(ctx, name):
        """ Delete a database environment """
        load_riptide_core(ctx)
        cmd_constraint_has_db(ctx)

        project = ctx.system_config["project"]
        engine = ctx.engine
        dbenv = DbEnvironments(project, engine)

        echo("Deleting... this may take a while...")
        try:
            dbenv.drop(name)
            echo()
            echo("Environment deleted: " + style(name, bold=True))
            echo()
        except FileNotFoundError:
            raise RiptideCliError("Envrionment with this name does not exist.", ctx)
        except OSError:
            raise RiptideCliError("Can not delete the environment that is currently active.", ctx)
        except Exception as ex:
            raise RiptideCliError("Error deleting environment", ctx) from ex
示例#9
0
    async def new(ctx, stay, name):
        """ Create a new (blank) database environment """
        load_riptide_core(ctx)
        cmd_constraint_has_db(ctx)

        project = ctx.system_config["project"]
        engine = ctx.engine
        dbenv = DbEnvironments(project, engine)

        try:
            dbenv.new(name, copy_from=None)
            echo()
            echo("New environment created: " + style(name, bold=True))
            echo()
        except FileExistsError:
            raise RiptideCliError("Envrionment with this name already exists.", ctx)
        except NameError:
            raise RiptideCliError("Invalid name for new environment, do not use special characters", ctx)
        except Exception as ex:
            raise RiptideCliError("Error creating environment", ctx) from ex

        if not stay:
            await switch_impl(ctx, name)
示例#10
0
    def status(ctx):
        """
        Print information and status of the database.
        """
        load_riptide_core(ctx)
        cmd_constraint_has_db(ctx)

        project = ctx.system_config["project"]
        engine = ctx.engine
        dbenv = DbEnvironments(project, engine)
        db_driver = db_driver_for_service.get(dbenv.db_service)

        running = engine.service_status(project, dbenv.db_service["$name"])

        if running:
            echo(f"{'Status':<20}: " + style("Running", bold=True, fg="green"))
        else:
            echo(f"{'Status':<20}: " + style("Not running", bold=True, fg="red"))

        for key,label in db_driver.collect_info().items():
            echo(f"{key:<20}: {label}")

        current = dbenv.currently_selected_name()
        echo("Active environment  : " + style(current, bold=True))
示例#11
0
async def setup_assistant(ctx, force, skip):
    project = ctx.system_config["project"]
    engine = ctx.engine

    if ctx.project_is_set_up and not force:
        raise RiptideCliError(
            "The project is already set up. If you still want to run this command, pass --force.",
            ctx)

    if skip:
        echo("Project was marked as set up.")
        finish(ctx)
        return

    echo(style("Thank you for using Riptide!", fg='cyan', bold=True))
    echo(
        f"This command will guide you through the initial setup for {project['name']}."
    )
    echo(
        style("Please follow it very carefully, it won't take long!",
              bold=True))
    echo(style("> Press any key to continue...", fg='magenta'))
    getchar()
    echo()
    echo(header("> BEGIN SETUP"))
    if "notices" in project["app"] and "usage" in project["app"]["notices"]:
        echo()
        echo(
            style(f"Usage notes for running {project['app']['name']}",
                  bold=True) + " with Riptide:")
        echo(TAB +
             TAB.join(project["app"]["notices"]["usage"].splitlines(True)))
    echo()

    # Q1
    echo(style("> Do you wish to run this interactive setup? [Y/n] ",
               fg='magenta'),
         nl=False)
    if getchar(True).lower() == 'n':
        echo()
        echo()
        echo(header("> END SETUP"))
        echo("Okay! To re-run this setup, pass the --force option.")
        finish(ctx)
        return
    echo()
    echo()
    echo(header("> INTERACTIVE SETUP"))

    # Q2: New or existing?
    echo(style("> Are you working on a ", fg='magenta') +
         style("n", bold=True, fg="cyan") +
         style("ew project that needs to be installed or do you want to ",
               fg='magenta') + style("I", bold=True, fg="cyan") +
         style("mport existing data? [n/I] ", fg='magenta'),
         nl=False)
    if getchar(True).lower() == 'n':
        # New project
        if "notices" in project["app"] and "installation" in project["app"][
                "notices"]:
            echo()
            echo()
            echo(header("> NEW PROJECT"))
            echo(
                "Okay! Riptide can't guide you through the installation automatically."
            )
            echo(
                f"Please read these notes on how to run a first-time-installation for {project['app']['name']}."
            )
            echo()
            echo(style("Installation instructions:", bold=True))
            echo(TAB + TAB.join(project["app"]["notices"]
                                ["installation"].splitlines(True)))
            finish(ctx)
            return

    # Existing project
    echo()
    echo()
    echo(header("> EXISTING PROJECT"))

    db_can_be_imported = DbEnvironments.has_db(project)
    files_can_be_imported = 'import' in project['app']

    if not db_can_be_imported and not files_can_be_imported:
        # Nothing to import
        echo(
            f"The app {project['app']['name']} does not specify a database or files to import. You are already done!"
        )
        finish(ctx)
        return

    # Import db
    if db_can_be_imported:
        dbenv = DbEnvironments(project, engine)
        db_driver = db_driver_for_service.get(dbenv.db_service)
        echo(TAB + header("> DATABASE IMPORT"))
        echo(style(
            f"> Do you want to import a database (format {dbenv.db_service['driver']['name']})? [Y/n] ",
            fg='magenta'),
             nl=False)
        if getchar(True).lower() != 'n':
            # Import db
            echo()
            exit_cmd = False
            while not exit_cmd:
                echo(db_driver.ask_for_import_file() + " ", nl=False)
                path = stdin.readline().rstrip('\r\n')
                try:
                    echo(CMD_SEP)
                    await importt_impl(ctx, path)
                    exit_cmd = True
                    echo(CMD_SEP)
                except RiptideCliError as err:
                    echo("Error: " + style(str(err), fg='red'))
                    echo(CMD_SEP)
                    echo(style("> Do you want to try again? [y/N] ",
                               fg='magenta'),
                         nl=False)
                    if getchar(True).lower() != 'y':
                        exit_cmd = True
                    echo()

        else:
            echo()
            echo(
                "Skipping database import. If you change your mind, run db:import."
            )

    if files_can_be_imported:
        echo(TAB + header("> FILE IMPORT"))
        for key, entry in project['app']['import'].items():
            echo(TAB + TAB + header(f"> {key} IMPORT"))
            echo(style(
                f"> Do you wish to import {entry['name']} to <project>/{entry['target']}? [Y/n] ",
                fg='magenta'),
                 nl=False)
            if getchar(True).lower() != 'n':
                # Import files
                echo()
                exit_cmd = False
                while not exit_cmd:
                    echo("Enter path of files or directory to copy: ",
                         nl=False)
                    path = stdin.readline().rstrip('\r\n')
                    try:
                        echo(CMD_SEP)
                        files_impl(ctx, key, path)
                        exit_cmd = True
                        echo(CMD_SEP)
                    except RiptideCliError as err:
                        echo("Error: " + style(str(err), fg='red'))
                        echo(CMD_SEP)
                        echo(style("> Do you want to try again? [y/N] ",
                                   fg='magenta'),
                             nl=False)
                        if getchar(True).lower() != 'y':
                            exit_cmd = True
                        echo()
            else:
                echo()
    echo()
    echo(header("> IMPORT DONE!", bold=True))
    echo("All files were imported.")
    finish(ctx)
示例#12
0
 def collect_volumes(self):
     return DbEnvironments.get_volume_configuration_for_driver(
         DATA_PATH, self.service)
示例#13
0
 def resolve_db_current(parent, info):
     if not DbEnvironments.has_db(_get_project_doc(parent)):
         return None
     dbenv = DbEnvironments(_get_project_doc(parent), registry().engine)
     return dbenv.currently_selected_name()
示例#14
0
 def resolve_db_list(parent, info):
     if not DbEnvironments.has_db(_get_project_doc(parent)):
         return None
     dbenv = DbEnvironments(_get_project_doc(parent), registry().engine)
     return dbenv.list()
示例#15
0
 def resolve_db_available(parent, info):
     return DbEnvironments.has_db(_get_project_doc(parent))
示例#16
0
async def db_switch_impl(
        subject: ReplaySubject,
        project: Project,
        name: str,
        total_steps_from_ctx=0,
        current_step_in_ctx=0
):
    """Switches db env. Has 3 total steps and can be used in other db operations."""
    engine = registry().engine
    dbenv = DbEnvironments(project, engine)
    db_name = dbenv.db_service["$name"]

    subject.on_next(ResultStep(
        steps=total_steps_from_ctx + 3,
        current_step=current_step_in_ctx + 1,
        text="Switching database..."
    ))

    # 1. If running, stop database
    was_running = engine.service_status(project, db_name, registry().system_config)
    if was_running:
        subject.on_next(ResultStep(
            steps=total_steps_from_ctx + 3,
            current_step=current_step_in_ctx + 1,
            text="Stopping database service..."
        ))
        async for _ in registry().engine.stop_project(project, [db_name]):
            pass

    # 2. Switch environment
    try:
        subject.on_next(ResultStep(
            steps=total_steps_from_ctx + 3,
            current_step=current_step_in_ctx + 2,
            text=f"Switching environment to {name}..."
        ))
        dbenv.switch(name)
    except FileNotFoundError:
        subject.on_next(ResultStep(
            steps=total_steps_from_ctx + 3,
            current_step=current_step_in_ctx + 2,
            text=f"Environment {name} does not exist.",
            is_end=True,
            is_error=True
        ))
    except Exception as ex:
        subject.on_next(ResultStep(
            steps=total_steps_from_ctx + 3,
            current_step=current_step_in_ctx + 2,
            text=f"Error switching environment: {str(ex)}",
            is_end=True,
            is_error=True
        ))
    else:
        # 3. If was running: start database again
        if was_running:
            subject.on_next(ResultStep(
                steps=total_steps_from_ctx + 3,
                current_step=current_step_in_ctx + 3,
                text=f"Starting database...",
            ))
            async for _ in registry().engine.start_project(project, [db_name]):
                pass

        subject.on_next(ResultStep(
            steps=total_steps_from_ctx + 3,
            current_step=current_step_in_ctx + 3,
            text=f"Finished switching database environment to {name}.",
            is_end=True
        ))
示例#17
0
def cmd_constraint_has_db(ctx):
    cmd_constraint_project_loaded(ctx)
    if not DbEnvironments.has_db(ctx.system_config["project"]):
        raise RiptideCliError("The project doesn't have a service with the role 'db'. "
                              "This is required to use this command.", ctx)