From d34c278232f2373fc09f7bcee4bff43c6f4a1d19 Mon Sep 17 00:00:00 2001 From: Tim Felgentreff Date: Mon, 23 Sep 2024 14:30:43 +0200 Subject: [PATCH] [GR-58394] Fix Eclipse config generation with absolute paths, on Windows, and provide alternative entry point for VSCode usage --- docs/IDE.md | 1 + src/mx/_impl/mx.py | 4 +- src/mx/_impl/mx_ide_eclipse.py | 71 ++++++++++++++++++++++++++++++++-- 3 files changed, 71 insertions(+), 5 deletions(-) diff --git a/docs/IDE.md b/docs/IDE.md index 45f76f31f..055a9684e 100644 --- a/docs/IDE.md +++ b/docs/IDE.md @@ -119,6 +119,7 @@ Once you have installed Eclipse, if you have multiple Java versions on your comp ``` Run `mx eclipseinit` to create the Eclipse project configurations. +You may set the `WORKSPACE` environment variable to an Eclipse workspace directory, otherwise the workspace is expected to be a parent of the primary suite. This will print the following instructions on how to import projects: ``` diff --git a/src/mx/_impl/mx.py b/src/mx/_impl/mx.py index 8e6c51942..42c8dee6a 100755 --- a/src/mx/_impl/mx.py +++ b/src/mx/_impl/mx.py @@ -3665,7 +3665,7 @@ def _register_visit(s): def get_mx_path(): """Absolute path to the mx executable""" - return join(_mx_home, 'mx') + return join(_mx_home, 'mx.cmd' if is_windows() else 'mx') # Location of mx repo @@ -18197,7 +18197,7 @@ def alarm_handler(signum, frame): _CACHE_DIR = get_env('MX_CACHE_DIR', join(dot_mx_dir(), 'cache')) # The version must be updated for every PR (checked in CI) and the comment should reflect the PR's issue -version = VersionSpec("7.31.0") # GR-57631 Extend mx with benchpoints command +version = VersionSpec("7.31.1") # GR-58394 Fix Eclipse config for VSCode and Windows _mx_start_datetime = datetime.utcnow() diff --git a/src/mx/_impl/mx_ide_eclipse.py b/src/mx/_impl/mx_ide_eclipse.py index 0888fdbf0..1d10cfa03 100644 --- a/src/mx/_impl/mx_ide_eclipse.py +++ b/src/mx/_impl/mx_ide_eclipse.py @@ -41,7 +41,7 @@ "generate_eclipse_workingsets", ] -import os, time, zipfile, tempfile +import json, os, re, time, zipfile, tempfile # TODO use defusedexpat? import xml.parsers.expat, xml.sax.saxutils, xml.dom.minidom from collections import namedtuple @@ -455,6 +455,67 @@ def make_eclipse_launch(suite, javaArgs, jre, name=None, deps=None): mx.update_file(sourcesFile, '\n'.join(sources)) return mx.update_file(launchFile, launch) + +@mx.command( + 'mx', + 'vscodeinit', + usage_msg="Generate Eclipse project configuration suitable for using with VSCode.\nThis differs from normal Eclipse config only in how annotation processors paths are set up, to account for differences in the VSCode Eclipse language server versus full Eclipse." +) +def vscodeinit(args): + """(re)generate Eclipse project configurations and working sets for VSCode usage""" + parser = ArgumentParser(prog='mx vscodeinit') + parser.add_argument('--no-build', action='store_false', dest='buildProcessorJars', help='Do not build annotation processor jars.') + parser.add_argument('-f', '--force', action='store_true', dest='force', default=False, help='Ignore timestamps when updating files.') + args = parser.parse_args(args) + + eclipseinit(None, args.buildProcessorJars, logToConsole=True, force=args.force, absolutePaths=True, pythonProjects=False) + + projects = sorted([p.dir for suite in mx.suites(True) for p in suite.projects if exists(join(p.dir, ".project"))]) + dists = sorted([d.get_ide_project_dir() for suite in mx.suites(True) for d in suite.dists if exists(join(getattr(d, "get_ide_project_dir", lambda: "")() or "", ".project"))]) + workspace = { + "folders": [{"path": p} for p in projects + dists], + "settings": { + "java.sharedIndexes.enabled": "off", + "java.completion.filteredTypes": [ + "java.awt.*", + "com.sun.*", + "sun.*", + "io.micrometer.shaded.*" + ], + }, + } + + if _EclipseJRESystemLibraries: + installedJREs = [n for n in _EclipseJRESystemLibraries] + if installedJREs: + rts = workspace["settings"]["java.configuration.runtimes"] = [] + for idx, name in enumerate(installedJREs): + rts.append({ + "name": name, + "path": mx.get_jdk(re.sub("[^0-9]+", "", name)).home, + "default": idx == 0 + }) + + workspace_dir = dirname(abspath(mx.primary_suite().vc_dir)) + workspace_file = join(workspace_dir, mx.primary_suite().name + ".code-workspace") + with open(workspace_file, "w") as f: + json.dump(workspace, f) + + mx.log(f''' +---------------------------------------------- +VSCode project generation successfully completed for {workspace_file} + +The recommended next steps are: + 1) Run mx build. This ensures all shaded JARs and annotation processors are built. + 2) Open VSCode. + 3) Make sure you have installed the 'Language Support for Java' extension. + 4) Open {workspace_file} as workspace. + +Note that setting MX_BUILD_EXPLODED=true can improve build times. See "Exploded builds" in the mx README.md. +---------------------------------------------- + ''') + + @mx.command('mx', 'eclipseinit') def eclipseinit_cli(args): """(re)generate Eclipse project configurations and working sets""" @@ -593,7 +654,7 @@ def _add_eclipse_linked_resources(xml_doc, project_loc, linked_resources, absolu xml_doc.open('link') xml_doc.element('name', data=lr.name) xml_doc.element('type', data=lr.type) - xml_doc.element('locationURI', data=get_eclipse_project_rel_locationURI(lr.location, project_loc) if not absolutePaths else lr.location) + xml_doc.element('locationURI', data=get_eclipse_project_rel_locationURI(lr.location, project_loc) if not absolutePaths else f"file://{lr.location.replace('\\', '/')}") xml_doc.close('link') xml_doc.close('linkedResources') @@ -610,6 +671,7 @@ def _eclipse_project_rel(project_loc, path, linked_resources, res_type=IRESOURCE return name else: return os.path.relpath(path, project_loc) + def _eclipseinit_project(p, files=None, libFiles=None, absolutePaths=False): # PROJECT_LOC Eclipse variable project_loc = mx_util.ensure_dir_exists(p.dir) @@ -853,7 +915,10 @@ def processDep(dep, edge): processorsPath = mx.classpath_entries(names=processors) for e in processorsPath: if e.isDistribution() and not isinstance(e.suite, mx.BinarySuite): - out.element('factorypathentry', {'kind' : 'WKSPJAR', 'id' : f'/{e.name}/{basename(e.path)}', 'enabled' : 'true', 'runInBatchMode' : 'false'}) + if absolutePaths: + out.element('factorypathentry', {'kind' : 'EXTJAR', 'id' : e.path, 'enabled' : 'true', 'runInBatchMode' : 'false'}) + else: + out.element('factorypathentry', {'kind' : 'WKSPJAR', 'id' : f'/{e.name}/{basename(e.path)}', 'enabled' : 'true', 'runInBatchMode' : 'false'}) elif e.isJdkLibrary() or e.isJreLibrary(): path = e.classpath_repr(jdk, resolve=True) if path: