def setup_bkrepo(repo_url, repo_path): try: repo = Repo(repo_path) except NoSuchPathError: logging.info('git clone: {}'.format(repo_url)) repo = Repo.clone_from(repo_url, repo_path) else: logging.info('git pull: {}'.format(repo_url)) repo.remote().pull() return repo
class GitRepo: def __init__(self, config: Config, path: str = None) -> None: self.__config: Config = config try: if not path: path = config.root_path self.__repo = Repo(path) assert not self.__repo.bare self.origin = self.__repo.remote('origin') except InvalidGitRepositoryError: log_error("Path " + path + " is not a git repository. Please go to valid git repository!") sys.exit() def pull(self, branch_name: str = None): if not branch_name: branch = self.__repo.active_branch.name else: branch = branch_name try: log_info('Pull changes from origin ...') self.__repo.git.execute("git pull origin {}".format(branch).split(" ")) except GitCommandError: log_error("Pull from origin/" + branch + " on " + self.__repo.working_tree_dir + " is not possible as you might have uncommitted or untracked files. Fix the working tree, and then try again.") if not prompt_yesno_question("Did you fix the issue manually? Resume script?"): self.reset() sys.exit() def reset(self): if (self.__config.cleanup_silently or prompt_yesno_question( 'Should the repository and file system to be reset automatically?\nThis will reset the entire repository inlcuding latest commits to comply to remote.\nThis will also delete untrackted files!')): # arbitrary 20, but extensive enough to reset all hopefully log_info("Executing reset (git reset --hard HEAD~20)") self.__repo.git.reset('--hard', 'HEAD~20') self.update_and_clean() def update_and_clean(self): log_info("Executing update and cleanup (git pull origin && git clean -fd)") self.pull() self.__repo.git.clean("-fd") if not self.is_working_copy_clean(): log_error("Reset and cleanup did not work out. Other branches have local commits not yet pushed:") log_info("\n" + self.__list_unpushed_commits()) if not prompt_yesno_question( "Something went wrong during cleanup. Please check if you can perform the cleanup on your own. Resume the script?"): self.reset() sys.exit() def checkout(self, branch_name): log_info("Checkout " + branch_name) self.__repo.git.checkout(branch_name) self.update_and_clean() def commit(self, commit_message: str): try: if self.__list_uncommitted_files() != "": log_info("Committing ...") self.__repo.index.commit("#" + str(self.__config.github_issue_no) + " " + commit_message) else: log_info("Nothing to commit.") except Exception as e: if "no changes added to commit" in str(e): log_info("No File is changed, Nothing to commit..") def push(self, force: bool = False): ''' Boolean return type states, whether to continue process or abort''' if (not force and not self.has_unpushed_commits()): log_info("Nothing to be pushed.") return if (self.__config.test_run or self.__config.debug) and not prompt_yesno_question( "[DEBUG] Changes will be pushed now. Continue?"): self.reset() sys.exit() if self.__config.dry_run: log_info_dry('Skipping pushing of changes.') return try: log_info( "Pushing to origin/" + self.__repo.active_branch.name + " in " + self.__repo.working_tree_dir + " ...") self.__repo.git.execute("git push origin " + self.__repo.active_branch.name + " --tags") except Exception as e: if "no changes added to commit" in str(e): log_info("No file is changed, nothing to commit.") else: if not prompt_yesno_question( "Something went wrong during pushing. Please check if you can perform pushing on your own. Resume the script?"): self.reset() def add_modified_files(self) -> None: self.__repo.git.add(u=True) def merge(self, source: str, target: str) -> None: if self.__config.dry_run: log_info_dry("Would merge from " + source + " to " + target) return try: self.checkout(target) log_info("Executing git pull...") self.pull() log_info("Merging...") self.__repo.git.execute("git merge " + self.__config.branch_to_be_released) log_info("Adapting automatically generated merge commit message to include issue no.") automatic_commit_message = self.__repo.git.execute("git log -1 --pretty=%B") if "Merge" in automatic_commit_message and str( self.__config.github_issue_no) not in automatic_commit_message: self.__repo.git.execute('git commit --amend -m"#' + str( self.__config.github_issue_no) + ' ' + automatic_commit_message + '"') except Exception as ex: log_error("Something went wrong, please check if merge conflicts exist and solve them.") if self.__config.debug: print(ex) if not prompt_yesno_question( "If there were conflicts you solved and committed, would you like to resume the script?"): self.__repo.git.execute("git merge --abort") self.reset() sys.exit() def update_documentation(self) -> None: log_info("Changing the " + self.__config.wiki_version_overview_page + " file, updating the version number...") version_decl = self.__config.cobigenwiki_title_name new_version_decl = version_decl + " v" + self.__config.release_version modified_file = os.path.join(self.__config.root_path, "documentation", self.__config.wiki_version_overview_page) with FileInput(modified_file, inplace=True) as file: for line in file: line = re.sub(r'' + version_decl + r'\s+v[0-9]\.[0-9]\.[0-9]', new_version_decl, line) sys.stdout.write(line) self.add_modified_files() def exists_tag(self, tag_name) -> bool: return tag_name in self.__repo.tags def get_changed_files_of_last_commit(self) -> List[str]: return str(self.__repo.git.execute("git diff HEAD^ HEAD --name-only".split(" "))).strip().splitlines() def create_tag_on_last_commit(self) -> None: self.__repo.create_tag(self.__config.tag_name) log_info("Git tag " + self.__config.tag_name + " created!") def assure_clean_working_copy(self) -> None: if not self.is_working_copy_clean(True): log_error("Working copy is not clean!") if self.__config.cleanup_silently or prompt_yesno_question( "Should I clean the repo for you? This will delete all untracked files and hardly reset the repository!"): self.reset() else: log_info("Please cleanup your working copy first. Then run the script again.") sys.exit() else: log_info("Working copy clean.") def is_working_copy_clean(self, check_all_branches=False) -> bool: return self.__repo.git.execute( "git diff --shortstat".split(" ")) == "" and not self.has_uncommitted_files() and not self.has_unpushed_commits() def __list_uncommitted_files(self) -> str: return self.__repo.git.execute("git status --porcelain".split(" ")) def has_uncommitted_files(self) -> bool: return self.__list_uncommitted_files() != "" def __list_unpushed_commits(self) -> str: # just check for the current branch return self.__repo.git.execute("git log origin/" + self.__get_current_branch_name() + "..HEAD") # check for all branches: # return self.__repo.git.execute("git log --branches --not --remotes".split(" ")) def __get_current_branch_name(self) -> str: return self.__repo.git.execute("git rev-parse --abbrev-ref HEAD") def has_unpushed_commits(self) -> bool: return self.__list_unpushed_commits() != "" def __is_tracked_and_dirty(self, path: str) -> bool: changed = [item.a_path for item in self.__repo.index.diff(None)] changedAbs = [os.path.abspath(os.path.join(self.__repo.working_tree_dir, item.a_path)) for item in self.__repo.index.diff(None)] log_debug("Untracked and Dirty files: " + str(changed)) if path in changed or path in changedAbs: # modified return True else: return False
class GitModule(object): def __init__(self, **kwargs): url = kwargs.get("url") local_path = kwargs.get("local_path") self.work_dir = None if url is None and local_path is None: raise ValueError("Must supply one of url and local_path") if url and local_path: raise ValueError("Can only supply one of url and local_path") if url: self.work_dir = tempfile.mkdtemp() self.repo = Repo.clone_from(url, self.work_dir) else: self.work_dir = None self.repo = Repo(local_path) origin = self.repo.remote(name="origin") origin.fetch() def __del__(self): if self.work_dir and os.path.isdir(self.work_dir): shutil.rmtree(self.work_dir) def getRoot(self): return self.repo.working_tree_dir def relPath(self, path): if path.startswith(self.getRoot()): N = len(self.getRoot()) + 1 return path[N:] else: raise IOError("Not part of repo:%s ?!" % path) def absPath(self, path): repo_path = os.path.join(self.getRoot(), path) if os.path.exists(repo_path): return repo_path else: raise IOError("No such entry in repo:%s" % path) def checkout(self, ref): self.repo.git.checkout(ref) def getHead(self): head = self.repo.heads[0] return (head.name, head.commit) def runTests(self, cmd): full_cmd = self.absPath(cmd) if not os.path.isfile(full_cmd): raise IOError("Is not an executable file:%s" % cmd) if not os.access(full_cmd, os.X_OK): raise OSError("File not executable: %s" % cmd) exit_code = subprocess.call(full_cmd) if exit_code == 0: return True else: return False def install(self, target, files=[], directories=[]): if os.path.exists(target): if not os.path.isdir(target): raise OSError( "Target:%s already exists - and is not a directory" % target) else: os.makedirs(target) for dir in directories: if os.path.dirname(dir): target_path = os.path.join(target, os.path.dirname(dir)) if not os.path.isdir(target_path): os.makedirs(target_path) for dirpath, dirnames, filenames in os.walk(self.absPath(dir)): target_path = os.path.join(target, self.relPath(dirpath)) if not os.path.isdir(target_path): os.makedirs(target_path) for file in filenames: src_file = os.path.join(dirpath, file) target_file = os.path.join(target_path, file) shutil.copy(src_file, target_file) for file in files: target_file = os.path.join(target, file) if os.path.dirname(file): target_path = os.path.join(target, os.path.dirname(file)) if not os.path.isdir(target_path): os.makedirs(target_path) shutil.copy(self.absPath(file), target_file)
from setuptools import setup from git.repo.base import Repo from os.path import dirname, realpath, exists import os vcs = Repo(dirname(realpath(__file__))) urls = [u for u in vcs.remote().urls] if len(urls) < 1: raise NotImplementedError() versionnum = ( len([c for c in vcs.iter_commits()]) - 116 # version 0.0.* had 115 revisions - 57 # version 0.1.* had 56 revisions - 71 # version 0.2.* had 70 revisions ) versionstr = "0.3.%d" % versionnum print("Current version %s" % versionstr) logfile = os.path.join(os.sep, "var", "log", "simple_shuffle.log") # HACK: This requires that the permissions be changed manually, needs to be # fixed. How to determine the user executing a command as sudo? if not exists(logfile): open(logfile, 'w').close() setup(name="Simple Shuffle", version=versionstr, author="D. Scott Boggs", author_email="*****@*****.**", description="Shuffles a folder of music. That is all.", license="GPLv3",
def git_repo(self, request, github_repo, branch=None, remote='origin', checkout_root=None): """ py.test fixture to clone a GitHub based repo onto the local disk. Arguments: github_repo (:class:`~github3.GitHub`): The repo to read from branch (str): The branch to check out Returns: A :class:`~git.repo.base.Repo` object, with the master branch checked out and up to date with the remote. """ if checkout_root is None: checkout_root = request.config.option.checkout_root if not os.path.exists(checkout_root): os.makedirs(checkout_root) repo_dir = os.path.join( os.path.join(checkout_root, github_repo.owner.name), github_repo.name ) if github_repo.private: repo_url = github_repo.ssh_url else: repo_url = github_repo.clone_url if not os.path.exists(repo_dir): repo = Repo.clone_from(repo_url, repo_dir) else: repo = Repo(repo_dir) if github_repo not in SYNCED: try: remote_obj = repo.remote(remote) except ValueError: repo.create_remote(remote, repo_url) remote_obj = repo.remote(remote) if remote_obj.fetch != repo_url: remote_obj.set_url(repo_url) remote_obj.fetch() SYNCED.add(github_repo) if branch is None: branch = github_repo.default_branch head = repo.head remote_branch = RemoteReference(repo, 'refs/remotes/{}/{}'.format(remote, branch)) local_branch = Head(repo, 'refs/heads/{}'.format(branch)) try: if head.commit != remote_branch.commit: local_branch.commit = remote_branch.commit local_branch.checkout() except ValueError: pytest.xfail("Branch {} is empty".format(branch)) return repo
class GitModule(object): def clone(self , url): self.repo = Repo.clone_from( url , self.work_dir ) def __init__(self , **kwargs): url = kwargs.get("url") local_path = kwargs.get("local_path") self.work_dir = None if url is None and local_path is None: raise ValueError("Must supply one of url and local_path") if url and local_path: raise ValueError("Can only supply one of url and local_path") if url: self.work_dir = tempfile.mkdtemp( ) self.clone( url ) else: self.work_dir = None self.repo = Repo( local_path ) origin = self.repo.remote( name = "origin") origin.fetch( ) def __del__(self): if self.work_dir and os.path.isdir( self.work_dir ): shutil.rmtree( self.work_dir ) def getRoot(self): return self.repo.working_tree_dir def relPath(self , path): if path.startswith( self.getRoot( ) ): N = len(self.getRoot()) + 1 return path[N:] else: raise IOError("Not part of repo:%s ?!" % path) def absPath(self , path): repo_path = os.path.join( self.getRoot() , path) if os.path.exists( repo_path ): return repo_path else: raise IOError("No such entry in repo:%s" % path) def checkout(self , ref): self.repo.git.checkout( ref ) def getHeadSHA(self): commit = self.repo.commit("HEAD") return commit.hexsha def runTests(self , cmd): full_cmd = self.absPath( cmd ) if not os.path.isfile( full_cmd ): raise IOError("Is not an executable file:%s" % cmd) if not os.access( full_cmd , os.X_OK): raise OSError("File not executable: %s" % cmd) exit_code = subprocess.call( full_cmd ) if exit_code == 0: return True else: return False def install(self , target, files = [] , directories = []): if os.path.exists( target ): if not os.path.isdir( target ): raise OSError("Target:%s already exists - and is not a directory" % target) else: os.makedirs( target ) for dir in directories: repo_path = os.path.join( self.getRoot() , dir) if not os.path.exists( repo_path ): target_path = os.path.join( target , dir) if not os.path.isdir( target_path ): os.makedirs( target_path ) continue if os.path.dirname( dir ): target_path = os.path.join( target , os.path.dirname( dir )) if not os.path.isdir( target_path ): os.makedirs( target_path ) for dirpath , dirnames , filenames in os.walk( self.absPath(dir)): target_path = os.path.join( target , self.relPath( dirpath )) if not os.path.isdir( target_path ): os.makedirs( target_path ) for file in filenames: src_file = os.path.join( dirpath , file ) target_file = os.path.join( target_path , file ) shutil.copy( src_file , target_file ) for file in files: target_file = os.path.join( target , file ) if os.path.dirname( file ): target_path = os.path.join( target , os.path.dirname( file )) if not os.path.isdir( target_path ): os.makedirs( target_path ) shutil.copy( self.absPath( file ) , target_file )