def test_pull_internal(self): repos_url = self.make_repository("a") dc = self.get_commit_editor(repos_url) dc.add_dir("trunk") dc.close() dc = self.get_commit_editor(repos_url) branches = dc.add_dir("branches") branches.add_dir("branches/foo", "trunk", 1) dc.close() otherbranch = Branch.open(urlutils.join(repos_url, "branches", "foo")) branch = Branch.open(urlutils.join(repos_url, "trunk")) old_last_revid = branch.last_revision() result = branch.pull(otherbranch) self.assertEquals(branch.last_revision(), otherbranch.last_revision()) self.assertEquals(result.new_revid, otherbranch.last_revision()) self.assertEquals(result.old_revid, old_last_revid) self.assertEquals(result.old_revno, 1) self.assertEquals(result.new_revno, 2) self.assertEquals(result.master_branch, branch) self.assertEquals(result.source_branch, otherbranch) self.assertEquals(result.target_branch, branch)
def _add_project(self, path, project=None): if project is None: project = u"*/" * self.level if path == u"trunk": return urlutils.join(path, project) else: return urlutils.join(urlutils.join(path, project), u"*")
def get_tag_path(self, name, project=u""): """Return the path at which the tag with specified name should be found. :param name: Name of the tag. :param project: Optional name of the project the tag is for. Can include slashes. :return: Path of the tag. """ subpath = urlutils.join(u"tags", name.strip(u"/")) if project in (None, u""): return subpath return urlutils.join(project, subpath)
def get_branch_path(self, name, project=""): """Return the path at which the branch with specified name should be found. :param name: Name of the branch. :param project: Optional name of the project the branch is for. Can include slashes. :return: Path of the branch. """ if name == u"": return urlutils.join(project, u"trunk").strip(u"/") else: return urlutils.join(project, u"branches", name).strip(u"/")
def get_branch_path(self, name, project=""): # Only implemented for level 0 if name == u"trunk": if project == u"": return u"trunk" else: return urlutils.join(project, u"trunk") else: if project == u"": return urlutils.join(u"branches", name) else: return urlutils.join(project, u"branches", name)
def url_join_unescaped_path(url, path): (scheme, netloc, basepath, query, fragment) = urlparse.urlsplit(url) path = urlutils.join(urllib.unquote(basepath), path) if scheme in ("http", "https"): # Without this, URLs with + in them break path = urllib.quote(path, safe="/+%") return urlparse.urlunsplit((scheme, netloc, path, query, fragment))
def keyword_url(revid, rev, relpath, revmeta): # URL in the svn repository # See if c.revision() can be traced back to a subversion revision if revmeta is not None: return urlutils.join(revmeta.repository.base, revmeta.branch_path, relpath) return relpath
def test_multi_stack(self): """base + stacked + stacked-on-stacked""" base_tree, stacked_tree = self.make_stacked_target() self.build_tree(['stacked/f3.txt']) stacked_tree.add(['f3.txt'], [b'f3.txt-id']) stacked_key = (b'stacked-rev-id', ) stacked_tree.commit('add f3', rev_id=stacked_key[0]) stacked_only_repo = self.get_only_repo(stacked_tree) self.assertPresent([self.r2_key], stacked_only_repo.inventories, [self.r1_key, self.r2_key]) # This ensures we get a Remote URL, rather than a local one. stacked2_url = urlutils.join(base_tree.branch.base, '../stacked2') stacked2_bzrdir = stacked_tree.controldir.sprout( stacked2_url, revision_id=self.r1_key[0], stacked=True) if isinstance(stacked2_bzrdir, remote.RemoteBzrDir): stacked2_branch = stacked2_bzrdir.open_branch() stacked2_tree = stacked2_branch.create_checkout('stacked2', lightweight=True) else: stacked2_tree = stacked2_bzrdir.open_workingtree() # stacked2 is stacked on stacked, but its content is rev1, so # it needs to pull the basis information from a fallback-of-fallback. self.build_tree(['stacked2/f3.txt']) stacked2_only_repo = self.get_only_repo(stacked2_tree) self.assertPresent([], stacked2_only_repo.inventories, [self.r1_key, self.r2_key]) stacked2_tree.add(['f3.txt'], [b'f3.txt-id']) stacked2_tree.commit('add f3', rev_id=b'stacked2-rev-id') # We added data to this read-locked repo, so refresh it stacked2_only_repo.refresh_data() self.assertPresent([self.r1_key], stacked2_only_repo.inventories, [self.r1_key, self.r2_key])
def clone(self, offset=None): """See Transport.clone().""" if offset is None: newurl = self.base else: newurl = urlutils.join(self.base, offset) return SvnRaTransport(newurl, self)
def test_find_branches(self): repos_url = self.make_client("a", "dc") self.build_tree({ 'dc/branches/brancha': None, 'dc/branches/branchab': None, 'dc/branches/brancha/data': "data", "dc/branches/branchab/data": "data" }) self.client_add("dc/branches") self.client_commit("dc", "My Message") repos = Repository.open(repos_url) repos.set_layout(TrunkLayout(0)) branches = repos.find_branches() self.assertEquals(2, len(branches)) self.assertEquals(urlutils.join(repos.base, "branches/brancha"), branches[1].base) self.assertEquals(urlutils.join(repos.base, "branches/branchab"), branches[0].base)
def get_tag_path(self, name, project=""): """Return the path at which the tag with specified name should be found. :param name: Name of the tag. :param project: Optional name of the project the tag is for. Can include slashes. :return: Path of the tag." """ return urlutils.join("tags", project, name.strip("/"))
def get_paths_connection(self, paths): paths = [p.strip(u"/") for p in paths] prefix = common_prefix(paths) subpaths = [urlutils.determine_relative_path(prefix, p) for p in paths] conn, relprefix = self.get_path_connection(prefix) if relprefix == u"": relsubpaths = subpaths else: relsubpaths = [urlutils.join(relprefix, p) for p in subpaths] return (conn, relsubpaths)
def convert_relocate_error(url, num, msg): """Convert a permanently moved error.""" # Try to guess the new url if "'" in msg: new_url = msg.split("'")[1] elif "«" in msg: new_url = msg[msg.index("»")+2:msg.index("«")] else: raise AssertionError("Unable to parse error message: %s" % msg) raise RedirectRequested(source=_url_escape_uri(url), target=_url_escape_uri(urlutils.join(url, new_url)), is_permanent=True)
def test_get_branch_path_old(self): repos_url = self.make_repository("a") dc = self.get_commit_editor(repos_url) dc.add_dir("trunk") dc.close() dc = self.get_commit_editor(repos_url) dc.add_dir("trunk2", "trunk", 1) dc.close() branch = Branch.open(urlutils.join(repos_url, "trunk2")) self.assertEqual("trunk2", branch.get_branch_path(2)) self.assertEqual("trunk", branch.get_branch_path(1))
def test_set_get_parent(self): """Set, re-get and reset the parent""" b = self.make_branch('subdir') url = 'http://example.com/bzr/bzr.dev' b.set_parent(url) self.assertEqual(url, b.get_parent()) self.assertEqual(url, b._get_parent_location()) b.set_parent(None) self.assertEqual(None, b.get_parent()) b.set_parent('../other_branch') expected_parent = urlutils.join(self.get_url('subdir'), '../other_branch') self.assertEqual(expected_parent, b.get_parent()) path = urlutils.join(self.get_url('subdir'), '../yanb') b.set_parent(path) self.assertEqual('../yanb', b._get_parent_location()) self.assertEqual(path, b.get_parent()) self.assertRaises(urlutils.InvalidURL, b.set_parent, u'\xb5') b.set_parent(urlutils.escape(u'\xb5')) self.assertEqual('%C2%B5', b._get_parent_location()) self.assertEqual(b.base + '%C2%B5', b.get_parent()) # Handle the case for older style absolute local paths if sys.platform == 'win32': # TODO: jam 20060515 Do we want to special case Windows local # paths as well? Nobody has complained about it. pass else: b.lock_write() b._set_parent_location('/local/abs/path') b.unlock() self.assertEqual('file:///local/abs/path', b.get_parent())
def __init__(self, repository, controldir, branch_path, mapping, revnum=None, project=None, _skip_check=False): """Instantiate a new SvnBranch. :param repository: SvnRepository this branch is part of. :param controldir: Control dir this branch was opened on :param branch_path: Relative path inside the repository this branch is located at. :param revnum: Subversion revision number of the branch to look at; none for latest. :param _skip_check: If True, don't check if the branch actually exists. """ self.repository = repository self.controldir = controldir self._format = SvnBranchFormat() self.layout = self.repository.get_layout() if not isinstance(branch_path, text_type): raise TypeError(branch_path) self._branch_path = branch_path.strip(u"/") self.base = urlutils.join(self.repository.base, urlutils.escape( self._branch_path)).rstrip("/") super(SvnBranch, self).__init__(mapping) self._lock_mode = None self._lock_count = 0 self._clear_cached_state() if not _skip_check: try: if self.check_path() != NODE_DIR: raise NotBranchError(self.base) except SubversionException as e: if e.args[1] == ERR_FS_NO_SUCH_REVISION: raise NotBranchError(self.base) raise if project is None: try: project = self.layout.get_branch_project(branch_path) except NotSvnBranchPath: raise NotBranchError(branch_path) assert isinstance(project, text_type) self.project = project self.name = self.layout.get_branch_name(branch_path)
def check_file_revs(self, revid, branch_path, revnum, mapping, relpath): self._annotated = [] for (revmeta, hidden, mapping) in self._repository._revmeta_provider._iter_reverse_revmeta_mapping_history( branch_path, revnum, to_revnum=0, mapping=mapping): if hidden: continue self._related_revs[revmeta.metarev.revnum] = revmeta, mapping self._text = "" path = urlutils.join(branch_path, relpath.encode("utf-8")).strip("/") try: self._repository.svn_transport.get_file_revs(path, -1, revnum, self._handler, include_merged_revisions=True) except subvertpy.SubversionException, (msg, num): if num == subvertpy.ERR_FS_NOT_FILE: return [] raise
def _get_root_action(self, path, parent_ids, overwrite, append_revisions_only, create_prefix=False): """Determine the action to take on the tree root. :param path: Branch path :param parent_ids: Parent ids :param overwrite: Whether to overwrite any existing history :param create_prefix: Whether to create the prefix for path :return: root_action tuple for use with SvnCommitBuilder """ assert not append_revisions_only or not overwrite bp_parts = path.split("/") existing_bp_parts = check_dirs_exist(self.target.svn_transport, bp_parts, -1) if (len(existing_bp_parts) != len(bp_parts) and len(existing_bp_parts) + 1 != len(bp_parts)): existing_path = "/".join(existing_bp_parts) if create_prefix: create_branch_container(self.target.svn_transport, path, existing_path) return ("create", ) raise MissingPrefix(path, existing_path) if len(existing_bp_parts) < len(bp_parts): # Branch doesn't exist yet return ("create", ) ( revmeta, hidden, mapping ) = self.target._revmeta_provider._iter_reverse_revmeta_mapping_history( path, self.target.get_latest_revnum(), to_revnum=0, mapping=self.target.get_mapping()).next() assert not hidden if tuple(parent_ids) == () or tuple(parent_ids) == (NULL_REVISION, ): return ("replace", revmeta.metarev.revnum) else: if revmeta.get_revision_id(mapping) != parent_ids[0]: if append_revisions_only: raise AppendRevisionsOnlyViolation( urlutils.join(self.target.base, path)) return ("replace", revmeta.metarev.revnum) else: return ("open", revmeta.metarev.revnum)
def make_stacked_target(self): base_tree = self.make_branch_and_tree('base') self.build_tree(['base/f1.txt']) base_tree.add(['f1.txt'], [b'f1.txt-id']) base_tree.commit('initial', rev_id=self.r1_key[0]) self.build_tree(['base/f2.txt']) base_tree.add(['f2.txt'], [b'f2.txt-id']) base_tree.commit('base adds f2', rev_id=self.r2_key[0]) stacked_url = urlutils.join(base_tree.branch.base, '../stacked') stacked_bzrdir = base_tree.controldir.sprout(stacked_url, stacked=True) if isinstance(stacked_bzrdir, remote.RemoteBzrDir): stacked_branch = stacked_bzrdir.open_branch() stacked_tree = stacked_branch.create_checkout('stacked', lightweight=True) else: stacked_tree = stacked_bzrdir.open_workingtree() return base_tree, stacked_tree
def set_tag(self, tag_name, tag_target): """Set a new tag in a Subversion repository.""" path = self.branch.layout.get_tag_path(tag_name, self.branch.project) parent = urlutils.dirname(path) try: (from_uuid, from_bp, from_revnum), mapping = self.repository.lookup_bzr_revision_id( tag_target, project=self.branch.project) except bzr_errors.NoSuchRevision: mutter("not setting tag %s; unknown revision %s", tag_name, tag_target) if GhostTagsNotSupported is not None: raise GhostTagsNotSupported(self.branch._format) return self._ensure_tag_parent_exists(parent) try: current_from_foreign_revid = self._lookup_tag_revmeta( path).metarev.get_foreign_revid() deletefirst = True except KeyError: current_from_foreign_revid = None deletefirst = False if current_from_foreign_revid == (from_uuid, from_bp, from_revnum): # Already present return mutter("setting tag %s from %r (deletefirst: %r)", path, (from_uuid, from_bp, from_revnum), deletefirst) conn = self.repository.svn_transport.get_connection(parent) try: with svn_errors.convert_svn_error( conn.get_commit_editor)(self._revprops( "Add tag %s" % tag_name.encode("utf-8"), {tag_name.encode("utf-8"): tag_target})) as ci: root = ci.open_root() if deletefirst: root.delete_entry(urlutils.basename(path)) tag_dir = root.add_directory( urlutils.basename(path), urlutils.join(self.repository.base, from_bp), from_revnum) tag_dir.close() root.close() # FIXME: This shouldn't have to remove the entire cache, just update it self.repository._clear_cached_state() finally: self.repository.svn_transport.add_connection(conn)
def _get_colocated_branch(self, source_branch, prefix, remember_parent): target_dir = self.get_dir(prefix, prefix) if source_branch.project in (None, ""): name = source_branch.name else: if source_branch.name is None: name = source_branch.project else: name = urlutils.join(source_branch.project, source_branch.name) try: return target_dir.open_branch(name) except NotBranchError: target_branch = target_dir.create_branch(name) if remember_parent: target_branch.set_parent(source_branch.base) return target_branch
def app_for_non_branch(self, environ): segment = path_info_pop(environ) if segment is None: raise httpexceptions.HTTPMovedPermanently.relative_redirect( environ['SCRIPT_NAME'] + '/', environ) elif segment == '': if self.name: name = self.name else: name = '/' return DirectoryUI(environ['loggerhead.static.url'], self.transport, name) else: new_transport = self.transport.clone(segment) if self.name: new_name = urlutils.join(self.name, segment) else: new_name = '/' + segment return BranchesFromTransportServer(new_transport, self.root, new_name)
def mkdir(self, relpath, mode=None, message=u"Creating directory"): relpath = urlutils.join(self.repos_path, relpath) dirname, basename = urlutils.split(relpath) conn = self.get_connection(dirname.strip("/")) try: with conn.get_commit_editor({"svn:log": message}) as ce: try: with ce.open_root(-1) as node: node.add_directory(relpath, None, -1).close() except subvertpy.SubversionException as e: msg, num = e.args if num == ERR_FS_NOT_FOUND: raise NoSuchFile(msg) if num == ERR_FS_NOT_DIRECTORY: raise NoSuchFile(msg) if num == subvertpy.ERR_FS_ALREADY_EXISTS: raise FileExists(msg) raise finally: self.add_connection(conn)
def root_inventory(self): # FIXME if self._bzr_inventory is not None: return self._bzr_inventory self._bzr_inventory = Inventory() self._bzr_inventory.revision_id = self.get_revision_id() root_repos = self._repository.svn_transport.get_svn_repos_root() editor = TreeBuildEditor(self) conn = self._repository.svn_transport.get_connection() try: reporter = conn.do_switch( self._revmeta.metarev.revnum, "", True, urlutils.join(root_repos, self._revmeta.metarev.branch_path).rstrip("/"), editor) try: reporter.set_path("", 0, True, None) reporter.finish() except: reporter.abort() raise finally: self._repository.svn_transport.add_connection(conn) return self._bzr_inventory
def _create_lightweight_checkout(self, to_location, revision_id=None): """Create a new lightweight checkout of this branch. :param to_location: URL of location to create the checkout in. :param revision_id: Tip of the checkout. :return: WorkingTree object of the checkout. """ from .workingtree import ( SvnCheckout, SvnWorkingTreeDirFormat, update_wc, ) if revision_id is None or revision_id == self.last_revision(): bp = self.get_branch_path() uuid = self.repository.uuid revnum = self.get_revnum() else: (uuid, bp, revnum), mapping = self.lookup_bzr_revision_id(revision_id) transport = get_transport(to_location) transport.ensure_base() to_path = transport.local_abspath(".") svn_url, readonly = bzr_to_svn_url( urlutils.join(self.repository.base, bp)) wc.ensure_adm(to_path.encode("utf-8"), uuid, svn_url, bzr_to_svn_url(self.repository.base)[0], revnum) with wc.Adm(None, to_path.encode("utf-8"), write_lock=True) as adm: conn = self.repository.svn_transport.connections.get(svn_url) try: update_wc(adm, to_path.encode("utf-8"), conn, svn_url, revnum) finally: if not conn.busy: self.repository.svn_transport.add_connection(conn) dir = SvnCheckout(transport, SvnWorkingTreeDirFormat()) return dir.open_workingtree()
def _todo(self, target_branch, last_revid, last_foreign_revid, stop_revision, project, overwrite, append_revisions_only): graph = self.get_graph() todo = [] if append_revisions_only: for revid in graph.iter_lefthand_ancestry(stop_revision, (NULL_REVISION, None)): if revid == last_revid: break todo.append(revid) else: if last_revid != NULL_REVISION: url = urlutils.join(self.target.base, target_branch) raise AppendRevisionsOnlyViolation(url) todo.reverse() return todo, ("open", last_foreign_revid[2]) else: for revid in graph.iter_lefthand_ancestry(stop_revision, (NULL_REVISION, None)): if self._target_has_revision(revid, project=project): break todo.append(revid) todo.reverse() return todo, ("replace", last_foreign_revid[2])
def is_tag_parent(self, path, project=None): return self.is_tag(urlutils.join(path, u"trunk"), project)
def get_tag_path(self, name, project=""): if project == u"": return urlutils.join(u"tags", name) return urlutils.join(project, u"tags", name)
def _add_project(self, path, project=None): if project is None: return path return urlutils.join(project, path)
def test_local_abspath(self): repos_url = self.make_svn_repository('a') t = SvnRaTransport("%s" % repos_url) self.assertEquals(urlutils.join(self.test_dir, "a"), t.local_abspath('.'))