Skip to content

Commit 4356c75

Browse files
Eyjafjallajokull-Romanroivanov
andauthored
SDKJAVA-522: FIX url and local path (#46)
* SDKJAVA-522: FIX url and local path Signed-off-by: roivanov <ext-roman.ivanov@here.com> * SDKJAVA-522: fix tests and formatting --signoff Signed-off-by: roivanov <ext-roman.ivanov@here.com> * SDKJAVA-522: formatting once again Signed-off-by: roivanov <ext-roman.ivanov@here.com> * SDKJAVA-522: fix test Signed-off-by: roivanov <ext-roman.ivanov@here.com> --------- Signed-off-by: roivanov <ext-roman.ivanov@here.com> Co-authored-by: roivanov <ext-roman.ivanov@here.com>
1 parent 805d38c commit 4356c75

3 files changed

Lines changed: 93 additions & 70 deletions

File tree

plugin/src/main/scala/com/here/bom/internal/BomReader.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,10 +64,10 @@ class BomReader(pomLocator: IvyPomLocator, logger: Logger, scalaBinaryVersion: S
6464
}
6565

6666
private def readPom(moduleId: NormalizedArtifact): PomReader = {
67-
val pomFile = pomLocator
68-
.getPomFile(moduleId)
67+
val url = pomLocator
68+
.getPomUrl(moduleId)
69+
.orElse(pomLocator.getPomFile(moduleId).map(_.toURI.toURL))
6970
.getOrElse(sys.error(s"Failed to resolve ${moduleId}"))
70-
val url = pomFile.asURL
7171
logger.debug(f"Reading pom file $url")
7272
new PomReader(url, new URLResource(url))
7373
}

plugin/src/main/scala/com/here/bom/internal/IvyPomLocator.scala

Lines changed: 84 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,11 @@
1818
*/
1919
package com.here.bom.internal
2020

21+
import lmcoursier.internal.shaded.coursier.core.shaded.geny.Generator.from
2122
import sbt.File
2223
import sbt.util.Logger
2324

25+
import java.net.{URI, URL}
2426
import java.io.FileInputStream
2527
import java.util.Properties
2628
import scala.collection.JavaConverters.*
@@ -106,75 +108,96 @@ class IvyPomLocator(resolver: DependencyResolutionProxy, ivyHome: File, logger:
106108
}
107109
}
108110

109-
def findLocalPomFile(moduleId: NormalizedArtifact): Option[File] = {
110-
/*
111-
If the artifact was resolved by Ivy, the pom file will be stored under .ivy2 directory.
112-
But if it was previously resolved by Maven, Ivy will not download it second time and just store the reference
113-
Original POM file could be under either .ivy or .m2 directory:
114-
115-
Examples:
116-
1) Pom file under .ivy directory:
117-
$ ~/s/vsvu-utils (batch-support)> cat ~/.ivy2/cache/com.here.platform/sdk-dep-common_2.12/ivydata-1.0.46.properties
118-
#ivy cached data file for com.here.platform#sdk-dep-common_2.12;1.0.46
119-
#Mon Jan 17 12:20:26 CET 2022
120-
artifact\:sdk-dep-common_2.12\#pom.original\#pom\#-691773007.location=~/.m2/repository/com/here/platform/sdk-dep-common_2.12/1.0.46/sdk-dep-common_2.12-1.0.46.pom
121-
artifact\:sdk-dep-common_2.12\#pom.original\#pom\#-691773007.is-local=true
122-
artifact\:sdk-dep-common_2.12\#pom.original\#pom\#-691773007.exists=true
123-
artifact\:ivy\#ivy\#xml\#-1235680096.exists=true
124-
artifact\:ivy\#ivy\#xml\#-1235680096.location=~/.m2/repository/com/here/platform/sdk-dep-common_2.12/1.0.46/sdk-dep-common_2.12-1.0.46.pom
125-
resolver=sbt-chain
126-
artifact\:ivy\#ivy\#xml\#-1235680096.is-local=true
127-
2) Pom file downloaded by Maven first:
128-
$ ~/s/vsvu-utils (batch-support)> cat ~/.ivy2/cache/com.here.platform/sdk-dep-common_2.12/ivydata-1.0.47.properties
129-
#ivy cached data file for com.here.platform#sdk-dep-common_2.12;1.0.47
130-
#Thu Jan 06 12:38:21 CET 2022
131-
artifact\:sdk-dep-common_2.12\#pom.original\#pom\#-691766754.is-local=false
132-
artifact\:sdk-dep-common_2.12\#pom.original\#pom\#-691766754.exists=true
133-
artifact\:ivy\#ivy\#xml\#-1235673843.exists=true
134-
artifact\:ivy\#ivy\#xml\#-1235673843.location=https\://artifactory.in.here.com/artifactory/here-olp-sit/com/here/platform/sdk-dep-common_2.12/1.0.47/sdk-dep-common_2.12-1.0.47.pom
135-
artifact\:ivy\#ivy\#xml\#-1235673843.is-local=false
136-
artifact\:sdk-dep-common_2.12\#pom.original\#pom\#-691766754.location=https\://artifactory.in.here.com/artifactory/here-olp-sit/com/here/platform/sdk-dep-common_2.12/1.0.47/sdk-dep-common_2.12-1.0.47.pom
137-
*/
138-
val localIvyPomLocation = new File(
111+
private def findLocalPomFile(moduleId: NormalizedArtifact): Option[File] =
112+
resolvePomUrl(moduleId).flatMap(urlToLocalFile)
113+
114+
def getPomUrl(moduleId: NormalizedArtifact): Option[URL] =
115+
resolvePomUrl(moduleId)
116+
117+
/** Canonical local ivy original path (if Ivy materialized it). */
118+
private def ivyOriginalPath(moduleId: NormalizedArtifact): File =
119+
new File(
139120
ivyHome,
140121
s"/cache/${moduleId.group}/${moduleId.name}/ivy-${moduleId.version}.xml.original"
141122
)
142-
if (localIvyPomLocation.exists()) {
143-
logger.debug(f"Found local pom file: $localIvyPomLocation")
144-
Some(localIvyPomLocation)
145-
} else {
146-
val ivyPropsFile = new File(
147-
ivyHome,
148-
s"/cache/${moduleId.group}/${moduleId.name}/ivydata-${moduleId.version}.properties"
149-
)
150-
logger.debug(f"Trying to load local pom file: $ivyPropsFile")
151-
referencedPomLocation(ivyPropsFile)
152-
}
123+
124+
/** ivydata-<ver>.properties path. */
125+
private def ivyDataPath(moduleId: NormalizedArtifact): File =
126+
new File(
127+
ivyHome,
128+
s"/cache/${moduleId.group}/${moduleId.name}/ivydata-${moduleId.version}.properties"
129+
)
130+
131+
/** Convert URL → File only for file: scheme. */
132+
private def urlToLocalFile(u: URL): Option[File] =
133+
if (u.getProtocol.equalsIgnoreCase("file")) Some(new File(u.toURI)) else None
134+
135+
/**
136+
* If the artifact was resolved by Ivy, the POM will be under ~/.ivy2/cache/... as
137+
* ivy-<ver>.xml.original. If it was previously resolved by Maven, Ivy may not download it again
138+
* and only store a reference in ivydata-<ver>.properties. That .location can be a local
139+
* filesystem path (~/.m2/...) or a remote URL (https://...).
140+
*
141+
* Examples: 1) Local POM (ivy):
142+
* ~/.ivy2/cache/com.here.platform/sdk-dep-common_2.12/ivydata-1.0.46.properties
143+
* artifact:...pom.original...location=~/.m2/repository/.../sdk-dep-common_2.12-1.0.46.pom ...
144+
* is-local=true
145+
*
146+
* 2) Remote POM (downloaded by Maven first):
147+
* ~/.ivy2/cache/com.here.platform/sdk-dep-common_2.12/ivydata-1.0.47.properties
148+
* artifact:...pom.original...location=https://artifactory.../sdk-dep-common_2.12-1.0.47.pom ...
149+
* is-local=false
150+
*
151+
* Resolution strategy:
152+
* - If ivy-<ver>.xml.original exists => return its file: URL.
153+
* - Else read ivydata .location: * if it parses as URL with scheme => return that URL (handles
154+
* https:// or file:/) * else if it's a filesystem path that exists => return file: URL * else
155+
* \=> None
156+
*/
157+
158+
private def resolvePomUrl(moduleId: NormalizedArtifact): Option[URL] = {
159+
val local = ivyOriginalPath(moduleId)
160+
if (local.exists()) return Some(local.toURI.toURL)
161+
referencedPomUrl(ivyDataPath(moduleId))
153162
}
154163

155-
private def referencedPomLocation(ivyPropertyFile: File): Option[File] = {
164+
/** Read a usable URL from ivydata (normalizes “https\://”, handles file paths). */
165+
private def referencedPomUrl(ivyPropertyFile: File): Option[URL] = {
166+
if (!ivyPropertyFile.exists()) return None
167+
156168
val properties = new Properties()
157-
if (ivyPropertyFile.exists()) {
158-
val is = new FileInputStream(ivyPropertyFile)
159-
try {
160-
properties.load(is)
161-
} finally {
162-
is.close()
163-
}
169+
val is = new FileInputStream(ivyPropertyFile)
170+
try properties.load(is)
171+
finally is.close()
172+
173+
val locationKeyOpt: Option[String] =
174+
properties
175+
.keys()
176+
.asScala
177+
.collect { case s: String if s.endsWith(".location") => s }
178+
.headOption
179+
180+
locationKeyOpt.flatMap { locationKey =>
181+
val rawLocation0 = properties.getProperty(locationKey)
182+
val rawLocation = Option(rawLocation0).map(_.replace("\\:", ":"))
164183

165-
val locationKey =
166-
properties.keys().asScala.find(key => key.asInstanceOf[String].endsWith(".location"))
167-
if (locationKey.isEmpty) {
168-
logger.warn(f"No *.location entry in the file $ivyPropertyFile")
184+
rawLocation.flatMap { loc =>
185+
// Prefer interpreting as a URI; if it has a scheme, we’re done.
186+
try {
187+
val uri = new URI(loc)
188+
if (uri.getScheme != null) Some(uri.toURL)
189+
else {
190+
// No scheme => treat as filesystem path and require it to exist.
191+
val file = new File(loc)
192+
if (file.exists()) Some(file.toURI.toURL) else None
193+
}
194+
} catch {
195+
case _: Exception =>
196+
// Fallback: treat as filesystem path if valid & exists.
197+
val file = new File(loc)
198+
if (file.exists()) Some(file.toURI.toURL) else None
199+
}
169200
}
170-
locationKey.map(k => {
171-
val f = new File(properties.getProperty(k.asInstanceOf[String]))
172-
require(f.exists(), s"File $f doesn't exist, is artifact cache corrupted?")
173-
f
174-
})
175-
} else {
176-
logger.debug(f"File: $ivyPropertyFile not exists")
177-
None
178201
}
179202
}
180203
}

plugin/src/test/scala/com/here/bom/internal/BomReaderSpec.scala

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,9 @@ class BomReaderSpec extends AnyFlatSpec with Matchers with MockFactory {
3535

3636
val bomReader = new BomReader(pomLocatorMock, loggerMock, scalaBinaryVersion)
3737

38-
(pomLocatorMock.getPomFile _)
38+
(pomLocatorMock.getPomUrl _)
3939
.expects(*)
40-
.returns(Some(createMockPomFile("com.test", "test_bom", "1.0", false)))
40+
.returns(Some(createMockPomFile("com.test", "test_bom", "1.0", false).toURI.toURL))
4141

4242
val bom = bomReader.makeBom(ModuleID("com.test", "test_bom", "1.0"))
4343
bom should not be (null)
@@ -55,19 +55,19 @@ class BomReaderSpec extends AnyFlatSpec with Matchers with MockFactory {
5555

5656
val bomReader = new BomReader(pomLocatorMock, loggerMock, scalaBinaryVersion)
5757

58-
(pomLocatorMock.getPomFile _)
58+
(pomLocatorMock.getPomUrl _)
5959
.expects(where((moduleId: NormalizedArtifact) => {
6060
moduleId.group.equals("com.test") && moduleId.name
6161
.equals("test_bom_parent") && moduleId.version.equals("1.0")
6262
}))
63-
.returns(Some(createMockPomFile("com.test", "test_bom_parent", "1.0", false)))
63+
.returns(Some(createMockPomFile("com.test", "test_bom_parent", "1.0", false).toURI.toURL))
6464

65-
(pomLocatorMock.getPomFile _)
65+
(pomLocatorMock.getPomUrl _)
6666
.expects(where((moduleId: NormalizedArtifact) => {
6767
moduleId.group.equals("com.test") && moduleId.name.equals("test_bom") && moduleId.version
6868
.equals("1.0")
6969
}))
70-
.returns(Some(createMockPomFile("com.test", "test_bom", "1.0", true)))
70+
.returns(Some(createMockPomFile("com.test", "test_bom", "1.0", true).toURI.toURL))
7171

7272
val bom = bomReader.makeBom(ModuleID("com.test", "test_bom", "1.0"))
7373
bom should not be (null)

0 commit comments

Comments
 (0)