написал что-то быстрое и грязное, но у меня это работает.Я был бы рад увидеть решение, которое использует распознаватель Ivy, который должен обеспечивать ту же функциональность, только более надежно.
По моему опыту, потому что людям трудно понять, является ли шаблон, подобный [organisation]/[module](/scala_[scalaVersion])(/sbt_[sbtVersion])/[revision]/[artifact](-[classifier])(-[revision]).[ext]
соответствует тому, что им нужно, или дублирует другой шаблон, который уже существует в sbt.repositories
, люди просто копируют и вставляют шаблоны из одного файла репо в другой, пока сборка не заработает.Со временем это создает запутанный беспорядок, и нам нужны инструменты для решения таких вопросов, как «какой шаблон соответствует данной зависимости» или «какие два шаблона идентичны» или «какой шаблон не соответствует ни одной зависимости» и т. Д.
import java.io.File
import java.net.URL
import java.util.regex.Pattern
import scala.collection.JavaConversions._
import scala.collection.mutable
import scala.io.{Codec, Source}
import scala.util.control.NonFatal
object FindDependency {
def main(args: Array[String]): Unit = {
val root = new File(".")
val sbtRepos = new File(root, "./build/sbt.repositories")
implicit val dep = Dep(organisation = "com.foo.bar.sbt", module = "baz", artifact = "baz", revision = "1.2.3-SNAPSHOT", ext = "jar"
, scalaVersion = "2.10", sbtVersion = "0.13", artType = "jar", classifier = "")
println(sbtRepos.getCanonicalPath + ": exists?" + sbtRepos.exists)
processSbtRepos(sbtRepos)
}
def processSbtRepos(repoFilePath: File)(implicit dep: Dep): Unit = {
val source = Source.fromFile(repoFilePath)(Codec.ISO8859)
source.getLines.foreach { line =>
if (!ignore(line)) {
println(s"\n$line")
val namePattern = line.split(":") map (_.trim)
if (namePattern.length >= 3) artifactUrl(namePattern)
}
}
source.close
}
def artifactUrl(words: Array[String])(implicit dep: Dep): Unit = {
val artBase = repoUrl(words)
val artifactPattern = if (artBase.indexOf('[') > 0) artBase else artBase + ",[organisation]/[module]/[revision]/[artifact]-[revision].[ext]"
val artUrls = dep.potentialUrls(artifactPattern)
artUrls.foreach { url =>
if (isValidUrl(url)) {
println(s"$artifactPattern -> $url")
}
}
}
def isValidUrl(url: String): Boolean = {
try {
val u = new URL(url)
val contentLength = u.openConnection.getContentLength
val openStream = u.openStream
val binaryData = new Array[Byte](contentLength)
openStream.read(binaryData)
openStream.close
true
} catch {
case NonFatal(_) => false
}
}
def repoUrl(words: Array[String]): String = words.drop(1).mkString(":")
def ignore(line: String): Boolean = {
line.indexOf("http://") < 0
}
}
/**
* Represents a dependency
*
* @param artType artifact type, e.g. "sources", "javadoc", ""
*/
case class Dep(organisation: String, module: String, artifact: String, revision: String
, ext: String, scalaVersion: String, sbtVersion: String, artType: String
, classifier: String) {
/**
* Given a pattern and the known parameters for a dependency, replace the details of the dependency in the pattern.
*
* @return a concrete URL (with optional portions) where the dependency may be located
*/
def replace(pattern: String): String = {
pattern.replaceAll(Pattern.quote("[artifact]"), artifact)
.replaceAll(Pattern.quote("[ext]"), ext)
.replaceAll(Pattern.quote("[module]"), module)
.replaceAll(Pattern.quote("[organisation]"), organisation)
.replaceAll(Pattern.quote("[organization]"), organisation)
.replaceAll(Pattern.quote("[revision]"), revision)
.replaceAll(Pattern.quote("[scalaVersion]"), scalaVersion)
.replaceAll(Pattern.quote("[sbtVersion]"), sbtVersion)
.replaceAll(Pattern.quote("[type]"), artType)
.replaceAll(Pattern.quote("[classifier]"), classifier)
}
def potentialUrls(pattern: String): Seq[String] = {
val urlWithOpts = replace(pattern)
.replaceAll(" ", "")
.replaceAll(",", "/")
.replaceAll("\\(", "(?") // mark the optional elements with the prefix "?"
val words = urlWithOpts.split("\\(|\\)").map(_.trim).filterNot(_.isEmpty).filterNot(_ == "?-")
val urls = mutable.ArrayBuffer.empty[String]
val urlsCrt = mutable.ArrayBuffer.empty[String] // a temp container for urls
urls.add(words(0)) // the first "word" is the repo URL, which is not optional
words.drop(1).foreach { word =>
// transfer the current list of URLs to the temp container
urlsCrt.clear
urlsCrt ++= urls
urls.clear
if (word.startsWith("?")) {
// append all URLs that were there before, unchanged (because this word is optional)
urls ++= urlsCrt
// as well as all URLs that were there before, each concatenated with this word
urls ++= urlsCrt.map(_ + word.substring(1))
} else {
// to each URL that was there before, concatenate the new word
urls ++= urlsCrt.map(_ + word)
}
}
urls
}
}