コード例 #1
0
ファイル: copysrc.py プロジェクト: dabrahams/0compile
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))
コード例 #2
0
ファイル: copysrc.py プロジェクト: talex5/0compile
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
コード例 #3
0
ファイル: copysrc.py プロジェクト: dabrahams/0compile
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
コード例 #4
0
ファイル: copysrc.py プロジェクト: talex5/0compile
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))
コード例 #5
0
ファイル: include_deps.py プロジェクト: dabrahams/0compile
def do_include_deps(args):
	"""include-deps"""
	buildenv = BuildEnv()

	depdir = os.path.realpath('dependencies')
	ensure_dir(depdir)

	dirs_to_copy = []

	sels = buildenv.get_selections()
	for needed_iface in sels.selections:
		impl = buildenv.chosen_impl(needed_iface)
		assert impl
		if impl.local_path is not None:
			raise SafeException("Can't export '%s' as it's a local implementation (not supported yet; sorry)" % impl)
		if not impl.id.startswith('package:'):
			dirs_to_copy.append(lookup(impl))
	
	copied = 0
	for cached in dirs_to_copy:
		required_digest = os.path.basename(cached)
		target_impl_dir = os.path.join(depdir, required_digest)
		if not os.path.isdir(target_impl_dir):
			if required_digest.startswith('sha1='):
				shutil.copytree(cached, target_impl_dir)
			else:
				manifest_data = file(os.path.join(cached, '.manifest')).read()
				manifest.copy_tree_with_verify(cached, depdir, manifest_data, required_digest)
			copied += 1

	print "Copied %d dependencies to %s (%d already there)" % (copied, depdir, len(dirs_to_copy) - copied)
コード例 #6
0
def do_include_deps(args):
	"""include-deps"""
	buildenv = BuildEnv()

	depdir = os.path.realpath('dependencies')
	ensure_dir(depdir)

	dirs_to_copy = []

	sels = buildenv.get_selections()
	for needed_iface in sels.selections:
		impl = buildenv.chosen_impl(needed_iface)
		assert impl
		if impl.local_path is not None:
			raise SafeException("Can't export '%s' as it's a local implementation (not supported yet; sorry)" % impl)
		if not impl.id.startswith('package:'):
			dirs_to_copy.append(lookup(impl))
	
	copied = 0
	for cached in dirs_to_copy:
		required_digest = os.path.basename(cached)
		target_impl_dir = os.path.join(depdir, required_digest)
		if not os.path.isdir(target_impl_dir):
			if required_digest.startswith('sha1='):
				shutil.copytree(cached, target_impl_dir)
			else:
				with open(os.path.join(cached, '.manifest'), 'rb') as stream:
					manifest_data = stream.read()
				manifest.copy_tree_with_verify(cached, depdir, manifest_data, required_digest)
			copied += 1

	print("Copied %d dependencies to %s (%d already there)" % (copied, depdir, len(dirs_to_copy) - copied))
コード例 #7
0
def do_build(args):
	"""build [ --no-sandbox ] [ --shell | --force | --clean ]"""
	buildenv = BuildEnv()
	sels = buildenv.get_selections()

	parser = OptionParser(usage="usage: %prog build [options]")

	parser.add_option('', "--no-sandbox", help="disable use of sandboxing", action='store_true')
	parser.add_option("-s", "--shell", help="run a shell instead of building", action='store_true')
	parser.add_option("-c", "--clean", help="remove the build directories", action='store_true')
	parser.add_option("-f", "--force", help="build even if dependencies have changed", action='store_true')

	parser.disable_interspersed_args()

	(options, args2) = parser.parse_args(args)

	builddir = os.path.realpath('build')

	changes = buildenv.get_build_changes()
	if changes:
		if not (options.force or options.clean):
			raise SafeException("Build dependencies have changed:\n" +
					'\n'.join(changes) + "\n\n" +
					"To build anyway, use: 0compile build --force\n" +
					"To do a clean build:  0compile build --clean")
		if not options.no_sandbox:
			print("Build dependencies have changed:\n" + '\n'.join(changes))

	ensure_dir(builddir, options.clean)
	ensure_dir(buildenv.distdir, options.clean)

	if options.no_sandbox:
		return do_build_internal(options, args2)

	tmpdir = tempfile.mkdtemp(prefix = '0compile-')
	try:
		my_dir = os.path.dirname(__file__)
		readable = ['.', my_dir]
		writable = ['build', buildenv.distdir, tmpdir]
		env('TMPDIR', tmpdir)

		for selection in list(sels.selections.values()):
			if not is_package_impl(selection):
				readable.append(lookup(selection))

		options = []
		if __main__.options.verbose:
			options.append('--verbose')

		readable.append('/etc')	# /etc/ld.*

		spawn_and_check_maybe_sandboxed(readable, writable, tmpdir, sys.executable, ['-u', sys.argv[0]] + options + ['build', '--no-sandbox'] + args)
	finally:
		info("Deleting temporary directory '%s'" % tmpdir)
		shutil.rmtree(tmpdir)
コード例 #8
0
ファイル: build.py プロジェクト: dabrahams/0compile
def do_build(args):
	"""build [ --no-sandbox ] [ --shell | --force | --clean ]"""
	buildenv = BuildEnv()
	sels = buildenv.get_selections()

	parser = OptionParser(usage="usage: %prog build [options]")

	parser.add_option('', "--no-sandbox", help="disable use of sandboxing", action='store_true')
	parser.add_option("-s", "--shell", help="run a shell instead of building", action='store_true')
	parser.add_option("-c", "--clean", help="remove the build directories", action='store_true')
	parser.add_option("-f", "--force", help="build even if dependencies have changed", action='store_true')

	parser.disable_interspersed_args()

	(options, args2) = parser.parse_args(args)

	builddir = os.path.realpath('build')

	changes = buildenv.get_build_changes()
	if changes:
		if not (options.force or options.clean):
			raise SafeException("Build dependencies have changed:\n" +
					'\n'.join(changes) + "\n\n" +
					"To build anyway, use: 0compile build --force\n" +
					"To do a clean build:  0compile build --clean")
		if not options.no_sandbox:
			print "Build dependencies have changed:\n" + '\n'.join(changes)

	ensure_dir(builddir, options.clean)
	ensure_dir(buildenv.distdir, options.clean)

	if options.no_sandbox:
		return do_build_internal(options, args2)

	tmpdir = tempfile.mkdtemp(prefix = '0compile-')
	try:
		my_dir = os.path.dirname(__file__)
		readable = ['.', my_dir]
		writable = ['build', buildenv.distdir, tmpdir]
		env('TMPDIR', tmpdir)

		for selection in sels.selections.values():
			if not is_package_impl(selection):
				readable.append(lookup(selection))

		options = []
		if __main__.options.verbose:
			options.append('--verbose')

		readable.append('/etc')	# /etc/ld.*

		spawn_and_check_maybe_sandboxed(readable, writable, tmpdir, sys.executable, ['-u', sys.argv[0]] + options + ['build', '--no-sandbox'] + args)
	finally:
		info("Deleting temporary directory '%s'" % tmpdir)
		shutil.rmtree(tmpdir)
コード例 #9
0
ファイル: publish.py プロジェクト: dabrahams/0compile
def do_publish(args):
	"""publish [ DOWNLOAD-BASE-URL ]"""

	parser = OptionParser(usage="usage: %prog publish [options] [ DOWNLOAD-BASE-URL ]")

	parser.add_option('', "--target-feed", help="name of output feed file to create", metavar='FILE')
	(options, args2) = parser.parse_args(args)

	buildenv = BuildEnv()
	if len(args2) == 0:
		if not buildenv.download_base_url:
			raise SafeException("No download base set. Give the URL for a remote directory.")
	elif len(args2) == 1:
		buildenv.config.set('compile', 'download-base-url', args2[0])
		buildenv.save()

	info("Using download base URL: %s", buildenv.download_base_url)

	if not os.path.isdir(buildenv.distdir):
		raise SafeException("Directory '%s' does not exist. Try 'compile build'." % buildenv.distdir)

	distdir = os.path.basename(buildenv.distdir)
	archive_name = buildenv.archive_stem + '.tar.bz2'

	# Make all directories in the archive user writable
	for main, dirs, files in os.walk(distdir):
		os.chmod(main, os.stat(main).st_mode | 0200)

	import tarfile
	archive = tarfile.open(archive_name, mode = 'w:bz2')
	archive.add(distdir, buildenv.archive_stem)
	archive.close()

	target_feed = options.target_feed or buildenv.local_download_iface

	download_url = os.path.join(buildenv.download_base_url, archive_name)
	shutil.copyfile(buildenv.local_iface_file, target_feed)
	
	# XXX: we're assuming that 0publish requires the same version of Python as
	# 0compile. This is currently needed for Arch Linux, but long-term we need to
	# use the <runner>.
	spawn_and_check(sys.executable, [
		pubish_command,
		target_feed,
		'--archive-url', download_url,
		'--archive-extract', buildenv.archive_stem])

	if options.target_feed is None:
		# If --target-feed is used this is probably a script, so don't print
		# out hints.
		print "Now upload '%s' as:\n%s\n" % (archive_name, download_url)

		print "Once uploaded, you can download and run with:"
		print "$ 0launch %s" % target_feed
コード例 #10
0
ファイル: bugs.py プロジェクト: 0install/0compile
def do_report_bug(args):
    """report-bug"""
    buildenv = BuildEnv()

    log_name = join('build', 'build-failure.log')
    build_log = codecs.open(log_name, 'r', 'utf-8')
    log_text = build_log.read()
    build_log.close()

    build_env_xml_file = join(buildenv.metadir, 'build-environment.xml')
    if os.path.exists(build_env_xml_file):
        with open(build_env_xml_file, 'r') as build_env_xml:
            log_text += '\n\nSelected versions:\n' + build_env_xml.read()
    else:
        log_text += '\n\n"%s" file not found' % build_env_xml_file

    log_text = codecs.encode(log_text, 'utf-8')

    import urllib.request, urllib.parse, urllib.error
    from urllib.request import urlopen

    print("Sending contents of %s file to default bug reporting site..." %
          log_name)

    stream = urlopen(
        'http://api.0install.net/api/report-bug/',
        urllib.parse.urlencode({
            'uri': buildenv.interface,
            'body': log_text
        }).encode())
    print(stream.read())
    stream.close()
コード例 #11
0
ファイル: gui_support.py プロジェクト: talex5/0compile
	def set_responses_sensitive(self):
		self.set_response_sensitive(RESPONSE_SETUP, True)
		self.set_response_sensitive(RESPONSE_BUILD, True)

		buildenv = BuildEnv()
		have_binary = os.path.exists(buildenv.local_iface_file)
		self.set_response_sensitive(RESPONSE_REGISTER, have_binary)
		self.set_response_sensitive(RESPONSE_PUBLISH, have_binary)
コード例 #12
0
ファイル: setup.py プロジェクト: dabrahams/0compile
def do_setup(args, get_dir_callback = None):
	"setup [ SOURCE-URI [ DIR ] ]"
	if len(args) == 0:
		assert get_dir_callback is None
		buildenv = BuildEnv()
		interface = buildenv.interface
		assert interface
		create_dir = None
		buildenv.get_selections(prompt = True)
	else:
		buildenv = BuildEnv(need_config = False)
		interface = args[0]
		if get_dir_callback:
			assert len(args) == 1
		if len(args) == 1:
			create_dir = os.path.basename(interface)
			if create_dir.endswith('.xml'):
				create_dir = create_dir[:-4]
			if create_dir.startswith('alias:'):
				create_dir = create_dir.split(':', 1)[1]
			assert os.path.dirname(create_dir) == ''
			assert create_dir != os.path.curdir
			if get_dir_callback:
				create_dir = get_dir_callback(create_dir)
		elif len(args) == 2:
			create_dir = args[1]
			if create_dir == '.':
				create_dir = None
		else:
			raise __main__.UsageError()

		iface_uri = model.canonical_iface_uri(args[0])
		if os.path.isabs(iface_uri):
			root = qdom.parse(file(iface_uri))
			if root.uri == namespaces.XMLNS_IFACE and root.name == 'selections':
				# Looks like this is a selections file, not an interface.
				buildenv.config.set('compile', 'selections', iface_uri)
				iface_uri = root.getAttribute('interface')
		buildenv.config.set('compile', 'interface', iface_uri)

		if create_dir and os.path.exists(create_dir):
			raise SafeException("Directory '%s' already exists." % create_dir)
		buildenv.get_selections()

	if create_dir:
		try:
			os.mkdir(create_dir)
		except:
			print >>sys.stderr, "Failed to create new directory '%s'" % os.path.abspath(create_dir)
			raise
		os.chdir(create_dir)
		print "Created directory %s" % create_dir

	buildenv.save()
コード例 #13
0
def do_clean(args):
	"""clean"""
	if args:
		raise __main__.UsageError()

	buildenv = BuildEnv()

	for x in ['build', buildenv.distdir]:
		if os.path.exists(x):
			print "Removing '%s'" % os.path.basename(x)
			shutil.rmtree(x)
コード例 #14
0
def do_gui(args):
    "gui [--no-prompt] [SOURCE-URI]"
    if args and args[0] == '--no-prompt':
        del args[0]
        # This option no longer has any effect, since it is the default.
        # However, old versions of 0launch's GUI pass it (< 0.52)

    from zeroinstall.gtkui import pygtkcompat
    pygtkcompat.enable()
    pygtkcompat.enable_gtk(version='3.0')

    import gui_support
    import gtk

    try:
        if len(args) == 0:
            pass
        elif len(args) == 1:
            import setup

            def get_dir_callback(default_dir):
                compile_dir = gui_support.choose_dir(
                    _('Create build directory'), default_dir)
                if compile_dir:
                    return compile_dir
                raise SafeException("Cancelled at user's request")

            setup.do_setup(args, get_dir_callback)
        else:
            raise SafeException("usage: 0compile gui URI")

        buildenv = BuildEnv()
        box = gui_support.CompileBox(buildenv.interface)
        box.connect('destroy', lambda b: gtk.main_quit())
        box.show()

        gtk.main()
    except KeyboardInterrupt:
        pass
    except SafeException as ex:
        gui_support.alert(None, '%s' % ex)
        sys.exit(1)
    except Exception as ex:
        import traceback
        traceback.print_exc()
        gui_support.alert(None, '%s: %s' % (ex.__class__, ex))
        sys.exit(1)
コード例 #15
0
def do_setup(args, get_dir_callback=None):
    "setup [ SOURCE-URI [ DIR ] ]"
    if len(args) == 0:
        assert get_dir_callback is None
        buildenv = BuildEnv()
        interface = buildenv.interface
        assert interface
        create_dir = None
        buildenv.get_selections(prompt=True)
    else:
        buildenv = BuildEnv(need_config=False)
        interface = args[0]
        if get_dir_callback:
            assert len(args) == 1
        if len(args) == 1:
            create_dir = os.path.basename(interface)
            if create_dir.endswith('.xml'):
                create_dir = create_dir[:-4]
            if create_dir.startswith('alias:'):
                create_dir = create_dir.split(':', 1)[1]
            assert os.path.dirname(create_dir) == ''
            assert create_dir != os.path.curdir
            if get_dir_callback:
                create_dir = get_dir_callback(create_dir)
        elif len(args) == 2:
            create_dir = args[1]
            if create_dir == '.':
                create_dir = None
        else:
            raise __main__.UsageError()

        iface_uri = model.canonical_iface_uri(args[0])
        if os.path.isabs(iface_uri):
            # Use a relative path if the feed is inside the current directory.
            # This is useful if the properties file is shared with other users.
            rel_iface_uri = os.path.relpath(iface_uri, create_dir or ".")
            if not rel_iface_uri.startswith("."):
                iface_uri = rel_iface_uri

            root = qdom.parse(file(iface_uri))
            if root.uri == namespaces.XMLNS_IFACE and root.name == 'selections':
                # Looks like this is a selections file, not an interface.
                buildenv.config.set('compile', 'selections', iface_uri)
                iface_uri = root.getAttribute('interface')
        buildenv.config.set('compile', 'interface', iface_uri)

        if create_dir and os.path.exists(create_dir):
            raise SafeException("Directory '%s' already exists." % create_dir)
        buildenv.get_selections()

    if create_dir:
        try:
            os.mkdir(create_dir)
        except:
            print >> sys.stderr, "Failed to create new directory '%s'" % os.path.abspath(
                create_dir)
            raise
        os.chdir(create_dir)
        print "Created directory %s" % create_dir

    buildenv.save()
コード例 #16
0
def do_build_internal(options, args):
    """build-internal"""
    # If a sandbox is being used, we're in it now.
    import getpass, socket

    buildenv = BuildEnv()
    sels = buildenv.get_selections()

    builddir = os.path.realpath('build')
    ensure_dir(buildenv.metadir)

    build_env_xml = join(buildenv.metadir, 'build-environment.xml')

    buildenv_doc = sels.toDOM()

    # Create build-environment.xml file
    root = buildenv_doc.documentElement
    info = buildenv_doc.createElementNS(XMLNS_0COMPILE, 'build-info')
    root.appendChild(info)
    info.setAttributeNS(None, 'time', time.strftime('%Y-%m-%d %H:%M').strip())
    info.setAttributeNS(None, 'host', socket.getfqdn())
    info.setAttributeNS(None, 'user', getpass.getuser())
    info.setAttributeNS(None, 'arch', '%s-%s' % (uname[0], uname[4]))
    stream = file(build_env_xml, 'w')
    buildenv_doc.writexml(stream, addindent="  ", newl="\n")
    stream.close()

    # Create local binary interface file.
    # We use the main feed for the interface as the template for the name,
    # summary, etc (note: this is not necessarily the feed that contained
    # the source code).
    master_feed = iface_cache.get_feed(buildenv.interface)
    src_impl = buildenv.chosen_impl(buildenv.interface)
    write_sample_feed(buildenv, master_feed, src_impl)

    # Check 0compile is new enough
    min_version = model.parse_version(
        src_impl.attrs.get(XMLNS_0COMPILE + ' min-version', None))
    if min_version and min_version > model.parse_version(__main__.version):
        raise SafeException(
            "%s-%s requires 0compile >= %s, but we are only version %s" %
            (master_feed.get_name(), src_impl.version,
             model.format_version(min_version), __main__.version))

    # Create the patch
    patch_file = join(buildenv.metadir, 'from-%s.patch' % src_impl.version)
    if buildenv.user_srcdir:
        with open(patch_file, 'w') as stream:
            # (ignore errors; will already be shown on stderr)
            try:
                subprocess.call(["diff", "-urN", buildenv.orig_srcdir, 'src'],
                                stdout=stream)
            except OSError as ex:
                print >> sys.stderr, "WARNING: Failed to run 'diff': ", ex
        if os.path.getsize(patch_file) == 0:
            os.unlink(patch_file)
    elif os.path.exists(patch_file):
        os.unlink(patch_file)

    env('BUILDDIR', builddir)
    env('DISTDIR', buildenv.distdir)
    env('SRCDIR', buildenv.user_srcdir or buildenv.orig_srcdir)
    env('BINARYFEED', buildenv.local_iface_file)
    os.chdir(builddir)
    print "cd", builddir

    setup = CompileSetup(iface_cache.stores, sels)
    setup.prepare_env()

    # These mappings are needed when mixing Zero Install -dev packages with
    # native package binaries.
    mappings = {}
    for impl in sels.selections.values():
        # Add mappings that have been set explicitly...
        new_mappings = impl.attrs.get(XMLNS_0COMPILE + ' lib-mappings', '')
        if new_mappings:
            new_mappings = new_mappings.split(' ')
            for mapping in new_mappings:
                assert ':' in mapping, "lib-mappings missing ':' in '%s' from '%s'" % (
                    mapping, impl.feed)
                name, major_version = mapping.split(':', 1)
                assert '/' not in mapping, "lib-mappings '%s' contains a / in the version number (from '%s')!" % (
                    mapping, impl.feed)
                if sys.platform == 'darwin':
                    mappings[name] = 'lib%s.%s.dylib' % (name, major_version)
                else:
                    mappings[name] = 'lib%s.so.%s' % (name, major_version)
        # Auto-detect required mappings where possible...
        # (if the -dev package is native, the symlinks will be OK)
        if not is_package_impl(impl):
            impl_path = lookup(impl)
            for libdirname in ['lib', 'usr/lib', 'lib64', 'usr/lib64']:
                libdir = os.path.join(impl_path, libdirname)
                if os.path.isdir(libdir):
                    find_broken_version_symlinks(libdir, mappings)

    if mappings:
        set_up_mappings(mappings)

    overrides_dir = os.path.join(os.environ['TMPDIR'], PKG_CONFIG_OVERRIDES)
    if os.path.isdir(overrides_dir):
        add_overrides = model.EnvironmentBinding('PKG_CONFIG_PATH',
                                                 PKG_CONFIG_OVERRIDES)
        do_env_binding(add_overrides, os.environ['TMPDIR'])

    # Some programs want to put temporary build files in the source directory.
    # Make a copy of the source if needed.
    dup_src_type = src_impl.attrs.get(XMLNS_0COMPILE + ' dup-src', None)
    if dup_src_type == 'true':
        dup_src(copy_file)
        env('SRCDIR', builddir)
    elif dup_src_type:
        raise Exception("Unknown dup-src value '%s'" % dup_src_type)

    if options.shell:
        spawn_and_check(find_in_path('cmd' if os.name == 'nt' else 'sh'), [])
    else:
        command = sels.commands[0].qdom.attrs.get('shell-command', None)
        if command is None:
            # New style <command>
            prog_args = setup.build_command(sels.interface,
                                            sels.command) + args
        else:
            # Old style shell-command='...'
            if os.name == 'nt':
                prog_args = [
                    os.environ['0COMPILE_BASH'], '-eux', '-c', command
                ] + args
            else:
                prog_args = ['/bin/sh', '-c', command + ' "$@"', '-'] + args
            assert len(sels.commands) == 1

        # Remove any existing log files
        for log in ['build.log', 'build-success.log', 'build-failure.log']:
            if os.path.exists(log):
                os.unlink(log)

        # Run the command, copying output to a new log
        with open('build.log', 'w') as log:
            print >> log, "Build log for %s-%s" % (master_feed.get_name(),
                                                   src_impl.version)
            print >> log, "\nBuilt using 0compile-%s" % __main__.version
            print >> log, "\nBuild system: " + ', '.join(uname)
            print >> log, "\n%s:\n" % ENV_FILE
            with open(os.path.join(os.pardir, ENV_FILE)) as properties_file:
                shutil.copyfileobj(properties_file, log)

            log.write('\n')

            if os.path.exists(patch_file):
                print >> log, "\nPatched with:\n"
                shutil.copyfileobj(file(patch_file), log)
                log.write('\n')

            if command:
                print "Executing: " + command, args
                print >> log, "Executing: " + command, args
            else:
                print "Executing: " + str(prog_args)
                print >> log, "Executing: " + str(prog_args)

            # Tee the output to the console and to the log
            child = subprocess.Popen(prog_args,
                                     stdout=subprocess.PIPE,
                                     stderr=subprocess.STDOUT)
            while True:
                data = os.read(child.stdout.fileno(), 100)
                if not data: break
                sys.stdout.write(data)
                log.write(data)
            status = child.wait()
            failure = None
            if status == 0:
                print >> log, "Build successful"
                shorten_dynamic_library_install_names()
                fixup_generated_pkgconfig_files()
                remove_la_files()
            elif status > 0:
                failure = "Build failed with exit code %d" % status
            else:
                failure = "Build failure: exited due to signal %d" % (-status)
            if failure:
                print >> log, failure

        if failure:
            os.rename('build.log', 'build-failure.log')
            raise SafeException("Command '%s': %s" % (prog_args, failure))
        else:
            os.rename('build.log', 'build-success.log')
コード例 #17
0
ファイル: autocompile.py プロジェクト: dabrahams/0compile
	def compile_and_register(self, sels, forced_iface_uri = None):
		"""If forced_iface_uri, register as an implementation of this interface,
		ignoring the any <feed-for>, etc."""

		buildenv = BuildEnv(need_config = False)
		buildenv.config.set('compile', 'interface', sels.interface)
		buildenv.config.set('compile', 'selections', 'selections.xml')
		
		# Download any required packages now, so we can use the GUI to request confirmation, etc
		download_missing = sels.download_missing(self.config, include_packages = True)
		if download_missing:
			yield download_missing
			tasks.check(download_missing)

		tmpdir = tempfile.mkdtemp(prefix = '0compile-')
		try:
			os.chdir(tmpdir)

			# Write configuration for build...

			buildenv.save()

			sel_file = open('selections.xml', 'w')
			try:
				doc = sels.toDOM()
				doc.writexml(sel_file)
				sel_file.write('\n')
			finally:
				sel_file.close()

			# Do the build...

			build = self.spawn_build(buildenv.iface_name)
			if build:
				yield build
				tasks.check(build)

			# Register the result...
			dom = minidom.parse(buildenv.local_iface_file)

			feed_for_elem, = dom.getElementsByTagNameNS(namespaces.XMLNS_IFACE, 'feed-for')
			claimed_iface = feed_for_elem.getAttribute('interface')

			if forced_iface_uri is not None:
				if forced_iface_uri != claimed_iface:
					self.note("WARNING: registering as feed for {forced}, though feed claims to be for {claimed}".format(
						forced = forced_iface_uri,
						claimed = claimed_iface))
			else:
				forced_iface_uri = claimed_iface		# (the top-level interface being built)

			version = sels.selections[sels.interface].version

			site_package_versions_dir = basedir.save_data_path('0install.net', 'site-packages',
						*model.escape_interface_uri(forced_iface_uri))
			leaf =  '%s-%s' % (version, uname[4])
			site_package_dir = os.path.join(site_package_versions_dir, leaf)
			self.note("Storing build in %s" % site_package_dir)

			# 1. Copy new version in under a temporary name. Names starting with '.' are ignored by 0install.
			tmp_distdir = os.path.join(site_package_versions_dir, '.new-' + leaf)
			shutil.copytree(buildenv.distdir, tmp_distdir, symlinks = True)

			# 2. Rename the previous build to .old-VERSION (deleting that if it already existed)
			if os.path.exists(site_package_dir):
				self.note("(moving previous build out of the way)")
				previous_build_dir = os.path.join(site_package_versions_dir, '.old-' + leaf)
				if os.path.exists(previous_build_dir):
					shutil.rmtree(previous_build_dir)
				os.rename(site_package_dir, previous_build_dir)
			else:
				previous_build_dir = None

			# 3. Rename the new version immediately after renaming away the old one to minimise time when there's
			# no version.
			os.rename(tmp_distdir, site_package_dir)

			# 4. Delete the old version.
			if previous_build_dir:
				self.note("(deleting previous build)")
				shutil.rmtree(previous_build_dir)

			local_feed = os.path.join(site_package_dir, '0install', 'feed.xml')
			assert os.path.exists(local_feed), "Feed %s not found!" % local_feed

			# Reload - our 0install will detect the new feed automatically
			iface = self.config.iface_cache.get_interface(forced_iface_uri)
			reader.update_from_cache(iface, iface_cache = self.config.iface_cache)
			self.config.iface_cache.get_feed(local_feed, force = True)

			# Write it out - 0install will add the feed so that older 0install versions can find it
			writer.save_interface(iface)
		except:
			self.note("\nBuild failed: leaving build directory %s for inspection...\n" % tmpdir)
			raise
		else:
			# Can't delete current directory on Windows, so move to parent first
			os.chdir(os.path.join(tmpdir, os.path.pardir))

			ro_rmtree(tmpdir)
コード例 #18
0
def do_publish(args):
    """publish [ DOWNLOAD-BASE-URL ]"""

    parser = OptionParser(
        usage="usage: %prog publish [options] [ DOWNLOAD-BASE-URL ]")

    parser.add_option('',
                      "--target-feed",
                      help="name of output feed file to create",
                      metavar='FILE')
    (options, args2) = parser.parse_args(args)

    buildenv = BuildEnv()
    if len(args2) == 1:
        buildenv.config.set('compile', 'download-base-url', args2[0])
        buildenv.save()
    elif len(args2) > 1:
        parser.print_help()
        sys.exit(1)

    download_base_url = buildenv.download_base_url or None

    if download_base_url:
        info("Using download base URL: %s", download_base_url)

    if not os.path.isdir(buildenv.distdir):
        raise SafeException(
            "Directory '%s' does not exist. Try 'compile build'." %
            buildenv.distdir)

    distdir = os.path.basename(buildenv.distdir)
    archive_name = buildenv.archive_stem + '.tar.bz2'

    # Make all directories in the archive user writable
    for main, dirs, files in os.walk(distdir):
        os.chmod(main, os.stat(main).st_mode | 0o200)

    import tarfile
    archive = tarfile.open(archive_name, mode='w:bz2')
    archive.add(distdir, buildenv.archive_stem)
    archive.close()

    target_feed = options.target_feed or buildenv.local_download_iface

    if download_base_url:
        download_url = os.path.join(download_base_url, archive_name)
    else:
        download_url = archive_name
    shutil.copyfile(buildenv.local_iface_file, target_feed)

    # XXX: we're assuming that 0publish requires the same version of Python as
    # 0compile. This is currently needed for Arch Linux, but long-term we need to
    # use the <runner>.
    spawn_and_check(sys.executable, [
        pubish_command, target_feed, '--archive-url', download_url,
        '--archive-extract', buildenv.archive_stem
    ])

    if options.target_feed is None:
        # If --target-feed is used this is probably a script, so don't print
        # out hints.
        if download_base_url:
            print("Now upload '%s' as:\n%s\n" % (archive_name, download_url))
            print("Once uploaded, you can download and run with:")
            print("0launch %s" % target_feed)
        else:
            print("Generated archive '%s' and feed '%s'." %
                  (archive_name, target_feed))
            print("Upload it to a repository with:")
            print("0repo add %s" % target_feed)
コード例 #19
0
ファイル: autocompile.py プロジェクト: talex5/0compile
    def compile_and_register(self, sels, forced_iface_uri=None):
        """If forced_iface_uri, register as an implementation of this interface,
		ignoring the any <feed-for>, etc."""

        buildenv = BuildEnv(need_config=False)
        buildenv.config.set('compile', 'interface', sels.interface)
        buildenv.config.set('compile', 'selections', 'selections.xml')

        # Download any required packages now, so we can use the GUI to request confirmation, etc
        download_missing = sels.download_missing(self.config,
                                                 include_packages=True)
        if download_missing:
            yield download_missing
            tasks.check(download_missing)

        tmpdir = tempfile.mkdtemp(prefix='0compile-')
        try:
            os.chdir(tmpdir)

            # Write configuration for build...

            buildenv.save()

            sel_file = open('selections.xml', 'w')
            try:
                doc = sels.toDOM()
                doc.writexml(sel_file)
                sel_file.write('\n')
            finally:
                sel_file.close()

            # Do the build...

            build = self.spawn_build(buildenv.iface_name)
            if build:
                yield build
                tasks.check(build)

            # Register the result...
            dom = minidom.parse(buildenv.local_iface_file)

            feed_for_elem, = dom.getElementsByTagNameNS(
                namespaces.XMLNS_IFACE, 'feed-for')
            claimed_iface = feed_for_elem.getAttribute('interface')

            if forced_iface_uri is not None:
                if forced_iface_uri != claimed_iface:
                    self.note(
                        "WARNING: registering as feed for {forced}, though feed claims to be for {claimed}"
                        .format(forced=forced_iface_uri,
                                claimed=claimed_iface))
            else:
                forced_iface_uri = claimed_iface  # (the top-level interface being built)

            version = sels.selections[sels.interface].version

            site_package_versions_dir = basedir.save_data_path(
                '0install.net', 'site-packages',
                *model.escape_interface_uri(forced_iface_uri))
            leaf = '%s-%s' % (version, build_target_machine_type)
            site_package_dir = os.path.join(site_package_versions_dir, leaf)
            self.note("Storing build in %s" % site_package_dir)

            # 1. Copy new version in under a temporary name. Names starting with '.' are ignored by 0install.
            tmp_distdir = os.path.join(site_package_versions_dir,
                                       '.new-' + leaf)
            shutil.copytree(buildenv.distdir, tmp_distdir, symlinks=True)

            # 2. Rename the previous build to .old-VERSION (deleting that if it already existed)
            if os.path.exists(site_package_dir):
                self.note("(moving previous build out of the way)")
                previous_build_dir = os.path.join(site_package_versions_dir,
                                                  '.old-' + leaf)
                if os.path.exists(previous_build_dir):
                    shutil.rmtree(previous_build_dir)
                os.rename(site_package_dir, previous_build_dir)
            else:
                previous_build_dir = None

            # 3. Rename the new version immediately after renaming away the old one to minimise time when there's
            # no version.
            os.rename(tmp_distdir, site_package_dir)

            # 4. Delete the old version.
            if previous_build_dir:
                self.note("(deleting previous build)")
                shutil.rmtree(previous_build_dir)

            local_feed = os.path.join(site_package_dir, '0install', 'feed.xml')
            assert os.path.exists(
                local_feed), "Feed %s not found!" % local_feed

            # Reload - our 0install will detect the new feed automatically
            iface = self.config.iface_cache.get_interface(forced_iface_uri)
            reader.update_from_cache(iface,
                                     iface_cache=self.config.iface_cache)
            self.config.iface_cache.get_feed(local_feed, force=True)

            # Write it out - 0install will add the feed so that older 0install versions can find it
            writer.save_interface(iface)

            seen_key = (forced_iface_uri, sels.selections[sels.interface].id)
            assert seen_key not in self.seen, seen_key
            self.seen[seen_key] = site_package_dir
        except:
            self.note(
                "\nBuild failed: leaving build directory %s for inspection...\n"
                % tmpdir)
            raise
        else:
            # Can't delete current directory on Windows, so move to parent first
            os.chdir(os.path.join(tmpdir, os.path.pardir))

            ro_rmtree(tmpdir)
コード例 #20
0
ファイル: gui_support.py プロジェクト: talex5/0compile
		def response(box, resp):
			if resp == RESPONSE_SETUP:
				def done_setup():
					self.add_msg('Now use Build to compile the chosen source code.')
				self.run_command((sys.executable, main_path, 'setup'), done_setup)
			elif resp == RESPONSE_BUILD:
				def done_build():
					self.add_msg('\nBuild successful. Now register or publish the build.')
				def build_failed():
					self.add_msg('\nIf the messages displayed above indicate a missing dependency (e.g. no C compiler '
						     "or a library that isn't available through Zero Install) then install it using your "
						     'normal package manager and click on Build again. Note that for libraries you often '
						     'need the -dev version of the package. '
						     '\nOtherwise, please notify the developers of this problem (this will transmit '
						     'the contents of the build/build-failure.log file):')
					end = self.buffer.get_end_iter()
					anchor = self.buffer.create_child_anchor(end)
					align = gtk.Alignment(0.0, 0.0, 1.0, 1.0)
					button = ButtonMixed(gtk.STOCK_YES, 'Notify developers')
					align.add(button)
					align.set_padding(8, 8, 8, 8)
					align.show_all()
					self.tv.add_child_at_anchor(align, anchor)
					self.add_msg('\n')
					def report_bug(button):
						def done_notify():
							self.add_msg("\nReport sent. Thank you! (note: you won't get a reply, as "
								"no contact details were sent; write to the project's mailing "
								"list if you want to discuss the problem)")
						self.run_command((sys.executable, main_path, 'report-bug'), done_notify)
					button.connect('clicked', report_bug)
				buildenv = BuildEnv()
				changes = buildenv.get_build_changes()
				if changes:
					options = get_build_options(box, '\n'.join(changes) + '\n\nIt would be best to do a clean (full) build.')
				else:
					options = []
				if options is not None:
					box.run_command([sys.executable, main_path, 'build'] + options, done_build, build_failed)
			elif resp == RESPONSE_REGISTER:
				buildenv = BuildEnv()

				iface = iface_cache.get_interface(interface)
				reader.update_from_cache(iface)

				# Register using the feed-for, if available
				real_iface = iface
				for uri in iface.feed_for or []:
					real_iface = iface_cache.get_interface(uri)
					self.add_msg("Registering as a feed for %s" % real_iface.uri)
					break
				else:
					if os.path.isabs(iface.uri):
						self.add_msg("Warning: no <feed-for> in local feed %s!" % iface.uri)

				feed = buildenv.local_iface_file
				for f in real_iface.feeds or []:
					if f.uri == feed:
						self.add_msg("Feed '%s' is already registered for interface '%s'!\n" % (feed, real_iface.uri))
						return
				box.buffer.insert_at_cursor("Registering feed '%s'\n" % feed)
				real_iface.extra_feeds.append(model.Feed(feed, arch = None, user_override = True))
				writer.save_interface(real_iface)
				box.buffer.insert_at_cursor("Done. You can now close this window.\n")
			elif resp == RESPONSE_PUBLISH:
				buildenv = BuildEnv()
				box = PublishBox(self, buildenv)
				resp = box.run()
				box.destroy()
				if resp == gtk.RESPONSE_OK:
					def done_publish():
						self.add_msg("\nYou can use '0publish --local' to add this "
							"into the main feed. If you don't have a main feed then this "
							"will create one. See "
							"http://0install.net/injector-packagers.html for more information.")
					self.run_command((sys.executable, main_path,
						'publish', box.archive_dir.get_text()), done_publish)
			elif resp == gtk.RESPONSE_CANCEL or resp == gtk.RESPONSE_DELETE_EVENT:
				if self.kill_child(): return
				self.destroy()
			else:
				self.add_msg('Unknown response: %s' % resp)
コード例 #21
0
ファイル: build.py プロジェクト: dabrahams/0compile
def do_build_internal(options, args):
	"""build-internal"""
	# If a sandbox is being used, we're in it now.
	import getpass, socket

	buildenv = BuildEnv()
	sels = buildenv.get_selections()

	builddir = os.path.realpath('build')
	ensure_dir(buildenv.metadir)

	build_env_xml = join(buildenv.metadir, 'build-environment.xml')

	buildenv_doc = sels.toDOM()

	# Create build-environment.xml file
	root = buildenv_doc.documentElement
	info = buildenv_doc.createElementNS(XMLNS_0COMPILE, 'build-info')
	root.appendChild(info)
	info.setAttributeNS(None, 'time', time.strftime('%Y-%m-%d %H:%M').strip())
	info.setAttributeNS(None, 'host', socket.getfqdn())
	info.setAttributeNS(None, 'user', getpass.getuser())
	info.setAttributeNS(None, 'arch', '%s-%s' % (uname[0], uname[4]))
	stream = file(build_env_xml, 'w')
	buildenv_doc.writexml(stream, addindent="  ", newl="\n")
	stream.close()

	# Create local binary interface file.
	# We use the main feed for the interface as the template for the name,
	# summary, etc (note: this is not necessarily the feed that contained
	# the source code).
	master_feed = iface_cache.get_feed(buildenv.interface)
	src_impl = buildenv.chosen_impl(buildenv.interface)
	write_sample_feed(buildenv, master_feed, src_impl)

	# Check 0compile is new enough
	min_version = model.parse_version(src_impl.attrs.get(XMLNS_0COMPILE + ' min-version', None))
	if min_version and min_version > model.parse_version(__main__.version):
		raise SafeException("%s-%s requires 0compile >= %s, but we are only version %s" %
				(master_feed.get_name(), src_impl.version, model.format_version(min_version), __main__.version))

	# Create the patch
	patch_file = join(buildenv.metadir, 'from-%s.patch' % src_impl.version)
	if buildenv.user_srcdir:
		with open(patch_file, 'w') as stream:
			# (ignore errors; will already be shown on stderr)
			try:
				subprocess.call(["diff", "-urN", buildenv.orig_srcdir, 'src'], stdout = stream)
			except OSError as ex:
				print >>sys.stderr, "WARNING: Failed to run 'diff': ", ex
		if os.path.getsize(patch_file) == 0:
			os.unlink(patch_file)
	elif os.path.exists(patch_file):
		os.unlink(patch_file)

	env('BUILDDIR', builddir)
	env('DISTDIR', buildenv.distdir)
	env('SRCDIR', buildenv.user_srcdir or buildenv.orig_srcdir)
	env('BINARYFEED', buildenv.local_iface_file)
	os.chdir(builddir)
	print "cd", builddir

	setup = CompileSetup(iface_cache.stores, sels)
	setup.prepare_env()

	# These mappings are needed when mixing Zero Install -dev packages with
	# native package binaries.
	mappings = {}
	for impl in sels.selections.values():
		# Add mappings that have been set explicitly...
		new_mappings = impl.attrs.get(XMLNS_0COMPILE + ' lib-mappings', '')
		if new_mappings:
			new_mappings = new_mappings.split(' ')
			for mapping in new_mappings:
				assert ':' in mapping, "lib-mappings missing ':' in '%s' from '%s'" % (mapping, impl.feed)
				name, major_version = mapping.split(':', 1)
				assert '/' not in mapping, "lib-mappings '%s' contains a / in the version number (from '%s')!" % (mapping, impl.feed)
				if sys.platform == 'darwin':
					mappings[name] = 'lib%s.%s.dylib' % (name, major_version)
				else:
					mappings[name] = 'lib%s.so.%s' % (name, major_version)
		# Auto-detect required mappings where possible...
		# (if the -dev package is native, the symlinks will be OK)
		if not is_package_impl(impl):
			impl_path = lookup(impl)
			for libdirname in ['lib', 'usr/lib', 'lib64', 'usr/lib64']:
				libdir = os.path.join(impl_path, libdirname)
				if os.path.isdir(libdir):
					find_broken_version_symlinks(libdir, mappings)

	if mappings:
		set_up_mappings(mappings)

	overrides_dir = os.path.join(os.environ['TMPDIR'], PKG_CONFIG_OVERRIDES)
	if os.path.isdir(overrides_dir):
		add_overrides = model.EnvironmentBinding('PKG_CONFIG_PATH', PKG_CONFIG_OVERRIDES)
		do_env_binding(add_overrides, os.environ['TMPDIR'])

	# Some programs want to put temporary build files in the source directory.
	# Make a copy of the source if needed.
	dup_src_type = src_impl.attrs.get(XMLNS_0COMPILE + ' dup-src', None)
	if dup_src_type == 'true':
		dup_src(shutil.copy2)
		env('SRCDIR', builddir)
	elif dup_src_type:
		raise Exception("Unknown dup-src value '%s'" % dup_src_type)

	if options.shell:
		spawn_and_check(find_in_path('cmd' if os.name == 'nt' else 'sh'), [])
	else:
		command = sels.commands[0].qdom.attrs.get('shell-command', None)
		if command is None:
			# New style <command>
			prog_args = setup.build_command(sels.interface, sels.command) + args
		else:
			# Old style shell-command='...'
			if os.name == 'nt':
				prog_args = ['cmd', '/c', command] + args
			else:
				prog_args = ['/bin/sh', '-c', command + ' "$@"', '-'] + args
			assert len(sels.commands) == 1

		# Remove any existing log files
		for log in ['build.log', 'build-success.log', 'build-failure.log']:
			if os.path.exists(log):
				os.unlink(log)

		# Run the command, copying output to a new log
		with open('build.log', 'w') as log:
			print >>log, "Build log for %s-%s" % (master_feed.get_name(),
							      src_impl.version)
			print >>log, "\nBuilt using 0compile-%s" % __main__.version
			print >>log, "\nBuild system: " + ', '.join(uname)
			print >>log, "\n%s:\n" % ENV_FILE
			with open(os.path.join(os.pardir, ENV_FILE)) as properties_file:
				shutil.copyfileobj(properties_file, log)

			log.write('\n')

			if os.path.exists(patch_file):
				print >>log, "\nPatched with:\n"
				shutil.copyfileobj(file(patch_file), log)
				log.write('\n')

			if command:
				print "Executing: " + command, args
				print >>log, "Executing: " + command, args
			else:
				print "Executing: " + str(prog_args)
				print >>log, "Executing: " + str(prog_args)

			# Tee the output to the console and to the log
			child = subprocess.Popen(prog_args, stdout = subprocess.PIPE, stderr = subprocess.STDOUT)
			while True:
				data = os.read(child.stdout.fileno(), 100)
				if not data: break
				sys.stdout.write(data)
				log.write(data)
			status = child.wait()
			failure = None
			if status == 0:
				print >>log, "Build successful"
				shorten_dynamic_library_install_names()
				fixup_generated_pkgconfig_files()
				remove_la_files()
			elif status > 0:
				failure = "Build failed with exit code %d" % status
			else:
				failure = "Build failure: exited due to signal %d" % (-status)
			if failure:
				print >>log, failure

		if failure:
			os.rename('build.log', 'build-failure.log')
			raise SafeException("Command '%s': %s" % (prog_args, failure))
		else:
			os.rename('build.log', 'build-success.log')