def _resolve_entry(self, path): """Given a path, load its node and flags, or raise KeyError if missing. This takes into account any pending writes in the builder. """ upath = pycompat.fsdecode(path) ent = None if path in self._pending_changes: val = self._pending_changes[path] if val is None: raise KeyError return val t = self._tree comps = upath.split('/') te = self._tree for comp in comps[:-1]: te = te[comp] t = self._git_repo[te.id] ent = t[comps[-1]] if ent.filemode == pygit2.GIT_FILEMODE_BLOB: flags = b'' elif ent.filemode == pygit2.GIT_FILEMODE_BLOB_EXECUTABLE: flags = b'x' elif ent.filemode == pygit2.GIT_FILEMODE_LINK: flags = b'l' else: raise ValueError('unsupported mode %s' % oct(ent.filemode)) return ent.id.raw, flags
def drop(self, f): index = self.git.index index.read() fs = pycompat.fsdecode(f) if fs in index: index.remove(fs) index.write()
def _promptvctextension(ui, cw, ext, msg): ext_path = _vctextpath(pycompat.sysstr(ext)) # Do nothing (return) if the user has configured this extension, unless it # points to the directory that we manage and that directory is missing. users_ext_path = ui.config(b'extensions', ext) if users_ext_path != None: users_ext_path = pycompat.fsdecode( util.normpath(util.expandpath(users_ext_path))) if users_ext_path != ext_path or os.path.exists(ext_path): return # Verify the extension loads before prompting to enable it. This is # done out of paranoia. # Even if we launch hg.exe, sys.argv[0] is "hg" on Windows. Since "hg" isn't # a Windows application, we can't simply run it. So change to the ".exe" # variant if necessary. hg = sys.argv[0] if sys.platform in ('win32', 'msys') and hg.endswith('hg'): hg += '.exe' result = subprocess.check_output([ hg, '--config', 'extensions.testmodule=%s' % ext_path, '--config', 'ui.traceback=true' ], stderr=subprocess.STDOUT) if b'Traceback' in result: return if uipromptchoice(ui, b'%s (Yn) $$ &Yes $$ &No' % msg): return _enableext(cw, pycompat.sysstr(ext), ext_path)
def applychanges(self, repo, tr, changes): """Apply a list of changes to bookmarks""" # TODO: this should respect transactions, but that's going to # require enlarging the gitbmstore to know how to do in-memory # temporary writes and read those back prior to transaction # finalization. for name, node in changes: if node is None: self.gitrepo.references.delete(_BMS_PREFIX + pycompat.fsdecode(name)) else: self.gitrepo.references.create( _BMS_PREFIX + pycompat.fsdecode(name), gitutil.togitnode(node), force=True, )
def parents(self, node): gn = gitutil.togitnode(node) gp = pycompat.fsdecode(self.path) ps = [] for p in self._db.execute( '''SELECT p1filenode, p2filenode FROM changedfiles WHERE filenode = ? AND filename = ? ''', (gn, gp), ).fetchone(): if p is None: commit = self._db.execute( "SELECT node FROM changedfiles " "WHERE filenode = ? AND filename = ?", (gn, gp), ).fetchone()[0] # This filelog is missing some data. Build the # filelog, then recurse (which will always find data). if pycompat.ispy3: commit = commit.decode('ascii') index.fill_in_filelog(self.gitrepo, self._db, commit, gp, gn) return self.parents(node) else: ps.append(bin(p)) return ps
def set_untracked(self, f): index = self.git.index index.read() fs = pycompat.fsdecode(f) if fs in index: index.remove(fs) index.write() return True return False
def set_tracked(self, f): uf = pycompat.fsdecode(f) if uf in self.git.index: return False index = self.git.index index.read() index.add(uf) index.write() return True
def __iter__(self): for clrev in self._db.execute( ''' SELECT rev FROM changelog INNER JOIN changedfiles ON changelog.node = changedfiles.node WHERE changedfiles.filename = ? AND changedfiles.filenode != ? ''', (pycompat.fsdecode(self.path), gitutil.nullgit), ): yield clrev[0]
def _checkevolve(ui, cw, hg_version): if hg_version < (4, 3, 0): ui.warn(EVOLVE_INCOMPATIBLE) return remote_evolve_path = b'https://www.mercurial-scm.org/repo/evolve/' # Install to the same dir as v-c-t, unless the mozbuild directory path is passed (testing) evolve_clone_dir = ui.config(b'mozilla', b'mozbuild_state_path', _vcthome()) local_evolve_path = b'%(evolve_clone_dir)s/evolve' % {b'evolve_clone_dir': evolve_clone_dir} evolve_config_value = os.path.normpath('%(evolve_path)s/hgext3rd/evolve' % \ {'evolve_path': pycompat.sysstr(local_evolve_path)}) users_evolve_path = ui.config(b'extensions', b'evolve') if users_evolve_path: users_evolve_path = os.path.normpath(pycompat.fsdecode(util.normpath(util.expandpath(users_evolve_path)))) # If evolve is not installed, install it. (If the user's path to evolve is # the path that we manage, but it doesn't exist yet, assume that their # config file has been copied to a new machine and we need to clone evolve. if users_evolve_path == None or \ (users_evolve_path == evolve_config_value and not os.path.exists(evolve_config_value)): if uipromptchoice(ui, EVOLVE_INFO_WARNING): return try: # Clone the evolve extension and enable hg.clone(ui, {}, remote_evolve_path, branch=(b'stable',), dest=local_evolve_path) _enableext(cw, 'evolve', evolve_config_value) ui.write(b'Evolve was downloaded successfully.\n') except error.Abort as hg_err: ui.write(pycompat.bytestr(hg_err)) ui.write(EVOLVE_CLONE_ERROR) return # If evolve is installed and managed by this wizard, # update it via pull/update if users_evolve_path == evolve_config_value: if uipromptchoice(ui, EVOLVE_UPDATE_PROMPT % {b'evolve_dir': local_evolve_path}): return try: local_evolve_repo = hg.repository(ui, local_evolve_path) # Pull the latest stable, update to tip hgpull(ui, local_evolve_repo, source=remote_evolve_path, branch=(b'stable',)) hgupdate(ui, local_evolve_repo, rev=b'stable') ui.write(b'Evolve was updated successfully.\n') except error.Abort as hg_err: ui.write(EVOLVE_CLONE_ERROR)
def rev(self, node): row = self._db.execute( ''' SELECT rev FROM changelog INNER JOIN changedfiles ON changelog.node = changedfiles.node WHERE changedfiles.filename = ? AND changedfiles.filenode = ?''', (pycompat.fsdecode(self.path), gitutil.togitnode(node)), ).fetchone() if row is None: raise error.LookupError(self.path, node, _(b'no such node')) return int(row[0])
def node(self, rev): maybe = self._db.execute( '''SELECT filenode FROM changedfiles INNER JOIN changelog ON changelog.node = changedfiles.node WHERE changelog.rev = ? AND filename = ? ''', (rev, pycompat.fsdecode(self.path)), ).fetchone() if maybe is None: raise IndexError('gitlog %r out of range %d' % (self.path, rev)) return bin(maybe[0])
def inner(*args, **kwargs): cassette = pycompat.fsdecode(kwargs.pop(r'test_vcr', None)) if cassette: import hgdemandimport with hgdemandimport.deactivated(): import vcr as vcrmod import vcr.stubs as stubs vcr = vcrmod.VCR(serializer=r'json', before_record_request=sanitiserequest, before_record_response=sanitiseresponse, custom_patches=[ (urlmod, r'httpconnection', stubs.VCRHTTPConnection), (urlmod, r'httpsconnection', stubs.VCRHTTPSConnection), ]) vcr.register_matcher(r'hgmatcher', hgmatcher) with vcr.use_cassette(cassette, match_on=[r'hgmatcher']): return fn(*args, **kwargs) return fn(*args, **kwargs)
def remove(self, f): index = self.git.index index.read() index.remove(pycompat.fsdecode(f)) index.write()
def getgid(groupname): try: gid = grp.getgrnam(pycompat.fsdecode(groupname)).gr_gid return gid except KeyError: return None
def __getitem__(self, k): return ( self.gitrepo.references[_BMS_PREFIX + pycompat.fsdecode(k)] .peel() .id.raw )
def __contains__(self, name): return ( _BMS_PREFIX + pycompat.fsdecode(name) ) in self.gitrepo.references
def add(self, f): index = self.git.index index.read() index.add(pycompat.fsdecode(f)) index.write()
def write(self, transaction, link, p1, p2, added, removed, match=None): # We're not (for now, anyway) going to audit filenames, so we # can ignore added and removed. # TODO what does this match argument get used for? hopefully # just narrow? assert not match or isinstance(match, matchmod.alwaysmatcher) touched_dirs = pathutil.dirs(list(self._pending_changes)) trees = { b'': self._tree, } # path: treebuilder builders = { b'': self._repo.TreeBuilder(self._tree), } # get a TreeBuilder for every tree in the touched_dirs set for d in sorted(touched_dirs, key=lambda x: (len(x), x)): if d == b'': # loaded root tree above continue comps = d.split(b'/') full = b'' for part in comps: parent = trees[full] try: parent_tree_id = parent[pycompat.fsdecode(part)].id new = self._repo[parent_tree_id] except KeyError: # new directory new = None full += b'/' + part if new is not None: # existing directory trees[full] = new builders[full] = self._repo.TreeBuilder(new) else: # new directory, use an empty dict to easily # generate KeyError as any nested new dirs get # created. trees[full] = {} builders[full] = self._repo.TreeBuilder() for f, info in self._pending_changes.items(): if b'/' not in f: dirname = b'' basename = f else: dirname, basename = f.rsplit(b'/', 1) dirname = b'/' + dirname if info is None: builders[dirname].remove(pycompat.fsdecode(basename)) else: n, fl = info mode = { b'': pygit2.GIT_FILEMODE_BLOB, b'x': pygit2.GIT_FILEMODE_BLOB_EXECUTABLE, b'l': pygit2.GIT_FILEMODE_LINK, }[fl] builders[dirname].insert( pycompat.fsdecode(basename), gitutil.togitnode(n), mode ) # This visits the buffered TreeBuilders in deepest-first # order, bubbling up the edits. for b in sorted(builders, key=len, reverse=True): if b == b'': break cb = builders[b] dn, bn = b.rsplit(b'/', 1) builders[dn].insert( pycompat.fsdecode(bn), cb.write(), pygit2.GIT_FILEMODE_TREE ) return builders[b''].write().raw