From 605f08f8b8b41215bd11c60d9a5908c4e73500be Mon Sep 17 00:00:00 2001 From: Thomas Leonard Date: Sun, 20 Jun 2010 18:02:32 +0100 Subject: [PATCH] Added writer.save_feed Before, information for feeds and interfaces went into a single file in "user_overrides". Now, feed information is saved under "feeds" and interface settings go under "interfaces". The old files will be loaded if the new ones aren't found. --- tests/testwriter.py | 23 ++++------ zeroinstall/0launch-gui/properties.py | 2 +- zeroinstall/injector/iface_cache.py | 5 +- zeroinstall/injector/reader.py | 75 ++++++++++++++++++++---------- zeroinstall/injector/writer.py | 86 ++++++++++++++++++----------------- 5 files changed, 108 insertions(+), 83 deletions(-) diff --git a/tests/testwriter.py b/tests/testwriter.py index fe44bd5..40a1b41 100755 --- a/tests/testwriter.py +++ b/tests/testwriter.py @@ -23,12 +23,14 @@ class TestWriter(BaseTest): iface.extra_feeds.append(model.Feed('http://sys-feed', None, False)) iface.extra_feeds.append(model.Feed('http://user-feed', 'Linux-*', True)) writer.save_interface(iface) + writer.save_feed(main_feed) iface = model.Interface('http://test/test') self.assertEquals(None, iface.stability_policy) main_feed = model.ZeroInstallFeed(test_feed, local_path = '/Hello') iface_cache.iface_cache._feeds[iface.uri] = main_feed - reader.update_user_overrides(iface, main_feed) + reader.update_user_overrides(iface) + reader.update_user_feed_overrides(main_feed) self.assertEquals(model.developer, iface.stability_policy) self.assertEquals(100, main_feed.last_checked) self.assertEquals("[]", str(iface.extra_feeds)) @@ -50,23 +52,14 @@ class TestWriter(BaseTest): self.assertEquals(None, feed) def testStoreStability(self): - iface = model.Interface('http://example.com:8000/Hello.xml') - main_feed = model.ZeroInstallFeed(test_feed, local_path = '/Hello.xml') - iface_cache.iface_cache._feeds[iface.uri] = main_feed + main_feed = reader.load_feed('Hello.xml', local = True) impl = main_feed.implementations['sha1=3ce644dc725f1d21cfcf02562c76f375944b266a'] impl.user_stability = model.developer - writer.save_interface(iface) - - iface = model.Interface('http://example.com:8000/Hello.xml') - self.assertEquals(None, iface.stability_policy) - reader.update_user_overrides(iface) - - del iface_cache.iface_cache._feeds[iface.uri] + writer.save_feed(main_feed) - # Now visible - reader.update(iface, 'Hello.xml') - main_feed = iface_cache.iface_cache.get_feed(iface.uri) - reader.update_user_overrides(iface, main_feed) + # Rating now visible + main_feed = reader.load_feed('Hello.xml', local = True) + reader.update_user_feed_overrides(main_feed) self.assertEquals(1, len(main_feed.implementations)) impl = main_feed.implementations['sha1=3ce644dc725f1d21cfcf02562c76f375944b266a'] diff --git a/zeroinstall/0launch-gui/properties.py b/zeroinstall/0launch-gui/properties.py index 91dc4b3..f510a3b 100644 --- a/zeroinstall/0launch-gui/properties.py +++ b/zeroinstall/0launch-gui/properties.py @@ -282,7 +282,7 @@ class Properties: i = 0 stability.set_active(i) - def set_stability_policy(combo): + def set_stability_policy(combo, stability = stability): # (pygtk bug?) i = stability.get_active() if i == 0: new_stability = None diff --git a/zeroinstall/injector/iface_cache.py b/zeroinstall/injector/iface_cache.py index b764be3..0de59cb 100644 --- a/zeroinstall/injector/iface_cache.py +++ b/zeroinstall/injector/iface_cache.py @@ -320,7 +320,10 @@ class IfaceCache(object): if feed != False: return feed - feed = self._feeds[url] = reader.load_feed_from_cache(url) + feed = reader.load_feed_from_cache(url) + if feed: + reader.update_user_feed_overrides(feed) + self._feeds[url] = feed return feed def get_interface(self, uri): diff --git a/zeroinstall/injector/reader.py b/zeroinstall/injector/reader.py index 5ca2b17..9c903ca 100644 --- a/zeroinstall/injector/reader.py +++ b/zeroinstall/injector/reader.py @@ -22,10 +22,10 @@ def update_from_cache(interface): @return: True if cached version and user overrides loaded OK. False if upstream not cached. Local interfaces (starting with /) are always considered to be cached, although they are not actually stored in the cache. + Internal: use L{iface_cache.iface_cache.get_interface} instread. @rtype: bool""" interface.reset() from zeroinstall.injector.iface_cache import iface_cache - main_feed = iface_cache.get_feed(interface.uri, force = True) # Add the distribution package manager's version, if any path = basedir.load_first_data(config_site, 'native_feeds', model._pretty_escape(interface.uri)) @@ -34,7 +34,11 @@ def update_from_cache(interface): info(_("Adding native packager feed '%s'"), path) interface.extra_feeds.append(Feed(os.path.realpath(path), None, False)) - update_user_overrides(interface, main_feed) + update_user_overrides(interface) + + main_feed = iface_cache.get_feed(interface.uri, force = True) + if main_feed: + update_user_feed_overrides(main_feed) return main_feed is not None @@ -52,15 +56,18 @@ def load_feed_from_cache(url): else: return None -def update_user_overrides(interface, main_feed = None): - """Update an interface with user-supplied information. - @param interface: the interface object to update - @type interface: L{model.Interface} - @param main_feed: feed to update with last_checked information - @note: feed updates shouldn't really be here. main_feed may go away in future. +def update_user_feed_overrides(feed): + """Update a feed with user-supplied information. + Sets last_checked and user_stability ratings. + @param feed: feed to update + @since 0.49 """ user = basedir.load_first_config(config_site, config_prog, - 'user_overrides', escape(interface.uri)) + 'feeds', model._pretty_escape(feed.url)) + if user is None: + # For files saved by 0launch < 0.49 + user = basedir.load_first_config(config_site, config_prog, + 'user_overrides', escape(feed.url)) if not user: return @@ -70,34 +77,52 @@ def update_user_overrides(interface, main_feed = None): warn(_("Error reading '%(user)s': %(exception)s"), {'user': user, 'exception': ex}) raise - # This is a bit wrong; this information is about the feed, - # not the interface. - if main_feed: - last_checked = root.getAttribute('last-checked') - if last_checked: - main_feed.last_checked = int(last_checked) - - stability_policy = root.getAttribute('stability-policy') - if stability_policy: - interface.set_stability_policy(stability_levels[str(stability_policy)]) + last_checked = root.getAttribute('last-checked') + if last_checked: + feed.last_checked = int(last_checked) for item in root.childNodes: if item.uri != XMLNS_IFACE: continue if item.name == 'implementation': id = item.getAttribute('id') assert id is not None - if main_feed: - impl = main_feed.implementations.get(id, None) - else: - impl = None + impl = feed.implementations.get(id, None) if not impl: - debug(_("Ignoring user-override for unknown implementation %(id)s in %(interface)s"), {'id': id, 'interface': interface}) + debug(_("Ignoring user-override for unknown implementation %(id)s in %(interface)s"), {'id': id, 'interface': feed}) continue user_stability = item.getAttribute('user-stability') if user_stability: impl.user_stability = stability_levels[str(user_stability)] - elif item.name == 'feed': + +def update_user_overrides(interface): + """Update an interface with user-supplied information. + Sets preferred stability and updates extra_feeds. + @param interface: the interface object to update + @type interface: L{model.Interface} + """ + user = basedir.load_first_config(config_site, config_prog, + 'interfaces', model._pretty_escape(interface.uri)) + if user is None: + # For files saved by 0launch < 0.49 + user = basedir.load_first_config(config_site, config_prog, + 'user_overrides', escape(interface.uri)) + if not user: + return + + try: + root = qdom.parse(file(user)) + except Exception, ex: + warn(_("Error reading '%(user)s': %(exception)s"), {'user': user, 'exception': ex}) + raise + + stability_policy = root.getAttribute('stability-policy') + if stability_policy: + interface.set_stability_policy(stability_levels[str(stability_policy)]) + + for item in root.childNodes: + if item.uri != XMLNS_IFACE: continue + if item.name == 'feed': feed_src = item.getAttribute('src') if not feed_src: raise InvalidInterface(_('Missing "src" attribute in ')) diff --git a/zeroinstall/injector/writer.py b/zeroinstall/injector/writer.py index ef75275..60dc64c 100644 --- a/zeroinstall/injector/writer.py +++ b/zeroinstall/injector/writer.py @@ -1,5 +1,5 @@ """ -Save per-interface configuration information. +Save per-interface and per-feed configuration information. """ # Copyright (C) 2009, Thomas Leonard @@ -11,26 +11,49 @@ from xml.dom import minidom, XMLNS_NAMESPACE from zeroinstall.support import basedir -from zeroinstall.injector.model import escape +from zeroinstall.injector import model from zeroinstall.injector.namespaces import config_site, config_prog, XMLNS_IFACE from zeroinstall.injector.iface_cache import iface_cache -def _add_impl(parent, impl): - if impl.user_stability: - doc = parent.ownerDocument - node = doc.createElementNS(XMLNS_IFACE, 'implementation') - parent.appendChild(node) - node.setAttribute('user-stability', str(impl.user_stability)) - node.setAttribute('id', impl.id) +def _atomic_save(doc, parent, uri): + import tempfile + tmp_fd, tmp_name = tempfile.mkstemp(dir = parent) + try: + tmp_file = os.fdopen(tmp_fd, 'w') + doc.writexml(tmp_file, addindent = " ", newl = '\n') + tmp_file.close() + path = os.path.join(parent, model._pretty_escape(uri)) + os.rename(tmp_name, path) + except: + os.unlink(tmp_name) + raise def save_feed(feed): - # This is wrong. Feed and interface settings should be saved in separate files. - save_interface(iface_cache.get_interface(feed.url)) + """Save information about a feed. Currently, this is the last_checked time and any user-set stability ratings. + @since 0.49""" + feeds = basedir.save_config_path(config_site, config_prog, 'feeds') -def save_interface(interface): - user_overrides = basedir.save_config_path(config_site, config_prog, 'user_overrides') + impl = minidom.getDOMImplementation() + doc = impl.createDocument(XMLNS_IFACE, 'feed-preferences', None) + root = doc.documentElement + root.setAttributeNS(XMLNS_NAMESPACE, 'xmlns', XMLNS_IFACE) + + if feed.last_checked: + root.setAttribute('last-checked', str(feed.last_checked)) - feed = iface_cache.get_feed(interface.uri) + impls = feed.implementations.values() + impls.sort() + for impl in impls: + if impl.user_stability: + node = doc.createElementNS(XMLNS_IFACE, 'implementation') + root.appendChild(node) + node.setAttribute('user-stability', str(impl.user_stability)) + node.setAttribute('id', impl.id) + + _atomic_save(doc, feeds, feed.url) + +def save_interface(interface): + user_overrides = basedir.save_config_path(config_site, config_prog, 'interfaces') impl = minidom.getDOMImplementation() doc = impl.createDocument(XMLNS_IFACE, 'interface-preferences', None) @@ -42,31 +65,12 @@ def save_interface(interface): if interface.stability_policy: root.setAttribute('stability-policy', str(interface.stability_policy)) - if feed is not None: - if feed.last_checked: - root.setAttribute('last-checked', str(feed.last_checked)) - - impls = feed.implementations.values() - impls.sort() - for impl in impls: - _add_impl(root, impl) + for feed in interface.extra_feeds: + if feed.user_override: + elem = doc.createElementNS(XMLNS_IFACE, 'feed') + root.appendChild(elem) + elem.setAttribute('src', feed.uri) + if feed.arch: + elem.setAttribute('arch', feed.arch) - for feed in interface.extra_feeds: - if feed.user_override: - elem = doc.createElementNS(XMLNS_IFACE, 'feed') - root.appendChild(elem) - elem.setAttribute('src', feed.uri) - if feed.arch: - elem.setAttribute('arch', feed.arch) - - import tempfile - tmp_fd, tmp_name = tempfile.mkstemp(dir = user_overrides) - try: - tmp_file = os.fdopen(tmp_fd, 'w') - doc.writexml(tmp_file, addindent = " ", newl = '\n') - tmp_file.close() - path = os.path.join(user_overrides, escape(interface.uri)) - os.rename(tmp_name, path) - except: - os.unlink(tmp_name) - raise + _atomic_save(doc, user_overrides, interface.uri) -- 2.11.4.GIT