1515 */
1616package nebula.plugin.dependencylock.dependencyfixture
1717
18- import java.util.concurrent.atomic.AtomicBoolean
1918import nebula.test.dependencies.DependencyGraph
2019import nebula.test.dependencies.GradleDependencyGenerator
2120
21+ import java.io.RandomAccessFile
22+ import java.nio.channels.FileLock
23+ import java.util.concurrent.atomic.AtomicBoolean
24+
2225class Fixture {
23- static AtomicBoolean created = new AtomicBoolean (false )
24- static String repo = new File (' build/testrepogen/mavenrepo' ). absolutePath
26+ /* * Project root (directory containing build/), derived from this class's location. */
27+ private static File getProjectRoot () {
28+ def source = Fixture . class. protectionDomain. codeSource. location
29+ def current = new File (source. toURI())
30+ if (current. file) {
31+ current = current. parentFile
32+ }
33+ while (current != null ) {
34+ def buildDir = new File (current, ' build' )
35+ if (buildDir. exists() && buildDir. directory) {
36+ return current
37+ }
38+ current = current. parentFile
39+ }
40+ throw new IllegalStateException (" Could not find project root (directory containing build/) from ${ source} " )
41+ }
42+
43+ private static final String TESTREPOGEN_DIR = new File (getProjectRoot(), ' build/testrepogen' ). absolutePath
44+ static final String repo = new File (TESTREPOGEN_DIR , ' mavenrepo' ). absolutePath
45+
46+ private static final AtomicBoolean created = new AtomicBoolean (false )
47+ private static final File LOCK_FILE = new File (TESTREPOGEN_DIR , ' .fixture.lock' )
48+ /* * Marker so we can detect if another spec overwrote the shared repo (e.g. old PathAwareDependencyDiffSpec). */
49+ private static final String FIXTURE_MARKER = ' nebula-dependency-lock-fixture-v1'
2550
2651 static createFixture () {
2752 def myGraph = [
@@ -43,13 +68,41 @@ class Fixture {
4368 ' circular:oneleveldeep:1.0.0 -> circular:a:1.0.0'
4469 ]
4570
46- def generator = new GradleDependencyGenerator (new DependencyGraph (myGraph))
71+ def generator = new GradleDependencyGenerator (new DependencyGraph (myGraph), TESTREPOGEN_DIR )
4772 generator. generateTestMavenRepo()
73+ new File (TESTREPOGEN_DIR , ' .fixture-marker' ). text = FIXTURE_MARKER
4874 }
4975
76+ /**
77+ * Creates the shared Maven repo once. Uses an absolute path and a file lock so that
78+ * when multiple test workers run in parallel, only one creates the repo and others wait.
79+ */
5080 static createFixtureIfNotCreated () {
51- if (! created. getAndSet(true )) {
52- createFixture()
81+ if (created. getAndSet(true )) {
82+ return
83+ }
84+ LOCK_FILE . parentFile. mkdirs()
85+ def raf = new RandomAccessFile (LOCK_FILE , ' rw' )
86+ FileLock lock = null
87+ try {
88+ lock = raf. channel. lock()
89+ def markerFile = new File (TESTREPOGEN_DIR , ' .fixture-marker' )
90+ if (! markerFile. exists() || markerFile. text != FIXTURE_MARKER ) {
91+ def mavenrepoDir = new File (TESTREPOGEN_DIR , ' mavenrepo' )
92+ if (mavenrepoDir. exists()) {
93+ mavenrepoDir. deleteDir()
94+ }
95+ createFixture()
96+ }
97+ } finally {
98+ if (lock != null ) {
99+ try {
100+ lock. release()
101+ } catch (IOException ignored) {}
102+ }
103+ try {
104+ raf. close()
105+ } catch (IOException ignored) {}
53106 }
54107 }
55108}
0 commit comments