From 28d8ae8d84cf9f983ef7c00aa725780f6a0a9604 Mon Sep 17 00:00:00 2001 From: Anders F Bjorklund Date: Mon, 19 Apr 2010 20:51:57 +0200 Subject: [PATCH] Added support for Apple disk image (.dmg) archives --- tests/HelloWorld.dmg | Bin 0 -> 50272 bytes tests/testunpack.py | 4 ++++ zeroinstall/zerostore/unpack.py | 29 ++++++++++++++++++++++++++++- 3 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 tests/HelloWorld.dmg diff --git a/tests/HelloWorld.dmg b/tests/HelloWorld.dmg new file mode 100644 index 0000000000000000000000000000000000000000..971b6d66c78a3c3a82602a2dad9bd78dfce2748b GIT binary patch literal 50272 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 literal 0 HcwPel00001 diff --git a/tests/testunpack.py b/tests/testunpack.py index 959789a..7ae20ff 100755 --- a/tests/testunpack.py +++ b/tests/testunpack.py @@ -33,6 +33,10 @@ class AbstractTestUnpack(BaseTest): unpack.unpack_archive('ftp://foo/file.tgz', file('HelloWorld.tgz'), self.tmpdir) self.assert_manifest('sha1=3ce644dc725f1d21cfcf02562c76f375944b266a') + def testDmg(self): + unpack.unpack_archive('ftp://foo/file.dmg', file('HelloWorld.dmg'), self.tmpdir) + self.assert_manifest('sha1=3ce644dc725f1d21cfcf02562c76f375944b266a') + def testZip(self): unpack.unpack_archive('ftp://foo/file.zip', file('HelloWorld.zip'), self.tmpdir) self.assert_manifest('sha1=3ce644dc725f1d21cfcf02562c76f375944b266a') diff --git a/zeroinstall/zerostore/unpack.py b/zeroinstall/zerostore/unpack.py index 0155aec..d6d5593 100644 --- a/zeroinstall/zerostore/unpack.py +++ b/zeroinstall/zerostore/unpack.py @@ -6,6 +6,7 @@ from zeroinstall import _ import os, subprocess import shutil +import glob import traceback from tempfile import mkdtemp, mkstemp import re @@ -73,6 +74,7 @@ def type_from_url(url): if url.endswith('.tar'): return 'application/x-tar' if url.endswith('.zip'): return 'application/zip' if url.endswith('.cab'): return 'application/vnd.ms-cab-compressed' + if url.endswith('.dmg'): return 'application/x-apple-diskimage' return None def check_type_ok(mime_type): @@ -99,6 +101,10 @@ def check_type_ok(mime_type): if not find_in_path('cabextract'): raise SafeException(_("This package looks like a Microsoft Cabinet archive, but you don't have the 'cabextract' command " "I need to extract it. Install the package containing it first.")) + elif mime_type == 'application/x-apple-diskimage': + if not find_in_path('hdiutil'): + raise SafeException(_("This package looks like a Apple Disk Image, but you don't have the 'hdiutil' command " + "I need to extract it.")) elif mime_type == 'application/x-lzma-compressed-tar': pass # We can get it through Zero Install elif mime_type == 'application/x-xz-compressed-tar': @@ -200,6 +206,8 @@ def unpack_archive(url, data, destdir, extract = None, type = None, start_offset extract_tar(data, destdir, extract, 'gzip', start_offset) elif type == 'application/vnd.ms-cab-compressed': extract_cab(data, destdir, extract, start_offset) + elif type == 'application/x-apple-diskimage': + extract_dmg(data, destdir, extract, start_offset) else: raise SafeException(_('Unknown MIME type "%(type)s" for "%(url)s"') % {'type': type, 'url': url}) @@ -291,7 +299,26 @@ def extract_cab(stream, destdir, extract, start_offset = 0): _extract(stream, destdir, ['cabextract', '-s', '-q', 'archive.cab']) os.unlink(cab_copy_name) - + +def extract_dmg(stream, destdir, extract, start_offset = 0): + "@since: 0.46" + if extract: + raise SafeException(_('Sorry, but the "extract" attribute is not yet supported for DMGs')) + + stream.seek(start_offset) + # hdiutil can't read from stdin, so make a copy... + dmg_copy_name = os.path.join(destdir, 'archive.dmg') + dmg_copy = file(dmg_copy_name, 'w') + shutil.copyfileobj(stream, dmg_copy) + dmg_copy.close() + + mountpoint = mkdtemp(prefix='archive') + subprocess.check_call(["hdiutil", "attach", "-quiet", "-mountpoint", mountpoint, "-nobrowse", dmg_copy_name]) + subprocess.check_call(["cp", "-pR"] + glob.glob("%s/*" % mountpoint) + [destdir]) + subprocess.check_call(["hdiutil", "detach", "-quiet", mountpoint]) + os.rmdir(mountpoint) + os.unlink(dmg_copy_name) + def extract_zip(stream, destdir, extract, start_offset = 0): if extract: # Limit the characters we accept, to avoid sending dodgy -- 2.11.4.GIT