コード例 #1
0
ファイル: install.py プロジェクト: res2k/0export
def add_to_menu(uris):
	for uri in uris:
		iface = config.iface_cache.get_interface(uri)
		icon_path = config.iface_cache.get_icon_path(iface)

		feed_category = ''
		for meta in iface.get_metadata(namespaces.XMLNS_IFACE, 'category'):
			c = meta.content
			if '\n' in c:
				raise Exception("Invalid category '%s'" % c)
			feed_category = c
			break

		xdgutils.add_to_menu(iface, icon_path, feed_category)

	if find_in_path('0launch'):
		return

	if find_in_path('sudo') and find_in_path('gnome-terminal') and find_in_path('apt-get'):
		check_call(['gnome-terminal', '--disable-factory', '-x', 'sh', '-c',
					   'echo "We need to install the zeroinstall-injector package to make the menu items work."; '
					   'sudo apt-get install zeroinstall-injector || sleep 4'])

		if find_in_path('0launch'):
			return

	import gtk
	box = gtk.MessageDialog(None, 0, buttons = gtk.BUTTONS_OK)
	box.set_markup("The new menu item won't work until the '<b>zeroinstall-injector</b>' package is installed.\n"
			"Please install it using your distribution's package manager.")
	box.run()
	box.destroy()
	gtk.gdk.flush()
コード例 #2
0
ファイル: applistbox.py プロジェクト: rammstein/0install
 def action_run(self, uri):
     iface = self.iface_cache.get_interface(uri)
     reader.update_from_cache(iface)
     if len(iface.get_metadata(namespaces.XMLNS_IFACE, 'needs-terminal')):
         if gtk.pygtk_version >= (2, 16,
                                  0) and gtk.gdk.WINDOWING == 'quartz':
             script = ['0launch', '--', uri]
             osascript = support.find_in_path('osascript')
             subprocess.Popen([
                 osascript, '-e', 'tell app "Terminal"', '-e', 'activate',
                 '-e',
                 'do script "%s"' % ' '.join(script), '-e', 'end tell'
             ])
             return
         for terminal in [
                 'x-terminal-emulator', 'xterm', 'gnome-terminal', 'rxvt',
                 'konsole'
         ]:
             exe = support.find_in_path(terminal)
             if exe:
                 if terminal == 'gnome-terminal':
                     flag = '-x'
                 else:
                     flag = '-e'
                 subprocess.Popen([terminal, flag, '0launch', '--', uri])
                 break
         else:
             box = gtk.MessageDialog(
                 self.window, gtk.DIALOG_MODAL,
                 gtk.MESSAGE_ERROR, gtk.BUTTONS_OK,
                 _("Can't find a suitable terminal emulator"))
             box.run()
             box.destroy()
     else:
         subprocess.Popen(['0launch', '--', uri])
コード例 #3
0
ファイル: applistbox.py プロジェクト: dsqmoore/0install
	def action_run(self, uri):
		iface = self.iface_cache.get_interface(uri)
		reader.update_from_cache(iface)
		if len(iface.get_metadata(namespaces.XMLNS_IFACE, 'needs-terminal')):
			if gtk.pygtk_version >= (2,16,0) and gtk.gdk.WINDOWING == 'quartz':
				script = ['0launch', '--', uri]
				osascript = support.find_in_path('osascript')
				subprocess.Popen([osascript, '-e', 'tell app "Terminal"', '-e', 'activate',
							     '-e', 'do script "%s"' % ' '.join(script), '-e', 'end tell'])
				return
			for terminal in ['x-terminal-emulator', 'xterm', 'gnome-terminal', 'rxvt', 'konsole']:
				exe = support.find_in_path(terminal)
				if exe:
					if terminal == 'gnome-terminal':
						flag = '-x'
					else:
						flag = '-e'
					subprocess.Popen([terminal, flag, '0launch', '--', uri])
					break
			else:
				box = gtk.MessageDialog(self.window, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, _("Can't find a suitable terminal emulator"))
				box.run()
				box.destroy()
		else:
			subprocess.Popen(['0launch', '--', uri])
コード例 #4
0
ファイル: gpg.py プロジェクト: dabrahams/zeroinstall
def _run_gpg(args, **kwargs):
	global _gnupg_options
	if _gnupg_options is None:
		gpg_path = find_in_path('gpg') or find_in_path('gpg2') or 'gpg'
		_gnupg_options = [gpg_path, '--no-secmem-warning']

		if hasattr(os, 'geteuid') and os.geteuid() == 0 and 'GNUPGHOME' not in os.environ:
			_gnupg_options += ['--homedir', os.path.join(basedir.home, '.gnupg')]
			info(_("Running as root, so setting GnuPG home to %s"), _gnupg_options[-1])

	return subprocess.Popen(_gnupg_options + args, **kwargs)
コード例 #5
0
def _run_gpg(args, **kwargs):
	global _gnupg_options
	if _gnupg_options is None:
		gpg_path = find_in_path('gpg') or find_in_path('gpg2') or 'gpg'
		_gnupg_options = [gpg_path, '--no-secmem-warning',
                          '--preserve-permissions', '--no-permission-warning']

		if hasattr(os, 'geteuid') and os.geteuid() == 0 and 'GNUPGHOME' not in os.environ:
			_gnupg_options += ['--homedir', os.path.join(basedir.home, '.gnupg')]
			info(_("Running as root, so setting GnuPG home to %s"), _gnupg_options[-1])

	return subprocess.Popen(_gnupg_options + args, **kwargs)
コード例 #6
0
ファイル: gpg.py プロジェクト: AlexanderRyzhko/0install-TUF
def _run_gpg(args, **kwargs):
	"""@type args: [str]
	@rtype: subprocess.Popen"""
	global _gnupg_options
	if _gnupg_options is None:
		gpg_path = os.environ.get('ZEROINSTALL_GPG') or find_in_path('gpg') or find_in_path('gpg2') or 'gpg'
		_gnupg_options = [gpg_path, '--no-secmem-warning']

		if hasattr(os, 'geteuid') and os.geteuid() == 0 and 'GNUPGHOME' not in os.environ:
			_gnupg_options += ['--homedir', os.path.join(basedir.home, '.gnupg')]
			logger.info(_("Running as root, so setting GnuPG home to %s"), _gnupg_options[-1])

	return subprocess.Popen(_gnupg_options + args, universal_newlines = True, **kwargs)
コード例 #7
0
ファイル: model.py プロジェクト: dsqmoore/0install
def canonical_iface_uri(uri):
	"""If uri is a relative path, convert to an absolute one.
	A "file:///foo" URI is converted to "/foo".
	An "alias:prog" URI expands to the URI in the 0alias script
	Otherwise, return it unmodified.
	@rtype: str
	@raise SafeException: if uri isn't valid
	"""
	if uri.startswith('http://') or uri.startswith('https://'):
		if uri.count("/") < 3:
			raise SafeException(_("Missing / after hostname in URI '%s'") % uri)
		return uri
	elif uri.startswith('file:///'):
		path = uri[7:]
	elif uri.startswith('file:'):
		if uri[5] == '/':
			raise SafeException(_('Use file:///path for absolute paths, not {uri}').format(uri = uri))
		path = os.path.abspath(uri[5:])
	elif uri.startswith('alias:'):
		from zeroinstall import alias
		alias_prog = uri[6:]
		if not os.path.isabs(alias_prog):
			full_path = support.find_in_path(alias_prog)
			if not full_path:
				raise alias.NotAnAliasScript("Not found in $PATH: " + alias_prog)
		else:
			full_path = alias_prog
		return alias.parse_script(full_path).uri
	else:
		path = os.path.realpath(uri)

	if os.path.isfile(path):
		return path

	if '/' not in uri:
		alias_path = support.find_in_path(uri)
		if alias_path is not None:
			from zeroinstall import alias
			try:
				alias.parse_script(alias_path)
			except alias.NotAnAliasScript:
				pass
			else:
				raise SafeException(_("Bad interface name '{uri}'.\n"
					"(hint: try 'alias:{uri}' instead)".format(uri = uri)))

	raise SafeException(_("Bad interface name '%(uri)s'.\n"
			"(doesn't start with 'http:', and "
			"doesn't exist as a local file '%(interface_uri)s' either)") %
			{'uri': uri, 'interface_uri': path})
コード例 #8
0
ファイル: man.py プロジェクト: timdiels/0install
def _0install_man(config, command):
    from zeroinstall import apps, alias, helpers

    path = support.find_in_path(command)
    if not path:
        return None

    with open(path, 'rt') as stream:
        app_info = apps.parse_script_header(stream)
        if app_info:
            app = config.app_mgr.lookup_app(app_info.name)
            sels = app.get_selections()
            main = None
        else:
            alias_info = alias.parse_script_header(stream)
            if alias_info is None:
                return None
            sels = helpers.ensure_cached(alias_info.uri,
                                         alias_info.command,
                                         config=config)
            if not sels:
                # Cancelled by user
                sys.exit(1)
            main = alias_info.main

    helpers.exec_man(config.stores, sels, main, fallback_name=command)
    assert 0
コード例 #9
0
ファイル: __init__.py プロジェクト: timdiels/0install
	def _add_with_helper(self, required_digest, path):
		"""Use 0store-secure-add to copy 'path' to the system store.
		@param required_digest: the digest for path
		@type required_digest: str
		@param path: root of implementation directory structure
		@type path: str
		@return: True iff the directory was copied into the system cache successfully
		"""
		if required_digest.startswith('sha1='):
			return False		# Old digest alg not supported
		helper = support.find_in_path('0store-secure-add-helper')
		if not helper:
			logger.info(_("'0store-secure-add-helper' command not found. Not adding to system cache."))
			return False
		import subprocess
		env = os.environ.copy()
		env['ENV_NOT_CLEARED'] = 'Unclean'	# (warn about insecure configurations)
		env['HOME'] = 'Unclean'			# (warn about insecure configurations)
		dev_null = os.open(os.devnull, os.O_RDONLY)
		try:
			logger.info(_("Trying to add to system cache using %s"), helper)
			child = subprocess.Popen([helper, required_digest],
						 stdin = dev_null,
						 cwd = path,
						 env = env)
			exit_code = child.wait()
		finally:
			os.close(dev_null)

		if exit_code:
			logger.warn(_("0store-secure-add-helper failed."))
			return False

		logger.info(_("Added succcessfully."))
		return True
コード例 #10
0
ファイル: man.py プロジェクト: res2k/0install
def _0install_man(config, command):
    """@type command: str"""
    from zeroinstall import apps, alias, helpers

    path = support.find_in_path(command)
    if not path:
        return None

    try:
        with open(path, "rt") as stream:
            app_info = apps.parse_script_header(stream)
            if app_info:
                app = config.app_mgr.lookup_app(app_info.name)
                sels = app.get_selections()
                main = None
            else:
                alias_info = alias.parse_script_header(stream)
                if alias_info is None:
                    return None
                sels = helpers.ensure_cached(alias_info.uri, alias_info.command, config=config)
                if not sels:
                    # Cancelled by user
                    sys.exit(1)
                main = alias_info.main
    except IOError as ex:
        logger.info("%s: falling back to `man %s`", ex, command)
        os.execlp("man", "man", command)
        sys.exit(1)

    helpers.exec_man(config.stores, sels, main, fallback_name=command)
    assert 0
コード例 #11
0
def _0install_man(config, command):
    """@type command: str"""
    from zeroinstall import apps, alias, helpers

    path = support.find_in_path(command)
    if not path:
        return None

    try:
        with open(path, 'rt') as stream:
            app_info = apps.parse_script_header(stream)
            if app_info:
                app = config.app_mgr.lookup_app(app_info.name)
                sels = app.get_selections()
                main = None
            else:
                alias_info = alias.parse_script_header(stream)
                if alias_info is None:
                    return None
                sels = helpers.ensure_cached(alias_info.uri,
                                             alias_info.command,
                                             config=config)
                if not sels:
                    # Cancelled by user
                    sys.exit(1)
                main = alias_info.main
    except IOError as ex:
        logger.info("%s: falling back to `man %s`", ex, command)
        os.execlp('man', 'man', command)
        sys.exit(1)

    helpers.exec_man(config.stores, sels, main, fallback_name=command)
    assert 0
コード例 #12
0
ファイル: install.py プロジェクト: res2k/0export
def run(uri, args, prog_args):
	print "Running program..."
	if copied_0launch_in_cache:
		launch = os.path.join(copied_0launch_in_cache, '0launch')
	else:
		launch = find_in_path('0launch')
	os.execv(launch, [launch] + args + [uri] + prog_args)
コード例 #13
0
ファイル: __init__.py プロジェクト: dabrahams/zeroinstall
	def _add_with_helper(self, required_digest, path):
		"""Use 0store-secure-add to copy 'path' to the system store.
		@param required_digest: the digest for path
		@type required_digest: str
		@param path: root of implementation directory structure
		@type path: str
		@return: True iff the directory was copied into the system cache successfully
		"""
		if required_digest.startswith('sha1='):
			return False		# Old digest alg not supported
		helper = support.find_in_path('0store-secure-add-helper')
		if not helper:
			info(_("'0store-secure-add-helper' command not found. Not adding to system cache."))
			return False
		import subprocess
		env = os.environ.copy()
		env['ENV_NOT_CLEARED'] = 'Unclean'	# (warn about insecure configurations)
		env['HOME'] = 'Unclean'			# (warn about insecure configurations)
		dev_null = os.open(os.devnull, os.O_RDONLY)
		try:
			info(_("Trying to add to system cache using %s"), helper)
			child = subprocess.Popen([helper, required_digest],
						 stdin = dev_null,
						 cwd = path,
						 env = env)
			exit_code = child.wait()
		finally:
			os.close(dev_null)

		if exit_code:
			warn(_("0store-secure-add-helper failed."))
			return False

		info(_("Added succcessfully."))
		return True
コード例 #14
0
ファイル: man.py プロジェクト: dabrahams/0install
def _0install_man(config, command):
	from zeroinstall import apps, alias, helpers

	path = support.find_in_path(command)
	if not path:
		return None

	with open(path, 'rt') as stream:
		app_info = apps.parse_script_header(stream)
		if app_info:
			app = config.app_mgr.lookup_app(app_info.name)
			sels = app.get_selections()
			main = None
		else:
			alias_info = alias.parse_script_header(stream)
			if alias_info is None:
				return None
			sels = helpers.ensure_cached(alias_info.uri, alias_info.command, config = config)
			if not sels:
				# Cancelled by user
				sys.exit(1)
			main = alias_info.main

	helpers.exec_man(config.stores, sels, main, fallback_name = command)
	assert 0
コード例 #15
0
ファイル: model.py プロジェクト: pombredanne/zero-install
def canonical_iface_uri(uri):
	"""If uri is a relative path, convert to an absolute one.
	A "file:///foo" URI is converted to "/foo".
	An "alias:prog" URI expands to the URI in the 0alias script
	Otherwise, return it unmodified.
	@rtype: str
	@raise SafeException: if uri isn't valid
	"""
	if uri.startswith('http://') or uri.startswith('https://'):
		if uri.count("/") < 3:
			raise SafeException(_("Missing / after hostname in URI '%s'") % uri)
		return uri
	elif uri.startswith('file:///'):
		return uri[7:]
	elif uri.startswith('alias:'):
		from zeroinstall import alias, support
		alias_prog = uri[6:]
		if not os.path.isabs(alias_prog):
			full_path = support.find_in_path(alias_prog)
			if not full_path:
				raise alias.NotAnAliasScript("Not found in $PATH: " + alias_prog)
		else:
			full_path = alias_prog
		interface_uri, main = alias.parse_script(full_path)
		return interface_uri
	else:
		iface_uri = os.path.realpath(uri)
		if os.path.isfile(iface_uri):
			return iface_uri
	raise SafeException(_("Bad interface name '%(uri)s'.\n"
			"(doesn't start with 'http:', and "
			"doesn't exist as a local file '%(interface_uri)s' either)") %
			{'uri': uri, 'interface_uri': iface_uri})
コード例 #16
0
ファイル: gpg.py プロジェクト: timdiels/0install
def _run_gpg(args, **kwargs):
    global _gnupg_options
    if _gnupg_options is None:
        gpg_path = os.environ.get('ZEROINSTALL_GPG') or find_in_path(
            'gpg') or find_in_path('gpg2') or 'gpg'
        _gnupg_options = [gpg_path, '--no-secmem-warning']

        if hasattr(os, 'geteuid') and os.geteuid(
        ) == 0 and 'GNUPGHOME' not in os.environ:
            _gnupg_options += [
                '--homedir', os.path.join(basedir.home, '.gnupg')
            ]
            logger.info(_("Running as root, so setting GnuPG home to %s"),
                        _gnupg_options[-1])

    return subprocess.Popen(_gnupg_options + args,
                            universal_newlines=True,
                            **kwargs)
コード例 #17
0
ファイル: unpack.py プロジェクト: dabrahams/0install
def _exec_maybe_sandboxed(writable, prog, *args):
	"""execlp prog, with (only) the 'writable' directory writable if sandboxing is available.
	If no sandbox is available, run without a sandbox."""
	prog_path = find_in_path(prog)
	if not prog_path: raise Exception(_("'%s' not found in $PATH") % prog)
	if _pola_run is None:
		os.execlp(prog_path, prog_path, *args)
	# We have pola-shell :-)
	pola_args = ['--prog', prog_path, '-f', '/']
	for a in args:
		pola_args += ['-a', a]
	if writable:
		pola_args += ['-fw', writable]
	os.execl(_pola_run, _pola_run, *pola_args)
コード例 #18
0
def _exec_maybe_sandboxed(writable, prog, *args):
    """execlp prog, with (only) the 'writable' directory writable if sandboxing is available.
	If no sandbox is available, run without a sandbox."""
    prog_path = find_in_path(prog)
    if not prog_path: raise Exception(_("'%s' not found in $PATH") % prog)
    if _pola_run is None:
        os.execlp(prog_path, prog_path, *args)
    # We have pola-shell :-)
    pola_args = ['--prog', prog_path, '-f', '/']
    for a in args:
        pola_args += ['-a', a]
    if writable:
        pola_args += ['-fw', writable]
    os.execl(_pola_run, _pola_run, *pola_args)
コード例 #19
0
def check_type_ok(mime_type):
    """Check we have the needed software to extract from an archive of the given type.
	@type mime_type: str
	@raise SafeException: if the needed software is not available"""
    assert mime_type
    if mime_type == 'application/x-rpm':
        if not find_in_path('rpm2cpio'):
            raise SafeException(
                _("This package looks like an RPM, but you don't have the rpm2cpio command "
                  "I need to extract it. Install the 'rpm' package first (this works even if "
                  "you're on a non-RPM-based distribution such as Debian)."))
    elif mime_type == 'application/x-deb':
        if not find_in_path('ar'):
            raise SafeException(
                _("This package looks like a Debian package, but you don't have the 'ar' command "
                  "I need to extract it. Install the package containing it (sometimes called 'binutils') "
                  "first. This works even if you're on a non-Debian-based distribution such as Red Hat)."
                  ))
    elif mime_type == 'application/x-bzip-compressed-tar':
        pass  # We'll fall back to Python's built-in tar.bz2 support
    elif mime_type == 'application/zip':
        if not find_in_path('unzip'):
            raise SafeException(
                _("This package looks like a zip-compressed archive, but you don't have the 'unzip' command "
                  "I need to extract it. Install the package containing it first."
                  ))
    elif mime_type == 'application/vnd.ms-cab-compressed':
        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':
        if not find_in_path('unxz'):
            raise SafeException(
                _("This package looks like a xz-compressed package, but you don't have the 'unxz' command "
                  "I need to extract it. Install the package containing it (it's probably called 'xz-utils') "
                  "first."))
    elif mime_type in ('application/x-compressed-tar', 'application/x-tar',
                       'application/x-ruby-gem'):
        pass
    else:
        from zeroinstall import version
        raise SafeException(
            _("Unsupported archive type '%(type)s' (for injector version %(version)s)"
              ) % {
                  'type': mime_type,
                  'version': version
              })
コード例 #20
0
ファイル: __init__.py プロジェクト: rammstein/0install
    def _add_with_helper(self, required_digest, path, dry_run):
        """Use 0store-secure-add to copy 'path' to the system store.
		@param required_digest: the digest for path
		@type required_digest: str
		@param path: root of implementation directory structure
		@type path: str
		@return: True iff the directory was copied into the system cache successfully"""
        if required_digest.startswith('sha1='):
            return False  # Old digest alg not supported
        if os.environ.get('ZEROINSTALL_PORTABLE_BASE'):
            return False  # Can't use helper with portable mode
        helper = support.find_in_path('0store-secure-add-helper')
        if not helper:
            logger.info(
                _("'0store-secure-add-helper' command not found. Not adding to system cache."
                  ))
            return False
        if dry_run:
            print(
                _("[dry-run] would use {helper} to store {required_digest} in system store"
                  ).format(helper=helper, required_digest=required_digest))
            self.dry_run_names.add(required_digest)
            return True
        import subprocess
        env = os.environ.copy()
        env['ENV_NOT_CLEARED'] = 'Unclean'  # (warn about insecure configurations)
        env['HOME'] = 'Unclean'  # (warn about insecure configurations)
        dev_null = os.open(os.devnull, os.O_RDONLY)
        try:
            logger.info(_("Trying to add to system cache using %s"), helper)
            child = subprocess.Popen([helper, required_digest],
                                     stdin=dev_null,
                                     cwd=path,
                                     env=env)
            exit_code = child.wait()
        finally:
            os.close(dev_null)

        if exit_code:
            logger.warning(_("0store-secure-add-helper failed."))
            return False

        logger.info(_("Added succcessfully."))
        return True
コード例 #21
0
	def action_run(self, uri):
		iface = self.iface_cache.get_interface(uri)
		reader.update_from_cache(iface)
		if len(iface.get_metadata(namespaces.XMLNS_IFACE, 'needs-terminal')):
			for terminal in ['xterm', 'gnome-terminal', 'rxvt', 'konsole']:
				exe = support.find_in_path(terminal)
				if exe:
					if terminal == 'gnome-terminal':
						flag = '-x'
					else:
						flag = '-e'
					subprocess.Popen([terminal, flag, '0launch', '--', uri])
					break
			else:
				box = gtk.MessageDialog(self.window, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, _("Can't find a suitable terminal emulator"))
				box.run()
				box.destroy()
		else:
			subprocess.Popen(['0launch', '--', uri])
コード例 #22
0
ファイル: __init__.py プロジェクト: dsqmoore/0install
	def _add_with_helper(self, required_digest, path, dry_run):
		"""Use 0store-secure-add to copy 'path' to the system store.
		@param required_digest: the digest for path
		@type required_digest: str
		@param path: root of implementation directory structure
		@type path: str
		@return: True iff the directory was copied into the system cache successfully
		"""
		if required_digest.startswith('sha1='):
			return False		# Old digest alg not supported
		if os.environ.get('ZEROINSTALL_PORTABLE_BASE'):
			return False		# Can't use helper with portable mode
		helper = support.find_in_path('0store-secure-add-helper')
		if not helper:
			logger.info(_("'0store-secure-add-helper' command not found. Not adding to system cache."))
			return False
		if dry_run:
			print(_("[dry-run] would use {helper} to store {required_digest} in system store").format(
				helper = helper,
				required_digest = required_digest))
			self.dry_run_names.add(required_digest)
			return True
		import subprocess
		env = os.environ.copy()
		env['ENV_NOT_CLEARED'] = 'Unclean'	# (warn about insecure configurations)
		env['HOME'] = 'Unclean'			# (warn about insecure configurations)
		dev_null = os.open(os.devnull, os.O_RDONLY)
		try:
			logger.info(_("Trying to add to system cache using %s"), helper)
			child = subprocess.Popen([helper, required_digest],
						 stdin = dev_null,
						 cwd = path,
						 env = env)
			exit_code = child.wait()
		finally:
			os.close(dev_null)

		if exit_code:
			logger.warning(_("0store-secure-add-helper failed."))
			return False

		logger.info(_("Added succcessfully."))
		return True
コード例 #23
0
	def action_run(self, uri):
		iface = self.iface_cache.get_interface(uri)
		reader.update_from_cache(iface)
		if len(iface.get_metadata(namespaces.XMLNS_IFACE, 'needs-terminal')):
			for terminal in ['xterm', 'gnome-terminal', 'rxvt', 'konsole']:
				exe = support.find_in_path(terminal)
				if exe:
					if terminal == 'gnome-terminal':
						flag = '-x'
					else:
						flag = '-e'
					subprocess.Popen([terminal, flag, '0launch', '--', uri])
					break
			else:
				box = gtk.MessageDialog(self.window, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, _("Can't find a suitable terminal emulator"))
				box.run()
				box.destroy()
		else:
			subprocess.Popen(['0launch', '--', uri])
コード例 #24
0
ファイル: support.py プロジェクト: talex5/0compile
def spawn_maybe_sandboxed(readable, writable, tmpdir, prog, args):
	"""spawn prog, with (only) the 'writable' directories writable if sandboxing is available.
	The readable directories will be readable, as well as various standard locations.
	If no sandbox is available, run without a sandbox."""

	USE_PLASH = 'USE_PLASH_0COMPILE'

	assert os.path.isabs(prog)
	_pola_run = find_in_path('pola-run')

	if _pola_run is None:
		#print "Not using sandbox (plash not installed)"
		use_plash = False
	else:
		use_plash = os.environ.get(USE_PLASH, '').lower() or 'not set'
		if use_plash in ('not set', 'false'):
			print "Not using plash: $%s is %s" % (USE_PLASH, use_plash)
			use_plash = False
		elif use_plash == 'true':
			use_plash = True
		else:
			raise Exception('$%s must be "true" or "false", not "%s"' % (USE_PLASH, use_plash))

	if not use_plash:
		return subprocess.Popen([prog] + args)
	
	print "Using plash to sandbox the build..."
	
	# We have pola-shell :-)
	pola_args = ['--prog', prog, '-B']
	for a in args:
		pola_args += ['-a', a]
	for r in readable:
		pola_args += ['-f', r]
	for w in writable:
		pola_args += ['-fw', w]
	pola_args += ['-tw', '/tmp', tmpdir]
	os.environ['TMPDIR'] = '/tmp'
	return subprocess.Popen([_pola_run] + pola_args)
コード例 #25
0
ファイル: support.py プロジェクト: dabrahams/0compile
def spawn_maybe_sandboxed(readable, writable, tmpdir, prog, args):
	"""spawn prog, with (only) the 'writable' directories writable if sandboxing is available.
	The readable directories will be readable, as well as various standard locations.
	If no sandbox is available, run without a sandbox."""

	USE_PLASH = 'USE_PLASH_0COMPILE'

	assert os.path.isabs(prog)
	_pola_run = find_in_path('pola-run')

	if _pola_run is None:
		#print "Not using sandbox (plash not installed)"
		use_plash = False
	else:
		use_plash = os.environ.get(USE_PLASH, '').lower() or 'not set'
		if use_plash in ('not set', 'false'):
			print "Not using plash: $%s is %s" % (USE_PLASH, use_plash)
			use_plash = False
		elif use_plash == 'true':
			use_plash = True
		else:
			raise Exception('$%s must be "true" or "false", not "%s"' % (USE_PLASH, use_plash))

	if not use_plash:
		return subprocess.Popen([prog] + args)
	
	print "Using plash to sandbox the build..."
	
	# We have pola-shell :-)
	pola_args = ['--prog', prog, '-B']
	for a in args:
		pola_args += ['-a', a]
	for r in readable:
		pola_args += ['-f', r]
	for w in writable:
		pola_args += ['-fw', w]
	pola_args += ['-tw', '/tmp', tmpdir]
	os.environ['TMPDIR'] = '/tmp'
	return subprocess.Popen([_pola_run] + pola_args)
コード例 #26
0
def canonical_iface_uri(uri):
	"""If uri is a relative path, convert to an absolute one.
	A "file:///foo" URI is converted to "/foo".
	An "alias:prog" URI expands to the URI in the 0alias script
	Otherwise, return it unmodified.
	@rtype: str
	@raise SafeException: if uri isn't valid
	"""
	if uri.startswith('http://') or uri.startswith('https://'):
		if uri.count("/") < 3:
			raise SafeException(_("Missing / after hostname in URI '%s'") % uri)
		return uri
	elif uri.startswith('file:///'):
		path = uri[7:]
	elif uri.startswith('file:'):
		if uri[5] == '/':
			raise SafeException(_('Use file:///path for absolute paths, not {uri}').format(uri = uri))
		path = os.path.abspath(uri[5:])
	elif uri.startswith('alias:'):
		from zeroinstall import alias, support
		alias_prog = uri[6:]
		if not os.path.isabs(alias_prog):
			full_path = support.find_in_path(alias_prog)
			if not full_path:
				raise alias.NotAnAliasScript("Not found in $PATH: " + alias_prog)
		else:
			full_path = alias_prog
		return alias.parse_script(full_path).uri
	else:
		path = os.path.realpath(uri)

	# Might be local sweet directory
	if os.path.exists(path):
		return path
	raise SafeException(_("Bad interface name '%(uri)s'.\n"
			"(doesn't start with 'http:', and "
			"doesn't exist as a local file '%(interface_uri)s' either)") %
			{'uri': uri, 'interface_uri': path})
コード例 #27
0
ファイル: unpack.py プロジェクト: linuxmidhun/0install
def check_type_ok(mime_type):
	"""Check we have the needed software to extract from an archive of the given type.
	@type mime_type: str
	@raise SafeException: if the needed software is not available"""
	assert mime_type
	if mime_type == 'application/x-rpm':
		if not find_in_path('rpm2cpio'):
			raise SafeException(_("This package looks like an RPM, but you don't have the rpm2cpio command "
					"I need to extract it. Install the 'rpm' package first (this works even if "
					"you're on a non-RPM-based distribution such as Debian)."))
	elif mime_type == 'application/x-deb':
		if not find_in_path('ar'):
			raise SafeException(_("This package looks like a Debian package, but you don't have the 'ar' command "
					"I need to extract it. Install the package containing it (sometimes called 'binutils') "
					"first. This works even if you're on a non-Debian-based distribution such as Red Hat)."))
	elif mime_type == 'application/x-bzip-compressed-tar':
		pass	# We'll fall back to Python's built-in tar.bz2 support
	elif mime_type == 'application/zip':
		if not find_in_path('unzip'):
			raise SafeException(_("This package looks like a zip-compressed archive, but you don't have the 'unzip' command "
					"I need to extract it. Install the package containing it first."))
	elif mime_type == 'application/vnd.ms-cab-compressed':
		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':
		if not find_in_path('unxz'):
			raise SafeException(_("This package looks like a xz-compressed package, but you don't have the 'unxz' command "
					"I need to extract it. Install the package containing it (it's probably called 'xz-utils') "
					"first."))
	elif mime_type in ('application/x-compressed-tar', 'application/x-tar', 'application/x-ruby-gem'):
		pass
	else:
		from zeroinstall import version
		raise SafeException(_("Unsupported archive type '%(type)s' (for injector version %(version)s)") % {'type': mime_type, 'version': version})
コード例 #28
0
ファイル: utils.py プロジェクト: res2k/0export
def get_gpg():
	return find_in_path('gpg') or find_in_path('gpg2')
コード例 #29
0
ファイル: unpack.py プロジェクト: dabrahams/0install
def extract_tar(stream, destdir, extract, decompress, start_offset = 0):
	if extract:
		# Limit the characters we accept, to avoid sending dodgy
		# strings to tar
		if not re.match('^[a-zA-Z0-9][- _a-zA-Z0-9.]*$', extract):
			raise SafeException(_('Illegal character in extract attribute'))

	assert decompress in [None, 'bzip2', 'gzip', 'lzma', 'xz']

	if _gnu_tar():
		ext_cmd = ['tar']
		if decompress:
			if decompress == 'bzip2':
				ext_cmd.append('--bzip2')
			elif decompress == 'gzip':
				ext_cmd.append('-z')
			elif decompress == 'lzma':
				unlzma = find_in_path('unlzma')
				if not unlzma:
					unlzma = os.path.abspath(os.path.join(os.path.dirname(__file__), '_unlzma'))
				ext_cmd.append('--use-compress-program=' + unlzma)
			elif decompress == 'xz':
				unxz = find_in_path('unxz')
				if not unxz:
					unxz = os.path.abspath(os.path.join(os.path.dirname(__file__), '_unxz'))
				ext_cmd.append('--use-compress-program=' + unxz)

		if recent_gnu_tar():
			ext_cmd.extend(('-x', '--no-same-owner', '--no-same-permissions'))
		else:
			ext_cmd.extend(('xf', '-'))

		if extract:
			ext_cmd.append(extract)

		_extract(stream, destdir, ext_cmd, start_offset)
	else:
		import tempfile

		# Since we don't have GNU tar, use python's tarfile module. This will probably
		# be a lot slower and we do not support lzma and xz; however, it is portable.
		# (lzma and xz are handled by first uncompressing stream to a temporary file.
		# this is simple to do, but less efficient than piping through the program)
		if decompress is None:
			rmode = 'r|'
		elif decompress == 'bzip2':
			rmode = 'r|bz2'
		elif decompress == 'gzip':
			rmode = 'r|gz'
		elif decompress == 'lzma':
			unlzma = find_in_path('unlzma')
			if not unlzma:
				unlzma = os.path.abspath(os.path.join(os.path.dirname(__file__), '_unlzma'))
			temp = tempfile.NamedTemporaryFile(suffix='.tar', mode='w+b')
			subprocess.check_call((unlzma), stdin=stream, stdout=temp)
			rmode = 'r|'
			stream = temp
		elif decompress == 'xz':
			unxz = find_in_path('unxz')
			if not unxz:
				unxz = os.path.abspath(os.path.join(os.path.dirname(__file__), '_unxz'))
			temp = tempfile.NamedTemporaryFile(suffix='.tar', mode='w+b')
			subprocess.check_call((unxz), stdin=stream, stdout=temp)
			rmode = 'r|'
			stream = temp
		else:
			raise SafeException(_('GNU tar unavailable; unsupported compression format: %s') % decompress)

		import tarfile

		stream.seek(start_offset)
		# Python 2.5.1 crashes if name is None; see Python bug #1706850
		tar = tarfile.open(name = '', mode = rmode, fileobj = stream)

		current_umask = os.umask(0)
		os.umask(current_umask)

		uid = gid = None
		try:
			uid = os.geteuid()
			gid = os.getegid()
		except:
			logger.debug(_("Can't get uid/gid"))

		def chmod_extract(tarinfo):
			# If any X bit is set, they all must be
			if tarinfo.mode & 0o111:
				tarinfo.mode |= 0o111

			# Everyone gets read and write (subject to the umask)
			# No special bits are allowed.
			tarinfo.mode = ((tarinfo.mode | 0o666) & ~current_umask) & 0o777

			# Don't change owner, even if run as root
			if uid:
				tarinfo.uid = uid
			if gid:
				tarinfo.gid = gid
			tar.extract(tarinfo, destdir)

		extracted_anything = False
		ext_dirs = []

		for tarinfo in tar:
			if extract is None or \
			   tarinfo.name.startswith(extract + '/') or \
			   tarinfo.name == extract:
				if tarinfo.isdir():
					ext_dirs.append(tarinfo)

				chmod_extract(tarinfo)
				extracted_anything = True

		# Due to a bug in tarfile (python versions < 2.5), we have to manually
		# set the mtime of each directory that we extract after extracting everything.

		for tarinfo in ext_dirs:
			dirname = os.path.join(destdir, tarinfo.name)
			os.utime(dirname, (tarinfo.mtime, tarinfo.mtime))

		tar.close()

		if extract and not extracted_anything:
			raise SafeException(_('Unable to find specified file = %s in archive') % extract)
コード例 #30
0
def extract_tar(stream, destdir, extract, decompress, start_offset=0):
    if extract:
        # Limit the characters we accept, to avoid sending dodgy
        # strings to tar
        if not re.match('^[a-zA-Z0-9][- _a-zA-Z0-9.]*$', extract):
            raise SafeException(_('Illegal character in extract attribute'))

    assert decompress in [None, 'bzip2', 'gzip', 'lzma', 'xz']

    if _gnu_tar():
        ext_cmd = ['tar']
        if decompress:
            if decompress == 'bzip2':
                ext_cmd.append('--bzip2')
            elif decompress == 'gzip':
                ext_cmd.append('-z')
            elif decompress == 'lzma':
                unlzma = find_in_path('unlzma')
                if not unlzma:
                    unlzma = os.path.abspath(
                        os.path.join(os.path.dirname(__file__), '_unlzma'))
                ext_cmd.append('--use-compress-program=' + unlzma)
            elif decompress == 'xz':
                ext_cmd.append('--use-compress-program=unxz')

        if recent_gnu_tar():
            ext_cmd.extend(('-x', '--no-same-owner', '--no-same-permissions'))
        else:
            ext_cmd.extend(('xf', '-'))

        if extract:
            ext_cmd.append(extract)

        _extract(stream, destdir, ext_cmd, start_offset)
    else:
        # Since we don't have GNU tar, use python's tarfile module. This will probably
        # be a lot slower and we do not support lzma and xz; however, it is portable.
        if decompress is None:
            rmode = 'r|'
        elif decompress == 'bzip2':
            rmode = 'r|bz2'
        elif decompress == 'gzip':
            rmode = 'r|gz'
        else:
            raise SafeException(
                _('GNU tar unavailable; unsupported compression format: %s') %
                decompress)

        import tarfile

        stream.seek(start_offset)
        # Python 2.5.1 crashes if name is None; see Python bug #1706850
        tar = tarfile.open(name='', mode=rmode, fileobj=stream)

        current_umask = os.umask(0)
        os.umask(current_umask)

        uid = gid = None
        try:
            uid = os.geteuid()
            gid = os.getegid()
        except:
            debug(_("Can't get uid/gid"))

        def chmod_extract(tarinfo):
            # If any X bit is set, they all must be
            if tarinfo.mode & 0111:
                tarinfo.mode |= 0111

            # Everyone gets read and write (subject to the umask)
            # No special bits are allowed.
            tarinfo.mode = ((tarinfo.mode | 0666) & ~current_umask) & 0777

            # Don't change owner, even if run as root
            if uid:
                tarinfo.uid = uid
            if gid:
                tarinfo.gid = gid
            tar.extract(tarinfo, destdir)

        extracted_anything = False
        ext_dirs = []

        for tarinfo in tar:
            if extract is None or \
               tarinfo.name.startswith(extract + '/') or \
               tarinfo.name == extract:
                if tarinfo.isdir():
                    ext_dirs.append(tarinfo)

                chmod_extract(tarinfo)
                extracted_anything = True

        # Due to a bug in tarfile (python versions < 2.5), we have to manually
        # set the mtime of each directory that we extract after extracting everything.

        for tarinfo in ext_dirs:
            dirname = os.path.join(destdir, tarinfo.name)
            os.utime(dirname, (tarinfo.mtime, tarinfo.mtime))

        tar.close()

        if extract and not extracted_anything:
            raise SafeException(
                _('Unable to find specified file = %s in archive') % extract)
コード例 #31
0
ファイル: testunpack.py プロジェクト: rammstein/0install
class AbstractTestUnpack():
    def setUp(self):
        BaseTest.setUp(self)

        self.tmpdir = tempfile.mkdtemp('-testunpack')

        os.umask(0o022)

    def tearDown(self):
        BaseTest.tearDown(self)

        support.ro_rmtree(self.tmpdir)

        assert os.umask(0o022) == 0o022

    def testBadExt(self):
        try:
            with open('HelloWorld.tgz', 'rb') as stream:
                unpack.unpack_archive('ftp://foo/file.foo', stream,
                                      self.tmpdir)
            assert False
        except SafeException as ex:
            assert 'Unknown extension' in str(ex)

    def testTgz(self):
        with open('HelloWorld.tgz', 'rb') as stream:
            unpack.unpack_archive('ftp://foo/file.tgz', stream, self.tmpdir)
        self.assert_manifest('sha1=3ce644dc725f1d21cfcf02562c76f375944b266a')

    @skipIf(sys.getfilesystemencoding().lower() != "utf-8",
            "tar only unpacks to utf-8")
    def testNonAsciiTgz(self):
        with open('unicode.tar.gz', 'rb') as stream:
            unpack.unpack_archive('ftp://foo/file.tgz', stream, self.tmpdir)
        self.assert_manifest(
            'sha1new=e42ffed02179169ef2fa14a46b0d9aea96a60c10')

    @skipIf(not find_in_path('hdiutil'), "not running on MacOS X; no hdiutil")
    def testDmg(self):
        with open('HelloWorld.dmg', 'rb') as stream:
            unpack.unpack_archive('ftp://foo/file.dmg', stream, self.tmpdir)
        self.assert_manifest('sha1=3ce644dc725f1d21cfcf02562c76f375944b266a')

    def testZip(self):
        with open('HelloWorld.zip', 'rb') as stream:
            unpack.unpack_archive('ftp://foo/file.zip', stream, self.tmpdir)
        self.assert_manifest('sha1=3ce644dc725f1d21cfcf02562c76f375944b266a')

    def testExtract(self):
        with open('HelloWorld.tgz', 'rb') as stream:
            unpack.unpack_archive('ftp://foo/file.tgz',
                                  stream,
                                  self.tmpdir,
                                  extract='HelloWorld')
        self.assert_manifest('sha1=3ce644dc725f1d21cfcf02562c76f375944b266a')

    @skipIf(sys.getfilesystemencoding().lower() != "utf-8",
            "tar only unpacks to utf-8")
    def testExtractNonAscii(self):
        with open('unicode.tar.gz', 'rb') as stream:
            unpack.unpack_archive('ftp://foo/file.tgz',
                                  stream,
                                  self.tmpdir,
                                  extract=b'unicode'.decode('ascii'))
        self.assert_manifest('sha1=af2d132f5f15532bbf041b59414d08c8bc1a616e')

    def testExtractOver(self):
        with open('HelloWorld.tgz', 'rb') as stream:
            unpack.unpack_archive_over('ftp://foo/file.tgz',
                                       stream,
                                       self.tmpdir,
                                       extract='HelloWorld')
        self.assert_manifest('sha1=491678c37f77fadafbaae66b13d48d237773a68f')

    def testExtractZip(self):
        with open('HelloWorld.zip', 'rb') as stream:
            unpack.unpack_archive('ftp://foo/file.zip',
                                  stream,
                                  self.tmpdir,
                                  extract='HelloWorld')
        self.assert_manifest('sha1=3ce644dc725f1d21cfcf02562c76f375944b266a')

    def testExtractIllegal(self):
        try:
            with open('HelloWorld.tgz', 'rb') as stream:
                unpack.unpack_archive('ftp://foo/file.tgz',
                                      stream,
                                      self.tmpdir,
                                      extract='Hello`World`')
            assert False
        except SafeException as ex:
            assert 'Illegal' in str(ex)

    def testExtractFails(self):
        stderr = os.dup(2)
        try:
            null = os.open(os.devnull, os.O_WRONLY)
            os.close(2)
            os.dup2(null, 2)
            try:
                with open('HelloWorld.tgz', 'rb') as stream:
                    unpack.unpack_archive('ftp://foo/file.tgz',
                                          stream,
                                          self.tmpdir,
                                          extract='HelloWorld2')
                assert False
            except SafeException as ex:
                if ('Failed to extract' not in str(ex) and  # GNU tar
                        'Unable to find' not in str(ex)):  # Python tar
                    raise ex
        finally:
            os.dup2(stderr, 2)

    def testTargz(self):
        with open('HelloWorld.tgz', 'rb') as stream:
            unpack.unpack_archive('ftp://foo/file.tar.GZ', stream, self.tmpdir)
        self.assert_manifest('sha1=3ce644dc725f1d21cfcf02562c76f375944b266a')

    def testTbz(self):
        with open('HelloWorld.tar.bz2', 'rb') as stream:
            unpack.unpack_archive('ftp://foo/file.tar.bz2', stream,
                                  self.tmpdir)
        self.assert_manifest('sha1=3ce644dc725f1d21cfcf02562c76f375944b266a')

    def testTar(self):
        with open('HelloWorld.tar', 'rb') as stream:
            unpack.unpack_archive('ftp://foo/file.tar', stream, self.tmpdir)
        self.assert_manifest(
            'sha1new=290eb133e146635fe37713fd58174324a16d595f')

    @skipIf(not find_in_path('rpm2cpio'), "not running; no rpm2cpio")
    def testRPM(self):
        with open('dummy-1-1.noarch.rpm', 'rb') as stream:
            unpack.unpack_archive('ftp://foo/file.rpm', stream, self.tmpdir)
        self.assert_manifest('sha1=7be9228c8fe2a1434d4d448c4cf130e3c8a4f53d')

    def testDeb(self):
        with open('dummy_1-1_all.deb', 'rb') as stream:
            unpack.unpack_archive('ftp://foo/file.deb', stream, self.tmpdir)
        self.assert_manifest(
            'sha1new=2c725156ec3832b7980a3de2270b3d8d85d4e3ea')

    def testGem(self):
        with open('hello-0.1.gem', 'rb') as stream:
            unpack.unpack_archive('ftp://foo/file.gem', stream, self.tmpdir)
        self.assert_manifest(
            'sha1new=fbd4827be7a18f9821790bdfd83132ee60d54647')

    def testSpecial(self):
        os.chmod(self.tmpdir, 0o2755)
        store = Store(self.tmpdir)
        with open('HelloWorld.tgz', 'rb') as stream:
            store.add_archive_to_cache(
                'sha1=3ce644dc725f1d21cfcf02562c76f375944b266a', stream,
                'http://foo/foo.tgz')

    def testBad(self):
        logging.getLogger('').setLevel(logging.ERROR)

        store = Store(self.tmpdir)
        try:
            with open('HelloWorld.tgz', 'rb') as stream:
                store.add_archive_to_cache(
                    'sha1=3ce644dc725f1d21cfcf02562c76f375944b266b', stream,
                    'http://foo/foo.tgz')
            assert 0
        except BadDigest:
            pass

        logging.getLogger('').setLevel(logging.INFO)

    def assert_manifest(self, required):
        alg_name = required.split('=', 1)[0]
        manifest.fixup_permissions(self.tmpdir)

        sha1 = alg_name + '=' + manifest.add_manifest_file(
            self.tmpdir, manifest.get_algorithm(alg_name)).hexdigest()
        self.assertEqual(sha1, required)

        # Check permissions are sensible
        for root, dirs, files in os.walk(self.tmpdir):
            for f in files + dirs:
                full = os.path.join(root, f)
                if os.path.islink(full): continue
                full_mode = os.stat(full).st_mode
                self.assertEqual(0o444, full_mode & 0o666)  # Must be r-?r-?r-?
コード例 #32
0
        support.ro_rmtree(self.tmpdir)

        assert os.umask(0022) == 0022

    def testBadExt(self):
        try:
            unpack.unpack_archive("ftp://foo/file.foo", file("HelloWorld.tgz"), self.tmpdir)
            assert False
        except SafeException, ex:
            assert "Unknown extension" in str(ex)

    def testTgz(self):
        unpack.unpack_archive("ftp://foo/file.tgz", file("HelloWorld.tgz"), self.tmpdir)
        self.assert_manifest("sha1=3ce644dc725f1d21cfcf02562c76f375944b266a")

    @skipIf(not find_in_path("hdiutil"), "not running on MacOS X; no hdiutil")
    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")

    def testExtract(self):
        unpack.unpack_archive("ftp://foo/file.tgz", file("HelloWorld.tgz"), self.tmpdir, extract="HelloWorld")
        self.assert_manifest("sha1=3ce644dc725f1d21cfcf02562c76f375944b266a")

    def testExtractOver(self):
        unpack.unpack_archive_over("ftp://foo/file.tgz", file("HelloWorld.tgz"), self.tmpdir, extract="HelloWorld")
        self.assert_manifest("sha1=491678c37f77fadafbaae66b13d48d237773a68f")