public static void createSymlink(@Nonnull File baseDir, @Nonnull String targetPath,
            @Nonnull String symlinkPath, @Nonnull TaskListener listener) throws InterruptedException {
        try {
            Path path = fileToPath(new File(baseDir, symlinkPath));
            Path target = Paths.get(targetPath, MemoryReductionUtil.EMPTY_STRING_ARRAY);

            final int maxNumberOfTries = 4;
            final int timeInMillis = 100;
            for (int tryNumber = 1; tryNumber <= maxNumberOfTries; tryNumber++) {
                Files.deleteIfExists(path);
                try {
                    Files.createSymbolicLink(path, target);
                    break;
                } catch (FileAlreadyExistsException fileAlreadyExistsException) {
                    if (tryNumber < maxNumberOfTries) {
                        TimeUnit.MILLISECONDS.sleep(timeInMillis); //trying to defeat likely ongoing race condition
                        continue;
                    }
                    LOGGER.log(Level.WARNING, "symlink FileAlreadyExistsException thrown {0} times => cannot createSymbolicLink", maxNumberOfTries);
                    throw fileAlreadyExistsException;
                }
            }
        } catch (UnsupportedOperationException e) {
            PrintStream log = listener.getLogger();
            log.print("Symbolic links are not supported on this platform");
            Functions.printStackTrace(e, log);
        } catch (IOException e) {
            if (Functions.isWindows() && e instanceof FileSystemException) {
                warnWindowsSymlink();
                return;
            }
            PrintStream log = listener.getLogger();
            log.printf("ln %s %s failed%n",targetPath, new File(baseDir, symlinkPath));
            Functions.printStackTrace(e, log);
        }
    }
public static void createSymlink ( @ Nonnull File baseDir , @ Nonnull String targetPath , @ Nonnull String symlinkPath , @ Nonnull TaskListener listener ) throws InterruptedException { try { Path path = fileToPath ( new File ( baseDir , symlinkPath ) ) ; Path target = Paths . get ( targetPath , MemoryReductionUtil . EMPTY_STRING_ARRAY ) ; final int maxNumberOfTries = 4 ; final int timeInMillis = 100 ; for ( int tryNumber = 1 ; tryNumber <= maxNumberOfTries ; tryNumber ++ ) { Files . deleteIfExists ( path ) ; try { Files . createSymbolicLink ( path , target ) ; break ; } catch ( FileAlreadyExistsException fileAlreadyExistsException ) { if ( tryNumber < maxNumberOfTries ) { TimeUnit . MILLISECONDS . sleep ( timeInMillis ) ; continue ; } LOGGER . log ( Level . WARNING , "symlink FileAlreadyExistsException thrown {0} times => cannot createSymbolicLink" , maxNumberOfTries ) ; throw fileAlreadyExistsException ; } } } catch ( UnsupportedOperationException e ) { PrintStream log = listener . getLogger ( ) ; log . print ( "Symbolic links are not supported on this platform" ) ; Functions . printStackTrace ( e , log ) ; } catch ( IOException e ) { if ( Functions . isWindows ( ) && e instanceof FileSystemException ) { warnWindowsSymlink ( ) ; return ; } PrintStream log = listener . getLogger ( ) ; log . printf ( "ln %s %s failed%n" , targetPath , new File ( baseDir , symlinkPath ) ) ; Functions . printStackTrace ( e , log ) ; } }
Creates a symlink to targetPath at baseDir+symlinkPath.
<p>
If there's a prior symlink at baseDir+symlinkPath, it will be overwritten.

@param baseDir
Base directory to resolve the 'symlinkPath' parameter.
@param targetPath
The file that the symlink should point to. Usually relative to the directory of the symlink but may instead be an absolute path.
@param symlinkPath
Where to create a symlink in (relative to {@code baseDir})