Skip to content
This repository has been archived by the owner on Dec 27, 2022. It is now read-only.

Commit

Permalink
Refactored code as required for the new 0publish
Browse files Browse the repository at this point in the history
  • Loading branch information
Tim Diels committed Aug 20, 2011
2 parents a34088e + 690fadd commit 7f12577
Show file tree
Hide file tree
Showing 8 changed files with 438 additions and 203 deletions.
15 changes: 15 additions & 0 deletions tests/ImplementationNoId.xml
@@ -0,0 +1,15 @@
<?xml version="1.0" ?>
<?xml-stylesheet type='text/xsl' href='interface.xsl'?>
<interface main="HelloWorld/main" uri="http://example.com:8000/Hello.xml" xmlns="http://zero-install.sourceforge.net/2004/injector/interface">
<name>Hello</name>
<summary>Hello</summary>
<description>Hello</description>
<implementation version="1">
<archive href="http://localhost:8000/HelloWorld.tgz" size="176"/>
</implementation>
</interface>
<!-- Base64 Signature
iEYEABECAAYFAkmqgqEACgkQb88SG+I5DgvHdgCbBWNXJPIIyYwpLcO4GG6VQE6i89MAniWUyvZd
RIDJACxauMnd7SIpxdcg
-->
15 changes: 15 additions & 0 deletions tests/MissingSize.xml
@@ -0,0 +1,15 @@
<?xml version="1.0" ?>
<?xml-stylesheet type='text/xsl' href='interface.xsl'?>
<interface main="HelloWorld/main" uri="http://example.com:8000/MissingSize.xml" xmlns="http://zero-install.sourceforge.net/2004/injector/interface">
<name>Hello</name>
<summary>Hello</summary>
<description>Hello</description>
<implementation id="sha1=3ce644dc725f1d21cfcf02562c76f375944b266a" version="1">
<archive href="http://localhost:8000/HelloWorld.tgz" />
</implementation>
</interface>
<!-- Base64 Signature
iEYEABECAAYFAkmqgqEACgkQb88SG+I5DgvHdgCbBWNXJPIIyYwpLcO4GG6VQE6i89MAniWUyvZd
RIDJACxauMnd7SIpxdcg
-->
33 changes: 33 additions & 0 deletions tests/testdownload.py
Expand Up @@ -269,6 +269,39 @@ def testWrongSize(self):
if "Downloaded archive has incorrect size" not in str(ex):
raise ex

def testImplementationGenerateMissingId(self):
old_out = sys.stdout
try:
sys.stdout = StringIO()
self.child = server.handle_requests(('HelloWorld.tgz'))

from zeroinstall.zerostore import manifest
alg = manifest.get_algorithm('sha1')
assert alg

from zeroinstall.injector.reader import load_feed
feed = load_feed(os.path.abspath('ImplementationNoId.xml'), True, False, False, alg, self.config)

expected_id = 'sha1=3ce644dc725f1d21cfcf02562c76f375944b266a'
assert feed.implementations[expected_id]
assert feed.implementations[expected_id].id == expected_id
finally:
sys.stdout = old_out

def testArchiveGenerateMissingSize(self):
old_out = sys.stdout
try:
sys.stdout = StringIO()
self.child = server.handle_requests(('HelloWorld.tgz'))

from zeroinstall.injector.reader import load_feed
feed = load_feed(os.path.abspath('MissingSize.xml'), True, False, True, None, self.config)

expected_id = 'sha1=3ce644dc725f1d21cfcf02562c76f375944b266a'
assert feed.implementations[expected_id].download_sources[0].size == 176
finally:
sys.stdout = old_out

def testRecipe(self):
old_out = sys.stdout
try:
Expand Down
1 change: 1 addition & 0 deletions tests/testmodel.py
Expand Up @@ -176,6 +176,7 @@ def testDownloadSource(self):
assert a.download_sources[0].size == 1024
assert a.download_sources[0].extract == None
assert a.feed is f
assert len(tuple(a.archives)) == 2

def testEnvBind(self):
a = model.EnvironmentBinding('PYTHONPATH', 'path')
Expand Down
106 changes: 15 additions & 91 deletions zeroinstall/injector/fetch.py
Expand Up @@ -11,7 +11,7 @@

from zeroinstall.support import tasks, basedir
from zeroinstall.injector.namespaces import XMLNS_IFACE, config_site
from zeroinstall.injector.model import DownloadSource, Recipe, SafeException, escape, DistributionSource
from zeroinstall.injector.model import SafeException, escape, DistributionSource
from zeroinstall.injector.iface_cache import PendingFeed, ReplayAttack
from zeroinstall.injector.handler import NoTrustedKeys
from zeroinstall.injector import download
Expand Down Expand Up @@ -96,38 +96,15 @@ def __init__(self, config):
def handler(self):
return self.config.handler

@tasks.async
def cook(self, required_digest, recipe, stores, force = False, impl_hint = None):
"""Follow a Recipe.
@deprecated: use impl.retrieve() instead
@param impl_hint: the Implementation this is for (if any) as a hint for the GUI
@see: L{download_impl} uses this method when appropriate"""
# Maybe we're taking this metaphor too far?

# Start preparing all steps
step_commands = [step.prepare(self, force, impl_hint) for step in recipe.steps]

# Create an empty directory for the new implementation
store = stores.stores[0]
tmpdir = store.get_tmp_dir_for(required_digest)

try:
# Run steps
valid_blockers = [s.blocker for s in step_commands if s.blocker is not None]
for step_command in step_commands:
if step_command.blocker:
while not step_command.blocker.happened:
yield valid_blockers
tasks.check(valid_blockers)
step_command.run(tmpdir)

# Check that the result is correct and store it in the cache
store.check_manifest_and_rename(required_digest, tmpdir)
tmpdir = None
finally:
# If unpacking fails, remove the temporary directory
if tmpdir is not None:
from zeroinstall import support
support.ro_rmtree(tmpdir)
# Note: unused
return impl_hint.retrieve(self, recipe, stores, force)


def get_feed_mirror(self, url):
"""Return the URL of a mirror for this feed."""
Expand Down Expand Up @@ -297,6 +274,7 @@ def fetch_key_info(self, fingerprint):

def download_impl(self, impl, retrieval_method, stores, force = False):
"""Download an implementation.
@deprecated: use impl.retrieve(...) instead
@param impl: the selected implementation
@type impl: L{model.ZeroInstallImplementation}
@param retrieval_method: a way of getting the implementation (e.g. an Archive or a Recipe)
Expand All @@ -307,68 +285,14 @@ def download_impl(self, impl, retrieval_method, stores, force = False):
@rtype: L{tasks.Blocker}"""
assert impl
assert retrieval_method

if isinstance(retrieval_method, DistributionSource):
return retrieval_method.install(self.handler)

from zeroinstall.zerostore import manifest
best = None
for digest in impl.digests:
alg_name = digest.split('=', 1)[0]
alg = manifest.algorithms.get(alg_name, None)
if alg and (best is None or best.rating < alg.rating):
best = alg
required_digest = digest

if best is None:
if not impl.digests:
raise SafeException(_("No <manifest-digest> given for '%(implementation)s' version %(version)s") %
{'implementation': impl.feed.get_name(), 'version': impl.get_version()})
raise SafeException(_("Unknown digest algorithms '%(algorithms)s' for '%(implementation)s' version %(version)s") %
{'algorithms': impl.digests, 'implementation': impl.feed.get_name(), 'version': impl.get_version()})

@tasks.async
def download_impl():
if isinstance(retrieval_method, DownloadSource):
blocker, stream = self.download_archive(retrieval_method, force = force, impl_hint = impl)
yield blocker
tasks.check(blocker)

stream.seek(0)
self._add_to_cache(required_digest, stores, retrieval_method, stream)
elif isinstance(retrieval_method, Recipe):
blocker = self.cook(required_digest, retrieval_method, stores, force, impl_hint = impl)
yield blocker
tasks.check(blocker)
else:
raise Exception(_("Unknown download type for '%s'") % retrieval_method)

self.handler.impl_added_to_store(impl)
return download_impl()

def _add_to_cache(self, required_digest, stores, retrieval_method, stream):
assert isinstance(retrieval_method, DownloadSource)
stores.add_archive_to_cache(required_digest, stream, retrieval_method.url, retrieval_method.extract,
type = retrieval_method.type, start_offset = retrieval_method.start_offset or 0)
return impl.retrieve(self, retrieval_method, stores, force)

def download_archive(self, download_source, force = False, impl_hint = None):
"""Fetch an archive. You should normally call L{download_impl}
instead, since it handles other kinds of retrieval method too."""
from zeroinstall.zerostore import unpack

url = download_source.url
if not (url.startswith('http:') or url.startswith('https:') or url.startswith('ftp:')):
raise SafeException(_("Unknown scheme in download URL '%s'") % url)

mime_type = download_source.type
if not mime_type:
mime_type = unpack.type_from_url(download_source.url)
if not mime_type:
raise SafeException(_("No 'type' attribute on archive, and I can't guess from the name (%s)") % download_source.url)
unpack.check_type_ok(mime_type)
dl = self.handler.get_download(download_source.url, force = force, hint = impl_hint)
dl.expected_size = download_source.size + (download_source.start_offset or 0)
return (dl.downloaded, dl.tempfile)
instead, since it handles other kinds of retrieval method too.
@deprecated: use download_source.download instead"""
# Note: unused
return download_source.download(self, force, impl_hint)

def download_icon(self, interface, force = False):
"""Download an icon for this interface and add it to the
Expand Down Expand Up @@ -484,8 +408,8 @@ def dl_error(ex, tb = None):

def get_best_source(self, impl):
"""Return the best download source for this implementation.
@rtype: L{model.RetrievalMethod}"""
if impl.download_sources:
return impl.download_sources[0]
return None
@rtype: L{model.RetrievalMethod}
@deprecated: use impl.best_download_source instead
"""
return impl.best_download_source

0 comments on commit 7f12577

Please sign in to comment.