def fetch_jdk(args): """fetches required JDK version If mx is not passed the --quiet flag, menu will be printed for available JDK selection. """ args = _parse_fetchsettings(args) distribution = args["java-distribution"] base_path = args["base-path"] artifact = distribution.get_folder_name() final_path = distribution.get_final_path(base_path) url = mx_urlrewrites.rewriteurl(distribution.get_url()) sha_url = url + ".sha1" archive_name = distribution.get_archive_name() archive_target_location = join(base_path, archive_name) if not is_quiet(): if not mx.ask_yes_no("Install {} to {}".format(artifact, final_path), default='y'): mx.abort("JDK installation canceled") if exists(final_path): if args["keep-archive"]: mx.warn( "The --keep-archive option is ignored when the JDK is already installed." ) mx.log("Requested JDK is already installed at {}".format(final_path)) else: # Try to extract on the same file system as the target to be able to atomically move the result. with mx.TempDir(parent_dir=base_path) as temp_dir: mx.log("Fetching {} archive from {}...".format(artifact, url)) archive_location = join(temp_dir, archive_name) mx._opts.no_download_progress = is_quiet() sha1_hash = mx._hashFromUrl(sha_url).decode('utf-8') mx.download_file_with_sha1(artifact, archive_location, [url], sha1_hash, archive_location + '.sha1', resolve=True, mustExist=True, sources=False) untar = mx.TarExtractor(archive_location) mx.log("Installing {} to {}...".format(artifact, final_path)) extracted_path = join(temp_dir, 'extracted') try: untar.extract(extracted_path) except: mx.rmtree(temp_dir, ignore_errors=True) mx.abort("Error parsing archive. Please try again") jdk_root_folder = get_extracted_jdk_archive_root_folder( extracted_path) if args["keep-archive"]: atomic_file_move_with_fallback(archive_location, archive_target_location) atomic_file_move_with_fallback( archive_location + '.sha1', archive_target_location + ".sha1") mx.log( "Archive is located at {}".format(archive_target_location)) atomic_file_move_with_fallback( join(extracted_path, jdk_root_folder), final_path) curr_path = final_path if mx.is_darwin() and exists(join(final_path, 'Contents', 'Home')): if args["strip-contents-home"]: with mx.TempDir(parent_dir=final_path) as tmp_path: shutil.move(final_path, tmp_path) shutil.move(join(tmp_path, 'Contents', 'Home'), final_path) else: final_path = join(final_path, 'Contents', 'Home') if "alias" in args: alias_full_path = join(base_path, args["alias"]) if exists(alias_full_path): mx.rmtree(alias_full_path) if not (mx.is_windows() or mx.is_cygwin()): os.symlink(abspath(curr_path), alias_full_path) else: mx.copytree(curr_path, alias_full_path, symlinks=True) # fallback for windows final_path = alias_full_path mx.log("Run the following to set JAVA_HOME in your shell:") shell = os.environ.get("SHELL") if shell is None: shell = '' print(get_setvar_format(shell) % ("JAVA_HOME", abspath(final_path)))
def gc_dists(args): """ Garbage collect mx distributions.""" parser = argparse.ArgumentParser(prog='mx gc-dists', description='''Garbage collect layout distributions. By default, it collects all found layout distributions that are *not* part of the current configuration (see `--keep-current`). This command respects mx level suite filtering (e.g., `mx --suite my-suite gc-dists`). ''', epilog='''If the environment variable `MX_GC_AFTER_BUILD` is set, %(prog)s will be executed after `mx build` using the content of the environment variable as parameters.''') # mutually exclusive groups do not support title and description - wrapping in another group as a workaround action_group_desc = parser.add_argument_group('actions', 'What to do with the result. One of the following arguments is required.') action_group = action_group_desc.add_mutually_exclusive_group(required=True) action_group.add_argument('-f', '--force', action='store_true', help='remove layout distributions without further questions') action_group.add_argument('-n', '--dry-run', action='store_true', help='show what would be removed without actually doing anything') action_group.add_argument('-i', '--interactive', action='store_true', help='ask for every layout distributions whether it should be removed') keep_current_group_desc = parser.add_argument_group('current configuration handling', description='How to deal with the current configuration, i.e., what `mx build` would rebuild.') keep_current_group = keep_current_group_desc.add_mutually_exclusive_group() keep_current_group.add_argument('--keep-current', action='store_true', default=True, help='keep layout distributions of the current configuration (default)') keep_current_group.add_argument('--no-keep-current', action='store_false', dest='keep_current', help='remove layout distributions of the current configuration') filter_group = parser.add_argument_group('result filters', description='Filter can be combined.') filter_group.add_argument('--reverse', action='store_true', help='reverse the result') filter_group.add_argument('--older-than', action=TimeAction, help='only show results older than the specified point in time (format: {})'.format(TimeAction.fmt.replace('%', '%%'))) try: parsed_args = parser.parse_args(args) except ValueError as ve: parser.error(str(ve)) suites = mx.suites(opt_limit_to_suite=True, includeBinary=False, include_mx=False) c = [] for s in suites: c += _gc_layout_dists(s, parsed_args) if not c: mx.log("Nothing to do!") return if parsed_args.older_than: c = [x for x in c if x[1] < parsed_args.older_than] # sort by mod date c = sorted(c, key=lambda x: x[1], reverse=parsed_args.reverse) # calculate max sizes max_path = 0 max_mod_time = 0 max_size = 0 for path, mod_time, size in c: max_path = max(len(path), max_path) max_mod_time = max(len(_format_datetime(mod_time)), max_mod_time) max_size = max(len(_format_bytes(size)), max_size) msg_fmt = '{0:<' + str(max_path) + '} modified {1:<' + str(max_mod_time + len(' ago')) +'} {2:<' + str(max_size) + '}' size_sum = 0 for path, mod_time, size in c: if parsed_args.dry_run: mx.log(msg_fmt.format(path, _format_datetime(mod_time) + ' ago', _format_bytes(size))) size_sum += size else: msg = '{0} (modified {1} ago, size {2})'.format(path, _format_datetime(mod_time), _format_bytes(size)) if parsed_args.force or parsed_args.interactive and mx.ask_yes_no('Delete ' + msg): mx.log('rm ' + path) mx.rmtree(path) size_sum += size if parsed_args.dry_run: mx.log('Would free ' + _format_bytes(size_sum)) else: mx.log('Freed ' + _format_bytes(size_sum))
def fetch_jdk(args): """ Installs a JDK based on the coordinates in `args`. See ``mx fetch-jdk --help`` for more info. Note that if a JDK already exists at the installation location denoted by `args`, no action is taken. :return str: the JAVA_HOME for the JDK at the installation location denoted by `args` """ settings = _parse_args(args) jdk_binary = settings["jdk-binary"] jdks_dir = settings["jdks-dir"] artifact = jdk_binary._folder_name final_path = jdk_binary.get_final_path(jdks_dir) url = mx_urlrewrites.rewriteurl(jdk_binary._url) sha_url = url + ".sha1" archive_name = jdk_binary._archive archive_target_location = join(jdks_dir, archive_name) if not is_quiet(): if not mx.ask_yes_no("Install {} to {}".format(artifact, final_path), default='y'): mx.abort("JDK installation canceled") if exists(final_path): if settings["keep-archive"]: mx.warn( "The --keep-archive option is ignored when the JDK is already installed." ) mx.log("Requested JDK is already installed at {}".format(final_path)) else: # Try to extract on the same file system as the target to be able to atomically move the result. with mx.TempDir(parent_dir=jdks_dir) as temp_dir: mx.log("Fetching {} archive from {}...".format(artifact, url)) archive_location = join(temp_dir, archive_name) mx._opts.no_download_progress = is_quiet() try: sha1_hash = mx._hashFromUrl(sha_url).decode('utf-8') except Exception as e: #pylint: disable=broad-except mx.abort('Error retrieving {}: {}'.format(sha_url, e)) mx.download_file_with_sha1(artifact, archive_location, [url], sha1_hash, archive_location + '.sha1', resolve=True, mustExist=True, sources=False) untar = mx.TarExtractor(archive_location) mx.log("Installing {} to {}...".format(artifact, final_path)) extracted_path = join(temp_dir, 'extracted') try: untar.extract(extracted_path) except: mx.rmtree(temp_dir, ignore_errors=True) mx.abort("Error parsing archive. Please try again") jdk_root_folder = _get_extracted_jdk_archive_root_folder( extracted_path) if settings["keep-archive"]: atomic_file_move_with_fallback(archive_location, archive_target_location) atomic_file_move_with_fallback( archive_location + '.sha1', archive_target_location + ".sha1") mx.log( "Archive is located at {}".format(archive_target_location)) atomic_file_move_with_fallback( join(extracted_path, jdk_root_folder), final_path) curr_path = final_path if exists(join(final_path, 'Contents', 'Home')): if settings["strip-contents-home"]: with mx.TempDir() as tmp_path: tmp_jdk = join(tmp_path, 'jdk') shutil.move(final_path, tmp_jdk) shutil.move(join(tmp_jdk, 'Contents', 'Home'), final_path) else: final_path = join(final_path, 'Contents', 'Home') alias = settings.get('alias') if alias: alias_full_path = join(jdks_dir, alias) if not exists(alias_full_path) or os.path.realpath( alias_full_path) != os.path.realpath(abspath(curr_path)): if os.path.islink(alias_full_path): os.unlink(alias_full_path) elif exists(alias_full_path): mx.abort( alias_full_path + ' exists and it is not an existing symlink so it can not be used for a new symlink. Please remove it manually.' ) if mx.can_symlink(): if isabs(alias): os.symlink(curr_path, alias_full_path) else: reldir = os.path.relpath(dirname(curr_path), dirname(alias_full_path)) if reldir == '.': alias_target = basename(curr_path) else: alias_target = join(reldir, basename(curr_path)) os.symlink(alias_target, alias_full_path) else: mx.copytree(curr_path, alias_full_path) final_path = alias_full_path mx.log("Run the following to set JAVA_HOME in your shell:") shell = os.environ.get("SHELL") if shell is None: shell = '' if not settings["strip-contents-home"] and exists( join(final_path, 'Contents', 'Home')): java_home = join(final_path, 'Contents', 'Home') else: java_home = final_path mx.log(get_setvar_format(shell) % ("JAVA_HOME", abspath(java_home))) return final_path
def fsckprojects(args): """find directories corresponding to deleted Java projects and delete them""" for suite in mx.suites(True, includeBinary=False): projectDirs = [p.dir for p in suite.projects] distIdeDirs = [ d.get_ide_project_dir() for d in suite.dists if d.isJARDistribution() and d.get_ide_project_dir() is not None ] for dirpath, dirnames, files in os.walk(suite.dir): if dirpath == suite.dir: # no point in traversing vc metadata dir, lib, .workspace # if there are nested source suites must not scan those now, as they are not in projectDirs (but contain .project files) omitted = [suite.mxDir, 'lib', '.workspace', 'mx.imports'] if suite.vc: omitted.append(suite.vc.metadir()) dirnames[:] = [d for d in dirnames if d not in omitted] elif dirpath == suite.get_output_root(): # don't want to traverse output dir dirnames[:] = [] elif dirpath == suite.mxDir: # don't want to traverse mx.name as it contains a .project dirnames[:] = [] elif dirpath in projectDirs: # don't traverse subdirs of an existing project in this suite dirnames[:] = [] elif dirpath in distIdeDirs: # don't traverse subdirs of an existing distribution in this suite dirnames[:] = [] else: maybe_project = basename(dirpath) if not mx._removedDeps.get(maybe_project): projectConfigFiles = frozenset([ '.classpath', '.project', 'nbproject', maybe_project + '.iml' ]) indicators = projectConfigFiles.intersection(files) if len(indicators) != 0: indicators = [ os.path.relpath(join(dirpath, i), suite.vc_dir) for i in indicators ] indicatorsInVC = suite.vc.locate( suite.vc_dir, indicators) # Only proceed if there are indicator files that are not under VC if len(indicators) > len(indicatorsInVC): if mx.ask_yes_no( dirpath + ' looks like a removed project -- delete it', 'n'): shutil.rmtree(dirpath) mx.log('Deleted ' + dirpath) ideaProjectDirectory = join(suite.dir, '.idea') librariesDirectory = join(ideaProjectDirectory, 'libraries') if librariesDirectory and exists(librariesDirectory): neededLibraries = set() unique_library_file_names = set() for p in suite.projects_recursive( ) + mx._mx_suite.projects_recursive(): if not p.isJavaProject(): continue def processDep(dep, edge): if dep is p: return if dep.isLibrary() or dep.isJARDistribution( ) or dep.isJdkLibrary() or dep.isMavenProject( ) or dep.isClasspathDependency(): neededLibraries.add(dep) p.walk_deps(visit=processDep, ignoredEdges=[mx.DEP_EXCLUDED]) neededLibraryFiles = frozenset([ mx_ide_intellij._intellij_library_file_name( l.name, unique_library_file_names) for l in neededLibraries ]) existingLibraryFiles = frozenset(os.listdir(librariesDirectory)) for library_file in existingLibraryFiles - neededLibraryFiles: file_path = join(librariesDirectory, library_file) relative_file_path = os.path.relpath(file_path, os.curdir) if mx.ask_yes_no( relative_file_path + ' looks like a removed library -- delete it', 'n'): os.remove(file_path) mx.log('Deleted ' + relative_file_path)