15
15
16
16
import static org .eclipse .jdt .ls .core .internal .JVMConfigurator .configureJVMSettings ;
17
17
18
+ import java .io .ByteArrayInputStream ;
18
19
import java .io .File ;
20
+ import java .io .IOException ;
19
21
import java .net .URI ;
20
22
import java .util .ArrayList ;
21
23
import java .util .Arrays ;
29
31
import java .util .stream .Stream ;
30
32
31
33
import org .apache .commons .lang3 .StringUtils ;
34
+ import org .eclipse .core .internal .preferences .EclipsePreferences ;
32
35
import org .eclipse .core .internal .resources .CharsetManager ;
33
36
import org .eclipse .core .internal .resources .Workspace ;
34
37
import org .eclipse .core .resources .FileInfoMatcherDescription ;
38
+ import org .eclipse .core .resources .IFile ;
35
39
import org .eclipse .core .resources .IFolder ;
36
40
import org .eclipse .core .resources .IMarker ;
37
41
import org .eclipse .core .resources .IProject ;
52
56
import org .eclipse .core .runtime .IProgressMonitor ;
53
57
import org .eclipse .core .runtime .IStatus ;
54
58
import org .eclipse .core .runtime .MultiStatus ;
59
+ import org .eclipse .core .runtime .NullProgressMonitor ;
55
60
import org .eclipse .core .runtime .OperationCanceledException ;
56
61
import org .eclipse .core .runtime .Platform ;
57
62
import org .eclipse .core .runtime .Status ;
@@ -343,6 +348,45 @@ public static IProject createJavaProject(IProject project, IProgressMonitor moni
343
348
return createJavaProject (project , null , "src" , "bin" , monitor );
344
349
}
345
350
351
+ /*
352
+ * ⚠ These value is duplicated in ProjectsManager as both bundles must remain independent,
353
+ * but the same dir should be used for .project or .settings/.classpath.
354
+ * So when updating one, think about updating the other.
355
+ */
356
+ public static final String GENERATES_METADATA_FILES_AT_PROJECT_ROOT = "java.import.generatesMetadataFilesAtProjectRoot" ;
357
+ public static final IPath METADATA_FOLDER_PATH = ResourcesPlugin .getWorkspace ().getRoot ().getLocation ().append (".projects" );
358
+
359
+ /**
360
+ * Check whether the metadata files needs to be generated at project root.
361
+ */
362
+ public static boolean generatesMetadataFilesAtProjectRoot () {
363
+ String property = System .getProperty (GENERATES_METADATA_FILES_AT_PROJECT_ROOT );
364
+ if (property == null ) {
365
+ return true ;
366
+ }
367
+ return Boolean .parseBoolean (property );
368
+ }
369
+
370
+ /**
371
+ * Get the redirected path of the input path. The path will be redirected to
372
+ * the workspace's metadata folder ({@link JLSFsUtils#METADATA_FOLDER_PATH}).
373
+ * @param projectName name of the project.
374
+ * @param path path needs to be redirected.
375
+ * @return the redirected path.
376
+ */
377
+ public static IPath getMetaDataFilePath (String projectName , IPath path ) {
378
+ if (path .segmentCount () == 1 ) {
379
+ return METADATA_FOLDER_PATH .append (projectName ).append (path );
380
+ }
381
+
382
+ String lastSegment = path .lastSegment ();
383
+ if (IProjectDescription .DESCRIPTION_FILE_NAME .equals (lastSegment )) {
384
+ return METADATA_FOLDER_PATH .append (projectName ).append (lastSegment );
385
+ }
386
+
387
+ return null ;
388
+ }
389
+
346
390
public static IProject createJavaProject (IProject project , IPath projectLocation , String src , String bin , IProgressMonitor monitor ) throws CoreException , OperationCanceledException {
347
391
if (project .exists ()) {
348
392
return project ;
@@ -355,6 +399,9 @@ public static IProject createJavaProject(IProject project, IPath projectLocation
355
399
}
356
400
project .create (description , monitor );
357
401
project .open (monitor );
402
+ if (!generatesMetadataFilesAtProjectRoot () && !DEFAULT_PROJECT_NAME .equals (project .getName ())) {
403
+ linkResources (project );
404
+ }
358
405
359
406
//Turn into Java project
360
407
description = project .getDescription ();
@@ -396,6 +443,43 @@ public static IProject createJavaProject(IProject project, IPath projectLocation
396
443
return project ;
397
444
}
398
445
446
+ public static void linkResources (IProject project ) throws CoreException {
447
+ IFile classpathFile = project .getFile (IJavaProject .CLASSPATH_FILE_NAME );
448
+ if (!classpathFile .exists ()) {
449
+ File diskFile = getMetaDataFilePath (classpathFile .getProject ().getName (), classpathFile .getProjectRelativePath ()).toFile ();
450
+ if (!diskFile .exists ()) {
451
+ try {
452
+ diskFile .getParentFile ().mkdirs ();
453
+ diskFile .createNewFile ();
454
+ } catch (IOException ex ) {
455
+ throw new CoreException (Status .error (diskFile + " cannot be created" , ex )); //$NON-NLS-1$
456
+ }
457
+ }
458
+ classpathFile .createLink (diskFile .toURI (), IResource .NONE , new NullProgressMonitor ());
459
+ classpathFile .setContents (new ByteArrayInputStream ("<classpath/>" .getBytes ()), 0 , null );
460
+ }
461
+ IFile factorypathFile = project .getFile (".factorypath" );
462
+ if (!factorypathFile .exists ()) {
463
+ File diskFile = getMetaDataFilePath (classpathFile .getProject ().getName (), factorypathFile .getProjectRelativePath ()).toFile ();
464
+ if (!diskFile .exists ()) {
465
+ try {
466
+ diskFile .getParentFile ().mkdirs ();
467
+ diskFile .createNewFile ();
468
+ } catch (IOException ex ) {
469
+ throw new CoreException (Status .error (diskFile + " cannot be created" , ex )); //$NON-NLS-1$
470
+ }
471
+ }
472
+ factorypathFile .createLink (diskFile .toURI (), IResource .ALLOW_MISSING_LOCAL , new NullProgressMonitor ());
473
+ factorypathFile .setContents (new ByteArrayInputStream ("<factorypath/>" .getBytes ()), 0 , null );
474
+ }
475
+ IFolder settingsFolder = project .getFolder (EclipsePreferences .DEFAULT_PREFERENCES_DIRNAME );
476
+ if (!settingsFolder .exists ()) {
477
+ File diskFolder = getMetaDataFilePath (classpathFile .getProject ().getName (), settingsFolder .getProjectRelativePath ()).toFile ();
478
+ diskFolder .mkdirs ();
479
+ settingsFolder .createLink (diskFolder .toURI (), IResource .ALLOW_MISSING_LOCAL , new NullProgressMonitor ());
480
+ }
481
+ }
482
+
399
483
@ Override
400
484
public Job updateProject (IProject project , boolean force ) {
401
485
if (project == null || ProjectUtils .isInternalBuildSupport (BuildSupportManager .find (project ).orElse (null ))) {
@@ -426,6 +510,7 @@ public IStatus runInWorkspace(IProgressMonitor monitor) {
426
510
updateEncoding (monitor );
427
511
project .deleteMarkers (BUILD_FILE_MARKER_TYPE , false , IResource .DEPTH_ONE );
428
512
long elapsed = System .currentTimeMillis () - start ;
513
+ replaceLinkedMetadataWithLocal (project );
429
514
JavaLanguageServerPlugin .logInfo ("Updated " + projectName + " in " + elapsed + " ms" );
430
515
} catch (Exception e ) {
431
516
String msg = "Error updating " + projectName ;
@@ -625,5 +710,12 @@ public void reportProjectsStatus() {
625
710
JavaLanguageServerPlugin .sendStatus (ServiceStatus .ProjectStatus , "OK" );
626
711
}
627
712
}
713
+
714
+ private void replaceLinkedMetadataWithLocal (IProject p ) throws CoreException {
715
+ if (new File (p .getLocation ().toFile (), IJavaProject .CLASSPATH_FILE_NAME ).exists () &&
716
+ p .getFile (IJavaProject .CLASSPATH_FILE_NAME ).isLinked ()) {
717
+ p .getFile (IJavaProject .CLASSPATH_FILE_NAME ).delete (false , false , null );
718
+ }
719
+ }
628
720
629
721
}
0 commit comments