def lookup_xml_id(self, url): """A helper method for locating a part of a WADL document. :param url: The URL (with anchor) of the desired part of the WADL document. :return: The XML ID corresponding to the anchor. """ markup_uri = URI(self.markup_url).ensureNoSlash() markup_uri.fragment = None if url.startswith('http'): # It's an absolute URI. this_uri = URI(url).ensureNoSlash() else: # It's a relative URI. this_uri = markup_uri.resolve(url) possible_xml_id = this_uri.fragment this_uri.fragment = None if this_uri == markup_uri: # The URL pointed elsewhere within the same WADL document. # Return its fragment. return possible_xml_id # XXX leonardr 2008-05-28: # This needs to be implemented eventually for Launchpad so # that a script using this client can navigate from a WADL # representation of a non-root resource to its definition at # the server root. raise NotImplementedError("Can't look up definition in another " "url (%s)" % url)
def list(self, dirname): """Download the HTML index at subdir and scrape for URLs. Returns a list of directory names (links ending with /, or that result in redirects to themselves ending in /) and filenames (everything else) that reside underneath the path. """ self.log.info("Listing %s" % dirname) try: response = self.request("GET", dirname) try: soup = BeautifulSoup(response.read()) finally: response.close() except (IOError, socket.error) as exc: raise HTTPWalkerError(str(exc)) base = URI(self.base).resolve(dirname) # Collect set of URLs that are below the base URL urls = set() for anchor in soup("a"): href = anchor.get("href") if href is None: continue try: url = base.resolve(href) except InvalidURIError: continue # Only add the URL if it is strictly inside the base URL. if base.contains(url) and not url.contains(base): urls.add(url) dirnames = set() filenames = set() for url in urls: if url.path.endswith(';type=a') or url.path.endswith(';type=i'): # these links come from Squid's FTP dir listing to # force either ASCII or binary download and can be # ignored. continue filename = subdir(base.path, url.path) if self.isDirectory(url.path): dirnames.add(as_dir(filename)) else: filenames.add(filename) return (sorted(dirnames), sorted(filenames))
class MenuBase(UserAttributeCache): """Base class for facets and menus.""" implements(IMenuBase) links = None extra_attributes = None enable_only = ALL_LINKS _baseclassname = 'MenuBase' _initialized = False _forbiddenlinknames = set([ 'user', 'initialize', 'links', 'enable_only', 'iterlinks', 'initLink', 'updateLink', 'extra_attributes' ]) def __init__(self, context): # The attribute self.context is defined in IMenuBase. self.context = context self.request = None def initialize(self): """Override this in subclasses to do initialization.""" pass def _check_links(self): assert self.links is not None, ( 'Subclasses of %s must provide self.links' % self._baseclassname) assert isinstance( self.links, (tuple, list)), ("self.links must be a tuple or list.") def _buildLink(self, name): method = getattr(self, name, None) # Since Zope traversals hides the root cause of an AttributeError, # an AssertionError is raised explaining what went wrong. if method is None: raise AssertionError('%r does not define %r method.' % (self, name)) linkdata = method() # The link need only provide ILinkData. We need an ILink so that # we can set attributes on it like 'name' and 'url' and 'linked'. return ILink(linkdata) def _get_link(self, name): request = get_current_browser_request() if request is not None: # We must not use a weak ref here because if we do so and # templates do stuff like "context/menu:bugs/foo", then there # would be no reference to the Link object, which would allow it # to be garbage collected during the course of the request. cache = request.annotations.setdefault(MENU_ANNOTATION_KEY, {}) key = (self.__class__, self.context, name) link = cache.get(key) if link is None: link = self._buildLink(name) cache[key] = link return link return self._buildLink(name) def _rootUrlForSite(self, site): """Return the root URL for the given site.""" try: return URI(allvhosts.configs[site].rooturl) except KeyError: raise AssertionError('unknown site', site) def _init_link_data(self): if self._initialized: return self._initialized = True self.initialize() self._check_links() links_set = set(self.links) assert not links_set.intersection(self._forbiddenlinknames), ( "The following names may not be links: %s" % ', '.join(self._forbiddenlinknames)) if isinstance(self.context, LaunchpadView): # It's a navigation menu for a view instead of a db object. Views # don't have a canonical URL, they use the db object one used as # the context for that view. context = self.context.context else: context = self.context self._contexturlobj = URI(canonical_url(context)) if self.enable_only is ALL_LINKS: self._enable_only_set = links_set else: self._enable_only_set = set(self.enable_only) unknown_links = self._enable_only_set - links_set if len(unknown_links) > 0: # There are links named in enable_only that do not exist in # self.links. raise AssertionError( "Links in 'enable_only' not found in 'links': %s" % ', '.join(sorted(unknown_links))) def initLink(self, linkname, request_url=None): self._init_link_data() link = self._get_link(linkname) link.name = linkname # Set the .enabled attribute of the link to False if it is not # in enable_only. if linkname not in self._enable_only_set: link.enabled = False # Set the .url attribute of the link, using the menu's context. if link.site is None: rootsite = self._contexturlobj.resolve('/') else: rootsite = self._rootUrlForSite(link.site) # Is the target a full URI already? try: link.url = URI(link.target) except InvalidURIError: if link.target.startswith('/'): link.url = rootsite.resolve(link.target) else: link.url = rootsite.resolve(self._contexturlobj.path).append( link.target) # Make the link unlinked if it is a link to the current page. if request_url is not None: if request_url.ensureSlash() == link.url.ensureSlash(): link.linked = False idx = self.links.index(linkname) link.sort_key = idx return link def updateLink(self, link, request_url, **kwargs): """Called each time a link is rendered. Override to update the link state as required for the given request. """ pass def iterlinks(self, request_url=None, **kwargs): """See IMenu.""" self._check_links() for linkname in self.links: link = self.initLink(linkname, request_url) self.updateLink(link, request_url, **kwargs) yield link
class MenuBase(UserAttributeCache): """Base class for facets and menus.""" implements(IMenuBase) links = None extra_attributes = None enable_only = ALL_LINKS _baseclassname = 'MenuBase' _initialized = False _forbiddenlinknames = set( ['user', 'initialize', 'links', 'enable_only', 'iterlinks', 'initLink', 'updateLink', 'extra_attributes']) def __init__(self, context): # The attribute self.context is defined in IMenuBase. self.context = context self.request = None def initialize(self): """Override this in subclasses to do initialization.""" pass def _check_links(self): assert self.links is not None, ( 'Subclasses of %s must provide self.links' % self._baseclassname) assert isinstance(self.links, (tuple, list)), ( "self.links must be a tuple or list.") def _buildLink(self, name): method = getattr(self, name, None) # Since Zope traversals hides the root cause of an AttributeError, # an AssertionError is raised explaining what went wrong. if method is None: raise AssertionError( '%r does not define %r method.' % (self, name)) linkdata = method() # The link need only provide ILinkData. We need an ILink so that # we can set attributes on it like 'name' and 'url' and 'linked'. return ILink(linkdata) def _get_link(self, name): request = get_current_browser_request() if request is not None: # We must not use a weak ref here because if we do so and # templates do stuff like "context/menu:bugs/foo", then there # would be no reference to the Link object, which would allow it # to be garbage collected during the course of the request. cache = request.annotations.setdefault(MENU_ANNOTATION_KEY, {}) key = (self.__class__, self.context, name) link = cache.get(key) if link is None: link = self._buildLink(name) cache[key] = link return link return self._buildLink(name) def _rootUrlForSite(self, site): """Return the root URL for the given site.""" try: return URI(allvhosts.configs[site].rooturl) except KeyError: raise AssertionError('unknown site', site) def _init_link_data(self): if self._initialized: return self._initialized = True self.initialize() self._check_links() links_set = set(self.links) assert not links_set.intersection(self._forbiddenlinknames), ( "The following names may not be links: %s" % ', '.join(self._forbiddenlinknames)) if isinstance(self.context, LaunchpadView): # It's a navigation menu for a view instead of a db object. Views # don't have a canonical URL, they use the db object one used as # the context for that view. context = self.context.context else: context = self.context self._contexturlobj = URI(canonical_url(context)) if self.enable_only is ALL_LINKS: self._enable_only_set = links_set else: self._enable_only_set = set(self.enable_only) unknown_links = self._enable_only_set - links_set if len(unknown_links) > 0: # There are links named in enable_only that do not exist in # self.links. raise AssertionError( "Links in 'enable_only' not found in 'links': %s" % ', '.join(sorted(unknown_links))) def initLink(self, linkname, request_url=None): self._init_link_data() link = self._get_link(linkname) link.name = linkname # Set the .enabled attribute of the link to False if it is not # in enable_only. if linkname not in self._enable_only_set: link.enabled = False # Set the .url attribute of the link, using the menu's context. if link.site is None: rootsite = self._contexturlobj.resolve('/') else: rootsite = self._rootUrlForSite(link.site) # Is the target a full URI already? try: link.url = URI(link.target) except InvalidURIError: if link.target.startswith('/'): link.url = rootsite.resolve(link.target) else: link.url = rootsite.resolve(self._contexturlobj.path).append( link.target) # Make the link unlinked if it is a link to the current page. if request_url is not None: if request_url.ensureSlash() == link.url.ensureSlash(): link.linked = False idx = self.links.index(linkname) link.sort_key = idx return link def updateLink(self, link, request_url, **kwargs): """Called each time a link is rendered. Override to update the link state as required for the given request. """ pass def iterlinks(self, request_url=None, **kwargs): """See IMenu.""" self._check_links() for linkname in self.links: link = self.initLink(linkname, request_url) self.updateLink(link, request_url, **kwargs) yield link