def clone_repo_and_checkout_tag(localRepo, bookid, tagname, filename, dest_path): repo_home = pathof(localRepo) repo_home = repo_home.replace("/", os.sep) repo_path = os.path.join(repo_home, "epub_" + bookid) dest_path = dest_path.replace("/", os.sep) cdir = os.getcwd() # first verify both repo and tagname exist taglst = [] if os.path.exists(repo_path): if not os.path.exists(dest_path): return "" os.chdir(repo_path) tags = porcelain.list_tags(repo='.') for atag in tags: taglst.append(unicode_str(atag)) # use dest_path to clone into # clone current repo "s" into new repo "r" with open_repo_closing(".") as s: s.clone(dest_path, mkdir=False, bare=False, origin=b"origin", checkout=False) # cd out **before** the repo closes os.chdir(dest_path) with open_repo_closing(".") as r: if tagname not in taglist or tagname == "HEAD": tagkey = utf8_str("HEAD") else: tagkey = utf8_str("refs/tags/" + tagname) refkey = tagkey # if annotated tag get the commit id it pointed to instead if isinstance(r[tagkey], Tag): refkey = r[tagkey].object[1] r.reset_index(r[refkey].tree) r.refs.set_symbolic_ref(b"HEAD", tagkey) # cd out **before** the repo closes os.chdir(cdir) return "success"
def __load_repo_metadata(self, repo_url): from dulwich import porcelain subdir = get_repo_subdir(repo_url) repo_dir = os.path.join(self.__beq_dir, subdir) commit_url = get_commit_url(repo_url) try: with porcelain.open_repo_closing(repo_dir) as local_repo: last_commit = local_repo[local_repo.head()] last_commit_time_utc = last_commit.commit_time last_commit_qdt = QDateTime() last_commit_qdt.setTime_t(last_commit_time_utc) self.lastCommitDate.setDateTime(last_commit_qdt) from datetime import datetime import calendar d = datetime.utcnow() now_utc = calendar.timegm(d.utctimetuple()) days_since_commit = (now_utc - last_commit_time_utc) / 60 / 60 / 24 warning_msg = '' if days_since_commit > 7.0: warning_msg = f" was {round(days_since_commit)} days ago, press the button to update -->" commit_link = f"{commit_url}/{last_commit.id.decode('utf-8')}" self.infoLabel.setText(f"<a href=\"{commit_link}\">Last Commit</a>{warning_msg}") self.infoLabel.setTextFormat(Qt.RichText) self.infoLabel.setTextInteractionFlags(Qt.TextBrowserInteraction) self.infoLabel.setOpenExternalLinks(True) self.lastCommitMessage.setPlainText( f"Author: {last_commit.author.decode('utf-8')}\n\n{last_commit.message.decode('utf-8')}") except: logger.exception(f"Unable to open git repo in {self.__beq_dir}") self.__beq_dir_not_exists(repo_url)
def get_tag_list(localRepo, bookid): repo_home = pathof(localRepo) repo_home = repo_home.replace("/", os.sep) repo_path = os.path.join(repo_home, "epub_" + bookid) cdir = os.getcwd() taglst = [] if os.path.exists(repo_path): os.chdir(repo_path) with open_repo_closing(".") as r: tags = sorted(r.refs.as_dict(b"refs/tags")) for atag in tags: tagkey = b"refs/tags/" + atag obj = r[tagkey] tag_name = unicode_str(atag) tag_message = "" tag_date = "" if isinstance(obj,Tag): time_tuple = time.gmtime(obj.tag_time + obj.tag_timezone) time_str = time.strftime("%a %b %d %Y %H:%M:%S",time_tuple) timezone_str = format_timezone(obj.tag_timezone).decode('ascii') tag_date = time_str + " " + timezone_str tag_message = unicode_str(obj.message) if isinstance(obj, Commit): time_tuple = time.gmtime(obj.author_time + obj.author_timezone) time_str = time.strftime("%a %b %d %Y %H:%M:%S",time_tuple) timezone_str = format_timezone(obj.author_timezone).decode('ascii') tag_date = time_str + " " + timezone_str tag_message = unicode_str(obj.message) taglst.append(tag_name + "|" + tag_date + "|" + tag_message) os.chdir(cdir) return taglst
def logsummary(repo=".", paths=None, outstream=sys.stdout, max_entries=None, reverse=False, stats=False): """Write commit logs with optional diff stat summaries Args: repo: Path to repository paths: Optional set of specific paths to print entries for outstream: Stream to write log output to reverse: Reverse order in which entries are printed max_entries: Optional maximum number of entries to display stats: Print diff stats """ with open_repo_closing(repo) as r: walker = r.get_walker(max_entries=max_entries, paths=paths, reverse=reverse) for entry in walker: def decode(x): return commit_decode(entry.commit, x) print_commit(entry.commit, decode, outstream) if stats: commit = entry.commit if commit.parents: parent_commit = r[commit.parents[0]] base_tree = parent_commit.tree else: base_tree = None adiff = b"" with BytesIO() as diffstream: write_tree_diff( diffstream, r.object_store, base_tree, commit.tree) diffstream.seek(0) adiff = diffstream.getvalue() dsum = diffstat(adiff.split(b'\n')) outstream.write(dsum.decode('utf-8')) outstream.write("\n\n")
def remote_add_or_update(repo, name, url): """ Modified version of Dulwich's porcelain.remote_add(); adds a remote if it doesn't yet exist for the given repository, otherwise updates the URL and/or refspec if it's changed """ if not isinstance(name, bytes): name = name.encode('utf-8') if not isinstance(url, bytes): url = url.encode('utf-8') with open_repo_closing(repo) as r: c = r.get_config() section = (b'remote', name) refspec = f'+refs/heads/*:refs/remotes/{name.decode()}/*' refspec = refspec.encode('utf-8') if c.has_section(section): if c.get(section, b'url') == url: try: if c.get(section, b'fetch') == refspec: return except KeyError: # 'fetch' missing, set it in the following code pass c.set(section, b'url', url) c.set(section, b'fetch', refspec) c.write_to_path()
def __delete_legacy_dir(self): git_metadata_dir = os.path.abspath(os.path.join( self.__beq_dir, '.git')) move_it = False if os.path.exists(git_metadata_dir): from dulwich import porcelain with porcelain.open_repo_closing(self.__beq_dir) as local_repo: config = local_repo.get_config() remote_url = config.get(('remote', 'origin'), 'url').decode() if remote_url == BEQ_DEFAULT_REPO: move_it = True if move_it is True: logger.info( f"Migrating legacy repo location from {self.__beq_dir}") target_dir = os.path.abspath( os.path.join(self.__beq_dir, 'bmiller_miniDSPBEQ')) os.mkdir(target_dir) for d in os.listdir(self.__beq_dir): if d != 'bmiller_miniDSPBEQ': src = os.path.abspath(os.path.join(self.__beq_dir, d)) if os.path.isdir(src): dst = os.path.abspath(os.path.join(target_dir, d)) logger.info(f"Migrating {src} to {dst}") shutil.move(src, dst) else: logger.info(f"Migrating {src} to {target_dir}") shutil.move(src, target_dir)
def __pull_beq(repo, local_dir): ''' pulls the git repo but does not use dulwich pull as it has file lock issues on windows ''' from dulwich import porcelain, index with porcelain.open_repo_closing(local_dir) as local_repo: remote_refs = porcelain.fetch(local_repo, repo) local_repo[b"HEAD"] = remote_refs[b"refs/heads/master"] index_file = local_repo.index_path() tree = local_repo[b"HEAD"].tree index.build_index_from_tree(local_repo.path, index_file, local_repo.object_store, tree)
def add(content_repo, custom_content_repo, paths): """Add files to the custom content repo and stage them.""" for p in paths: dst = os.path.join(custom_content_repo.path, p) src = os.path.join(content_repo.path, p) os.makedirs(os.path.dirname(dst), exist_ok=True) copyfile(src, dst) with open_repo_closing(custom_content_repo) as r: r.stage(paths)
def checkout_head(repo_path): result = True cdir = os.getcwd() result = cleanWorkingDir(repo_path) if not result: return result os.chdir(repo_path) with open_repo_closing(".") as r: r.reset_index(r[b"HEAD"].tree) # cd out **before** the repo closes os.chdir(cdir) os.chdir(cdir) return result
def checkout_tag(repo_path, tagname): result = True cdir = os.getcwd() result = cleanWorkingDir(repo_path) if not result: return result os.chdir(repo_path) with open_repo_closing(".") as r: tagkey = utf8_str("refs/tags/" + tagname) refkey = tagkey # if annotated tag get the commit it pointed to if isinstance(r[tagkey], Tag): refkey = r[tagkey].object[1] r.reset_index(r[refkey].tree) # use this to reset HEAD to this tag (ie. revert) # r.refs.set_symbolic_ref(b"HEAD", tagkey) # cd out **before** the repo closes os.chdir(cdir) os.chdir(cdir) return result
def _from_path(self, path): # We already know that the path is a (symlink to a) directory # If it is a symlink, it is a local repository, even if the other end # is a git repo if path.is_symlink(): return Repository(path.stem, 'local', path.resolve()) # Now we know we have a path to a directory that is not a symlink # To have type 'git', it must be a git repo with a remote called 'origin' # The remote URL is what we return as path try: with porcelain.open_repo_closing(path) as r: # Let the KeyError get caught be the outer try origin = r.get_config().get((b"remote", b"origin"), b"url") return Repository(path.stem, 'git', origin.decode()) except Exception: # Ignore errors pass # If it is not a git repo with an origin, treat it as a regular directory return Repository(path.stem, 'local', path.resolve())
def generate_diff_from_checkpoints(localRepo, bookid, leftchkpoint, rightchkpoint): repo_home = pathof(localRepo) repo_home = repo_home.replace("/", os.sep) repo_path = os.path.join(repo_home, "epub_" + bookid) success = True if os.path.exists(repo_path): os.chdir(repo_path) with open_repo_closing(".") as r: tags = r.refs.as_dict(b"refs/tags") commit1 = r[r[tags[utf8_str(leftchkpoint)]].object[1]] commit2 = r[r[tags[utf8_str(rightchkpoint)]].object[1]] output = io.BytesIO() try: write_tree_diff(output, r.object_store, commit1.tree, commit2.tree) except Exception as e: print("diff failed in python") print(str(e)) success = False pass if success: return output.getvalue() return ''
def getRepositoryAuthorsByNumberOfCommits(path): authors = {} # email -> (name, numCommits, latestCommitDate). with porcelain.open_repo_closing(path) as repo: for entry in repo.get_walker(): commit = entry.commit author = utf8(commit.author) date = gmtime(commit.author_time) name, email = [s.strip(' <>') for s in author.rsplit(' ', 1)] _, numCommits, _ = authors.get(email, ('ignored', 0, 'ignored')) numCommits += 1 authors[email] = (name, numCommits, date) items = [(email, name, numCommits, date) for email, (name, numCommits, date) in authors.items()] authorsByNumCommits = sorted(items, key=lambda author: author[2])[::-1] # List of (email, name, numCommits, latestCommitDate) tuples. return authorsByNumCommits
def commit(root, indexfile, message=None): with porcelain.open_repo_closing(root) as repo: porcelain.add(repo, indexfile) if message is None: message = "update %s" % (os.path.basename(indexfile)) porcelain.commit(repo, message=message, author=_AUTHOR, committer=_COMMITTER)
import sys import semver from dulwich import porcelain from dulwich.client import get_transport_and_path from dulwich.objectspec import parse_reftuples with porcelain.open_repo_closing(".") as repo: latest_version = None latest_version_ref = None for ref in repo.refs.as_dict(b"refs/tags"): if ref.startswith(b"v"): sv_part = ref[1:].decode('ascii') if latest_version is None: latest_version = sv_part latest_version_ref = repo.refs[b"refs/tags/" + ref] elif semver.compare(sv_part, latest_version) > 0: latest_version = sv_part latest_version_ref = repo.refs[b"refs/tags/" + ref] client, host_path = get_transport_and_path("git://github.com/godfoder/dulwitch_selfref") remote_refs = client.fetch(host_path.encode('utf-8'), repo, progress=sys.stderr.write) # print(remote_refs) # print(repo.refs) dirty = False for ref in remote_refs:
def check_update(): data = {} repo = Repo('.') local_ref = repo.head().decode('utf-8') print('Versão local: ', local_ref) remote_commit = porcelain.ls_remote(REMOTE_REPO)[b"HEAD"].decode('utf-8') print('\nVersão remota: ', remote_commit) with porcelain.open_repo_closing(repo) as r: walker = r.get_walker(max_entries=1) for entry in walker: message = str(entry.commit.message)[2:-3] author = str(entry.commit.author) if message.startswith('Merge'): continue stamp = datetime.utcfromtimestamp(entry.commit.commit_time) delta = timedelta(hours=3) last_update = (stamp - delta).strftime('%d/%m/%Y' + ' ás ' + '%H:%M:%S') data['local'] = local_ref data['remote'] = remote_commit data['last_update'] = last_update #print(data) # tag_labels = tag_list(repo) # print(tag_labels) # for i in ref.get_walker(include=[local_ref]): # print(i) # import git # repo = git.Repo(".") # tree = repo.tree() # for blob in tree: # commit = next(repo.iter_commits(paths=blob.path, max_count=1)) # print(blob.path, commit.author, commit.committed_date) # path = sys.argv[0].encode('utf-8') # w = ref.get_walker(paths=[path], c = next(iter(w)).commit) # try: # c = next(iter(w)).commit # except StopIteration: # print("No file %s anywhere in history." % sys.argv[0]) # else: # print("%s was last changed by %s at %s (commit %s)" % ( # sys.argv[1], c.author, time.ctime(c.author_time), c.id)) # log = porcelain.log('.', max_entries=1) # print(log) # log = porcelain.log(LOCAL_REPO) # print(log) # changes = porcelain.get_tree_changes(LOCAL_REPO) # print(changes) # status = porcelain.status(LOCAL_REPO) # print(status) # r = porcelain.fetch(LOCAL_REPO,REMOTE_REPO) # print(r) # for i in r: # print(i) if local_ref != remote_commit: pass # print('\nNOVA VERSÃO DISPONÍVEL,INSTALANDO...\n') # update() else: pass # print('\nVC JÁ ESTÁ COM A ÚLTIMA VERSÃO INSTALADA.') return data