diff --git a/tycho-api/src/main/java/org/eclipse/tycho/FileLockService.java b/tycho-api/src/main/java/org/eclipse/tycho/FileLockService.java index 21e525627a..4aa33f92c3 100644 --- a/tycho-api/src/main/java/org/eclipse/tycho/FileLockService.java +++ b/tycho-api/src/main/java/org/eclipse/tycho/FileLockService.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2011 SAP AG and others. + * Copyright (c) 2011, 2023 SAP AG and others. * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 * which accompanies this distribution, and is available at @@ -13,6 +13,7 @@ package org.eclipse.tycho; +import java.io.Closeable; import java.io.File; /** @@ -21,10 +22,25 @@ public interface FileLockService { /** - * Get a locker object which can be used to protect read/write access from multiple processes on - * the given file. Locking is advisory only, i.e. all processes must use the same locking - * mechanism. + * Locks the given file to protect read/write access from multiple processes on it. Locking is + * advisory only, i.e. all processes must use the same locking mechanism. + *

+ * This is equivalent to {@link #lock(File, long)} with a timeout argument of 10 seconds. + *

*/ - public FileLocker getFileLocker(File file); + default Closeable lock(File file) { + return lock(file, 10000L); + } + /** + * Locks the given file to protect read/write access from multiple processes on it. Locking is + * advisory only, i.e. all processes must use the same locking mechanism. + */ + Closeable lock(File file, long timeout); + + /** + * Locks the given file for this JVM to protect read/write access from multiple threads in this + * JVM on it. + */ + Closeable lockVirtually(File file); } diff --git a/tycho-core/src/main/java/org/eclipse/tycho/core/locking/FileLockServiceImpl.java b/tycho-core/src/main/java/org/eclipse/tycho/core/locking/FileLockServiceImpl.java index 270afe2d9f..51991a83a8 100644 --- a/tycho-core/src/main/java/org/eclipse/tycho/core/locking/FileLockServiceImpl.java +++ b/tycho-core/src/main/java/org/eclipse/tycho/core/locking/FileLockServiceImpl.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2011, 2020 SAP AG and others. + * Copyright (c) 2011, 2023 SAP AG and others. * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 * which accompanies this distribution, and is available at @@ -13,28 +13,62 @@ package org.eclipse.tycho.core.locking; +import java.io.Closeable; import java.io.File; import java.io.IOException; +import java.nio.file.Path; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; import org.codehaus.plexus.component.annotations.Component; import org.eclipse.tycho.FileLockService; +import org.eclipse.tycho.LockTimeoutException; @Component(role = FileLockService.class) public class FileLockServiceImpl implements FileLockService { + record FileLocks(FileLockerImpl fileLocker, Lock vmLock) { + } + + private final Map lockers = new ConcurrentHashMap<>(); - private final Map lockers = new ConcurrentHashMap<>(); + @Override + public Closeable lock(File file, long timeout) { + FileLocks locks = getFileLocker(file.toPath()); + FileLockerImpl locker = locks.fileLocker(); + try { + if (!locks.vmLock().tryLock(timeout, TimeUnit.MILLISECONDS)) { + throw new LockTimeoutException("lock timeout: Could not acquire lock on file " + locker.lockMarkerFile + + " for " + timeout + " msec"); + } + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new LockTimeoutException("Interrupted", e); + } + locker.lock(timeout); + return () -> { + locks.fileLocker().release(); + locks.vmLock().unlock(); + }; + } @Override - public FileLockerImpl getFileLocker(File file) { - String key; + public Closeable lockVirtually(File file) { + FileLocks locks = getFileLocker(file.toPath()); + locks.vmLock().lock(); + return locks.vmLock()::unlock; + } + + FileLocks getFileLocker(Path file) { + Path key; try { - key = file.getCanonicalPath(); + key = file.toRealPath(); } catch (IOException e) { - key = file.getAbsolutePath(); + key = file.toAbsolutePath().normalize(); } - return lockers.computeIfAbsent(key, k -> new FileLockerImpl(file)); + return lockers.computeIfAbsent(key, f -> new FileLocks(new FileLockerImpl(f), new ReentrantLock())); } } diff --git a/tycho-core/src/main/java/org/eclipse/tycho/core/locking/FileLockerImpl.java b/tycho-core/src/main/java/org/eclipse/tycho/core/locking/FileLockerImpl.java index 7fcb2a07ff..216a1d480d 100644 --- a/tycho-core/src/main/java/org/eclipse/tycho/core/locking/FileLockerImpl.java +++ b/tycho-core/src/main/java/org/eclipse/tycho/core/locking/FileLockerImpl.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2011 SAP AG and others. + * Copyright (c) 2011, 2023 SAP AG and others. * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 * which accompanies this distribution, and is available at @@ -15,60 +15,46 @@ import java.io.File; import java.io.IOException; -import java.net.MalformedURLException; import java.nio.channels.FileChannel; import java.nio.channels.FileLock; +import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardOpenOption; -import org.eclipse.tycho.FileLocker; import org.eclipse.tycho.LockTimeoutException; -public class FileLockerImpl implements FileLocker { +public class FileLockerImpl { private static final String LOCKFILE_SUFFIX = ".tycholock"; - final File lockMarkerFile; + final Path lockMarkerFile; private FileLock lock; - private File file; + private Path file; - public FileLockerImpl(File file) { - this.file = file; + FileLockerImpl(Path file) { + this.file = file.toAbsolutePath().normalize(); + this.lockMarkerFile = Files.isDirectory(this.file) // + ? this.file.resolve(LOCKFILE_SUFFIX) + : this.file.getParent().resolve(this.file.getFileName() + LOCKFILE_SUFFIX); try { - if (file.isDirectory()) { - this.lockMarkerFile = new File(file, LOCKFILE_SUFFIX).getCanonicalFile(); - } else { - this.lockMarkerFile = new File(file.getParentFile(), file.getName() + LOCKFILE_SUFFIX) - .getCanonicalFile(); + if (Files.isDirectory(lockMarkerFile)) { + throw new IllegalStateException( + "Lock marker file " + lockMarkerFile + " already exists and is a directory"); } - if (lockMarkerFile.isDirectory()) { - throw new RuntimeException("Lock marker file " + lockMarkerFile + " already exists and is a directory"); - } - File parentDir = lockMarkerFile.getParentFile(); - if (!parentDir.mkdirs() && !parentDir.isDirectory()) { - throw new RuntimeException("Could not create parent directory " + parentDir + " of lock marker file"); - } - } catch (MalformedURLException e) { - throw new RuntimeException(e); + Files.createDirectories(lockMarkerFile.getParent()); } catch (IOException e) { - throw new RuntimeException(e); + throw new IllegalStateException(e); } } - @Override - public void lock() { - lock(10000L); - } - - @Override - public void lock(long timeout) { + void lock(long timeout) { if (timeout < 0) { throw new IllegalArgumentException("timeout must not be negative"); } if (lock != null) { - throw new LockTimeoutException("already locked file " + file.getAbsolutePath()); + throw new LockTimeoutException("already locked file " + file); } lock = aquireLock(timeout); @@ -81,8 +67,7 @@ private FileLock aquireLock(long timeout) { for (long i = 0; i < maxTries; i++) { try { if (channel == null) { - Path path = lockMarkerFile.toPath(); - channel = FileChannel.open(path, StandardOpenOption.WRITE, StandardOpenOption.CREATE); + channel = FileChannel.open(lockMarkerFile, StandardOpenOption.WRITE, StandardOpenOption.CREATE); } FileLock fileLock = channel.tryLock(); if (fileLock != null) { @@ -105,26 +90,22 @@ private FileLock aquireLock(long timeout) { channel = null; } } - throw new LockTimeoutException("lock timeout: Could not acquire lock on file " - + lockMarkerFile.getAbsolutePath() + " for " + timeout + " msec"); + throw new LockTimeoutException( + "lock timeout: Could not acquire lock on file " + lockMarkerFile + " for " + timeout + " msec"); } - @Override - public synchronized void release() { + synchronized void release() { if (lock != null) { try { lock.acquiredBy().close(); } catch (Exception e) { } lock = null; - if (!lockMarkerFile.delete()) { - lockMarkerFile.deleteOnExit(); + File lockFile = lockMarkerFile.toFile(); + if (!lockFile.delete()) { + lockFile.deleteOnExit(); } } } - public synchronized boolean isLocked() { - return lock != null; - } - } diff --git a/tycho-core/src/main/java/org/eclipse/tycho/core/osgitools/DefaultBundleReader.java b/tycho-core/src/main/java/org/eclipse/tycho/core/osgitools/DefaultBundleReader.java index 841247215c..7542ceb8ef 100644 --- a/tycho-core/src/main/java/org/eclipse/tycho/core/osgitools/DefaultBundleReader.java +++ b/tycho-core/src/main/java/org/eclipse/tycho/core/osgitools/DefaultBundleReader.java @@ -36,7 +36,6 @@ import org.codehaus.plexus.component.annotations.Requirement; import org.codehaus.plexus.logging.AbstractLogEnabled; import org.eclipse.tycho.FileLockService; -import org.eclipse.tycho.FileLocker; import org.eclipse.tycho.TychoConstants; @Component(role = BundleReader.class) @@ -189,9 +188,7 @@ public File getEntry(File bundleLocation, String path) { throw new RuntimeException("can't get canonical path for " + cacheFile, e); } result = extractedFiles.computeIfAbsent(cacheKey, nil -> { - FileLocker locker = fileLockService.getFileLocker(outputDirectory); - locker.lock(LOCK_TIMEOUT); - try { + try (var locked = fileLockService.lock(outputDirectory, LOCK_TIMEOUT)) { extractZipEntries(bundleLocation, path, outputDirectory); if (cacheFile.exists()) { return Optional.of(cacheFile); @@ -200,8 +197,6 @@ public File getEntry(File bundleLocation, String path) { } catch (IOException e) { throw new RuntimeException( "Can't extract '" + path + "' from " + bundleLocation + " to " + outputDirectory, e); - } finally { - locker.release(); } }); } diff --git a/tycho-core/src/main/java/org/eclipse/tycho/p2/repository/FileBasedTychoRepositoryIndex.java b/tycho-core/src/main/java/org/eclipse/tycho/p2/repository/FileBasedTychoRepositoryIndex.java index a4f3814b39..a88db13366 100644 --- a/tycho-core/src/main/java/org/eclipse/tycho/p2/repository/FileBasedTychoRepositoryIndex.java +++ b/tycho-core/src/main/java/org/eclipse/tycho/p2/repository/FileBasedTychoRepositoryIndex.java @@ -30,7 +30,6 @@ import java.util.Set; import org.eclipse.tycho.FileLockService; -import org.eclipse.tycho.FileLocker; import org.eclipse.tycho.core.shared.MavenContext; import org.eclipse.tycho.core.shared.MavenLogger; @@ -47,7 +46,7 @@ public class FileBasedTychoRepositoryIndex implements TychoRepositoryIndex { private final File indexFile; private final MavenLogger logger; - private FileLocker fileLocker; + private final FileLockService fileLockService; private Set addedGavs = new HashSet<>(); private Set removedGavs = new HashSet<>(); @@ -58,28 +57,17 @@ private FileBasedTychoRepositoryIndex(File indexFile, FileLockService fileLockSe super(); this.indexFile = indexFile; this.mavenContext = mavenContext; - this.fileLocker = fileLockService.getFileLocker(indexFile); + this.fileLockService = fileLockService; this.logger = mavenContext.getLogger(); if (indexFile.isFile()) { - lock(); - try { + try (var locked = fileLockService.lock(indexFile)) { gavs = read(new FileInputStream(indexFile)); } catch (IOException e) { throw new RuntimeException(e); - } finally { - unlock(); } } } - private void lock() { - fileLocker.lock(); - } - - private void unlock() { - fileLocker.release(); - } - @Override public MavenContext getMavenContext() { return mavenContext; @@ -118,8 +106,7 @@ public synchronized void save() throws IOException { if (!parentDir.isDirectory()) { parentDir.mkdirs(); } - lock(); - try { + try (var locked = fileLockService.lock(indexFile)) { reconcile(); // minimize time window for corrupting the file by first writing to a temp file, then moving it File tempFile = File.createTempFile("index", "tmp", indexFile.getParentFile()); @@ -128,8 +115,6 @@ public synchronized void save() throws IOException { indexFile.delete(); } tempFile.renameTo(indexFile); - } finally { - unlock(); } } diff --git a/tycho-core/src/test/java/org/eclipse/tycho/core/locking/FileLockServiceTest.java b/tycho-core/src/test/java/org/eclipse/tycho/core/locking/FileLockServiceTest.java index 67d8672c32..7a3ca09bbd 100644 --- a/tycho-core/src/test/java/org/eclipse/tycho/core/locking/FileLockServiceTest.java +++ b/tycho-core/src/test/java/org/eclipse/tycho/core/locking/FileLockServiceTest.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2011, 2022 SAP AG and others. + * Copyright (c) 2011, 2023 SAP AG and others. * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 * which accompanies this distribution, and is available at @@ -20,9 +20,14 @@ import java.io.File; import java.io.IOException; +import java.nio.channels.FileChannel; +import java.nio.channels.FileLock; +import java.nio.channels.OverlappingFileLockException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardOpenOption; import java.util.Random; -import org.eclipse.tycho.FileLocker; import org.eclipse.tycho.LockTimeoutException; import org.junit.Before; import org.junit.Rule; @@ -42,90 +47,60 @@ public void setup() { @Test public void testIsLocked() throws IOException { - FileLockerImpl fileLocker = subject.getFileLocker(newTestFile()); - fileLocker.lock(); - try { - assertTrue(fileLocker.isLocked()); - } finally { - fileLocker.release(); - assertFalse(fileLocker.isLocked()); + File file = newTestFile(); + try (var locked = subject.lock(file)) { + assertTrue(isLocked(file)); } + assertFalse(isLocked(file)); } @Test(expected = IllegalArgumentException.class) public void testNegativeTimeout() throws IOException { - FileLocker fileLocker = subject.getFileLocker(newTestFile()); - fileLocker.lock(-1L); + subject.lock(newTestFile(), -1L); } @Test public void testLockDirectory() throws IOException { File testDir = tempFolder.newFolder("test"); - FileLockerImpl fileLocker = subject.getFileLocker(testDir); - fileLocker.lock(); - try { - assertTrue(fileLocker.isLocked()); - assertEquals(new File(testDir, ".tycholock").getCanonicalPath(), - fileLocker.lockMarkerFile.getCanonicalPath()); - } finally { - fileLocker.release(); - } - } - - @Test - public void testLockReentranceSameLocker() throws IOException { - FileLocker fileLocker = subject.getFileLocker(newTestFile()); - fileLocker.lock(); - try { - // locks are not re-entrant - fileLocker.lock(0L); - fail("lock already held by same VM but could be acquired a second time"); - } catch (LockTimeoutException e) { - // expected - } finally { - fileLocker.release(); + Path lockFile = getLockMarkerFile(testDir); + try (var locked = subject.lock(testDir)) { + assertTrue(isLocked(testDir)); + assertEquals(new File(testDir, ".tycholock").getCanonicalPath(), lockFile.toRealPath().toString()); } } @Test public void testReuseLockerObject() throws IOException { - FileLockerImpl fileLocker = subject.getFileLocker(newTestFile()); - lockAndRelease(fileLocker); - lockAndRelease(fileLocker); + File file = newTestFile(); + lockAndRelease(file); + lockAndRelease(file); } - private void lockAndRelease(FileLockerImpl fileLocker) { - assertFalse(fileLocker.isLocked()); - fileLocker.lock(); - assertTrue(fileLocker.isLocked()); - fileLocker.release(); - assertFalse(fileLocker.isLocked()); + private void lockAndRelease(File file) throws IOException { + assertFalse(isLocked(file)); + try (var locked = subject.lock(file)) { + assertTrue(isLocked(file)); + } + assertFalse(isLocked(file)); } @Test public void testLockReentranceDifferentLocker() throws IOException { final File testFile = newTestFile(); - FileLocker fileLocker1 = subject.getFileLocker(testFile); - FileLocker fileLocker2 = subject.getFileLocker(testFile); - fileLocker1.lock(); - try { - fileLocker2.lock(0L); + try (var locked = subject.lock(testFile)) { + subject.lock(testFile, 0L); fail("lock already held by same VM but could be acquired a second time"); } catch (LockTimeoutException e) { // expected - } finally { - fileLocker1.release(); } } @Test public void testLockedByOtherProcess() throws Exception { File testFile = newTestFile(); - FileLocker locker = subject.getFileLocker(testFile); LockProcess lockProcess = new LockProcess(testFile, 200L); lockProcess.lockFileInForkedProcess(); - try { - locker.lock(0L); + try (var locked = subject.lock(testFile, 0L)) { fail("lock already held by other VM but could be acquired a second time"); } catch (LockTimeoutException e) { // expected @@ -136,49 +111,35 @@ public void testLockedByOtherProcess() throws Exception { @Test public void testTimeout() throws Exception { File testFile = newTestFile(); - FileLocker locker = subject.getFileLocker(testFile); long waitTime = 1000L; LockProcess lockProcess = new LockProcess(testFile, waitTime); long start = System.currentTimeMillis(); lockProcess.lockFileInForkedProcess(); - locker.lock(20000L); - try { + try (var locked = subject.lock(testFile, 20000L)) { long duration = System.currentTimeMillis() - start; assertTrue(duration >= waitTime); } finally { lockProcess.cleanup(); - locker.release(); } } - @Test - public void testRelease() throws Exception { - FileLockerImpl locker = subject.getFileLocker(newTestFile()); - assertFalse(locker.isLocked()); - // releasing without holding the lock should do nothing - locker.release(); - } - @Test public void testMarkerFileDeletion() throws Exception { - FileLockerImpl locker = subject.getFileLocker(newTestFile()); - locker.lock(); - assertTrue(locker.lockMarkerFile.isFile()); - locker.release(); - assertFalse(locker.lockMarkerFile.isFile()); + File file = newTestFile(); + Path lockFile = getLockMarkerFile(file); + try (var locked = subject.lock(file)) { + assertTrue(Files.isRegularFile(lockFile)); + } + assertFalse(Files.isRegularFile(lockFile)); } @Test public void testURLEncoding() throws IOException { File testFile = new File(tempFolder.getRoot(), "file with spaces" + new Random().nextInt()); File markerFile = new File(testFile.getAbsolutePath() + ".tycholock"); - FileLocker fileLocker = subject.getFileLocker(testFile); assertFalse(markerFile.isFile()); - fileLocker.lock(); - try { + try (var locked = subject.lock(testFile)) { assertTrue(markerFile.isFile()); - } finally { - fileLocker.release(); } } @@ -187,4 +148,17 @@ private File newTestFile() throws IOException { return testFile; } + private Path getLockMarkerFile(File file) { + return subject.getFileLocker(file.toPath()).fileLocker().lockMarkerFile; + } + + private boolean isLocked(File file) throws IOException { + try (var channel = FileChannel.open(getLockMarkerFile(file), StandardOpenOption.WRITE, + StandardOpenOption.CREATE); FileLock lock = channel.tryLock();) { + return lock == null; + } catch (OverlappingFileLockException e) { + return true; + } + } + } diff --git a/tycho-its/src/test/java/org/eclipse/tycho/test/pomDependencyConsider/LocalMavenRepositoryTool.java b/tycho-its/src/test/java/org/eclipse/tycho/test/pomDependencyConsider/LocalMavenRepositoryTool.java index 5e1be22158..1495af946a 100644 --- a/tycho-its/src/test/java/org/eclipse/tycho/test/pomDependencyConsider/LocalMavenRepositoryTool.java +++ b/tycho-its/src/test/java/org/eclipse/tycho/test/pomDependencyConsider/LocalMavenRepositoryTool.java @@ -27,7 +27,6 @@ import java.util.Set; import org.eclipse.tycho.FileLockService; -import org.eclipse.tycho.FileLocker; import org.eclipse.tycho.test.util.EnvironmentUtil; public class LocalMavenRepositoryTool { @@ -59,12 +58,8 @@ public File getArtifactFile(String groupId, String artifactId, String version, S public Set getArtifactIndexLines() throws IOException { File indexFile = getArtifactIndexFile(); - FileLocker locker = fileLockService.getFileLocker(indexFile); - locker.lock(); - try { + try (var locked = fileLockService.lock(indexFile)) { return readLines(indexFile); - } finally { - locker.release(); } } @@ -95,14 +90,10 @@ public void removeLinesFromMetadataIndex(String... linesToBeRemoved) throws IOEx private void filterLinesFromIndex(File indexFile, Set toBeRemoved) throws FileNotFoundException, IOException { - FileLocker locker = fileLockService.getFileLocker(indexFile); - locker.lock(); - try { + try (var locked = fileLockService.lock(indexFile)) { Set currentLines = readLines(indexFile); currentLines.removeAll(toBeRemoved); writeLines(indexFile, currentLines); - } finally { - locker.release(); } } diff --git a/tycho-p2-publisher-plugin/src/main/java/org/eclipse/tycho/plugins/p2/publisher/PublishProductMojo.java b/tycho-p2-publisher-plugin/src/main/java/org/eclipse/tycho/plugins/p2/publisher/PublishProductMojo.java index ffba1a56ff..7b96432091 100644 --- a/tycho-p2-publisher-plugin/src/main/java/org/eclipse/tycho/plugins/p2/publisher/PublishProductMojo.java +++ b/tycho-p2-publisher-plugin/src/main/java/org/eclipse/tycho/plugins/p2/publisher/PublishProductMojo.java @@ -30,7 +30,11 @@ import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.MojoFailureException; -import org.apache.maven.plugins.annotations.*; +import org.apache.maven.plugins.annotations.Component; +import org.apache.maven.plugins.annotations.LifecyclePhase; +import org.apache.maven.plugins.annotations.Mojo; +import org.apache.maven.plugins.annotations.Parameter; +import org.apache.maven.plugins.annotations.ResolutionScope; import org.codehaus.plexus.archiver.ArchiverException; import org.codehaus.plexus.archiver.UnArchiver; import org.eclipse.equinox.p2.metadata.expression.IExpression; @@ -43,7 +47,6 @@ import org.eclipse.tycho.ArtifactType; import org.eclipse.tycho.DependencyArtifacts; import org.eclipse.tycho.FileLockService; -import org.eclipse.tycho.FileLocker; import org.eclipse.tycho.Interpolator; import org.eclipse.tycho.PackagingType; import org.eclipse.tycho.PlatformPropertiesUtils; @@ -207,19 +210,15 @@ private File getExpandedLauncherBinaries() throws MojoExecutionException, MojoFa return unzipped.getAbsoluteFile(); } try { - FileLocker locker = fileLockService.getFileLocker(equinoxExecFeature); - locker.lock(); - try { + try (var locked = fileLockService.lock(equinoxExecFeature)) { // unzip now then: unzipped.mkdirs(); deflater.setSourceFile(equinoxExecFeature); deflater.setDestDirectory(unzipped); deflater.extract(); return unzipped.getAbsoluteFile(); - } finally { - locker.release(); } - } catch (ArchiverException e) { + } catch (ArchiverException | IOException e) { throw new MojoFailureException("Unable to unzip the equinox executable feature", e); } } diff --git a/tycho-packaging-plugin/src/main/java/org/eclipse/tycho/packaging/FeatureXmlTransformer.java b/tycho-packaging-plugin/src/main/java/org/eclipse/tycho/packaging/FeatureXmlTransformer.java index 4486197a25..ef56b2192e 100644 --- a/tycho-packaging-plugin/src/main/java/org/eclipse/tycho/packaging/FeatureXmlTransformer.java +++ b/tycho-packaging-plugin/src/main/java/org/eclipse/tycho/packaging/FeatureXmlTransformer.java @@ -15,6 +15,7 @@ import java.io.File; import java.io.IOException; +import java.util.Enumeration; import java.util.Map; import java.util.Objects; import java.util.function.BinaryOperator; @@ -31,7 +32,6 @@ import org.eclipse.tycho.ArtifactKey; import org.eclipse.tycho.ArtifactType; import org.eclipse.tycho.FileLockService; -import org.eclipse.tycho.FileLocker; import org.eclipse.tycho.IllegalArtifactReferenceException; import org.eclipse.tycho.TargetPlatform; import org.eclipse.tycho.model.Feature; @@ -157,9 +157,7 @@ private static String quote(String nullableString) { } private void setDownloadAndInstallSize(PluginRef pluginRefToEdit, File artifact) { - if (!pluginRefToEdit.hasInstallSize() && !pluginRefToEdit.hasDownloadSize()) { - return; - } + // TODO 375111 optionally disable this? long downloadSize = 0; long installSize = 0; if (artifact.isFile()) { @@ -168,23 +166,26 @@ private void setDownloadAndInstallSize(PluginRef pluginRefToEdit, File artifact) } else { log.info("Download/install size is not calculated for directory based bundle " + pluginRefToEdit.getId()); } - if (pluginRefToEdit.hasDownloadSize()) { - pluginRefToEdit.setDownloadSize(downloadSize / KBYTE); - } - if (pluginRefToEdit.hasInstallSize()) { - pluginRefToEdit.setInstallSize(installSize / KBYTE); - } + + pluginRefToEdit.setDownloadSize(downloadSize / KBYTE); + pluginRefToEdit.setInstallSize(installSize / KBYTE); } protected long getInstallSize(File location) { - FileLocker locker = fileLockService.getFileLocker(location); - locker.lock(); - try (JarFile jar = new JarFile(location)) { - return jar.stream().mapToLong(JarEntry::getSize).filter(s -> s > 0).sum(); + long installSize = 0; + try (var locked = fileLockService.lock(location); // + JarFile jar = new JarFile(location);) { + Enumeration entries = jar.entries(); + while (entries.hasMoreElements()) { + JarEntry entry = entries.nextElement(); + long entrySize = entry.getSize(); + if (entrySize > 0) { + installSize += entrySize; + } + } } catch (IOException e) { throw new RuntimeException("Could not determine installation size of file " + location, e); - } finally { - locker.release(); } + return installSize; } } diff --git a/tycho-packaging-plugin/src/main/java/org/eclipse/tycho/packaging/UpdateSiteAssembler.java b/tycho-packaging-plugin/src/main/java/org/eclipse/tycho/packaging/UpdateSiteAssembler.java index a275afbeaf..bd22800ab7 100644 --- a/tycho-packaging-plugin/src/main/java/org/eclipse/tycho/packaging/UpdateSiteAssembler.java +++ b/tycho-packaging-plugin/src/main/java/org/eclipse/tycho/packaging/UpdateSiteAssembler.java @@ -28,7 +28,6 @@ import org.codehaus.plexus.component.repository.exception.ComponentLookupException; import org.codehaus.plexus.util.FileUtils; import org.eclipse.tycho.FileLockService; -import org.eclipse.tycho.FileLocker; import org.eclipse.tycho.ReactorProject; import org.eclipse.tycho.core.ArtifactDependencyVisitor; import org.eclipse.tycho.core.FeatureDescription; @@ -199,15 +198,11 @@ private void unpackJar(File location, File outputJar) { unzip.setSourceFile(location); unzip.setDestDirectory(outputJar); - FileLocker locker = fileLockService.getFileLocker(location); - locker.lock(); - try { + try (var locked = fileLockService.lock(location)) { unzip.extract(); - } catch (ArchiverException e) { + } catch (ArchiverException | IOException e) { throw new RuntimeException("Could not unpack jar", e); - } finally { - locker.release(); - } + } } private void copyDir(File location, File outputJar) { diff --git a/tycho-testing-harness/src/main/java/org/eclipse/tycho/test/util/NoopFileLockService.java b/tycho-testing-harness/src/main/java/org/eclipse/tycho/test/util/NoopFileLockService.java index 51751e8ade..566e9d38b0 100644 --- a/tycho-testing-harness/src/main/java/org/eclipse/tycho/test/util/NoopFileLockService.java +++ b/tycho-testing-harness/src/main/java/org/eclipse/tycho/test/util/NoopFileLockService.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2011, 2012 SAP SE and others. + * Copyright (c) 2011, 2023 SAP SE and others. * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 * which accompanies this distribution, and is available at @@ -13,29 +13,21 @@ package org.eclipse.tycho.test.util; +import java.io.Closeable; import java.io.File; import org.eclipse.tycho.FileLockService; -import org.eclipse.tycho.FileLocker; -import org.eclipse.tycho.LockTimeoutException; public class NoopFileLockService implements FileLockService { @Override - public FileLocker getFileLocker(File file) { - return new FileLocker() { - - @Override - public void release() { - } - - @Override - public void lock() { - } + public Closeable lock(File file, long timeout) { + return lockVirtually(file); + } - @Override - public void lock(long timeout) throws LockTimeoutException { - } + @Override + public Closeable lockVirtually(File file) { + return () -> { }; }