簡體   English   中英

查找sbt在其中找到插件或JAR的存儲庫

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM