Exemple #1
0
    def testFeeds(self):
        iface = model.Interface('http://test/test')
        main_feed = model.ZeroInstallFeed(test_feed, local_path='/Hello')
        self.config.iface_cache._feeds[iface.uri] = main_feed
        iface.stability_policy = model.developer
        main_feed.last_checked = 100
        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')
        self.config.iface_cache._feeds[iface.uri] = 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("[<Feed from http://user-feed>]",
                          str(iface.extra_feeds))

        feed = iface.extra_feeds[0]
        self.assertEquals('http://user-feed', feed.uri)
        self.assertEquals('Linux', feed.os)
        self.assertEquals(None, feed.machine)
Exemple #2
0
    def testLocalArchive(self):
        local_iface = os.path.join(mydir, 'LocalArchive.xml')
        with open(local_iface, 'rb') as stream:
            root = qdom.parse(stream)

        # Not local => error
        feed = model.ZeroInstallFeed(root)
        impl = feed.implementations['impl1']
        blocker = self.config.fetcher.download_impls([impl],
                                                     self.config.stores)
        try:
            tasks.wait_for_blocker(blocker)
            assert 0
        except model.SafeException as ex:
            assert "Relative URL 'HelloWorld.tgz' in non-local feed" in str(
                ex), ex

        feed = model.ZeroInstallFeed(root, local_path=local_iface)

        # Missing file
        impl2 = feed.implementations['impl2']
        blocker = self.config.fetcher.download_impls([impl2],
                                                     self.config.stores)
        try:
            tasks.wait_for_blocker(blocker)
            assert 0
        except model.SafeException as ex:
            assert 'tests/IDONTEXIST.tgz' in str(ex), ex

        # Wrong size
        impl3 = feed.implementations['impl3']
        blocker = self.config.fetcher.download_impls([impl3],
                                                     self.config.stores)
        try:
            tasks.wait_for_blocker(blocker)
            assert 0
        except model.SafeException as ex:
            assert 'feed says 177, but actually 176 bytes' in str(ex), ex

        self.config.network_use = model.network_offline
        r = Requirements(local_iface)
        r.command = None
        driver = Driver(requirements=r, config=self.config)
        driver.need_download()
        assert driver.solver.ready, driver.solver.get_failure_reason()

        # Local => OK
        impl = feed.implementations['impl1']

        path = self.config.stores.lookup_maybe(impl.digests)
        assert not path

        blocker = self.config.fetcher.download_impls([impl],
                                                     self.config.stores)
        tasks.wait_for_blocker(blocker)

        path = self.config.stores.lookup_any(impl.digests)
        assert os.path.exists(os.path.join(path, 'HelloWorld'))
    def build_feed(self):
        def child(parent, name, attrs=None):
            new = qdom.Element(XMLNS_IFACE, name, attrs or {})
            parent.childNodes.append(new)
            return new

        root = qdom.Element(XMLNS_IFACE, 'interface',
                            {'uri': uri_prefix + self.name})
        child(root, 'name').content = self.name
        child(root, 'summary').content = self.name

        i = 0
        for version in self.versions.values():
            attrs = {
                'id': str(i),
                'version': str(version.n),
                'main': 'dummy',
            }
            if version.arch:
                attrs['arch'] = version.arch
            impl = child(root, 'implementation', attrs)
            child(impl, 'manifest-digest', {'sha1new': '1234'})
            for lib, min_v, max_v in version.requires:
                req = child(impl, 'requires', {'interface': uri_prefix + lib})
                child(req, 'version', {
                    'before': str(int(max_v) + 1),
                    'not-before': min_v
                })
            i += 1

        feed = model.ZeroInstallFeed(root)
        feed.last_modified = 1
        return feed
Exemple #4
0
def ask_if_previous_still_testing(master_doc, new_version):
	new_version_parsed = model.parse_version(new_version)
	xml = master_doc.toxml(encoding = 'utf-8')
	master = model.ZeroInstallFeed(qdom.parse(BytesIO(xml)))

	previous_versions = [impl.version for impl in master.implementations.values() if impl.version < new_version_parsed]
	if not previous_versions:
		return

	previous_version = max(previous_versions)

	# (all the <implementations> with this version number)
	previous_testing_impls = [impl for impl in master.implementations.values()
					if impl.version == previous_version
					and impl.upstream_stability == model.testing]

	if not previous_testing_impls:
		return

	print("The previous release, version {version}, is still marked as 'testing'. Set to stable?".format(
		version = model.format_version(previous_version)))
	if get_choice(['Yes', 'No']) != 'Yes':
		return

	ids_to_change = frozenset(impl.id for impl in previous_testing_impls)

	for impl in master_doc.getElementsByTagNameNS(XMLNS_IFACE, 'implementation'):
		if impl.getAttribute('id') in ids_to_change:
			impl.setAttribute('stability', 'stable')
Exemple #5
0
def graduation_check(feeds, feeds_dir):
	# Warn about releases that are still 'testing' a while after release
	now = time.time()
	def age(impl):
		released = impl.metadata.get('released', None)
		if not released:
			return 0
		released_time = time.mktime(time.strptime(released, '%Y-%m-%d'))
		return now - released_time

	shown_header = False
	for feed in feeds:
		with open(feed.source_path, 'rb') as stream:
			zfeed = model.ZeroInstallFeed(qdom.parse(stream))
			if zfeed.implementations:
				# Find the latest version number (note that there may be several implementations with this version number)
				latest_version = max(impl.version for impl in zfeed.implementations.values())
				testing_impls = [impl for impl in zfeed.implementations.values()
						 if impl.version == latest_version and
						    impl.upstream_stability == model.stability_levels['testing'] and
						    age(impl) > TIME_TO_GRADUATE]
				if testing_impls:
					if not shown_header:
						print("Releases which are still marked as 'testing' after {days} days:".format(
							days = TIME_TO_GRADUATE / DAY))
						shown_header = True
					print("- {name} v{version}, {age} days ({path})".format(
						age = int(age(testing_impls[0]) / DAY),
						name = zfeed.get_name(),
						path = os.path.relpath(feed.source_path, feeds_dir),
						version = model.format_version(latest_version)))
Exemple #6
0
    def testDebian(self):
        dpkgdir = os.path.join(os.path.dirname(__file__), 'dpkg')
        host = distro.DebianDistribution(os.path.join(dpkgdir, 'status'))
        host._packagekit = DummyPackageKit()

        factory = self.make_factory(host)
        host.get_package_info('gimp', factory)
        self.assertEqual({}, self.feed.implementations)

        # Initially, we only get information about the installed version...
        host.get_package_info('python-bittorrent', factory)
        self.assertEqual(1, len(self.feed.implementations))

        # Tell distro to fetch information about candidates...
        master_feed = parse_impls(
            """<package-implementation package='python-bittorrent'>
					       <restricts interface='http://python.org/python'>
					         <version not-before='3'/>
					       </restricts>
					     </package-implementation>
					  """)
        h = handler.Handler()
        candidates = host.fetch_candidates(master_feed)
        if candidates:
            h.wait_for_blocker(candidates)
        # Now we see the uninstalled package
        self.feed = host.get_feed(master_feed)
        self.assertEqual(2, len(self.feed.implementations))

        # Check restriction appears for both candidates
        for impl in self.feed.implementations.values():
            self.assertEqual(1, len(impl.requires))
            self.assertEqual("http://python.org/python",
                             impl.requires[0].interface)

        self.assertEqual(2, len(self.feed.implementations))
        bittorrent_installed = self.feed.implementations[
            'package:deb:python-bittorrent:3.4.2-10:*']
        bittorrent_uninstalled = self.feed.implementations[
            'package:deb:python-bittorrent:3.4.2-11.1:*']
        self.assertEqual('3.4.2-10', bittorrent_installed.get_version())
        self.assertTrue(bittorrent_installed.installed)
        self.assertFalse(bittorrent_uninstalled.installed)
        self.assertEqual(None, bittorrent_installed.machine)

        self.feed = model.ZeroInstallFeed(empty_feed, local_path='/empty.xml')
        host.get_package_info('libxcomposite-dev', factory)
        self.assertEqual(1, len(self.feed.implementations))
        libxcomposite = self.feed.implementations[
            'package:deb:libxcomposite-dev:0.3.1-1:i386']
        self.assertEqual('0.3.1-1', libxcomposite.get_version())
        self.assertEqual('i386', libxcomposite.machine)

        # Java is special...
        master_feed = parse_impls(
            """<package-implementation package='openjdk-7-jre'/>""")
        feed = host.get_feed(master_feed)
        self.assertEqual(1, len(feed.implementations))
        self.assertEqual('7.3-2.1.1-3',
                         list(feed.implementations.values())[0].get_version())
Exemple #7
0
    def testLocale(self):
        local_path = os.path.join(mydir, 'Local.xml')
        with open(local_path, 'rb') as stream:
            dom = qdom.parse(stream)
        feed = model.ZeroInstallFeed(dom, local_path=local_path)
        # (defaults to en-US if no language is set in the locale)
        self.assertEqual("Local feed (English)", feed.summary)
        self.assertEqual("English", feed.description)

        self.assertEqual(4, len(feed.summaries))
        self.assertEqual(2, len(feed.descriptions))

        try:
            basetest.test_locale = ('es_ES', 'UTF8')

            self.assertEqual("Fuente local", feed.summary)
            self.assertEqual("Español", feed.description)

            basetest.test_locale = ('en_GB', 'UTF8')

            self.assertEqual("Local feed (English GB)", feed.summary)

            basetest.test_locale = ('fr_FR', 'UTF8')

            self.assertEqual("Local feed (English)", feed.summary)
            self.assertEqual("English", feed.description)
        finally:
            basetest.test_locale = (None, None)
Exemple #8
0
	def load_built_feed(self):
		path = self.local_iface_file
		stream = file(path)
		try:
			feed = model.ZeroInstallFeed(qdom.parse(stream), local_path = path)
		finally:
			stream.close()
		return feed
	def testMetadata(self):
		main_feed = model.ZeroInstallFeed(empty_feed, local_path = '/foo')
		e = qdom.parse(StringIO('<ns:b xmlns:ns="a" foo="bar"/>'))
		main_feed.metadata = [e]
		assert main_feed.get_metadata('a', 'b') == [e]
		assert main_feed.get_metadata('b', 'b') == []
		assert main_feed.get_metadata('a', 'a') == []
		assert e.getAttribute('foo') == 'bar'
Exemple #10
0
 def testDownloadSource(self):
     f = model.ZeroInstallFeed(empty_feed, local_path='/foo')
     a = model.ZeroInstallImplementation(f, 'foo', None)
     a.add_download_source('ftp://foo', 1024, None)
     a.add_download_source('ftp://foo.tgz', 1025, 'foo')
     assert a.download_sources[0].url == 'ftp://foo'
     assert a.download_sources[0].size == 1024
     assert a.download_sources[0].extract == None
     assert a.feed is f
Exemple #11
0
def parse_impls(impls):
    xml = """<?xml version="1.0" ?>
		 <interface xmlns="http://zero-install.sourceforge.net/2004/injector/interface">
		   <name>Foo</name>
		   <summary>Foo</summary>
		   <description>Foo</description>
		   {impls}
		</interface>""".format(impls=impls)
    element = qdom.parse(BytesIO(xml.encode('utf-8')))
    return model.ZeroInstallFeed(element, "myfeed.xml")
Exemple #12
0
 def testMetadata(self):
     main_feed = model.ZeroInstallFeed(empty_feed, local_path='/foo')
     assert main_feed.local_path == "/foo"
     e = qdom.parse(BytesIO(b'<ns:b xmlns:ns="a" foo="bar"/>'))
     main_feed.metadata = [e]
     assert main_feed.get_metadata('a', 'b') == [e]
     assert main_feed.get_metadata('b', 'b') == []
     assert main_feed.get_metadata('a', 'a') == []
     assert e.getAttribute('foo') == 'bar'
     self.assertEqual(None, main_feed.get_replaced_by())
Exemple #13
0
def parse_impls(impls):
	xml = """<?xml version="1.0" ?>
		 <interface xmlns="http://zero-install.sourceforge.net/2004/injector/interface">
		   <name>Foo</name>
		   <summary>Foo</summary>
		   <description>Foo</description>
		   %s
		</interface>""" % impls
	element = qdom.parse(StringIO(xml))
	return model.ZeroInstallFeed(element, "myfeed.xml")
Exemple #14
0
    def testDefault(self):
        host = distro.Distribution()

        factory = self.make_factory(host)
        host.get_package_info('gimp', factory)
        self.assertEqual(self.feed.implementations, {})

        # Special case: we can always find a version of Python
        master_feed = model.ZeroInstallFeed(None)
        master_feed.url = 'http://repo.roscidus.com/python/python'
        feed = host.get_feed(master_feed)
        self.assertEqual(1, len(feed.implementations))
Exemple #15
0
    def import_feed(self, url, contents):
        """contents can be a path or an Element."""
        iface_cache = self.config.iface_cache
        iface_cache.get_interface(url)

        if isinstance(contents, qdom.Element):
            feed = model.ZeroInstallFeed(contents)
        else:
            feed = reader.load_feed(contents)

        iface_cache._feeds[url] = feed
        return feed
Exemple #16
0
	def testDebian(self):
		dpkgdir = os.path.join(os.path.dirname(__file__), 'dpkg')
		host = distro.DebianDistribution(
				os.path.join(dpkgdir, 'status'),
				os.path.join(dpkgdir, 'pkgcache.bin'))
		host._packagekit = DummyPackageKit()

		factory = self.make_factory(host)
		host.get_package_info('gimp', factory)
		self.assertEquals({}, self.feed.implementations)

		# Initially, we only get information about the installed version...
		host.get_package_info('python-bittorrent', factory)
		self.assertEquals(1, len(self.feed.implementations))

		# Tell distro to fetch information about candidates...
		master_feed = parse_impls("""<package-implementation package='python-bittorrent'/>""")
		h = handler.Handler()
		candidates = host.fetch_candidates(master_feed)
		if candidates:
			h.wait_for_blocker(candidates)
		# Now we see the uninstalled package
		self.feed = model.ZeroInstallFeed(empty_feed, local_path = '/empty.xml')
		host.get_package_info('python-bittorrent', factory)
		self.assertEquals(2, len(self.feed.implementations))

		self.assertEquals(2, len(self.feed.implementations))
		bittorrent_installed = self.feed.implementations['package:deb:python-bittorrent:3.4.2-10:*']
		bittorrent_uninstalled = self.feed.implementations['package:deb:python-bittorrent:3.4.2-11.1:*']
		self.assertEquals('3.4.2-10', bittorrent_installed.get_version())
		self.assertTrue(bittorrent_installed.installed)
		self.assertFalse(bittorrent_uninstalled.installed)
		self.assertEquals(None, bittorrent_installed.machine)

		self.feed = model.ZeroInstallFeed(empty_feed, local_path = '/empty.xml')
		host.get_package_info('libxcomposite-dev', factory)
		self.assertEquals(1, len(self.feed.implementations))
		libxcomposite = self.feed.implementations['package:deb:libxcomposite-dev:0.3.1-1:i386']
		self.assertEquals('0.3.1-1', libxcomposite.get_version())
		self.assertEquals('i386', libxcomposite.machine)
Exemple #17
0
def import_missing_archive(config, impl, archive):
	from io import BytesIO
	from zeroinstall.injector import model, qdom
	from repo import archives
	print("Importing missing archive {name}".format(name = archive))
	doc = qdom.parse(BytesIO(impl.ownerDocument.documentElement.toxml('utf-8')))
	feed = model.ZeroInstallFeed(doc)
	impl = feed.implementations[impl.getAttribute('id')]
	required_digest = archives.pick_digest(impl)
	new_archives = []
	for method in impl.download_sources:
		new_archives += archives.process_method(config, 'incoming', impl, method, required_digest)
	archives.upload_archives(config, new_archives)
	for x in new_archives:
		os.unlink(x.incoming_path)
	return config.archive_db.lookup(archive)
	def testCommand(self):
		local_path = os.path.join(mydir, 'Command.xml')
		dom = qdom.parse(open(local_path))
		feed = model.ZeroInstallFeed(dom, local_path = local_path)

		assert feed.implementations['a'].main == 'foo'
		assert feed.implementations['a'].commands['run'].path == 'foo'
		assert feed.implementations['a'].commands['test'].path == 'test-foo'

		assert feed.implementations['b'].main == 'bar'
		assert feed.implementations['b'].commands['run'].path == 'bar'
		assert feed.implementations['b'].commands['test'].path == 'test-foo'

		assert feed.implementations['c'].main == 'runnable/missing'
		assert feed.implementations['c'].commands['run'].path == 'runnable/missing'
		assert feed.implementations['c'].commands['test'].path == 'test-baz'
Exemple #19
0
    def testCommand(self):
        local_path = os.path.join(mydir, 'Command.xml')
        with open(local_path, 'rb') as stream:
            dom = qdom.parse(stream)
        feed = model.ZeroInstallFeed(dom, local_path=local_path)

        assert feed.implementations['a'].main == 'foo'
        assert feed.implementations['a'].commands['run'].path == 'foo'
        assert feed.implementations['a'].commands['test'].path == 'test-foo'

        assert feed.implementations['b'].main == 'bar'
        assert feed.implementations['b'].commands['run'].path == 'bar'
        assert feed.implementations['b'].commands['test'].path == 'test-foo'

        assert feed.implementations['c'].main == 'test-gui'
        assert feed.implementations['c'].commands['run'].path == 'test-gui'
        assert feed.implementations['c'].commands['test'].path == 'test-baz'
Exemple #20
0
 def testCommand(self):
     comp_dir = os.path.join(self.tmpdir, 'cprog-command')
     compile('setup',
             local_cprog_command_path,
             comp_dir,
             expect='Created directory')
     os.chdir(comp_dir)
     compile('build', expect='Hello from C!')
     target_dir = 'cprog-command-%s' % support.get_arch_name().lower()
     binary_feed = os.path.join(target_dir, '0install', 'feed.xml')
     run(zi_command, "run", binary_feed, expect='Hello from C!')
     s = open(binary_feed, 'r')
     feed = model.ZeroInstallFeed(qdom.parse(s), binary_feed)
     s.close()
     impl, = feed.implementations.values()
     assert impl.arch, "Missing arch on %s" % impl
     self.assertEqual("Public Domain", str(impl.metadata['license']))
Exemple #21
0
def check(data, warnings = True):
	assert type(data) == bytes, type(data)	# (must not be unicode)

	try:
		doc = minidom.parseString(data)
		if doc.documentElement.getAttribute('uri'):
			local_path = None
		else:
			local_path = '/tmp/local.xml'
		model.ZeroInstallFeed(qdom.parse(io.BytesIO(data)), local_path = local_path)
	except InvalidInterface as ex:
		raise
	except Exception as ex:
		warn("Internal error: %s", ex)
		raise InvalidInterface(str(ex))
	
	if warnings:
		checkElement(doc.documentElement)
Exemple #22
0
    def testArch(self):
        archdir = os.path.join(os.path.dirname(__file__), 'arch')
        arch = distro.ArchDistribution(archdir)

        factory = self.make_factory(arch)
        arch.get_package_info('gimp', factory)
        self.assertEqual({}, self.feed.implementations)

        arch.get_package_info('zeroinstall-injector', factory)
        self.assertEqual(1, len(self.feed.implementations))
        zip = self.feed.implementations[
            'package:arch:zeroinstall-injector:1.5-1:*']
        self.assertEqual('1.5-1', zip.get_version())

        self.feed = model.ZeroInstallFeed(empty_feed, local_path='/empty.xml')
        arch.get_package_info('python2', factory)
        impl, = self.feed.implementations.values()
        self.assertEqual('2.7.2-4', impl.get_version())
Exemple #23
0
    def testSetAtttibs(self):
        local_data = open(local_file).read()
        result = release.set_attributes(local_data,
                                        '0.2',
                                        id='sha1=98765',
                                        version='3.7',
                                        main=None)
        feed = model.ZeroInstallFeed(qdom.parse(io.BytesIO(result)),
                                     "local.xml")
        assert len(feed.implementations) == 1
        assert feed.implementations['sha1=98765'].get_version() == '3.7'

        try:
            result = release.set_attributes(local_data,
                                            '0.3',
                                            id='sha1=98765',
                                            version='3.7',
                                            main=None)
            assert 0
        except Exception as ex:
            assert str(ex) == 'No implementations with version=0.3'
Exemple #24
0
def create_from_local(local):
    path = os.path.abspath(local)
    with open(path, 'rb') as stream:
        feed = model.ZeroInstallFeed(qdom.parse(stream), local_path=path)
    if not feed.feed_for:
        raise Exception(
            "No <feed-for> in '%s'; can't use it as a local feed." % local)
    if len(feed.feed_for) != 1:
        raise Exception("Multiple <feed-for> elements. Not supported, sorry!")
    uri = list(feed.feed_for)[0]

    doc = minidom.parse(local)
    root = doc.documentElement
    root.setAttribute('uri', uri)

    for element in root.getElementsByTagNameNS(XMLNS_IFACE, 'feed-for'):
        if element.parentNode is root:
            remove_with_preceding_comments(element)

    root.appendChild(doc.createTextNode('\n'))

    # minidom's writer loses the newline after the PI
    return xml_header + root.toxml('utf-8')
Exemple #25
0
    def testImpl(self):
        f = model.ZeroInstallFeed(None)
        f.url = 'http://foo'
        a = model.ZeroInstallImplementation(f, 'foo', None)
        assert a.id == 'foo'
        assert a.size == a.version == a.user_stability == None
        assert a.arch == a.upstream_stability == None
        assert a.dependencies == {}
        assert a.download_sources == []
        assert a.get_stability() is model.testing
        a.upstream_stability = model.stable
        assert a.get_stability() is model.stable
        a.user_stability = model.buggy
        assert a.get_stability() is model.buggy
        a.version = model.parse_version('1.2.3')
        self.assertEqual('1.2.3', a.get_version())
        a.version = model.parse_version('1.2.3-rc2-post')
        self.assertEqual('1.2.3-rc2-post', a.get_version())
        assert str(a) == 'foo'

        b = model.ZeroInstallImplementation(f, 'foo', None)
        b.version = model.parse_version("1.2.1")
        assert b > a
Exemple #26
0
 def get_public_feed(self, name, uri_basename):
     with open(os.path.join(self.tmp, 'my-repo', 'public', uri_basename),
               'rb') as stream:
         return model.ZeroInstallFeed(qdom.parse(stream))
Exemple #27
0
 def get_public_feed(self, name, uri_basename):
     with open(name, 'rb') as stream:
         return model.ZeroInstallFeed(qdom.parse(stream))
Exemple #28
0
def process(config, xml_file, delete_on_success):
	# Step 1 : check everything looks sensible, reject if not

	with open(xml_file, 'rb') as stream:
		xml_text = stream.read()
		sig_index = xml_text.rfind('\n<!-- Base64 Signature')
		if sig_index != -1:
			stream.seek(0)
			stream, sigs = gpg.check_stream(stream)
		else:
			sig_index = len(xml_text)
			sigs = []
		root = qdom.parse(BytesIO(xml_text))

	master = get_feed_url(root, xml_file)
	import_master = 'uri' in root.attrs

	if not import_master:
		root.attrs['uri'] = master	# (hack so we can parse it here without setting local_path)

	# Check signatures are valid
	if config.CONTRIBUTOR_GPG_KEYS is not None:
		for sig in sigs:
			if isinstance(sig, gpg.ValidSig) and sig.fingerprint in config.CONTRIBUTOR_GPG_KEYS:
				break
		else:
			raise SafeException("No trusted signatures on feed {path}; signatures were: {sigs}".format(
				path = xml_file,
				sigs = ', '.join([str(s) for s in sigs])))

	feed = model.ZeroInstallFeed(root)

	# Perform custom checks defined by the repository owner
	for impl in feed.implementations.values():
		problem = config.check_new_impl(impl)
		if problem:
			raise SafeException("{problem} in {xml_file}\n(this check was configured in {config}: check_new_impl())".format(
				problem = problem, xml_file = xml_file, config = config.__file__))

	feeds_rel_path = paths.get_feeds_rel_path(config, master)
	feed_path = join("feeds", feeds_rel_path)
	feed_dir = dirname(feed_path)
	if not os.path.isdir(feed_dir):
		os.makedirs(feed_dir)

	scm.ensure_no_uncommitted_changes(feed_path)

	if import_master:
		if os.path.exists(feed_path):
			with open(feed_path, 'rb') as stream:
				existing = stream.read()
			if existing == xml_text[:sig_index]:
				print("Already imported {feed}; skipping".format(feed = feed_path))
				if delete_on_success:
					os.unlink(xml_file)
				return None
			else:
				raise SafeException("Can't import '{url}'; non-identical feed {path} already exists.\n\n"
						    "To ADD new versions to this feed, remove the a 'uri' attribute from "
						    "the root element in {new}.\n\n"
						    "To EDIT the feed, just edit {path} directly rather than trying to add it again.\n\n"
						    "To RE-UPLOAD the archives, do that manually and then edit archives.db."
						    .format(url = feed.url, new = xml_file, path = feed_path))

	# Calculate commit message
	if import_master:
		name = basename(xml_file)
		if name == 'feed.xml':
			name = basename(dirname(xml_file))
		action = 'Imported {file}'.format(file = name)
	else:
		versions = set(i.get_version() for i in feed.implementations.values())
		action = 'Added {name} {versions}'.format(name = feed.get_name(), versions = ', '.join(versions))
	commit_msg = '%s\n\n%s' % (action, xml_text.decode('utf-8'))

	# Calculate new XML
	new_file = not os.path.exists(feed_path)
	git_path = relpath(feed_path, 'feeds')

	if import_master:
		assert new_file
		new_xml = xml_text[:sig_index]
	elif new_file:
		new_xml = create_from_local(master, xml_file)
	else:
		# Merge into existing feed
		try:
			new_doc = merge.merge_files(master, feed_path, xml_file)
		except merge.DuplicateIDException as ex:
			# Did we already import this XML? Compare with the last Git log entry.
			msg, previous_commit_xml = get_last_commit(git_path)
			if previous_commit_xml == xml_text:
				print("Already merged this into {feed}; skipping".format(feed = feed_path))
				return msg
			raise ex

		new_xml = None	# (will regenerate from new_doc below)

	# Step 2 : upload archives to hosting

	processed_archives = archives.process_archives(config, incoming_dir = dirname(xml_file), feed = feed)

	# Step 3 : merge XML into feeds directory

	# Regenerate merged feed
	if new_xml is None:
		new_versions = frozenset(impl.get_version() for impl in feed.implementations.values())
		if len(new_versions) == 1 and getattr(config, 'TRACK_TESTING_IMPLS', True):
			ask_if_previous_still_testing(new_doc, list(new_versions)[0])
		new_xml = formatting.format_doc(new_doc)

	did_git_add = False

	try:
		with open(feed_path + '.new', 'wb') as stream:
			stream.write(new_xml)
		support.portable_rename(feed_path + '.new', feed_path)

		# Commit
		if new_file:
			subprocess.check_call(['git', 'add', git_path], cwd = 'feeds')
			did_git_add = True

		# (this must be last in the try block)
		scm.commit('feeds', [git_path], commit_msg, key = config.GPG_SIGNING_KEY)
	except Exception as ex:
		# Roll-back (we didn't commit to Git yet)
		print(ex)
		print("Error updating feed {feed}; rolling-back...".format(feed = xml_file))
		if new_file:
			if os.path.exists(feed_path):
				os.unlink(feed_path)
			if did_git_add:
				subprocess.check_call(['git', 'rm', '--', git_path], cwd = 'feeds')
		else:
			subprocess.check_call(['git', 'checkout', 'HEAD', '--', git_path], cwd = 'feeds')
		raise

	# Delete XML and archives from incoming directory
	if delete_on_success:
		os.unlink(xml_file)
		for archive in processed_archives:
			os.unlink(archive.incoming_path)

	return commit_msg.split('\n', 1)[0]
Exemple #29
0
 def testReplaced(self):
     local_path = os.path.join(mydir, 'Replaced.xml')
     with open(local_path, 'rb') as stream:
         dom = qdom.parse(stream)
     feed = model.ZeroInstallFeed(dom, local_path=local_path)
     self.assertEqual("http://localhost:8000/Hello", feed.get_replaced_by())
Exemple #30
0
 def testInterface(self):
     i = model.Interface('http://foo')
     self.assertEqual('(foo)', i.get_name())
     feed = model.ZeroInstallFeed(empty_feed, local_path='/foo')
     self.assertEqual('Empty', feed.get_name())
     repr(i)