Esempio n. 1
0
def revsetmatch(ui, pattern):
    try:
        # hg >= 1.9
        return revset.match(ui, pattern)
    except TypeError:
        # hg <= 1.8
        return revset.match(pattern)
Esempio n. 2
0
def getlogrevs(repo, pats, opts):
    """Return (revs, expr, filematcher) where revs is a list of
    revision numbers, expr is a revset string built from log options
    and file patterns or None, and used to filter 'revs'. If --stat or
    --patch are not passed filematcher is None. Otherwise it is a
    callable taking a revision number and returning a match objects
    filtering the files to be detailed when displaying the revision.
    """
    if not len(repo):
        return [], None, None
    # Default --rev value depends on --follow but --follow behaviour
    # depends on revisions resolved from --rev...
    follow = opts.get('follow') or opts.get('follow_first')
    if opts.get('rev'):
        revs = scmutil.revrange(repo, opts['rev'])
    else:
        if follow and len(repo) > 0:
            revs = scmutil.revrange(repo, ['.:0'])
        else:
            revs = range(len(repo) - 1, -1, -1)
    if not revs:
        return [], None, None
    expr, filematcher = _makelogrevset(repo, pats, opts, revs)
    if expr:
        # Evaluate revisions in changelog order for performance
        # reasons but preserve the original sequence order in the
        # filtered result.
        matched = set(revset.match(repo.ui, expr)(repo, sorted(revs)))
        revs = [r for r in revs if r in matched]
    if not opts.get('hidden'):
        # --hidden is still experimental and not worth a dedicated revset
        # yet. Fortunately, filtering revision number is fast.
        revs = [r for r in revs if r not in repo.changelog.hiddenrevs]
    return revs, expr, filematcher
Esempio n. 3
0
 def run(self):
     if '(' not in self.text:
         try:
             ctx = self.repo[self.text]
             self.showMessage.emit(_('found revision'))
             self.queryIssued.emit(self.query, [ctx.rev()])
             return
         except (error.RepoError, error.LookupError, error.Abort):
             self.text = 'keyword("%s")' % self.text
     cwd = os.getcwd()
     try:
         os.chdir(self.repo.root)
         func = revset.match(self.repo.ui, self.text)
         l = []
         for c in func(self.repo, range(len(self.repo))):
             l.append(c)
         if len(l):
             self.showMessage.emit(_('%d matches found') % len(l))
         else:
             self.showMessage.emit(_('No matches found'))
         self.queryIssued.emit(self.query, l)
     except error.ParseError, e:
         if len(e.args) == 2:
             msg, pos = e.args
             self.setCursorPosition.emit(0, pos)
         else:
             msg = e.args[0]
         self.showMessage.emit(_('Parse Error: ') + hglib.tounicode(msg))
Esempio n. 4
0
 def run(self):
     if '(' not in self.text:
         try:
             ctx = self.repo[self.text]
             self.showMessage.emit(_('found revision'))
             self.queryIssued.emit(self.query, [ctx.rev()])
             return
         except (error.RepoError, error.LookupError, error.Abort):
             self.text = 'keyword("%s")' % self.text
     cwd = os.getcwd()
     try:
         os.chdir(self.repo.root)
         func = revset.match(self.repo.ui, self.text)
         l = []
         for c in func(self.repo, range(len(self.repo))):
             l.append(c)
         if len(l):
             self.showMessage.emit(_('%d matches found') % len(l))
         else:
             self.showMessage.emit(_('No matches found'))
         self.queryIssued.emit(self.query, l)
     except error.ParseError, e:
         if len(e.args) == 2:
             msg, pos = e.args
             self.setCursorPosition.emit(0, pos)
         else:
             msg = e.args[0]
         self.showMessage.emit(_('Parse Error: ') + hglib.tounicode(msg))
Esempio n. 5
0
    def update_info(self, *args):
        def set_csinfo_mode(mode):
            """Show the csinfo widget or the info text label"""
            # hide first, then show
            if mode:
                self.rev_to_match_info_text.setShown(False)
                self.rev_to_match_info.setShown(True)
            else:
                self.rev_to_match_info.setShown(False)
                self.rev_to_match_info_text.setShown(True)

        def csinfo_update(ctx):
            self.rev_to_match_info.update(ctx)
            set_csinfo_mode(True)

        def csinfo_set_text(text):
            self.rev_to_match_info_text.setText(text)
            set_csinfo_mode(False)

        self.rev_to_match_info_lbl.setText(_('Revision to Match:'))
        new_rev = hglib.fromunicode(self.rev_combo.currentText())
        if new_rev.lower() == 'null':
            self.match_btn.setEnabled(True)
            return
        try:
            csinfo_update(self.repo[new_rev])
            return
        except (error.LookupError, error.RepoLookupError, error.RepoError):
            pass

        # If we get this far, assume we are matching a revision set
        validrevset = False
        try:
            func = revset.match(self.repo.ui, new_rev)
            rset = [c for c in func(self.repo, range(len(self.repo)))]
            if len(rset) > 1:
                self.rev_to_match_info_lbl.setText(_('Revisions to Match:'))
                csinfo_set_text(_('Match any of <b><i>%d</i></b> revisions') \
                    % len(rset))
            else:
                self.rev_to_match_info_lbl.setText(_('Revision to Match:'))
                csinfo_update(rset[0])
            validrevset = True
        except (error.LookupError, error.RepoLookupError):
            csinfo_set_text(_('<b>Unknown revision!</b>'))
        except (error.ParseError):
            csinfo_set_text(_('<b>Parse Error!</b>'))
        if validrevset:
            self.match_btn.setEnabled(True)
        else:
            self.match_btn.setDisabled(True)
Esempio n. 6
0
    def update_info(self, *args):
        def set_csinfo_mode(mode):
            """Show the csinfo widget or the info text label"""
            # hide first, then show
            if mode:
                self.rev_to_match_info_text.setShown(False)
                self.rev_to_match_info.setShown(True)
            else:
                self.rev_to_match_info.setShown(False)
                self.rev_to_match_info_text.setShown(True)
        def csinfo_update(ctx):
            self.rev_to_match_info.update(ctx)
            set_csinfo_mode(True)
        def csinfo_set_text(text):
            self.rev_to_match_info_text.setText(text)
            set_csinfo_mode(False)

        self.rev_to_match_info_lbl.setText(_('Revision to Match:'))
        new_rev = hglib.fromunicode(self.rev_combo.currentText())
        if new_rev.lower() == 'null':
            self.match_btn.setEnabled(True)
            return
        try:
            csinfo_update(self.repo[new_rev])
            return
        except (error.LookupError, error.RepoLookupError, error.RepoError):
            pass

        # If we get this far, assume we are matching a revision set
        validrevset = False
        try:
            func = revset.match(self.repo.ui, new_rev)
            rset = [c for c in func(self.repo, range(len(self.repo)))]
            if len(rset) > 1:
                self.rev_to_match_info_lbl.setText(_('Revisions to Match:'))
                csinfo_set_text(_('Match any of <b><i>%d</i></b> revisions') \
                    % len(rset))
            else:
                self.rev_to_match_info_lbl.setText(_('Revision to Match:'))
                csinfo_update(rset[0])
            validrevset = True
        except (error.LookupError, error.RepoLookupError):
            csinfo_set_text(_('<b>Unknown revision!</b>'))
        except (error.ParseError):
            csinfo_set_text(_('<b>Parse Error!</b>'))
        if validrevset:
            self.match_btn.setEnabled(True)
        else:
            self.match_btn.setDisabled(True)
Esempio n. 7
0
    def commit(self):
        tip, base = self.revs
        func = revset.match(self.repo.ui, '%s::%s' % (base, tip))
        revcount = len(self.repo)
        revs = [c for c in func(self.repo, range(revcount)) if c != base]
        descs = [self.repo[c].description() for c in revs]
        self.repo.opener('cur-message.txt', 'w').write('\n* * *\n'.join(descs))

        dlg = commit.CommitDialog(self.repo, [], {}, self)
        dlg.finished.connect(dlg.deleteLater)
        dlg.exec_()
        self.showMessage.emit(_('Compress is complete, old history untouched'))
        self.compressbtn.setText(_('Close'))
        self.compressbtn.clicked.disconnect(self.commit)
        self.compressbtn.clicked.connect(self.accept)
Esempio n. 8
0
    def commit(self):
        tip, base = self.revs
        func = revset.match(self.repo.ui, '%s::%s' % (base, tip))
        revcount = len(self.repo)
        revs = [c for c in func(self.repo, range(revcount)) if c != base]
        descs = [self.repo[c].description() for c in revs]
        self.repo.opener('cur-message.txt', 'w').write('\n* * *\n'.join(descs))

        dlg = commit.CommitDialog(self.repo, [], {}, self)
        dlg.finished.connect(dlg.deleteLater)
        dlg.exec_()
        self.showMessage.emit(_('Compress is complete, old history untouched'))
        self.compressbtn.setText(_('Close'))
        self.compressbtn.clicked.disconnect(self.commit)
        self.compressbtn.clicked.connect(self.accept)
Esempio n. 9
0
 def run(self):
     cwd = os.getcwd()
     try:
         os.chdir(self.repo.root)
         func = revset.match(self.repo.ui, self.text)
         l = list(func(self.repo, list(self.repo)))
         if len(l):
             self.showMessage.emit(_('%d matches found') % len(l))
         else:
             self.showMessage.emit(_('No matches found'))
         self.queryIssued.emit(self.query, l)
     except error.ParseError, e:
         if len(e.args) == 2:
             msg, pos = e.args
             self.setCursorPosition.emit(0, pos)
         else:
             msg = e.args[0]
         self.showMessage.emit(_('Parse Error: ') + hglib.tounicode(msg))
Esempio n. 10
0
 def run(self):
     cwd = os.getcwd()
     try:
         os.chdir(self.repo.root)
         func = revset.match(self.repo.ui, self.text)
         l = list(func(self.repo, list(self.repo)))
         if len(l):
             self.showMessage.emit(_('%d matches found') % len(l))
         else:
             self.showMessage.emit(_('No matches found'))
         self.queryIssued.emit(self.query, l)
     except error.ParseError, e:
         if len(e.args) == 2:
             msg, pos = e.args
             self.setCursorPosition.emit(0, pos)
         else:
             msg = e.args[0]
         self.showMessage.emit(_('Parse Error: ') + hglib.tounicode(msg))
Esempio n. 11
0
    def getsearchmode(query):
        try:
            ctx = web.repo[query]
        except (error.RepoError, error.LookupError):
            # query is not an exact revision pointer, need to
            # decide if it's a revset expression or keywords
            pass
        else:
            return MODE_REVISION, ctx

        revdef = 'reverse(%s)' % query
        try:
            tree = revset.parse(revdef)
        except ParseError:
            # can't parse to a revset tree
            return MODE_KEYWORD, query

        if revset.depth(tree) <= 2:
            # no revset syntax used
            return MODE_KEYWORD, query

        if any((token, (value or '')[:3]) == ('string', 're:')
               for token, value, pos in revset.tokenize(revdef)):
            return MODE_KEYWORD, query

        funcsused = revset.funcsused(tree)
        if not funcsused.issubset(revset.safesymbols):
            return MODE_KEYWORD, query

        mfunc = revset.match(web.repo.ui, revdef)
        try:
            revs = mfunc(web.repo)
            return MODE_REVSET, revs
            # ParseError: wrongly placed tokens, wrongs arguments, etc
            # RepoLookupError: no such revision, e.g. in 'revision:'
            # Abort: bookmark/tag not exists
            # LookupError: ambiguous identifier, e.g. in '(bc)' on a large repo
        except (ParseError, RepoLookupError, Abort, LookupError):
            return MODE_KEYWORD, query
Esempio n. 12
0
    def getsearchmode(query):
        try:
            ctx = web.repo[query]
        except (error.RepoError, error.LookupError):
            # query is not an exact revision pointer, need to
            # decide if it's a revset expression or keywords
            pass
        else:
            return MODE_REVISION, ctx

        revdef = 'reverse(%s)' % query
        try:
            tree, pos = revset.parse(revdef)
        except ParseError:
            # can't parse to a revset tree
            return MODE_KEYWORD, query

        if revset.depth(tree) <= 2:
            # no revset syntax used
            return MODE_KEYWORD, query

        if util.any((token, (value or '')[:3]) == ('string', 're:')
                    for token, value, pos in revset.tokenize(revdef)):
            return MODE_KEYWORD, query

        funcsused = revset.funcsused(tree)
        if not funcsused.issubset(revset.safesymbols):
            return MODE_KEYWORD, query

        mfunc = revset.match(web.repo.ui, revdef)
        try:
            revs = mfunc(web.repo, list(web.repo))
            return MODE_REVSET, revs
            # ParseError: wrongly placed tokens, wrongs arguments, etc
            # RepoLookupError: no such revision, e.g. in 'revision:'
            # Abort: bookmark/tag not exists
            # LookupError: ambiguous identifier, e.g. in '(bc)' on a large repo
        except (ParseError, RepoLookupError, Abort, LookupError):
            return MODE_KEYWORD, query
Esempio n. 13
0
 def revs(self, expr, *args):
     expr = revsetlang.formatspec(expr, *args)
     m = revset.match(None, expr)
     return m(self)
Esempio n. 14
0
def getfastlogrevs(orig, repo, pats, opts):
    blacklist = ['all', 'branch', 'rev', 'sparse']
    if any(opts.get(opt) for opt in blacklist) or not opts.get('follow'):
        return orig(repo, pats, opts)

    reponame = repo.ui.config('fbconduit', 'reponame')
    if reponame and repo.ui.configbool('fastlog', 'enabled'):
        wctx = repo[None]
        match, pats = scmutil.matchandpats(wctx, pats, opts)
        files = match.files()
        if not files or '.' in files:
            # Walking the whole repo - bail on fastlog
            return orig(repo, pats, opts)

        dirs = set()
        wvfs = repo.wvfs
        for path in files:
            if wvfs.isdir(path) and not wvfs.islink(path):
                dirs.update([path + '/'])
            else:
                # bail on symlinks, and also bail on files for now
                # with follow behavior, for files, we are supposed
                # to track copies / renames, but it isn't convenient
                # to do this through scmquery
                return orig(repo, pats, opts)

        rev = repo['.'].rev()

        parents = repo.changelog.parentrevs
        public = set()

        # Our criterion for invoking fastlog is finding a single
        # common public ancestor from the current head.  First we
        # have to walk back through drafts to find all interesting
        # public parents.  Typically this will just be one, but if
        # there are merged drafts, we may have multiple parents.
        if repo[rev].phase() == phases.public:
            public.add(rev)
        else:
            queue = deque()
            queue.append(rev)
            seen = set()
            while queue:
                cur = queue.popleft()
                if cur not in seen:
                    seen.add(cur)
                    if repo[cur].mutable():
                        for p in parents(cur):
                            if p != nullrev:
                                queue.append(p)
                    else:
                        public.add(cur)

        def fastlog(repo, startrev, dirs, localmatch):
            filefunc = repo.changelog.readfiles
            for parent in lazyparents(startrev, public, parents):
                files = filefunc(parent)
                if dirmatches(files, dirs):
                    yield parent
            repo.ui.debug('found common parent at %s\n' % repo[parent].hex())
            for rev in combinator(repo, parent, dirs, localmatch):
                yield rev

        def combinator(repo, rev, dirs, localmatch):
            """combinator(repo, rev, dirs, localmatch)
            Make parallel local and remote queries along ancestors of
            rev along path and combine results, eliminating duplicates,
            restricting results to those which match dirs
            """
            LOCAL = 'L'
            REMOTE = 'R'
            queue = util.queue(FASTLOG_QUEUE_SIZE + 100)
            hash = repo[rev].hex()

            local = LocalIteratorThread(queue, LOCAL, rev,
                                        dirs, localmatch, repo)
            remote = FastLogThread(queue, REMOTE, reponame, 'hg', hash, dirs,
                                   repo)

            # Allow debugging either remote or local path
            debug = repo.ui.config('fastlog', 'debug')
            if debug != 'local':
                repo.ui.debug('starting fastlog at %s\n' % hash)
                remote.start()
            if debug != 'remote':
                local.start()
            seen = set([rev])

            try:
                while True:
                    try:
                        producer, success, msg = queue.get(True, 3600)
                    except util.empty:
                        raise error.Abort("Timeout reading log data")
                    if not success:
                        if producer == LOCAL:
                            raise error.Abort(msg)
                        elif msg:
                            repo.ui.log("hgfastlog", msg)
                            continue

                    if msg is None:
                        # Empty message means no more results
                        return

                    rev = msg
                    if debug:
                        if producer == LOCAL:
                            repo.ui.debug('LOCAL:: %s\n' % msg)
                        elif producer == REMOTE:
                            repo.ui.debug('REMOTE:: %s\n' % msg)

                    if rev not in seen:
                        seen.add(rev)
                        yield rev
            finally:
                local.stop()
                remote.stop()

        # Complex match - use a revset.
        complex = ['date', 'exclude', 'include', 'keyword', 'no_merges',
                   'only_merges', 'prune', 'user']
        if match.anypats() or any(opts.get(opt) for opt in complex):
            f = fastlog(repo, rev, dirs, None)
            revs = smartset.generatorset(f, iterasc=False)
            revs.reverse()
            if not revs:
                return smartset.baseset([]), None, None
            expr, filematcher = cmdutil._makelogrevset(repo, pats, opts, revs)
            matcher = revset.match(repo.ui, expr)
            matched = matcher(repo, revs)
            return matched, expr, filematcher
        else:
            # Simple match without revset shaves ~0.5 seconds off
            # hg log -l 100 -T ' ' on common directories.
            expr = 'fastlog(%s)' % ','.join(dirs)
            return fastlog(repo, rev, dirs, dirmatches), expr, None

    return orig(repo, pats, opts)