示例#1
0
    def iterate_revisions(self, upper, lower):
        """Iterate through script revisions, starting at the given
        upper revision identifier and ending at the lower.

        The traversal uses strictly the `down_revision`
        marker inside each migration script, so
        it is a requirement that upper >= lower,
        else you'll get nothing back.

        The iterator yields :class:`.Script` objects.

        """
        if upper is not None and _relative_destination.match(upper):
            relative = int(upper)
            revs = list(self._iterate_revisions("head", lower))
            revs = revs[-relative:]
            if len(revs) != abs(relative):
                raise util.CommandError("Relative revision %s didn't "
                                        "produce %d migrations" %
                                        (upper, abs(relative)))
            return iter(revs)
        elif lower is not None and _relative_destination.match(lower):
            relative = int(lower)
            revs = list(self._iterate_revisions(upper, "base"))
            revs = revs[0:-relative]
            if len(revs) != abs(relative):
                raise util.CommandError("Relative revision %s didn't "
                                        "produce %d migrations" %
                                        (lower, abs(relative)))
            return iter(revs)
        else:
            return self._iterate_revisions(upper, lower)
示例#2
0
def downgrade(config, revision, sql=False, tag=None):
    """Revert to a previous version."""

    script = ScriptDirectory.from_config(config)
    starting_rev = None
    if ":" in revision:
        if not sql:
            raise util.CommandError("Range revision not allowed")
        starting_rev, revision = revision.split(':', 2)
    elif sql:
        raise util.CommandError("downgrade with --sql requires <fromrev>:<torev>")

    def downgrade(rev, context):
        return script._downgrade_revs(revision, rev)

    with EnvironmentContext(
        config,
        script,
        fn=downgrade,
        as_sql=sql,
        starting_rev=starting_rev,
        destination_rev=revision,
        tag=tag
    ):
        script.run_env()
示例#3
0
    def init():
        """
        Prepare directory with alembic.ini, mako-files and directory for
        migrations. Part of functional was copied from original Alembic Init
        but changed some things with config
        """
        if os.access(config.alembic_dir, os.F_OK):
            raise util.CommandError("Directory {} already exists".format(
                config.alembic_dir))

        template_dir = os.path.join(config.template_path +
                                    config.template_name)

        if not os.access(template_dir, os.F_OK):
            raise util.CommandError("No such template {}".format(template_dir))

        util.status(
            "Creating directory {}".format(os.path.abspath(
                config.alembic_dir)), os.makedirs, config.alembic_dir)

        versions = os.path.join(config.alembic_dir, 'versions')
        util.status("Creating directory %s" % os.path.abspath(versions),
                    os.makedirs, versions)

        script = ScriptDirectory(config.alembic_dir)

        dirs = os.listdir(template_dir)
        dirs += [
            'versions/create_table_alembic_version_history.py',
        ]

        for file_ in dirs:
            file_path = os.path.join(template_dir, file_)

            if file_ == 'alembic.ini.mako':
                config_file = os.path.abspath('alembic.ini')
                if os.access(config_file, os.F_OK):
                    util.msg(
                        "File {} already exists, skipping".format(config_file))
                else:
                    script._generate_template(
                        template_dir + '/alembic.ini.mako',
                        os.path.join(config.alembic_dir, 'alembic.ini'),
                        script_location=config.alembic_dir)
            elif os.path.isfile(file_path):
                output_file = os.path.join(config.alembic_dir, file_)
                script._copy_file(file_path, output_file)

        util.msg("Please edit configuration/connection/logging "
                 "settings in {} before proceeding.".format(
                     os.path.join(config.alembic_dir, 'alembic.ini')))
示例#4
0
def _produce_migration_diffs(context,
                             template_args,
                             imports,
                             include_symbol=None,
                             include_schemas=False):
    opts = context.opts
    metadata = opts['target_metadata']
    include_symbol = opts.get('include_symbol', include_symbol)
    include_schemas = opts.get('include_schemas', include_schemas)

    if metadata is None:
        raise util.CommandError(
            "Can't proceed with --autogenerate option; environment "
            "script %s does not provide "
            "a MetaData object to the context." %
            (context.script.env_py_location))
    autogen_context, connection = _autogen_context(context, imports)

    diffs = []
    _produce_net_changes(connection, metadata, diffs, autogen_context,
                         include_symbol, include_schemas)
    template_args[opts['upgrade_token']] = \
            _indent(_produce_upgrade_commands(diffs, autogen_context))
    template_args[opts['downgrade_token']] = \
            _indent(_produce_downgrade_commands(diffs, autogen_context))
    template_args['imports'] = "\n".join(sorted(imports))
示例#5
0
    def retrieve_migrations(rev, context):
        if set(script_directory.get_revisions(rev)) != \
                set(script_directory.get_revisions("heads")):
            raise util.CommandError("Target database is not up to date.")

        imports = set()
        autogen._produce_migration_diffs(context, template_args, imports)
        return []
示例#6
0
    def downgrade(self, revision, sql=False, tag=None):
        """Revert to a previous version.

        :param revision: string revision target or range for --sql mode

        :param sql: if True, use ``--sql`` mode

        :param tag: an arbitrary "tag" that can be intercepted by custom
        ``env.py`` scripts via the :meth:`.EnvironmentContext.get_tag_argument`
        method.

        """

        config = self.config
        script = self.script_directory
        config.attributes["engine"] = self.engine

        output_buffer = io.StringIO()
        config.attributes["output_buffer"] = output_buffer

        starting_rev = None
        if ":" in revision:
            if not sql:
                raise util.CommandError("Range revision not allowed")
            starting_rev, revision = revision.split(":", 2)
        elif sql:
            raise util.CommandError(
                "downgrade with --sql requires <fromrev>:<torev>"
            )

        def do_downgrade(rev, context):
            return script._downgrade_revs(revision, rev)

        with EnvironmentContext(
            config,
            script,
            fn=do_downgrade,
            as_sql=sql,
            starting_rev=starting_rev,
            destination_rev=revision,
            tag=tag,
        ):
            script.run_env()
            output_buffer.seek(0)
            return output_buffer.read()
示例#7
0
    def __init__(self, dir, file_template=_default_file_template):
        self.dir = dir
        self.versions = os.path.join(self.dir, 'versions')
        self.file_template = file_template

        if not os.access(dir, os.F_OK):
            raise util.CommandError("Path doesn't exist: %r.  Please use "
                                    "the 'init' command to create a new "
                                    "scripts folder." % dir)
示例#8
0
    def alter_column(self,
                     table_name,
                     column_name,
                     nullable=None,
                     server_default=False,
                     name=None,
                     type_=None,
                     schema=None,
                     autoincrement=None,
                     existing_type=None,
                     existing_server_default=None,
                     existing_nullable=None,
                     existing_autoincrement=None):

        if nullable is not None and existing_type is None:
            if type_ is not None:
                existing_type = type_
                # the NULL/NOT NULL alter will handle
                # the type alteration
                type_ = None
            else:
                raise util.CommandError(
                    "MS-SQL ALTER COLUMN operations "
                    "with NULL or NOT NULL require the "
                    "existing_type or a new type_ be passed.")

        super(MSSQLImpl,
              self).alter_column(table_name,
                                 column_name,
                                 nullable=nullable,
                                 type_=type_,
                                 schema=schema,
                                 autoincrement=autoincrement,
                                 existing_type=existing_type,
                                 existing_nullable=existing_nullable,
                                 existing_autoincrement=existing_autoincrement)

        if server_default is not False:
            if existing_server_default is not False or \
                server_default is None:
                self._exec(
                    _exec_drop_col_constraint(self, table_name, column_name,
                                              'sys.default_constraints'))
            if server_default is not None:
                super(MSSQLImpl,
                      self).alter_column(table_name,
                                         column_name,
                                         schema=schema,
                                         server_default=server_default)

        if name is not None:
            super(MSSQLImpl, self).alter_column(table_name,
                                                column_name,
                                                schema=schema,
                                                name=name)
示例#9
0
    def history(self, rev_range="base:heads", indicate_current=False):
        """List changeset scripts in chronological order.

        :param rev_range: string revision range

        :param indicate_current: indicate current revision.

        ..versionadded:: 0.9.9

        """

        if rev_range is not None:
            if ":" not in rev_range:
                raise util.CommandError(
                    "History range requires [start]:[end], "
                    "[start]:, or :[end]"
                )
            base, head = rev_range.strip().split(":")
        else:
            base = head = None

        environment = (
            util.asbool(self.config.get_main_option("revision_environment"))
            or indicate_current
        )

        def _display_history(base, head, currents=()):

            history = list()
            for sc in self.script_directory.walk_revisions(
                base=base or "base", head=head or "heads"
            ):
                if indicate_current:
                    sc._db_current_indicator = sc in currents
                history.insert(0, sc)

            return history

        def _display_history_w_current(base, head):
            def _display_current_history(rev):
                if head == "current":
                    return _display_history(base, rev, rev)
                elif base == "current":
                    return _display_history(rev, head, rev)
                else:
                    return _display_history(base, head, rev)
                return []

            rev = self.current
            return _display_current_history(rev)

        if base == "current" or head == "current" or environment:
            return _display_history_w_current(base, head)
        else:
            return _display_history(base, head)
示例#10
0
def init(config, directory, template='generic'):
    """Initialize a new scripts directory."""

    if os.access(directory, os.F_OK):
        raise util.CommandError("Directory %s already exists" % directory)

    template_dir = os.path.join(config.get_template_directory(),
                                    template)
    if not os.access(template_dir, os.F_OK):
        raise util.CommandError("No such template %r" % template)

    util.status("Creating directory %s" % os.path.abspath(directory),
                os.makedirs, directory)

    versions = os.path.join(directory, 'versions')
    util.status("Creating directory %s" % os.path.abspath(versions),
                os.makedirs, versions)

    script = ScriptDirectory(directory)

    for file_ in os.listdir(template_dir):
        file_path = os.path.join(template_dir, file_)
        if file_ == 'alembic.ini.mako':
            config_file = os.path.abspath(config.config_file_name)
            if os.access(config_file, os.F_OK):
                util.msg("File %s already exists, skipping" % config_file)
            else:
                script._generate_template(
                    file_path,
                    config_file,
                    script_location=directory
                )
        elif os.path.isfile(file_path):
            output_file = os.path.join(directory, file_)
            script._copy_file(
                file_path,
                output_file
            )

    util.msg("Please edit configuration/connection/logging "\
            "settings in %r before proceeding." % config_file)
示例#11
0
    def get_revision(self, id_):
        """Return the :class:`.Script` instance with the given rev id."""

        id_ = self.as_revision_number(id_)
        try:
            return self._revision_map[id_]
        except KeyError:
            # do a partial lookup
            revs = [
                x for x in self._revision_map
                if x is not None and x.startswith(id_)
            ]
            if not revs:
                raise util.CommandError("No such revision '%s'" % id_)
            elif len(revs) > 1:
                raise util.CommandError("Multiple revisions start "
                                        "with '%s', %s..." %
                                        (id_, ", ".join("'%s'" % r
                                                        for r in revs[0:3])))
            else:
                return self._revision_map[revs[0]]
示例#12
0
文件: config.py 项目: zky001/me
    def get_section_option(self, section, name, default=None):
        """Return an option from the given section of the .ini file.

        """
        if not self.file_config.has_section(section):
            raise util.CommandError("No config file %r found, or file has no "
                                    "'[%s]' section" %
                                    (self.config_file_name, section))
        if self.file_config.has_option(section, name):
            return self.file_config.get(section, name)
        else:
            return default
示例#13
0
 def _iterate_revisions(self, upper, lower):
     lower = self.get_revision(lower)
     upper = self.get_revision(upper)
     orig = lower.revision if lower else 'base', \
             upper.revision if upper else 'base'
     script = upper
     while script != lower:
         if script is None and lower is not None:
             raise util.CommandError(
                 "Revision %s is not an ancestor of %s" % orig)
         yield script
         downrev = script.down_revision
         script = self._revision_map[downrev]
示例#14
0
def get_revisions(config, rev_range=None):
    script = ScriptDirectory.from_config(config)

    if rev_range is not None:
        if ":" not in rev_range:
            raise util.CommandError(
                "History range requires [start]:[end], [start]:, or :[end]")
        base, head = rev_range.strip().split(":")
    else:
        base = head = None

    return script.walk_revisions(
        base=base or "base",
        head=head or "heads",
    )
示例#15
0
    def from_config(cls, config):
        """Produce a new :class:`.ScriptDirectory` given a :class:`.Config`
        instance.

        The :class:`.Config` need only have the ``script_location`` key
        present.

        """
        script_location = config.get_main_option('script_location')
        if script_location is None:
            raise util.CommandError("No 'script_location' key "
                                    "found in configuration.")
        return ScriptDirectory(
            util.coerce_resource_to_filename(script_location),
            file_template=config.get_main_option('file_template',
                                                 _default_file_template))
示例#16
0
    def get_current_head(self):
        """Return the current head revision.

        If the script directory has multiple heads
        due to branching, an error is raised.

        Returns a string revision number.

        """
        current_heads = self.get_heads()
        if len(current_heads) > 1:
            raise util.CommandError("Only a single head supported so far...")
        if current_heads:
            return current_heads[0]
        else:
            return None
示例#17
0
    def get_current_revision(self):
        """Return the current revision, usually that which is present
        in the ``alembic_version`` table in the database.

        If this :class:`.MigrationContext` was configured in "offline"
        mode, that is with ``as_sql=True``, the ``starting_rev``
        parameter is returned instead, if any.

        """
        if self.as_sql:
            return self._start_from_rev
        else:
            if self._start_from_rev:
                raise util.CommandError("Can't specify current_rev to context "
                                        "when using a database connection")
            self._version.create(self.connection, checkfirst=True)
        return self.connection.scalar(self._version.select())
示例#18
0
文件: mysql.py 项目: zky001/me
    def __init__(self, name, column_name, schema=None,
                        newname=None,
                        type_=None,
                        nullable=None,
                        default=False,
                        autoincrement=None):
        super(AlterColumn, self).__init__(name, schema=schema)
        self.column_name = column_name
        self.nullable = nullable
        self.newname = newname
        self.default = default
        self.autoincrement = autoincrement
        if type_ is None:
            raise util.CommandError(
                "All MySQL ALTER COLUMN operations "
                "require the existing type."
            )

        self.type_ = sqltypes.to_instance(type_)
示例#19
0
    def mkdir(self):
        """Create the script directory and template."""
        script_dir = self.config.get_main_option("script_location")
        template_src = os.path.join(self.config.get_template_directory(),
                                    "generic", "script.py.mako")
        template_dest = os.path.join(script_dir, "script.py.mako")

        if not os.access(template_src, os.F_OK):
            raise util.CommandError(
                "Template {0} does not exist".format(template_src))

        if not os.access(script_dir, os.F_OK):
            os.makedirs(script_dir)

        if not os.access(template_dest, os.F_OK):
            shutil.copy(template_src, template_dest)

        for version_location in self.script_directory._version_locations:
            if not os.access(version_location, os.F_OK):
                os.makedirs(version_location)
示例#20
0
 def _from_filename(cls, dir_, filename):
     if not _rev_file.match(filename):
         return None
     module = util.load_python_file(dir_, filename)
     if not hasattr(module, "revision"):
         # attempt to get the revision id from the script name,
         # this for legacy only
         m = _legacy_rev.match(filename)
         if not m:
             raise util.CommandError(
                 "Could not determine revision id from filename %s. "
                 "Be sure the 'revision' variable is "
                 "declared inside the script (please see 'Upgrading "
                 "from Alembic 0.1 to 0.2' in the documentation)." %
                 filename)
         else:
             revision = m.group(1)
     else:
         revision = module.revision
     return Script(module, revision, os.path.join(dir_, filename))
示例#21
0
    def get_starting_revision_argument(self):
        """Return the 'starting revision' argument,
        if the revision was passed using ``start:end``.

        This is only meaningful in "offline" mode.
        Returns ``None`` if no value is available
        or was configured.

        This function does not require that the :class:`.MigrationContext`
        has been configured.

        """
        if self._migration_context is not None:
            return self.script._as_rev_number(
                self.get_context()._start_from_rev)
        elif 'starting_rev' in self.context_opts:
            return self.script._as_rev_number(
                self.context_opts['starting_rev'])
        else:
            raise util.CommandError(
                "No starting revision argument is available.")
示例#22
0
def upgrade(config, revision, sql=False, tag=None):
    """Upgrade to a later version."""

    script = ScriptDirectory.from_config(config)

    starting_rev = None
    if ":" in revision:
        if not sql:
            raise util.CommandError("Range revision not allowed")
        starting_rev, revision = revision.split(':', 2)

    def upgrade(rev, context):
        return script._upgrade_revs(revision, rev)

    with EnvironmentContext(
        config,
        script,
        fn = upgrade,
        as_sql = sql,
        starting_rev = starting_rev,
        destination_rev = revision,
        tag = tag
    ):
        script.run_env()
示例#23
0
    def init(self, directory, template="mampoer_generic", package=False):
        """Initialize a new scripts directory.

        :param template: string name of the migration environment template to
        use.

        :param package: when True, write ``__init__.py`` files into the
        environment location as well as the versions/ location.

        .. versionadded:: 1.2


        """

        if os.access(directory, os.F_OK) and os.listdir(directory):
            raise util.CommandError(
                "Directory %s already exists and is not empty" % directory)

        template_dir = os.path.join(self.get_template_directory(), template)
        if not os.access(template_dir, os.F_OK):
            raise util.CommandError("No such template %r" % template)

        if not os.access(directory, os.F_OK):
            util.status(
                "Creating directory %s" % os.path.abspath(directory),
                os.makedirs,
                directory,
            )

        versions = os.path.join(directory, "versions")
        util.status(
            "Creating directory %s" % os.path.abspath(versions),
            os.makedirs,
            versions,
        )

        script = ScriptDirectory(directory)

        for file_ in os.listdir(template_dir):
            file_path = os.path.join(template_dir, file_)
            if file_ == "mampoer.ini.mako":
                config_file = os.path.abspath(self.config.config_file_name)
                if os.access(config_file, os.F_OK):
                    util.msg("File %s already exists, skipping" % config_file)
                else:
                    script._generate_template(file_path,
                                              config_file,
                                              script_location=directory)
            elif os.path.isfile(file_path):
                output_file = os.path.join(directory, file_)
                script._copy_file(file_path, output_file)

        if package:
            for path in [
                    os.path.join(os.path.abspath(directory), "__init__.py"),
                    os.path.join(os.path.abspath(versions), "__init__.py"),
            ]:
                file_ = util.status("Adding %s" % path, open, path, "w")
                file_.close()
        util.msg("Please edit configuration/connection/logging "
                 "settings in %r before proceeding." % config_file)
示例#24
0
    def stamp(self, revision, sql=False, tag=None, purge=False):
        """'stamp' the revision table with the given revision; don't
        run any migrations.

        :param revision: target revision or list of revisions.   May be a list
        to indicate stamping of multiple branch heads.

        .. note:: this parameter is called "revisions" in the command line
            interface.

        .. versionchanged:: 1.2  The revision may be a single revision or
            list of revisions when stamping multiple branch heads.

        :param sql: use ``--sql`` mode

        :param tag: an arbitrary "tag" that can be intercepted by custom
        ``env.py`` scripts via the :class:`.EnvironmentContext.get_tag_argument`
        method.

        :param purge: delete all entries in the version table before stamping.

        .. versionadded:: 1.2

        """

        config = self.config
        script = self.script_directory
        config.attributes["engine"] = self.engine

        output_buffer = io.StringIO()
        config.attributes["output_buffer"] = output_buffer

        starting_rev = None
        if sql:
            destination_revs = []
            for _revision in util.to_list(revision):
                if ":" in _revision:
                    srev, _revision = _revision.split(":", 2)

                    if starting_rev != srev:
                        if starting_rev is None:
                            starting_rev = srev
                        else:
                            raise util.CommandError(
                                "Stamp operation with --sql only supports a "
                                "single starting revision at a time")
                destination_revs.append(_revision)
        else:
            destination_revs = util.to_list(revision)

        def do_stamp(rev, context):
            return script._stamp_revs(util.to_tuple(destination_revs), rev)

        with EnvironmentContext(
                config,
                script,
                fn=do_stamp,
                as_sql=sql,
                starting_rev=starting_rev if sql else None,
                destination_rev=util.to_tuple(destination_revs),
                tag=tag,
                purge=purge,
        ):
            script.run_env()
            output_buffer.seek(0)
            return output_buffer.read()
示例#25
0
 def retrieve_migrations(rev, context):
     if script.get_revision(rev) is not script.get_revision("head"):
         raise util.CommandError("Target database is not up to date.")
     autogen._produce_migration_diffs(context, template_args, imports)
     return []