写了一些又快又脏的东西,但它对我有用。我很高兴看到使用 Ivy 解析器的解决方案,它必须提供相同的功能,而且更可靠。
根据我的经验,因为人们很难理解像 [organisation]/[module](/scala_[scalaVersion])(/sbt_[sbtVersion])/[revision]/[artifact](-[classifier])(-[revision]).[ext] 这样的模式是否匹配他们需要的模式,或者是否复制了 sbt.repositories 中已经存在的另一种模式,人们只需将模式从一个 repo 文件复制粘贴到另一个文件中直到构建工作。随着时间的推移,这会造成混乱,我们需要工具来处理诸如“哪个模式与给定的依赖项匹配”或“哪两个模式相同”或“哪个模式与任何依赖项不匹配”等问题。
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
}
}