Пример #1
0
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
Пример #2
0
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
Пример #3
0
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)
Пример #4
0
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",
Пример #5
0
    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
Пример #6
0
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 )
Пример #7
0
    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