Esempio n. 1
0
    def _recreate_repository(self, path: str, repo: dict):
        """ Recreate (remove and clone) repository on specifed path.

            :param path: string path to repository
            :type path: string
            :param repo: dict representing item from deployment file
            :type repo: dict
            :raises: :class:`DeployException`
        """
        import git
        from pypeapp.lib.git_progress import _GitProgress
        try:
            shutil.rmtree(path)
        except (OSError, PermissionError) as e:
            raise DeployException(("Cannot remove existing non"
                                   " git repository.{}".format(e))) from e
        else:
            # clone repo
            try:
                git.Repo.clone_from(repo.get('url'),
                                    path,
                                    progress=_GitProgress(),
                                    env=None,
                                    b=repo.get('branch') or repo.get('tag'),
                                    recursive=True)
            except git.exc.GitCommandError as e:
                raise DeployException("Git clone failed for {}".format(
                    repo.get("url"))) from e
Esempio n. 2
0
    def deploy(self, force=False):
        """ Do repositories deployment and install python dependencies.

            Go throught deployment file and install repositories specified
            there. Also add additional python dependencies with pip.

            :param force:   overwrite existng repos if it's working tree is
                            dirty.
            :type force: bool
            :raises: :class:`DeployException`

        """
        import git
        from pypeapp.lib.git_progress import _GitProgress
        settings = self._determine_deployment_file()
        deploy = self._read_deployment_file(settings)
        term = Terminal()

        # go throught repositories
        term.echo(">>> Deploying repositories ...")
        for ritem in deploy.get('repositories'):
            path = os.path.join(self._pype_root, "repos", ritem.get('name'))

            term.echo(" -- processing [ {} / {} ]".format(
                ritem.get('name'),
                ritem.get('branch') or ritem.get('tag')))

            if self._validate_is_directory(path):
                # path exists
                # is it repository?
                if not self._validate_is_repo(path):
                    # no, remove dir no matter of content
                    term.echo("  - removing existing directory and cloning...")
                    self._recreate_repository(path, ritem)
                else:
                    # dir is repository
                    repo = git.Repo(path)
                    # is it right one?
                    if not self._validate_origin(path, str(ritem.get('url'))):
                        # repository has different origin then specified
                        term.echo("!!! repository has different origin. ")
                        if (self._validate_is_dirty(path) is True
                                and force is False):
                            raise DeployException(('Invalid repository on '
                                                   'path {}'.format(path)))
                        term.echo(" -> recreating repository. ")
                        self._recreate_repository(path, ritem)
                        pass
                    if (self._validate_is_dirty(path) is True
                            and force is False):
                        raise DeployException(("Repo on path [ {} ] has dirty"
                                               " worktree").format(path), 300)

                    # are we on correct branch?
                    if not ritem.get('tag'):
                        if not self._validate_is_branch(
                                path, ritem.get('branch')):

                            term.echo("  . switching to [ {} ] ...".format(
                                ritem.get('branch')))
                            branch = repo.create_head(ritem.get('branch'),
                                                      'HEAD')

                            branch.checkout(force=force)

                    # update repo
                    term.echo("  . updating ...")
                    repo.remotes.origin.fetch(tags=True, force=True)
                    # build refspec
                    if ritem.get('branch'):
                        refspec = "refs/heads/{}".format(ritem.get('branch'))
                        repo.remotes.origin.pull(refspec)
                    elif ritem.get('tag'):
                        tags = repo.tags
                        if ritem.get('tag') not in tags:
                            raise DeployException(
                                ("Tag {} is missing on remote "
                                 "origin").format(ritem.get('tag')))
                        t = tags[ritem.get('tag')]
                        term.echo("  . tag: [{}, {} / {}]".format(
                            t.name, t.commit, t.commit.committed_date))
                        repo.remotes.origin.pull(ritem.get('tag'))

            else:
                # path doesn't exist, clone
                try:
                    git.Repo.clone_from(ritem.get('url'),
                                        path,
                                        progress=_GitProgress(),
                                        env=None,
                                        b=ritem.get('branch')
                                        or ritem.get('tag'),
                                        recursive=True)
                except git.exc.GitCommandError as e:
                    raise DeployException("Git clone failed for {}".format(
                        ritem.get("url"))) from e

        # Go through zip files.
        term.echo(">>> Deploying archive files ...")
        if deploy.get('archive_files'):
            for item in deploy.get("archive_files"):
                term.echo(" -- processing [ {} ]".format(
                    item.get("extract_path")))
                path = os.path.normpath(
                    os.path.join(self._pype_root, item.get("extract_path")))

                if self._validate_is_directory(path):
                    term.echo("  - removing existing directory.")
                    shutil.rmtree(path)

                # Download archive file.
                archive_type = item.get('archive_type')
                basename = os.path.split(path)[-1]
                filename = '.'.join([basename, archive_type])
                archive_file_path = tempfile.mkdtemp(basename + '_archive')
                archive_file_path = os.path.join(archive_file_path, filename)

                if item.get("vendor"):
                    source = os.path.join(os.environ.get("PYPE_ROOT"),
                                          'vendor', 'packages',
                                          item.get("vendor"))
                    if not os.path.isfile(source):
                        raise DeployException(
                            "Local archive {} doesn't exist".format(source))
                    shutil.copyfile(source, archive_file_path)

                if item.get("url"):
                    term.echo("  - downloading [ {} ]".format(item.get("url")))
                    success = self._download_file(item.get("url"),
                                                  archive_file_path)

                    if not success:
                        raise DeployException(
                            "Failed to download [ {} ]".format(
                                item.get("url")),
                            130  # noqa: E501
                        )

                # checksum
                if item.get('md5_url'):
                    response = urlopen(item.get('md5_url'))
                    md5 = response.read().decode('ascii').split(" ")[0]
                    calc = self.calculate_checksum(archive_file_path)
                    if md5 != calc:
                        raise DeployException(
                            "Checksum failed {} != {} on {}".format(
                                md5, calc, archive_file_path))
                # Extract files from archive
                if archive_type in ['zip']:
                    zip_file = zipfile.ZipFile(archive_file_path)
                    zip_file.extractall(path)

                elif archive_type in [
                        'tar', 'tgz', 'tar.gz', 'tar.xz', 'tar.bz2'
                ]:
                    if archive_type == 'tar':
                        tar_type = 'r:'
                    elif archive_type.endswith('xz'):
                        tar_type = 'r:xz'
                    elif archive_type.endswith('gz'):
                        tar_type = 'r:gz'
                    elif archive_type.endswith('bz2'):
                        tar_type = 'r:bz2'
                    else:
                        tar_type = 'r:*'
                    try:
                        tar_file = tarfile.open(archive_file_path, tar_type)
                    except tarfile.ReadError:
                        raise DeployException(
                            "corrupted archive: also consider to download the "
                            "archive manually, add its path to the url, run "
                            "`./pype deploy`")
                    tar_file.extractall(path)
                    tar_file.close()

                # Move folders/files if skip first subfolder is set
                if item.get('skip_first_subfolder', False):
                    self.move_subfolders_to_main(path)

        # install python dependencies
        term.echo(">>> Adding python dependencies ...")
        for pitem in deploy.get('pip'):
            term.echo(" -- processing [ {} ]".format(pitem))
            try:
                subprocess.check_output(
                    [sys.executable, '-m', 'pip', 'install', pitem])
            except subprocess.CalledProcessError as e:
                raise DeployException('PIP command failed with {}'.format(
                    e.returncode)) from e