mirror of https://github.com/sbt/sbt.git
Add tasks / settings allowing using other SBT sources as a repository
This commit is contained in:
parent
0f914cf781
commit
16225d98e6
|
|
@ -99,6 +99,18 @@ class Helper(
|
||||||
MavenRepository("https://repo1.maven.org/maven2")
|
MavenRepository("https://repo1.maven.org/maven2")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
val sourceDirectories = common.sources.map { path =>
|
||||||
|
val subDir = "target/repository"
|
||||||
|
val dir = new File(path)
|
||||||
|
val repoDir = new File(dir, subDir)
|
||||||
|
if (!dir.exists())
|
||||||
|
Console.err.println(s"Warning: sources $path not found")
|
||||||
|
else if (!repoDir.exists())
|
||||||
|
Console.err.println(s"Warning: directory $subDir not found under sources path $path")
|
||||||
|
|
||||||
|
repoDir
|
||||||
|
}
|
||||||
|
|
||||||
val repositoriesValidation = CacheParse.repositories(common.repository).map { repos0 =>
|
val repositoriesValidation = CacheParse.repositories(common.repository).map { repos0 =>
|
||||||
|
|
||||||
var repos = (if (common.noDefault) Nil else defaultRepositories) ++ repos0
|
var repos = (if (common.noDefault) Nil else defaultRepositories) ++ repos0
|
||||||
|
|
@ -119,10 +131,14 @@ class Helper(
|
||||||
}
|
}
|
||||||
|
|
||||||
val repositories = repositoriesValidation match {
|
val repositories = repositoriesValidation match {
|
||||||
case Success(repos) => repos
|
case Success(repos) =>
|
||||||
|
val sourceRepositories = sourceDirectories.map(dir =>
|
||||||
|
MavenRepository(dir.toURI.toString, changing = Some(true))
|
||||||
|
)
|
||||||
|
sourceRepositories ++ repos
|
||||||
case Failure(errors) =>
|
case Failure(errors) =>
|
||||||
prematureExit(
|
prematureExit(
|
||||||
s"Error parsing repositories:\n${errors.list.map(" "+_).mkString("\n")}"
|
s"Error with repositories:\n${errors.list.map(" "+_).mkString("\n")}"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -140,8 +156,36 @@ class Helper(
|
||||||
s"Cannot parse forced versions:\n" + forceVersionErrors.map(" "+_).mkString("\n")
|
s"Cannot parse forced versions:\n" + forceVersionErrors.map(" "+_).mkString("\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val sourceRepositoryForceVersions = sourceDirectories.flatMap { base =>
|
||||||
|
|
||||||
|
// FIXME Also done in the plugin module
|
||||||
|
|
||||||
|
def pomDirComponents(f: File, components: Vector[String]): Stream[Vector[String]] =
|
||||||
|
if (f.isDirectory) {
|
||||||
|
val components0 = components :+ f.getName
|
||||||
|
Option(f.listFiles()).toStream.flatten.flatMap(pomDirComponents(_, components0))
|
||||||
|
} else if (f.getName.endsWith(".pom"))
|
||||||
|
Stream(components)
|
||||||
|
else
|
||||||
|
Stream.empty
|
||||||
|
|
||||||
|
Option(base.listFiles())
|
||||||
|
.toVector
|
||||||
|
.flatten
|
||||||
|
.flatMap(pomDirComponents(_, Vector()))
|
||||||
|
// at least 3 for org / name / version - the contrary should not happen, but who knows
|
||||||
|
.filter(_.length >= 3)
|
||||||
|
.map { components =>
|
||||||
|
val org = components.dropRight(2).mkString(".")
|
||||||
|
val name = components(components.length - 2)
|
||||||
|
val version = components.last
|
||||||
|
|
||||||
|
Module(org, name) -> version
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val forceVersions = {
|
val forceVersions = {
|
||||||
val grouped = forceVersions0
|
val grouped = (forceVersions0 ++ sourceRepositoryForceVersions)
|
||||||
.groupBy { case (mod, _) => mod }
|
.groupBy { case (mod, _) => mod }
|
||||||
.map { case (mod, l) => mod -> l.map { case (_, version) => version } }
|
.map { case (mod, l) => mod -> l.map { case (_, version) => version } }
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,9 +24,12 @@ case class CommonOptions(
|
||||||
@Help("Maximum number of resolution iterations (specify a negative value for unlimited, default: 100)")
|
@Help("Maximum number of resolution iterations (specify a negative value for unlimited, default: 100)")
|
||||||
@Short("N")
|
@Short("N")
|
||||||
maxIterations: Int = 100,
|
maxIterations: Int = 100,
|
||||||
@Help("Repositories - for multiple repositories, separate with comma and/or repeat this option (e.g. -r central,ivy2local -r sonatype-snapshots, or equivalently -r central,ivy2local,sonatype-snapshots)")
|
@Help("Repository - for multiple repositories, separate with comma and/or add this option multiple times (e.g. -r central,ivy2local -r sonatype-snapshots, or equivalently -r central,ivy2local,sonatype-snapshots)")
|
||||||
@Short("r")
|
@Short("r")
|
||||||
repository: List[String],
|
repository: List[String],
|
||||||
|
@Help("Source repository - for multiple repositories, separate with comma and/or add this option multiple times")
|
||||||
|
@Short("R")
|
||||||
|
sources: List[String],
|
||||||
@Help("Do not add default repositories (~/.ivy2/local, and Central)")
|
@Help("Do not add default repositories (~/.ivy2/local, and Central)")
|
||||||
noDefault: Boolean = false,
|
noDefault: Boolean = false,
|
||||||
@Help("Modify names in Maven repository paths for SBT plugins")
|
@Help("Modify names in Maven repository paths for SBT plugins")
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,77 @@
|
||||||
|
package coursier.maven
|
||||||
|
|
||||||
|
import coursier.core.{ Dependency, Project }
|
||||||
|
|
||||||
|
object WritePom {
|
||||||
|
|
||||||
|
def project(proj: Project, packaging: Option[String]) = {
|
||||||
|
|
||||||
|
def dependencyNode(config: String, dep: Dependency) = {
|
||||||
|
<dependency>
|
||||||
|
<groupId>{dep.module.organization}</groupId>
|
||||||
|
<artifactId>{dep.module.name}</artifactId>
|
||||||
|
{
|
||||||
|
if (dep.version.isEmpty)
|
||||||
|
Nil
|
||||||
|
else
|
||||||
|
Seq(<version>{dep.version}</version>)
|
||||||
|
}
|
||||||
|
{
|
||||||
|
if (config.isEmpty)
|
||||||
|
Nil
|
||||||
|
else
|
||||||
|
Seq(<scope>{config}</scope>)
|
||||||
|
}
|
||||||
|
</dependency>
|
||||||
|
}
|
||||||
|
|
||||||
|
<project>
|
||||||
|
// parent
|
||||||
|
<groupId>{proj.module.organization}</groupId>
|
||||||
|
<artifactId>{proj.module.name}</artifactId>
|
||||||
|
{
|
||||||
|
packaging
|
||||||
|
.map(p => <packaging>{p}</packaging>)
|
||||||
|
.toSeq
|
||||||
|
}
|
||||||
|
<description>{proj.info.description}</description>
|
||||||
|
<url>{proj.info.homePage}</url>
|
||||||
|
<version>{proj.version}</version>
|
||||||
|
// licenses
|
||||||
|
<name>{proj.module.name}</name>
|
||||||
|
<organization>
|
||||||
|
<name>{proj.module.name}</name>
|
||||||
|
<url>{proj.info.homePage}</url>
|
||||||
|
</organization>
|
||||||
|
// SCM
|
||||||
|
// developers
|
||||||
|
{
|
||||||
|
if (proj.dependencies.isEmpty)
|
||||||
|
Nil
|
||||||
|
else
|
||||||
|
<dependencies>{
|
||||||
|
proj.dependencies.map {
|
||||||
|
case (config, dep) =>
|
||||||
|
dependencyNode(config, dep)
|
||||||
|
}
|
||||||
|
}</dependencies>
|
||||||
|
}
|
||||||
|
{
|
||||||
|
if (proj.dependencyManagement.isEmpty)
|
||||||
|
Nil
|
||||||
|
else
|
||||||
|
<dependencyManagement>
|
||||||
|
<dependencies>{
|
||||||
|
proj.dependencyManagement.map {
|
||||||
|
case (config, dep) =>
|
||||||
|
dependencyNode(config, dep)
|
||||||
|
}
|
||||||
|
}</dependencies>
|
||||||
|
</dependencyManagement>
|
||||||
|
}
|
||||||
|
// properties
|
||||||
|
// repositories
|
||||||
|
</project>
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -16,6 +16,7 @@ object CoursierPlugin extends AutoPlugin {
|
||||||
val coursierArtifactsChecksums = Keys.coursierArtifactsChecksums
|
val coursierArtifactsChecksums = Keys.coursierArtifactsChecksums
|
||||||
val coursierCachePolicies = Keys.coursierCachePolicies
|
val coursierCachePolicies = Keys.coursierCachePolicies
|
||||||
val coursierVerbosity = Keys.coursierVerbosity
|
val coursierVerbosity = Keys.coursierVerbosity
|
||||||
|
val coursierSourceRepositories = Keys.coursierSourceRepositories
|
||||||
val coursierResolvers = Keys.coursierResolvers
|
val coursierResolvers = Keys.coursierResolvers
|
||||||
val coursierSbtResolvers = Keys.coursierSbtResolvers
|
val coursierSbtResolvers = Keys.coursierSbtResolvers
|
||||||
val coursierFallbackDependencies = Keys.coursierFallbackDependencies
|
val coursierFallbackDependencies = Keys.coursierFallbackDependencies
|
||||||
|
|
@ -32,6 +33,11 @@ object CoursierPlugin extends AutoPlugin {
|
||||||
|
|
||||||
val coursierDependencyTree = Keys.coursierDependencyTree
|
val coursierDependencyTree = Keys.coursierDependencyTree
|
||||||
val coursierDependencyInverseTree = Keys.coursierDependencyInverseTree
|
val coursierDependencyInverseTree = Keys.coursierDependencyInverseTree
|
||||||
|
|
||||||
|
val coursierExport = Keys.coursierExport
|
||||||
|
val coursierExportDirectory = Keys.coursierExportDirectory
|
||||||
|
val coursierExportJavadoc = Keys.coursierExportJavadoc
|
||||||
|
val coursierExportSources = Keys.coursierExportSources
|
||||||
}
|
}
|
||||||
|
|
||||||
import autoImport._
|
import autoImport._
|
||||||
|
|
@ -52,6 +58,7 @@ object CoursierPlugin extends AutoPlugin {
|
||||||
coursierArtifactsChecksums := Seq(None),
|
coursierArtifactsChecksums := Seq(None),
|
||||||
coursierCachePolicies := Settings.defaultCachePolicies,
|
coursierCachePolicies := Settings.defaultCachePolicies,
|
||||||
coursierVerbosity := Settings.defaultVerbosityLevel,
|
coursierVerbosity := Settings.defaultVerbosityLevel,
|
||||||
|
coursierSourceRepositories := Nil,
|
||||||
coursierResolvers <<= Tasks.coursierResolversTask,
|
coursierResolvers <<= Tasks.coursierResolversTask,
|
||||||
coursierSbtResolvers <<= externalResolvers in updateSbtClassifiers,
|
coursierSbtResolvers <<= externalResolvers in updateSbtClassifiers,
|
||||||
coursierFallbackDependencies <<= Tasks.coursierFallbackDependenciesTask,
|
coursierFallbackDependencies <<= Tasks.coursierFallbackDependenciesTask,
|
||||||
|
|
@ -74,7 +81,11 @@ object CoursierPlugin extends AutoPlugin {
|
||||||
coursierResolution <<= Tasks.resolutionTask(),
|
coursierResolution <<= Tasks.resolutionTask(),
|
||||||
coursierSbtClassifiersResolution <<= Tasks.resolutionTask(
|
coursierSbtClassifiersResolution <<= Tasks.resolutionTask(
|
||||||
sbtClassifiers = true
|
sbtClassifiers = true
|
||||||
)
|
),
|
||||||
|
coursierExport <<= Tasks.coursierExportTask,
|
||||||
|
coursierExportDirectory := baseDirectory.in(ThisBuild).value / "target" / "repository",
|
||||||
|
coursierExportJavadoc := false,
|
||||||
|
coursierExportSources := false
|
||||||
) ++
|
) ++
|
||||||
inConfig(Compile)(treeSettings) ++
|
inConfig(Compile)(treeSettings) ++
|
||||||
inConfig(Test)(treeSettings)
|
inConfig(Test)(treeSettings)
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ object Keys {
|
||||||
|
|
||||||
val coursierVerbosity = SettingKey[Int]("coursier-verbosity", "")
|
val coursierVerbosity = SettingKey[Int]("coursier-verbosity", "")
|
||||||
|
|
||||||
|
val coursierSourceRepositories = SettingKey[Seq[File]]("coursier-source-repositories")
|
||||||
val coursierResolvers = TaskKey[Seq[Resolver]]("coursier-resolvers", "")
|
val coursierResolvers = TaskKey[Seq[Resolver]]("coursier-resolvers", "")
|
||||||
val coursierSbtResolvers = TaskKey[Seq[Resolver]]("coursier-sbt-resolvers", "")
|
val coursierSbtResolvers = TaskKey[Seq[Resolver]]("coursier-sbt-resolvers", "")
|
||||||
|
|
||||||
|
|
@ -41,4 +42,21 @@ object Keys {
|
||||||
"coursier-dependency-inverse-tree",
|
"coursier-dependency-inverse-tree",
|
||||||
"Prints dependencies and transitive dependencies as an inverted tree (dependees as children)"
|
"Prints dependencies and transitive dependencies as an inverted tree (dependees as children)"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
val coursierExport = TaskKey[Option[File]](
|
||||||
|
"coursier-export",
|
||||||
|
"Generates files allowing using these sources as a source dependency repository"
|
||||||
|
)
|
||||||
|
val coursierExportDirectory = TaskKey[File](
|
||||||
|
"coursier-export-directory",
|
||||||
|
"Base directory for the products of coursierExport"
|
||||||
|
)
|
||||||
|
val coursierExportJavadoc = SettingKey[Boolean](
|
||||||
|
"coursier-export-javadoc",
|
||||||
|
"Build javadoc packages for the coursier source dependency repository"
|
||||||
|
)
|
||||||
|
val coursierExportSources = SettingKey[Boolean](
|
||||||
|
"coursier-export-sources",
|
||||||
|
"Build sources packages for the coursier source dependency repository"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import coursier.core.Publication
|
||||||
import coursier.ivy.IvyRepository
|
import coursier.ivy.IvyRepository
|
||||||
import coursier.Keys._
|
import coursier.Keys._
|
||||||
import coursier.Structure._
|
import coursier.Structure._
|
||||||
|
import coursier.maven.WritePom
|
||||||
import coursier.util.{ Config, Print }
|
import coursier.util.{ Config, Print }
|
||||||
import org.apache.ivy.core.module.id.ModuleRevisionId
|
import org.apache.ivy.core.module.id.ModuleRevisionId
|
||||||
|
|
||||||
|
|
@ -299,6 +300,40 @@ object Tasks {
|
||||||
else
|
else
|
||||||
coursierResolvers.value
|
coursierResolvers.value
|
||||||
|
|
||||||
|
val sourceRepositories = coursierSourceRepositories.value.map { dir =>
|
||||||
|
// FIXME Don't hardcode this path?
|
||||||
|
new File(dir, "target/repository")
|
||||||
|
}
|
||||||
|
|
||||||
|
val sourceRepositoriesForcedDependencies = sourceRepositories.flatMap {
|
||||||
|
base =>
|
||||||
|
|
||||||
|
def pomDirComponents(f: File, components: Vector[String]): Stream[Vector[String]] =
|
||||||
|
if (f.isDirectory) {
|
||||||
|
val components0 = components :+ f.getName
|
||||||
|
Option(f.listFiles()).toStream.flatten.flatMap(pomDirComponents(_, components0))
|
||||||
|
} else if (f.getName.endsWith(".pom"))
|
||||||
|
Stream(components)
|
||||||
|
else
|
||||||
|
Stream.empty
|
||||||
|
|
||||||
|
Option(base.listFiles())
|
||||||
|
.toVector
|
||||||
|
.flatten
|
||||||
|
.flatMap(pomDirComponents(_, Vector()))
|
||||||
|
// at least 3 for org / name / version - the contrary should not happen, but who knows
|
||||||
|
.filter(_.length >= 3)
|
||||||
|
.map { components =>
|
||||||
|
val org = components.dropRight(2).mkString(".")
|
||||||
|
val name = components(components.length - 2)
|
||||||
|
val version = components.last
|
||||||
|
|
||||||
|
Module(org, name) -> version
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO Warn about possible duplicated modules from source repositories?
|
||||||
|
|
||||||
val verbosityLevel = coursierVerbosity.value
|
val verbosityLevel = coursierVerbosity.value
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -308,7 +343,12 @@ object Tasks {
|
||||||
dep.copy(exclusions = dep.exclusions ++ exclusions)
|
dep.copy(exclusions = dep.exclusions ++ exclusions)
|
||||||
}.toSet,
|
}.toSet,
|
||||||
filter = Some(dep => !dep.optional),
|
filter = Some(dep => !dep.optional),
|
||||||
forceVersions = userForceVersions ++ forcedScalaModules(sv) ++ projects.map(_.moduleVersion)
|
forceVersions =
|
||||||
|
// order matters here
|
||||||
|
userForceVersions ++
|
||||||
|
sourceRepositoriesForcedDependencies ++
|
||||||
|
forcedScalaModules(sv) ++
|
||||||
|
projects.map(_.moduleVersion)
|
||||||
)
|
)
|
||||||
|
|
||||||
if (verbosityLevel >= 2) {
|
if (verbosityLevel >= 2) {
|
||||||
|
|
@ -331,12 +371,12 @@ object Tasks {
|
||||||
"ivy.home" -> (new File(sys.props("user.home")).toURI.getPath + ".ivy2")
|
"ivy.home" -> (new File(sys.props("user.home")).toURI.getPath + ".ivy2")
|
||||||
) ++ sys.props
|
) ++ sys.props
|
||||||
|
|
||||||
val repositories = Seq(
|
val sourceRepositories0 = sourceRepositories.map {
|
||||||
globalPluginsRepo,
|
base =>
|
||||||
interProjectRepo
|
MavenRepository(base.toURI.toString, changing = Some(true))
|
||||||
) ++ resolvers.flatMap(
|
}
|
||||||
FromSbt.repository(_, ivyProperties, log)
|
|
||||||
) ++ {
|
val fallbackDependenciesRepositories =
|
||||||
if (fallbackDependencies.isEmpty)
|
if (fallbackDependencies.isEmpty)
|
||||||
Nil
|
Nil
|
||||||
else {
|
else {
|
||||||
|
|
@ -349,7 +389,12 @@ object Tasks {
|
||||||
FallbackDependenciesRepository(map)
|
FallbackDependenciesRepository(map)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
val repositories =
|
||||||
|
Seq(globalPluginsRepo, interProjectRepo) ++
|
||||||
|
sourceRepositories0 ++
|
||||||
|
resolvers.flatMap(FromSbt.repository(_, ivyProperties, log)) ++
|
||||||
|
fallbackDependenciesRepositories
|
||||||
|
|
||||||
def resolution = {
|
def resolution = {
|
||||||
val pool = Executors.newFixedThreadPool(parallelDownloads, Strategy.DefaultDaemonThreadFactory)
|
val pool = Executors.newFixedThreadPool(parallelDownloads, Strategy.DefaultDaemonThreadFactory)
|
||||||
|
|
@ -748,4 +793,93 @@ object Tasks {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def coursierExportTask =
|
||||||
|
(
|
||||||
|
sbt.Keys.state,
|
||||||
|
sbt.Keys.thisProjectRef,
|
||||||
|
sbt.Keys.projectID,
|
||||||
|
sbt.Keys.scalaVersion,
|
||||||
|
sbt.Keys.scalaBinaryVersion,
|
||||||
|
sbt.Keys.ivyConfigurations,
|
||||||
|
streams,
|
||||||
|
coursierProject,
|
||||||
|
coursierExportDirectory,
|
||||||
|
coursierExportJavadoc,
|
||||||
|
coursierExportSources
|
||||||
|
).flatMap { (state, projectRef, projId, sv, sbv, ivyConfs, streams, proj, exportDir, exportJavadoc, exportSources) =>
|
||||||
|
|
||||||
|
val javadocPackageTasks =
|
||||||
|
if (exportJavadoc)
|
||||||
|
Seq(Some("javadoc") -> packageDoc)
|
||||||
|
else
|
||||||
|
Nil
|
||||||
|
|
||||||
|
val sourcesPackageTasks =
|
||||||
|
if (exportJavadoc)
|
||||||
|
Seq(Some("sources") -> packageSrc)
|
||||||
|
else
|
||||||
|
Nil
|
||||||
|
|
||||||
|
val packageTasks = Seq(None -> packageBin) ++ javadocPackageTasks ++ sourcesPackageTasks
|
||||||
|
|
||||||
|
val configs = Seq(None -> Compile, Some("tests") -> Test)
|
||||||
|
|
||||||
|
val productTasks =
|
||||||
|
for {
|
||||||
|
(classifierOpt, pkgTask) <- packageTasks
|
||||||
|
(classifierPrefixOpt, config) <- configs
|
||||||
|
if publishArtifact.in(projectRef).in(pkgTask).in(config).getOrElse(state, false)
|
||||||
|
} yield {
|
||||||
|
val classifier = (classifierPrefixOpt.toSeq ++ classifierOpt.toSeq).mkString("-")
|
||||||
|
pkgTask.in(projectRef).in(config).get(state).map((classifier, _))
|
||||||
|
}
|
||||||
|
|
||||||
|
val productTask = sbt.std.TaskExtra.joinTasks(productTasks).join
|
||||||
|
|
||||||
|
val dir = new File(
|
||||||
|
exportDir,
|
||||||
|
s"${proj.module.organization.replace('.', '/')}/${proj.module.name}/${proj.version}"
|
||||||
|
)
|
||||||
|
|
||||||
|
def pom = "<?xml version='1.0' encoding='UTF-8'?>\n" + WritePom.project(proj, Some("jar"))
|
||||||
|
|
||||||
|
val log = streams.log
|
||||||
|
|
||||||
|
productTask.map { products =>
|
||||||
|
|
||||||
|
if (products.isEmpty)
|
||||||
|
None
|
||||||
|
else {
|
||||||
|
|
||||||
|
dir.mkdirs()
|
||||||
|
|
||||||
|
val pomFile = new File(dir, s"${proj.module.name}-${proj.version}.pom")
|
||||||
|
Files.write(pomFile.toPath, pom.getBytes("UTF-8"))
|
||||||
|
log.info(s"Wrote POM file to $pomFile")
|
||||||
|
|
||||||
|
for ((classifier, f) <- products) {
|
||||||
|
|
||||||
|
val suffix = if (classifier.isEmpty) "" else "-" + classifier
|
||||||
|
|
||||||
|
val jarPath = new File(dir, s"${proj.module.name}-${proj.version}$suffix.jar")
|
||||||
|
|
||||||
|
if (jarPath.exists()) {
|
||||||
|
if (!jarPath.delete())
|
||||||
|
log.warn(s"Cannot remove $jarPath")
|
||||||
|
}
|
||||||
|
|
||||||
|
Files.createSymbolicLink(
|
||||||
|
jarPath.toPath,
|
||||||
|
dir.toPath.relativize(f.toPath)
|
||||||
|
)
|
||||||
|
log.info(s"Created symbolic link $jarPath -> $f")
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO Clean extra files in dir
|
||||||
|
|
||||||
|
Some(exportDir)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue