Exemple #1
0
 def __init__(self, app, migrations_folder=None):
     self.app = app
     self.path = os.path.join(app.root_path, migrations_folder
                              or 'migrations')
     if not os.path.exists(self.path):
         os.mkdir(self.path)
     self.cwd = os.path.dirname(__file__)
     self.file_template = self.app.config.migrations.file_template or \
         self._default_file_template
     self.truncate_slug_length = \
         self.app.config.migrations.filename_len or 40
     self.revision_map = RevisionsMap(self.app, self._load_revisions)
     self.templater = Renoir(path=self.cwd, mode='plain')
def templater_html_indent():
    return Renoir(
        escape='all', adjust_indent=True, debug=True,
        path=os.path.join(
            os.path.dirname(os.path.abspath(__file__)), 'html'
        )
    )
def templater_noreload():
    return Renoir()
def templater_reload():
    return Renoir(reload=True)
Exemple #5
0
class ScriptDir(object):
    _slug_re = re.compile(r'\w+')
    _default_file_template = "%(rev)s_%(slug)s"

    def __init__(self, app, migrations_folder=None):
        self.app = app
        self.path = os.path.join(app.root_path, migrations_folder
                                 or 'migrations')
        if not os.path.exists(self.path):
            os.mkdir(self.path)
        self.cwd = os.path.dirname(__file__)
        self.file_template = self.app.config.migrations.file_template or \
            self._default_file_template
        self.truncate_slug_length = \
            self.app.config.migrations.filename_len or 40
        self.revision_map = RevisionsMap(self.app, self._load_revisions)
        self.templater = Renoir(path=self.cwd, mode='plain')

    def _load_revisions(self):
        sys.path.insert(0, self.path)
        for rev_file in os.listdir(os.path.abspath(self.path)):
            script = Script._from_filename(self, rev_file)
            if script is None:
                continue
            yield script

    @contextmanager
    def _catch_revision_errors(self,
                               ancestor=None,
                               multiple_heads=None,
                               start=None,
                               end=None,
                               resolution=None):
        try:
            yield
        except RangeNotAncestorError as rna:
            if start is None:
                start = rna.lower
            if end is None:
                end = rna.upper
            if not ancestor:
                ancestor = (
                    "Requested range %(start)s:%(end)s does not refer to "
                    "ancestor/descendant revisions along the same branch")
            ancestor = ancestor % {"start": start, "end": end}
            raise Exception(ancestor)
        except MultipleHeads as mh:
            if not multiple_heads:
                multiple_heads = (
                    "Multiple head revisions are present for given "
                    "argument '%(head_arg)s'; please "
                    "specify a specific target revision, "
                    "'<branchname>@%(head_arg)s' to "
                    "narrow to a specific head, or 'heads' for all heads")
            multiple_heads = multiple_heads % {
                "head_arg": end or mh.argument,
                "heads": str(mh.heads)
            }
            raise Exception(multiple_heads)
        except ResolutionError as re:
            if resolution is None:
                resolution = "Can't locate revision identified by '%s'" % (
                    re.argument)
            raise Exception(resolution)
        except RevisionError as err:
            raise Exception(err.args[0])

    def walk_revisions(self, base="base", head="heads"):
        with self._catch_revision_errors(start=base, end=head):
            for rev in self.revision_map.iterate_revisions(head,
                                                           base,
                                                           inclusive=True):
                yield rev

    def get_revision(self, revid):
        with self._catch_revision_errors():
            return self.revision_map.get_revision(revid)

    def get_revisions(self, revid):
        with self._catch_revision_errors():
            return self.revision_map.get_revisions(revid)

    def get_upgrade_revs(self, destination, current_rev):
        with self._catch_revision_errors(
                ancestor="Destination %(end)s is not a valid upgrade "
                "target from current head(s)",
                end=destination):
            revs = self.revision_map.iterate_revisions(destination,
                                                       current_rev,
                                                       implicit_base=True)
            return reversed(list(revs))

    def get_downgrade_revs(self, destination, current_rev):
        with self._catch_revision_errors(
                ancestor="Destination %(end)s is not a valid downgrade "
                "target from current head(s)",
                end=destination):
            revs = self.revision_map.iterate_revisions(current_rev,
                                                       destination)
            return list(revs)

    def _rev_filename(self, revid, message, creation_date):
        slug = "_".join(self._slug_re.findall(message or "")).lower()
        if len(slug) > self.truncate_slug_length:
            slug = slug[:self.truncate_slug_length].rsplit('_', 1)[0] + '_'
        filename = "%s.py" % (self.file_template % {
            'rev': revid,
            'slug': slug,
            'year': creation_date.year,
            'month': creation_date.month,
            'day': creation_date.day,
            'hour': creation_date.hour,
            'minute': creation_date.minute,
            'second': creation_date.second
        })
        return filename

    def _generate_template(self, filename, ctx):
        rendered = self.templater.render('migration.tmpl', ctx)
        with open(os.path.join(self.path, filename), 'w') as f:
            f.write(rendered)

    def generate_revision(self, revid, message, head=None, splice=False, **kw):
        """Generate a new revision file.

        This runs the templater, and creates a new file.

        :param revid: String revision id.
        :param message: the revision message.
        :param head: the head revision to generate against. Defaults
         to the current "head" if no branches are present, else raises
         an exception.
        :param splice: if True, allow the "head" version to not be an
         actual head; otherwise, the selected head must be a head
         (e.g. endpoint) revision.
        """
        if head is None:
            head = "head"

        with self._catch_revision_errors(multiple_heads=(
                "Multiple heads are present; please specify the head "
                "revision on which the new revision should be based, "
                "or perform a merge.")):
            heads = self.revision_map.get_revisions(head)

        if len(set(heads)) != len(heads):
            raise Exception("Duplicate head revisions specified")

        creation_date = datetime.now()

        rev_filename = self._rev_filename(revid, message, creation_date)

        if not splice:
            for head in heads:
                if head is not None and not head.is_head:
                    raise Exception(
                        "Revision %s is not a head revision; please specify "
                        "--splice to create a new branch from this revision" %
                        head.revision)

        down_migration = tuple(h.revision if h is not None else None
                               for h in heads)

        down_migration_var = tuple_rev_as_scalar(down_migration)
        if isinstance(down_migration_var, str):
            down_migration_var = "%r" % down_migration_var
        else:
            down_migration_var = str(down_migration_var)

        template_ctx = dict(
            asis=asis,
            up_migration=revid,
            down_migration=down_migration_var,
            creation_date=creation_date,
            down_migration_str=", ".join(r for r in down_migration),
            message=message if message is not None else ("empty message"),
            upgrades=kw.get('upgrades', ['pass']),
            downgrades=kw.get('downgrades', ['pass']))
        self._generate_template(rev_filename, template_ctx)

        script = Script._from_filename(self, rev_filename)
        self.revision_map.add_revision(script)
        return script
def templater_html():
    return Renoir(
        debug=True, path=os.path.join(
            os.path.dirname(os.path.abspath(__file__)), 'html'
        )
    )
def templater_indent():
    return Renoir(
        mode='plain', adjust_indent=True, debug=True, path=os.path.join(
            os.path.dirname(os.path.abspath(__file__)), 'yaml'
        )
    )
def templater_blocks():
    return Renoir(
        mode='plain', debug=True, path=os.path.join(
            os.path.dirname(os.path.abspath(__file__)), 'blocks'
        )
    )
Exemple #9
0
    @property
    def current_line(self):
        try:
            return self.sourcelines[self.lineno - 1]
        except IndexError:
            return u''

    @cachedprop
    def render_locals(self):
        rv = dict()
        for k, v in self.locals.items():
            try:
                rv[k] = str(v)
            except Exception:
                rv[k] = '<unavailable>'
        return rv


debug_templater = Renoir(
    path=os.path.join(os.path.dirname(__file__), 'assets', 'debug'))


def smart_traceback(app):
    exc_type, exc_value, tb = sys.exc_info()
    return Traceback(app, exc_type, exc_value, tb)


def debug_handler(tb):
    return debug_templater.render('view.html', {'tb': tb})
def templater_escape():
    return Renoir(escape='all', debug=True)
def templater_indent():
    return Renoir(mode='plain', adjust_indent=True, debug=True)
def templater():
    return Renoir(mode='plain', debug=True)
def templater():
    rv = Renoir()
    rv.use_extension(FooExtension)
    rv.use_extension(BarExtension)
    return rv