Example #1
0
    def transformFallbackLocation(self, branch, url):
        """See `BranchOpenPolicy.transformFallbackLocation`.

        For mirrored branches, we stack on whatever the remote branch claims
        to stack on, but this URL still needs to be checked.
        """
        return urljoin(branch.base, url), True
Example #2
0
    def transformFallbackLocation(self, branch, url):
        """See `BranchOpenPolicy.transformFallbackLocation`.

        For mirrored branches, we stack on whatever the remote branch claims
        to stack on, but this URL still needs to be checked.
        """
        return urljoin(branch.base, url), True
Example #3
0
    def _setHead(self, target_url, target_ref):
        """Set HEAD on a remote repository.

        This relies on the turnip-set-symbolic-ref extension.
        """
        service = "turnip-set-symbolic-ref"
        url = urljoin(target_url, service)
        headers = {
            "Content-Type": "application/x-%s-request" % service,
        }
        body = pkt_line("HEAD %s" % target_ref) + pkt_line(None)
        try:
            response = urlfetch(url, method="POST", headers=headers, data=body)
            response.raise_for_status()
        except Exception as e:
            raise GitProtocolError(str(e))
        content_type = response.headers.get("Content-Type")
        if content_type != ("application/x-%s-result" % service):
            raise GitProtocolError("Invalid Content-Type from server: %s" %
                                   content_type)
        content = io.BytesIO(response.content)
        proto = Protocol(content.read, None)
        pkt = proto.read_pkt_line()
        if pkt is None:
            raise GitProtocolError("Unexpected flush-pkt from server")
        elif pkt.rstrip(b"\n") == b"ACK HEAD":
            pass
        elif pkt.startswith(b"ERR "):
            raise GitProtocolError(
                pkt[len(b"ERR "):].rstrip(b"\n").decode("UTF-8"))
        else:
            raise GitProtocolError("Unexpected packet %r from server" % pkt)
 def setUp(self):
     super(TestPullerMasterIntegration, self).setUp()
     self.makeCleanDirectory(config.codehosting.mirrored_branches_root)
     self.bzr_tree = self.make_branch_and_tree('src-branch')
     url = urljoin(self.serveOverHTTP(), 'src-branch')
     self.bzr_tree.commit('rev1')
     branch_id = self.factory.makeAnyBranch(
         branch_type=BranchType.MIRRORED, url=url).id
     self.layer.txn.commit()
     self.db_branch = getUtility(IBranchLookup).get(branch_id)
     self.client = FakeCodehostingEndpointProxy()
Example #5
0
 def setUp(self):
     super(TestPullerMasterIntegration, self).setUp()
     self.makeCleanDirectory(config.codehosting.mirrored_branches_root)
     self.bzr_tree = self.make_branch_and_tree('src-branch')
     url = urljoin(self.serveOverHTTP(), 'src-branch')
     self.bzr_tree.commit('rev1')
     branch_id = self.factory.makeAnyBranch(
         branch_type=BranchType.MIRRORED, url=url).id
     self.layer.txn.commit()
     self.db_branch = getUtility(IBranchLookup).get(branch_id)
     self.client = FakeCodehostingEndpointProxy()
Example #6
0
 def makeDirectory(self, directory_name, commit_message=None):
     """Make a directory on the repository."""
     if commit_message is None:
         commit_message = 'Make %r' % (directory_name,)
     ra = self._get_ra(self.get_url())
     editor = ra.get_commit_editor({"svn:log": commit_message})
     root = editor.open_root()
     root.add_directory(directory_name).close()
     root.close()
     editor.close()
     return urljoin(self.get_url(), directory_name)
Example #7
0
 def makeDirectory(self, directory_name, commit_message=None):
     """Make a directory on the repository."""
     if commit_message is None:
         commit_message = 'Make %r' % (directory_name,)
     ra = self._get_ra(self.get_url())
     editor = ra.get_commit_editor({"svn:log": commit_message})
     root = editor.open_root()
     root.add_directory(directory_name).close()
     root.close()
     editor.close()
     return urljoin(self.get_url(), directory_name)
Example #8
0
    def push(self,
             db_branch_id,
             bzr_branch,
             required_format,
             stacked_on_url=None):
        """Push up `bzr_branch` as the Bazaar branch for `code_import`.

        :return: A boolean that is true if the push was non-trivial
            (i.e. actually transferred revisions).
        """
        self.transport.create_prefix()
        target_url = self._getMirrorURL(db_branch_id, push=True)
        try:
            remote_branch = Branch.open(target_url)
        except NotBranchError:
            remote_branch = BzrDir.create_branch_and_repo(
                target_url, format=required_format)
            old_branch = None
        else:
            if remote_branch.bzrdir.needs_format_conversion(required_format):
                # For upgrades, push to a new branch in
                # the new format. When done pushing,
                # retire the old .bzr directory and rename
                # the new one in place.
                old_branch = remote_branch
                upgrade_url = urljoin(target_url, "backup.bzr")
                try:
                    remote_branch.bzrdir.root_transport.delete_tree(
                        'backup.bzr')
                except NoSuchFile:
                    pass
                remote_branch = BzrDir.create_branch_and_repo(
                    upgrade_url, format=required_format)
            else:
                old_branch = None
        # This can be done safely, since only modern formats are used to
        # import to.
        if stacked_on_url is not None:
            remote_branch.set_stacked_on_url(stacked_on_url)
        pull_result = remote_branch.pull(bzr_branch, overwrite=True)
        # Because of the way we do incremental imports, there may be revisions
        # in the branch's repo that are not in the ancestry of the branch tip.
        # We need to transfer them too.
        remote_branch.repository.fetch(bzr_branch.repository)
        if old_branch is not None:
            # The format has changed; move the new format
            # branch in place.
            base_transport = old_branch.bzrdir.root_transport
            base_transport.delete_tree('.bzr')
            base_transport.rename("backup.bzr/.bzr", ".bzr")
            base_transport.rmdir("backup.bzr")
        return pull_result.old_revid != pull_result.new_revid
Example #9
0
 def _getMirrorURL(self, db_branch_id, push=False):
     """Return the URL that `db_branch` is stored at."""
     base_url = self.transport.base
     if push:
         # Pulling large branches over sftp is less CPU-intensive, but
         # pushing over bzr+ssh seems to be more reliable.
         split = urlsplit(base_url)
         if split.scheme == 'sftp':
             base_url = urlunsplit([
                 'bzr+ssh', split.netloc, split.path, split.query,
                 split.fragment
             ])
     return urljoin(base_url, '%08x' % db_branch_id)
Example #10
0
    def push(self, db_branch_id, bzr_branch, required_format,
             stacked_on_url=None):
        """Push up `bzr_branch` as the Bazaar branch for `code_import`.

        :return: A boolean that is true if the push was non-trivial
            (i.e. actually transferred revisions).
        """
        self.transport.create_prefix()
        target_url = self._getMirrorURL(db_branch_id)
        try:
            remote_branch = Branch.open(target_url)
        except NotBranchError:
            remote_branch = BzrDir.create_branch_and_repo(
                target_url, format=required_format)
            old_branch = None
        else:
            if remote_branch.bzrdir.needs_format_conversion(
                    required_format):
                # For upgrades, push to a new branch in
                # the new format. When done pushing,
                # retire the old .bzr directory and rename
                # the new one in place.
                old_branch = remote_branch
                upgrade_url = urljoin(target_url, "backup.bzr")
                try:
                    remote_branch.bzrdir.root_transport.delete_tree(
                        'backup.bzr')
                except NoSuchFile:
                    pass
                remote_branch = BzrDir.create_branch_and_repo(
                    upgrade_url, format=required_format)
            else:
                old_branch = None
        # This can be done safely, since only modern formats are used to
        # import to.
        if stacked_on_url is not None:
            remote_branch.set_stacked_on_url(stacked_on_url)
        pull_result = remote_branch.pull(bzr_branch, overwrite=True)
        # Because of the way we do incremental imports, there may be revisions
        # in the branch's repo that are not in the ancestry of the branch tip.
        # We need to transfer them too.
        remote_branch.repository.fetch(bzr_branch.repository)
        if old_branch is not None:
            # The format has changed; move the new format
            # branch in place.
            base_transport = old_branch.bzrdir.root_transport
            base_transport.delete_tree('.bzr')
            base_transport.rename("backup.bzr/.bzr", ".bzr")
            base_transport.rmdir("backup.bzr")
        return pull_result.old_revid != pull_result.new_revid
    def test_mirror_imported_branch(self):
        # Run the puller on a populated imported branch pull queue.
        # Create the branch in the database.
        db_branch = self.factory.makeAnyBranch(branch_type=BranchType.IMPORTED)
        db_branch.requestMirror()
        transaction.commit()

        # Create the Bazaar branch in the expected location.
        branch_url = urljoin(config.launchpad.bzr_imports_root_url,
                             '%08x' % db_branch.id)
        branch = BzrDir.create_branch_convenience(branch_url)
        tree = branch.bzrdir.open_workingtree()
        tree.commit('rev1')

        transaction.commit()

        # Run the puller.
        command, retcode, output, error = self.runPuller()
        self.assertRanSuccessfully(command, retcode, output, error)

        self.assertMirrored(db_branch, source_branch=branch)
    def test_mirror_imported_branch(self):
        # Run the puller on a populated imported branch pull queue.
        # Create the branch in the database.
        db_branch = self.factory.makeAnyBranch(
            branch_type=BranchType.IMPORTED)
        db_branch.requestMirror()
        transaction.commit()

        # Create the Bazaar branch in the expected location.
        branch_url = urljoin(
            config.launchpad.bzr_imports_root_url, '%08x' % db_branch.id)
        branch = BzrDir.create_branch_convenience(branch_url)
        tree = branch.bzrdir.open_workingtree()
        tree.commit('rev1')

        transaction.commit()

        # Run the puller.
        command, retcode, output, error = self.runPuller()
        self.assertRanSuccessfully(command, retcode, output, error)

        self.assertMirrored(db_branch, source_branch=branch)
Example #13
0
 def _doImport(self):
     self._logger.info("Starting job.")
     try:
         self._opener_policy.checkOneURL(self.source_details.url)
     except BadUrl as e:
         self._logger.info("Invalid URL: %s" % e)
         return CodeImportWorkerExitCode.FAILURE_FORBIDDEN
     unauth_target_url = urljoin(config.codehosting.git_browse_root,
                                 self.source_details.target_id)
     split = urlsplit(unauth_target_url)
     target_netloc = ":%s@%s" % (self.source_details.macaroon.serialize(),
                                 split.hostname)
     if split.port:
         target_netloc += ":%s" % split.port
     target_url = urlunsplit(
         [split.scheme, target_netloc, split.path, "", ""])
     # XXX cjwatson 2016-10-11: Ideally we'd put credentials in a
     # credentials store instead.  However, git only accepts credentials
     # that have both a non-empty username and a non-empty password.
     self._logger.info("Getting existing repository from hosting service.")
     try:
         self._runGit("clone", "--mirror", target_url, "repository")
     except subprocess.CalledProcessError as e:
         self._logger.info(
             "Unable to get existing repository from hosting service: "
             "git clone exited %s" % e.returncode)
         return CodeImportWorkerExitCode.FAILURE
     self._logger.info("Fetching remote repository.")
     try:
         self._runGit("config", "gc.auto", "0", cwd="repository")
         # Remove any stray remote-tracking refs from the last time round.
         self._deleteRefs("repository", "refs/remotes/source/**")
         self._runGit("remote",
                      "add",
                      "source",
                      self.source_details.url,
                      cwd="repository")
         self._runGit("fetch",
                      "--prune",
                      "source",
                      "+refs/*:refs/*",
                      cwd="repository")
         try:
             new_head = self._getHead("repository", "source")
         except (subprocess.CalledProcessError, GitProtocolError) as e2:
             self._logger.info("Unable to fetch default branch: %s" % e2)
             new_head = None
         self._runGit("remote", "rm", "source", cwd="repository")
         # XXX cjwatson 2016-11-03: For some reason "git remote rm"
         # doesn't actually remove the refs.
         self._deleteRefs("repository", "refs/remotes/source/**")
     except subprocess.CalledProcessError as e:
         self._logger.info("Unable to fetch remote repository: %s" % e)
         return CodeImportWorkerExitCode.FAILURE_INVALID
     self._logger.info("Pushing repository to hosting service.")
     try:
         if new_head is not None:
             # Push the target of HEAD first to ensure that it is always
             # available.
             self._runGit("push",
                          target_url,
                          "+%s:%s" % (new_head, new_head),
                          cwd="repository")
             try:
                 self._setHead(target_url, new_head)
             except GitProtocolError as e:
                 self._logger.info("Unable to set default branch: %s" % e)
         self._runGit("push", "--mirror", target_url, cwd="repository")
     except subprocess.CalledProcessError as e:
         self._logger.info(
             "Unable to push to hosting service: git push exited %s" %
             e.returncode)
         return CodeImportWorkerExitCode.FAILURE
     return CodeImportWorkerExitCode.SUCCESS
Example #14
0
 def _getMirrorURL(self, db_branch_id):
     """Return the URL that `db_branch` is stored at."""
     return urljoin(self.transport.base, '%08x' % db_branch_id)