Semantik der Tools zur Abhängigkeitsauflösung

Tool zur Lösung von Abhängigkeiten


Ein Abhängigkeitsauflöser (im Folgenden als Resolver bezeichnet, ca. Transl.) Oder Paketmanager ist ein Programm, das einen konsistenten Satz von Modulen unter Berücksichtigung der vom Benutzer festgelegten Einschränkungen definiert.


Einschränkungen werden normalerweise durch Modulnamen und Versionsnummern angegeben. Im JVM-Ökosystem für Maven-Module wird auch der Organisationsname (Gruppen-ID) angegeben. Darüber hinaus können Einschränkungen Versionsbereiche, ausgeschlossene Module, Versionsüberschreibungen usw. umfassen.


Die drei Hauptkategorien von Paketen werden durch Betriebssystempakete (Homebrew-, Debian-Pakete usw.) dargestellt.
Module für bestimmte Programmiersprachen (CPAN, RubyGem, Maven usw.) und anwendungsspezifische Erweiterungen (Eclipse-Plugins, IntelliJ-Plugins, VS-Code-Erweiterungen).


Resolversemantik


In erster Näherung können wir die Abhängigkeiten der Module als DAG (gerichteter azyklischer Graph, gerichteter azyklischer Graph) darstellen.


Diese Darstellung wird als Abhängigkeitsgraph bezeichnet. Betrachten Sie die Abhängigkeiten zweier Module:


  • a:1.0 hängt von c:1.0
  • b:1.0 hängt von c:1.0 und d:1.0

 +-----+ +-----+ |a:1.0| |b:1.0| +--+--+ +--+--+ | | +<-------+ | | vv +--+--+ +--+--+ |c:1.0| |d:1.0| +-----+ +-----+ 

Wenn das Modul von a:1.0 und b:1.0 abhängt, wird eine vollständige Liste der Abhängigkeiten angezeigt a:1.0 , b:1.0 , c:1.0 und d:1.0 . Und das ist nur eine Baumtour.


Die Situation wird komplizierter, wenn transitive Abhängigkeiten durch eine Reihe von Versionen angegeben werden:


  • a:1.0 hängt von c:1.0
  • b:1.0 hängt von c:[1.0,2) und d:1.0

 +-----+ +-----+ |a:1.0| |b:1.0| +--+--+ +--+--+ | | | +-----------+ | | | vvv +--+--+ +--+------+ +--+--+ |c:1.0| |c:[1.0,2)| |d:1.0| +-----+ +---------+ +-----+ 

Oder wenn für transitive Abhängigkeiten unterschiedliche Versionen angegeben sind:


  • a:1.0 hängt von c:1.0
  • b:1.0 hängt von c:1.2 und d:1.2

Oder wenn Ausnahmen für die Abhängigkeit ausgelöst werden:


  • Abhängigkeit von a:1.0 , abhängig von c:1.0 , ausgenommen c:*
  • b:1.0 hängt von c:1.2 und d:1.2

Verschiedene Resolver interpretieren die von den Benutzern festgelegten Einschränkungen unterschiedlich. Ich nenne solche Regeln die Semantik von Resolvern.


Möglicherweise müssen Sie einige dieser Semantiken kennen, zum Beispiel:


  • Semantik Ihres eigenen Moduls (bestimmt durch das von Ihnen verwendete Build-Tool);
  • die Semantik der von Ihnen verwendeten Bibliotheken (bestimmt durch das vom Autor verwendete Build-Tool);
  • Die Semantik der Module, die Ihr Modul als Abhängigkeit verwendet (definiert durch das Endbenutzer-Build-Tool).

Tools zur Abhängigkeitsauflösung im JVM-Ökosystem


Da ich sbt , muss ich hauptsächlich im JVM-Ökosystem arbeiten.


Semantics Maven: Nächste gewinnt


In Diagrammen, in denen ein Abhängigkeitskonflikt besteht (im Abhängigkeitsdiagramm a gibt es viele verschiedene Versionen der Komponente d , z. B. d:1.0 und d:2.0 ), verwendet Maven die Strategie der nächsten Gewinne , um den Konflikt zu lösen.


Das Lösen von Abhängigkeitskonflikten ist ein Prozess, der bestimmt, welche Version eines Artefakts ausgewählt wird, wenn mehrere verschiedene Versionen desselben Artefakts unter den Abhängigkeiten gefunden werden. Maven wählt die nächstgelegene Definition aus. Das heißt verwendet die Version, die Ihrem Projekt im Abhängigkeitsbaum am nächsten kommt.
Sie können jederzeit garantieren, dass Sie die richtige Version verwenden, indem Sie sie explizit im POM des Projekts deklarieren. Beachten Sie, dass die erste ausgewählt wird, wenn zwei Versionen der Abhängigkeit dieselbe Tiefe im Baum haben. Die nächstgelegene Definition bedeutet, dass die Version verwendet wird, die dem Projekt im Abhängigkeitsbaum am nächsten liegt. Wenn zum Beispiel die Abhängigkeiten für A , B und C als A -> B -> C -> D 2.0 und A -> E -> D 1.0 , wird beim Erstellen von A D 1.0 verwendet, weil Der Weg von A nach D über E kürzer (als über B und C , ca. transl.).

Dies bedeutet, dass viele mit Maven veröffentlichte Java-Module unter Verwendung der Semantik der nearest-wins kompiliert wurden. Erstellen Sie zur Veranschaulichung eine einfache pom.xml :


 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.example</groupId> <artifactId>foo</artifactId> <version>1.0.0</version> <packaging>jar</packaging> <dependencyManagement> <dependencies> <dependency> <groupId>com.typesafe.play</groupId> <artifactId>play-ws-standalone_2.12</artifactId> <version>1.0.1</version> </dependency> </dependencies> </dependencyManagement> </project> 

mvn dependency:build-classpath gibt den aufgelösten classpath .
Es ist bemerkenswert, dass der resultierende Baum com.typesafe:config:1.2.0 , obwohl Akka 2.5.3 transitiv von com.typesafe:config:1.3.1 abhängig ist.


mvn dependency:tree gibt diese visuelle Bestätigung:


 [INFO] --- maven-dependency-plugin:2.8:tree (default-cli) @ foo --- [INFO] com.example:foo:jar:1.0.0 [INFO] \- com.typesafe.play:play-ws-standalone_2.12:jar:1.0.1:compile [INFO] +- org.scala-lang:scala-library:jar:2.12.2:compile [INFO] +- javax.inject:javax.inject:jar:1:compile [INFO] +- com.typesafe:ssl-config-core_2.12:jar:0.2.2:compile [INFO] | +- com.typesafe:config:jar:1.2.0:compile [INFO] | \- org.scala-lang.modules:scala-parser-combinators_2.12:jar:1.0.4:compile [INFO] \- com.typesafe.akka:akka-stream_2.12:jar:2.5.3:compile [INFO] +- com.typesafe.akka:akka-actor_2.12:jar:2.5.3:compile [INFO] | \- org.scala-lang.modules:scala-java8-compat_2.12:jar:0.8.0:compile [INFO] \- org.reactivestreams:reactive-streams:jar:1.0.0:compile 

Viele Bibliotheken bieten Abwärtskompatibilität, aber die direkte Kompatibilität ist mit wenigen Ausnahmen nicht garantiert, was alarmierend ist.


Semantik von Apache Ivy: Neueste Siege


Standardmäßig verwendet Apache Ivy die Strategie der neuesten Gewinne , um Abhängigkeitskonflikte zu lösen.


Wenn dieser Container nicht vorhanden ist, wird der Standardkonfliktmanager für alle Module verwendet. Der aktuelle Standard-Konfliktmanager ist "Neueste Version".
Hinweis: Der Containerkonflikt ist eine der Ivy-Dateien.

Bis zur Version SBT 1.3.x interne Abhängigkeitsauflöser Apache Ivy. Die zuvor verwendete pom.xml wird in SBT etwas kurz beschrieben:


 ThisBuild / scalaVersion := "2.12.8" ThisBuild / organization := "com.example" ThisBuild / version := "1.0.0-SNAPSHOT" lazy val root = (project in file(".")) .settings( name := "foo", libraryDependencies += "com.typesafe.play" %% "play-ws-standalone" % "1.0.1", ) 

sbt shell in der sbt shell show externalDependencyClasspath , um den aufgelösten Klassenpfad sbt shell . Es sollte die Version von com.typesafe:config:1.3.1 . Außerdem wird weiterhin die folgende Warnung angezeigt:


 [warn] There may be incompatibilities among your library dependencies; run 'evicted' to see detailed eviction warnings. 

sbt shell Sie den evicted sbt shell in der sbt shell , erhalten Sie einen Konfliktlösungsbericht:


 sbt:foo> evicted [info] Updating ... [info] Done updating. [info] Here are other dependency conflicts that were resolved: [info] * com.typesafe:config:1.3.1 is selected over 1.2.0 [info] +- com.typesafe.akka:akka-actor_2.12:2.5.3 (depends on 1.3.1) [info] +- com.typesafe:ssl-config-core_2.12:0.2.2 (depends on 1.2.0) [info] * com.typesafe:ssl-config-core_2.12:0.2.2 is selected over 0.2.1 [info] +- com.typesafe.play:play-ws-standalone_2.12:1.0.1 (depends on 0.2.2) [info] +- com.typesafe.akka:akka-stream_2.12:2.5.3 (depends on 0.2.1) 

In der Semantik der latest-wins bedeutet die Angabe von config:1.2.0 in der Praxis, dass Sie mir Version 1.2.0 oder höher zur Verfügung stellen.
Dieses Verhalten ist etwas vorzuziehen als bei der Strategie der nearest-wins , da die Versionen der transitiven Bibliotheken nicht herabgestuft werden. Der evicted Anruf sollte jedoch prüfen, ob die Ersetzungen korrekt vorgenommen wurden.


Semantik-Kurier: Neueste Siege


Bevor wir uns der Beschreibung der Semantik nähern, werde ich eine wichtige Frage beantworten - wie wird Coursier ausgesprochen? Laut Alex Arshambos Notiz wird es als Chick- Sie ausgesprochen.


Interessanterweise enthält die Dokumentation für Coursier eine Seite zur Versionierung , auf der die Semantik der Auflösung von Abhängigkeiten erläutert wird.


Betrachten Sie den Schnittpunkt gegebener Intervalle:
  • Wenn es leer ist (Intervalle überschneiden sich nicht), liegt ein Konflikt vor.
  • Wenn keine Intervalle angegeben sind, wird angenommen, dass der Schnittpunkt durch (,) dargestellt wird (das Intervall, das allen Versionen entspricht).
    Betrachten Sie dann bestimmte Versionen:
    • Wir verwerfen bestimmte Versionen unterhalb der Grenzen des Intervalls.
    • Wenn bestimmte Versionen über den Grenzen des Intervalls liegen, liegt ein Konflikt vor.
    • Wenn sich bestimmte Versionen innerhalb der Grenzen des Intervalls befinden, sollte das Ergebnis das neueste sein.
    • Wenn es keine spezifischen Versionen innerhalb oder oberhalb der Grenzen des Intervalls gibt, sollte das Ergebnis das Intervall sein.

Weil es soll also - das ist die Semantik der latest-wins .
Sie können dies überprüfen, indem Sie sbt 1.3.0-RC3 , das Coursier verwendet.


 ThisBuild / scalaVersion := "2.12.8" ThisBuild / organization := "com.example" ThisBuild / version := "1.0.0-SNAPSHOT" lazy val root = (project in file(".")) .settings( name := "foo", libraryDependencies += "com.typesafe.play" %% "play-ws-standalone" % "1.0.1", ) 

sbt 1.3.0-RC3 Sie show externalDependencyClasspath von der Konsole sbt 1.3.0-RC3 com.typesafe:config:1.3.1 , wird erwartungsgemäß com.typesafe:config:1.3.1 . Der Konfliktlösungsbericht berichtet dasselbe:


 sbt:foo> evicted [info] Here are other dependency conflicts that were resolved: [info] * com.typesafe:config:1.3.1 is selected over 1.2.0 [info] +- com.typesafe.akka:akka-actor_2.12:2.5.3 (depends on 1.3.1) [info] +- com.typesafe:ssl-config-core_2.12:0.2.2 (depends on 1.2.0) [info] * com.typesafe:ssl-config-core_2.12:0.2.2 is selected over 0.2.1 [info] +- com.typesafe.play:play-ws-standalone_2.12:1.0.1 (depends on 0.2.2) [info] +- com.typesafe.akka:akka-stream_2.12:2.5.3 (depends on 0.2.1) 

Hinweis: Apache Ivy emuliert die Semantik der nearest-wins ?


Beim Auflösen von ivy.xml aus dem Maven-Repository konvertiert Ivy die POM Datei und legt das Attribut force="true" in ivy.xml im Cache ab.


Beispiel: cat ~/.ivy2/cache/com.typesafe.akka/akka-actor_2.12/ivy-2.5.3.xml :


  <dependencies> <dependency org="org.scala-lang" name="scala-library" rev="2.12.2" force="true" conf="compile->compile(*),master(compile);runtime->runtime(*)"/> <dependency org="com.typesafe" name="config" rev="1.3.1" force="true" conf="compile->compile(*),master(compile);runtime->runtime(*)"/> <dependency org="org.scala-lang.modules" name="scala-java8-compat_2.12" rev="0.8.0" force="true" conf="compile->compile(*),master(compile);runtime->runtime(*)"/> </dependencies> 

Ivy Dokumentation sagt:


Diese beiden latest Konfliktmanager berücksichtigen das Attribut "Kraftabhängigkeit".
Daher können direkte Abhängigkeiten ein force Attribut deklarieren (siehe Abhängigkeit), was darauf hinweist, dass bei direkten Abhängigkeiten und indirekten Revisionen direkte Abhängigkeitsrevisionen bevorzugt werden sollten.

Für mich bedeutet diese Formulierung, dass force="true" konzipiert wurde, um die Logik der latest-wins neu zu definieren und die Semantik der nearest-wins emulieren. Glücklicherweise war dies nicht vorgesehen, und wir haben jetzt die latest-wins : Wie wir sehen können, sbt 1.2.8 com.typesafe:config:1.3.1 .


Man kann jedoch den Effekt von force="true" wenn man einen strengen Konfliktmanager verwendet, der gebrochen zu sein scheint.


 ThisBuild / conflictManager := ConflictManager.strict 

Das Problem ist, dass ein strenger Konfliktmanager die Versionsersetzung nicht zu verhindern scheint. show externalDependencyClasspath fröhlich com.typesafe:config:1.3.1 .
Ein damit verbundenes Problem besteht darin, dass das Hinzufügen einer Version von com.typesafe:config:1.3.1 , die ein strenger Konfliktmanager in das Diagramm com.typesafe:config:1.3.1 , zu einem Fehler führt.


 ThisBuild / scalaVersion := "2.12.8" ThisBuild / organization := "com.example" ThisBuild / version := "1.0.0-SNAPSHOT" ThisBuild / conflictManager := ConflictManager.strict lazy val root = (project in file(".")) .settings( name := "foo", libraryDependencies ++= List( "com.typesafe.play" %% "play-ws-standalone" % "1.0.1", "com.typesafe" % "config" % "1.3.1", ) ) 

Es sieht so aus:


 sbt:foo> show externalDependencyClasspath [info] Updating ... [error] com.typesafe#config;1.2.0 (needed by [com.typesafe#ssl-config-core_2.12;0.2.2]) conflicts with com.typesafe#config;1.3.1 (needed by [com.example#foo_2.12;1.0.0-SNAPSHOT]) [error] org.apache.ivy.plugins.conflict.StrictConflictException: com.typesafe#config;1.2.0 (needed by [com.typesafe#ssl-config-core_2.12;0.2.2]) conflicts with com.typesafe#config;1.3.1 (needed by [com.example#foo_2.12;1.0.0-SNAPSHOT]) 

Über die Versionierung


Wir haben die Semantik der latest-wins , was darauf hindeutet, dass Versionen in einer Zeichenfolgendarstellung in einer bestimmten Reihenfolge auftreten können.
Daher ist die Versionierung Teil der Semantik.


Versionierungsverfahren in Apache Ivy


Dieser Javadoc-Kommentar besagt, dass sich Ivy beim Erstellen des Versionskomparators auf die Funktion des Vergleichens von Versionen aus PHP konzentriert hat :


Diese Funktion ersetzt zuerst _, - und + durch einen Punkt . in String-Darstellungen von Versionen und fügt auch hinzu . vor und nach allem, was keine Zahl ist. So wird beispielsweise aus '4.3.2RC1' '4.3.2.RC.1'. Sie vergleicht dann die erhaltenen Teile von links nach rechts.

Für Teile, die spezielle Elemente enthalten ( dev , alpha oder a , beta oder b , RC oder rc , # , pl oder p ) *, werden die Elemente in der folgenden Reihenfolge verglichen:

jede Zeichenfolge, die kein spezielles Element ist <dev <alpha = a <beta = b <RC = rc <# <pl = p.

Somit können nicht nur verschiedene Ebenen (z. B. '4.1' und '4.1.2') verglichen werden, sondern auch PHP-spezifische Versionen, die Informationen zum Entwicklungsstatus enthalten.
* ca. perev.

Wir können überprüfen, wie die Versionen bestellt sind, indem wir eine kleine Funktion schreiben.


 scala> :paste // Entering paste mode (ctrl-D to finish) val strategy = new org.apache.ivy.plugins.latest.LatestRevisionStrategy case class MockArtifactInfo(version: String) extends org.apache.ivy.plugins.latest.ArtifactInfo { def getRevision: String = version def getLastModified: Long = -1 } def sortVersionsIvy(versions: String*): List[String] = { import scala.collection.JavaConverters._ strategy.sort(versions.toArray map MockArtifactInfo) .asScala.toList map { case MockArtifactInfo(v) => v } } // Exiting paste mode, now interpreting. scala> sortVersionsIvy("1.0", "2.0", "1.0-alpha", "1.0+alpha", "1.0-X1", "1.0a", "2.0.2") res7: List[String] = List(1.0-X1, 1.0a, 1.0-alpha, 1.0+alpha, 1.0, 2.0, 2.0.2) 

Versionierungsverfahren in Coursier


Die GitHub-Seite zur Semantik der Abhängigkeitsauflösung enthält einen Abschnitt zur Versionierung.


Coursier verwendet Mavens maßgeschneiderte Versionsreihenfolge. Vor dem Vergleich werden die Zeichenfolgendarstellungen der Versionen in separate Elemente unterteilt ...
Um solche Elemente zu erhalten, werden Versionen durch die Zeichen., - und _ (und die Trennzeichen selbst werden verworfen) sowie durch Ersetzungen von Buchstaben zu Zahlen oder von Zahlen zu Buchstaben getrennt.

Um den Test zu schreiben, erstellen Sie ein Unterprojekt mit den Abhängigkeiten libraryDependencies += "io.get-coursier" %% "coursier-core" % "2.0.0-RC2-6" und führen Sie die console :


 sbt:foo> helper/console [info] Starting scala interpreter... Welcome to Scala 2.12.8 (OpenJDK 64-Bit Server VM, Java 1.8.0_212). Type in expressions for evaluation. Or try :help. scala> import coursier.core.Version import coursier.core.Version scala> def sortVersionsCoursier(versions: String*): List[String] = | versions.toList.map(Version.apply).sorted.map(_.repr) sortVersionsCoursier: (versions: String*)List[String] scala> sortVersionsCoursier("1.0", "2.0", "1.0-alpha", "1.0+alpha", "1.0-X1", "1.0a", "2.0.2") res0: List[String] = List(1.0-alpha, 1.0, 1.0-X1, 1.0+alpha, 1.0a, 2.0, 2.0.2) 

Wie sich herausstellt, bestellt Coursier die Versionsnummern in einer völlig anderen Reihenfolge als Ivy.
Wenn Sie zulässige alphabetische Tags verwendet haben, kann diese Reihenfolge zu Verwirrung führen.


Über Versionsbereiche


Normalerweise vermeide ich die Verwendung von Versionsbereichen, obwohl diese häufig in Webjars und npm-Modulen verwendet werden, die auf Maven Central neu veröffentlicht wurden. So etwas wie "is-number": "^4.0.0" kann in das Modul geschrieben werden "is-number": "^4.0.0" was [4.0.0,5) .


Versionsbereichsbehandlung in Apache Ivy


In dieser Baugruppe hängt angular-boostrap:0.14.2 vom angular:[1.3.0,) .


 ThisBuild / scalaVersion := "2.12.8" ThisBuild / organization := "com.example" ThisBuild / version := "1.0.0-SNAPSHOT" lazy val root = (project in file(".")) .settings( name := "foo", libraryDependencies ++= List( "org.webjars.bower" % "angular" % "1.4.7", "org.webjars.bower" % "angular-bootstrap" % "0.14.2", ) ) 

sbt 1.2.8 show externalDependencyClasspath in sbt 1.2.8 wird sbt 1.2.8 angular-bootstrap:0.14.2 und angular:1.7.8 . Und wohin ging 1.7.8 ? Wenn Ivy auf eine Reihe von Versionen stößt, geht es im Wesentlichen ins Internet und findet, was es finden kann, manchmal sogar mithilfe von Screenscraping.


Durch diese Verarbeitung von Versionsbereichen wiederholen sich Baugruppen nicht (wenn Sie dieselbe Baugruppe alle paar Monate ausführen, erhalten Sie unterschiedliche Ergebnisse).


Handhabung der Versionsbereiche in Coursier


Abschnitt zur Auflösung von Coursier-Abhängigkeiten auf der Github- Seite
liest:


Spezifische Versionen in Intervallen werden bevorzugt
Wenn Ihr Modul von [1.0,2.0) und 1.4 abhängig ist, wird die Versionsgenehmigung zugunsten von 1.4 durchgeführt.
Wenn eine Abhängigkeit von 1.4 besteht, wird diese Version im Bereich [1.0,2.0] bevorzugt.

Es sieht vielversprechend aus.


 sbt:foo> show externalDependencyClasspath [warn] There may be incompatibilities among your library dependencies; run 'evicted' to see detailed eviction warnings. [info] * Attributed(/Users/eed3si9n/.sbt/boot/scala-2.12.8/lib/scala-library.jar) [info] * Attributed(/Users/eed3si9n/.coursier/cache/v1/https/repo1.maven.org/maven2/org/webjars/bower/angular/1.4.7/angular-1.4.7.jar) [info] * Attributed(/Users/eed3si9n/.coursier/cache/v1/https/repo1.maven.org/maven2/org/webjars/bower/angular-bootstrap/0.14.2/angular-bootstrap-0.14.2.jar) 

show externalDependencyClasspath auf derselben Assembly mit angular-bootstrap:0.14.2 angular-bootstrap:0.14.2 angular:1.4.7 wie erwartet angular-bootstrap:0.14.2 angular-bootstrap:0.14.2 und angular:1.4.7 . Dies ist eine Verbesserung gegenüber Ivy.


Betrachten Sie den komplizierteren Fall, wenn mehrere disjunkte Versionsbereiche verwendet werden. Zum Beispiel:


 ThisBuild / scalaVersion := "2.12.8" ThisBuild / organization := "com.example" ThisBuild / version := "1.0.0-SNAPSHOT" lazy val root = (project in file(".")) .settings( name := "foo", libraryDependencies ++= List( "org.webjars.npm" % "randomatic" % "1.1.7", "org.webjars.npm" % "is-odd" % "2.0.0", ) ) 

Der Aufruf von show externalDependencyClasspath in sbt 1.3.0-RC3 gibt den folgenden Fehler zurück:


 sbt:foo> show externalDependencyClasspath [info] Updating https://repo1.maven.org/maven2/org/webjars/npm/kind-of/maven-metadata.xml No new update since 2018-03-10 06:32:27 https://repo1.maven.org/maven2/org/webjars/npm/is-number/maven-metadata.xml No new update since 2018-03-09 15:25:26 https://repo1.maven.org/maven2/org/webjars/npm/is-buffer/maven-metadata.xml No new update since 2018-08-17 14:21:46 [info] Resolved dependencies [error] lmcoursier.internal.shaded.coursier.error.ResolutionError$ConflictingDependencies: Conflicting dependencies: [error] org.webjars.npm:is-number:[3.0.0,4):default(compile) [error] org.webjars.npm:is-number:[4.0.0,5):default(compile) [error] at lmcoursier.internal.shaded.coursier.Resolve$.validate(Resolve.scala:394) [error] at lmcoursier.internal.shaded.coursier.Resolve.validate0$1(Resolve.scala:140) [error] at lmcoursier.internal.shaded.coursier.Resolve.$anonfun$ioWithConflicts0$4(Resolve.scala:184) [error] at lmcoursier.internal.shaded.coursier.util.Task$.$anonfun$flatMap$2(Task.scala:14) [error] at scala.concurrent.Future.$anonfun$flatMap$1(Future.scala:307) [error] at scala.concurrent.impl.Promise.$anonfun$transformWith$1(Promise.scala:41) [error] at scala.concurrent.impl.CallbackRunnable.run(Promise.scala:64) [error] at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [error] at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [error] at java.lang.Thread.run(Thread.java:748) [error] (update) lmcoursier.internal.shaded.coursier.error.ResolutionError$ConflictingDependencies: Conflicting dependencies: [error] org.webjars.npm:is-number:[3.0.0,4):default(compile) [error] org.webjars.npm:is-number:[4.0.0,5):default(compile) 

Technisch ist das richtig, weil Diese Bereiche überschneiden sich nicht. Während sbt 1.2.8 dies in is-number:4.0.0 auflöst.


Aufgrund der Tatsache, dass Versionsbereiche häufig genug sind, um nervig zu sein, sende ich eine Pull-Anfrage an Coursier, um zusätzliche Semantikregeln für die latest-wins zu implementieren, mit denen Sie spätere Versionen aus den unteren Grenzen der Bereiche auswählen können.
Siehe Coursier / Coursier # 1284 .


Fazit


Die Resolversemantik definiert einen bestimmten Klassenpfad basierend auf benutzerdefinierten Einschränkungen.


In der Regel manifestieren sich Detailunterschiede auf unterschiedliche Weise bei der Lösung von Versionskonflikten.


  • Maven verwendet die nearest-wins Strategie, mit der transitive Abhängigkeiten herabgestuft werden können.
  • Ivy verwendet die Strategie der latest-wins .
  • Coursier verwendet hauptsächlich die Strategie der latest-wins , während versucht wird, Versionen strenger anzugeben.
  • Der Ivy-Versionsbereichs-Handler geht ins Internet, wodurch derselbe Build nicht wiederholbar ist.
  • Coursier und Ivy organisieren String-Darstellungen von Versionen auf sehr unterschiedliche Weise.

Nicht einmal solche Feinheiten des Scala-Ökosystems werden auf der ScalaConf am 26. November in Moskau diskutiert. Artem Seleznev wird die Praxis der Arbeit mit der Datenbank in der funktionalen Programmierung ohne JDBC einführen . Wojtek Pitula wird über Integration sprechen und erzählen, wie er eine Anwendung erstellt hat, in der er alle Arbeitsbibliotheken platziert hat. Auf der Konferenz werden 16 weitere Berichte mit technischem Hardcore vorgestellt.

Source: https://habr.com/ru/post/de474106/


All Articles