From d4aefd34fcea8fad80566c94115db0c8658701cb Mon Sep 17 00:00:00 2001 From: msosnicki Date: Mon, 10 Aug 2026 10:04:29 +0200 Subject: [PATCH] Add missing Repository parsing methods --- .../java/coursierapi/RepositoryParser.java | 18 ++++++++ .../error/RepositoryParsingError.java | 34 ++++++++++++++ .../error/SimpleRepositoryParsingError.java | 13 ++++++ .../coursier/internal/api/ApiHelper.scala | 20 +++++++++ .../scala/coursierapi/RepositoryTests.scala | 44 +++++++++++++++++++ 5 files changed, 129 insertions(+) create mode 100644 interface/src/main/java/coursierapi/RepositoryParser.java create mode 100644 interface/src/main/java/coursierapi/error/RepositoryParsingError.java create mode 100644 interface/src/main/java/coursierapi/error/SimpleRepositoryParsingError.java diff --git a/interface/src/main/java/coursierapi/RepositoryParser.java b/interface/src/main/java/coursierapi/RepositoryParser.java new file mode 100644 index 0000000..9603d4a --- /dev/null +++ b/interface/src/main/java/coursierapi/RepositoryParser.java @@ -0,0 +1,18 @@ +package coursierapi; + +import coursier.internal.api.ApiHelper; + +import java.util.List; + +public final class RepositoryParser { + + private RepositoryParser() {} + + public static Repository repository(String input) { + return ApiHelper.parseRepository(input); + } + + public static List repositories(List inputs) { + return ApiHelper.parseRepositories(inputs); + } +} diff --git a/interface/src/main/java/coursierapi/error/RepositoryParsingError.java b/interface/src/main/java/coursierapi/error/RepositoryParsingError.java new file mode 100644 index 0000000..a2196c8 --- /dev/null +++ b/interface/src/main/java/coursierapi/error/RepositoryParsingError.java @@ -0,0 +1,34 @@ +package coursierapi.error; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +public class RepositoryParsingError extends CoursierError { + + private final List errors; + + private RepositoryParsingError(List errors, String message) { + super(message); + this.errors = Collections.unmodifiableList(errors); + } + + public static RepositoryParsingError of(SimpleRepositoryParsingError error, SimpleRepositoryParsingError... errors) { + List errorsList = new ArrayList<>(); + errorsList.add(error); + errorsList.addAll(Arrays.asList(errors)); + + StringBuilder b = new StringBuilder(); + for (SimpleRepositoryParsingError errorElement : errorsList) { + b.append(errorElement.getMessage()); + b.append('\n'); + } + + return new RepositoryParsingError(errorsList, b.toString()); + } + + public List getErrors() { + return errors; + } +} diff --git a/interface/src/main/java/coursierapi/error/SimpleRepositoryParsingError.java b/interface/src/main/java/coursierapi/error/SimpleRepositoryParsingError.java new file mode 100644 index 0000000..57a17ee --- /dev/null +++ b/interface/src/main/java/coursierapi/error/SimpleRepositoryParsingError.java @@ -0,0 +1,13 @@ +package coursierapi.error; + +public abstract class SimpleRepositoryParsingError extends CoursierError { + + SimpleRepositoryParsingError(String message) { + super(message); + } + + public static SimpleRepositoryParsingError of(String message) { + return new SimpleRepositoryParsingError(message) { + }; + } +} diff --git a/interface/src/main/scala/coursier/internal/api/ApiHelper.scala b/interface/src/main/scala/coursier/internal/api/ApiHelper.scala index b5322f3..f98d1ea 100644 --- a/interface/src/main/scala/coursier/internal/api/ApiHelper.scala +++ b/interface/src/main/scala/coursier/internal/api/ApiHelper.scala @@ -68,6 +68,25 @@ object ApiHelper { dependency(dep) } + def parseRepository(s: String): coursierapi.Repository = + coursier.parse.RepositoryParser.repository(s) match { + case Left(err) => + throw new IllegalArgumentException(err) + case Right(repo) => + repository(repo) + } + + def parseRepositories(inputs: ju.List[String]): ju.List[coursierapi.Repository] = + coursier.parse.RepositoryParser.repositories(inputs.asScala.toSeq).either match { + case Left(errs) => + throw coursierapi.error.RepositoryParsingError.of( + coursierapi.error.SimpleRepositoryParsingError.of(errs.head), + errs.tail.map(coursierapi.error.SimpleRepositoryParsingError.of): _* + ) + case Right(repos) => + repos.map(repository).asJava + } + private[this] def authenticationOpt(credentials: Credentials): Option[Authentication] = if (credentials == null) None @@ -282,6 +301,7 @@ object ApiHelper { coursierapi.IvyRepository.of(ivy.pattern.string) .withMetadataPattern(mdPatternOpt.orNull) .withCredentials(credentialsOpt.orNull) + .withDropInfoAttributes(ivy.dropInfoAttributes) case other => ApiRepo(other) } diff --git a/interface/src/test/scala/coursierapi/RepositoryTests.scala b/interface/src/test/scala/coursierapi/RepositoryTests.scala index 5aa5bd8..d651ae0 100644 --- a/interface/src/test/scala/coursierapi/RepositoryTests.scala +++ b/interface/src/test/scala/coursierapi/RepositoryTests.scala @@ -2,8 +2,10 @@ package coursierapi import coursier.{LocalRepositories, Repositories} import coursier.internal.api.ApiHelper +import scala.collection.JavaConverters._ import utest._ + object RepositoryTests extends TestSuite { val tests = Tests { @@ -38,6 +40,48 @@ object RepositoryTests extends TestSuite { } } + test("parser") { + test("central") { + val parsed = ApiHelper.repository(RepositoryParser.repository("central")) + val expected = coursier.parse.RepositoryParser.repository("central").toOption.get + assert(parsed == expected) + } + + test("ivy2Local") { + val parsed = ApiHelper.repository(RepositoryParser.repository("ivy2Local")) + val expected = coursier.parse.RepositoryParser.repository("ivy2Local").toOption.get + assert(parsed == expected) + } + + test("ivyPattern") { + val input = "ivy:https://repo/[organisation]/[module]/[revision]/[artifact].[ext]" + val parsed = ApiHelper.repository(RepositoryParser.repository(input)) + val expected = coursier.parse.RepositoryParser.repository(input).toOption.get + assert(parsed == expected) + } + + test("invalidSingle") { + val input = "ivy:[unclosed" + assertThrows[IllegalArgumentException] { + RepositoryParser.repository(input) + } + } + + test("batch") { + val inputs = List("central", "ivy2Local") + val parsed = RepositoryParser.repositories(inputs.asJava).asScala.map(ApiHelper.repository) + val expected = inputs.map(s => coursier.parse.RepositoryParser.repository(s).toOption.get) + assert(parsed.toList == expected) + } + + test("invalidBatch") { + val ex = assertThrows[coursierapi.error.RepositoryParsingError] { + RepositoryParser.repositories(List("ivy:[unclosed", "ivy:[alsoUnclosed").asJava) + } + assert(ex.getErrors.size() == 2) + } + } + } }