From 3821239b438138cd038828000173a0d7e184cf3c Mon Sep 17 00:00:00 2001 From: Mark Harrah Date: Sat, 19 Mar 2011 14:06:11 -0400 Subject: [PATCH] cleanup --- .../src/main/resources/scalac-plugin.xml | 4 - .../main/scala/sbt/BasicProjectTypes.scala | 571 ----------- .../src/main/scala/sbt/BuilderProject.scala | 262 ----- sbt_pending/src/main/scala/sbt/Control.scala | 73 -- sbt_pending/src/main/scala/sbt/FileTask.scala | 109 -- .../src/main/scala/sbt/FileUtilities.scala | 933 ------------------ .../main/scala/sbt/IntegrationTesting.scala | 94 -- sbt_pending/src/main/scala/sbt/Main.scala | 774 --------------- sbt_pending/src/main/scala/sbt/Project.scala | 537 ---------- .../src/main/scala/sbt/ProjectConsole.scala | 79 -- .../src/main/scala/sbt/ProjectInfo.scala | 140 --- .../src/main/scala/sbt/ProjectPaths.scala | 302 ------ .../src/main/scala/sbt/TaskManager.scala | 104 -- .../main/scala/sbt/impl/CommandParser.scala | 61 -- .../scala/sbt/processor/CommandRunner.scala | 28 - .../main/scala/sbt/processor/Execute.scala | 24 - .../main/scala/sbt/processor/Handler.scala | 35 - .../src/main/scala/sbt/processor/Info.scala | 26 - .../src/main/scala/sbt/processor/Loader.scala | 41 - .../main/scala/sbt/processor/Manager.scala | 84 -- .../src/main/scala/sbt/processor/Parser.scala | 50 - .../main/scala/sbt/processor/Persist.scala | 26 - .../main/scala/sbt/processor/Processor.scala | 148 --- .../main/scala/sbt/processor/Retrieve.scala | 33 - .../scala/sbt/NameFilterSpecification.scala | 39 - .../test/scala/sbt/VersionSpecification.scala | 61 -- .../scala/sbt/wrap/MutableSetWrapper.scala | 89 -- 27 files changed, 4727 deletions(-) delete mode 100644 sbt_pending/src/main/resources/scalac-plugin.xml delete mode 100644 sbt_pending/src/main/scala/sbt/BasicProjectTypes.scala delete mode 100644 sbt_pending/src/main/scala/sbt/BuilderProject.scala delete mode 100644 sbt_pending/src/main/scala/sbt/Control.scala delete mode 100644 sbt_pending/src/main/scala/sbt/FileTask.scala delete mode 100644 sbt_pending/src/main/scala/sbt/FileUtilities.scala delete mode 100644 sbt_pending/src/main/scala/sbt/IntegrationTesting.scala delete mode 100755 sbt_pending/src/main/scala/sbt/Main.scala delete mode 100644 sbt_pending/src/main/scala/sbt/Project.scala delete mode 100644 sbt_pending/src/main/scala/sbt/ProjectConsole.scala delete mode 100644 sbt_pending/src/main/scala/sbt/ProjectInfo.scala delete mode 100644 sbt_pending/src/main/scala/sbt/ProjectPaths.scala delete mode 100644 sbt_pending/src/main/scala/sbt/TaskManager.scala delete mode 100644 sbt_pending/src/main/scala/sbt/impl/CommandParser.scala delete mode 100644 sbt_pending/src/main/scala/sbt/processor/CommandRunner.scala delete mode 100644 sbt_pending/src/main/scala/sbt/processor/Execute.scala delete mode 100644 sbt_pending/src/main/scala/sbt/processor/Handler.scala delete mode 100644 sbt_pending/src/main/scala/sbt/processor/Info.scala delete mode 100644 sbt_pending/src/main/scala/sbt/processor/Loader.scala delete mode 100644 sbt_pending/src/main/scala/sbt/processor/Manager.scala delete mode 100644 sbt_pending/src/main/scala/sbt/processor/Parser.scala delete mode 100644 sbt_pending/src/main/scala/sbt/processor/Persist.scala delete mode 100644 sbt_pending/src/main/scala/sbt/processor/Processor.scala delete mode 100644 sbt_pending/src/main/scala/sbt/processor/Retrieve.scala delete mode 100644 sbt_pending/src/test/scala/sbt/NameFilterSpecification.scala delete mode 100644 sbt_pending/src/test/scala/sbt/VersionSpecification.scala delete mode 100644 sbt_pending/src/test/scala/sbt/wrap/MutableSetWrapper.scala diff --git a/sbt_pending/src/main/resources/scalac-plugin.xml b/sbt_pending/src/main/resources/scalac-plugin.xml deleted file mode 100644 index 54ec5669c..000000000 --- a/sbt_pending/src/main/resources/scalac-plugin.xml +++ /dev/null @@ -1,4 +0,0 @@ - - sbt-analyze - sbt.Analyzer - diff --git a/sbt_pending/src/main/scala/sbt/BasicProjectTypes.scala b/sbt_pending/src/main/scala/sbt/BasicProjectTypes.scala deleted file mode 100644 index 1a7ef203e..000000000 --- a/sbt_pending/src/main/scala/sbt/BasicProjectTypes.scala +++ /dev/null @@ -1,571 +0,0 @@ -/* sbt -- Simple Build Tool - * Copyright 2009 Mark Harrah - */ -package sbt - -import scala.xml.{Node, NodeSeq} -import StringUtilities.{appendable,nonEmpty} -import BasicManagedProject._ - -/** A project that provides a classpath. */ -trait ClasspathProject extends Project -{ - /** The local classpath for this project.*/ - def projectClasspath(config: Configuration): PathFinder - - /** Returns the classpath of this project and the classpaths of all dependencies for the - * given configuration. Specifically, this concatentates projectClasspath(config) for all - * projects of type ClasspathProject in topologicalSort. */ - def fullClasspath(config: Configuration): PathFinder = - Path.lazyPathFinder - { - val set = new wrap.MutableSetWrapper(new java.util.LinkedHashSet[Path]) - for(project <- topologicalSort) - { - project match - { - case sp: ClasspathProject => set ++= sp.projectClasspath(config).get - case _ => () - } - } - set.toList - } - /* Filter used to select dependencies for the classpath from managed and unmanaged directories. - * By default, it explicitly filters (x)sbt-launch(er)-.jar, since it contains minified versions of various classes.*/ - def classpathFilter: FileFilter = "*.jar" - "*sbt-launch*.jar" -} -trait BasicDependencyProject extends BasicManagedProject with UnmanagedClasspathProject -{ - /** This returns the classpath for only this project for the given configuration.*/ - def projectClasspath(config: Configuration) = fullUnmanagedClasspath(config) +++ managedClasspath(config) -} -/** A project that provides a directory in which jars can be manually managed.*/ -trait UnmanagedClasspathProject extends ClasspathProject -{ - /** The location of the manually managed (unmanaged) dependency directory.*/ - def dependencyPath: Path - /** The classpath containing all jars in the unmanaged directory. */ - def unmanagedClasspath: PathFinder = - { - val base = descendents(dependencyPath, classpathFilter) - if(scratch) - base +++ (info.projectPath * classpathFilter) - else - base - } - /** The classpath containing all unmanaged classpath elements for the given configuration. This typically includes - * at least 'unmanagedClasspath'.*/ - def fullUnmanagedClasspath(config: Configuration): PathFinder -} - -trait IvyTasks extends Project -{ - def ivyTask(action: => Unit) = - task - { - try { action; None } - catch { - case e: ResolveException => - log.error(e.toString) - Some(e.toString) - case e: Exception => - log.trace(e) - log.error(e.toString) - Some(e.toString) - } - } - def updateTask(module: => IvySbt#Module, configuration: => UpdateConfiguration) = - ivyTask { IvyActions.update(module, configuration) } - - def publishTask(module: => IvySbt#Module, publishConfiguration: => PublishConfiguration) = - ivyTask - { - val publishConfig = publishConfiguration - import publishConfig._ - val deliveredIvy = if(publishIvy) Some(deliveredPattern) else None - IvyActions.publish(module, resolverName, srcArtifactPatterns, deliveredIvy, configurations) - } - def deliverTask(module: => IvySbt#Module, deliverConfiguration: => PublishConfiguration, logging: => UpdateLogging.Value) = - ivyTask - { - val deliverConfig = deliverConfiguration - import deliverConfig._ - IvyActions.deliver(module, status, deliveredPattern, extraDependencies, configurations, logging) - } - @deprecated def makePomTask(module: => IvySbt#Module, output: => Path, extraDependencies: => Iterable[ModuleID], pomExtra: => NodeSeq, configurations: => Option[Iterable[Configuration]]): Task = - makePomTask(module, MakePomConfiguration(extraDependencies, configurations, pomExtra), output) - def makePomTask(module: => IvySbt#Module, configuration: => MakePomConfiguration, output: => Path): Task = - ivyTask { IvyActions.makePom(module, configuration, output asFile) } - - - def installTask(module: IvySbt#Module, from: Resolver, to: Resolver) = - ivyTask { IvyActions.install(module, from.name, to.name) } - - def cleanCacheTask(ivySbt: => IvySbt) = - ivyTask { IvyActions.cleanCache(ivySbt) } - - def cleanLibTask(managedDependencyPath: Path) = - task { FileUtilities.clean(managedDependencyPath.get, log) } -} - -/** A project that provides automatic dependency management.*/ -trait ManagedProject extends ClasspathProject with IvyTasks -{ - /** This is the public ID of the project (used for publishing, for example) */ - def moduleID: String = normalizedName - /** This is the full public ID of the project (used for publishing, for example) */ - def projectID: ModuleID = ModuleID(organization, moduleID, version.toString).artifacts(artifacts.toSeq : _*).cross(true) - - /** This is the default name for artifacts (such as jars) without any version string.*/ - def artifactID = moduleID - /** This is the default name for artifacts (such as jars) including the version string.*/ - def artifactBaseName = artifactID + "-" + version.toString - def artifacts: Iterable[Artifact] - - def managedDependencyPath: Path - /** The managed classpath for the given configuration. This can be overridden to add jars from other configurations - * so that the Ivy 'extends' mechanism is not required. That way, the jars are only copied to one configuration.*/ - def managedClasspath(config: Configuration): PathFinder = configurationClasspath(config) - /** All dependencies in the given configuration. */ - final def configurationClasspath(config: Configuration): PathFinder = descendents(configurationPath(config), classpathFilter) - - /** The base path to which dependencies in configuration 'config' are downloaded.*/ - def configurationPath(config: Configuration): Path = managedDependencyPath / config.toString - - - /** Creates a new configuration with the given name.*/ - def config(name: String) = new Configuration(name) -} -/** This class groups required configuration for the deliver and publish tasks. */ -trait PublishConfiguration extends NotNull -{ - /** The name of the resolver to which publishing should be done.*/ - def resolverName: String - /** The Ivy pattern used to determine the delivered Ivy file location. An example is - * (outputPath / "[artifact]-[revision].[ext]").relativePath. */ - def deliveredPattern: String - /** Ivy patterns used to find artifacts for publishing. An example pattern is - * (outputPath / "[artifact]-[revision].[ext]").relativePath */ - def srcArtifactPatterns: Iterable[String] - /** Additional dependencies to include for delivering/publishing only. These are typically dependencies on - * subprojects. */ - def extraDependencies: Iterable[ModuleID] - /** The status to use when delivering or publishing. This might be "release" or "integration" or another valid Ivy status. */ - def status: String - /** The configurations to include in the publish/deliver action: specify none for all configurations. */ - def configurations: Option[Iterable[Configuration]] - /** True if the Ivy file should be published. */ - def publishIvy: Boolean -} -object ManagedStyle extends Enumeration -{ - val Maven, Ivy, Auto = Value -} -import ManagedStyle.{Auto, Ivy, Maven, Value => ManagedType} -trait BasicManagedProject extends ManagedProject with ReflectiveManagedProject with BasicDependencyPaths -{ - def ivyUpdateConfiguration = new UpdateConfiguration(managedDependencyPath.asFile, outputPattern, true/*sync*/, ivyUpdateLogging) - def ivyUpdateLogging = UpdateLogging.DownloadOnly - def ivyLocalOnly: Boolean = offline.value - - def ivyRepositories: Seq[Resolver] = - { - val repos = repositories.toSeq - if(repos.isEmpty) Nil else Resolver.withDefaultResolvers(repos) - } - def otherRepositories: Seq[Resolver] = defaultPublishRepository.toList - def ivyValidate = true - def ivyScala: Option[IvyScala] = Some(new IvyScala(buildScalaVersion, checkScalaInConfigurations, checkExplicitScalaDependencies, filterScalaJars)) - def ivyCacheDirectory: Option[Path] = None - - def ivyPaths: IvyPaths = new IvyPaths(info.projectPath.asFile, ivyCacheDirectory.map(_.asFile)) - def inlineIvyConfiguration = new InlineIvyConfiguration(ivyPaths, ivyRepositories.toSeq, otherRepositories, moduleConfigurations.toSeq, ivyLocalOnly, Some(info.launcher.globalLock), log) - def ivyConfiguration: IvyConfiguration = - { - val in = inlineIvyConfiguration - def adapt(c: IvyConfiguration): IvyConfiguration = c.withBase(in.baseDirectory) - def parentIvyConfiguration(default: IvyConfiguration)(p: Project) = p match { case b: BasicManagedProject => adapt(b.ivyConfiguration); case _ => default } - if(in.resolvers.isEmpty) - { - if(in.moduleConfigurations.isEmpty && in.otherResolvers.isEmpty) - { - IvyConfiguration(in.paths, in.lock, in.localOnly, in.log) match - { - case e: ExternalIvyConfiguration => e - case i => info.parent map(parentIvyConfiguration(i)) getOrElse(i) - } - } - else - in.changeResolvers(Resolver.withDefaultResolvers(Nil)) - } - else - in - } - - def moduleSettings: ModuleSettings = defaultModuleSettings - def byIvyFile(path: Path): IvyFileConfiguration = new IvyFileConfiguration(path.asFile, ivyScala, ivyValidate) - def byPom(path: Path): PomConfiguration = new PomConfiguration(path.asFile, ivyScala, ivyValidate) - /** The settings that represent inline declarations. The default settings combines the information - * from 'ivyXML', 'projectID', 'repositories', ivyConfigurations, defaultConfiguration, - * ivyScala, and 'libraryDependencies' and does not typically need to be be overridden. */ - def inlineSettings = new InlineConfiguration(projectID, withCompat, ivyXML, ivyConfigurations, defaultConfiguration, ivyScala, ivyValidate) - /** Library dependencies with extra dependencies for compatibility*/ - private def withCompat = - { - val deps = libraryDependencies - deps ++ compatExtra(deps) - } - /** Determines extra libraries needed for compatibility. Currently, this is the compatibility test framework. */ - private def compatExtra(deps: Set[ModuleID]) = - if(isScala27 && deps.exists(requiresCompat)) { log.debug("Using compatibility implementation of test interface."); compatTestFramework } else Nil - /** True if the given dependency requires the compatibility test framework. */ - private def requiresCompat(m: ModuleID) = - { - def nameMatches(name: String, id: String) = name == id || name.startsWith(id + "_2.7.") - - (nameMatches(m.name, "scalacheck") && Set("1.5", "1.6").contains(m.revision)) || - (nameMatches(m.name, "specs") && Set("1.6.0", "1.6.1").contains(m.revision)) || - (nameMatches(m.name, "scalatest") && m.revision == "1.0") - } - /** Extra dependencies to add if a dependency on an older test framework (one released before the uniform test interface) is declared. - * This is the compatibility test framework by default.*/ - def compatTestFramework = Set("org.scala-tools.sbt" %% "test-compat" % "0.4.1" % "test") - - def defaultModuleSettings: ModuleSettings = - { - val in = inlineSettings - if(in.configurations.isEmpty) - { - if(in.dependencies.isEmpty && in.ivyXML.isEmpty && (in.module.explicitArtifacts.size <= 1) && in.configurations.isEmpty) - externalSettings - else if(useDefaultConfigurations) - in withConfigurations ( Configurations.defaultMavenConfigurations ) - else - in - } - else - in - } - def externalSettings = ModuleSettings(ivyScala, ivyValidate, projectID)(info.projectPath.asFile, log) - - def ivySbt: IvySbt = new IvySbt(ivyConfiguration) - def ivyModule: IvySbt#Module = newIvyModule(moduleSettings) - def newIvyModule(moduleSettings: ModuleSettings): IvySbt#Module = - { - val i = ivySbt - new i.Module(moduleSettings) - } - - - /** The pattern for Ivy to use when retrieving dependencies into the local project. Classpath management - * depends on the first directory being [conf] and the extension being [ext].*/ - def outputPattern = "[conf]/[artifact](-[revision])(-[classifier]).[ext]" - /** Override this to specify the publications, configurations, and/or dependencies sections of an Ivy file. - * See http://code.google.com/p/simple-build-tool/wiki/LibraryManagement for details.*/ - def ivyXML: NodeSeq = NodeSeq.Empty - def pomExtra: NodeSeq = NodeSeq.Empty - - override def ivyConfigurations: Iterable[Configuration] = - { - val reflective = super.ivyConfigurations - val extra = extraDefaultConfigurations - if(useDefaultConfigurations) - { - if(reflective.isEmpty && extra.isEmpty) - Nil - else - Configurations.removeDuplicates(Configurations.defaultMavenConfigurations ++ reflective ++ extra) - } - else - reflective ++ extra - } - def extraDefaultConfigurations: List[Configuration] = Nil - def useIntegrationTestConfiguration = false - def defaultConfiguration: Option[Configuration] = Some(Configurations.DefaultConfiguration(useDefaultConfigurations)) - def useMavenConfigurations = true // TODO: deprecate after going through a minor version series to verify that this works ok - def useDefaultConfigurations = useMavenConfigurations - def managedStyle: ManagedType = - info.parent match - { - case Some(m: BasicManagedProject) => m.managedStyle - case _ => Auto - } - protected implicit final val defaultPatterns: Patterns = - { - managedStyle match - { - case Maven => Resolver.mavenStylePatterns - case Ivy => Resolver.ivyStylePatterns - case Auto => Resolver.defaultPatterns - } - } - - def updateModuleSettings = moduleSettings - def updateIvyModule = newIvyModule(updateModuleSettings) - def deliverModuleSettings = moduleSettings.noScala - def deliverIvyModule = newIvyModule(deliverModuleSettings) - def publishModuleSettings = deliverModuleSettings - def publishIvyModule = newIvyModule(publishModuleSettings) - /** True if the default implicit extensions should be used when determining classpaths. The default value is true. */ - def defaultConfigurationExtensions = true - /** If true, verify that explicit dependencies on Scala libraries use the same version as scala.version. */ - def checkExplicitScalaDependencies = true - /** If true, filter dependencies on scala-library and scala-compiler. This is true by default to avoid conflicts with - * the jars provided by sbt. You can set this to false to download these jars. Overriding checkScalaInConfigurations might - * be more appropriate, however.*/ - def filterScalaJars = true - /** The configurations to check/filter.*/ - def checkScalaInConfigurations: Iterable[Configuration] = ivyConfigurations - def defaultPublishRepository: Option[Resolver] = - { - reflectiveRepositories.get(PublishToName) orElse - info.parent.flatMap - { - case managed: BasicManagedProject => managed.defaultPublishRepository - case _ => None - } - } - /** Includes the Compile configuration on the Runtime classpath, and Compile and Runtime on the Test classpath. - * Including Compile and Runtime can be disabled by setting defaultConfigurationExtensions to false.*/ - override def managedClasspath(config: Configuration) = - { - import Configurations.{Compile, Default, Runtime, Test} - val baseClasspath = configurationClasspath(config) - config match - { - case Compile => baseClasspath +++ managedClasspath(Default) - case Runtime if defaultConfigurationExtensions => baseClasspath +++ managedClasspath(Compile) - case Test if defaultConfigurationExtensions => baseClasspath +++ managedClasspath(Runtime) - case _ => baseClasspath - } - } - - protected def updateAction = updateTask(updateIvyModule, ivyUpdateConfiguration) describedAs UpdateDescription - protected def cleanLibAction = cleanLibTask(managedDependencyPath) describedAs CleanLibDescription - protected def cleanCacheAction = cleanCacheTask(ivySbt) describedAs CleanCacheDescription - - protected def deliverProjectDependencies: Iterable[ModuleID] = - { - val interDependencies = new scala.collection.mutable.ListBuffer[ModuleID] - dependencies.foreach(dep => dep match { case mp: ManagedProject => interDependencies += mp.projectID; case _ => () }) - if(filterScalaJars) - interDependencies ++= deliverScalaDependencies - interDependencies.readOnly - } - def pomIncludeRepository(repo: MavenRepository): Boolean = !repo.root.startsWith("file:") - def pomPostProcess(pom: Node): Node = pom - - def makePomConfiguration = new MakePomConfiguration(deliverProjectDependencies, None, pomExtra, pomPostProcess, pomIncludeRepository) - protected def deliverScalaDependencies: Iterable[ModuleID] = Nil - protected def makePomAction = makePomTask(deliverIvyModule, makePomConfiguration, pomPath) - protected def deliverLocalAction = deliverTask(deliverIvyModule, publishLocalConfiguration, ivyUpdateLogging) - protected def publishLocalAction = - { - val dependencies = deliverLocal :: publishPomDepends - publishTask(publishIvyModule, publishLocalConfiguration) dependsOn(dependencies : _*) - } - protected def publishLocalConfiguration = new DefaultPublishConfiguration("local", "release", true) - protected def deliverAction = deliverTask(deliverIvyModule, publishConfiguration, ivyUpdateLogging) - protected def publishAction = - { - val dependencies = deliver :: publishPomDepends - publishTask(publishIvyModule, publishConfiguration) dependsOn(dependencies : _*) - } - private def publishPomDepends = if(managedStyle == Maven) makePom :: Nil else Nil - protected def publishConfiguration = - { - val repository = defaultPublishRepository.getOrElse(error("Repository to publish to not specified.")) - val publishIvy = managedStyle != Maven - new DefaultPublishConfiguration(repository, "release", publishIvy) - } - protected class DefaultPublishConfiguration(val resolverName: String, val status: String, val publishIvy: Boolean) extends PublishConfiguration - { - def this(resolver: Resolver, status: String, publishIvy: Boolean) = this(resolver.name, status, publishIvy) - def this(resolverName: String, status: String) = this(resolverName, status, true) - def this(resolver: Resolver, status: String) = this(resolver.name, status) - - protected def deliveredPathPattern = outputPath / "[artifact]-[revision](-[classifier]).[ext]" - def deliveredPattern = deliveredPathPattern.relativePath - def srcArtifactPatterns: Iterable[String] = - { - val pathPatterns = - (outputPath / "[artifact]-[revision]-[type](-[classifier]).[ext]") :: - (outputPath / "[artifact]-[revision](-[classifier]).[ext]") :: - Nil - pathPatterns.map(_.relativePath) - } - def extraDependencies: Iterable[ModuleID] = deliverProjectDependencies - /** The configurations to include in the publish/deliver action: specify none for all public configurations. */ - def configurations: Option[Iterable[Configuration]] = None - } - - def packageToPublishActions: Seq[ManagedTask] = Nil - - private[this] def depMap[T](f: BasicManagedProject => T) = - topologicalSort.dropRight(1).flatMap { case m: BasicManagedProject => f(m) :: Nil; case _ => Nil } - - lazy val update = updateAction - lazy val makePom = makePomAction dependsOn(packageToPublishActions : _*) - lazy val cleanLib = cleanLibAction - lazy val cleanCache = cleanCacheAction - // deliver must run after its dependencies' `publish` so that the artifacts produced by the dependencies can be resolved - // (deliver requires a resolve first) - lazy val deliverLocal: Task = deliverLocalAction dependsOn((depMap(_.publishLocal) ++ packageToPublishActions) : _*) - lazy val publishLocal: Task = publishLocalAction - lazy val deliver: Task = deliverAction dependsOn((depMap(_.publish) ++ packageToPublishActions) : _*) - lazy val publish: Task = publishAction -} - -object BasicManagedProject -{ - val UpdateDescription = - "Resolves and retrieves automatically managed dependencies." - val CleanLibDescription = - "Deletes the managed library directory." - val CleanCacheDescription = - "Deletes the cache of artifacts downloaded for automatically managed dependencies." - - val PublishToName = "publish-to" - val RetrieveFromName = "retrieve-from" -} - -class DefaultInstallProject(val info: ProjectInfo) extends InstallProject with MavenStyleScalaPaths with BasicDependencyProject -{ - def fullUnmanagedClasspath(config: Configuration) = unmanagedClasspath - def dependencies = info.dependencies -} -trait InstallProject extends BasicManagedProject -{ - def installModuleSettings: ModuleSettings = moduleSettings.noScala - def installIvyModule: IvySbt#Module = newIvyModule(installModuleSettings) - - lazy val install = installTask(installIvyModule, fromResolver, toResolver) - def toResolver = reflectiveRepositories.get(PublishToName).getOrElse(error("No repository to publish to was specified")) - def fromResolver = reflectiveRepositories.get(RetrieveFromName).getOrElse(error("No repository to retrieve from was specified")) -} - -trait BasicDependencyPaths extends ManagedProject -{ - import BasicDependencyPaths._ - def dependencyDirectoryName = DefaultDependencyDirectoryName - def managedDirectoryName = DefaultManagedDirectoryName - def pomName = artifactBaseName + PomExtension - def dependencyPath = path(dependencyDirectoryName) - def managedDependencyPath = crossPath(managedDependencyRootPath) - def managedDependencyRootPath: Path = managedDirectoryName - def pomPath = outputPath / pomName -} -object BasicDependencyPaths -{ - val DefaultManagedDirectoryName = "lib_managed" - val DefaultManagedSourceDirectoryName = "src_managed" - val DefaultDependencyDirectoryName = "lib" - val PomExtension = ".pom" -} -import scala.collection.{Map, mutable} -/** A Project that determines its tasks by reflectively finding all vals with a type -* that conforms to Task.*/ -trait ReflectiveTasks extends Project -{ - def tasks: Map[String, ManagedTask] = reflectiveTaskMappings - def reflectiveTaskMappings : Map[String, Task] = Reflective.reflectiveMappings[Task](this) -} -/** A Project that determines its method tasks by reflectively finding all vals with a type -* that conforms to MethodTask.*/ -trait ReflectiveMethods extends Project -{ - def methods: Map[String, MethodTask] = reflectiveMethodMappings - def reflectiveMethodMappings : Map[String, MethodTask] = Reflective.reflectiveMappings[MethodTask](this) -} -/** A Project that determines its dependencies on other projects by reflectively -* finding all vals with a type that conforms to Project.*/ -trait ReflectiveModules extends Project -{ - override def subProjects: Map[String, Project] = reflectiveModuleMappings - def reflectiveModuleMappings : Map[String, Project] = Reflective.reflectiveMappings[Project](this) -} -/** A Project that determines its dependencies on other projects by reflectively -* finding all vals with a type that conforms to Project and determines its tasks -* by reflectively finding all vals with a type that conforms to Task.*/ -trait ReflectiveProject extends ReflectiveModules with ReflectiveTasks with ReflectiveMethods - -/** This Project subclass is used to contain other projects as dependencies.*/ -class ParentProject(val info: ProjectInfo) extends BasicDependencyProject with Cleanable -{ - def dependencies: Iterable[Project] = info.dependencies ++ subProjects.values.toList - /** The directories to which a project writes are listed here and is used - * to check a project and its dependencies for collisions.*/ - override def outputDirectories = managedDependencyPath :: outputPath :: Nil - def fullUnmanagedClasspath(config: Configuration) = unmanagedClasspath -} - -object Reflective -{ - def reflectiveMappings[T](obj: AnyRef)(implicit m: scala.reflect.Manifest[T]): Map[String, T] = - { - val mappings = new mutable.HashMap[String, T] - for ((name, value) <- ReflectUtilities.allVals[T](obj)) - mappings(ReflectUtilities.transformCamelCase(name, '-')) = value - mappings - } -} - -/** A Project that determines its library dependencies by reflectively finding all vals with a type -* that conforms to ModuleID.*/ -trait ReflectiveLibraryDependencies extends ManagedProject -{ - def excludeIDs: Iterable[ModuleID] = projectID :: Nil - /** Defines the library dependencies of this project. By default, this finds vals of type ModuleID defined on the project. - * This can be overridden to directly provide dependencies */ - def libraryDependencies: Set[ModuleID] = reflectiveLibraryDependencies - def reflectiveLibraryDependencies : Set[ModuleID] = Set[ModuleID](Reflective.reflectiveMappings[ModuleID](this).values.toList: _*) -- excludeIDs -} - -trait ReflectiveConfigurations extends Project -{ - def ivyConfigurations: Iterable[Configuration] = reflectiveIvyConfigurations - def reflectiveIvyConfigurations: Set[Configuration] = Configurations.removeDuplicates(Reflective.reflectiveMappings[Configuration](this).values.toList) -} -trait ReflectiveArtifacts extends ManagedProject -{ - def managedStyle: ManagedType - def artifacts: Set[Artifact] = - { - val reflective = reflectiveArtifacts - managedStyle match - { - case Maven => reflective ++ List(Artifact(artifactID, "pom", "pom")) - case Ivy => reflective - case Auto => reflective - } - } - def reflectiveArtifacts: Set[Artifact] = Set(Reflective.reflectiveMappings[Artifact](this).values.toList: _*) -} -/** A Project that determines its library dependencies by reflectively finding all vals with a type -* that conforms to ModuleID.*/ -trait ReflectiveRepositories extends Project -{ - def repositories: Set[Resolver] = - { - val reflective = Set[Resolver]() ++ reflectiveRepositories.toList.flatMap { case (PublishToName, _) => Nil; case (_, value) => List(value) } - info.parent match - { - case Some(p: ReflectiveRepositories) => p.repositories ++ reflective - case None => reflective - } - } - def reflectiveRepositories: Map[String, Resolver] = Reflective.reflectiveMappings[Resolver](this) - - def moduleConfigurations: Set[ModuleConfiguration] = - { - val reflective = Set[ModuleConfiguration](reflectiveModuleConfigurations.values.toList: _*) - info.parent match - { - case Some(p: ReflectiveRepositories) => p.moduleConfigurations ++ reflective - case None => reflective - } - } - def reflectiveModuleConfigurations: Map[String, ModuleConfiguration] = Reflective.reflectiveMappings[ModuleConfiguration](this) -} - -trait ReflectiveManagedProject extends ReflectiveProject with ReflectiveArtifacts with ReflectiveRepositories with ReflectiveLibraryDependencies with ReflectiveConfigurations \ No newline at end of file diff --git a/sbt_pending/src/main/scala/sbt/BuilderProject.scala b/sbt_pending/src/main/scala/sbt/BuilderProject.scala deleted file mode 100644 index 3504ebc72..000000000 --- a/sbt_pending/src/main/scala/sbt/BuilderProject.scala +++ /dev/null @@ -1,262 +0,0 @@ -/* sbt -- Simple Build Tool - * Copyright 2008, 2009 Mark Harrah, David MacIver - */ -package sbt - -import BasicProjectPaths._ -import scala.collection.{immutable, Map} -import immutable.Map.{empty => emptyMap} - -sealed abstract class InternalProject extends Project -{ - override def defaultLoggingLevel = Level.Warn - override final def historyPath = None - override def tasks: Map[String, ManagedTask] = emptyMap - override final protected def disableCrossPaths = false - override final def shouldCheckOutputDirectories = false -} -sealed abstract class BasicBuilderProject extends InternalProject -{ - def sourceFilter = "*.scala" | "*.java" - def jarFilter: NameFilter = "*.jar" - def compilePath = outputPath / DefaultMainCompileDirectoryName - def mainResourcesPath = path(DefaultResourcesDirectoryName) - def dependencyPath = path(DefaultDependencyDirectoryName) - def libraries = descendents(dependencyPath, jarFilter) - override final def dependencies = Nil - - protected final def logInfo(messages: String*): Unit = atInfo { messages.foreach(message => log.info(message)) } - protected final def atInfo(action: => Unit) - { - val oldLevel = log.getLevel - log.setLevel(Level.Info) - action - log.setLevel(oldLevel) - } - - def projectClasspath = compilePath +++ libraries +++ sbtJars - def sbtJars = info.sbtClasspath - - abstract class BuilderCompileConfiguration extends AbstractCompileConfiguration - { - def projectPath = info.projectPath - def log = BasicBuilderProject.this.log - def options = CompileOptions.Deprecation :: CompileOptions.Unchecked :: Nil - def javaOptions = Nil - def maxErrors = ScalaProject.DefaultMaximumCompileErrors - def compileOrder = CompileOrder.Mixed - } - def definitionCompileConfiguration = - new BuilderCompileConfiguration - { - def label = "builder" - def sourceRoots = info.projectPath +++ path(DefaultSourceDirectoryName) - def sources = (info.projectPath * sourceFilter) +++ path(DefaultSourceDirectoryName).descendentsExcept(sourceFilter, defaultExcludes) - def outputDirectory = compilePath - def classpath = projectClasspath - def analysisPath = outputPath / DefaultMainAnalysisDirectoryName - } - - def tpe: String - - import xsbt.ScalaInstance - - lazy val definitionCompileConditional = new BuilderCompileConditional(definitionCompileConfiguration, buildCompiler, tpe) - final class BuilderCompileConditional(config: BuilderCompileConfiguration, compiler: xsbt.AnalyzingCompiler, tpe: String) extends AbstractCompileConditional(config, compiler) - { - type AnalysisType = BuilderCompileAnalysis - override protected def constructAnalysis(analysisPath: Path, projectPath: Path, log: Logger) = - new BuilderCompileAnalysis(analysisPath, projectPath, log) - override protected def execute(cAnalysis: ConditionalAnalysis): Option[String] = - { - if(cAnalysis.dirtySources.isEmpty) - None - else - { - definitionChanged() - logInfo( - "Recompiling " + tpe + "...", - "\t" + cAnalysis.toString) - super.execute(cAnalysis) - } - } - protected def analysisCallback: AnalysisCallback = - new BasicAnalysisCallback(info.projectPath, analysis) - { - def superclassNames = List(Project.ProjectClassName) - def annotationNames = Nil - def foundApplication(sourcePath: Path, className: String) {} - def foundAnnotated(sourcePath: Path, subclassName: String, annotationName: String, isModule: Boolean) {} - def foundSubclass(sourcePath: Path, subclassName: String, superclassName: String, isModule: Boolean) - { - if(superclassName == Project.ProjectClassName && !isModule) - { - log.debug("Found " + tpe + " " + subclassName) - analysis.addProjectDefinition(sourcePath, subclassName) - } - } - } - } - protected def definitionChanged() {} - lazy val compile = compileTask - def compileTask = task { definitionCompileConditional.run } - - def projectDefinition: Either[String, Option[String]] = - { - definitionCompileConditional.analysis.allProjects.toList match - { - case Nil => - log.debug("No " + tpe + "s detected using default project.") - Right(None) - case singleDefinition :: Nil => Right(Some(singleDefinition)) - case multipleDefinitions =>Left(multipleDefinitions.mkString("Multiple " + tpe + "s detected: \n\t","\n\t","\n")) - } - } - override final def methods = emptyMap -} -/** The project definition used to build project definitions. */ -final class BuilderProject(val info: ProjectInfo, val pluginPath: Path, rawLogger: Logger) extends BasicBuilderProject with ReflectiveTasks -{ - override def name = "Project Definition Builder" - lazy val pluginProject = - { - if(pluginPath.exists) - Some(new PluginBuilderProject(ProjectInfo(pluginPath.asFile, Nil, None)(rawLogger, info.app, info.buildScalaVersion))) - else - None - } - override def projectClasspath = super.projectClasspath +++ - pluginProject.map(_.pluginClasspath).getOrElse(Path.emptyPathFinder) - def tpe = "project definition" - - override def compileTask = super.compileTask dependsOn(pluginProject.map(_.sync).toList : _*) - override def tasks = immutable.Map() ++ super[ReflectiveTasks].tasks ++ pluginProject.toList.flatMap { _.tasks.map { case (k,v) => (k + "-plugins", v) } } - - final class PluginBuilderProject(val info: ProjectInfo) extends BasicBuilderProject with ReflectiveTasks - { - override def name = "Plugin Builder" - // don't include Java sources because BND includes Java sources in its jar (#85) - def pluginSourceFilter: NameFilter = "*.scala" - lazy val pluginUptodate = propertyOptional[Boolean](false) - def tpe = "plugin definition" - def managedSourcePath = path(BasicDependencyPaths.DefaultManagedSourceDirectoryName) - def managedDependencyPath = crossPath(BasicDependencyPaths.DefaultManagedDirectoryName) - override protected def definitionChanged() { setUptodate(false) } - override def tasks: Map[String, ManagedTask] = super[ReflectiveTasks].tasks - def setUptodate(flag: Boolean) - { - pluginUptodate() = flag - saveEnvironment() - } - - private def pluginTask(f: => Option[String]) = task { if(!pluginUptodate.value) f else None } - - lazy val sync = pluginTask(doSync()) dependsOn(extract) - lazy val extract = pluginTask(extractSources()) dependsOn(autoUpdate) - lazy val autoUpdate = pluginTask(loadAndUpdate(false)) dependsOn(compile) - // manual update. force uptodate = false - lazy val update = task { manualUpdate() } dependsOn(compile) describedAs("Manual plugin update. Used when autoUpdate is disabled.") - - def manualUpdate() = - { - setUptodate(false) - val result = loadAndUpdate(true) - logInfo("'reload' required to rebuild plugins.") - result - } - def doSync() = pluginCompileConditional.run orElse { setUptodate(true); None } - def extractSources() = - { - FileUtilities.clean(managedSourcePath, log) orElse - Control.lazyFold(plugins.get.toList) { jar => - Control.thread(FileUtilities.unzip(jar, extractTo(jar), pluginSourceFilter, log)) { extracted => - if(!extracted.isEmpty) - logInfo("\tExtracted source plugin " + jar + " ...") - None - } - } - } - def loadAndUpdate(forceUpdate: Boolean) = - { - Control.thread(projectDefinition) { - case Some(definition) => - val pluginInfo = ProjectInfo(info.projectPath.asFile, Nil, None)(rawLogger, info.app, info.buildScalaVersion) - val pluginBuilder = Project.constructProject(pluginInfo, Project.getProjectClass[PluginDefinition](definition, projectClasspath, getClass.getClassLoader)) - if(forceUpdate || pluginBuilder.autoUpdate) - { - logInfo("\nUpdating plugins...") - pluginBuilder.projectName() = "Plugin Definition" - pluginBuilder.projectVersion() = OpaqueVersion("1.0") - val result = pluginBuilder.update.run - if(result.isEmpty) - { - atInfo { - log.success("Plugins updated successfully.") - log.info("") - } - } - result - } - else - { - log.warn("Plugin definition recompiled, but autoUpdate is disabled.\n\tUsing already retrieved plugins...") - None - } - case None => None - } - } - def extractTo(jar: Path) = - { - val name = jar.asFile.getName - managedSourcePath / name.substring(0, name.length - ".jar".length) - } - def plugins = descendents(managedDependencyPath, jarFilter) - def pluginClasspath: PathFinder = plugins +++ pluginCompileConfiguration.outputDirectory - - lazy val pluginCompileConditional = new BuilderCompileConditional(pluginCompileConfiguration, buildCompiler, "plugin") - lazy val pluginCompileConfiguration = - new BuilderCompileConfiguration - { - def label = "plugin builder" - def sourceRoots = managedSourcePath - def sources = descendents(sourceRoots, sourceFilter) - def outputDirectory = outputPath / "plugin-classes" - def classpath: PathFinder = pluginClasspath +++ sbtJars - def analysisPath = outputPath / "plugin-analysis" - } - } -} -class PluginDefinition(val info: ProjectInfo) extends InternalProject with BasicManagedProject -{ - override def defaultLoggingLevel = Level.Info - override final def outputPattern = "[artifact](-[revision]).[ext]" - override final val tasks = immutable.Map("update" -> update) - override def projectClasspath(config: Configuration) = Path.emptyPathFinder - override def dependencies = info.dependencies - def autoUpdate = true -} -class PluginProject(info: ProjectInfo) extends DefaultProject(info) -{ - /* Since plugins are distributed as source, there is no need to append _ */ - override def moduleID = normalizedName - /* Fix the version used to build to the version currently running sbt. */ - override def buildScalaVersion = defScalaVersion.value - /* Add sbt to the classpath */ - override def unmanagedClasspath = super.unmanagedClasspath +++ info.sbtClasspath - /* Package the plugin as source. */ - override def packageAction = packageSrc dependsOn(test) - override def packageSrcJar = jarPath - /* Some setup to make publishing quicker to configure. */ - override def useMavenConfigurations = true - override def managedStyle = ManagedStyle.Maven -} -class ProcessorProject(info: ProjectInfo) extends DefaultProject(info) -{ - /* Fix the version used to build to the version currently running sbt. */ - override def buildScalaVersion = defScalaVersion.value - /* Add sbt to the classpath */ - override def unmanagedClasspath = super.unmanagedClasspath +++ info.sbtClasspath - /* Some setup to make publishing quicker to configure. */ - override def useMavenConfigurations = true - override def managedStyle = ManagedStyle.Maven -} \ No newline at end of file diff --git a/sbt_pending/src/main/scala/sbt/Control.scala b/sbt_pending/src/main/scala/sbt/Control.scala deleted file mode 100644 index 8117fe29a..000000000 --- a/sbt_pending/src/main/scala/sbt/Control.scala +++ /dev/null @@ -1,73 +0,0 @@ -/* sbt -- Simple Build Tool - * Copyright 2008, 2009 Mark Harrah - */ -package sbt - -/** The trap methods execute the provided code in a try block and handle a thrown exception.*/ -object Control -{ - def trap[T](errorMessagePrefix: => String, log: Logger)(execute: => Either[String, T]): Either[String, T] = - try { execute } - catch { case e => log.trace(e); Left(errorMessagePrefix + e.toString) } - - def trapAndFinally[T](errorMessagePrefix: => String, log: Logger)(execute: => Either[String, T])(doFinally: => Unit): Either[String, T] = - try { execute } - catch { case e => log.trace(e); Left(errorMessagePrefix + e.toString) } - finally { trapAndLog(log)(doFinally) } - - def trapUnit(errorMessagePrefix: => String, log: Logger)(execute: => Option[String]): Option[String] = - try { execute } - catch { case e => log.trace(e); Some(errorMessagePrefix + e.toString) } - - def trapUnitAndFinally(errorMessagePrefix: => String, log: Logger)(execute: => Option[String])(doFinally: => Unit): Option[String] = - try { execute } - catch { case e => log.trace(e); Some(errorMessagePrefix + e.toString) } - finally { trapAndLog(log)(doFinally) } - - def trap(execute: => Unit) - { - try { execute } - catch { case e: Exception => () } - } - def trapAndLog(log: Logger)(execute: => Unit) - { - try { execute } - catch { case e => log.trace(e); log.error(e.toString) } - } - def convertException[T](t: => T): Either[Exception, T] = - { - try { Right(t) } - catch { case e: Exception => Left(e) } - } - def convertErrorMessage[T](log: Logger)(t: => T): Either[String, T] = - { - try { Right(t) } - catch { case e: Exception => log.trace(e); Left(e.toString) } - } - - def getOrError[T](result: Either[String, T]): T = result.fold(error, x=>x) - final def lazyFold[T](list: List[T])(f: T => Option[String]): Option[String] = - list match - { - case Nil => None - case head :: tail => - f(head) match - { - case None => lazyFold(tail)(f) - case x => x - } - } - final def lazyFold[T, S](list: List[T], value: S)(f: (S,T) => Either[String, S]): Either[String, S] = - list match - { - case Nil => Right(value) - case head :: tail => - f(value, head) match - { - case Right(newValue) => lazyFold(tail, newValue)(f) - case x => x - } - } - def thread[T](e: Either[String, T])(f: T => Option[String]): Option[String] = - e.right.flatMap( t => f(t).toLeft(()) ).left.toOption -} \ No newline at end of file diff --git a/sbt_pending/src/main/scala/sbt/FileTask.scala b/sbt_pending/src/main/scala/sbt/FileTask.scala deleted file mode 100644 index a59883083..000000000 --- a/sbt_pending/src/main/scala/sbt/FileTask.scala +++ /dev/null @@ -1,109 +0,0 @@ -/* sbt -- Simple Build Tool - * Copyright 2009 Mark Harrah - */ -package sbt - -import scala.collection.{mutable, Map, Set} - -sealed trait ProductsSources extends NotNull -{ - def products: Iterable[Path] - def sources: Iterable[Path] -} -sealed trait ProductsWrapper extends NotNull -{ - def from(sources: => Iterable[Path]): ProductsSources = from(Path.lazyPathFinder(sources)) - def from(sources: PathFinder): ProductsSources -} -/** Provides methods to define tasks with basic conditional execution based on the sources -* and products of the task. */ -trait FileTasks extends Project -{ - implicit def wrapProduct(product: => Path): ProductsWrapper = FileTasks.wrapProduct(product) - implicit def wrapProducts(productsList: => Iterable[Path]): ProductsWrapper = FileTasks.wrapProducts(productsList) - /** Runs 'action' if the given products are out of date with respect to the given sources. */ - def fileTask(label: String, files: ProductsSources)(action: => Option[String]): Task = - task { FileTasks.runOption(label, files, log)(action) } - /** Runs 'action' if any of the given products do not exist. */ - def fileTask(label: String, products: => Iterable[Path])(action: => Option[String]): Task = - task { FileTasks.existenceCheck[Option[String]](label, products, log)(action)(None) } - - /** Creates a new task that performs 'action' only when the given products are out of date with respect to the given sources.. */ - def fileTask(files: ProductsSources)(action: => Option[String]): Task = fileTask("", files)(action) - /** Creates a new task that performs 'action' only when at least one of the given products does not exist.. */ - def fileTask(products: => Iterable[Path])(action: => Option[String]): Task = fileTask("", products)(action) - -} -object FileTasks -{ - implicit def wrapProduct(product: => Path): ProductsWrapper = wrapProducts(product :: Nil) - implicit def wrapProducts(productsList: => Iterable[Path]): ProductsWrapper = - new ProductsWrapper - { - def from(sourceFinder: PathFinder) = - new ProductsSources - { - def products = productsList - def sources = sourceFinder.get - } - } - /** Runs 'ifOutofdate' if the given products are out of date with respect to the given sources.*/ - def runOption(label: String, files: ProductsSources, log: Logger)(ifOutofdate: => Option[String]): Option[String] = - { - val result = apply[Option[String]](label, files, log)(ifOutofdate)(None) - if(result.isDefined) - FileUtilities.clean(files.products, true, log) - result - } - /** Returns 'ifOutofdate' if the given products are out of date with respect to the given sources. Otherwise, returns ifUptodate. */ - def apply[T](label: String, files: ProductsSources, log: Logger)(ifOutofdate: => T)(ifUptodate: => T): T = - { - val products = files.products - require(!products.isEmpty, "No products were specified; products must be known in advance.") - existenceCheck[T](label, products, log)(ifOutofdate) - { - val sources = files.sources - if(sources.isEmpty) - { - log.debug("Running " + label + " task because no sources exist.") - ifOutofdate - } - else - { - val oldestProductModifiedTime = mapLastModified(products).reduceLeft(_ min _) - val newestSourceModifiedTime = mapLastModified(sources).reduceLeft(_ max _) - if(oldestProductModifiedTime < newestSourceModifiedTime) - { - if(log.atLevel(Level.Debug)) - { - log.debug("Running " + label + " task because the following sources are newer than at least one product: ") - logDebugIndented(sources.filter(_.lastModified > oldestProductModifiedTime), log) - log.debug(" The following products are older than at least one source: ") - logDebugIndented(products.filter(_.lastModified < newestSourceModifiedTime), log) - } - ifOutofdate - } - else - ifUptodate - } - } - } - /** Checks that all 'products' exist. If they do, 'ifAllExists' is returned, otherwise 'products' is returned.*/ - private def existenceCheck[T](label: String, products: Iterable[Path], log: Logger)(action: => T)(ifAllExist: => T) = - { - val nonexisting = products.filter(!_.exists) - if(nonexisting.isEmpty) - ifAllExist - else - { - if(log.atLevel(Level.Debug)) - { - log.debug("Running " + label + " task because at least one product does not exist:") - logDebugIndented(nonexisting, log) - } - action - } - } - private def logDebugIndented[T](it: Iterable[T], log: Logger) { it.foreach(x => log.debug("\t" + x)) } - private def mapLastModified(paths: Iterable[Path]): Iterable[Long] = paths.map(_.lastModified) -} \ No newline at end of file diff --git a/sbt_pending/src/main/scala/sbt/FileUtilities.scala b/sbt_pending/src/main/scala/sbt/FileUtilities.scala deleted file mode 100644 index 0d0477906..000000000 --- a/sbt_pending/src/main/scala/sbt/FileUtilities.scala +++ /dev/null @@ -1,933 +0,0 @@ -/* sbt -- Simple Build Tool - * Copyright 2008, 2009, 2010 Mark Harrah, Nathan Hamblen, Justin Caballero - */ -package sbt - -import java.io.{Closeable, File, FileInputStream, FileOutputStream, InputStream, OutputStream} -import java.io.{ByteArrayOutputStream, InputStreamReader, OutputStreamWriter} -import java.io.{BufferedReader, BufferedWriter, FileReader, FileWriter, Reader, Writer} -import java.util.zip.{GZIPInputStream, GZIPOutputStream} -import java.net.{URL, URISyntaxException} -import java.nio.charset.{Charset, CharsetDecoder, CharsetEncoder} -import java.nio.channels.FileChannel -import java.util.jar.{Attributes, JarEntry, JarFile, JarInputStream, JarOutputStream, Manifest} -import java.util.zip.{GZIPOutputStream, ZipEntry, ZipFile, ZipInputStream, ZipOutputStream} - -import OpenResource._ - -final class Preserved private[sbt](toRestore: scala.collection.Map[File, Path], temp: File) extends NotNull -{ - def restore(log: Logger) = - { - try - { - Control.lazyFold(toRestore.toList) { case (src, dest) => - FileUtilities.copyFile(src, dest.asFile, log) - } - } - finally { FileUtilities.clean(Path.fromFile(temp) :: Nil, true, log) } - } -} - -/** A collection of file related methods. */ -object FileUtilities -{ - import wrap.Wrappers.readOnly - /** The size of the byte or char buffer used in various methods.*/ - private val BufferSize = 8192 - val Newline = System.getProperty("line.separator") - /** A pattern used to split a String by path separator characters.*/ - private val PathSeparatorPattern = java.util.regex.Pattern.compile(File.pathSeparator) - - /** Splits a String around path separator characters. */ - private[sbt] def pathSplit(s: String) = PathSeparatorPattern.split(s) - - def preserve(paths: Iterable[Path], log: Logger): Either[String, Preserved] = - { - for(tmp <- createTemporaryDirectory(log).right) yield - { - val pathMap = new scala.collection.mutable.HashMap[File, Path] - val destinationDirectory = Path.fromFile(tmp) - for(source <- paths) - { - val toPath = Path.fromString(destinationDirectory, source.relativePath) - copyFile(source, toPath, log) - pathMap(toPath.asFile) = source - } - new Preserved(readOnly(pathMap), tmp) - } - } - - /** Gzips the file 'in' and writes it to 'out'. 'in' cannot be the same file as 'out'. */ - def gzip(in: Path, out: Path, log: Logger): Option[String] = - { - require(in != out, "Input file cannot be the same as the output file.") - readStream(in.asFile, log) { inputStream => - writeStream(out.asFile, log) { outputStream => - gzip(inputStream, outputStream, log) - } - } - } - /** Gzips the InputStream 'in' and writes it to 'output'. Neither stream is closed.*/ - def gzip(input: InputStream, output: OutputStream, log: Logger): Option[String] = - gzipOutputStream.ioOption(output, "gzipping", log) { gzStream => transfer(input, gzStream, log) } - - def gunzip(input: InputStream, output: OutputStream, log: Logger): Option[String] = - gzipInputStream.ioOption(input, "gunzipping", log) { gzStream => transfer(gzStream, output, log) } - /** Gunzips the file 'in' and writes it to 'out'. 'in' cannot be the same file as 'out'. */ - def gunzip(in: Path, out: Path, log: Logger): Option[String] = - { - require(in != out, "Input file cannot be the same as the output file.") - readStream(in.asFile, log) { inputStream => - writeStream(out.asFile, log) { outputStream => - gunzip(inputStream, outputStream, log) - } - } - } - - /** Creates a jar file. - * @param sources The files to include in the jar file. The path used for the jar is - * relative to the base directory for the source. That is, the path in the jar for source - * (basePath ###) / x / y is x / y. - * @param outputJar The file to write the jar to. - * @param manifest The manifest for the jar. - * @param recursive If true, any directories in sources are recursively processed. Otherwise, - * they are not - * @param log The Logger to use. */ - def jar(sources: Iterable[Path], outputJar: Path, manifest: Manifest, recursive: Boolean, log: Logger) = - archive(sources, outputJar, Some(manifest), recursive, log) - /** Creates a zip file. - * @param sources The files to include in the jar file. The path used for the jar is - * relative to the base directory for the source. That is, the path in the jar for source - * (basePath ###) / x / y is x / y. - * @param outputZip The file to write the zip to. - * @param recursive If true, any directories in sources are recursively processed. Otherwise, - * they are not - * @param log The Logger to use. */ - def zip(sources: Iterable[Path], outputZip: Path, recursive: Boolean, log: Logger) = - archive(sources, outputZip, None, recursive, log) - - private def archive(sources: Iterable[Path], outputPath: Path, manifest: Option[Manifest], recursive: Boolean, log: Logger) = - { - log.info("Packaging " + outputPath + " ...") - val outputFile = outputPath.asFile - if(outputFile.isDirectory) - Some("Specified output file " + outputFile + " is a directory.") - else - { - val outputDir = outputFile.getParentFile - val result = createDirectory(outputDir, log) orElse - withZipOutput(outputFile, manifest, log) - { output => - val createEntry: (String => ZipEntry) = if(manifest.isDefined) new JarEntry(_) else new ZipEntry(_) - writeZip(sources, output, recursive, log)(createEntry) - } - if(result.isEmpty) - log.info("Packaging complete.") - result - } - } - - private def writeZip(sources: Iterable[Path], output: ZipOutputStream, recursive: Boolean, log: Logger)(createEntry: String => ZipEntry) = - { - def add(source: Path) - { - val sourceFile = source.asFile - if(sourceFile.isDirectory) - { - if(recursive) - wrapNull(sourceFile.listFiles).foreach(file => add(source / file.getName)) - } - else if(sourceFile.exists) - { - val relativePath = source.relativePathString("/") - log.debug("\tAdding " + source + " as " + relativePath + " ...") - val nextEntry = createEntry(relativePath) - nextEntry.setTime(sourceFile.lastModified) - output.putNextEntry(nextEntry) - transferAndClose(new FileInputStream(sourceFile), output, log) - output.closeEntry() - } - else - log.warn("\tSource " + source + " does not exist.") - } - sources.foreach(add) - None - } - - private def withZipOutput(file: File, manifest: Option[Manifest], log: Logger)(f: ZipOutputStream => Option[String]): Option[String] = - { - writeStream(file, log) - { - fileOut => - { - val (zipOut, ext) = - manifest match - { - case Some(mf) => - { - import Attributes.Name.MANIFEST_VERSION - val main = mf.getMainAttributes - if(!main.containsKey(MANIFEST_VERSION)) - main.put(MANIFEST_VERSION, "1.0") - (new JarOutputStream(fileOut, mf), "jar") - } - case None => (new ZipOutputStream(fileOut), "zip") - } - Control.trapUnitAndFinally("Error writing " + ext + ": ", log) - { f(zipOut) } { zipOut.close } - } - } - } - import scala.collection.Set - /** Unzips the contents of the zip file from to the toDirectory directory.*/ - def unzip(from: Path, toDirectory: Path, log: Logger): Either[String, Set[Path]] = - unzip(from, toDirectory, AllPassFilter, log) - /** Unzips the contents of the zip file from to the toDirectory directory.*/ - def unzip(from: File, toDirectory: Path, log: Logger): Either[String, Set[Path]] = - unzip(from, toDirectory, AllPassFilter, log) - /** Unzips the contents of the zip file from to the toDirectory directory.*/ - def unzip(from: InputStream, toDirectory: Path, log: Logger): Either[String, Set[Path]] = - unzip(from, toDirectory, AllPassFilter, log) - /** Unzips the contents of the zip file from to the toDirectory directory.*/ - def unzip(from: URL, toDirectory: Path, log: Logger): Either[String, Set[Path]] = - unzip(from, toDirectory, AllPassFilter, log) - - /** Unzips the contents of the zip file from to the toDirectory directory. - * Only the entries that match the given filter are extracted. */ - def unzip(from: Path, toDirectory: Path, filter: NameFilter, log: Logger): Either[String, Set[Path]] = - unzip(from.asFile, toDirectory, filter, log) - /** Unzips the contents of the zip file from to the toDirectory directory. - * Only the entries that match the given filter are extracted. */ - def unzip(from: File, toDirectory: Path, filter: NameFilter, log: Logger): Either[String, Set[Path]] = - readStreamValue(from, log)(in => unzip(in, toDirectory, filter, log)) - /** Unzips the contents of the zip file from to the toDirectory directory. - * Only the entries that match the given filter are extracted. */ - def unzip(from: URL, toDirectory: Path, filter: NameFilter, log: Logger): Either[String, Set[Path]] = - readStreamValue(from, log) { stream => unzip(stream, toDirectory, filter, log) } - /** Unzips the contents of the zip file from to the toDirectory directory. - * Only the entries that match the given filter are extracted. */ - def unzip(from: InputStream, toDirectory: Path, filter: NameFilter, log: Logger): Either[String, Set[Path]] = - { - createDirectory(toDirectory, log) match - { - case Some(err) => Left(err) - case None => zipInputStream.io(from, "unzipping", log) { zipInput => extract(zipInput, toDirectory, filter, log) } - } - } - private def extract(from: ZipInputStream, toDirectory: Path, filter: NameFilter, log: Logger) = - { - val set = new scala.collection.mutable.HashSet[Path] - // don't touch dirs as we unzip because we don't know order of zip entires (any child will - // update the dir's time) - val dirTimes = new scala.collection.mutable.HashMap[Path, Long] - def next(): Option[String] = - { - val entry = from.getNextEntry - if(entry == null) - None - else - { - val name = entry.getName - val entryErr = - if(filter.accept(name)) - { - val target = Path.fromString(toDirectory, name) - log.debug("Extracting zip entry '" + name + "' to '" + target + "'") - if(entry.isDirectory) - { - dirTimes += target -> entry.getTime - createDirectory(target, log) - } - else - writeStream(target.asFile, log) { out => FileUtilities.transfer(from, out, log) } orElse - { - set += target - touchExisting(target.asFile, entry.getTime, log) - None - } - } - else - { - log.debug("Ignoring zip entry '" + name + "'") - None - } - from.closeEntry() - entryErr match { case None => next(); case x => x } - } - } - val result = next() - for ((dir, time) <- dirTimes) touchExisting(dir.asFile, time, log) - result.toLeft(readOnly(set)) - } - - /** Copies all bytes from the given input stream to the given output stream. - * Neither stream is closed.*/ - def transfer(in: InputStream, out: OutputStream, log: Logger): Option[String] = - transferImpl(in, out, false, log) - /** Copies all bytes from the given input stream to the given output stream. The - * input stream is closed after the method completes.*/ - def transferAndClose(in: InputStream, out: OutputStream, log: Logger): Option[String] = - transferImpl(in, out, true, log) - private def transferImpl(in: InputStream, out: OutputStream, close: Boolean, log: Logger): Option[String] = - { - Control.trapUnitAndFinally("Error during transfer: ", log) - { - val buffer = new Array[Byte](BufferSize) - def read: None.type = - { - val byteCount = in.read(buffer) - if(byteCount >= 0) - { - out.write(buffer, 0, byteCount) - read - } - else - None - } - read - } - { if(close) in.close } - } - - /** Creates a file at the given location.*/ - def touch(path: Path, log: Logger): Option[String] = touch(path.asFile, log) - /** Creates a file at the given location.*/ - def touch(file: File, log: Logger): Option[String] = - { - Control.trapUnit("Could not create file " + file + ": ", log) - { - if(file.exists) - touchExisting(file, System.currentTimeMillis, log) - else - createDirectory(file.getParentFile, log) orElse { file.createNewFile(); None } - } - } - /** Sets the last mod time on the given {@code file}, which must already exist */ - private def touchExisting(file: File, time: Long, log: Logger): Option[String] = - { - def updateFailBase = "Could not update last modified for file " + file - Control.trapUnit(updateFailBase + ": ", log) - { if(file.setLastModified(time)) None else Some(updateFailBase) } - } - /** Creates a directory at the given location.*/ - def createDirectory(dir: Path, log: Logger): Option[String] = createDirectory(dir.asFile, log) - /** Creates a directory at the given location.*/ - def createDirectory(dir: File, log: Logger): Option[String] = - { - Control.trapUnit("Could not create directory " + dir + ": ", log) - { - if(dir.exists) - { - if(dir.isDirectory) - None - else - Some(dir + " exists and is not a directory.") - } - else - { - dir.mkdirs() - log.debug("Created directory " + dir) - None - } - } - } - /** Creates directories at the given locations.*/ - def createDirectories(d: Iterable[Path], log: Logger): Option[String] = createDirectories(Path.getFiles(d).toList, log) - /** Creates directories at the given locations.*/ - def createDirectories(d: List[File], log: Logger): Option[String] = - d match - { - case Nil => None - case head :: tail => createDirectory(head, log) orElse createDirectories(tail, log) - } - /** The maximum number of times a unique temporary filename is attempted to be created.*/ - private val MaximumTries = 10 - /** Creates a temporary directory and returns it.*/ - def createTemporaryDirectory(log: Logger): Either[String, File] = - { - def create(tries: Int): Either[String, File] = - { - if(tries > MaximumTries) - Left("Could not create temporary directory.") - else - { - val randomName = "sbt_" + java.lang.Integer.toHexString(random.nextInt) - val f = new File(temporaryDirectory, randomName) - - if(createDirectory(f, log).isEmpty) - Right(f) - else - create(tries + 1) - } - } - create(0) - } - - def withTemporaryDirectory(log: Logger)(action: File => Option[String]): Option[String] = - doInTemporaryDirectory(log: Logger)(file => action(file).toLeft(())).left.toOption - /** Creates a temporary directory and provides its location to the given function. The directory - * is deleted after the function returns.*/ - def doInTemporaryDirectory[T](log: Logger)(action: File => Either[String, T]): Either[String, T] = - { - def doInDirectory(dir: File): Either[String, T] = - { - Control.trapAndFinally("", log) - { action(dir) } - { delete(dir, true, log) } - } - createTemporaryDirectory(log).right.flatMap(doInDirectory) - } - def withTemporaryFile[T](log: Logger, prefix: String, postfix: String)(action: File => Either[String, T]): Either[String, T] = - { - Control.trap("Error creating temporary file: ", log) - { - val file = File.createTempFile(prefix, postfix) - Control.trapAndFinally("", log) - { action(file) } - { file.delete() } - } - } - - /** Copies the files declared in sources to the destinationDirectory - * directory. The source directory hierarchy is flattened so that all copies are immediate - * children of destinationDirectory. Directories are not recursively entered.*/ - def copyFlat(sources: Iterable[Path], destinationDirectory: Path, log: Logger) = - { - val targetSet = new scala.collection.mutable.HashSet[Path] - copyImpl(sources, destinationDirectory, log) - { - source => - { - val from = source.asFile - val toPath = destinationDirectory / from.getName - targetSet += toPath - val to = toPath.asFile - if(!to.exists || from.lastModified > to.lastModified && !from.isDirectory) - { - log.debug("Copying " + source + " to " + toPath) - copyFile(from, to, log) - } - else - None - } - }.toLeft(readOnly(targetSet)) - } - private def copyImpl(sources: Iterable[Path], destinationDirectory: Path, log: Logger) - (doCopy: Path => Option[String]): Option[String] = - { - val target = destinationDirectory.asFile - val creationError = - if(target.isDirectory) - None - else - createDirectory(target, log) - def copy(sources: List[Path]): Option[String] = - { - sources match - { - case src :: remaining => - { - doCopy(src) match - { - case None => copy(remaining) - case error => error - } - } - case Nil => None - } - } - creationError orElse ( Control.trapUnit("", log) { copy(sources.toList) } ) - } - /** Retrieves the content of the given URL and writes it to the given File. */ - def download(url: URL, to: File, log: Logger) = - { - readStream(url, log) { inputStream => - writeStream(to, log) { outputStream => - transfer(inputStream, outputStream, log) - } - } - } - - /** - * Equivalent to {@code copy(sources, destinationDirectory, false, log)}. - */ - def copy(sources: Iterable[Path], destinationDirectory: Path, log: Logger): Either[String, Set[Path]] = - copy(sources, destinationDirectory, false, log) - - /** - * Equivalent to {@code copy(sources, destinationDirectory, overwrite, false, log)}. - */ - def copy(sources: Iterable[Path], destinationDirectory: Path, overwrite: Boolean, log: Logger): Either[String, Set[Path]] = - copy(sources, destinationDirectory, overwrite, false, log) - - /** Copies the files declared in sources to the destinationDirectory - * directory. Directories are not recursively entered. The destination hierarchy matches the - * source paths relative to any base directories. For example: - * - * A source (basePath ###) / x / y is copied to destinationDirectory / x / y. - * - * @param overwrite if true, existing destination files are always overwritten - * @param preserveLastModified if true, the last modified time of copied files will be set equal to - * their corresponding source files. - */ - def copy(sources: Iterable[Path], destinationDirectory: Path, - overwrite: Boolean, preserveLastModified: Boolean, log: Logger): Either[String, Set[Path]] = - { - val targetSet = new scala.collection.mutable.HashSet[Path] - copyImpl(sources, destinationDirectory, log) - { - source => - { - val from = source.asFile - val toPath = Path.fromString(destinationDirectory, source.relativePath) - targetSet += toPath - val to = toPath.asFile - if(!to.exists || overwrite || from.lastModified > to.lastModified) - { - val result = - if(from.isDirectory) - createDirectory(to, log) - else - { - log.debug("Copying " + source + " to " + toPath) - copyFile(from, to, log) - } - if (result.isEmpty && preserveLastModified) - touchExisting(to, from.lastModified, log) - else - result - } - else - None - } - }.toLeft(readOnly(targetSet)) - } - - /** Copies the files declared in sources to the targetDirectory - * directory. The source directory hierarchy is flattened so that all copies are immediate - * children of targetDirectory. Directories are not recursively entered.*/ - def copyFilesFlat(sources: Iterable[File], targetDirectory: Path, log: Logger) = - { - require(targetDirectory.asFile.isDirectory, "Target '" + targetDirectory + "' is not a directory.") - val byName = new scala.collection.mutable.HashMap[String, File] - for(source <- sources) byName.put(source.getName, source) - val uniquelyNamedSources = byName.values - val targetSet = new scala.collection.mutable.HashSet[Path] - def copy(source: File): Option[String] = - { - if(source.isDirectory) - copyAll(source.listFiles.toList) - else if(source.exists) - { - val targetPath = targetDirectory / source.getName - targetSet += targetPath - if(!targetPath.exists || source.lastModified > targetPath.lastModified) - { - log.debug("Copying " + source + " to " + targetPath) - copyFile(source, targetPath.asFile, log) - } - else - None - } - else - None - } - def copyAll(sources: List[File]): Option[String] = - sources match - { - case head :: tail => - copy(head) match - { - case None => copyAll(tail) - case x => x - } - case Nil => None - } - - Control.trap("Error copying files: ", log) { copyAll(uniquelyNamedSources.toList).toLeft(readOnly(targetSet)) } - } - /** Copies sourceFile to targetFile. If targetFile - * exists, it is overwritten. Note that unlike higher level copies in FileUtilities, this - * method always performs the copy, even if sourceFile is older than targetFile.*/ - def copyFile(sourceFile: Path, targetFile: Path, log: Logger): Option[String] = - copyFile(sourceFile.asFile, targetFile.asFile, log) - /** Copies sourceFile to targetFile. If targetFile - * exists, it is overwritten. Note that unlike higher level copies in FileUtilities, this - * method always performs the copy, even if sourceFile is older than targetFile.*/ - def copyFile(sourceFile: File, targetFile: File, log: Logger): Option[String] = - { - require(sourceFile.exists, "Source file '" + sourceFile.getAbsolutePath + "' does not exist.") - require(!sourceFile.isDirectory, "Source file '" + sourceFile.getAbsolutePath + "' is a directory.") - readChannel(sourceFile, log)( - in => writeChannel(targetFile, log) { - out => { - val copied = out.transferFrom(in, 0, in.size) - if(copied == in.size) - None - else - Some("Could not copy '" + sourceFile + "' to '" + targetFile + "' (" + copied + "/" + in.size + " bytes copied)") - } - } - ) - } - - /** Synchronizes the contents of the sourceDirectory directory to the - * targetDirectory directory.*/ - def sync(sourceDirectory: Path, targetDirectory: Path, log: Logger): Option[String] = - syncPaths((sourceDirectory ###) ** AllPassFilter, targetDirectory, log) - def syncPaths(sources: PathFinder, targetDirectory: Path, log: Logger): Option[String] = - { - copy(sources.get, targetDirectory, log).right.flatMap - { copiedTo => prune(targetDirectory, copiedTo, log).toLeft(()) }.left.toOption - } - def prune(directory: Path, keepOnly: Iterable[Path], log: Logger): Option[String] = - { - val existing = ((directory ###) ** AllPassFilter).get - val toRemove = scala.collection.mutable.HashSet(existing.toSeq: _*) - toRemove --= keepOnly - if(log.atLevel(Level.Debug)) - toRemove.foreach(r => log.debug("Pruning " + r)) - clean(toRemove, true, log) - } - - /** Copies the contents of the source directory to the target directory .*/ - def copyDirectory(source: Path, target: Path, log: Logger): Option[String] = - copyDirectory(source.asFile, target.asFile, log) - /** Copies the contents of the source directory to the target directory .*/ - def copyDirectory(source: File, target: File, log: Logger): Option[String] = - { - require(source.isDirectory, "Source '" + source.getAbsolutePath + "' is not a directory.") - require(!target.exists, "Target '" + target.getAbsolutePath + "' already exists.") - def copyDirectory(sourceDir: File, targetDir: File): Option[String] = - createDirectory(targetDir, log) orElse copyContents(sourceDir, targetDir) - def copyContents(sourceDir: File, targetDir: File): Option[String] = - sourceDir.listFiles.foldLeft(None: Option[String]) - { - (result, file) => - result orElse - { - val targetFile = new File(targetDir, file.getName) - if(file.isDirectory) - copyDirectory(file, targetFile) - else - copyFile(file, targetFile, log) - } - } - copyDirectory(source, target) - } - - - /** Deletes the given file recursively.*/ - def clean(file: Path, log: Logger): Option[String] = clean(file :: Nil, log) - /** Deletes the given files recursively.*/ - def clean(files: Iterable[Path], log: Logger): Option[String] = clean(files, false, log) - /** Deletes the given files recursively. quiet determines the logging level. - * If it is true, each file in files is logged at the info level. - * If it is false, the debug level is used.*/ - def clean(files: Iterable[Path], quiet: Boolean, log: Logger): Option[String] = - deleteFiles(Path.getFiles(files), quiet, log) - - private def deleteFiles(files: Iterable[File], quiet: Boolean, log: Logger): Option[String] = - ((None: Option[String]) /: files)( (result, file) => result orElse delete(file, quiet, log)) - private def delete(file: File, quiet: Boolean, log: Logger): Option[String] = - { - def logMessage(message: => String) - { - log.log(if(quiet) Level.Debug else Level.Info, message) - } - Control.trapUnit("Error deleting file " + file + ": ", log) - { - if(file.isDirectory) - { - logMessage("Deleting directory " + file) - deleteFiles(wrapNull(file.listFiles), true, log) - file.delete - } - else if(file.exists) - { - logMessage("Deleting file " + file) - file.delete - } - None - } - } - - /** Appends the given String content to the provided file using the default encoding. - * A new file is created if it does not exist.*/ - def append(file: File, content: String, log: Logger): Option[String] = append(file, content, Charset.defaultCharset, log) - /** Appends the given String content to the provided file using the given encoding. - * A new file is created if it does not exist.*/ - def append(file: File, content: String, charset: Charset, log: Logger): Option[String] = - write(file, content, charset, true, log) - - /** Writes the given String content to the provided file using the default encoding. - * If the file exists, it is overwritten.*/ - def write(file: File, content: String, log: Logger): Option[String] = write(file, content, Charset.defaultCharset, log) - /** Writes the given String content to the provided file using the given encoding. - * If the file already exists, it is overwritten.*/ - def write(file: File, content: String, charset: Charset, log: Logger): Option[String] = - write(file, content, charset, false, log) - private def write(file: File, content: String, charset: Charset, append: Boolean, log: Logger): Option[String] = - { - if(charset.newEncoder.canEncode(content)) - write(file, charset, append, log) { w => w.write(content); None } - else - Some("String cannot be encoded by charset " + charset.name) - } - - /** Opens a Writer on the given file using the default encoding, - * passes it to the provided function, and closes the Writer.*/ - def write(file: File, log: Logger)(f: Writer => Option[String]): Option[String] = - write(file, Charset.defaultCharset, log)(f) - /** Opens a Writer on the given file using the given encoding, - * passes it to the provided function, and closes the Writer.*/ - def write(file: File, charset: Charset, log: Logger)(f: Writer => Option[String]): Option[String] = - write(file, charset, false, log)(f) - private def write(file: File, charset: Charset, append: Boolean, log: Logger)(f: Writer => Option[String]): Option[String] = - fileWriter(charset, append).ioOption(file, Writing, log)(f) - - /** Opens a Reader on the given file using the default encoding, - * passes it to the provided function, and closes the Reader.*/ - def read(file: File, log: Logger)(f: Reader => Option[String]): Option[String] = - read(file, Charset.defaultCharset, log)(f) - /** Opens a Reader on the given file using the default encoding, - * passes it to the provided function, and closes the Reader.*/ - def read(file: File, charset: Charset, log: Logger)(f: Reader => Option[String]): Option[String] = - fileReader(charset).ioOption(file, Reading, log)(f) - /** Opens a Reader on the given file using the default encoding, - * passes it to the provided function, and closes the Reader.*/ - def readValue[R](file: File, log: Logger)(f: Reader => Either[String, R]): Either[String, R] = - readValue(file, Charset.defaultCharset, log)(f) - /** Opens a Reader on the given file using the given encoding, - * passes it to the provided function, and closes the Reader.*/ - def readValue[R](file: File, charset: Charset, log: Logger)(f: Reader => Either[String, R]): Either[String, R] = - fileReader(charset).io(file, Reading, log)(f) - - /** Reads the contents of the given file into a String using the default encoding. - * The resulting String is wrapped in Right.*/ - def readString(file: File, log: Logger): Either[String, String] = readString(file, Charset.defaultCharset, log) - /** Reads the contents of the given file into a String using the given encoding. - * The resulting String is wrapped in Right.*/ - def readString(file: File, charset: Charset, log: Logger): Either[String, String] = readValue(file, charset, log)(readString) - - def readString(in: InputStream, log: Logger): Either[String, String] = readString(in, Charset.defaultCharset, log) - def readString(in: InputStream, charset: Charset, log: Logger): Either[String, String] = - streamReader.io((in, charset), Reading, log)(readString) - def readString(in: Reader, log: Logger): Either[String, String] = - Control.trapAndFinally("Error reading bytes from reader: ", log) - { readString(in) } - { in.close() } - private def readString(in: Reader): Either[String, String] = - { - val builder = new StringBuilder - val buffer = new Array[Char](BufferSize) - def readNext() - { - val read = in.read(buffer, 0, buffer.length) - if(read >= 0) - { - builder.append(buffer, 0, read) - readNext() - } - else - None - } - readNext() - Right(builder.toString) - } - /** Appends the given bytes to the given file. */ - def append(file: File, bytes: Array[Byte], log: Logger): Option[String] = - writeBytes(file, bytes, true, log) - /** Writes the given bytes to the given file. If the file already exists, it is overwritten.*/ - def write(file: File, bytes: Array[Byte], log: Logger): Option[String] = - writeBytes(file, bytes, false, log) - private def writeBytes(file: File, bytes: Array[Byte], append: Boolean, log: Logger): Option[String] = - writeStream(file, append, log) { out => out.write(bytes); None } - - /** Reads the entire file into a byte array. */ - def readBytes(file: File, log: Logger): Either[String, Array[Byte]] = readStreamValue(file, log)(readBytes) - def readBytes(in: InputStream, log: Logger): Either[String, Array[Byte]] = - Control.trapAndFinally("Error reading bytes from input stream: ", log) - { readBytes(in) } - { in.close() } - private def readBytes(in: InputStream): Either[String, Array[Byte]] = - { - val out = new ByteArrayOutputStream - val buffer = new Array[Byte](BufferSize) - def readNext() - { - val read = in.read(buffer) - if(read >= 0) - { - out.write(buffer, 0, read) - readNext() - } - } - readNext() - Right(out.toByteArray) - } - - /** Opens an OutputStream on the given file with append=true and passes the stream - * to the provided function. The stream is closed before this function returns.*/ - def appendStream(file: File, log: Logger)(f: OutputStream => Option[String]): Option[String] = - fileOutputStream(true).ioOption(file, Appending, log)(f) - /** Opens an OutputStream on the given file and passes the stream - * to the provided function. The stream is closed before this function returns.*/ - def writeStream(file: File, log: Logger)(f: OutputStream => Option[String]): Option[String] = - fileOutputStream(false).ioOption(file, Writing, log)(f) - private def writeStream(file: File, append: Boolean, log: Logger)(f: OutputStream => Option[String]): Option[String] = - if(append) appendStream(file, log)(f) else writeStream(file, log)(f) - /** Opens an InputStream on the given file and passes the stream - * to the provided function. The stream is closed before this function returns.*/ - def readStream(file: File, log: Logger)(f: InputStream => Option[String]): Option[String] = - fileInputStream.ioOption(file, Reading, log)(f) - /** Opens an InputStream on the given file and passes the stream - * to the provided function. The stream is closed before this function returns.*/ - def readStreamValue[R](file: File, log: Logger)(f: InputStream => Either[String, R]): Either[String, R] = - fileInputStream.io(file, Reading, log)(f) - /** Opens an InputStream on the given URL and passes the stream - * to the provided function. The stream is closed before this function returns.*/ - def readStream(url: URL, log: Logger)(f: InputStream => Option[String]): Option[String] = - urlInputStream.ioOption(url, Reading, log)(f) - /** Opens an InputStream on the given URL and passes the stream - * to the provided function. The stream is closed before this function returns.*/ - def readStreamValue[R](url: URL, log: Logger)(f: InputStream => Either[String, R]): Either[String, R] = - urlInputStream.io(url, Reading, log)(f) - - /** Opens a FileChannel on the given file for writing and passes the channel - * to the given function. The channel is closed before this function returns.*/ - def writeChannel(file: File, log: Logger)(f: FileChannel => Option[String]): Option[String] = - fileOutputChannel.ioOption(file, Writing, log)(f) - /** Opens a FileChannel on the given file for reading and passes the channel - * to the given function. The channel is closed before this function returns.*/ - def readChannel(file: File, log: Logger)(f: FileChannel => Option[String]): Option[String] = - fileInputChannel.ioOption(file, Reading, log)(f) - /** Opens a FileChannel on the given file for reading and passes the channel - * to the given function. The channel is closed before this function returns.*/ - def readChannelValue[R](file: File, log: Logger)(f: FileChannel => Either[String, R]): Either[String, R] = - fileInputChannel.io(file, Reading, log)(f) - - private[sbt] (a: Array[File]): Array[File] = - if(a == null) - new Array[File](0) - else - a - - /** Writes the given string to the writer followed by a newline.*/ - private[sbt] def writeLine(writer: Writer, line: String) - { - writer.write(line) - writer.write(Newline) - } - - def toFile(url: URL) = - try { new File(url.toURI) } - catch { case _: URISyntaxException => new File(url.getPath) } - - /** The directory in which temporary files are placed.*/ - val temporaryDirectory = new File(System.getProperty("java.io.tmpdir")) - def classLocation(cl: Class[_]): URL = - { - val codeSource = cl.getProtectionDomain.getCodeSource - if(codeSource == null) error("No class location for " + cl) - else codeSource.getLocation - } - def classLocationFile(cl: Class[_]): File = toFile(classLocation(cl)) - def classLocation[T](implicit mf: scala.reflect.Manifest[T]): URL = classLocation(mf.erasure) - def classLocationFile[T](implicit mf: scala.reflect.Manifest[T]): File = classLocationFile(mf.erasure) - - lazy val scalaLibraryJar: File = classLocationFile[scala.ScalaObject] - lazy val scalaCompilerJar: File = classLocationFile[scala.tools.nsc.Settings] - def scalaJars: Iterable[File] = List(scalaLibraryJar, scalaCompilerJar) - - /** The producer of randomness for unique name generation.*/ - private val random = new java.util.Random - - private val Reading = "reading" - private val Writing = "writing" - private val Appending = "appending" -} - -private abstract class OpenResource[Source, T] extends NotNull -{ - import OpenResource.{unwrapEither, wrapEither} - protected def open(src: Source, log: Logger): Either[String, T] - def ioOption(src: Source, op: String, log: Logger)(f: T => Option[String]) = - unwrapEither( io(src, op, log)(wrapEither(f)) ) - def io[R](src: Source, op: String, log: Logger)(f: T => Either[String,R]): Either[String, R] = - open(src, log).right flatMap - { - resource => Control.trapAndFinally("Error " + op + " "+ src + ": ", log) - { f(resource) } - { close(resource) } - } - protected def close(out: T): Unit -} -private trait CloseableOpenResource[Source, T <: Closeable] extends OpenResource[Source, T] -{ - protected def close(out: T): Unit = out.close() -} -import scala.reflect.{Manifest => SManifest} -private abstract class WrapOpenResource[Source, T <: Closeable](implicit srcMf: SManifest[Source], targetMf: SManifest[T]) extends CloseableOpenResource[Source, T] -{ - private def label[S](m: SManifest[S]) = m.erasure.getSimpleName - protected def open(source: Source): T - protected final def open(source: Source, log: Logger): Either[String, T] = - Control.trap("Error wrapping " + label(srcMf) + " in " + label(targetMf) + ": ", log) { Right(open(source)) } -} -private abstract class OpenFile[T] extends OpenResource[File, T] -{ - protected def open(file: File): T - protected final def open(file: File, log: Logger): Either[String, T] = - { - val parent = file.getParentFile - if(parent != null) - FileUtilities.createDirectory(parent, log) - Control.trap("Error opening " + file + ": ", log) { Right(open(file)) } - } -} -private abstract class CloseableOpenFile[T <: Closeable] extends OpenFile[T] with CloseableOpenResource[File, T] -private object OpenResource -{ - private def wrapEither[R](f: R => Option[String]): (R => Either[String, Unit]) = (r: R) => f(r).toLeft(()) - private def unwrapEither(e: Either[String, Unit]): Option[String] = e.left.toOption - - def fileOutputStream(append: Boolean) = - new CloseableOpenFile[FileOutputStream] { protected def open(file: File) = new FileOutputStream(file, append) } - def fileInputStream = new CloseableOpenFile[FileInputStream] - { protected def open(file: File) = new FileInputStream(file) } - def urlInputStream = new CloseableOpenResource[URL, InputStream] - { protected def open(url: URL, log: Logger) = Control.trap("Error opening " + url + ": ", log) { Right(url.openStream) } } - def fileOutputChannel = new CloseableOpenFile[FileChannel] - { protected def open(f: File) = (new FileOutputStream(f)).getChannel } - def fileInputChannel = new CloseableOpenFile[FileChannel] - { protected def open(f: File) = (new FileInputStream(f)).getChannel } - def fileWriter(charset: Charset, append: Boolean) = new CloseableOpenFile[Writer] - { protected def open(f: File) = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(f, append), charset)) } - def fileReader(charset: Charset) = new CloseableOpenFile[Reader] - { protected def open(f: File) = new BufferedReader(new InputStreamReader(new FileInputStream(f), charset)) } - def jarFile(verify: Boolean) = new OpenFile[JarFile] - { protected def open(f: File) = new JarFile(f, verify) - override protected def close(j: JarFile) = j.close() } - def zipFile = new OpenFile[ZipFile] - { protected def open(f: File) = new ZipFile(f) - override protected def close(z: ZipFile) = z.close() } - def streamReader = new WrapOpenResource[(InputStream, Charset), Reader] - { protected def open(streamCharset: (InputStream, Charset)) = new InputStreamReader(streamCharset._1, streamCharset._2) } - def gzipInputStream = new WrapOpenResource[InputStream, GZIPInputStream] - { protected def open(in: InputStream) = new GZIPInputStream(in) } - def zipInputStream = new WrapOpenResource[InputStream, ZipInputStream] - { protected def open(in: InputStream) = new ZipInputStream(in) } - def gzipOutputStream = new WrapOpenResource[OutputStream, GZIPOutputStream] - { protected def open(out: OutputStream) = new GZIPOutputStream(out) - override protected def close(out: GZIPOutputStream) = out.finish() } - def jarOutputStream = new WrapOpenResource[OutputStream, JarOutputStream] - { protected def open(out: OutputStream) = new JarOutputStream(out) } - def jarInputStream = new WrapOpenResource[InputStream, JarInputStream] - { protected def open(in: InputStream) = new JarInputStream(in) } - def zipEntry(zip: ZipFile) = new CloseableOpenResource[ZipEntry, InputStream] { - protected def open(entry: ZipEntry, log: Logger) = - Control.trap("Error opening " + entry.getName + " in " + zip + ": ", log) { Right(zip.getInputStream(entry)) } - } -} \ No newline at end of file diff --git a/sbt_pending/src/main/scala/sbt/IntegrationTesting.scala b/sbt_pending/src/main/scala/sbt/IntegrationTesting.scala deleted file mode 100644 index d09dde5b4..000000000 --- a/sbt_pending/src/main/scala/sbt/IntegrationTesting.scala +++ /dev/null @@ -1,94 +0,0 @@ -/* sbt -- Simple Build Tool - * Copyright 2009 Steven Blundy, Mark Harrah, Josh Cough - */ -package sbt - -import ScalaProject.{optionsAsString, javaOptionsAsString} - -trait IntegrationTesting extends NotNull -{ - /** Override to provide pre-test setup. */ - protected def pretests: Option[String] = None - /** Override to provide post-test cleanup. */ - protected def posttests: Option[String] = None -} -trait ScalaIntegrationTesting extends IntegrationTesting -{ self: ScalaProject => - - protected def integrationTestTask(frameworks: Seq[TestFramework], classpath: PathFinder, analysis: CompileAnalysis, options: => Seq[TestOption]) = - testTask(frameworks, classpath, analysis, options) -} - -trait BasicScalaIntegrationTesting extends BasicIntegrationTesting with MavenStyleIntegrationTestPaths -{ self: BasicScalaProject => } -/** A fully featured integration testing that may be mixed in with any subclass of BasicScalaProject. - * Pre-suite setup and post-suite cleanup are provide by overriding pretests and posttests respectively.*/ -trait BasicIntegrationTesting extends ScalaIntegrationTesting with IntegrationTestPaths with BasicDependencyProject -{ - self: BasicScalaProject => - - import BasicScalaIntegrationTesting._ - - lazy val integrationTestCompile = integrationTestCompileAction - lazy val integrationTest = integrationTestAction - - val integrationTestCompileConditional = new CompileConditional(integrationTestCompileConfiguration, buildCompiler) - - protected def integrationTestAction = integrationTestTask(integrationTestFrameworks, integrationTestClasspath, integrationTestCompileConditional.analysis, integrationTestOptions) dependsOn integrationTestCompile describedAs IntegrationTestCompileDescription - protected def integrationTestCompileAction = integrationTestCompileTask() dependsOn compile describedAs IntegrationTestDescription - - protected def integrationTestCompileTask() = task{ integrationTestCompileConditional.run } - - def integrationTestOptions: Seq[TestOption] = - TestSetup(() => pretests) :: - TestCleanup(() => posttests) :: - testOptions.toList - def integrationTestCompileOptions = testCompileOptions - def javaIntegrationTestCompileOptions: Seq[JavaCompileOption] = testJavaCompileOptions - - def integrationTestConfiguration = if(useIntegrationTestConfiguration) Configurations.IntegrationTest else Configurations.Test - def integrationTestClasspath = fullClasspath(integrationTestConfiguration) +++ optionalClasspath - - def integrationTestLabel = "integration-test" - def integrationTestCompileConfiguration = new IntegrationTestCompileConfig - - protected def integrationTestDependencies = new LibraryDependencies(this, integrationTestCompileConditional) - - def integrationTestFrameworks = testFrameworks - override def useIntegrationTestConfiguration = false - abstract override def extraDefaultConfigurations = - { - val superConfigurations = super.extraDefaultConfigurations - if(useIntegrationTestConfiguration) - integrationTestConfiguration :: superConfigurations - else - superConfigurations - } - abstract override def fullUnmanagedClasspath(config: Configuration) = - { - val superClasspath = super.fullUnmanagedClasspath(config) - if(config == integrationTestConfiguration) - integrationTestCompilePath +++ integrationTestResourcesPath +++ superClasspath - else - superClasspath - } - - class IntegrationTestCompileConfig extends BaseCompileConfig - { - def label = integrationTestLabel - def sourceRoots = integrationTestScalaSourceRoots - def sources = integrationTestSources - def outputDirectory = integrationTestCompilePath - def classpath = integrationTestClasspath - def analysisPath = integrationTestAnalysisPath - def baseCompileOptions = integrationTestCompileOptions - def javaOptions = javaOptionsAsString(javaCompileOptions) - def fingerprints = getFingerprints(integrationTestFrameworks) - } -} - -object BasicScalaIntegrationTesting -{ - val IntegrationTestCompileDescription = "Compiles integration test sources." - val IntegrationTestDescription = "Runs all integration tests detected during compilation." -} diff --git a/sbt_pending/src/main/scala/sbt/Main.scala b/sbt_pending/src/main/scala/sbt/Main.scala deleted file mode 100755 index 61a7e40d0..000000000 --- a/sbt_pending/src/main/scala/sbt/Main.scala +++ /dev/null @@ -1,774 +0,0 @@ -/* sbt -- Simple Build Tool - * Copyright 2008, 2009, 2010 Steven Blundy, Mark Harrah, David MacIver, Mikko Peltonen - */ -package sbt - -import java.io.File -import scala.collection.immutable.TreeSet -import complete.HistoryCommands -import HistoryCommands.{Start => HistoryPrefix} - -/** This class is the entry point for sbt. If it is given any arguments, it interprets them -* as actions, executes the corresponding actions, and exits. If there were no arguments provided, -* sbt enters interactive mode.*/ -object Main -{ - val NormalExitCode = 0 - val SetupErrorExitCode = 1 - val SetupDeclinedExitCode = 2 - val LoadErrorExitCode = 3 - val UsageErrorExitCode = 4 - val BuildErrorExitCode = 5 - val ProgramErrorExitCode = 6 - val MaxInt = java.lang.Integer.MAX_VALUE -} - -import Main._ - -class xMain extends xsbti.AppMain -{ - final def run(configuration: xsbti.AppConfiguration): xsbti.MainResult = - { - def run0(remainingArguments: List[String], buildScalaVersion: Option[String]): xsbti.MainResult = - { - // done this way because in Scala 2.7.7, tail recursion in catch blocks is not optimized - val result = try { Right(run(configuration, remainingArguments, buildScalaVersion)) } catch { case re: ReloadException => Left(re) } - result match - { - case Left(re) => run0(re.remainingArguments, re.buildScalaVersion) - case Right(r) => r - } - } - run0(configuration.arguments.map(_.trim).toList, None) - } - final def run(configuration: xsbti.AppConfiguration, remainingArguments: List[String], buildScalaVersion: Option[String]): xsbti.MainResult = - { - val startTime = System.currentTimeMillis - Project.loadProject(configuration.provider, buildScalaVersion) match - { - case err: LoadSetupError => - println("\n" + err.message) - ExitHooks.runExitHooks(Project.bootLogger) - Exit(SetupErrorExitCode) - case LoadSetupDeclined => - ExitHooks.runExitHooks(Project.bootLogger) - Exit(SetupDeclinedExitCode) - case err: LoadError => - { - val log = Project.bootLogger - println(err.message) - ExitHooks.runExitHooks(log) - // Because this is an error that can probably be corrected, prompt user to try again. - val line = - try { SimpleReader.readLine("\n Hit enter to retry or 'exit' to quit: ") } - catch - { - case e => - log.trace(e) - log.error(e.toString) - None - } - line match - { - case Some(l) => if(!isTerminateAction(l)) run(configuration, remainingArguments, buildScalaVersion) else Exit(NormalExitCode) - case None => Exit(LoadErrorExitCode) - } - } - case success: LoadSuccess => - { - import success.project - try - { - // in interactive mode, fill all undefined properties - if(configuration.arguments.length > 0 || fillUndefinedProjectProperties(project.projectClosure.toList.reverse)) - startProject(project, configuration, remainingArguments, startTime) - else - Exit(NormalExitCode) - } - finally { ExitHooks.runExitHooks(project.log) } - } - } - } - /** If no arguments are provided, drop to interactive prompt. - * If the user wants to run commands before dropping to the interactive prompt, - * make dropping to the interactive prompt the action to perform on failure */ - private def initialize(args: List[String]): List[String] = - args.lastOption match - { - case None => InteractiveCommand :: Nil - case Some(InteractiveCommand) => (FailureHandlerPrefix + InteractiveCommand) :: args - case Some(ExitCommand | QuitCommand) => args - case _ => args ::: ExitCommand :: Nil - } - private def startProject(project: Project, configuration: xsbti.AppConfiguration, remainingArguments: List[String], startTime: Long): xsbti.MainResult = - { - project.log.info("Building project " + project.name + " " + project.version.toString + " against Scala " + project.buildScalaVersion) - project.log.info(" using " + project.getClass.getName + " with sbt " + ComponentManager.version + " and Scala " + project.defScalaVersion.value) - processArguments(project, initialize(remainingArguments), configuration, startTime) match - { - case e: xsbti.Exit => - printTime(project, startTime, "session") - if(e.code == NormalExitCode) - project.log.success("Build completed successfully.") - else - project.log.error("Error during build.") - e - case r => r - } - } - /** This is the top-level command processing method. */ - private def processArguments(baseProject: Project, arguments: List[String], configuration: xsbti.AppConfiguration, startTime: Long): xsbti.MainResult = - { - type OnFailure = Option[String] - def ExitOnFailure = None - lazy val interactiveContinue = Some( InteractiveCommand ) - def remoteContinue(port: Int) = Some( FileCommandsPrefix + "-" + port ) - lazy val PHandler = new processor.Handler(baseProject) - - // replace in 2.8 - trait Trampoline - class Done(val r: xsbti.MainResult) extends Trampoline - class Continue(project: Project, arguments: List[String], failAction: OnFailure) extends Trampoline { - def apply() = process(project, arguments, failAction) - } - def continue(project: Project, arguments: List[String], failAction: OnFailure) = new Continue(project, arguments, failAction) - def result(r: xsbti.MainResult) = new Done(r) - def run(t: Trampoline): xsbti.MainResult = t match { case d: Done => d.r; case c: Continue => run(c()) } - - def process(project: Project, arguments: List[String], failAction: OnFailure): Trampoline = - { - project.log.debug("commands " + failAction.map("(on failure: " + _ + "): ").mkString + arguments.mkString(", ")) - def rememberCurrent(newArgs: List[String]) = rememberProject(rememberFail(newArgs)) - def rememberProject(newArgs: List[String]) = - if(baseProject.name != project.name && !internal(project)) (ProjectAction + " " + project.name) :: newArgs else newArgs - def rememberFail(newArgs: List[String]) = failAction.map(f => (FailureHandlerPrefix + f)).toList ::: newArgs - - def tryOrFail(action: => Trampoline) = try { action } catch { case e: Exception => logCommandError(project.log, e); failed(BuildErrorExitCode) } - def reload(args: List[String]) = - { - val newID = new ApplicationID(configuration.provider.id, baseProject.sbtVersion.value) - result( new Reboot(project.defScalaVersion.value, rememberCurrent(args), newID, configuration.baseDirectory) ) - } - def failed(code: Int) = - failAction match - { - case Some(c) => continue(project, c :: Nil, ExitOnFailure) - case None => result( Exit(code) ) - } - - arguments match - { - case "" :: tail => continue(project, tail, failAction) - case ResetCommand :: tail => JLine.resetTerminal(); continue(project, tail, failAction) - case x :: tail if x.startsWith(";") => continue(project, x.split("""\s*;\s*""").toList ::: tail, failAction) - case (ExitCommand | QuitCommand) :: _ => result( Exit(NormalExitCode) ) - case RebootCommand :: tail => reload( tail ) - case InteractiveCommand :: _ => continue(project, prompt(baseProject, project) :: arguments, interactiveContinue) - case BuilderCommand :: tail => - Project.getProjectBuilder(project.info, project.log) match - { - case Some(b) => project.log.info("Set current project to builder of " + project.name); continue(b, tail, failAction) - case None => project.log.error("No project/build directory for " + project.name + ".\n Not switching to builder project."); failed(BuildErrorExitCode) - } - case SpecificBuild(version, action) :: tail => - if(Some(version) != baseProject.info.buildScalaVersion) - { - if(checkVersion(baseProject, version)) - throw new ReloadException(rememberCurrent(action :: tail), Some(version)) - else - failed(UsageErrorExitCode) - } - else - continue(project, action :: tail, failAction) - - case CrossBuild(action) :: tail => - if(checkAction(project, action)) - { - CrossBuild(project, action) match - { - case Some(actions) => continue(project, actions ::: tail, failAction) - case None => failed(UsageErrorExitCode) - } - } - else - failed(UsageErrorExitCode) - - case SetProject(name) :: tail => - SetProject(baseProject, name, project) match - { - case Some(newProject) => continue(newProject, tail, failAction) - case None => failed(BuildErrorExitCode) - } - - case action :: tail if action.startsWith(HistoryPrefix) => - HistoryCommands(action.substring(HistoryPrefix.length).trim, baseProject.historyPath, JLine.MaxHistorySize, project.log) match - { - case Some(commands) => - commands.foreach(println) //better to print it than to log it - continue(project, commands ::: tail, failAction) - case None => failed(UsageErrorExitCode) - } - - case action :: tail if action.startsWith(FileCommandsPrefix) => - getSource(action.substring(FileCommandsPrefix.length).trim, baseProject.info.projectDirectory) match - { - case Left(portAndSuccess) => - val port = Math.abs(portAndSuccess) - val previousSuccess = portAndSuccess >= 0 - readMessage(port, previousSuccess) match - { - case Some(message) => continue(project, message :: (FileCommandsPrefix + port) :: Nil, remoteContinue(port)) - case None => - project.log.error("Connection closed.") - failed(BuildErrorExitCode) - } - - case Right(file) => - readLines(project, file) match - { - case Some(lines) => continue(project, lines ::: tail , failAction) - case None => failed(UsageErrorExitCode) - } - } - - case action :: tail if action.startsWith(FailureHandlerPrefix) => - val errorAction = action.substring(FailureHandlerPrefix.length).trim - continue(project, tail, if(errorAction.isEmpty) None else Some(errorAction) ) - - case action :: tail if action.startsWith(ProcessorPrefix) => - val processorCommand = action.substring(ProcessorPrefix.length).trim - val runner = processor.CommandRunner(PHandler.manager, PHandler.defParser, ProcessorPrefix, project.log) - tryOrFail { - runner(processorCommand) - continue(project, tail, failAction) - } - - case PHandler(parsed) :: tail => - tryOrFail { - parsed.processor(parsed.label, project, failAction, parsed.arguments) match - { - case s: processor.Success => continue(s.project, s.insertArguments ::: tail, s.onFailure) - case e: processor.Exit => result( Exit(e.code) ) - case r: processor.Reload => reload( r.insertArguments ::: tail ) - } - } - - case action :: tail => - val success = processAction(baseProject, project, action, failAction == interactiveContinue) - if(success) continue(project, tail, failAction) - else failed(BuildErrorExitCode) - - case Nil => - project.log.error("Invalid internal sbt state: no arguments") - result( Exit(ProgramErrorExitCode) ) - } - } - run(process(baseProject, arguments, ExitOnFailure)) - } - private def internal(p: Project) = p.isInstanceOf[InternalProject] - private def isInteractive(failureActions: Option[List[String]]) = failureActions == Some(InteractiveCommand :: Nil) - private def getSource(action: String, baseDirectory: File) = - { - try { Left(action.toInt) } - catch { case _: NumberFormatException => Right(new File(baseDirectory, action)) } - } - private def readMessage(port: Int, previousSuccess: Boolean): Option[String] = - { - // split into two connections because this first connection ends the previous communication - xsbt.IPC.client(port) { _.send(previousSuccess.toString) } - // and this second connection starts the next communication - xsbt.IPC.client(port) { ipc => - val message = ipc.receive - if(message eq null) None else Some(message) - } - } - object SetProject - { - def unapply(s: String) = - if(s.startsWith(ProjectAction + " ")) - Some(s.substring(ProjectAction.length + 1)) - else - None - def apply(baseProject: Project, projectName: String, currentProject: Project) = - { - val found = baseProject.projectClosure.find(_.name == projectName) - found match - { - case Some(newProject) => printProject("Set current project to ", newProject) - case None => currentProject.log.error("Invalid project name '" + projectName + "' (type 'projects' to list available projects).") - } - found - } - } - object SpecificBuild - { - import java.util.regex.Pattern.{compile,quote} - val pattern = compile(quote(SpecificBuildPrefix) + """\s*(\S+)\s*(.*)""") - def unapply(s: String) = - { - val m = pattern.matcher(s) - if(m.matches) - Some(m.group(1).trim, m.group(2).trim) - else - None - } - } - def checkVersion(p: Project, version: String) = - { - try { p.getScalaInstance(version); true } - catch { case e: xsbti.RetrieveException => p.log.error(e.getMessage); false } - } - object CrossBuild - { - def unapply(s: String) = if(s.startsWith(CrossBuildPrefix) && !s.startsWith(SpecificBuildPrefix)) Some(s.substring(1)) else None - def apply(project: Project, action: String): Option[List[String]] = - { - val againstScalaVersions = project.crossScalaVersions - if(againstScalaVersions.isEmpty) - { - Console.println("Project does not declare any Scala versions to cross-build against, building against current version...") - Some(action :: Nil) - } - else - { - if( !againstScalaVersions.forall(v => checkVersion(project, v)) ) - None - else - { - val actions = - againstScalaVersions.toList.map(SpecificBuildPrefix + _ + " " + action) ::: // build against all versions - (SpecificBuildPrefix + project.buildScalaVersion) :: // reset to the version before the cross-build - Nil - Some(actions) - } - } - } - } - private def readLines(project: Project, file: File): Option[List[String]] = - { - try { Some(xsbt.FileUtilities.readLines(file)) } - catch { case e: Exception => - project.log.trace(e) - project.log.error("Error reading commands from file " + file.getAbsolutePath + ": " + e.toString) - None - } - } - private def prompt(baseProject: Project, project: Project): String = - { - // the times for evaluating the lazy vals here are a few hundred ms out of a 2s startup - lazy val projectNames = baseProject.projectClosure.map(_.name) - val prefixes = ContinuousExecutePrefix :: CrossBuildPrefix :: Nil - lazy val scalaVersions = baseProject.crossScalaVersions ++ Seq(baseProject.defScalaVersion.value) - lazy val methods = project.methods - lazy val methodCompletions = new ExtraCompletions { def names = methods.keys.toList; def completions(name: String) = methods(name).completions } - lazy val completors = new Completors(ProjectAction, projectNames, basicCommands, List(GetAction, SetAction), SpecificBuildPrefix, scalaVersions, prefixes, project.taskNames, project.propertyNames, methodCompletions) - val reader = new LazyJLineReader(baseProject.historyPath, MainCompletor(completors), baseProject.log) - reader.readLine("> ").getOrElse(ExitCommand) - } - /** The name of the command that loads a console with access to the current project through the variable 'project'.*/ - val ProjectConsoleAction = "console-project" - /** The name of the command that shows the current project and logging level of that project.*/ - val ShowCurrent = "current" - /** The name of the command that shows all available actions.*/ - val ShowActions = "actions" - /** The name of the command that sets the currently active project.*/ - val ProjectAction = "project" - /** The name of the command that shows all available projects.*/ - val ShowProjectsAction = "projects" - val ExitCommand = "exit" - val QuitCommand = "quit" - /** The name of the command that resets JLine. This is necessary when resuming from suspension.*/ - val ResetCommand = "reset" - /** The name of the command that switches to the builder project.*/ - val BuilderCommand = "builder" - /** The name of the command that loads the interactive shell.*/ - val InteractiveCommand = "shell" - /** The list of lowercase command names that may be used to terminate the program.*/ - val TerminateActions: Iterable[String] = ExitCommand :: QuitCommand :: Nil - /** The name of the command that sets the value of the property given as its argument.*/ - val SetAction = "set" - /** The name of the command that gets the value of the property given as its argument.*/ - val GetAction = "get" - /** The name of the command that displays the help message. */ - val HelpAction = "help" - /** The command for reloading sbt.*/ - val RebootCommand = "reload" - /** The name of the command that toggles logging stacktraces. */ - val TraceCommand = "trace" - /** The name of the command that compiles all sources continuously when they are modified. */ - val ContinuousCompileCommand = "cc" - /** The prefix used to identify a request to execute the remaining input on source changes.*/ - val ContinuousExecutePrefix = "~" - /** The prefix used to identify a request to execute the remaining input across multiple Scala versions.*/ - val CrossBuildPrefix = "+" - /** The prefix used to identify a request to execute the remaining input after the next space against the - * Scala version between this prefix and the space (i.e. '++version action' means execute 'action' using - * Scala version 'version'. */ - val SpecificBuildPrefix = "++" - /** The prefix used to identify a file or local port to read commands from. */ - val FileCommandsPrefix = "<" - /** The prefix used to identify the action to run after an error*/ - val FailureHandlerPrefix = "-" - /** The prefix used to identify commands for managing processors.*/ - val ProcessorPrefix = "*" - - /** The number of seconds between polling by the continuous compile command.*/ - val ContinuousCompilePollDelaySeconds = 1 - - /** The list of logging levels.*/ - private def logLevels: Iterable[String] = TreeSet.empty[String] ++ Level.values.map(_.toString) - /** The list of all interactive commands other than logging level.*/ - private def basicCommands: Iterable[String] = TreeSet(ShowProjectsAction, ShowActions, ShowCurrent, HelpAction, - RebootCommand, TraceCommand, ContinuousCompileCommand, ProjectConsoleAction, BuilderCommand) ++ - logLevels.toList ++ TerminateActions ++ - HistoryCommands.plainCommands - - private def processAction(baseProject: Project, currentProject: Project, action: String, isInteractive: Boolean): Boolean = - action match - { - case HelpAction => displayHelp(isInteractive); true - case ShowProjectsAction => baseProject.projectClosure.foreach(listProject); true - case ProjectConsoleAction => - showResult(Run.projectConsole(currentProject), currentProject.log) - case _ => - if(action.startsWith(SetAction + " ")) - setProperty(currentProject, action.substring(SetAction.length + 1)) - else if(action.startsWith(GetAction + " ")) - getProperty(currentProject, action.substring(GetAction.length + 1)) - else if(action.startsWith(TraceCommand + " ")) - setTrace(currentProject, action.substring(TraceCommand.length + 1)) - else - handleCommand(currentProject, action) - } - - private def printCmd(name:String, desc:String) = Console.println(" " + name + " : " + desc) - val BatchHelpHeader = "You may execute any project action or method or one of the commands described below." - val InteractiveHelpHeader = "You may execute any project action or one of the commands described below. Only one action " + - "may be executed at a time in interactive mode and is entered by name, as it would be at the command line." + - " Also, tab completion is available." - private def displayHelp(isInteractive: Boolean) - { - Console.println(if(isInteractive) InteractiveHelpHeader else BatchHelpHeader) - Console.println("Available Commands:") - - printCmd("", "Executes the project specified action.") - printCmd(" *", "Executes the project specified method.") - printCmd(" ", "Runs the specified processor.") - printCmd(ContinuousExecutePrefix + " ", "Executes the project specified action or method whenever source files change.") - printCmd(FileCommandsPrefix + " file", "Executes the commands in the given file. Each command should be on its own line. Empty lines and lines beginning with '#' are ignored") - printCmd(CrossBuildPrefix + " ", "Executes the project specified action or method for all versions of Scala defined in crossScalaVersions.") - printCmd(SpecificBuildPrefix + " ", "Changes the version of Scala building the project and executes the provided command. is optional.") - printCmd(ProcessorPrefix, "Prefix for commands for managing processors. Run '" + ProcessorPrefix + "help' for details.") - printCmd(HistoryPrefix, "Prefix for history commands. Run '" + HistoryPrefix+ "' for history command help.") - printCmd(ShowActions, "Shows all available actions.") - printCmd(RebootCommand, "Reloads sbt, picking up modifications to sbt.version or scala.version and recompiling modified project definitions.") - printCmd(HelpAction, "Displays this help message.") - printCmd(ShowCurrent, "Shows the current project, Scala version, and logging level.") - printCmd(Level.values.mkString(", "), "Set logging for the current project to the specified level.") - printCmd(TraceCommand + " " + validTraceArguments, "Configures stack trace logging. " + traceExplanation) - printCmd(ProjectAction + " ", "Sets the currently active project.") - printCmd(ShowProjectsAction, "Shows all available projects.") - printCmd(TerminateActions.elements.mkString(", "), "Terminates the build.") - printCmd(SetAction + " ", "Sets the value of the property given as its argument.") - printCmd(GetAction + " ", "Gets the value of the property given as its argument.") - printCmd(ProjectConsoleAction, "Enters the Scala interpreter with the current project definition bound to the variable 'current' and all members imported.") - printCmd(BuilderCommand, "Set the current project to be the project definition builder.") - if(!isInteractive) - printCmd(InteractiveCommand, "Enters the sbt interactive shell") - } - private def listProject(p: Project) = printProject("\t", p) - private def printProject(prefix: String, p: Project): Unit = - Console.println(prefix + p.name + " " + p.version) - - /** Handles the given command string provided at the command line. Returns false if there was an error*/ - private def handleCommand(project: Project, command: String): Boolean = - { - command match - { - case GetAction => getArgumentError(project.log) - case SetAction => setArgumentError(project.log) - case ProjectAction => setProjectError(project.log) - case TraceCommand => setTraceError(project.log); true - case ShowCurrent => - printProject("Current project is ", project) - Console.println("Current Scala version is " + project.buildScalaVersion) - Console.println("Current log level is " + project.log.getLevel) - printTraceEnabled(project) - true - case ShowActions => showActions(project); true - case Level(level) => setLevel(project, level); true - case ContinuousCompileCommand => compileContinuously(project) - case action if action.startsWith(ContinuousExecutePrefix) => executeContinuously(project, action.substring(ContinuousExecutePrefix.length).trim) - case action => handleAction(project, action) - } - } - private def showActions(project: Project): Unit = Console.println(project.taskAndMethodList) - - // returns true if it succeeded - private def handleAction(project: Project, action: String): Boolean = - { - def show(result: Option[String]): Boolean = showResult(result, project.log) - val startTime = System.currentTimeMillis - val result = withAction(project, action)( (name, params) => show(project.call(name, params)))( name => show(project.act(name))) - printTime(project, startTime, "") - result - } - // returns true if it succeeded - private def showResult(result: Option[String], log: Logger): Boolean = - { - result match - { - case Some(errorMessage) => log.error(errorMessage); false - case None => log.success("Successful."); true - } - } - // true if the action exists - private def checkAction(project: Project, actionString: String): Boolean = - withAction(project, actionString)( (n,p) => true)( n => true) - private def withAction(project: Project, actionString: String)(ifMethod: (String, Array[String]) => Boolean)(ifAction: String => Boolean): Boolean = - { - def didNotExist(taskType: String, name: String) = - { - project.log.error("No " + taskType + " named '" + name + "' exists.") - project.log.info("Execute 'help' for a list of commands or 'actions' for a list of available project actions and methods.") - false - } - impl.CommandParser.parse(actionString) match - { - case Left(errMsg) => project.log.error(errMsg); false - case Right((name, parameters)) => - if(project.methods.contains(name)) - ifMethod(name, parameters.toArray) - else if(!parameters.isEmpty) - didNotExist("method", name) - else if(project.deepTasks.contains(name)) - ifAction(name) - else - didNotExist("action", name) - } - } - - /** Toggles whether stack traces are enabled.*/ - private def setTrace(project: Project, value: String): Boolean = - { - try - { - val newValue = if(value == "on") MaxInt else if(value == "off") -1 else if(value == "nosbt") 0 else value.toInt - project.projectClosure.foreach(_.log.setTrace(newValue)) - printTraceEnabled(project) - true - } - catch { case _: NumberFormatException => setTraceError(project.log) } - } - private def printTraceEnabled(project: Project) - { - def traceLevel(level: Int) = if(level == 0) " (no sbt stack elements)" else if(level == MaxInt) "" else " (maximum " + level + " stack elements per exception)" - Console.println("Stack traces are " + (if(project.log.traceEnabled) "enabled" + traceLevel(project.log.getTrace) else "disabled")) - } - /** Sets the logging level on the given project.*/ - private def setLevel(project: Project, level: Level.Value) - { - project.projectClosure.foreach(_.log.setLevel(level)) - Console.println("Set log level to " + project.log.getLevel) - } - /** Prints the elapsed time to the given project's log using the given - * initial time and the label 's'.*/ - private def printTime(project: Project, startTime: Long, s: String) - { - val endTime = System.currentTimeMillis() - project.log.info("") - val ss = if(s.isEmpty) "" else s + " " - project.log.info("Total " + ss + "time: " + (endTime - startTime + 500) / 1000 + " s, completed " + nowString) - } - private def nowString = - { - import java.text.DateFormat - val format = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM) - format.format(new java.util.Date) - } - /** Provides a partial message describing why the given property is undefined. */ - private def undefinedMessage(property: Project#UserProperty[_]): String = - { - property.resolve match - { - case vu: UndefinedValue => " is not defined." - case e: ResolutionException => " has invalid value: " + e.toString - case _ => "" - } - } - /** Prompts the user for the value of undefined properties. 'first' is true if this is the first time - * that the current property has been prompted.*/ - private def fillUndefinedProperties(project: Project, properties: List[(String, Project#Property[_])], first: Boolean): Boolean = - { - properties match - { - case (name, variable) :: tail => - { - val shouldAdvanceOrQuit = - variable match - { - case property: Project#UserProperty[_] => - if(first) - project.log.error(" Property '" + name + "' " + undefinedMessage(property)) - for(newValue <- SimpleReader.readLine(" Enter new value for " + name + " : ")) yield - { - try - { - property.setStringValue(newValue) - true - } - catch - { - case e => - project.log.error("Invalid value: " + e.getMessage) - false - } - } - case _ => Some(true) - } - shouldAdvanceOrQuit match - { - case Some(shouldAdvance) => fillUndefinedProperties(project, if(shouldAdvance) tail else properties, shouldAdvance) - case None => false - } - } - case Nil => true - } - } - /** Iterates over the undefined properties in the given projects, prompting the user for the value of each undefined - * property.*/ - private def fillUndefinedProjectProperties(projects: List[Project]): Boolean = - { - projects match - { - case project :: remaining => - val uninitialized = project.uninitializedProperties.toList - if(uninitialized.isEmpty) - fillUndefinedProjectProperties(remaining) - else - { - project.log.error("Project in " + project.info.projectDirectory.getAbsolutePath + " has undefined properties.") - val result = fillUndefinedProperties(project, uninitialized, true) && fillUndefinedProjectProperties(remaining) - project.saveEnvironment() - result - } - case Nil => true - } - } - /** Prints the value of the property with the given name in the given project. */ - private def getProperty(project: Project, propertyName: String): Boolean = - { - if(propertyName.isEmpty) - { - project.log.error("No property name specified.") - false - } - else - { - project.getPropertyNamed(propertyName) match - { - case Some(property) => - property.resolve match - { - case u: UndefinedValue => project.log.error("Value of property '" + propertyName + "' is undefined."); false - case ResolutionException(m, e) => project.log.error(m); false - case DefinedValue(value, isInherited, isDefault) => Console.println(value.toString); true - } - case None => - val value = System.getProperty(propertyName) - if(value == null) - project.log.error("No property named '" + propertyName + "' is defined.") - else - Console.println(value) - value != null - } - } - } - /** Separates the space separated property name/value pair and stores the value in the user-defined property - * with the given name in the given project. If no such property exists, the value is stored in a system - * property. */ - private def setProperty(project: Project, propertyNameAndValue: String): Boolean = - { - val m = """(\S+)(\s+\S.*)?""".r.pattern.matcher(propertyNameAndValue) - if(m.matches()) - { - val name = m.group(1) - val newValue = - { - val v = m.group(2) - if(v == null) "" else v.trim - } - def notePending(changed: String): Unit = Console.println(" Build will use " + changed + newValue + " after running 'reload' command or restarting sbt.") - project.getPropertyNamed(name) match - { - case Some(property) => - { - try - { - property.setStringValue(newValue) - property match - { - case project.defScalaVersion | project.buildScalaVersions => notePending("Scala ") - case project.sbtVersion => notePending("sbt ") - case _ => Console.println(" Set property '" + name + "' = '" + newValue + "'") - } - true - } - catch { case e => - project.log.error("Error setting property '" + name + "' in " + project.environmentLabel + ": " + e.toString) - false - } - finally { project.saveEnvironment().foreach(msg => project.log.error("Error saving environment: " + msg)) } - } - case None => - { - System.setProperty(name, newValue) - project.log.info(" Set system property '" + name + "' = '" + newValue + "'") - true - } - } - } - else - setArgumentError(project.log) - } - - private def compileContinuously(project: Project) = executeContinuously(project, "test-compile") - private def executeContinuously(project: Project, action: String) = - { - def shouldTerminate: Boolean = (System.in.available > 0) && (project.terminateWatch(System.in.read()) || shouldTerminate) - val actionValid = checkAction(project, action) - if(actionValid) - { - var count = 0 - val sourcesFinder: PathFinder = (Path.emptyPathFinder /: project.topologicalSort)(_ +++ _.watchPaths) - SourceModificationWatch.watchUntil(sourcesFinder, ContinuousCompilePollDelaySeconds)(shouldTerminate) - { - count += 1 - handleAction(project, action) - Console.println(count + ". Waiting for source changes... (press enter to interrupt)") - } - while (System.in.available() > 0) System.in.read() - } - actionValid - } - - def validTraceArguments = "'on', 'nosbt', 'off', or " - def traceExplanation = "'nosbt' prints stack traces up to the first sbt frame. An integer gives the number of frames to show per exception." - private def isTerminateAction(s: String) = TerminateActions.elements.contains(s.toLowerCase) - private def setTraceError(log: Logger) = logError(log)("Invalid arguments for 'trace': expected " + validTraceArguments + ".") - private def setArgumentError(log: Logger) = logError(log)("Invalid arguments for 'set': expected property name and new value.") - private def getArgumentError(log: Logger) = logError(log)("Invalid arguments for 'get': expected property name.") - private def setProjectError(log: Logger) = logError(log)("Invalid arguments for 'project': expected project name.") - private def logError(log: Logger)(s: String) = { log.error(s); false } - - private def logCommandError(log: Logger, e: Throwable) = - e match - { - case pe: processor.ProcessorException => - if(pe.getCause ne null) log.trace(pe.getCause) - log.error(e.getMessage) - case e => - log.trace(e) - log.error(e.toString) - } -} diff --git a/sbt_pending/src/main/scala/sbt/Project.scala b/sbt_pending/src/main/scala/sbt/Project.scala deleted file mode 100644 index 6bcf4d3b9..000000000 --- a/sbt_pending/src/main/scala/sbt/Project.scala +++ /dev/null @@ -1,537 +0,0 @@ -/* sbt -- Simple Build Tool - * Copyright 2008, 2009 Mark Harrah, David MacIver - */ -package sbt - -import xsbti.{AppProvider, ScalaProvider} -import xsbt.{AnalyzingCompiler, ScalaInstance} -import java.io.File -import java.net.URLClassLoader -import scala.collection._ -import FileUtilities._ -import Project._ - -trait Project extends TaskManager with Dag[Project] with BasicEnvironment -{ - /** The logger for this project definition. */ - final val log: Logger = logImpl - protected def logImpl: Logger = - { - val lg = new BufferedLogger(new FilterLogger(info.logger)) - lg.setLevel(defaultLoggingLevel) - lg - } - protected def defaultLoggingLevel = Level.Info - - trait ActionOption extends NotNull - - /** Basic project information. */ - def info: ProjectInfo - /** The project name. */ - def name: String = projectName.value - /** The project version. */ - def version: Version = projectVersion.value - /** The project organization. */ - def organization: String = projectOrganization.value - /** True if the project should cater to a quick throwaway project setup.*/ - def scratch = projectScratch.value - - final type ManagerType = Project - final type ManagedTask = Project#Task - /** The tasks declared on this project. */ - def tasks: Map[String, ManagedTask] - /** The task methods declared on this project */ - def methods: Map[String, MethodTask] - /** The names of all available tasks that may be called through `act`. These include - * the names of the Tasks in `tasks` and those of all dependencies.*/ - def taskNames: Iterable[String] = deepTasks.keys.toList - /** The names of all available method tasks that may be called through `call`. These - * only include the names of the MethodTasks in `methods` and not those of dependencies.*/ - def methodNames: Iterable[String] = methods.keys.toList - /** A description of all available method tasks in this project, but not of dependencies. */ - def methodList: String = descriptionList(methods) - /** A description of all available tasks in this project and all dependencies. If there - * are different tasks with the same name, only one will be included. */ - def taskList: String = descriptionList(deepTasks) - - final def taskName(task: Task) = tasks.find( _._2 eq task ).map(_._1) - /** A description of all available tasks in this project and all dependencies and all - * available method tasks in this project, but not of dependencies. If there - * are different tasks or methods with the same name, only one will be included. */ - def taskAndMethodList: String = descriptionList(tasksAndMethods) - /** The actions and methods declared on this project. */ - final def tasksAndMethods: Map[String, Described] = - immutable.TreeMap.empty[String, Described] ++ methods ++ tasks - private def descriptionList(described: Map[String, Described]): String = - { - val buffer = new StringBuilder - for((name, d) <- described) - buffer.append("\t" + name + d.description.map(x => ": " + x).getOrElse("") + "\n") - buffer.toString - } - /** Combines the method task maps of this project and all dependencies.*/ - private[sbt] def deepMethods: Map[String, Project#MethodTask] = deep(_.methods) - /** Combines the task maps of this project and all dependencies.*/ - private[sbt] def deepTasks: Map[String, Project#Task] = deep(_.tasks) - private def deep[T](p: Project => Map[String, T]): Map[String, T] = - { - var tasks: immutable.SortedMap[String,T] = new immutable.TreeMap[String, T] - for(dependentProject <- topologicalSort) - tasks ++= p(dependentProject).elements - tasks - } - /** A map of names to projects for all subprojects of this project. These are typically explicitly - * specified for the project and are different from those specified in the project constructor. The - * main use within sbt is in ParentProject.*/ - def subProjects: Map[String, Project] = immutable.Map.empty - def projectClosure: List[Project] = Dag.topologicalSort(this)(p => p.dependencies ++ p.subProjects.values.toList) - - def call(name: String, parameters: Array[String]): Option[String] = - { - methods.get(name) match - { - case Some(method) =>run(method(parameters), name) - case None => Some("Method '" + name + "' does not exist.") - } - } - private def run(task: Project#Task, taskName: String): Option[String] = - impl.RunTask(task, taskName, parallelExecution) match - { - case Nil => None - case x => Some(Set(x: _*).mkString("\n")) - } - - /** Executes the task with the given name. This involves executing the task for all - * project dependencies (transitive) and then for this project. Not every dependency - * must define a task with the given name. If this project and all dependencies - * do not define a task with the given name, an error is generated indicating this.*/ - def act(name: String): Option[String] = - { - val ordered = topologicalSort - val definedTasks = ordered.flatMap(_.tasks.get(name).toList) - def virtualTask(name: String): Task = new Task(None, definedTasks.filter(!_.interactive), false, None) - - if(definedTasks.isEmpty) - Some("Action '" + name + "' does not exist.") - else - { - tasks.get(name) match - { - case None => - val virtual = virtualTask(name) - if(virtual.dependencies.size == definedTasks.size) - run(virtual, name) - else - { - Some("Cannot run interactive action '" + name + - "' defined on multiple subprojects (change to the desired project with 'project ').") - } - case Some(task) => run(task, name) - } - } - } - - /** Logs the list of projects at the debug level.*/ - private def showBuildOrder(order: Iterable[Project]) - { - log.debug("Project build order:") - order.foreach(x => log.debug(" " + x.name) ) - log.debug("") - } - - /** Converts a String to a path relative to the project directory of this project. */ - implicit def path(component: String): Path = info.projectPath / component - /** Converts a String to a simple name filter. * has the special meaning: zero or more of any character */ - implicit def filter(simplePattern: String): NameFilter = GlobFilter(simplePattern) - - /** Loads the project at the given path and declares the project to have the given - * dependencies. This method will configure the project according to the - * project/ directory in the directory denoted by path.*/ - def project(path: Path, deps: Project*): Project = getProject(Project.loadProject(path, deps, Some(this), info.logger, info.app, info.buildScalaVersion), path) - - /** Loads the project at the given path using the given name and inheriting this project's version. - * The builder class is the default builder class, sbt.DefaultProject. The loaded project is declared - * to have the given dependencies. Any project/build/ directory for the project is ignored.*/ - def project(path: Path, name: String, deps: Project*): Project = project(path, name, Project.DefaultBuilderClass, deps: _*) - - /** Loads the project at the given path using the given name and inheriting it's version from this project. - * The Project implementation used is given by builderClass. The dependencies are declared to be - * deps. Any project/build/ directory for the project is ignored.*/ - def project[P <: Project](path: Path, name: String, builderClass: Class[P], deps: Project*): P = - { - require(builderClass != this.getClass, "Cannot recursively construct projects of same type: " + builderClass.getName) - project(path, name, info => Project.constructProject(info, builderClass), deps: _*) - } - /** Loads the project at the given path using the given name and inheriting it's version from this project. - * The construct function is used to obtain the Project instance. Any project/build/ directory for the project - * is ignored. The project is declared to have the dependencies given by deps.*/ - def project[P <: Project](path: Path, name: String, construct: ProjectInfo => P, deps: Project*): P = - initialize(construct(ProjectInfo(path.asFile, deps, Some(this))(info.logger, info.app, info.buildScalaVersion)), Some(new SetupInfo(name, None, None, false)), log) - - /** Initializes the project directories when a user has requested that sbt create a new project.*/ - def initializeDirectories() {} - /** True if projects should be run in parallel, false if they should run sequentially. - * This only has an effect for multi-projects. If this project has a parent, this value is - * inherited from that parent project.*/ - def parallelExecution: Boolean = - info.parent match - { - case Some(parent) => parent.parallelExecution - case None => false - } - - /** True if a project and its dependencies should be checked to ensure that their - * output directories are not the same, false if they should not be checked. */ - def shouldCheckOutputDirectories = true - - /** The list of directories to which this project writes. This is used to verify that multiple - * projects have not been defined with the same output directories. */ - def outputDirectories: Iterable[Path] = outputPath :: Nil - def rootProject = Project.rootProject(this) - /** The path to the file that provides persistence for properties.*/ - final def envBackingPath = info.builderPath / Project.DefaultEnvBackingName - /** The path to the file that provides persistence for history. */ - def historyPath: Option[Path] = Some(outputRootPath / ".history") - def outputPath = crossPath(outputRootPath) - def outputRootPath: Path = outputDirectoryName - def outputDirectoryName = DefaultOutputDirectoryName - - private def getProject(result: LoadResult, path: Path): Project = - result match - { - case LoadSetupDeclined => Predef.error("No project exists at path " + path) - case lse: LoadSetupError => Predef.error("Error setting up new project at path " + path + " : " + lse.message) - case err: LoadError => Predef.error("Error loading project at path " + path + " : " + err.message) - case success: LoadSuccess => success.project - } - - /** The property for the project's version. */ - final val projectVersion = property[Version] - /** The property for the project's name. */ - final val projectName = propertyLocalF[String](NonEmptyStringFormat) - /** The property for the project's organization. Defaults to the parent project's organization or the project name if there is no parent. */ - final val projectOrganization = propertyOptional[String](normalizedName, true) - /** The property that defines the version of Scala to use with the project definition. This can be different - * from the version of Scala used to build the project (current version used is buildScalaVersion, available are in buildScalaVersions). - * This property is only read by `sbt` on startup and reload.*/ - final val defScalaVersion = propertyOptional[String](info.definitionScalaVersion) - /** The property to specify the sbt revision to use. - * Note that this can by a dynamic revision (see Ivy documentation for details on dynamic revisions). - *Therefore, use `sbt.ComponentManager.version` and `timestamp` for actual version information. */ - final val sbtVersion = property[String] - final val projectInitialize = propertyOptional[Boolean](false) - final val projectScratch = propertyOptional[Boolean](false, true) - final val offline = propertyOptional[Boolean](false) - /** The property that defines the versions of Scala to build this project against as a comma separated string. This can be - * different from the version of Scala used to build and run the project definition (defined by defScalaVersion). - * This property is only read by `sbt` on startup and reload. The definitive source for the version of Scala currently - * being used is buildScalaVersion.*/ - final val buildScalaVersions = propertyOptional[String](defScalaVersion.value, true) - /** The definitive source for the version of Scala being requested to *build* the project. - * For the full version information, see buildScalaInstance.actualVersion.*/ - def buildScalaVersion = info.buildScalaVersion.getOrElse(crossScalaVersions.first) - private[sbt] def isScala27 = buildScalaInstance.actualVersion.startsWith("2.7.") - - - def componentManager = new ComponentManager(info.launcher.globalLock, info.app.components, log) - def buildScalaInstance = buildScalaInstance0 - final def buildLibraryJar = Path.fromFile(buildScalaInstance.libraryJar) - final def buildCompilerJar = Path.fromFile(buildScalaInstance.compilerJar) - final def buildScalaJars = Path.finder { buildScalaInstance.jars } - final def buildScalaInstance0: ScalaInstance = - { - val scalaVersion = buildScalaVersion - try { getScalaInstance(scalaVersion) } - catch { case e: xsbti.RetrieveException if info.buildScalaVersion.isEmpty => // only catch the exception if this is the default Scala version - log.error(e.getMessage) - SimpleReader.readLine("\nProvide a new Scala version or press enter to exit: ") match - { - case Some(v) if v.length > 0=> - buildScalaVersions() = replace(scalaVersion, v) - saveEnvironment() - buildScalaInstance0 - case _ => throw e - } - } - } - private def replace(originalV: String, newV: String) = buildScalaVersions.value.replaceAll("""\b\Q""" + originalV + """\E\b""", newV) - def getScalaInstance(version: String) = - localScalaInstances.find(_.version == version) getOrElse - xsbt.ScalaInstance(version, info.launcher) - lazy val localScalaInstances: Seq[ScalaInstance] = localScala ++ info.parent.toList.flatMap(_.localScalaInstances) - def localScala: Seq[ScalaInstance] = Nil - lazy val buildCompiler = new AnalyzingCompiler(buildScalaInstance, componentManager, log) - /** Get a `ScalaInstance` for the Scala version with base directory `home`. The library and compiler jars are - * assumed to be at `new File(home, "lib/scala-library.jar")` and `new File(home, "lib/scala-compiler.jar")`. - * The label for this instance is determined by the version String in the `compiler.properties` file in `scala-compiler.jar`.*/ - def defineScala(home: File): ScalaInstance = ScalaInstance(home, info.launcher) - /** Get a `ScalaInstance` for the Scala version with base directory `home`. The library and compiler jars are - * assumed to be at `new File(home, "lib/scala-library.jar")` and `new File(home, "lib/scala-compiler.jar")`. - * `version` is used as the label for this instance.*/ - def defineScala(version: String, home: File): ScalaInstance = ScalaInstance(version, home, info.launcher) - - /** If this project is cross-building, returns `base` with an additional path component containing the scala version - * currently used to build the project. Otherwise, this returns `base`. - * By default, cross-building is enabled when a project is loaded by the loader and crossScalaVersions is not empty.*/ - def crossPath(base: Path) = if(disableCrossPaths) base else base / crossString - /** If modifying paths for cross-building is enabled, this returns ScalaVersion.currentString. - * Otherwise, this returns the empty string. */ - def crossScalaVersionString: String = if(disableCrossPaths) "" else buildScalaVersion - private def crossString = "scala_" + buildScalaVersion - - - /** True if crossPath should be the identity function.*/ - protected def disableCrossPaths = crossScalaVersions.isEmpty - /** By default, this is the build.scala.versions property split around whitespace. This can be overridden directly if preferred.*/ - def crossScalaVersions: Seq[String] = - info.parent match - { - case Some(p) => p.crossScalaVersions - case None => buildScalaVersions.value.split("""\s+""").toList.reverse.removeDuplicates.reverse - } - /** A `PathFinder` that determines the files watched when an action is run with a preceeding ~ when this is the current - * project. This project does not need to include the watched paths for projects that this project depends on.*/ - def watchPaths: PathFinder = Path.emptyPathFinder - def terminateWatch(key: Int): Boolean = key == 10 || key == 13 - - protected final override def parentEnvironment = info.parent - - // .* included because svn doesn't mark .svn hidden - def defaultExcludes: FileFilter = (".*" - ".") || HiddenFileFilter - /** Short for parent.descendentsExcept(include, defaultExcludes)*/ - def descendents(parent: PathFinder, include: FileFilter) = parent.descendentsExcept(include, defaultExcludes) - override def toString = "Project " + projectName.get.getOrElse("at " + environmentLabel) - - def normalizedName = StringUtilities.normalize(name) -} -private[sbt] sealed trait LoadResult extends NotNull -private[sbt] final class LoadSuccess(val project: Project) extends LoadResult -private[sbt] final class LoadError(val message: String) extends LoadResult -private[sbt] final object LoadSetupDeclined extends LoadResult -private[sbt] final class LoadSetupError(val message: String) extends LoadResult - -object Project -{ - val BootDirectoryName = "boot" - val DefaultOutputDirectoryName = "target" - val DefaultEnvBackingName = "build.properties" - val DefaultBuilderClassName = "sbt.DefaultProject" - val DefaultBuilderClass = Class.forName(DefaultBuilderClassName).asSubclass(classOf[Project]) - - /** The name of the directory for project definitions.*/ - val BuilderProjectDirectoryName = "build" - /** The name of the directory for plugin definitions.*/ - val PluginProjectDirectoryName = "plugins" - /** The name of the class that all projects must inherit from.*/ - val ProjectClassName = classOf[Project].getName - - /** The logger that should be used before the root project definition is loaded.*/ - private[sbt] def bootLogger = - { - val log = new ConsoleLogger - log.setLevel(Level.Debug) - log - } - - private[sbt] def booted = java.lang.Boolean.getBoolean("sbt.boot") - - private[sbt] def loadProject(app: AppProvider): LoadResult = loadProject(app, None) - /** Loads the project in the current working directory. */ - private[sbt] def loadProject(app: AppProvider, buildScalaVersion: Option[String]): LoadResult = loadProject(bootLogger, app, buildScalaVersion) - /** Loads the project in the current working directory.*/ - private[sbt] def loadProject(log: Logger, app: AppProvider, buildScalaVersion: Option[String]): LoadResult = - checkOutputDirectories(loadProject(new File("."), Nil, None, log, app, buildScalaVersion)) - /** Loads the project in the directory given by 'path' and with the given dependencies.*/ - private[sbt] def loadProject(path: Path, deps: Iterable[Project], parent: Option[Project], log: Logger, app: AppProvider, buildScalaVersion: Option[String]): LoadResult = - loadProject(path.asFile, deps, parent, log, app, buildScalaVersion) - /** Loads the project in the directory given by 'projectDirectory' and with the given dependencies.*/ - private[sbt] def loadProject(projectDirectory: File, deps: Iterable[Project], parent: Option[Project], log: Logger, app: AppProvider, buildScalaVersion: Option[String]): LoadResult = - { - val info = ProjectInfo(projectDirectory, deps, parent)(log, app, buildScalaVersion) - ProjectInfo.setup(info, log) match - { - case err: SetupError => new LoadSetupError(err.message) - case SetupDeclined => LoadSetupDeclined - case AlreadySetup => loadProject(info, None, log) - case setup: SetupInfo => loadProject(info, Some(setup), log) - } - } - private def loadProject(info: ProjectInfo, setupInfo: Option[SetupInfo], log: Logger): LoadResult = - { - try - { - val result = - for(builderClass <- getProjectDefinition(info, log).right) yield - initialize(constructProject(info, builderClass), setupInfo, log) - result.fold(new LoadError(_), new LoadSuccess(_)) - } - catch - { - case ite: java.lang.reflect.InvocationTargetException => - { - val cause = - if(ite.getCause == null) ite - else ite.getCause - errorLoadingProject(cause, log) - } - case nme: NoSuchMethodException => new LoadError("Constructor with one argument of type sbt.ProjectInfo required for project definition.") - case e: Exception => errorLoadingProject(e, log) - } - } - private def errorLoadingProject(e: Throwable, log: Logger) = - e match - { - case _: xsbti.RetrieveException => LoadSetupDeclined - case _ => - log.trace(e) - new LoadError("Error loading project: " + e.toString) - } - /** Loads the project for the given `info` and represented by an instance of 'builderClass'.*/ - private[sbt] def constructProject[P <: Project](info: ProjectInfo, builderClass: Class[P]): P = - builderClass.getConstructor(classOf[ProjectInfo]).newInstance(info) - /** Checks the project's dependencies, initializes its environment, and possibly its directories.*/ - private def initialize[P <: Project](p: P, setupInfo: Option[SetupInfo], log: Logger): P = - { - def save() = p.saveEnvironment() foreach { errorMsg => log.error(errorMsg) } - setupInfo match - { - case Some(setup) => - { - p.projectName() = setup.name - for(v <- setup.version) - p.projectVersion() = v - for(org <- setup.organization) - p.projectOrganization() = org - if(!setup.initializeDirectories) - p.setEnvironmentModified(false) - save() - if(setup.initializeDirectories) - p.initializeDirectories() - } - case None => - if(p.projectInitialize.value) - { - p.initializeDirectories() - p.projectInitialize() = false - save() - } - } - val useName = p.projectName.get.getOrElse("at " + p.info.projectDirectory.getAbsolutePath) - checkDependencies(useName, p.info.dependencies, log) - p.buildScalaInstance // done so that build Scala version is initialized on project startup - p - } - /** Compiles the project definition classes and returns the project definition class name - * and the class loader that should be used to load the definition. */ - private def getProjectDefinition(info: ProjectInfo, buildLog: Logger): Either[String, Class[P] forSome { type P <: Project }] = - getProjectBuilder(info, buildLog) match - { - case Some(builder) => buildProjectDefinition(builder) - case None => Right(DefaultBuilderClass) - } - private def buildProjectDefinition(builderProject: BuilderProject): Either[String, Class[P] forSome { type P <: Project }] = - builderProject.compile.run.toLeft(()).right.flatMap { ignore => - builderProject.projectDefinition.right.map { - case Some(definition) => getProjectClass[Project](definition, builderProject.projectClasspath, getClass.getClassLoader) - case None => DefaultBuilderClass - } - } - private[sbt] def getProjectClasspath(project: Project): PathFinder = - getProjectBuilder(project.info, project.log) match - { - case Some(builder) => builder.projectClasspath - case _ if project.getClass == DefaultBuilderClass => project.info.sbtClasspath - case _ => - project.info.parent match - { - case Some(p) => getProjectClasspath(p) - case None => project.info.sbtClasspath - } - } - private[sbt] def getProjectBuilder(info: ProjectInfo, buildLog: Logger): Option[BuilderProject] = - { - if(info.builderProjectPath.asFile.isDirectory) - { - val builderInfo = ProjectInfo(info.builderProjectPath.asFile, Nil, None)(buildLog, info.app, Some(info.definitionScalaVersion)) - val builderProject = new BuilderProject(builderInfo, info.pluginsPath, buildLog) - Some(builderProject) - } - else - None - } - /** Verifies that the given list of project dependencies contains no nulls. The - * String argument should be the project name with the dependencies.*/ - private def checkDependencies(forProject: String, deps: Iterable[Project], log: Logger) - { - for(nullDep <- deps.find(_ == null)) - { - log.error("Project " + forProject + " had a null dependency. This is probably an initialization problem and might be due to a circular dependency.") - throw new RuntimeException("Null dependency in project " + forProject) - } - } - /** Verifies that output directories of the given project and all of its dependencies are - * all different. No verification is done if the project overrides - * 'shouldCheckOutputDirectories' to be false. The 'Project.outputDirectories' method is - * used to determine a project's output directories. */ - private def checkOutputDirectories(result: LoadResult): LoadResult = - result match - { - case success: LoadSuccess => - if(success.project.shouldCheckOutputDirectories) - checkOutputDirectoriesImpl(success.project) - else - success - case x => x - } - /** Verifies that output directories of the given project and all of its dependencies are - * all different. The 'Project.outputDirectories' method is used to determine a project's - * output directories. */ - private def checkOutputDirectoriesImpl(project: Project): LoadResult = - { - val projects = project.projectClosure - import scala.collection.mutable.{HashMap, HashSet, Set} - val outputDirectories = new HashMap[Path, Set[Project]] - for(p <- projects; path <- p.outputDirectories) - outputDirectories.getOrElseUpdate(path, new HashSet[Project]) += p - val shared = outputDirectories.filter(_._2.size > 1) - if(shared.isEmpty) - new LoadSuccess(project) - else - { - val sharedString = - { - val s = - for((path, projectsSharingPath) <- shared) yield - projectsSharingPath.map(_.name).mkString(", ") + " share " + path - s.mkString("\n\t") - } - new LoadError("The same directory is used for output for multiple projects:\n\t" + sharedString + - "\n (If this is intentional, use 'override def shouldCheckOutputDirectories = false' in your project definition.)") - } - } - import scala.reflect.Manifest - private[sbt] def getProjectClass[P <: Project](name: String, classpath: PathFinder, additional: ClassLoader)(implicit mf: Manifest[P]): Class[P] = - { - val loader =ClasspathUtilities.toLoader(classpath, additional) - val builderClass = Class.forName(name, false, loader) - val projectClass = mf.erasure - require(projectClass.isAssignableFrom(builderClass), "Builder class '" + builderClass + "' does not extend " + projectClass.getName + ".") - builderClass.asSubclass(projectClass).asInstanceOf[Class[P]] - } - - /** Writes the project name and a separator to the project's log at the info level.*/ - def showProjectHeader(project: Project) - { - val projectHeader = "Project " + project.name - project.log.info("") - project.log.info(projectHeader) - project.log.info("=" * projectHeader.length) - } - - def rootProject(p: Project): Project = - p.info.parent match - { - case Some(parent) => rootProject(parent) - case None => p - } -} diff --git a/sbt_pending/src/main/scala/sbt/ProjectConsole.scala b/sbt_pending/src/main/scala/sbt/ProjectConsole.scala deleted file mode 100644 index 1462e7396..000000000 --- a/sbt_pending/src/main/scala/sbt/ProjectConsole.scala +++ /dev/null @@ -1,79 +0,0 @@ -/* sbt -- Simple Build Tool - * Copyright 2008, 2009 Mark Harrah - */ -package sbt - -import scala.tools.nsc.{GenericRunnerCommand, Interpreter, InterpreterLoop, ObjectRunner, Settings} -import scala.tools.nsc.interpreter.InteractiveReader -import scala.tools.nsc.reporters.Reporter -import scala.tools.nsc.util.ClassPath - -/** This module is an interface to starting the scala interpreter or runner.*/ -object ProjectConsole -{ - /** Create a settings object and execute the provided function if the settings are created ok.*/ - private def createSettings(log: Logger)(f: Settings => Option[String]) = - { - val command = new GenericRunnerCommand(Nil, message => log.error(message)) - if(command.ok) - f(command.settings) - else - Some(command.usageMsg) - } - - /** Starts a Scala interpreter session with 'project' bound to the value 'current' in the console - * and the following two lines executed: - * import sbt._ - * import current._ - */ - def apply(project: Project): Option[String] = - { - import project.log - createSettings(log) { interpreterSettings => - createSettings(log) { compilerSettings => - log.info("Starting scala interpreter with project definition " + project.name + " ...") - log.info("") - Control.trapUnit("Error during session: ", log) - { - JLine.withJLine { - val loop = new ProjectInterpreterLoop(compilerSettings, project) - executeTrapExit(loop.main(interpreterSettings), log) - } - } - }} - } - /** A custom InterpreterLoop with the purpose of creating an interpreter with Project 'project' bound to the value 'current', - * and the following three lines interpreted: - * import sbt._ - * import Process._ - * import current._. - * To do this, - * 1) The compiler uses a different settings instance: 'compilerSettings', which will have its classpath set to include - * the Scala compiler and library jars and the classpath used to compile the project. - * 2) The parent class loader for the interpreter is the loader that loaded the project, so that the project can be bound to a variable - * in the interpreter. - */ - private class ProjectInterpreterLoop(compilerSettings: Settings, project: Project) extends InterpreterLoop - { - override def createInterpreter() - { - val projectLoader = project.getClass.getClassLoader - val classpath = Project.getProjectClasspath(project) - val fullClasspath = classpath.get ++ Path.fromFiles(project.info.app.scalaProvider.jars) - compilerSettings.classpath.value = Path.makeString(fullClasspath) - project.log.debug(" console-project classpath:\n\t" + fullClasspath.mkString("\n\t")) - - in = InteractiveReader.createDefault() - interpreter = new Interpreter(settings) - { - override protected def parentClassLoader = projectLoader - override protected def newCompiler(settings: Settings, reporter: Reporter) = super.newCompiler(compilerSettings, reporter) - } - interpreter.setContextClassLoader() - interpreter.bind("current", project.getClass.getName, project) - interpreter.interpret("import sbt._") - interpreter.interpret("import Process._") - interpreter.interpret("import current._") - } - } -} diff --git a/sbt_pending/src/main/scala/sbt/ProjectInfo.scala b/sbt_pending/src/main/scala/sbt/ProjectInfo.scala deleted file mode 100644 index f2c889dbf..000000000 --- a/sbt_pending/src/main/scala/sbt/ProjectInfo.scala +++ /dev/null @@ -1,140 +0,0 @@ -/* sbt -- Simple Build Tool - * Copyright 2008 Mark Harrah - */ -package sbt - -import java.io.File -import xsbti.{AppProvider, ScalaProvider} -import FileUtilities._ - -/** Represents the minimal information necessary to construct a Project. -* -* `projectDirectory` is the base directory for the project (not the root project directory) -* `dependencies` are the Projects that this Project depends on. -* `parent` is the parent Project, or None if this is the root project. -* `log` is the Logger to use as a base for the default project Logger. -* `buildScalaVersion` contains the explicitly requested Scala version to use for building (as when using `+` or `++`) or None if the normal version should be used. -*/ -final case class ProjectInfo(projectDirectory: File, dependencies: Iterable[Project], parent: Option[Project]) - (log: Logger, val app: AppProvider, val buildScalaVersion: Option[String]) extends NotNull -{ - /** The version of Scala running sbt.*/ - def definitionScalaVersion = app.scalaProvider.version - /** The launcher instance that booted sbt.*/ - def launcher = app.scalaProvider.launcher - - val logger = log - /** The base path for the project, preserving information to the root project directory.*/ - val projectPath: Path = - { - val toRoot = parent.flatMap(p => Path.relativize(p.info.projectPath, projectDirectory)) - new ProjectDirectory(projectDirectory, toRoot) - } - /** The path to build information. The current location is `project/`. - * Note: The directory used to be `metadata/`, hence the name of the constant in the implementation. - * Note 2: Although it is called builderPath, it is not the path to the builder definition, which is `builderProjectPath`*/ - val builderPath = projectPath / ProjectInfo.MetadataDirectoryName - /** The boot directory contains the jars needed for building the project, including Scala, sbt, processors and dependencies of these.*/ - def bootPath = builderPath / Project.BootDirectoryName - /** The path to the build definition project. - * Currently, this is 'project/build'. */ - def builderProjectPath = builderPath / Project.BuilderProjectDirectoryName - def builderProjectOutputPath = builderProjectPath / Project.DefaultOutputDirectoryName - /** The path to the plugin definition project. This declares the plugins to use for the build definition.*/ - def pluginsPath = builderPath / Project.PluginProjectDirectoryName - def pluginsOutputPath = pluginsPath / Project.DefaultOutputDirectoryName - /** The path to which the source code for plugins are extracted.*/ - def pluginsManagedSourcePath = pluginsPath / BasicDependencyPaths.DefaultManagedSourceDirectoryName - /** The path to which plugins are retrieved.*/ - def pluginsManagedDependencyPath = pluginsPath / BasicDependencyPaths.DefaultManagedDirectoryName - - /** The classpath containing all jars comprising sbt, except for the launcher.*/ - def sbtClasspath = Path.finder(app.mainClasspath) -} - -private[sbt] sealed trait SetupResult extends NotNull -private[sbt] final object SetupDeclined extends SetupResult -private[sbt] final class SetupError(val message: String) extends SetupResult -private[sbt] final object AlreadySetup extends SetupResult -private[sbt] final class SetupInfo(val name: String, val version: Option[Version], val organization: Option[String], val initializeDirectories: Boolean) extends SetupResult - -object ProjectInfo -{ - val MetadataDirectoryName = "project" - private val DefaultOrganization = "empty" - - def setup(info: ProjectInfo, log: Logger): SetupResult = - { - val builderDirectory = info.builderPath.asFile - if(builderDirectory.exists) - { - if(builderDirectory.isDirectory) - AlreadySetup - else - new SetupError("'" + builderDirectory.getAbsolutePath + "' is not a directory.") - } - else - setupProject(info.projectDirectory, log) - } - private def setupProject(projectDirectory: File, log: Logger): SetupResult = - { - if(confirmPrompt("No project found. Create new project?", false)) - { - val name = trim(SimpleReader.readLine("Project Name: ")) - if(name.isEmpty) - new SetupError("Project not created: no name specified.") - else - { - val organization = - { - val org = trim(SimpleReader.readLine("Organization [" + DefaultOrganization + "]: ")) - if(org.isEmpty) - DefaultOrganization - else - org - } - readVersion(projectDirectory, log) match - { - case None => new SetupError("Project not created: no version specified.") - case Some(version) => - if(verifyCreateProject(name, version, organization)) - new SetupInfo(name, Some(version), Some(organization), true) - else - SetupDeclined - } - } - } - else - SetupDeclined - } - private def verifyCreateProject(name: String, version: Version, organization: String): Boolean = - confirmPrompt("Create new project " + name + " " + version + " with organization " + organization +" ?", true) - - private def confirmPrompt(question: String, defaultYes: Boolean) = - { - val choices = if(defaultYes) " (Y/n) " else " (y/N) " - val answer = trim(SimpleReader.readLine(question + choices)) - val yes = "y" :: "yes" :: (if(defaultYes) List("") else Nil) - yes.contains(answer.toLowerCase) - } - - private def readVersion(projectDirectory: File, log: Logger): Option[Version] = - { - val version = trim(SimpleReader.readLine("Version: ")) - if(version.isEmpty) - None - else - { - Version.fromString(version) match - { - case Left(errorMessage) => - { - log.error("Invalid version: " + errorMessage) - readVersion(projectDirectory, log) - } - case Right(v) => Some(v) - } - } - } - private def trim(s: Option[String]) = s.getOrElse("") -} \ No newline at end of file diff --git a/sbt_pending/src/main/scala/sbt/ProjectPaths.scala b/sbt_pending/src/main/scala/sbt/ProjectPaths.scala deleted file mode 100644 index 2752b7008..000000000 --- a/sbt_pending/src/main/scala/sbt/ProjectPaths.scala +++ /dev/null @@ -1,302 +0,0 @@ -/* sbt -- Simple Build Tool - * Copyright 2008, 2009 Mark Harrah - */ -package sbt - -trait PackagePaths extends NotNull -{ - def jarPath: Path - def packageTestJar: Path - def packageDocsJar: Path - def packageSrcJar: Path - def packageTestSrcJar: Path - def packageProjectZip: Path -} -/** These are the paths required by BasicScalaProject.*/ -trait ScalaPaths extends PackagePaths -{ - /** A PathFinder that selects all main sources.*/ - def mainSources: PathFinder - /** A PathFinder that selects all test sources.*/ - def testSources: PathFinder - def mainSourceRoots: PathFinder - def testSourceRoots: PathFinder - /** A PathFinder that selects all main resources.*/ - def mainResources: PathFinder - /** A PathFinder that selects all test resources. */ - def testResources: PathFinder - - def mainCompilePath: Path - def testCompilePath: Path - def mainAnalysisPath: Path - def testAnalysisPath: Path - def mainDocPath: Path - def testDocPath: Path - def graphSourcesPath: Path - def graphPackagesPath: Path - def mainResourcesOutputPath: Path - def testResourcesOutputPath: Path - - /** A PathFinder that selects all the classes compiled from the main sources.*/ - def mainClasses: PathFinder - /** A PathFinder that selects all the classes compiled from the test sources.*/ - def testClasses: PathFinder - - /** Declares all paths to be packaged by the package action.*/ - def packagePaths: PathFinder - /** Declares all paths to be packaged by the package-test action.*/ - def packageTestPaths: PathFinder - /** Declares all sources to be packaged by the package-src action.*/ - def packageSourcePaths: PathFinder - /** Declares all sources to be packaged by the package-test-src action.*/ - def packageTestSourcePaths: PathFinder - /** Declares all paths to be packaged by the package-project action.*/ - def packageProjectPaths: PathFinder - - /** These are the directories that are created when a user makes a new project from sbt.*/ - protected def directoriesToCreate: List[Path] - /** The directories to which a project writes are listed here and is used - * to check a project and its dependencies for collisions.*/ - def outputDirectories: Iterable[Path] - - def artifactBaseName: String -} - -trait BasicScalaPaths extends Project with ScalaPaths -{ - def mainResourcesPath: PathFinder - def testResourcesPath: PathFinder - def managedDependencyPath: Path - def managedDependencyRootPath: Path - def dependencyPath: Path - - protected def sources(base: PathFinder) = descendents(base, sourceExtensions) - protected def sourceExtensions = "*.scala" | "*.java" - - def mainSources = - { - val normal = sources(mainSourceRoots) - if(scratch) - normal +++ (info.projectPath * sourceExtensions) - else - normal - } - def testSources = sources(testSourceRoots) - - def mainResources = descendents(mainResourcesPath ###, "*") - def testResources = descendents(testResourcesPath ###, "*") - - def mainClasses = (mainCompilePath ###) ** "*.class" - def testClasses = (testCompilePath ###) ** "*.class" - - def packagePaths = mainClasses +++ mainResources - def packageTestPaths = testClasses +++ testResources - def packageSourcePaths = mainSources +++ mainResources - def packageTestSourcePaths = testSources +++ testResources - def packageProjectPaths = descendents( (info.projectPath ###), "*") --- (packageProjectExcludes ** "*") - protected def packageProjectExcludes: PathFinder = - outputRootPath +++ managedDependencyRootPath +++ - info.bootPath +++ info.builderProjectOutputPath +++ - info.pluginsOutputPath +++ info.pluginsManagedSourcePath +++ info.pluginsManagedDependencyPath - - override def outputDirectories = outputPath :: managedDependencyPath :: Nil -} - -trait MavenStyleScalaPaths extends BasicScalaPaths with BasicPackagePaths -{ - import BasicProjectPaths._ - - def outputPath: Path - - def sourceDirectoryName = DefaultSourceDirectoryName - def mainDirectoryName = DefaultMainDirectoryName - def scalaDirectoryName = DefaultScalaDirectoryName - def javaDirectoryName = DefaultJavaDirectoryName - def resourcesDirectoryName = DefaultResourcesDirectoryName - def testDirectoryName = DefaultTestDirectoryName - def mainCompileDirectoryName = DefaultMainCompileDirectoryName - def testCompileDirectoryName = DefaultTestCompileDirectoryName - def docDirectoryName = DefaultDocDirectoryName - def apiDirectoryName = DefaultAPIDirectoryName - def graphDirectoryName = DefaultGraphDirectoryName - def mainAnalysisDirectoryName = DefaultMainAnalysisDirectoryName - def testAnalysisDirectoryName = DefaultTestAnalysisDirectoryName - def mainResourcesOutputDirectoryName = DefautMainResourcesOutputDirectoryName - def testResourcesOutputDirectoryName = DefautTestResourcesOutputDirectoryName - - def sourcePath = path(sourceDirectoryName) - - def mainSourcePath = sourcePath / mainDirectoryName - def mainScalaSourcePath = mainSourcePath / scalaDirectoryName - def mainJavaSourcePath = mainSourcePath / javaDirectoryName - def mainResourcesPath = mainSourcePath / resourcesDirectoryName - def mainDocPath = docPath / mainDirectoryName / apiDirectoryName - def mainCompilePath = outputPath / mainCompileDirectoryName - def mainResourcesOutputPath = outputPath / mainResourcesOutputDirectoryName - def mainAnalysisPath = outputPath / mainAnalysisDirectoryName - - def testSourcePath = sourcePath / testDirectoryName - def testJavaSourcePath = testSourcePath / javaDirectoryName - def testScalaSourcePath = testSourcePath / scalaDirectoryName - def testResourcesPath = testSourcePath / resourcesDirectoryName - def testDocPath = docPath / testDirectoryName / apiDirectoryName - def testCompilePath = outputPath / testCompileDirectoryName - def testResourcesOutputPath = outputPath / testResourcesOutputDirectoryName - def testAnalysisPath = outputPath / testAnalysisDirectoryName - - def docPath = outputPath / docDirectoryName - def graphPath = outputPath / graphDirectoryName - def graphPackagesPath = graphPath / "packages" - def graphSourcesPath = graphPath / "sources" - - /** These are the directories that are created when a user makes a new project from sbt.*/ - protected def directoriesToCreate: List[Path] = - dependencyPath :: - mainScalaSourcePath :: - mainResourcesPath :: - testScalaSourcePath :: - testResourcesPath :: - Nil - - def mainSourceRoots = (mainJavaSourcePath###) +++ (mainScalaSourcePath##) - def testSourceRoots = (testJavaSourcePath###) +++ (testScalaSourcePath##) -} - -trait BasicPackagePaths extends ScalaPaths with PackagePaths -{ - def outputPath: Path - - def defaultJarBaseName: String = artifactBaseName - def defaultJarName = defaultJarBaseName + ".jar" - def jarPath = outputPath / defaultJarName - def packageTestJar = defaultJarPath("-test.jar") - def packageDocsJar = defaultJarPath("-docs.jar") - def packageSrcJar= defaultJarPath("-src.jar") - def packageTestSrcJar = defaultJarPath("-test-src.jar") - def packageProjectZip = defaultJarPath("-project.zip") - def defaultJarPath(extension: String) = outputPath / (artifactBaseName + extension) -} - -object BasicProjectPaths -{ - val DefaultSourceDirectoryName = "src" - val DefaultMainCompileDirectoryName = "classes" - val DefaultTestCompileDirectoryName = "test-classes" - val DefaultDocDirectoryName = "doc" - val DefaultAPIDirectoryName = "api" - val DefaultGraphDirectoryName = "graph" - val DefaultMainAnalysisDirectoryName = "analysis" - val DefaultTestAnalysisDirectoryName = "test-analysis" - val DefautMainResourcesOutputDirectoryName = "resources" - val DefautTestResourcesOutputDirectoryName = "test-resources" - - val DefaultMainDirectoryName = "main" - val DefaultScalaDirectoryName = "scala" - val DefaultJavaDirectoryName = "java" - val DefaultResourcesDirectoryName = "resources" - val DefaultTestDirectoryName = "test" -} - -trait WebScalaPaths extends ScalaPaths -{ - def temporaryWarPath: Path - def webappResources: PathFinder - def jettyContextPath: String - def warPath: Path -} -trait MavenStyleWebScalaPaths extends WebScalaPaths with MavenStyleScalaPaths -{ - import WebProjectPaths._ - def temporaryWarPath = outputPath / webappDirectoryName - def webappPath = mainSourcePath / webappDirectoryName - def webappDirectoryName = DefaultWebappDirectoryName - def jettyContextPath = DefaultJettyContextPath - def defaultWarName = defaultJarBaseName + ".war" - def warPath = outputPath / defaultWarName - /** Additional files to include in the web application. */ - protected def extraWebappFiles: PathFinder = Path.emptyPathFinder - def webappResources = descendents(webappPath ###, "*") +++ extraWebappFiles -} -object WebProjectPaths -{ - val DefaultWebappDirectoryName = "webapp" - val DefaultJettyContextPath = "/" -} - -/** Defines default paths for a webstart project. It directly extends WebstartOptions to make -* it easy to implement and override webstart options in the common case of one webstartTask per -* project.*/ -trait WebstartPaths extends ScalaPaths -{ - import WebstartPaths._ - - def outputPath: Path - def jnlpPath: Path - - def webstartOutputDirectory = outputPath / webstartDirectoryName - - def jnlpFile = webstartOutputDirectory / jnlpFileName - def webstartLibDirectory = webstartOutputDirectory / webstartLibName - def webstartZip: Option[Path] = Some(outputPath / webstartZipName) - def jnlpResourcesPath = jnlpPath / BasicProjectPaths.DefaultResourcesDirectoryName - - def webstartLibName = DefaultWebstartLibName - def webstartDirectoryName = DefaultWebstartDirectoryName - - def webstartZipName: String - def jnlpFileName: String -} -object WebstartPaths -{ - val DefaultWebstartDirectoryName = "webstart" - val DefaultJnlpName = "jnlp" - val DefaultWebstartLibName = "lib" -} -trait MavenStyleWebstartPaths extends WebstartPaths with MavenStyleScalaPaths -{ - import WebstartPaths._ - def jnlpPath = mainSourcePath / DefaultJnlpName - def webstartMainJar = jarPath - def jnlpFileName = DefaultJnlpFileName - def webstartZipName = artifactBaseName + ".zip" - def DefaultJnlpFileName = artifactBaseName + ".jnlp" -} - -trait IntegrationTestPaths extends NotNull -{ - def integrationTestSources: PathFinder - def integrationTestScalaSourceRoots: PathFinder - def integrationTestResourcesPath: Path - - def integrationTestCompilePath: Path - def integrationTestAnalysisPath: Path -} -trait BasicIntegrationTestPaths extends IntegrationTestPaths -{ - def integrationTestScalaSourcePath: Path - def integrationTestScalaSourceRoots: PathFinder = integrationTestScalaSourcePath - def integrationTestSources = sources(integrationTestScalaSourceRoots) - protected def sources(base: PathFinder): PathFinder -} -trait MavenStyleIntegrationTestPaths extends BasicIntegrationTestPaths with MavenStyleScalaPaths -{ - import IntegrationTestPaths._ - - def integrationTestDirectoryName = DefaultIntegrationTestDirectoryName - def integrationTestCompileDirectoryName = DefaultIntegrationTestCompileDirectoryName - def integrationTestAnalysisDirectoryName = DefaultIntegrationTestAnalysisDirectoryName - - def integrationTestSourcePath = sourcePath / integrationTestDirectoryName - def integrationTestScalaSourcePath = integrationTestSourcePath / scalaDirectoryName - def integrationTestResourcesPath = integrationTestSourcePath / resourcesDirectoryName - - def integrationTestCompilePath = outputPath / integrationTestCompileDirectoryName - def integrationTestAnalysisPath = outputPath / integrationTestAnalysisDirectoryName -} - -object IntegrationTestPaths -{ - val DefaultIntegrationTestDirectoryName = "it" - val DefaultIntegrationTestCompileDirectoryName = "it-classes" - val DefaultIntegrationTestAnalysisDirectoryName = "it-analysis" -} \ No newline at end of file diff --git a/sbt_pending/src/main/scala/sbt/TaskManager.scala b/sbt_pending/src/main/scala/sbt/TaskManager.scala deleted file mode 100644 index 67ba599b2..000000000 --- a/sbt_pending/src/main/scala/sbt/TaskManager.scala +++ /dev/null @@ -1,104 +0,0 @@ -/* sbt -- Simple Build Tool - * Copyright 2008 David MacIver, Mark Harrah - */ -package sbt - -import TaskManager._ - -trait Described extends NotNull -{ - def description: Option[String] -} -trait TaskManager{ - type ManagerType >: this.type <: TaskManager - type ManagedTask >: Task <: TaskManager#Task with Dag[ManagedTask] - /** Creates a task that executes the given action when invoked.*/ - def task(action : => Option[String]) = new Task(None, Nil, false, action) - /** An interactive task is one that is not executed across all dependent projects when - * it is called directly. The dependencies of the task are still invoked across all dependent - * projects, however. */ - def interactiveTask(action: => Option[String]) = new Task(None, Nil, true, action) - /** Creates a method task that executes the given action when invoked. */ - def task(action: Array[String] => ManagedTask) = new MethodTask(None, action, Nil) - - def taskName(t: Task): Option[String] - final def taskNameString(task: Task): String = taskName(task).getOrElse(UnnamedName) - - /** A method task is an action that has parameters. Note that it is not a Task, though, - * because it requires arguments to perform its work. It therefore cannot be a dependency of - * a Task..*/ - final class MethodTask(val description: Option[String], action: Array[String] => ManagedTask, getCompletions: => Seq[String]) extends Described - { - /** Creates a new method task, identical to this method task, except with thE[String]e given description.*/ - def describedAs(description : String) = new MethodTask(Some(description), action, getCompletions) - /** Invokes this method task with the given arguments.*/ - def apply(arguments: Array[String]) = action(arguments) - def manager: ManagerType = TaskManager.this - def completeWith(add: => Seq[String]) = new MethodTask(description, action, add) - def completions = getCompletions - } - - sealed class Task(val explicitName: Option[String], val description : Option[String], val dependencies : List[ManagedTask], - val interactive: Boolean, action : => Option[String]) extends Dag[ManagedTask] with Described - { - def this(description : Option[String], dependencies : List[ManagedTask], interactive: Boolean, action : => Option[String]) = - this(None, description, dependencies, interactive, action) - checkTaskDependencies(dependencies) - def manager: ManagerType = TaskManager.this - def name = explicitName.getOrElse(taskNameString(this)) - private[sbt] def implicitName = taskName(this) - def named(name: String) = construct(Some(name), description,dependencies, interactive, action) - override def toString = "Task " + name - - /** Creates a new task, identical to this task, except with the additional dependencies specified.*/ - def dependsOn(tasks : ManagedTask*) = setDependencies(tasks.toList ::: dependencies) - private[sbt] def setDependencies(dependencyList: List[ManagedTask]) = - { - checkTaskDependencies(dependencyList) - construct(explicitName, description, dependencyList, interactive, action) - } - /** Creates a new task, identical to this task, except with the given description.*/ - def describedAs(description : String) = construct(explicitName, Some(description), dependencies, interactive, action); - private[sbt] def invoke = action; - - final def setInteractive = construct(explicitName, description, dependencies, true, action) - final def run = runSequentially(topologicalSort) - final def runDependenciesOnly = runSequentially(topologicalSort.dropRight(1)) - private def runSequentially(tasks: List[ManagedTask]) = Control.lazyFold(tasks)(_.invoke) - - def &&(that : Task) = - construct(explicitName, None, dependencies ::: that.dependencies, interactive || that.interactive, this.invoke.orElse(that.invoke)) - - protected def construct(explicitName: Option[String], description: Option[String], dependencies: List[ManagedTask], interactive: Boolean, - action : => Option[String]): Task = new Task(explicitName, description, dependencies, interactive, action) - } - final class CompoundTask private (explicitName: Option[String], description : Option[String], dependencies : List[ManagedTask], interactive: Boolean, - action : => Option[String], createWork: => SubWork[Project#Task]) extends Task(description, dependencies, interactive, action) - with CompoundWork[Project#Task] - { - def this(createWork: => SubWork[Project#Task]) = this(None, None, Nil, false, None, createWork) - override protected def construct(explicitName: Option[String], description: Option[String], dependencies: List[ManagedTask], - interactive: Boolean, action : => Option[String]) = new CompoundTask(explicitName, description, dependencies, interactive, action, createWork) - def work = createWork - } - def dynamic(createTask: => Project#Task) = new CompoundTask(SubWork[Project#Task](checkDynamic(createTask))) - /** Verifies that the given dynamically created task does not depend on any statically defined tasks. - * Returns the task if it is valid.*/ - private def checkDynamic(task: Project#Task) = - { - for(t <- task.topologicalSort if !(t eq task); staticName <- t.implicitName) - error("Dynamic task " + task.name + " depends on static task " + staticName) - task - } - private def checkTaskDependencies(dependencyList: List[ManagedTask]) - { - val nullDependencyIndex = dependencyList.findIndexOf(_ == null) - require(nullDependencyIndex < 0, "Dependency (at index " + nullDependencyIndex + ") is null. This may be an initialization issue or a circular dependency.") - val interactiveDependencyIndex = dependencyList.findIndexOf(_.interactive) - require(interactiveDependencyIndex < 0, "Dependency (at index " + interactiveDependencyIndex + ") is interactive. Interactive tasks cannot be dependencies.") - } -} -object TaskManager -{ - val UnnamedName = "" -} \ No newline at end of file diff --git a/sbt_pending/src/main/scala/sbt/impl/CommandParser.scala b/sbt_pending/src/main/scala/sbt/impl/CommandParser.scala deleted file mode 100644 index a2fab873d..000000000 --- a/sbt_pending/src/main/scala/sbt/impl/CommandParser.scala +++ /dev/null @@ -1,61 +0,0 @@ -/* sbt -- Simple Build Tool - * Copyright 2009 Mark Harrah - */ -package sbt.impl - -import scala.util.parsing.combinator.Parsers -import scala.util.parsing.input.CharSequenceReader -import scala.util.parsing.input.CharArrayReader.EofCh - -/** Parses a command of the form: -* identifier argument* -* where argument may be quoted to include spaces and -* quotes and backslashes should be escaped. -*/ -object Arguments -{ - def apply(commandString: String): Either[String, (String, List[String])] = - CommandParser.parse(commandString) -} - -/* Most of the complexity is for error handling.*/ -private[sbt] object CommandParser extends Parsers -{ - type Elem = Char - def parse(commandString: String): Either[String, (String, List[String])] = - { - command(new CharSequenceReader(commandString.trim, 0)) match - { - case Success(id ~ args, next) => Right((id, args)) - case err: NoSuccess => - { - val pos = err.next.pos - Left("Could not parse command: (" + pos.line + "," + pos.column + "): " + err.msg) - } - } - } - def command = phrase(identifier ~! (argument*)) - def identifier = unquoted | err("Expected identifier") - def argument = ( (whitespaceChar+) ~> (unquoted | quoted) ) - - def unquoted: Parser[String] = ((unquotedChar ~! (unquotedMainChar*)) ^^ { case a ~ tail => (a :: tail).mkString("") }) - def quoted: Parser[String] = quote ~> quotedChars <~ (quote | err("Missing closing quote character")) - - def quotedChars: Parser[String] = (escape | nonescapeChar)* - def escape: Parser[Char] = backslash ~> (escapeChar | err("Illegal escape")) - def escapeChar: Parser[Char] = quote | backslash - def nonescapeChar: Parser[Char] = elem("", ch => !isEscapeChar(ch) && ch != EofCh) - def unquotedChar: Parser[Char] = elem("", ch => !isEscapeChar(ch) && !Character.isWhitespace(ch) && ch != EofCh) - def unquotedMainChar: Parser[Char] = unquotedChar | (errorIfEscape ~> failure("")) - - private def errorIfEscape = (not(quote) | err("Unexpected quote character")) ~> - (not(backslash) | err("Escape sequences can only occur in a quoted argument")) - - private def isEscapeChar(ch: Char) = ch == '\\' || ch == '"' - - def quote: Parser[Char] = '"' - def backslash: Parser[Char] = '\\' - def whitespaceChar: Parser[Char] = elem("whitespace", ch => Character.isWhitespace(ch)) - - private implicit def toString(p: Parser[List[Char]]): Parser[String] = p ^^ {_ mkString "" } -} \ No newline at end of file diff --git a/sbt_pending/src/main/scala/sbt/processor/CommandRunner.scala b/sbt_pending/src/main/scala/sbt/processor/CommandRunner.scala deleted file mode 100644 index 3428036d9..000000000 --- a/sbt_pending/src/main/scala/sbt/processor/CommandRunner.scala +++ /dev/null @@ -1,28 +0,0 @@ -/* sbt -- Simple Build Tool - * Copyright 2010 Mark Harrah - */ -package sbt.processor - -/** Parses and executes a command (connects a parser to a runner). */ -class CommandRunner(parser: CommandParsing, execute: Executing) -{ - def apply(processorCommand: String): Unit = - parser.parseCommand(processorCommand) match - { - case Left(err) => throw new ProcessorException(err) - case Right(command) => execute(command) - } -} -object CommandRunner -{ - /** Convenience method for constructing a CommandRunner with the minimal information required.*/ - def apply(manager: Manager, defParser: DefinitionParser, prefix: String, log: Logger): CommandRunner = - { - val parser = new CommandParser(defaultErrorMessage(prefix), defParser) - val info = new InfoImpl(manager, prefix, parser, System.out.println) - val execute = new Execute(manager, info, log) - new CommandRunner(parser, execute) - } - def defaultErrorMessage(prefix: String) = - "Invalid processor command. Run " + prefix + "help to see valid commands." -} \ No newline at end of file diff --git a/sbt_pending/src/main/scala/sbt/processor/Execute.scala b/sbt_pending/src/main/scala/sbt/processor/Execute.scala deleted file mode 100644 index 5b86b8564..000000000 --- a/sbt_pending/src/main/scala/sbt/processor/Execute.scala +++ /dev/null @@ -1,24 +0,0 @@ -/* sbt -- Simple Build Tool - * Copyright 2010 Mark Harrah - */ -package sbt.processor - -/** Executes a parsed command. */ -class Execute(manager: Manager, info: Info, log: Logger) extends Executing -{ - def apply(command: Command): Unit = - command match - { - case dr: DefineRepository => - manager.defineRepository(dr.repo) - log.info("Defined new processor repository '" + dr.repo + "'") - case dp: DefineProcessor => - manager.defineProcessor(dp.pdef) - log.info("Defined new processor '" + dp.pdef + "'") - case rd: RemoveDefinition => - val removed = manager.removeDefinition(rd.label) - log.info("Removed '" + removed + "'") - case Help => info.help() - case Show => info.show() - } -} \ No newline at end of file diff --git a/sbt_pending/src/main/scala/sbt/processor/Handler.scala b/sbt_pending/src/main/scala/sbt/processor/Handler.scala deleted file mode 100644 index fc32fb8d0..000000000 --- a/sbt_pending/src/main/scala/sbt/processor/Handler.scala +++ /dev/null @@ -1,35 +0,0 @@ -/* sbt -- Simple Build Tool - * Copyright 2010 Mark Harrah - */ -package sbt.processor - -class Handler(baseProject: Project) extends NotNull -{ - def unapply(line: String): Option[ParsedProcessor] = - line.split("""\s+""", 2) match - { - case Array(label @ GetProcessor(processor), args @ _*) => Some( new ParsedProcessor(label, processor, args.mkString) ) - case _ => None - } - private object GetProcessor - { - def unapply(name: String): Option[Processor] = - manager.processorDefinition(name).flatMap(manager.processor) - } - - def lock = baseProject.info.launcher.globalLock - - lazy val scalaVersion = baseProject.defScalaVersion.value - lazy val base = baseProject.info.bootPath / ("scala-" + scalaVersion) / "sbt-processors" - lazy val persistBase = Path.userHome / ".ivy2" / "sbt" - - def retrieveLockFile = base / lockName - def persistLockFile = persistBase / lockName - def lockName = "processors.lock" - def definitionsFile = persistBase / "processors.properties" - def files = new ManagerFiles(base.asFile, retrieveLockFile.asFile, definitionsFile.asFile) - - lazy val defParser = new DefinitionParser - lazy val manager = new ManagerImpl(files, scalaVersion, new Persist(lock, persistLockFile.asFile, defParser), baseProject.offline.value, baseProject.log) -} -class ParsedProcessor(val label: String, val processor: Processor, val arguments: String) extends NotNull \ No newline at end of file diff --git a/sbt_pending/src/main/scala/sbt/processor/Info.scala b/sbt_pending/src/main/scala/sbt/processor/Info.scala deleted file mode 100644 index cc84f6e33..000000000 --- a/sbt_pending/src/main/scala/sbt/processor/Info.scala +++ /dev/null @@ -1,26 +0,0 @@ -/* sbt -- Simple Build Tool - * Copyright 2010 Mark Harrah - */ -package sbt.processor - -class InfoImpl(manager: Manager, prefix: String, parser: CommandParser, print: String => Unit) extends Info -{ - def show() - { - print("Processors:\n\t" + manager.processors.values.mkString("\n\t")) - print("\nProcessor repositories:\n\t" + manager.repositories.values.mkString("\n\t")) - } - def help() - { - import parser.{ShowCommand, HelpCommand, ProcessorCommand, RemoveCommand, RepositoryCommand} - val usage = - (HelpCommand -> "Display this help message") :: - (ShowCommand -> "Display defined processors and repositories") :: - (ProcessorCommand -> "Define 'label' to be the processor with the given ID") :: - (RepositoryCommand -> "Add a repository for searching for processors") :: - (RemoveCommand -> "Undefine the repository or processor with the given 'label'") :: - Nil - - print("Processor management commands:\n " + (usage.map{ case (c,d) => prefix + "" + c + " " + d}).mkString("\n ")) - } -} \ No newline at end of file diff --git a/sbt_pending/src/main/scala/sbt/processor/Loader.scala b/sbt_pending/src/main/scala/sbt/processor/Loader.scala deleted file mode 100644 index 46f6a9096..000000000 --- a/sbt_pending/src/main/scala/sbt/processor/Loader.scala +++ /dev/null @@ -1,41 +0,0 @@ -/* sbt -- Simple Build Tool - * Copyright 2010 Mark Harrah - */ -package sbt.processor - -import java.io.File -import java.net.{URL, URLClassLoader} -import xsbt.FileUtilities.read -import xsbt.OpenResource.urlInputStream -import xsbt.Paths._ -import xsbt.GlobFilter._ - -import ProcessorException.error - -class Loader extends NotNull -{ - def classNameResource = "sbt.processor" - def getProcessor(directory: File): Either[Throwable, Processor] = getProcessor( getLoader(directory) ) - private def getProcessor(loader: ClassLoader): Either[Throwable, Processor] = - { - val resource = loader.getResource(classNameResource) - if(resource eq null) Left(new ProcessorException("Processor existed but did not contain '" + classNameResource + "' descriptor.")) - else loadProcessor(loader, resource) - } - private def loadProcessor(loader: ClassLoader, resource : URL): Either[Throwable, Processor] = - try { Right(loadProcessor(loader, className(resource))) } - catch { case e: Exception => Left(e) } - - private def loadProcessor(loader: ClassLoader, className: String): Processor = - { - val processor = Class.forName(className, true, loader).newInstance - classOf[Processor].cast(processor) - } - private def className(resource: URL): String = urlInputStream(resource) { in => read(in).trim } - private def getLoader(dir: File) = - { - val jars = dir ** "*.jar" - val jarURLs = jars.files.toArray[File].map(_.toURI.toURL) - new URLClassLoader(jarURLs, getClass.getClassLoader) - } -} \ No newline at end of file diff --git a/sbt_pending/src/main/scala/sbt/processor/Manager.scala b/sbt_pending/src/main/scala/sbt/processor/Manager.scala deleted file mode 100644 index fd46c128e..000000000 --- a/sbt_pending/src/main/scala/sbt/processor/Manager.scala +++ /dev/null @@ -1,84 +0,0 @@ -/* sbt -- Simple Build Tool - * Copyright 2010 Mark Harrah - */ -package sbt.processor - -import java.io.File -import xsbt.Paths._ -import ProcessorException.error - -/** Files needed by ManagerImpl. -* `retrieveBaseDirectory` is the directory that processors are retrieved under. -* `retrieveLockFile` is used to synchronize access to that directory. -* `definitionsFile` is the file to save repository and processor definitions to. It is usually per-user instead of per-project.*/ -class ManagerFiles(val retrieveBaseDirectory: File, val retrieveLockFile: File, val definitionsFile: File) - -class ManagerImpl(files: ManagerFiles, scalaVersion: String, persist: Persist, localOnly: Boolean, log: Logger) extends Manager -{ - import files._ - - def processorDefinition(label: String): Option[ProcessorDefinition] = processors.get(label) - def processor(pdef: ProcessorDefinition): Option[Processor] = - { - def tryProcessor: Either[Throwable, Processor] = - (new Loader).getProcessor( retrieveDirectory(pdef) ) - - // try to load the processor. It will succeed here if the processor has already been retrieved - tryProcessor.left.flatMap { _ => - // if it hasn't been retrieved, retrieve the processor and its dependencies - retrieveProcessor(pdef, localOnly) - // try to load the processor now that it has been retrieved - tryProcessor.left.map { // if that fails, log a warning - case p: ProcessorException => log.warn(p.getMessage) - case t => log.trace(t); log.warn(t.toString) - } - }.right.toOption - } - def defineProcessor(p: ProcessorDefinition) - { - checkExisting(p) - retrieveProcessor(p, localOnly) - add(p) - } - def defineRepository(r: RepositoryDefinition) - { - checkExisting(r) - add(r) - } - def removeDefinition(label: String): Definition = - definitions.removeKey(label) match - { - case Some(removed) => - saveDefinitions() - removed - case None => error("Label '" + label + "' not defined.") - } - - private def retrieveProcessor(p: ProcessorDefinition, localOnly: Boolean): Unit = - { - val resolvers = repositories.values.toList.map(toResolver) - val module = p.toModuleID(scalaVersion) - ( new Retrieve(retrieveDirectory(p), module, persist.lock, retrieveLockFile, resolvers, log) ).retrieve(localOnly) - } - private def add(d: Definition) - { - definitions(d.label) = d - saveDefinitions() - } - - private lazy val definitions = loadDefinitions(definitionsFile) - def repositories = Map() ++ partialMap(definitions) { case (label, d: RepositoryDefinition) => (label, d) } - def processors = Map() ++ partialMap(definitions) { case (label, p: ProcessorDefinition) => (label, p) } - - private def checkExisting(p: Definition): Unit = definitions.get(p.label) map { d => error ("Label '" + p.label + "' already in use: " + d) } - private def partialMap[T,S](i: Iterable[T])(f: PartialFunction[T,S]) = i.filter(f.isDefinedAt).map(f) - private def toResolver(repo: RepositoryDefinition): Resolver = new MavenRepository(repo.label, repo.url) - - def retrieveDirectory(p: ProcessorDefinition) = retrieveBaseDirectory / p.group / p.module / p.rev - - private def saveDefinitions(): Unit = saveDefinitions(definitionsFile) - private def saveDefinitions(file: File): Unit = persist.save(file)(definitions.values.toList) - private def loadDefinitions(file: File): scala.collection.mutable.Map[String, Definition] = - scala.collection.mutable.HashMap( (if(file.exists) rawLoad(file) else Nil) : _*) - private def rawLoad(file: File): Seq[(String, Definition)] = persist.load(definitionsFile).map { d => (d.label, d) } -} \ No newline at end of file diff --git a/sbt_pending/src/main/scala/sbt/processor/Parser.scala b/sbt_pending/src/main/scala/sbt/processor/Parser.scala deleted file mode 100644 index 4d379f522..000000000 --- a/sbt_pending/src/main/scala/sbt/processor/Parser.scala +++ /dev/null @@ -1,50 +0,0 @@ -/* sbt -- Simple Build Tool - * Copyright 2010 Mark Harrah - */ -package sbt.processor - -/** Parses commands. `errorMessage` is the String used when a command is invalid. -* There is no detailed error reporting. -* Input Strings are assumed to be trimmed.*/ -class CommandParser(errorMessage: String, defParser: DefinitionParsing) extends CommandParsing -{ - def parseCommand(line: String): Either[String, Command] = - defParser.parseDefinition(line) match - { - case Some(p: ProcessorDefinition) => Right(new DefineProcessor(p)) - case Some(r: RepositoryDefinition) => Right(new DefineRepository(r)) - case None => parseOther(line) - } - - def parseOther(line: String) = - line match - { - case RemoveRegex(label) => Right(new RemoveDefinition(label)) - case HelpCommand | "" => Right(Help) - case ShowCommand => Right(Show) - case _ => Left(errorMessage) - } - - val ShowCommand = "show" - val HelpCommand = "help" - val ProcessorCommand = "