Example #1
0
def get_http_size(url, ttl=1):
    assert url.lower().startswith('http://')

    address = urlparse.urlparse(url)
    http = httplib.HTTPConnection(host(address), port(address) or 80)

    parts = url.split('/', 3)
    if len(parts) == 4:
        path = parts[3]
    else:
        path = ''

    http.request('HEAD', '/' + path, headers={'Host': host(address)})
    response = http.getresponse()
    try:
        if response.status == 200:
            return response.getheader('Content-Length')
        elif response.status in (301, 302):
            new_url_rel = response.getheader('Location') or response.getheader(
                'URI')
            new_url = urlparse.urljoin(url, new_url_rel)
        else:
            raise SafeException("HTTP error: got status code %s" %
                                response.status)
    finally:
        response.close()

    if ttl:
        info("Resource moved! Checking new URL %s" % new_url)
        assert new_url
        return get_http_size(new_url, ttl - 1)
    else:
        raise SafeException('Too many redirections.')
Example #2
0
def generate_public_xml(config, source_xml_path):
	"""Load source_xml_path and expand any relative URLs."""
	try:
		with open(source_xml_path, 'rb') as stream:
			doc = minidom.parse(stream)
	except:
		print("Failed to process %s" % (source_xml_path))
		raise

	root = doc.documentElement
	declared_iface = root.getAttribute('uri')
	if not declared_iface:
		raise SafeException("Feed '{path}' missing 'uri' attribute on root".format(path = source_xml_path))

	if not declared_iface.startswith(config.REPOSITORY_BASE_URL):
		raise SafeException("Feed '{path}' declares uri='{uri}', which is not under REPOSITORY_BASE_URL ({base})".format(
			path = source_xml_path,
			uri = declared_iface,
			base = config.REPOSITORY_BASE_URL))
	rel_uri = declared_iface[len(config.REPOSITORY_BASE_URL):]

	expected_path = join('feeds', config.get_feeds_rel_path(rel_uri))
	if expected_path != source_xml_path:
		raise SafeException("Feed '{path}' with uri='{uri}' should be located at '{expected_path}'".format(
			path = source_xml_path,
			uri = declared_iface,
			expected_path = expected_path))

	expand_relative_urls(config, root)

	return doc
Example #3
0
def handle(config, options, args):
    if len(args) == 0:
        if options.gui is None and os.environ.get('DISPLAY', None):
            options.gui = True
        if options.gui:
            from zeroinstall import helpers
            return helpers.get_selections_gui(None, [])
        else:
            for key, setting_type in settings.iteritems():
                value = getattr(config, key)
                print(key, "=", setting_type.format(value))
        return
    elif len(args) > 2:
        raise UsageError()

    option = args[0]
    if option not in settings:
        raise SafeException(_('Unknown option "%s"') % option)

    if len(args) == 1:
        value = getattr(config, option)
        print(settings[option].format(value))
    else:
        value = settings[option].parse(args[1])
        if option == 'network_use' and value not in model.network_levels:
            raise SafeException(
                _("Must be one of %s") % list(model.network_levels))
        setattr(config, option, value)

        config.save_globals()
Example #4
0
def spawn_and_check_maybe_sandboxed(readable, writable, tmpdir, prog, args):
	child = spawn_maybe_sandboxed(readable, writable, tmpdir, prog, args)
	status = child.wait()
	if status > 0:
		raise SafeException('Command failed with exit status %d' %  status)
	elif status < 0:
		raise SafeException('Command failed with signal %d' % -status)
Example #5
0
def parse_version(version_string):
    """Convert a version string to an internal representation.
	The parsed format can be compared quickly using the standard Python functions.
	 - Version := DottedList ("-" Mod DottedList?)*
	 - DottedList := (Integer ("." Integer)*)
	@rtype: tuple (opaque)
	@raise SafeException: if the string isn't a valid version
	@since: 0.24 (moved from L{reader}, from where it is still available):"""
    if version_string is None: return None
    parts = _version_re.split(version_string)
    if parts[-1] == '':
        del parts[-1]  # Ends with a modifier
    else:
        parts.append('')
    if not parts:
        raise SafeException(_("Empty version string!"))
    l = len(parts)
    try:
        for x in range(0, l, 2):
            part = parts[x]
            if part:
                parts[x] = map(int, parts[x].split('.'))
            else:
                parts[x] = []  # (because ''.split('.') == [''], not [])
        for x in range(1, l, 2):
            parts[x] = _version_mod_to_value[parts[x]]
        return parts
    except ValueError, ex:
        raise SafeException(
            _("Invalid version format in '%(version_string)s': %(exception)s")
            % {
                'version_string': version_string,
                'exception': ex
            })
Example #6
0
def pick_digest(impl):
    from zeroinstall.zerostore import manifest, parse_algorithm_digest_pair
    best = None
    for digest in impl.digests:
        alg_name, digest_value = parse_algorithm_digest_pair(digest)
        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()
            })

    return required_digest
Example #7
0
def handle(config, options, args):
	if len(args) == 0:
		from zeroinstall import helpers
		if helpers.get_selections_gui(None, [], use_gui = options.gui) == helpers.DontUseGUI:
			for key, setting_type in settings.items():
				value = getattr(config, key)
				print(key, "=", setting_type.format(value))
		# (else we displayed the preferences dialog in the GUI)
		return
	elif len(args) > 2:
		raise UsageError()

	option = args[0]
	if option not in settings:
		raise SafeException(_('Unknown option "%s"') % option)

	if len(args) == 1:
		value = getattr(config, option)
		print(settings[option].format(value))
	else:
		value = settings[option].parse(args[1])
		if option == 'network_use' and value not in model.network_levels:
			raise SafeException(_("Must be one of %s") % list(model.network_levels))
		setattr(config, option, value)

		config.save_globals()
Example #8
0
def do_diff(args):
    """diff"""
    if args:
        raise __main__.UsageError()
    buildenv = BuildEnv()

    if not os.path.isdir('src'):
        raise SafeException('No local src directory to diff against!')
    new_src = os.path.realpath('src')

    src_impl = buildenv.chosen_impl(buildenv.interface)
    assert src_impl

    prog = find_in_path('diff')
    args = ['-ur', lookup(src_impl), new_src]

    status = os.spawnv(os.P_WAIT, prog, [prog] + args)
    if status == 0:
        return False
    elif status == 1:
        return True
    elif status > 1:
        raise SafeException("Program '%s' failed with exit code %d" %
                            (prog, status))
    elif status < 0:
        raise SafeException("Program '%s' failed with signal %d" %
                            (prog, -status))
Example #9
0
def lookup(uri, missing_ok=False):
    """Search repositories.json for the repository which hosts 'uri'."""
    path = basedir.load_first_config('0install.net', '0repo',
                                     'repositories.json')
    if path:
        with open(path, 'rb') as stream:
            db = json.load(stream)
    else:
        db = {}

    from_registry = None
    for key, value in db.items():
        if uri.startswith(key):
            if from_registry:
                raise SafeException(
                    "Multiple matching repositories! {a} and {b}".format(
                        a=from_registry, b=value))
            from_registry = value

    if not from_registry:
        if missing_ok:
            return None
        else:
            raise SafeException(
                "No registered repository for {uri} (hint: use '0repo register')"
                .format(uri=uri))

    return from_registry
Example #10
0
    def _handle_restrictions(self, options):
        """Gets the list of restrictions specified by the user.
		Handles --before, --not-before, --version and --version-for options.
		If a mapping isn't present, then the user didn't specify a restriction.
		If an entry maps to None, the user wishes to remove the restriction."""
        version = options.version

        interface_uri = self.interface_uri

        # Convert old --before and --not_before to new --version-for
        if options.before is not None or options.not_before is not None:
            if version is not None:
                raise SafeException(
                    "Can't use --before or --not-before with --version")
            if options.before or options.not_before:
                version = (options.not_before or '') + '..'
                if options.before:
                    version += '!' + options.before
            else:
                version = ''  # Reset

        restrictions = dict((uri, (expr or None))
                            for (uri, expr) in (options.version_for or []))

        # Convert the --version short-cut to --version-for
        if version is not None:
            if interface_uri in restrictions:
                raise SafeException(
                    "Can't use --version and --version-for to set {uri}".
                    format(uri=interface_uri))
            restrictions[interface_uri] = version or None

        return restrictions
Example #11
0
def unpack_archive(url, data, destdir, extract = None, type = None, start_offset = 0):
	"""Unpack stream 'data' into directory 'destdir'. If extract is given, extract just
	that sub-directory from the archive (i.e. destdir/extract will exist afterwards).
	Works out the format from the name."""
	if type is None: type = type_from_url(url)
	if type is None: raise SafeException(_("Unknown extension (and no MIME type given) in '%s'") % url)
	if type == 'application/x-bzip-compressed-tar':
		extract_tar(data, destdir, extract, 'bzip2', start_offset)
	elif type == 'application/x-deb':
		extract_deb(data, destdir, extract, start_offset)
	elif type == 'application/x-rpm':
		extract_rpm(data, destdir, extract, start_offset)
	elif type == 'application/zip':
		extract_zip(data, destdir, extract, start_offset)
	elif type == 'application/x-tar':
		extract_tar(data, destdir, extract, None, start_offset)
	elif type == 'application/x-lzma-compressed-tar':
		extract_tar(data, destdir, extract, 'lzma', start_offset)
	elif type == 'application/x-xz-compressed-tar':
		extract_tar(data, destdir, extract, 'xz', start_offset)
	elif type == 'application/x-compressed-tar':
		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)
	elif type == 'application/x-ruby-gem':
		extract_gem(data, destdir, extract, start_offset)
	else:
		raise SafeException(_('Unknown MIME type "%(type)s" for "%(url)s"') % {'type': type, 'url': url})
Example #12
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".
	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:]
    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
          })
Example #13
0
def validate_name(name):
    """@type name: str"""
    if name == '0install':
        raise SafeException(
            "Creating an app called '0install' would cause trouble; try e.g. '00install' instead"
        )
    if valid_name.match(name): return
    raise SafeException("Invalid application name '{name}'".format(name=name))
Example #14
0
def handle(args):
    if args.key == '-':
        key = None
    else:
        # Get the fingerprint from the key ID (and check we have the secret key)
        try:
            keys = subprocess.check_output([
                'gpg', '-q', '--fixed-list-mode', '--fingerprint',
                '--with-colons', '--list-secret-keys', args.key
            ],
                                           encoding='utf-8')
        except subprocess.CalledProcessError as ex:
            raise SafeException("GPG key '{key}' not found ({ex})".format(
                key=args.key, ex=ex))

        in_ssb = False
        fingerprint = None
        for line in keys.split('\n'):
            bits = line.split(':')
            if bits[0] == 'ssb': in_ssb = True
            elif bits[0] == 'sec': in_ssb = False
            elif bits[0] == 'fpr':
                if in_ssb and fingerprint is not None:
                    pass  # Ignore sub-keys (unless we don't have a primary - can that happen?)
                elif fingerprint is None:
                    fingerprint = bits[9]
                else:
                    raise SafeException(
                        "Multiple GPG keys match '{key}':\n{output}".format(
                            key=args.key, output=keys))

        if fingerprint is None:
            raise SafeException(
                "GPG key not found '{key}'".format(key=args.key))
        key = '0x' + fingerprint

    # Create the directory structure
    os.mkdir(args.path)
    os.chdir(args.path)
    os.mkdir('incoming')
    os.mkdir('feeds')
    os.mkdir('public')

    # Write the configuration file, with the GPG key filled in
    with open(join(topdir, 'resources', '0repo-config.py.template'),
              'rt') as stream:
        data = stream.read()
    data = data.replace('"{{GPGKEY}}"', '"' + key + '"' if key else "None")
    with open('0repo-config.py', 'wt') as stream:
        stream.write(data)

    # Initialise the Git repository
    subprocess.check_call(['git', 'init', '-q', 'feeds'])
    scm.commit('feeds', [],
               'Created new repository',
               key,
               extra_options=['--allow-empty'])
Example #15
0
def unpack_archive_over(url,
                        data,
                        destdir,
                        extract=None,
                        type=None,
                        start_offset=0):
    """Like unpack_archive, except that we unpack to a temporary directory first and
	then move things over, checking that we're not following symlinks at each stage.
	Use this when you want to unpack an unarchive into a directory which already has
	stuff in it.
	@since: 0.28"""
    import stat
    tmpdir = mkdtemp(dir=destdir)
    try:
        mtimes = []

        unpack_archive(url, data, tmpdir, extract, type, start_offset)

        stem_len = len(tmpdir)
        for root, dirs, files in os.walk(tmpdir):
            relative_root = root[stem_len + 1:] or '.'
            target_root = os.path.join(destdir, relative_root)
            try:
                info = os.lstat(target_root)
            except OSError, ex:
                if ex.errno != 2:
                    raise  # Some odd error.
                # Doesn't exist. OK.
                os.mkdir(target_root)
            else:
                if stat.S_ISLNK(info.st_mode):
                    raise SafeException(
                        _('Attempt to unpack dir over symlink "%s"!') %
                        relative_root)
                elif not stat.S_ISDIR(info.st_mode):
                    raise SafeException(
                        _('Attempt to unpack dir over non-directory "%s"!') %
                        relative_root)
            mtimes.append(
                (relative_root, os.lstat(os.path.join(tmpdir, root)).st_mtime))

            for s in dirs:  # Symlinks are counted as directories
                src = os.path.join(tmpdir, relative_root, s)
                if os.path.islink(src):
                    files.append(s)

            for f in files:
                src = os.path.join(tmpdir, relative_root, f)
                dest = os.path.join(destdir, relative_root, f)
                if os.path.islink(dest):
                    raise SafeException(
                        _('Attempt to unpack file over symlink "%s"!') %
                        os.path.join(relative_root, f))
                os.rename(src, dest)

        for path, mtime in mtimes[1:]:
            os.utime(os.path.join(destdir, path), (mtime, mtime))
Example #16
0
	def get_selections(self, prompt = False):
		if self._selections:
			assert not prompt
			return self._selections

		selections_file = self.config.get('compile', 'selections')
		if selections_file:
			if prompt:
				raise SafeException("Selections are fixed by %s" % selections_file)
			stream = file(selections_file)
			try:
				self._selections = selections.Selections(qdom.parse(stream))
			finally:
				stream.close()
			from zeroinstall.injector import handler
			from zeroinstall.injector.config import load_config
			if os.isatty(1):
				h = handler.ConsoleHandler()
			else:
				h = handler.Handler()
			config = load_config(h)
			blocker = self._selections.download_missing(config)
			if blocker:
				print "Waiting for selected implementations to be downloaded..."
				h.wait_for_blocker(blocker)
		else:
			command = install_prog + ['download', '--source', '--xml']
			if prompt and '--console' not in install_prog:
				if os.name == 'nt':
					command[0] += '-win'
				command.append('--gui')
			command.append(self.interface)
			child = subprocess.Popen(command, stdout = subprocess.PIPE)
			try:
				self._selections = selections.Selections(qdom.parse(child.stdout))
			finally:
				if child.wait():
					raise SafeException(' '.join(repr(x) for x in command) + " failed (exit code %d)" % child.returncode)

		self.root_impl = self._selections.selections[self.interface]

		self.orig_srcdir = os.path.realpath(lookup(self.root_impl))
		self.user_srcdir = None

		if os.path.isdir('src'):
			self.user_srcdir = os.path.realpath('src')
			if self.user_srcdir == self.orig_srcdir or \
			   self.user_srcdir.startswith(os.path.join(self.orig_srcdir, '')) or \
			   self.orig_srcdir.startswith(os.path.join(self.user_srcdir, '')):
				info("Ignoring 'src' directory because it coincides with %s",
					self.orig_srcdir)
				self.user_srcdir = None

		return self._selections
Example #17
0
def ensure_safe(rel_path):
    """Ensure path is relative and doesn't contain '.', '..' or other hidden components. Also,
	leading '-' is disallowed, as it may be confused with an option."""
    if isabs(rel_path):
        raise SafeException("Path {path} not relative".format(path=rel_path))
    if rel_path.startswith(".") or "/." in rel_path:
        raise SafeException(
            "Path {path} contains a dot-file component".format(path=rel_path))
    if rel_path.startswith("-") or "/-" in rel_path:
        raise SafeException(
            "A component in {path} starts with '-'".format(path=rel_path))
    return rel_path
Example #18
0
def get_feed_dir(feed):
    if '#' in feed:
        raise SafeException("Invalid URL '%s'" % feed)
    scheme, rest = feed.split('://', 1)
    domain, rest = rest.split('/', 1)
    assert scheme in (
        'http', 'https', 'ftp'
    )  # Just to check for mal-formed lines; add more as needed
    for x in [scheme, domain, rest]:
        if not x or x.startswith('.'):
            raise SafeException("Invalid URL '%s'" % feed)
    return os.path.join('feeds', scheme, domain, escape_slashes(rest))
Example #19
0
def get_http_size(url, ttl = 3, method = None):
	address = urllib.parse.urlparse(url)

	if url.lower().startswith('http://'):
		http = httplib.HTTPConnection(address.hostname, address.port or 80)
	elif url.lower().startswith('https://'):
		http = httplib.HTTPSConnection(address.hostname, address.port or 443)
	else:
		assert False, url

	parts = url.split('/', 3)
	if len(parts) == 4:
		path = parts[3]
	else:
		path = ''

	if method is None:
		if address.hostname.endswith('.s3.amazonaws.com'):
			method = 'GET'	# HEAD doesn't work on S3 due to signature mismatch
		else:
			method = 'HEAD'

	http.request(method, '/' + path, headers = {'Host': address.hostname, 'User-agent': '0repo (http://0install.net/0repo.html)'})
	response = http.getresponse()
	try:
		if response.status == 200:
			l = response.getheader('Content-Length')
			if l is None:
				if method == "HEAD":
					print("No Content-Length header returned; requesting whole archive...")
					return get_http_size(url, ttl, method = "GET")
				else:
					return len(response.read())
			else:
				return int(l)
		elif response.status in (301, 302, 303):
			new_url_rel = response.getheader('Location') or response.getheader('URI')
			new_url = urllib.parse.urljoin(url, new_url_rel)
		else:
			raise SafeException("HTTP error: got status code %s for %s" % (response.status, url))
	finally:
		response.close()

	if ttl:
		print("Moved")
		print("Checking new URL {}...".format(new_url), end = '')
		assert new_url
		return get_http_size(new_url, ttl - 1)
	else:
		raise SafeException('Too many redirections.')
Example #20
0
def domain_from_url(url):
	"""Extract the trust domain for a URL.
	@param url: the feed's URL
	@type url: str
	@return: the trust domain
	@rtype: str
	@since: 0.27
	@raise SafeException: the URL can't be parsed"""
	import urlparse
	if os.path.isabs(url):
		raise SafeException(_("Can't get domain from a local path: '%s'") % url)
	domain = urlparse.urlparse(url)[1]
	if domain and domain != '*':
		return domain
	raise SafeException(_("Can't extract domain from URL '%s'") % url)
Example #21
0
    def integrate_shell(self, name):
        # TODO: remember which commands we create
        if not valid_name.match(name):
            raise SafeException(
                "Invalid shell command name '{name}'".format(name=name))
        bin_dir = find_bin_dir()
        launcher = os.path.join(bin_dir, name)
        if os.path.exists(launcher):
            raise SafeException(
                "Command already exists: {path}".format(path=launcher))

        with open(launcher, 'w') as stream:
            stream.write(_command_template.format(app=self.get_name()))
            # Make new script executable
            os.chmod(launcher, 0o111 | os.fstat(stream.fileno()).st_mode)
Example #22
0
	def release_without_0repo(archive_file, new_impls_feed):
		assert options.master_feed_file

		if not options.archive_dir_public_url:
			raise SafeException("Archive directory public URL is not set! Edit configuration and try again.")

		if status.updated_master_feed:
			print "Already added to master feed. Not changing."
		else:
			publish_opts = {}
			if os.path.exists(options.master_feed_file):
				# Check we haven't already released this version
				master = support.load_feed(os.path.realpath(options.master_feed_file))
				existing_releases = [impl for impl in master.implementations.values() if impl.get_version() == status.release_version]
				if len(existing_releases):
					raise SafeException("Master feed %s already contains an implementation with version number %s!" % (options.master_feed_file, status.release_version))

				previous_release = get_previous_release(status.release_version)
				previous_testing_releases = [impl for impl in master.implementations.values() if impl.get_version() == previous_release
													     and impl.upstream_stability == model.stability_levels["testing"]]
				if previous_testing_releases:
					print "The previous release, version %s, is still marked as 'testing'. Set to stable?" % previous_release
					if support.get_choice(['Yes', 'No']) == 'Yes':
						publish_opts['select_version'] = previous_release
						publish_opts['set_stability'] = "stable"

			support.publish(options.master_feed_file, local = new_impls_feed, xmlsign = True, key = options.key, **publish_opts)

			status.updated_master_feed = 'true'
			status.save()

		# Copy files...
		uploads = [os.path.basename(archive_file)]
		for b in compiler.get_binary_feeds():
			binary_feed = support.load_feed(b)
			impl, = binary_feed.implementations.values()
			uploads.append(os.path.basename(impl.download_sources[0].url))

		upload_archives(options, status, uploads)

		feed_base = os.path.dirname(list(local_feed.feed_for)[0])
		feed_files = [options.master_feed_file]
		print "Upload %s into %s" % (', '.join(feed_files), feed_base)
		cmd = options.master_feed_upload_command.strip()
		if cmd:
			support.show_and_run(cmd, feed_files)
		else:
			print "NOTE: No feed upload command set => you'll have to upload them yourself!"
Example #23
0
def get_feeds_rel_path(config, url):
    """Return the relative path under "feeds" where we should store the feed with the given URL.
	@raise SafeException: url is not within this repository, or is otherwise malformed."""

    if not url.startswith(config.REPOSITORY_BASE_URL):
        raise SafeException(
            "Feed URL '{url}' does not start with {base}".format(
                url=url, base=config.REPOSITORY_BASE_URL))

    uri_rel_path = url[len(config.REPOSITORY_BASE_URL):]
    feeds_rel_path = config.get_feeds_rel_path(uri_rel_path)
    if not feeds_rel_path.endswith('.xml'):
        raise SafeException(
            "Feed relative path {path} must end in '.xml'".format(
                path=feeds_rel_path))
    return ensure_safe(feeds_rel_path)
Example #24
0
def add_manifest_file(dir, digest_or_alg):
    """Writes a .manifest file into 'dir', and returns the digest.
	You should call fixup_permissions before this to ensure that the permissions are correct.
	On exit, dir itself has mode 555. Subdirectories are not changed.
	@param dir: root of the implementation
	@param digest_or_alg: should be an instance of Algorithm. Passing a digest
	here is deprecated."""
    mfile = os.path.join(dir, '.manifest')
    if os.path.islink(mfile) or os.path.exists(mfile):
        raise SafeException(
            _("Directory '%s' already contains a .manifest file!") % dir)
    manifest = ''
    if isinstance(digest_or_alg, Algorithm):
        alg = digest_or_alg
        digest = alg.new_digest()
    else:
        digest = digest_or_alg
        alg = get_algorithm('sha1')
    for line in alg.generate_manifest(dir):
        manifest += line + '\n'
    digest.update(manifest)

    os.chmod(dir, 0o755)
    stream = open(mfile, 'wb')
    os.chmod(dir, 0o555)
    stream.write(manifest)
    stream.close()
    os.chmod(mfile, 0o444)
    return digest
Example #25
0
def add_to_menu(iface, icon_path, category, zlaunch=None):
    """Write a .desktop file for this application.
	@param iface: the program being added
	@param icon_path: the path of the icon, or None
	@param category: the freedesktop.org menu category"""
    tmpdir = tempfile.mkdtemp(prefix='zero2desktop-')
    try:
        desktop_name = os.path.join(
            tmpdir, 'zeroinstall-%s.desktop' %
            iface.get_name().lower().replace(os.sep, '-').replace(' ', ''))
        desktop = open(desktop_name, 'w')
        desktop.write(
            _template % {
                'name': iface.get_name(),
                'comment': iface.summary,
                '0launch': zlaunch or '0launch',
                'iface': iface.uri,
                'category': category
            })
        if icon_path:
            desktop.write(_icon_template % icon_path)
        if len(iface.get_metadata(namespaces.XMLNS_IFACE, 'needs-terminal')):
            desktop.write('Terminal=true\n')
        desktop.close()
        status = os.spawnlp(os.P_WAIT, 'xdg-desktop-menu', 'xdg-desktop-menu',
                            'install', desktop_name)
    finally:
        shutil.rmtree(tmpdir)

    if status:
        raise SafeException(
            _('Failed to run xdg-desktop-menu (error code %d)') % status)
Example #26
0
    def get_first_system_store(self):
        """The first system store is the one we try writing to first.
		@since: 0.30"""
        try:
            return self.stores[1]
        except IndexError:
            raise SafeException(_("No system stores have been configured"))
Example #27
0
def do_copy_src(args):
    """copy-src"""
    if args:
        raise __main__.UsageError()

    buildenv = BuildEnv()

    src_impl = buildenv.chosen_impl(buildenv.interface)
    assert src_impl
    path = lookup(src_impl)
    assert path

    new_src = os.path.realpath('src')  # Just for better messages
    if os.path.exists(new_src):
        raise SafeException("Directory '%s' already exists!" % new_src)
    shutil.copytree(path, 'src', symlinks=True)
    # Make all files writable by the owner
    for root, dirs, files in os.walk('src'):
        os.chmod(root, os.stat(root).st_mode | 0200)
        for f in files:
            path = os.path.join(root, f)
            if not os.path.islink(path):
                os.chmod(path, os.stat(path).st_mode | 0200)

    print "Copied as '%s'" % new_src
Example #28
0
def _extract(stream, destdir, command, start_offset=0):
    """Run execvp('command') inside destdir in a child process, with
	stream seeked to 'start_offset' as stdin."""

    # Some zip archives are missing timezone information; force consistent results
    child_env = os.environ.copy()
    child_env['TZ'] = 'GMT'

    stream.seek(start_offset)

    # TODO: use pola-run if available, once it supports fchmod
    child = subprocess.Popen(command,
                             cwd=destdir,
                             stdin=stream,
                             stderr=subprocess.PIPE,
                             env=child_env)

    unused, cerr = child.communicate()

    status = child.wait()
    if status != 0:
        raise SafeException(
            _('Failed to extract archive (using %(command)s); exit code %(status)d:\n%(err)s'
              ) % {
                  'command': command,
                  'status': status,
                  'err': cerr.strip()
              })
Example #29
0
	def parse(value):
		if value.lower() == 'true':
			return True
		elif value.lower() == 'false':
			return False
		else:
			raise SafeException(_('Must be True or False, not "%s"') % value)
Example #30
0
def do_add(args):
    """add DIGEST (DIRECTORY | (ARCHIVE [EXTRACT]))"""
    from zeroinstall.zerostore import unpack
    if len(args) < 2: raise UsageError(_("Missing arguments"))
    digest = args[0]
    if os.path.isdir(args[1]):
        if len(args) > 2: raise UsageError(_("Too many arguments"))
        stores.add_dir_to_cache(digest, args[1])
    elif os.path.isfile(args[1]):
        if len(args) > 3: raise UsageError(_("Too many arguments"))
        if len(args) > 2:
            extract = args[2]
        else:
            extract = None

        type = unpack.type_from_url(args[1])
        if not type:
            raise SafeException(
                _("Unknown extension in '%s' - can't guess MIME type") %
                args[1])
        unpack.check_type_ok(type)

        with open(args[1], 'rb') as stream:
            stores.add_archive_to_cache(digest,
                                        stream,
                                        args[1],
                                        extract,
                                        type=type)
    else:
        try:
            os.stat(args[1])
        except OSError as ex:
            if ex.errno != errno.ENOENT:  # No such file or directory
                raise UsageError(str(ex))  # E.g. permission denied
        raise UsageError(_("No such file or directory '%s'") % args[1])