SBT: исключить класс из Jar

Я конвертирую старый проект jar в SBT и по странным причинам, которые нелегко решить, этот проект поставляется с " javax/servlet/Servlet.class" внутри него. Поэтому мне нужно как-то исключить этот класс из файла jar, сгенерированного package-bin. Как это сделать? Предпочтительно я хотел бы исключить использование подстановочного знака (т.е. javax. *).

Плагин сборки SBT выглядит так, как будто он имеет функции, которые будут делать это, но я обеспокоен тем, что использование сборки sbt означает, что мой проект jar не будет работать в проекте модуля мулити (т.е. если Я включаю его как зависимость в военном файле, тогда для военных проектов нужно сказать, чтобы запустить сборку в проекте зависимой jar, а не package-bin - но я могу быть ошибочно здесь).

Ответ 1

Каждая задача объявляет другие задачи и настройки, которые она использует. Вы можете использовать inspect для определения этих входов, как описано в Проверка параметров и в недавнем учебном стиле блоге Джона Cheng.

В этом случае соответствующая задача, используемая packageBin, равна mappings. Задача mappings собирает файлы, которые должны быть включены в банку, и отображает их в путь в банке. Некоторый фон объясняется Картографическими файлами, но в результате mappings создает значение типа Seq[(File, String)]. Здесь Файл - это входной файл, предоставляющий содержимое, а String - путь в банке.

Итак, чтобы изменить сопоставления для задачи packageBin, отфильтруйте пути из сопоставлений по умолчанию, которые вы не хотите включать:

mappings in (Compile,packageBin) ~= { (ms: Seq[(File, String)]) =>
  ms filter { case (file, toPath) =>
    toPath != "javax/servlet/Servlet.class"
  }
}

mappings in (Compile,packageBin) выбирает сопоставления для основной задачи пакета (в отличие от тестовых источников или задачи packageSrc).

x ~= f означает "установить x в результат применения функции f к предыдущему значению x". (Подробнее см. Подробнее о настройках.)

Фильтр отбрасывает все пары, где путь соответствует классу Servlet.

Ответ 2

Я придумал это решение, он определяет новую задачу компиляции, которая зависит от предыдущей задачи компиляции (таким образом, эффективно позволяя мне подключаться сразу после скомпилирования источника и перед его упаковкой)

def mySettings = {
  // add functionality to the standard compile task 
  inConfig(Compile)(Seq(compile in Compile <<= (target,streams,compile in Compile) map{
    (targetDirectory, taskStream, analysis) =>
      import taskStream.log
      // this runs after compile but before package-bin
      recursiveListFiles(targetDirectory, ".*javax.*".r) foreach { 
        file =>
          log.warn("deleting matched resource: " + file.getAbsolutePath())
          IO.delete(file)
      }
      analysis
    })) ++
    Seq(name := "MyProject", version := "1.0", exportJars := true)
}

def recursiveListFiles(f: File, r: Regex): Array[File] = {
  val these = f.listFiles
  val good = these.filter(f => r.findFirstIn(f.getName).isDefined)
  good ++ these.filter(_.isDirectory).flatMap(recursiveListFiles(_, r))
}

Его немного сложнее, чем я надеялся, но он позволяет мне делать всевозможные модификации перед упаковкой (в этом случае поиск целевой папки, удаляющей все файлы классов, которые соответствуют регулярному выражению). Также он выполнил мою вторую задачу - придерживаться жизненного цикла SBT по умолчанию.