Package zeroinstall :: Package injector :: Module reader
[frames] | no frames]

Source Code for Module zeroinstall.injector.reader

  1  """ 
  2  Parses an XML feed into a Python representation. You should probably use L{iface_cache.iface_cache} rather than the functions here. 
  3  """ 
  4   
  5  # Copyright (C) 2009, Thomas Leonard 
  6  # See the README file for details, or visit http://0install.net. 
  7   
  8  from zeroinstall import _ 
  9  import os 
 10  from logging import debug, info, warn 
 11  import errno 
 12   
 13  from zeroinstall.support import basedir 
 14  from zeroinstall.injector import qdom 
 15  from zeroinstall.injector.namespaces import config_site, config_prog, XMLNS_IFACE 
 16  from zeroinstall.injector.model import Interface, InvalidInterface, ZeroInstallFeed, escape, Feed, stability_levels 
 17  from zeroinstall.injector import model 
 18   
19 -class MissingLocalFeed(InvalidInterface):
20 pass
21
22 -def update_from_cache(interface, iface_cache = None):
23 """Read a cached interface and any native feeds or user overrides. 24 @param interface: the interface object to update 25 @type interface: L{model.Interface} 26 @return: True if cached version and user overrides loaded OK. 27 False if upstream not cached. Local interfaces (starting with /) are 28 always considered to be cached, although they are not actually stored in the cache. 29 Internal: use L{iface_cache.IfaceCache.get_interface} instread. 30 @rtype: bool""" 31 interface.reset() 32 if iface_cache is None: 33 from zeroinstall.injector import policy 34 iface_cache = policy.get_deprecated_singleton_config().iface_cache 35 36 # Add the distribution package manager's version, if any 37 path = basedir.load_first_data(config_site, 'native_feeds', model._pretty_escape(interface.uri)) 38 if path: 39 # Resolve any symlinks 40 info(_("Adding native packager feed '%s'"), path) 41 interface.extra_feeds.append(Feed(os.path.realpath(path), None, False)) 42 43 update_user_overrides(interface) 44 45 main_feed = iface_cache.get_feed(interface.uri, force = True) 46 if main_feed: 47 update_user_feed_overrides(main_feed) 48 49 return main_feed is not None
50
51 -def load_feed_from_cache(url, selections_ok = False):
52 """Load a feed. If the feed is remote, load from the cache. If local, load it directly. 53 @return: the feed, or None if it's remote and not cached.""" 54 try: 55 if os.path.isabs(url): 56 debug(_("Loading local feed file '%s'"), url) 57 return load_feed(url, local = True, selections_ok = selections_ok) 58 else: 59 cached = basedir.load_first_cache(config_site, 'interfaces', escape(url)) 60 if cached: 61 debug(_("Loading cached information for %(interface)s from %(cached)s"), {'interface': url, 'cached': cached}) 62 return load_feed(cached, local = False) 63 else: 64 return None 65 except InvalidInterface as ex: 66 ex.feed_url = url 67 raise
68
69 -def update_user_feed_overrides(feed):
70 """Update a feed with user-supplied information. 71 Sets last_checked and user_stability ratings. 72 @param feed: feed to update 73 @since 0.49 74 """ 75 user = basedir.load_first_config(config_site, config_prog, 76 'feeds', model._pretty_escape(feed.url)) 77 if user is None: 78 # For files saved by 0launch < 0.49 79 user = basedir.load_first_config(config_site, config_prog, 80 'user_overrides', escape(feed.url)) 81 if not user: 82 return 83 84 try: 85 root = qdom.parse(open(user)) 86 except Exception as ex: 87 warn(_("Error reading '%(user)s': %(exception)s"), {'user': user, 'exception': ex}) 88 raise 89 90 last_checked = root.getAttribute('last-checked') 91 if last_checked: 92 feed.last_checked = int(last_checked) 93 94 for item in root.childNodes: 95 if item.uri != XMLNS_IFACE: continue 96 if item.name == 'implementation': 97 id = item.getAttribute('id') 98 assert id is not None 99 impl = feed.implementations.get(id, None) 100 if not impl: 101 debug(_("Ignoring user-override for unknown implementation %(id)s in %(interface)s"), {'id': id, 'interface': feed}) 102 continue 103 104 user_stability = item.getAttribute('user-stability') 105 if user_stability: 106 impl.user_stability = stability_levels[str(user_stability)]
107
108 -def update_user_overrides(interface):
109 """Update an interface with user-supplied information. 110 Sets preferred stability and updates extra_feeds. 111 @param interface: the interface object to update 112 @type interface: L{model.Interface} 113 """ 114 user = basedir.load_first_config(config_site, config_prog, 115 'interfaces', model._pretty_escape(interface.uri)) 116 if user is None: 117 # For files saved by 0launch < 0.49 118 user = basedir.load_first_config(config_site, config_prog, 119 'user_overrides', escape(interface.uri)) 120 if not user: 121 return 122 123 try: 124 root = qdom.parse(open(user)) 125 except Exception as ex: 126 warn(_("Error reading '%(user)s': %(exception)s"), {'user': user, 'exception': ex}) 127 raise 128 129 stability_policy = root.getAttribute('stability-policy') 130 if stability_policy: 131 interface.set_stability_policy(stability_levels[str(stability_policy)]) 132 133 for item in root.childNodes: 134 if item.uri != XMLNS_IFACE: continue 135 if item.name == 'feed': 136 feed_src = item.getAttribute('src') 137 if not feed_src: 138 raise InvalidInterface(_('Missing "src" attribute in <feed>')) 139 interface.extra_feeds.append(Feed(feed_src, item.getAttribute('arch'), True, langs = item.getAttribute('langs')))
140
141 -def check_readable(feed_url, source):
142 """Test whether a feed file is valid. 143 @param feed_url: the feed's expected URL 144 @type feed_url: str 145 @param source: the name of the file to test 146 @type source: str 147 @return: the modification time in src (usually just the mtime of the file) 148 @rtype: int 149 @raise InvalidInterface: If the source's syntax is incorrect, 150 """ 151 try: 152 feed = load_feed(source, local = False) 153 154 if feed.url != feed_url: 155 raise InvalidInterface(_("Incorrect URL used for feed.\n\n" 156 "%(feed_url)s is given in the feed, but\n" 157 "%(interface_uri)s was requested") % 158 {'feed_url': feed.url, 'interface_uri': feed_url}) 159 return feed.last_modified 160 except InvalidInterface as ex: 161 info(_("Error loading feed:\n" 162 "Interface URI: %(uri)s\n" 163 "Local file: %(source)s\n" 164 "%(exception)s") % 165 {'uri': feed_url, 'source': source, 'exception': ex}) 166 raise InvalidInterface(_("Error loading feed '%(uri)s':\n\n%(exception)s") % {'uri': feed_url, 'exception': ex})
167
168 -def update(interface, source, local = False, iface_cache = None):
169 """Read in information about an interface. 170 Deprecated. 171 @param interface: the interface object to update 172 @type interface: L{model.Interface} 173 @param source: the name of the file to read 174 @type source: str 175 @param local: use file's mtime for last-modified, and uri attribute is ignored 176 @raise InvalidInterface: if the source's syntax is incorrect 177 @return: the new feed (since 0.32) 178 @see: L{update_from_cache}, which calls this""" 179 assert isinstance(interface, Interface) 180 181 feed = load_feed(source, local) 182 183 if not local: 184 if feed.url != interface.uri: 185 raise InvalidInterface(_("Incorrect URL used for feed.\n\n" 186 "%(feed_url)s is given in the feed, but\n" 187 "%(interface_uri)s was requested") % 188 {'feed_url': feed.url, 'interface_uri': interface.uri}) 189 190 if iface_cache is None: 191 from zeroinstall.injector import policy 192 iface_cache = policy.get_deprecated_singleton_config().iface_cache 193 iface_cache._feeds[unicode(interface.uri)] = feed 194 195 return feed
196
197 -def load_feed(source, local = False, selections_ok = False):
198 """Load a feed from a local file. 199 @param source: the name of the file to read 200 @type source: str 201 @param local: this is a local feed 202 @type local: bool 203 @param selections_ok: if it turns out to be a local selections document, return that instead 204 @type selections_ok: bool 205 @raise InvalidInterface: if the source's syntax is incorrect 206 @return: the new feed 207 @since: 0.48 208 @see: L{iface_cache.iface_cache}, which uses this to load the feeds""" 209 with open(source) as stream: 210 try: 211 root = qdom.parse(stream) 212 except IOError as ex: 213 if ex.errno == errno.ENOENT and local: 214 raise MissingLocalFeed(_("Feed not found. Perhaps this is a local feed that no longer exists? You can remove it from the list of feeds in that case.")) 215 raise InvalidInterface(_("Can't read file"), ex) 216 except Exception as ex: 217 raise InvalidInterface(_("Invalid XML"), ex) 218 219 if local: 220 if selections_ok and root.uri == XMLNS_IFACE and root.name == 'selections': 221 from zeroinstall.injector import selections 222 return selections.Selections(root) 223 local_path = source 224 else: 225 local_path = None 226 feed = ZeroInstallFeed(root, local_path) 227 feed.last_modified = int(os.stat(source).st_mtime) 228 return feed
229