[英]Find repository where sbt finds a plugin or JAR
嘗試對sbt
構建進行故障排除,想知道sbt.repositories
中的哪個模式與給定的三元sbt.repositories
匹配。
我有一個插件和兩個sbt
版本。 一個版本找到插件,而另一個版本找不到。 這兩個版本都使用sbt.repositories
文件來覆蓋具有內部站點(位於公司防火牆之后)的外部存儲庫。
兩次構建之間的sbt.repositories
文件不同,因此我懷疑其中一個缺少與插件匹配的模式。 sbt.repositories
文件足夠大,我不希望手動或反復試驗來這樣做。
我想使用sbt
自身的功能來打印消息,例如“使用模式(來自sbt.repositories
某種模式),我在(某些URL)找到了插件(org,name,ver)”。
sbt.repositories
的模式具有以下格式。 sbt
必須遍歷這些模式,計算所有組合並測試結果是否為有效的URL。 我想自己訪問該類,因此我可以從sbt.repositories
找出哪種模式允許一個版本找到插件(或JAR)。 然后,我將該模式添加到其他版本的sbt.repositories
中。
有誰知道此功能是否可以通過構建DSL使用(例如,從build.sbt
)或為此sbt
執行此操作的解析器類的名稱?
sbt.repositories
repo-name = http://some.internal.website.com:1234/artifacts/releases,[organisation]/[module](/scala_[scalaVersion])(/sbt_[sbtVersion])/[revision]/[artifact](-[classifier])(-[revision]).[ext]
我嘗試了sbt -Dsbt.log.noformat=true --debug clean update compile > someLogFile.txt
,它告訴我找到了哪些插件,包括我感興趣的插件,但沒有找到它們。
快速又骯臟地寫東西,但是對我有用。 我很高興看到使用Ivy解析器的解決方案,該解決方案必須更可靠地提供相同的功能。
以我的經驗,因為人類很難理解像[organisation]/[module](/scala_[scalaVersion])(/sbt_[sbtVersion])/[revision]/[artifact](-[classifier])(-[revision]).[ext]
符合他們的需求,或復制sbt.repositories
中已經存在的另一種模式,人們只是將模式從一個repo文件復制粘貼到另一個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
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.