From 65fc0e0453a18017c0a995d172561f2dbb79f0d1 Mon Sep 17 00:00:00 2001 From: Mark Harrah Date: Sun, 16 Aug 2009 14:29:08 -0400 Subject: [PATCH] Initial xsbt commit --- cache/Cache.scala | 58 +++ cache/FileInfo.scala | 74 ++++ cache/HListCache.scala | 44 +++ cache/NoCache.scala | 19 + cache/SeparatedCache.scala | 80 ++++ cache/lib/sbinary-0.3-alpha.jar | Bin 0 -> 143178 bytes cache/src/test/scala/CacheTest.scala | 21 + ivy/ConvertResolver.scala | 100 +++++ ivy/CustomXmlParser.scala | 35 ++ ivy/Ivy.scala | 307 +++++++++++++++ ivy/IvyActions.scala | 138 +++++++ ivy/IvyConfigurations.scala | 33 ++ ivy/IvyInterface.scala | 360 ++++++++++++++++++ ivy/IvyLogger.scala | 54 +++ ivy/IvyScala.scala | 74 ++++ notes | 32 ++ project/build.properties | 7 + project/build/XSbt.scala | 35 ++ tasks/ParallelRunner.scala | 190 +++++++++ tasks/Task.scala | 145 +++++++ tasks/TaskListener.scala | 33 ++ tasks/TaskRunner.scala | 17 + tasks/TaskScheduler.scala | 243 ++++++++++++ tasks/src/test/scala/TListCompileTest.scala | 17 + tasks/src/test/scala/TaskRunnerCircular.scala | 63 +++ tasks/src/test/scala/TaskRunnerFork.scala | 32 ++ tasks/src/test/scala/TestRunner.scala | 52 +++ tasks/src/test/scala/TestRunnerCall.scala | 42 ++ tasks/src/test/scala/TestRunnerSort.scala | 43 +++ tasks/src/test/scala/checkResult.scala | 29 ++ util/classpath/ClassLoaders.scala | 43 +++ util/collection/HLists.scala | 15 + util/collection/TreeHashSet.scala | 22 ++ util/collection/lib/metascala-0.1.jar | Bin 0 -> 128005 bytes util/control/ErrorHandling.scala | 18 + util/io/Hash.scala | 76 ++++ util/io/OpenResource.scala | 109 ++++++ util/log/Logger.scala | 71 ++++ 38 files changed, 2731 insertions(+) create mode 100644 cache/Cache.scala create mode 100644 cache/FileInfo.scala create mode 100644 cache/HListCache.scala create mode 100644 cache/NoCache.scala create mode 100644 cache/SeparatedCache.scala create mode 100644 cache/lib/sbinary-0.3-alpha.jar create mode 100644 cache/src/test/scala/CacheTest.scala create mode 100644 ivy/ConvertResolver.scala create mode 100644 ivy/CustomXmlParser.scala create mode 100644 ivy/Ivy.scala create mode 100644 ivy/IvyActions.scala create mode 100644 ivy/IvyConfigurations.scala create mode 100644 ivy/IvyInterface.scala create mode 100644 ivy/IvyLogger.scala create mode 100644 ivy/IvyScala.scala create mode 100644 notes create mode 100644 project/build.properties create mode 100644 project/build/XSbt.scala create mode 100644 tasks/ParallelRunner.scala create mode 100644 tasks/Task.scala create mode 100644 tasks/TaskListener.scala create mode 100644 tasks/TaskRunner.scala create mode 100644 tasks/TaskScheduler.scala create mode 100644 tasks/src/test/scala/TListCompileTest.scala create mode 100644 tasks/src/test/scala/TaskRunnerCircular.scala create mode 100644 tasks/src/test/scala/TaskRunnerFork.scala create mode 100644 tasks/src/test/scala/TestRunner.scala create mode 100644 tasks/src/test/scala/TestRunnerCall.scala create mode 100644 tasks/src/test/scala/TestRunnerSort.scala create mode 100644 tasks/src/test/scala/checkResult.scala create mode 100644 util/classpath/ClassLoaders.scala create mode 100644 util/collection/HLists.scala create mode 100644 util/collection/TreeHashSet.scala create mode 100644 util/collection/lib/metascala-0.1.jar create mode 100644 util/control/ErrorHandling.scala create mode 100644 util/io/Hash.scala create mode 100644 util/io/OpenResource.scala create mode 100644 util/log/Logger.scala diff --git a/cache/Cache.scala b/cache/Cache.scala new file mode 100644 index 000000000..b016c1654 --- /dev/null +++ b/cache/Cache.scala @@ -0,0 +1,58 @@ +package xsbt + +import sbinary.{CollectionTypes, Format, JavaFormats} +import java.io.File + +trait Cache[I,O] +{ + def apply(file: File)(i: I): Either[O, O => Unit] +} +trait SBinaryFormats extends CollectionTypes with JavaFormats with NotNull +{ + //TODO: add basic types minus FileFormat +} +object Cache extends BasicCacheImplicits with SBinaryFormats with HListCacheImplicits +{ + def cache[I,O](implicit c: Cache[I,O]): Cache[I,O] = c + def outputCache[O](implicit c: OutputCache[O]): OutputCache[O] = c + def inputCache[O](implicit c: InputCache[O]): InputCache[O] = c + + def wrapInputCache[I,DI](implicit convert: I => DI, base: InputCache[DI]): InputCache[I] = + new WrappedInputCache(convert, base) + def wrapOutputCache[O,DO](implicit convert: O => DO, reverse: DO => O, base: OutputCache[DO]): OutputCache[O] = + new WrappedOutputCache[O,DO](convert, reverse, base) + + /* Note: Task[O] { type Input = I } is written out because ITask[I,O] did not work (type could not be inferred properly) with a task + * with an HList input.*/ + def apply[I,O](task: Task[O] { type Input = I }, file: File)(implicit cache: Cache[I,O]): Task[O] { type Input = I } = + task match { case m: M[I,O,_] => + new M[I,O,Result[O]](None)(m.dependencies)(m.extract)(computeWithCache(m, cache, file)) + } + private def computeWithCache[I,O](m: M[I,O,_], cache: Cache[I,O], file: File)(in: I): Result[O] = + cache(file)(in) match + { + case Left(value) => Value(value) + case Right(store) => NewTask(m.map { out => store(out); out }) + } +} +trait BasicCacheImplicits extends NotNull +{ + implicit def basicInputCache[I](implicit format: Format[I], equiv: Equiv[I]): InputCache[I] = + new BasicInputCache(format, equiv) + implicit def basicOutputCache[O](implicit format: Format[O]): OutputCache[O] = + new BasicOutputCache(format) + + implicit def ioCache[I,O](implicit input: InputCache[I], output: OutputCache[O]): Cache[I,O] = + new SeparatedCache(input, output) + implicit def defaultEquiv[T]: Equiv[T] = new Equiv[T] { def equiv(a: T, b: T) = a == b } +} +trait HListCacheImplicits extends HLists +{ + implicit def hConsInputCache[H,T<:HList](implicit headCache: InputCache[H], tailCache: InputCache[T]): InputCache[HCons[H,T]] = + new HConsInputCache(headCache, tailCache) + implicit lazy val hNilInputCache: InputCache[HNil] = new HNilInputCache + + implicit def hConsOutputCache[H,T<:HList](implicit headCache: OutputCache[H], tailCache: OutputCache[T]): OutputCache[HCons[H,T]] = + new HConsOutputCache(headCache, tailCache) + implicit lazy val hNilOutputCache: OutputCache[HNil] = new HNilOutputCache +} \ No newline at end of file diff --git a/cache/FileInfo.scala b/cache/FileInfo.scala new file mode 100644 index 000000000..8c835fe95 --- /dev/null +++ b/cache/FileInfo.scala @@ -0,0 +1,74 @@ +package xsbt + +import java.io.{File, IOException} +import sbinary.{DefaultProtocol, Format} +import DefaultProtocol._ +import Function.tupled + +sealed trait FileInfo extends NotNull +{ + val file: File +} +sealed trait HashFileInfo extends FileInfo +{ + val hash: List[Byte] +} +sealed trait ModifiedFileInfo extends FileInfo +{ + val lastModified: Long +} +sealed trait HashModifiedFileInfo extends HashFileInfo with ModifiedFileInfo + +private final case class FileHash(file: File, hash: List[Byte]) extends HashFileInfo +private final case class FileModified(file: File, lastModified: Long) extends ModifiedFileInfo +private final case class FileHashModified(file: File, hash: List[Byte], lastModified: Long) extends HashModifiedFileInfo + +object FileInfo +{ + sealed trait Style[F <: FileInfo] extends NotNull + { + implicit def apply(file: File): F + implicit def unapply(info: F): File = info.file + implicit val format: Format[F] + import Cache._ + implicit def infoInputCache: InputCache[File] = wrapInputCache[File,F] + implicit def infoOutputCache: OutputCache[File] = wrapOutputCache[File,F] + } + object full extends Style[HashModifiedFileInfo] + { + implicit def apply(file: File): HashModifiedFileInfo = make(file, Hash(file).toList, file.lastModified) + def make(file: File, hash: List[Byte], lastModified: Long): HashModifiedFileInfo = FileHashModified(file.getAbsoluteFile, hash, lastModified) + implicit val format: Format[HashModifiedFileInfo] = wrap(f => (f.file, f.hash, f.lastModified), tupled(make _)) + } + object hash extends Style[HashFileInfo] + { + implicit def apply(file: File): HashFileInfo = make(file, computeHash(file).toList) + def make(file: File, hash: List[Byte]): HashFileInfo = FileHash(file.getAbsoluteFile, hash) + implicit val format: Format[HashFileInfo] = wrap(f => (f.file, f.hash), tupled(make _)) + private def computeHash(file: File) = try { Hash(file) } catch { case e: Exception => Nil } + } + object lastModified extends Style[ModifiedFileInfo] + { + implicit def apply(file: File): ModifiedFileInfo = make(file, file.lastModified) + def make(file: File, lastModified: Long): ModifiedFileInfo = FileModified(file.getAbsoluteFile, lastModified) + implicit val format: Format[ModifiedFileInfo] = wrap(f => (f.file, f.lastModified), tupled(make _)) + } +} + +final case class FilesInfo[F <: FileInfo] private(files: Set[F]) extends NotNull +object FilesInfo +{ + sealed trait Style[F <: FileInfo] extends NotNull + { + implicit def apply(files: Iterable[File]): FilesInfo[F] + implicit val format: Format[FilesInfo[F]] + } + private final class BasicStyle[F <: FileInfo](fileStyle: FileInfo.Style[F])(implicit infoFormat: Format[F]) extends Style[F] + { + implicit def apply(files: Iterable[File]) = FilesInfo( (Set() ++ files.map(_.getAbsoluteFile)).map(fileStyle.apply) ) + implicit val format: Format[FilesInfo[F]] = wrap(_.files, (fs: Set[F]) => new FilesInfo(fs)) + } + lazy val full: Style[HashModifiedFileInfo] = new BasicStyle(FileInfo.full)(FileInfo.full.format) + lazy val hash: Style[HashFileInfo] = new BasicStyle(FileInfo.hash)(FileInfo.hash.format) + lazy val lastModified: Style[ModifiedFileInfo] = new BasicStyle(FileInfo.lastModified)(FileInfo.lastModified.format) +} \ No newline at end of file diff --git a/cache/HListCache.scala b/cache/HListCache.scala new file mode 100644 index 000000000..eb3affd13 --- /dev/null +++ b/cache/HListCache.scala @@ -0,0 +1,44 @@ +package xsbt + +import java.io.{InputStream,OutputStream} +import metascala.HLists.{HCons,HList,HNil} + +class HNilInputCache extends NoInputCache[HNil] +class HConsInputCache[H,T <: HList](val headCache: InputCache[H], val tailCache: InputCache[T]) extends InputCache[HCons[H,T]] +{ + def uptodate(in: HCons[H,T])(cacheStream: InputStream) = + { + lazy val headResult = headCache.uptodate(in.head)(cacheStream) + lazy val tailResult = tailCache.uptodate(in.tail)(cacheStream) + new CacheResult + { + lazy val uptodate = headResult.uptodate && tailResult.uptodate + def update(outputStream: OutputStream) = + { + headResult.update(outputStream) + tailResult.update(outputStream) + } + } + } + def force(in: HCons[H,T])(cacheStream: OutputStream) = + { + headCache.force(in.head)(cacheStream) + tailCache.force(in.tail)(cacheStream) + } +} + +class HNilOutputCache extends NoOutputCache[HNil](HNil) +class HConsOutputCache[H,T <: HList](val headCache: OutputCache[H], val tailCache: OutputCache[T]) extends OutputCache[HCons[H,T]] +{ + def loadCached(cacheStream: InputStream) = + { + val head = headCache.loadCached(cacheStream) + val tail = tailCache.loadCached(cacheStream) + HCons(head, tail) + } + def update(out: HCons[H,T])(cacheStream: OutputStream) + { + headCache.update(out.head)(cacheStream) + tailCache.update(out.tail)(cacheStream) + } +} \ No newline at end of file diff --git a/cache/NoCache.scala b/cache/NoCache.scala new file mode 100644 index 000000000..a9cce3e99 --- /dev/null +++ b/cache/NoCache.scala @@ -0,0 +1,19 @@ +package xsbt + +import java.io.{InputStream,OutputStream} + +class NoInputCache[T] extends InputCache[T] +{ + def uptodate(in: T)(cacheStream: InputStream) = + new CacheResult + { + def uptodate = true + def update(outputStream: OutputStream) {} + } + def force(in: T)(outputStream: OutputStream) {} +} +class NoOutputCache[O](create: => O) extends OutputCache[O] +{ + def loadCached(cacheStream: InputStream) = create + def update(out: O)(cacheStream: OutputStream) {} +} \ No newline at end of file diff --git a/cache/SeparatedCache.scala b/cache/SeparatedCache.scala new file mode 100644 index 000000000..f9b212f4a --- /dev/null +++ b/cache/SeparatedCache.scala @@ -0,0 +1,80 @@ +package xsbt + +import sbinary.Format +import sbinary.JavaIO._ +import java.io.{File, InputStream, OutputStream} + +trait CacheResult +{ + def uptodate: Boolean + def update(stream: OutputStream): Unit +} +trait InputCache[I] extends NotNull +{ + def uptodate(in: I)(cacheStream: InputStream): CacheResult + def force(in: I)(cacheStream: OutputStream): Unit +} +trait OutputCache[O] extends NotNull +{ + def loadCached(cacheStream: InputStream): O + def update(out: O)(cacheStream: OutputStream): Unit +} +class SeparatedCache[I,O](input: InputCache[I], output: OutputCache[O]) extends Cache[I,O] +{ + def apply(file: File)(in: I) = + try { applyImpl(file, in) } + catch { case _: Exception => Right(update(file)(in)) } + protected def applyImpl(file: File, in: I) = + { + OpenResource.fileInputStream(file) { stream => + val cache = input.uptodate(in)(stream) + lazy val doUpdate = (result: O) => + { + OpenResource.fileOutputStream(false)(file) { stream => + cache.update(stream) + output.update(result)(stream) + } + } + if(cache.uptodate) + try { Left(output.loadCached(stream)) } + catch { case _: Exception => Right(doUpdate) } + else + Right(doUpdate) + } + } + protected def update(file: File)(in: I)(out: O) + { + OpenResource.fileOutputStream(false)(file) { stream => + input.force(in)(stream) + output.update(out)(stream) + } + } +} +class BasicOutputCache[O](val format: Format[O]) extends OutputCache[O] +{ + def loadCached(cacheStream: InputStream): O = format.reads(cacheStream) + def update(out: O)(cacheStream: OutputStream): Unit = format.writes(cacheStream, out) +} +class BasicInputCache[I](val format: Format[I], val equiv: Equiv[I]) extends InputCache[I] +{ + def uptodate(in: I)(cacheStream: InputStream) = + { + val loaded = format.reads(cacheStream) + new CacheResult + { + val uptodate = equiv.equiv(in, loaded) + def update(outputStream: OutputStream) = force(in)(outputStream) + } + } + def force(in: I)(outputStream: OutputStream) = format.writes(outputStream, in) +} +class WrappedInputCache[I,DI](val convert: I => DI, val base: InputCache[DI]) extends InputCache[I] +{ + def uptodate(in: I)(cacheStream: InputStream) = base.uptodate(convert(in))(cacheStream) + def force(in: I)(outputStream: OutputStream) = base.force(convert(in))(outputStream) +} +class WrappedOutputCache[O,DO](val convert: O => DO, val reverse: DO => O, val base: OutputCache[DO]) extends OutputCache[O] +{ + def loadCached(cacheStream: InputStream): O = reverse(base.loadCached(cacheStream)) + def update(out: O)(cacheStream: OutputStream): Unit = base.update(convert(out))(cacheStream) +} \ No newline at end of file diff --git a/cache/lib/sbinary-0.3-alpha.jar b/cache/lib/sbinary-0.3-alpha.jar new file mode 100644 index 0000000000000000000000000000000000000000..131ec72ce31c157fa6f6b6dd3c94d9a92b54b647 GIT binary patch literal 143178 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 k5;E|W2M println("File length: " + f.length); f.length } + val cached = Cache(lengthTask, new File("/tmp/length-cache")) + + val cTask = (createTask :: cached :: TNil) map { case (file :: len :: HNil) => println("File: " + file + " length: " + len); len :: file :: HNil } + val cachedC = Cache(cTask, new File("/tmp/c-cache")) + + TaskRunner(cachedC).left.foreach(_.foreach(f => f.exception.printStackTrace)) + } +} \ No newline at end of file diff --git a/ivy/ConvertResolver.scala b/ivy/ConvertResolver.scala new file mode 100644 index 000000000..51c3277eb --- /dev/null +++ b/ivy/ConvertResolver.scala @@ -0,0 +1,100 @@ +/* sbt -- Simple Build Tool + * Copyright 2008, 2009 Mark Harrah + */ +package xsbt + +import org.apache.ivy.{core,plugins} +import core.module.id.ModuleRevisionId +import plugins.resolver.{ChainResolver, DependencyResolver, IBiblioResolver} +import plugins.resolver.{AbstractPatternsBasedResolver, AbstractSshBasedResolver, FileSystemResolver, SFTPResolver, SshResolver, URLResolver} + +private object ConvertResolver +{ + /** Converts the given sbt resolver into an Ivy resolver..*/ + def apply(r: Resolver) = + { + r match + { + case repo: MavenRepository => + { + val resolver = new IBiblioResolver + initializeMavenStyle(resolver, repo.name, repo.root) + resolver + } + case JavaNet1Repository => + { + // Thanks to Matthias Pfau for posting how to use the Maven 1 repository on java.net with Ivy: + // http://www.nabble.com/Using-gradle-Ivy-with-special-maven-repositories-td23775489.html + val resolver = new IBiblioResolver { override def convertM2IdForResourceSearch(mrid: ModuleRevisionId) = mrid } + initializeMavenStyle(resolver, JavaNet1Repository.name, "http://download.java.net/maven/1/") + resolver.setPattern("[organisation]/[ext]s/[module]-[revision](-[classifier]).[ext]") + resolver + } + case repo: SshRepository => + { + val resolver = new SshResolver + initializeSSHResolver(resolver, repo) + repo.publishPermissions.foreach(perm => resolver.setPublishPermissions(perm)) + resolver + } + case repo: SftpRepository => + { + val resolver = new SFTPResolver + initializeSSHResolver(resolver, repo) + resolver + } + case repo: FileRepository => + { + val resolver = new FileSystemResolver + resolver.setName(repo.name) + initializePatterns(resolver, repo.patterns) + import repo.configuration.{isLocal, isTransactional} + resolver.setLocal(isLocal) + isTransactional.foreach(value => resolver.setTransactional(value.toString)) + resolver + } + case repo: URLRepository => + { + val resolver = new URLResolver + resolver.setName(repo.name) + initializePatterns(resolver, repo.patterns) + resolver + } + } + } + private def initializeMavenStyle(resolver: IBiblioResolver, name: String, root: String) + { + resolver.setName(name) + resolver.setM2compatible(true) + resolver.setRoot(root) + } + private def initializeSSHResolver(resolver: AbstractSshBasedResolver, repo: SshBasedRepository) + { + resolver.setName(repo.name) + resolver.setPassfile(null) + initializePatterns(resolver, repo.patterns) + initializeConnection(resolver, repo.connection) + } + private def initializeConnection(resolver: AbstractSshBasedResolver, connection: RepositoryHelpers.SshConnection) + { + import resolver._ + import connection._ + hostname.foreach(setHost) + port.foreach(setPort) + authentication foreach + { + case RepositoryHelpers.PasswordAuthentication(user, password) => + setUser(user) + setUserPassword(password) + case RepositoryHelpers.KeyFileAuthentication(file, password) => + setKeyFile(file) + setKeyFilePassword(password) + } + } + private def initializePatterns(resolver: AbstractPatternsBasedResolver, patterns: RepositoryHelpers.Patterns) + { + resolver.setM2compatible(patterns.isMavenCompatible) + patterns.ivyPatterns.foreach(resolver.addIvyPattern) + patterns.artifactPatterns.foreach(resolver.addArtifactPattern) + } +} diff --git a/ivy/CustomXmlParser.scala b/ivy/CustomXmlParser.scala new file mode 100644 index 000000000..6688d8ef7 --- /dev/null +++ b/ivy/CustomXmlParser.scala @@ -0,0 +1,35 @@ +/* sbt -- Simple Build Tool + * Copyright 2008, 2009 Mark Harrah + */ +package xsbt + +import java.io.ByteArrayInputStream +import java.net.URL + +import org.apache.ivy.{core, plugins} +import core.module.descriptor.{DefaultDependencyDescriptor, DefaultModuleDescriptor} +import core.settings.IvySettings +import plugins.parser.xml.XmlModuleDescriptorParser +import plugins.repository.Resource +import plugins.repository.url.URLResource + +/** Subclasses the default Ivy file parser in order to provide access to protected methods.*/ +private object CustomXmlParser extends XmlModuleDescriptorParser with NotNull +{ + import XmlModuleDescriptorParser.Parser + class CustomParser(settings: IvySettings) extends Parser(CustomXmlParser, settings) with NotNull + { + def setSource(url: URL) = + { + super.setResource(new URLResource(url)) + super.setInput(url) + } + def setInput(bytes: Array[Byte]) { setInput(new ByteArrayInputStream(bytes)) } + /** Overridden because the super implementation overwrites the module descriptor.*/ + override def setResource(res: Resource) {} + override def setMd(md: DefaultModuleDescriptor) = super.setMd(md) + override def parseDepsConfs(confs: String, dd: DefaultDependencyDescriptor) = super.parseDepsConfs(confs, dd) + override def getDefaultConf = super.getDefaultConf + override def setDefaultConf(conf: String) = super.setDefaultConf(conf) + } +} \ No newline at end of file diff --git a/ivy/Ivy.scala b/ivy/Ivy.scala new file mode 100644 index 000000000..d85a46733 --- /dev/null +++ b/ivy/Ivy.scala @@ -0,0 +1,307 @@ +/* sbt -- Simple Build Tool + * Copyright 2008, 2009 Mark Harrah + */ +package xsbt + +import Artifact.{defaultExtension, defaultType} + +import java.io.File + +import org.apache.ivy.{core, plugins, util, Ivy} +import core.cache.DefaultRepositoryCacheManager +import core.module.descriptor.{DefaultArtifact, DefaultDependencyArtifactDescriptor, MDArtifact} +import core.module.descriptor.{DefaultDependencyDescriptor, DefaultModuleDescriptor, ModuleDescriptor} +import core.module.id.{ArtifactId,ModuleId, ModuleRevisionId} +import core.settings.IvySettings +import plugins.matcher.PatternMatcher +import plugins.parser.m2.PomModuleDescriptorParser +import plugins.resolver.ChainResolver +import util.Message + +final class IvySbt(configuration: IvyConfiguration) +{ + import configuration._ + /** ========== Configuration/Setup ============ + * This part configures the Ivy instance by first creating the logger interface to ivy, then IvySettings, and then the Ivy instance. + * These are lazy so that they are loaded within the right context. This is important so that no Ivy XML configuration needs to be loaded, + * saving some time. This is necessary because Ivy has global state (IvyContext, Message, DocumentBuilder, ...). + */ + private lazy val logger = new IvyLoggerInterface(log) + private def withDefaultLogger[T](f: => T): T = + IvySbt.synchronized // Ivy is not thread-safe. In particular, it uses a static DocumentBuilder, which is not thread-safe + { + val originalLogger = Message.getDefaultLogger + Message.setDefaultLogger(logger) + try { f } + finally { Message.setDefaultLogger(originalLogger) } + } + private lazy val settings = + { + val is = new IvySettings + is.setBaseDir(paths.baseDirectory) + IvySbt.configureCache(is, paths.cacheDirectory) + if(resolvers.isEmpty) + autodetectConfiguration(is) + else + IvySbt.setResolvers(is, resolvers, log) + is + } + private lazy val ivy = + { + val i = Ivy.newInstance(settings) + i.getLoggerEngine.pushLogger(logger) + i + } + /** Called to configure Ivy when inline resolvers are not specified. + * This will configure Ivy with an 'ivy-settings.xml' file if there is one or else use default resolvers.*/ + private def autodetectConfiguration(settings: IvySettings) + { + log.debug("Autodetecting configuration.") + val defaultIvyConfigFile = IvySbt.defaultIvyConfiguration(paths.baseDirectory) + if(defaultIvyConfigFile.canRead) + settings.load(defaultIvyConfigFile) + else + IvySbt.setResolvers(settings, Resolver.withDefaultResolvers(Nil), log) + } + /** ========== End Configuration/Setup ============*/ + + /** Uses the configured Ivy instance within a safe context.*/ + def withIvy[T](f: Ivy => T): T = + withDefaultLogger + { + ivy.pushContext() + try { f(ivy) } + finally { ivy.popContext() } + } + + final class Module(val moduleConfiguration: ModuleConfiguration) extends NotNull + { + def logger = configuration.log + def withModule[T](f: (Ivy,DefaultModuleDescriptor,String) => T): T = + withIvy[T] { ivy => f(ivy, moduleDescriptor, defaultConfig) } + + import moduleConfiguration._ + private lazy val (moduleDescriptor: DefaultModuleDescriptor, defaultConfig: String) = + { + val (baseModule, baseConfiguration) = + if(isUnconfigured) + autodetectDependencies(IvySbt.toID(module)) + else + configureModule + ivyScala.foreach(IvyScala.checkModule(baseModule, baseConfiguration)) + baseModule.getExtraAttributesNamespaces.asInstanceOf[java.util.Map[String,String]].put("m", "m") + (baseModule, baseConfiguration) + } + private def configureModule = + { + val moduleID = newConfiguredModuleID + val defaultConf = defaultConfiguration getOrElse Configurations.config(ModuleDescriptor.DEFAULT_CONFIGURATION) + log.debug("Using inline dependencies specified in Scala" + (if(ivyXML.isEmpty) "." else " and XML.")) + + val parser = IvySbt.parseIvyXML(ivy.getSettings, IvySbt.wrapped(module, ivyXML), moduleID, defaultConf.name, validate) + + IvySbt.addArtifacts(moduleID, artifacts) + IvySbt.addDependencies(moduleID, dependencies, parser) + IvySbt.addMainArtifact(moduleID) + (moduleID, parser.getDefaultConf) + } + private def newConfiguredModuleID = + { + val mod = new DefaultModuleDescriptor(IvySbt.toID(module), "release", null, false) + mod.setLastModified(System.currentTimeMillis) + configurations.foreach(config => mod.addConfiguration(IvySbt.toIvyConfiguration(config))) + mod + } + + /** Parses the given Maven pom 'pomFile'.*/ + private def readPom(pomFile: File) = + { + val md = PomModuleDescriptorParser.getInstance.parseDescriptor(settings, toURL(pomFile), validate) + (IvySbt.toDefaultModuleDescriptor(md), "compile") + } + /** Parses the given Ivy file 'ivyFile'.*/ + private def readIvyFile(ivyFile: File) = + { + val url = toURL(ivyFile) + val parser = new CustomXmlParser.CustomParser(settings) + parser.setValidate(validate) + parser.setSource(url) + parser.parse() + val md = parser.getModuleDescriptor() + (IvySbt.toDefaultModuleDescriptor(md), parser.getDefaultConf) + } + private def toURL(file: File) = file.toURI.toURL + /** Called to determine dependencies when the dependency manager is SbtManager and no inline dependencies (Scala or XML) + * are defined. It will try to read from pom.xml first and then ivy.xml if pom.xml is not found. If neither is found, + * Ivy is configured with defaults.*/ + private def autodetectDependencies(module: ModuleRevisionId) = + { + log.debug("Autodetecting dependencies.") + val defaultPOMFile = IvySbt.defaultPOM(paths.baseDirectory) + if(defaultPOMFile.canRead) + readPom(defaultPOMFile) + else + { + val defaultIvy = IvySbt.defaultIvyFile(paths.baseDirectory) + if(defaultIvy.canRead) + readIvyFile(defaultIvy) + else + { + val defaultConf = ModuleDescriptor.DEFAULT_CONFIGURATION + log.warn("No dependency configuration found, using defaults.") + val moduleID = DefaultModuleDescriptor.newDefaultInstance(module) + IvySbt.addMainArtifact(moduleID) + IvySbt.addDefaultArtifact(defaultConf, moduleID) + (moduleID, defaultConf) + } + } + } + } +} + +private object IvySbt +{ + val DefaultIvyConfigFilename = "ivysettings.xml" + val DefaultIvyFilename = "ivy.xml" + val DefaultMavenFilename = "pom.xml" + + private def defaultIvyFile(project: File) = new File(project, DefaultIvyFilename) + private def defaultIvyConfiguration(project: File) = new File(project, DefaultIvyConfigFilename) + private def defaultPOM(project: File) = new File(project, DefaultMavenFilename) + + /** Sets the resolvers for 'settings' to 'resolvers'. This is done by creating a new chain and making it the default. */ + private def setResolvers(settings: IvySettings, resolvers: Seq[Resolver], log: IvyLogger) + { + val newDefault = new ChainResolver + newDefault.setName("sbt-chain") + newDefault.setReturnFirst(true) + newDefault.setCheckmodified(true) + resolvers.foreach(r => newDefault.add(ConvertResolver(r))) + settings.addResolver(newDefault) + settings.setDefaultResolver(newDefault.getName) + log.debug("Using repositories:\n" + resolvers.mkString("\n\t")) + } + private def configureCache(settings: IvySettings, dir: Option[File]) + { + val cacheDir = dir.getOrElse(settings.getDefaultRepositoryCacheBasedir()) + val manager = new DefaultRepositoryCacheManager("default-cache", settings, cacheDir) + manager.setUseOrigin(true) + manager.setChangingMatcher(PatternMatcher.REGEXP); + manager.setChangingPattern(".*-SNAPSHOT"); + settings.setDefaultRepositoryCacheManager(manager) + } + private def toIvyConfiguration(configuration: Configuration) = + { + import org.apache.ivy.core.module.descriptor.{Configuration => IvyConfig} + import IvyConfig.Visibility._ + import configuration._ + new IvyConfig(name, if(isPublic) PUBLIC else PRIVATE, description, extendsConfigs.map(_.name).toArray, transitive, null) + } + private def addDefaultArtifact(defaultConf: String, moduleID: DefaultModuleDescriptor) = + moduleID.addArtifact(defaultConf, new MDArtifact(moduleID, moduleID.getModuleRevisionId.getName, defaultType, defaultExtension)) + /** Adds the ivy.xml main artifact. */ + private def addMainArtifact(moduleID: DefaultModuleDescriptor) + { + val artifact = DefaultArtifact.newIvyArtifact(moduleID.getResolvedModuleRevisionId, moduleID.getPublicationDate) + moduleID.setModuleArtifact(artifact) + moduleID.check() + } + /** Converts the given sbt module id into an Ivy ModuleRevisionId.*/ + private def toID(m: ModuleID) = + { + import m._ + ModuleRevisionId.newInstance(organization, name, revision) + } + private def toIvyArtifact(moduleID: ModuleDescriptor, a: Artifact, configurations: Iterable[String]): MDArtifact = + { + val artifact = new MDArtifact(moduleID, a.name, a.`type`, a.extension, null, extra(a)) + configurations.foreach(artifact.addConfiguration) + artifact + } + private def extra(artifact: Artifact) = artifact.classifier.map(c => javaMap("m:classifier" -> c)).getOrElse(null) + + private object javaMap + { + import java.util.{HashMap, Map} + def apply[K,V](pairs: (K,V)*): Map[K,V] = + { + val map = new HashMap[K,V] + pairs.foreach { case (key, value) => map.put(key, value) } + map + } + } + /** Creates a full ivy file for 'module' using the 'content' XML as the part after the <info>...</info> section. */ + private def wrapped(module: ModuleID, content: scala.xml.NodeSeq) = + { + import module._ + + + {content} + + } + /** Parses the given in-memory Ivy file 'xml', using the existing 'moduleID' and specifying the given 'defaultConfiguration'. */ + private def parseIvyXML(settings: IvySettings, xml: scala.xml.NodeSeq, moduleID: DefaultModuleDescriptor, defaultConfiguration: String, validate: Boolean): CustomXmlParser.CustomParser = + parseIvyXML(settings, xml.toString, moduleID, defaultConfiguration, validate) + /** Parses the given in-memory Ivy file 'xml', using the existing 'moduleID' and specifying the given 'defaultConfiguration'. */ + private def parseIvyXML(settings: IvySettings, xml: String, moduleID: DefaultModuleDescriptor, defaultConfiguration: String, validate: Boolean): CustomXmlParser.CustomParser = + { + val parser = new CustomXmlParser.CustomParser(settings) + parser.setMd(moduleID) + parser.setDefaultConf(defaultConfiguration) + parser.setValidate(validate) + parser.setInput(xml.getBytes) + parser.parse() + parser + } + + /** This method is used to add inline dependencies to the provided module. */ + def addDependencies(moduleID: DefaultModuleDescriptor, dependencies: Iterable[ModuleID], parser: CustomXmlParser.CustomParser) + { + for(dependency <- dependencies) + { + val dependencyDescriptor = new DefaultDependencyDescriptor(moduleID, toID(dependency), false, dependency.isChanging, dependency.isTransitive) + dependency.configurations match + { + case None => // The configuration for this dependency was not explicitly specified, so use the default + parser.parseDepsConfs(parser.getDefaultConf, dependencyDescriptor) + case Some(confs) => // The configuration mapping (looks like: test->default) was specified for this dependency + parser.parseDepsConfs(confs, dependencyDescriptor) + } + for(artifact <- dependency.explicitArtifacts) + { + import artifact.{name, classifier, `type`, extension, url} + val extraMap = extra(artifact) + val ivyArtifact = new DefaultDependencyArtifactDescriptor(dependencyDescriptor, name, `type`, extension, url.getOrElse(null), extraMap) + for(conf <- dependencyDescriptor.getModuleConfigurations) + dependencyDescriptor.addDependencyArtifact(conf, ivyArtifact) + } + moduleID.addDependency(dependencyDescriptor) + } + } + /** This method is used to add inline artifacts to the provided module. */ + def addArtifacts(moduleID: DefaultModuleDescriptor, artifacts: Iterable[Artifact]) + { + val allConfigurations = moduleID.getPublicConfigurationsNames + for(artifact <- artifacts) + { + val configurationStrings = + { + val artifactConfigurations = artifact.configurations + if(artifactConfigurations.isEmpty) + allConfigurations + else + artifactConfigurations.map(_.name) + } + val ivyArtifact = toIvyArtifact(moduleID, artifact, configurationStrings) + configurationStrings.foreach(configuration => moduleID.addArtifact(configuration, ivyArtifact)) + } + } + /** This code converts the given ModuleDescriptor to a DefaultModuleDescriptor by casting or generating an error. + * Ivy 2.0.0 always produces a DefaultModuleDescriptor. */ + private def toDefaultModuleDescriptor(md: ModuleDescriptor) = + md match + { + case dmd: DefaultModuleDescriptor => dmd + case _ => error("Unknown ModuleDescriptor type.") + } +} diff --git a/ivy/IvyActions.scala b/ivy/IvyActions.scala new file mode 100644 index 000000000..ae3fcf6d2 --- /dev/null +++ b/ivy/IvyActions.scala @@ -0,0 +1,138 @@ +package xsbt + +import java.io.File + +import org.apache.ivy.{core, plugins, util, Ivy} +import core.cache.DefaultRepositoryCacheManager +import core.LogOptions +import core.deliver.DeliverOptions +import core.module.descriptor.{DefaultArtifact, DefaultDependencyArtifactDescriptor, MDArtifact} +import core.module.descriptor.{DefaultDependencyDescriptor, DefaultModuleDescriptor, DependencyDescriptor, ModuleDescriptor} +import core.module.id.{ArtifactId,ModuleId, ModuleRevisionId} +import core.publish.PublishOptions +import core.resolve.ResolveOptions +import core.retrieve.RetrieveOptions +import plugins.parser.m2.{PomModuleDescriptorParser,PomModuleDescriptorWriter} + +final class UpdateConfiguration(val retrieveDirectory: File, val outputPattern: String, val synchronize: Boolean, val quiet: Boolean) extends NotNull + +object IvyActions +{ + /** Clears the Ivy cache, as configured by 'config'. */ + def cleanCache(ivy: IvySbt) = ivy.withIvy { _.getSettings.getRepositoryCacheManagers.foreach(_.clean()) } + + /** Creates a Maven pom from the given Ivy configuration*/ + def makePom(module: IvySbt#Module, extraDependencies: Iterable[ModuleID], configurations: Option[Iterable[Configuration]], output: File) + { + module.withModule { (ivy, md, default) => + addLateDependencies(ivy, md, default, extraDependencies) + val pomModule = keepConfigurations(md, configurations) + PomModuleDescriptorWriter.write(pomModule, DefaultConfigurationMapping, output) + module.logger.info("Wrote " + output.getAbsolutePath) + } + } + // todo: correct default configuration for extra dependencies + private def addLateDependencies(ivy: Ivy, module: DefaultModuleDescriptor, defaultConfiguration: String, extraDependencies: Iterable[ModuleID]) + { + val parser = new CustomXmlParser.CustomParser(ivy.getSettings) + parser.setMd(module) + val defaultConf = if(defaultConfiguration.contains("->")) defaultConfiguration else (defaultConfiguration + "->default(compile)") + parser.setDefaultConf(defaultConf) + IvySbt.addDependencies(module, extraDependencies, parser) + } + private def getConfigurations(module: ModuleDescriptor, configurations: Option[Iterable[Configuration]]) = + configurations match + { + case Some(confs) => confs.map(_.name).toList.toArray + case None => module.getPublicConfigurationsNames + } + /** Retain dependencies only with the configurations given, or all public configurations of `module` if `configurations` is None. + * This currently only preserves the information required by makePom*/ + private def keepConfigurations(module: ModuleDescriptor, configurations: Option[Iterable[Configuration]]): ModuleDescriptor = + { + val keepConfigurations = getConfigurations(module, configurations) + val keepSet = Set(keepConfigurations.toSeq : _*) + def translate(dependency: DependencyDescriptor) = + { + val keep = dependency.getModuleConfigurations.filter(keepSet.contains) + if(keep.isEmpty) + None + else // TODO: translate the dependency to contain only configurations to keep + Some(dependency) + } + val newModule = new DefaultModuleDescriptor(module.getModuleRevisionId, "", null) + newModule.setHomePage(module.getHomePage) + for(dependency <- module.getDependencies; translated <- translate(dependency)) + newModule.addDependency(translated) + newModule + } + + def deliver(module: IvySbt#Module, status: String, deliverIvyPattern: String, extraDependencies: Iterable[ModuleID], configurations: Option[Iterable[Configuration]], quiet: Boolean) + { + module.withModule { case (ivy, md, default) => + addLateDependencies(ivy, md, default, extraDependencies) + resolve(quiet)(ivy, md, default) // todo: set download = false for resolve + val revID = md.getModuleRevisionId + val options = DeliverOptions.newInstance(ivy.getSettings).setStatus(status) + options.setConfs(getConfigurations(md, configurations)) + ivy.deliver(revID, revID.getRevision, deliverIvyPattern, options) + } + } + // todo: map configurations, extra dependencies + def publish(module: IvySbt#Module, resolverName: String, srcArtifactPatterns: Iterable[String], deliveredIvyPattern: Option[String], configurations: Option[Iterable[Configuration]]) + { + module.withModule { case (ivy, md, default) => + val revID = md.getModuleRevisionId + val patterns = new java.util.ArrayList[String] + srcArtifactPatterns.foreach(pattern => patterns.add(pattern)) + val options = (new PublishOptions).setOverwrite(true) + deliveredIvyPattern.foreach(options.setSrcIvyPattern) + options.setConfs(getConfigurations(md, configurations)) + ivy.publish(revID, patterns, resolverName, options) + } + } + /** Resolves and retrieves dependencies. 'ivyConfig' is used to produce an Ivy file and configuration. + * 'updateConfig' configures the actual resolution and retrieval process. */ + def update(module: IvySbt#Module, configuration: UpdateConfiguration) + { + module.withModule { case (ivy, md, default) => + import configuration._ + resolve(quiet)(ivy, md, default) + val retrieveOptions = new RetrieveOptions + retrieveOptions.setSync(synchronize) + val patternBase = retrieveDirectory.getAbsolutePath + val pattern = + if(patternBase.endsWith(File.separator)) + patternBase + outputPattern + else + patternBase + File.separatorChar + outputPattern + ivy.retrieve(md.getModuleRevisionId, pattern, retrieveOptions) + } + } + private def resolve(quiet: Boolean)(ivy: Ivy, module: DefaultModuleDescriptor, defaultConf: String) = + { + val resolveOptions = new ResolveOptions + if(quiet) + resolveOptions.setLog(LogOptions.LOG_DOWNLOAD_ONLY) + val resolveReport = ivy.resolve(module, resolveOptions) + if(resolveReport.hasError) + error(Set(resolveReport.getAllProblemMessages.toArray: _*).mkString("\n")) + } +} + +private object DefaultConfigurationMapping extends PomModuleDescriptorWriter.ConfigurationScopeMapping(new java.util.HashMap) +{ + override def getScope(confs: Array[String]) = + { + Configurations.defaultMavenConfigurations.find(conf => confs.contains(conf.name)) match + { + case Some(conf) => conf.name + case None => + if(confs.isEmpty || confs(0) == Configurations.Default.name) + null + else + confs(0) + } + } + override def isOptional(confs: Array[String]) = confs.isEmpty || (confs.length == 1 && confs(0) == Configurations.Optional.name) +} \ No newline at end of file diff --git a/ivy/IvyConfigurations.scala b/ivy/IvyConfigurations.scala new file mode 100644 index 000000000..366917c92 --- /dev/null +++ b/ivy/IvyConfigurations.scala @@ -0,0 +1,33 @@ +/* sbt -- Simple Build Tool + * Copyright 2008, 2009 Mark Harrah + */ +package xsbt + +import java.io.File +import scala.xml.NodeSeq + +final class IvyPaths(val baseDirectory: File, val cacheDirectory: Option[File]) extends NotNull +final class IvyConfiguration(val paths: IvyPaths, val resolvers: Seq[Resolver], val log: IvyLogger) extends NotNull + +final class ModuleConfiguration(val module: ModuleID, val dependencies: Iterable[ModuleID], val ivyXML: NodeSeq, + val configurations: Iterable[Configuration], val defaultConfiguration: Option[Configuration], val ivyScala: Option[IvyScala], + val artifacts: Iterable[Artifact], val validate: Boolean) extends NotNull +{ + def isUnconfigured = dependencies.isEmpty && ivyXML.isEmpty && configurations.isEmpty && + defaultConfiguration.isEmpty && artifacts.isEmpty +} +object ModuleConfiguration +{ + def configurations(explicitConfigurations: Iterable[Configuration], defaultConfiguration: Option[Configuration]) = + if(explicitConfigurations.isEmpty) + { + defaultConfiguration match + { + case Some(Configurations.DefaultIvyConfiguration) => Configurations.Default :: Nil + case Some(Configurations.DefaultMavenConfiguration) => Configurations.defaultMavenConfigurations + case _ => Nil + } + } + else + explicitConfigurations +} \ No newline at end of file diff --git a/ivy/IvyInterface.scala b/ivy/IvyInterface.scala new file mode 100644 index 000000000..ae89d431b --- /dev/null +++ b/ivy/IvyInterface.scala @@ -0,0 +1,360 @@ +/* sbt -- Simple Build Tool + * Copyright 2008, 2009 Mark Harrah + */ +package xsbt + +import java.io.File +import java.net.{URI, URL} +import scala.xml.NodeSeq +import org.apache.ivy.plugins.resolver.IBiblioResolver +import org.apache.ivy.util.url.CredentialsStore + +final case class ModuleID(organization: String, name: String, revision: String, configurations: Option[String], isChanging: Boolean, isTransitive: Boolean, explicitArtifacts: Seq[Artifact]) extends NotNull +{ + override def toString = organization + ":" + name + ":" + revision + // () required for chaining + def notTransitive() = intransitive() + def intransitive() = ModuleID(organization, name, revision, configurations, isChanging, false, explicitArtifacts) + def changing() = ModuleID(organization, name, revision, configurations, true, isTransitive, explicitArtifacts) + def from(url: String) = artifacts(Artifact(name, new URL(url))) + def classifier(c: String) = artifacts(Artifact(name, c)) + def artifacts(newArtifacts: Artifact*) = ModuleID(organization, name, revision, configurations, isChanging, isTransitive, newArtifacts ++ explicitArtifacts) +} +object ModuleID +{ + def apply(organization: String, name: String, revision: String): ModuleID = ModuleID(organization, name, revision, None) + def apply(organization: String, name: String, revision: String, configurations: Option[String]): ModuleID = + ModuleID(organization, name, revision, configurations, false, true) + def apply(organization: String, name: String, revision: String, configurations: Option[String], isChanging: Boolean, isTransitive: Boolean): ModuleID = + ModuleID(organization, name, revision, configurations, isChanging, isTransitive, Nil) +} +sealed trait Resolver extends NotNull +{ + def name: String +} +sealed case class MavenRepository(name: String, root: String) extends Resolver +{ + override def toString = name + ": " + root +} + +object RepositoryHelpers +{ + final case class Patterns(ivyPatterns: Seq[String], artifactPatterns: Seq[String], isMavenCompatible: Boolean) extends NotNull + { + private[xsbt] def mavenStyle(): Patterns = Patterns(ivyPatterns, artifactPatterns, true) + private[xsbt] def withIvys(patterns: Seq[String]): Patterns = Patterns(patterns ++ ivyPatterns, artifactPatterns, isMavenCompatible) + private[xsbt] def withArtifacts(patterns: Seq[String]): Patterns = Patterns(ivyPatterns, patterns ++ artifactPatterns, isMavenCompatible) + } + final case class SshConnection(authentication: Option[SshAuthentication], hostname: Option[String], port: Option[Int]) extends NotNull + { + def copy(authentication: Option[SshAuthentication]) = SshConnection(authentication, hostname, port) + } + /** Configuration specific to an Ivy filesystem resolver. */ + final case class FileConfiguration(isLocal: Boolean, isTransactional: Option[Boolean]) extends NotNull + { + def transactional() = FileConfiguration(isLocal, Some(true)) + def nontransactional() = FileConfiguration(isLocal, Some(false)) + def nonlocal() = FileConfiguration(false, isTransactional) + } + sealed trait SshAuthentication extends NotNull + final case class PasswordAuthentication(user: String, password: String) extends SshAuthentication + final case class KeyFileAuthentication(keyfile: File, password: String) extends SshAuthentication +} +import RepositoryHelpers.{Patterns, SshConnection, FileConfiguration} +import RepositoryHelpers.{KeyFileAuthentication, PasswordAuthentication, SshAuthentication} + +/** sbt interface to an Ivy repository based on patterns, which is most Ivy repositories.*/ +sealed abstract class PatternsBasedRepository extends Resolver +{ + type RepositoryType <: PatternsBasedRepository + /** Should be implemented to create a new copy of this repository but with `patterns` as given.*/ + protected def copy(patterns: Patterns): RepositoryType + + /** The object representing the configured patterns for this repository. */ + def patterns: Patterns + + /** Enables maven 2 compatibility for this repository. */ + def mavenStyle() = copy(patterns.mavenStyle()) + /** Adds the given patterns for resolving/publishing Ivy files.*/ + def ivys(ivyPatterns: String*): RepositoryType = copy(patterns.withIvys(ivyPatterns)) + /** Adds the given patterns for resolving/publishing artifacts.*/ + def artifacts(artifactPatterns: String*): RepositoryType = copy(patterns.withArtifacts(artifactPatterns)) +} +/** sbt interface for an Ivy filesystem repository. More convenient construction is done using Resolver.file. */ +final case class FileRepository(name: String, configuration: FileConfiguration, patterns: Patterns) extends PatternsBasedRepository +{ + type RepositoryType = FileRepository + protected def copy(patterns: Patterns): FileRepository = FileRepository(name, configuration, patterns) + private def copy(configuration: FileConfiguration) = FileRepository(name, configuration, patterns) + def transactional() = copy(configuration.transactional()) + def nonlocal() = copy(configuration.nonlocal()) +} +final case class URLRepository(name: String, patterns: Patterns) extends PatternsBasedRepository +{ + type RepositoryType = URLRepository + protected def copy(patterns: Patterns): URLRepository = URLRepository(name, patterns) +} +/** sbt interface for an Ivy ssh-based repository (ssh and sftp). Requires the Jsch library.. */ +sealed abstract class SshBasedRepository extends PatternsBasedRepository +{ + type RepositoryType <: SshBasedRepository + protected def copy(connection: SshConnection): RepositoryType + private def copy(authentication: SshAuthentication): RepositoryType = copy(connection.copy(Some(authentication))) + + /** The object representing the configured ssh connection for this repository. */ + def connection: SshConnection + + /** Configures this to use the specified user name and password when connecting to the remote repository. */ + def as(user: String, password: String): RepositoryType = copy(new PasswordAuthentication(user, password)) + /** Configures this to use the specified keyfile and password for the keyfile when connecting to the remote repository. */ + def as(keyfile: File, password: String): RepositoryType = copy(new KeyFileAuthentication(keyfile, password)) +} +/** sbt interface for an Ivy repository over ssh. More convenient construction is done using Resolver.ssh. */ +final case class SshRepository(name: String, connection: SshConnection, patterns: Patterns, publishPermissions: Option[String]) extends SshBasedRepository +{ + type RepositoryType = SshRepository + protected def copy(patterns: Patterns): SshRepository = SshRepository(name, connection, patterns, publishPermissions) + protected def copy(connection: SshConnection): SshRepository = SshRepository(name, connection, patterns, publishPermissions) + /** Defines the permissions to set when publishing to this repository. */ + def withPermissions(publishPermissions: String): SshRepository = withPermissions(Some(publishPermissions)) + def withPermissions(publishPermissions: Option[String]): SshRepository = SshRepository(name, connection, patterns, publishPermissions) +} +/** sbt interface for an Ivy repository over sftp. More convenient construction is done using Resolver.sftp. */ +final case class SftpRepository(name: String, connection: SshConnection, patterns: Patterns) extends SshBasedRepository +{ + type RepositoryType = SftpRepository + protected def copy(patterns: Patterns): SftpRepository = SftpRepository(name, connection, patterns) + protected def copy(connection: SshConnection): SftpRepository = SftpRepository(name, connection, patterns) +} + +import Resolver._ +object ScalaToolsReleases extends MavenRepository(ScalaToolsReleasesName, ScalaToolsReleasesRoot) +object ScalaToolsSnapshots extends MavenRepository(ScalaToolsSnapshotsName, ScalaToolsSnapshotsRoot) +object DefaultMavenRepository extends MavenRepository("public", IBiblioResolver.DEFAULT_M2_ROOT) +object JavaNet1Repository extends Resolver +{ + def name = "java.net Maven1 Repository" +} + +object Resolver +{ + val ScalaToolsReleasesName = "Scala-Tools Maven2 Repository" + val ScalaToolsSnapshotsName = "Scala-Tools Maven2 Snapshots Repository" + val ScalaToolsReleasesRoot = "http://scala-tools.org/repo-releases" + val ScalaToolsSnapshotsRoot = "http://scala-tools.org/repo-snapshots" + + def withDefaultResolvers(userResolvers: Seq[Resolver]): Seq[Resolver] = + withDefaultResolvers(userResolvers, true) + def withDefaultResolvers(userResolvers: Seq[Resolver], scalaTools: Boolean): Seq[Resolver] = + withDefaultResolvers(userResolvers, true, scalaTools) + def withDefaultResolvers(userResolvers: Seq[Resolver], mavenCentral: Boolean, scalaTools: Boolean): Seq[Resolver] = + Seq(Resolver.defaultLocal) ++ + userResolvers ++ + single(DefaultMavenRepository, mavenCentral)++ + single(ScalaToolsReleases, scalaTools) + private def single[T](value: T, nonEmpty: Boolean): Seq[T] = if(nonEmpty) Seq(value) else Nil + + /** A base class for defining factories for interfaces to Ivy repositories that require a hostname , port, and patterns. */ + sealed abstract class Define[RepositoryType <: SshBasedRepository] extends NotNull + { + /** Subclasses should implement this method to */ + protected def construct(name: String, connection: SshConnection, patterns: Patterns): RepositoryType + /** Constructs this repository type with the given `name`. `basePatterns` are the initial patterns to use. A ManagedProject + * has an implicit defining these initial patterns based on a setting for either Maven or Ivy style patterns.*/ + def apply(name: String)(implicit basePatterns: Patterns): RepositoryType = + apply(name, None, None, None) + /** Constructs this repository type with the given `name` and `hostname`. `basePatterns` are the initial patterns to use. + * A ManagedProject has an implicit defining these initial patterns based on a setting for either Maven or Ivy style patterns.*/ + def apply(name: String, hostname: String)(implicit basePatterns: Patterns): RepositoryType = + apply(name, Some(hostname), None, None) + /** Constructs this repository type with the given `name`, `hostname`, and the `basePath` against which the initial + * patterns will be resolved. `basePatterns` are the initial patterns to use. + * A ManagedProject has an implicit defining these initial patterns based on a setting for either Maven or Ivy style patterns.*/ + def apply(name: String, hostname: String, basePath: String)(implicit basePatterns: Patterns): RepositoryType = + apply(name, Some(hostname), None, Some(basePath)) + /** Constructs this repository type with the given `name`, `hostname`, and `port`. `basePatterns` are the initial patterns to use. + * A ManagedProject has an implicit defining these initial patterns based on a setting for either Maven or Ivy style patterns.*/ + def apply(name: String, hostname: String, port: Int)(implicit basePatterns: Patterns): RepositoryType = + apply(name, Some(hostname), Some(port), None) + /** Constructs this repository type with the given `name`, `hostname`, `port`, and the `basePath` against which the initial + * patterns will be resolved. `basePatterns` are the initial patterns to use. + * A ManagedProject has an implicit defining these initial patterns based on a setting for either Maven or Ivy style patterns.*/ + def apply(name: String, hostname: String, port: Int, basePath: String)(implicit basePatterns: Patterns): RepositoryType = + apply(name, Some(hostname), Some(port), Some(basePath)) + /** Constructs this repository type with the given `name`, `hostname`, `port`, and the `basePath` against which the initial + * patterns will be resolved. `basePatterns` are the initial patterns to use. All but the `name` are optional (use None). + * A ManagedProject has an implicit defining these initial patterns based on a setting for either Maven or Ivy style patterns.*/ + def apply(name: String, hostname: Option[String], port: Option[Int], basePath: Option[String])(implicit basePatterns: Patterns): RepositoryType = + construct(name, SshConnection(None, hostname, port), resolvePatterns(basePath, basePatterns)) + } + /** A factory to construct an interface to an Ivy SSH resolver.*/ + object ssh extends Define[SshRepository] + { + protected def construct(name: String, connection: SshConnection, patterns: Patterns) = SshRepository(name, connection, patterns, None) + } + /** A factory to construct an interface to an Ivy SFTP resolver.*/ + object sftp extends Define[SftpRepository] + { + protected def construct(name: String, connection: SshConnection, patterns: Patterns) = SftpRepository(name, connection, patterns) + } + /** A factory to construct an interface to an Ivy filesytem resolver. */ + object file + { + /** Constructs a file resolver with the given name. The patterns to use must be explicitly specified + * using the `ivys` or `artifacts` methods on the constructed resolver object.*/ + def apply(name: String): FileRepository = FileRepository(name, defaultFileConfiguration, ivyStylePatterns) + /** Constructs a file resolver with the given name and base directory. */ + def apply(name: String, baseDirectory: File)(implicit basePatterns: Patterns): FileRepository = + baseRepository(baseDirectory.toURI)(FileRepository(name, defaultFileConfiguration, _)) + } + object url + { + /** Constructs a URL resolver with the given name. The patterns to use must be explicitly specified + * using the `ivys` or `artifacts` methods on the constructed resolver object.*/ + def apply(name: String): URLRepository = URLRepository(name, ivyStylePatterns) + /** Constructs a file resolver with the given name and base directory. */ + def apply(name: String, baseURL: URL)(implicit basePatterns: Patterns): URLRepository = + baseRepository(baseURL.toURI)(URLRepository(name, _)) + } + private def baseRepository[T](baseURI: java.net.URI)(construct: Patterns => T)(implicit basePatterns: Patterns): T = + construct(resolvePatterns(baseURI.normalize, basePatterns)) + + /** If `base` is None, `patterns` is returned unchanged. + * Otherwise, the ivy file and artifact patterns in `patterns` are resolved against the given base. */ + private def resolvePatterns(base: Option[String], patterns: Patterns): Patterns = + base match + { + case Some(path) => resolvePatterns(pathURI(path), patterns) + case None => patterns + } + /** Resolves the ivy file and artifact patterns in `patterns` against the given base. */ + private def resolvePatterns(base: URI, basePatterns: Patterns): Patterns = + { + def resolve(pattern: String) = base.resolve(pathURI(pattern)).getPath + def resolveAll(patterns: Seq[String]) = patterns.map(resolve) + Patterns(resolveAll(basePatterns.ivyPatterns), resolveAll(basePatterns.artifactPatterns), basePatterns.isMavenCompatible) + } + /** Constructs a `URI` with the path component set to `path` and the other components set to null.*/ + private def pathURI(path: String) = new URI(null, null, path, null) + + def defaultFileConfiguration = FileConfiguration(true, None) + def mavenStylePatterns = Patterns(Nil, mavenStyleBasePattern :: Nil, true) + def ivyStylePatterns = Patterns(Nil, Nil, false) + + def defaultPatterns = mavenStylePatterns + def mavenStyleBasePattern = "[organisation]/[module]/[revision]/[artifact]-[revision](-[classifier]).[ext]" + def localBasePattern = "[organisation]/[module]/[revision]/[type]s/[artifact].[ext]" + + def userRoot = System.getProperty("user.home") + def userMavenRoot = userRoot + "/.m2/repository/" + def userIvyRoot = userRoot + "/.ivy2/" + + def defaultLocal = defaultUserFileRepository("local") + def defaultShared = defaultUserFileRepository("shared") + def defaultUserFileRepository(id: String) = file(id, new File(userIvyRoot, id))(defaultIvyPatterns) + def defaultIvyPatterns = + { + val pList = List(localBasePattern) + Patterns(pList, pList, false) + } +} + +object Configurations +{ + def config(name: String) = new Configuration(name) + def defaultMavenConfigurations = Compile :: Runtime :: Test :: Provided :: System :: Optional :: Sources :: Javadoc :: Nil + + lazy val Default = config("default") + lazy val Compile = config("compile") + lazy val IntegrationTest = config("it") hide + lazy val Provided = config("provided") + lazy val Javadoc = config("javadoc") + lazy val Runtime = config("runtime") + lazy val Test = config("test") hide + lazy val Sources = config("sources") + lazy val System = config("system") + lazy val Optional = config("optional") + + lazy val CompilerPlugin = config("plugin") hide + + private[xsbt] val DefaultMavenConfiguration = defaultConfiguration(true) + private[xsbt] val DefaultIvyConfiguration = defaultConfiguration(false) + private[xsbt] def DefaultConfiguration(mavenStyle: Boolean) = if(mavenStyle) DefaultMavenConfiguration else DefaultIvyConfiguration + private[xsbt] def defaultConfiguration(mavenStyle: Boolean) = + { + val base = if(mavenStyle) Configurations.Compile else Configurations.Default + config(base.name + "->default(compile)") + } + + private[xsbt] def removeDuplicates(configs: Iterable[Configuration]) = Set(scala.collection.mutable.Map(configs.map(config => (config.name, config)).toSeq: _*).values.toList: _*) +} +/** Represents an Ivy configuration. */ +final case class Configuration(name: String, description: String, isPublic: Boolean, extendsConfigs: List[Configuration], transitive: Boolean) extends NotNull +{ + require(name != null && !name.isEmpty) + require(description != null) + def this(name: String) = this(name, "", true, Nil, true) + def describedAs(newDescription: String) = Configuration(name, newDescription, isPublic, extendsConfigs, transitive) + def extend(configs: Configuration*) = Configuration(name, description, isPublic, configs.toList ::: extendsConfigs, transitive) + def notTransitive = intransitive + def intransitive = Configuration(name, description, isPublic, extendsConfigs, false) + def hide = Configuration(name, description, false, extendsConfigs, transitive) + override def toString = name +} + +final case class Artifact(name: String, `type`: String, extension: String, classifier: Option[String], configurations: Iterable[Configuration], url: Option[URL]) extends NotNull +object Artifact +{ + def apply(name: String): Artifact = Artifact(name, defaultType, defaultExtension, None, Nil, None) + def apply(name: String, classifier: String): Artifact = Artifact(name, defaultType, defaultExtension, Some(classifier), Nil, None) + def apply(name: String, `type`: String, extension: String): Artifact = Artifact(name, `type`, extension, None, Nil, None) + def apply(name: String, url: URL): Artifact =Artifact(name, extract(url, defaultType), extract(url, defaultExtension), None, Nil, Some(url)) + val defaultExtension = "jar" + val defaultType = "jar" + private[this] def extract(url: URL, default: String) = + { + val s = url.toString + val i = s.lastIndexOf('.') + if(i >= 0) + s.substring(i+1) + else + default + } +} +/* +object Credentials +{ + /** Add the provided credentials to Ivy's credentials cache.*/ + def add(realm: String, host: String, userName: String, passwd: String): Unit = + CredentialsStore.INSTANCE.addCredentials(realm, host, userName, passwd) + /** Load credentials from the given file into Ivy's credentials cache.*/ + def apply(file: String, log: Logger): Unit = apply(Path.fromFile(file), log) + /** Load credentials from the given file into Ivy's credentials cache.*/ + def apply(file: File, log: Logger): Unit = apply(Path.fromFile(file), log) + /** Load credentials from the given file into Ivy's credentials cache.*/ + def apply(path: Path, log: Logger) + { + val msg = + if(path.exists) + { + val properties = new scala.collection.mutable.HashMap[String, String] + def get(keys: List[String]) = keys.flatMap(properties.get).firstOption.toRight(keys.head + " not specified in credentials file: " + path) + + impl.MapUtilities.read(properties, path, log) orElse + { + List.separate( List(RealmKeys, HostKeys, UserKeys, PasswordKeys).map(get) ) match + { + case (Nil, List(realm, host, user, pass)) => add(realm, host, user, pass); None + case (errors, _) => Some(errors.mkString("\n")) + } + } + } + else + Some("Credentials file " + path + " does not exist") + msg.foreach(x => log.warn(x)) + } + private[this] val RealmKeys = List("realm") + private[this] val HostKeys = List("host", "hostname") + private[this] val UserKeys = List("user", "user.name", "username") + private[this] val PasswordKeys = List("password", "pwd", "pass", "passwd") +}*/ \ No newline at end of file diff --git a/ivy/IvyLogger.scala b/ivy/IvyLogger.scala new file mode 100644 index 000000000..ff3ad2f19 --- /dev/null +++ b/ivy/IvyLogger.scala @@ -0,0 +1,54 @@ +/* sbt -- Simple Build Tool + * Copyright 2008, 2009 Mark Harrah + */ +package xsbt + +import org.apache.ivy.util.{Message, MessageLogger} + +trait IvyLogger +{ + def info(msg: => String) + def debug(msg: => String) + def warn(msg: => String) + def error(msg: => String) + def verbose(msg: => String) +} + +/** Interface to Ivy logging. */ +private final class IvyLoggerInterface(logger: IvyLogger) extends MessageLogger +{ + def rawlog(msg: String, level: Int) = log(msg, level) + def log(msg: String, level: Int) + { + import Message.{MSG_DEBUG, MSG_VERBOSE, MSG_INFO, MSG_WARN, MSG_ERR} + level match + { + case MSG_DEBUG => debug(msg) + case MSG_VERBOSE => verbose(msg) + case MSG_INFO => info(msg) + case MSG_WARN => warn(msg) + case MSG_ERR => error(msg) + } + } + def debug(msg: String) = logger.debug(msg) + def verbose(msg: String) = logger.verbose(msg) + def deprecated(msg: String) = warn(msg) + def info(msg: String) = logger.info(msg) + def rawinfo(msg: String) = info(msg) + def warn(msg: String) = logger.warn(msg) + def error(msg: String) = logger.error(msg) + + private def emptyList = java.util.Collections.emptyList[T forSome { type T}] + def getProblems = emptyList + def getWarns = emptyList + def getErrors = emptyList + + def clearProblems = () + def sumupProblems = () + def progress = () + def endProgress = () + + def endProgress(msg: String) = info(msg) + def isShowProgress = false + def setShowProgress(progress: Boolean) {} +} diff --git a/ivy/IvyScala.scala b/ivy/IvyScala.scala new file mode 100644 index 000000000..0f3332d34 --- /dev/null +++ b/ivy/IvyScala.scala @@ -0,0 +1,74 @@ +/* sbt -- Simple Build Tool + * Copyright 2008, 2009 Mark Harrah + */ +package xsbt + +import java.util.Collections +import scala.collection.mutable.HashSet + +import org.apache.ivy.{core, plugins} +import core.module.descriptor.{DefaultExcludeRule, ExcludeRule} +import core.module.descriptor.{DefaultModuleDescriptor, ModuleDescriptor} +import core.module.id.{ArtifactId,ModuleId, ModuleRevisionId} +import plugins.matcher.ExactPatternMatcher + +final class IvyScala(val scalaVersion: String, val configurations: Iterable[Configuration], val checkExplicit: Boolean, val filterImplicit: Boolean) extends NotNull +private object IvyScala +{ + val ScalaOrganization = "org.scala-lang" + val ScalaLibraryID = "scala-library" + val ScalaCompilerID = "scala-compiler" + + /** Performs checks/adds filters on Scala dependencies (if enabled in IvyScala). */ + def checkModule(module: DefaultModuleDescriptor, conf: String)(check: IvyScala) + { + if(check.checkExplicit) + checkDependencies(module, check.scalaVersion, check.configurations) + if(check.filterImplicit) + excludeScalaJars(module, check.configurations) + } + /** Checks the immediate dependencies of module for dependencies on scala jars and verifies that the version on the + * dependencies matches scalaVersion. */ + private def checkDependencies(module: ModuleDescriptor, scalaVersion: String, configurations: Iterable[Configuration]) + { + val configSet = configurationSet(configurations) + for(dep <- module.getDependencies.toList) + { + val id = dep.getDependencyRevisionId + if(id.getOrganisation == ScalaOrganization && id.getRevision != scalaVersion && dep.getModuleConfigurations.exists(configSet.contains)) + error("Different Scala version specified in dependency ("+ id.getRevision + ") than in project (" + scalaVersion + ").") + } + } + private def configurationSet(configurations: Iterable[Configuration]) = HashSet(configurations.map(_.toString).toSeq : _*) + /** Adds exclusions for the scala library and compiler jars so that they are not downloaded. This is + * done because normally these jars are already on the classpath and cannot/should not be overridden. The version + * of Scala to use is done by setting scala.version in the project definition. */ + private def excludeScalaJars(module: DefaultModuleDescriptor, configurations: Iterable[Configuration]) + { + val configurationNames = + { + val names = module.getConfigurationsNames + if(configurations.isEmpty) + names + else + { + val configSet = configurationSet(configurations) + configSet.intersect(HashSet(names : _*)) + configSet.toArray + } + } + def excludeScalaJar(name: String): Unit = + module.addExcludeRule(excludeRule(ScalaOrganization, name, configurationNames)) + excludeScalaJar(ScalaLibraryID) + excludeScalaJar(ScalaCompilerID) + } + /** Creates an ExcludeRule that excludes artifacts with the given module organization and name for + * the given configurations. */ + private def excludeRule(organization: String, name: String, configurationNames: Iterable[String]): ExcludeRule = + { + val artifact = new ArtifactId(ModuleId.newInstance(organization, name), "*", "*", "*") + val rule = new DefaultExcludeRule(artifact, ExactPatternMatcher.INSTANCE, Collections.emptyMap[AnyRef,AnyRef]) + configurationNames.foreach(rule.addConfiguration) + rule + } +} \ No newline at end of file diff --git a/notes b/notes new file mode 100644 index 000000000..730c87dcf --- /dev/null +++ b/notes @@ -0,0 +1,32 @@ +Goals/Guidelines for xsbt +===== +As usual: + - Immutable interfaces + - Typesafe + - Robust, flexible API + +Task engine +- method tasks will be normal tasks that pull the command line from a CommandLine task +- possibly have per task logging, including configuration (e.g. 'debug compile') +- unnamed tasks log to parent task +- in parallel, optionally one task always logging + +- boot interface contains static final int version = N that main xsbt can use to check if it can be loaded by that version (a lower bound check) +- main xsbt has static final int version = N that boot can use to check if it can load that version (a lower bound check) +- Have Interfaces subproject that depends on no other project and defines interfaces in package xsbti. They are written in Java and cannot refer to Scala classes (compileOrder = JavaThenScala). These interfaces are loaded by the root loader and can be used to pass objects across ClassLoader boundaries. +- launcher/main interface is not static (no system properties!) +- simple, well-defined ClassLoaders +- use Exceptions instead of Option/Either +- every component gets its own subproject +- can use any version of compiler/Scala that is source compatible + - requires CrossLogger that can interface across ClassLoader boundaries with reflection +- Logger passed by implicit parameter +- build using normal cross-build conventions +- compiler: raw interface (no dependency analysis) or with dependency analysis +- compiler: can specify scala-library.jar and scala-compiler.jar + version instead of retrieving the ClassLoader +- minimal dependence on main xsbt logger from subcomponents: use thin interface for subcomponents and implement interface in separate files in main xsbt + +Dependency Management +- drop explicit managers +- resolvers are completely defined in project definition (use Resolver.withDefaultResolvers) +- configurations completely defined within project (use ModuleConfiguration.configurations) diff --git a/project/build.properties b/project/build.properties new file mode 100644 index 000000000..2597cae5b --- /dev/null +++ b/project/build.properties @@ -0,0 +1,7 @@ +#Project Properties +#Sat Aug 15 11:30:36 EDT 2009 +project.name=xsbt +project.organization=org.scala-tools.sbt +sbt.version=0.5.3-p1 +scala.version=2.7.5 +project.version=0.7 diff --git a/project/build/XSbt.scala b/project/build/XSbt.scala new file mode 100644 index 000000000..662a250f4 --- /dev/null +++ b/project/build/XSbt.scala @@ -0,0 +1,35 @@ +import sbt._ + +class XSbt(info: ProjectInfo) extends ParentProject(info) +{ + def utilPath = path("util") + + val controlSub = project(utilPath / "control", "Control", new Base(_)) + val collectionSub = project(utilPath / "collection", "Collections", new Base(_)) + val ioSub = project(utilPath / "io", "IO", new Base(_),controlSub) + val classpathSub = project(utilPath / "classpath", "Classpath", new Base(_)) + + val ivySub = project("ivy", "Ivy", new IvyProject(_)) + val logSub = project(utilPath / "log", "Logging", new Base(_)) + + val taskSub = project("tasks", "Tasks", new TaskProject(_), controlSub, collectionSub) + val cacheSub = project("cache", "Cache", new CacheProject(_), taskSub, ioSub) + + override def parallelExecution = true + class TaskProject(info: ProjectInfo) extends Base(info) + { + val sc = "org.scala-tools.testing" % "scalacheck" % "1.5" % "test->default" + } + class CacheProject(info: ProjectInfo) extends Base(info) + { + //override def compileOptions = super.compileOptions ++ List(Unchecked,ExplainTypes, CompileOption("-Xlog-implicits")) + } + class Base(info: ProjectInfo) extends DefaultProject(info) with AssemblyProject + { + override def scratch = true + } + class IvyProject(info: ProjectInfo) extends Base(info) + { + val ivy = "org.apache.ivy" % "ivy" % "2.0.0" + } +} \ No newline at end of file diff --git a/tasks/ParallelRunner.scala b/tasks/ParallelRunner.scala new file mode 100644 index 000000000..beeec76fe --- /dev/null +++ b/tasks/ParallelRunner.scala @@ -0,0 +1,190 @@ +/* sbt -- Simple Build Tool + * Copyright 2009 Mark Harrah + */ +package xsbt + +/** This file provides the parallel execution engine of sbt. It is a fairly general module, with pluggable Schedulers and Strategies. +* +* There are three main componenets to the engine: Distributors, Schedulers, and Strategies. +* +* A Scheduler provides work that is ready to execute. +* +* A Strategy is used by a Scheduler to select the work to process from the work that is ready. It is notified as work +* becomes ready. It is requested to select work to process from the work that is ready. +* +* A Distributor uses a Scheduler to obtain work up to the maximum work allowed to run at once. It runs each +* unit of work in its own Thread. It then returns the work and either the computed value or the error that occured. +* +* The Scheduler and Strategy are called from the main thread and therefore do not need to be thread-safe. +**/ + +import java.util.concurrent.LinkedBlockingQueue +import scala.collection.{immutable, mutable} +import immutable.TreeSet + +/** Processes work. */ +trait Compute[Work[_],Result[_]] { def apply[A](w: Work[A]): Result[A] } +/** Requests work from `scheduler` and processes it using `compute`. This class limits the amount of work processing at any given time +* to `workers`.*/ +final class Distributor[O,Work[_],Result[_]](val scheduler: Scheduler[O,Work,Result], compute: Compute[Work,Result], workers: Int) extends NotNull +{ + require(workers > 0) + final def run() = (new Run).run() + + private final class Run extends NotNull + { + import java.util.concurrent.LinkedBlockingQueue + private[this] val schedule = scheduler.run + /** The number of threads currently running. */ + private[this] var running = 0 + /** Pending notifications of completed work. */ + private[this] val complete = new LinkedBlockingQueue[Done[_]] + + private[Distributor] def run(): O = + { + def runImpl(): O = + { + next() + if(isIdle && !schedule.hasPending) // test if all work is complete + { + assume(schedule.isComplete, "Distributor idle and the scheduler indicated no work pending, but scheduler indicates it is not complete.") + schedule.result + } + else + { + waitForCompletedWork() // wait for some work to complete + runImpl() // continue + } + } + try { runImpl() } + finally { shutdown() } + } + private def shutdown(): Unit = all.foreach(_.work.put(None)) + // true if the maximum number of worker threads are currently running + private def atMaximum = running == workers + private def availableWorkers = workers - running + // true if no worker threads are currently running + private def isIdle = running == 0 + // process more work + private def next() + { + // if the maximum threads are being used, do nothing + // if all work is complete or the scheduler is waiting for current work to complete, do nothing + if(!atMaximum && schedule.hasPending) + { + val nextWork = schedule.next(availableWorkers) + val nextSize = nextWork.size + assume(nextSize <= availableWorkers, "Scheduler provided more work (" + nextSize + ") than allowed (" + availableWorkers + ")") + assume(nextSize > 0 || !isIdle, "Distributor idle and the scheduler indicated work pending, but provided no work.") + nextWork.foreach(work => process(work)) + } + } + // wait on the blocking queue `complete` until some work finishes and notify the scheduler + private def waitForCompletedWork() + { + assume(running > 0) + val done = complete.take() + running -= 1 + notifyScheduler(done) + } + private def notifyScheduler[T](done: Done[T]): Unit = schedule.complete(done.work, done.result) + private def process[T](work: Work[T]) + { + assume(running + 1 <= workers) + running += 1 + available.take().work.put(Some(work)) + } + private[this] val all = List.tabulate(workers, i => new Worker) + private[this] val available = + { + val q = new LinkedBlockingQueue[Worker] + all.foreach(q.put) + q + } + private final class Worker extends Thread with NotNull + { + lazy val work = + { + start() + new LinkedBlockingQueue[Option[Work[_]]] + } + override def run() + { + def processData[T](data: Work[T]) + { + val result = ErrorHandling.wideConvert(compute(data)) + complete.put( new Done(result, data) ) + } + def runImpl() + { + work.take() match + { + case Some(data) => + processData(data) + available.put(this) + runImpl() + case None => () + } + } + try { runImpl() } + catch { case e: InterruptedException => () } + } + } + } + private final class Done[T](val result: Either[Throwable, Result[T]], val work: Work[T]) extends NotNull +} +/** Schedules work of type Work that produces results of type Result. A Scheduler determines what work is ready to be processed. +* A Scheduler is itself immutable. It creates a mutable object for each scheduler run.*/ +trait Scheduler[O,Work[_],Result[_]] extends NotNull +{ + /** Starts a new run. The returned object is a new Run, representing a single scheduler run. All state for the run + * is encapsulated in this object.*/ + def run: Run + trait Run extends NotNull + { + /** Notifies this scheduler that work has completed with the given result.*/ + def complete[A](d: Work[A], result: Either[Throwable,Result[A]]): Unit + /** Returns true if there is any more work to be done, although remaining work can be blocked + * waiting for currently running work to complete.*/ + def hasPending: Boolean + /**Returns true if this scheduler has no more work to be done, ever.*/ + def isComplete: Boolean + /** Returns up to 'max' units of work. `max` is always positive. The returned sequence cannot be empty if there is + * no work currently being processed.*/ + def next(max: Int): Seq[Work[_]] + /** The final result after all work has completed. */ + def result: O + } +} +/** A Strategy selects the work to process from work that is ready to be processed.*/ +trait ScheduleStrategy[D] extends NotNull +{ + /** Starts a new run. The returned object is a new Run, representing a single strategy run. All state for the run + * is handled through this object and is encapsulated in this object.*/ + def run: Run + trait Run extends NotNull + { + /** Adds the given work to the list of work that is ready to run.*/ + def workReady(dep: D): Unit + /** Returns true if there is work ready to be run. */ + def hasReady: Boolean + /** Provides up to `max` units of work. `max` is always positive and this method is not called + * if hasReady is false. The returned list cannot be empty is there is work ready to be run.*/ + def next(max: Int): List[D] + } +} +final class SimpleStrategy[D] extends ScheduleStrategy[D] +{ + def run = new Run + { + private var ready = List[D]() + def workReady(dep: D) { ready ::= dep } + def hasReady = !ready.isEmpty + def next(max: Int): List[D] = + { + val ret = ready.take(max) + ready = ready.drop(max) + ret + } + } +} \ No newline at end of file diff --git a/tasks/Task.scala b/tasks/Task.scala new file mode 100644 index 000000000..0b99198ac --- /dev/null +++ b/tasks/Task.scala @@ -0,0 +1,145 @@ +package xsbt + +import Task.{mapTask,bindTask, ITask} +import scala.collection.{mutable,immutable} + +sealed abstract class Task[O] extends Identity +{ + type Input + def dependencies: TreeHashSet[Task[_]] // IMPORTANT!! immutable.HashSet is NOT suitable. It has issues with multi-threaded access + def map[N](f: O => N): ITask[O,N] + def bind[N](f: O => Task[N]): ITask[O,N] + def dependsOn(addDependencies: Task[_]*): ITask[Input,O] + def named(s: String): ITask[Input,O] +} +private final class M[I,O,R <: Result[O]](name: Option[String]) + (val dependencies: TreeHashSet[Task[_]])(val extract: Results => I)(val compute: I => R) extends Task[O] +{ + type Input = I + def this(dependencies: Task[_]*)(extract: Results => I)(compute: I => R) = + this(None)(TreeHashSet(dependencies: _*))(extract)(compute) + + final def dependsOn(addDependencies: Task[_]*) = new M(name)(dependencies ++ addDependencies)(extract)(compute) + final def map[N](f: O => N) = mapTask(this)(_(this))(f) + final def bind[N](f: O => Task[N]) = bindTask(this)(_(this))(f) + final def named(s: String) = + name match + { + case Some(n) => error("Cannot rename task already named '" + n + "'. (Tried to rename it to '" + s + "')") + case None => new M(Some(s))(dependencies)(extract)(compute) + } + final override def toString = "Task " + name.getOrElse("") +} +abstract class Identity extends NotNull +{ + final override def equals(o: Any) = o match { case a: AnyRef => this eq a; case _ => false } + final override def hashCode = System.identityHashCode(this) +} + +private trait Results extends NotNull +{ + def apply[O](task: Task[O]): O + def contains(task: Task[_]): Boolean +} + +private sealed trait Result[O] extends NotNull +private final case class NewTask[O](t: Task[O]) extends Result[O] +private final case class Value[O](t: O) extends Result[O] + +object Task +{ + type ITask[I,O] = Task[O] { type Input = I } + import Function.tupled + def apply[O](o: => O): ITask[Unit,O] = + new M[Unit,O,Value[O]]()(r => ())( u => Value(o) ) + def bindTask[I,O](dependencies: Task[_]*)(extract: Results => I)(compute: I => Task[O]): ITask[I,O] = + new M[I,O,NewTask[O]](dependencies : _*)(extract)(in => NewTask(compute(in))) + def mapTask[I,O](dependencies: Task[_]*)(extract: Results => I)(compute: I => O): ITask[I,O] = + new M[I,O,Value[O]](dependencies : _*)(extract)(in => Value(compute(in))) + + private[xsbt] def extract[I,O](t: ITask[I,O], results: Results): I = t match { case m: M[I,O,_] => m.extract(results) } + private[xsbt] def compute[I,O](t: ITask[I,O], input: I): Result[O] = t match { case m: M[I,O,_] => m.compute(input) } + + implicit def iterableToForkBuilder[A](t: Iterable[A]): ForkBuilderIterable[A] = new ForkBuilderIterable(t) + final class ForkBuilderIterable[A] private[Task](a: Iterable[A]) extends NotNull + { + def fork[X](f: A => X): Iterable[ITask[Unit,X]] = a.map(x => Task(f(x))) + def reduce(f: (A,A) => A): Task[A] = fork(x => x) reduce(f) + } + + implicit def iterableToBuilder[O](t: Iterable[Task[O]]): BuilderIterable[O] = new BuilderIterable(t) + final class BuilderIterable[O] private[Task](a: Iterable[Task[O]]) extends NotNull + { + //def mapBind[X](f: O => Task[_,X]): Iterable[Task[O,XO]] = a.map(_.bind(f)) + def join: Task[Iterable[O]] = join(identity[O]) + def join[X](f: O => X): Task[Iterable[X]] = mapTask(a.toSeq: _*)( r => a.map(t => r(t)) )(_.map(f)) + //def bindJoin[X](f: O => Task[_,X]): Task[Iterable[X],Iterable[X]] = mapBind(f).join + def reduce(f: (O,O) => O): Task[O] = + { + def reduce2(list: List[Task[O]], accumulate: List[Task[O]]): List[Task[O]] = + list match + { + case Nil => accumulate + case x :: Nil => x :: accumulate + case xa :: xb :: tail => reduce2(tail, ( (xa, xb) map f ) :: accumulate ) + } + def reduce1(list: List[Task[O]]): Task[O] = + list match + { + case Nil => error("Empty list") + case x :: Nil => x + case _ => reduce1(reduce2(list, Nil)) + } + reduce1(a.toList) + } + } + + import metascala.HLists.{HList,HNil,HCons} + sealed trait TList + { + type Head + type Tail <: TList + type HListType <: HList + def tasks: List[Task[_]] + def get(results: Results): HListType + } + final class TNil extends TList + { + type Head = Nothing + type Tail = TNil + type HListType = HNil + def ::[A](t: Task[A]) = TCons[A,HNil,TNil](t, this) + def tasks = Nil + def get(results: Results) = HNil + } + final case class TCons[H, HL <: HList, T <: TList { type HListType = HL}](head: Task[H], tail: T) extends TList + { + type Head = H + type Tail = T + type This = TCons[H,HL,T] + type HListType = HCons[H,HL] + def ::[A](t: Task[A]) = TCons[A,HListType,This](t, this) + def tasks = head :: tail.tasks + def get(results: Results) = HCons(results(head), tail.get(results)) + + def map[X](f: HListType => X): ITask[HListType,X] = mapTask(tasks: _*)(get)(f) + def bind[X](f: HListType => Task[X]): ITask[HListType,X] = bindTask(tasks: _*)(get)(f) + def join: ITask[HListType,HListType] = map(identity[HListType]) + } + val TNil = new TNil + + implicit def twoToBuilder[A,B](t: (Task[A], Task[B]) ): Builder2[A,B] = + t match { case (a,b) => new Builder2(a,b) } + final class Builder2[A,B] private[Task](a: Task[A], b: Task[B]) extends NotNull + { + def map[X](f: (A,B) => X): ITask[(A,B),X] = mapTask(a,b)(r => (r(a), r(b)))(tupled(f)) + def bind[X](f: (A,B) => Task[X]): ITask[(A,B),X] = bindTask(a,b)( r => (r(a), r(b)) )(tupled(f)) + } + + implicit def threeToBuilder[A,B,C](t: (Task[A], Task[B], Task[C])): Builder3[A,B,C] = t match { case (a,b,c) => new Builder3(a,b,c) } + final class Builder3[A,B,C] private[Task](a: Task[A], b: Task[B], c: Task[C]) extends NotNull + { + def map[X](f: (A,B,C) => X): ITask[(A,B,C),X] = mapTask(a,b,c)( r => (r(a), r(b), r(c)) )(tupled(f)) + def bind[X](f: (A,B,C) => Task[X]): ITask[(A,B,C),X] = bindTask(a,b,c)( r => (r(a), r(b), r(c)) )(tupled(f)) + } +} diff --git a/tasks/TaskListener.scala b/tasks/TaskListener.scala new file mode 100644 index 000000000..b8db525fa --- /dev/null +++ b/tasks/TaskListener.scala @@ -0,0 +1,33 @@ +package xsbt + +trait TaskListener extends NotNull +{ + def added(t: Task[_]): Unit + def runnable(t: Task[_]): Unit + def running(t: Task[_]): Unit + def calling(caller: Task[_], t: Task[_]): Unit + def called(caller: Task[_], t: Task[_]): Unit + def completed[T](t: Task[T], value: Option[T]): Unit + def failed[T](t: Task[T], exception: Throwable): Unit +} +class BasicTaskListener extends TaskListener +{ + def added(t: Task[_]) {} + def runnable(t: Task[_]) {} + def running(t: Task[_]) {} + def calling(caller: Task[_], t: Task[_]) {} + def called(caller: Task[_], t: Task[_]) {} + def completed[T](t: Task[T], value: Option[T]) {} + def failed[T](t: Task[T], exception: Throwable) {} +} +class DebugTaskListener extends TaskListener +{ + def added(t: Task[_]) { debug("Added " + t) } + def runnable(t: Task[_]) { debug("Runnable " + t)} + def running(t: Task[_]) { debug("Running " + t) } + def calling(caller: Task[_], t: Task[_]) { debug(caller + " calling " + t)} + def called(caller: Task[_], t: Task[_]) { debug(caller + " called " + t)} + def completed[T](t: Task[T], value: Option[T]) { debug("Completed " + t + " with " + value)} + def failed[T](t: Task[T], exception: Throwable) { debug("Failed " + t + " with " + exception.toString); exception.printStackTrace } + private def debug(msg: String) { println(msg) } +} \ No newline at end of file diff --git a/tasks/TaskRunner.scala b/tasks/TaskRunner.scala new file mode 100644 index 000000000..71e69f912 --- /dev/null +++ b/tasks/TaskRunner.scala @@ -0,0 +1,17 @@ +package xsbt + +object TaskRunner +{ + def apply[T](node: Task[T]): Either[ List[WorkFailure[Task[_]]] , T ] = apply(node, Runtime.getRuntime.availableProcessors) + /** Executes work for nodes in a directed acyclic graph with root node `node`. + * The maximum number of tasks to execute simultaneously is `maximumTasks`. */ + def apply[T](node: Task[T], maximumTasks: Int): Either[ List[WorkFailure[Task[_]]] , T ] = + { + require(maximumTasks > 0) + val compute = new Compute[Work.Job, Result] { def apply[A](w: Work.Job[A]) = w.apply } + val strategy = new SimpleStrategy[Work[_,_]] + val scheduler = new TaskScheduler(node, strategy, new BasicTaskListener) + val distributor = new Distributor[ Either[ List[WorkFailure[Task[_]]], T ] , Work.Job, Result](scheduler, compute, maximumTasks) + distributor.run() + } +} \ No newline at end of file diff --git a/tasks/TaskScheduler.scala b/tasks/TaskScheduler.scala new file mode 100644 index 000000000..a04406cf8 --- /dev/null +++ b/tasks/TaskScheduler.scala @@ -0,0 +1,243 @@ +package xsbt + +import scala.collection.{immutable,mutable} +import Task.ITask + +final case class WorkFailure[D](work: D, exception: Throwable) extends NotNull +{ + def map[C](f: D => C) = WorkFailure(f(work), exception) +} +private final class TaskScheduler[O](root: Task[O], strategy: ScheduleStrategy[Work[_,_]], newListener: => TaskListener) + extends Scheduler[ Either[ List[WorkFailure[Task[_]]], O ], Work.Job, Result] +{ + def run = new Run + { + val listener = newListener + def result = + { + assume(reverseDeps.isEmpty) + assume(forwardDeps.isEmpty) + assume(calls.isEmpty) + assume(!strategyRun.hasReady) + if(failureReports.isEmpty) + Right(completed(root)) + else + Left(failureReports.toList) + } + def next(max: Int) = + { + val running = strategyRun.next(max) + running.foreach(r => listener.running(r.source)) + running + } + def isComplete = reverseDeps.isEmpty + def hasPending = strategyRun.hasReady || !forwardDeps.isEmpty + def complete[A](work: Work.Job[A], result: Either[Throwable,Result[A]]): Unit = + { + val task = work.source + result match + { + case Left(err) => + failureReports += WorkFailure(task, err) + listener.failed(task, err) + retire(task, None) + assert(failed.contains(task)) + case Right(value) => + success(task, value) + assert(completed.contains(task) || (calls.isCalling(task) && !reverseDeps.isEmpty) || failed.contains(task)) + } + assert(calls.isCalling(task) || !reverseDeps.contains(task)) + assert(!forwardDeps.contains(task)) + } + + private def newDepMap = new mutable.HashMap[Task[_], mutable.Set[Task[_]]] + private val reverseDeps = newDepMap + private val forwardDeps = newDepMap + private val calls = new CalledByMap + private val completed = new ResultMap + private val strategyRun = strategy.run + private val failed = new mutable.HashSet[Task[_]] + private val failureReports = new mutable.ArrayBuffer[WorkFailure[Task[_]]] + + { + val initialized = addGraph(root, root) // TODO: replace second root with something better? (it is ignored here anyway) + assert(initialized) + } + + private def addReady[O](m: Task[O]) + { + def add[I](m: ITask[I,O]) + { + val input = Task.extract(m, completed) + strategyRun.workReady(new Work(m, input)) + listener.runnable(m) + } + + assert(!forwardDeps.contains(m), m) + assert(reverseDeps.contains(m), m) + assert(!completed.contains(m), m) + assert(!calls.isCalling(m), m) + assert(m.dependencies.forall(completed.contains), "Could not find result for dependency of ready task " + m) + add(m: ITask[_,O]) + } + // context called node + private def addGraph(node: Task[_], context: Task[_]): Boolean = + { + if(failed(node)) // node already failed + false + else if(calls.isCalling(node)) // node is waiting for a called task to complete, so we need to check for circular dependencies + { + if(calls.isCallerOf(node, context)) // if node called context, this is a circular dependency and is invalid + { + failureReports += WorkFailure(node, CircularDependency(node, context)) + false + } + else + true + } + else if(reverseDeps.contains(node) || completed.contains(node)) // node is either already added and is waiting for dependencies to complete or it has completed + true + else // node has never been added + newAdd(node, context) + } + private def newAdd(node: Task[_], context: Task[_]): Boolean = + { + val deps = node.dependencies.filter(dep => !completed.contains(dep)) + def finishAdding() = + { + listener.added(node) + true + } + if(deps.isEmpty) // node is ready to be run + { + reverseDeps(node) = new mutable.HashSet[Task[_]] + addReady(node) + finishAdding() + } + else if(deps.forall(dep => addGraph(dep,context))) // node requires dependencies to be added successfully and will then wait for them to complete before running + { + for(dep <- node.dependencies if !(completed.contains(dep) || reverseDeps.contains(dep) || calls.isCalling(dep))) + error("Invalid dependency state: (completed=" + completed.contains(dep) + ", reverse=" + reverseDeps.contains(dep) + ", calling=" + calls.isCalling(dep) + ") for " + dep) + reverseDeps(node) = new mutable.HashSet[Task[_]] + deps.foreach(dep => reverseDeps(dep) += node) // mark this node as depending on its dependencies + forwardDeps(node) = mutable.HashSet(deps.toSeq : _*) + finishAdding() + } + else // a dependency could not be added, so this node will fail as well. + { + failed += node + false + } + } + private def retire[O](m: Task[O], value: Option[O]) + { + value match + { + case Some(v) => completed(m) = v // map the task to its value + case None => failed += m // mark the task as failed. complete has already recorded the error message for the original cause + } + updateCurrentGraph(m, value.isDefined) // update forward and reverse dependency maps and propagate the change to depending tasks + listener.completed(m, value) + calls.remove(m) match // unwind the call stack + { + case Some(c) => + listener.called(c, m) + retire(c, value) + case None => () + } + } + private def updateCurrentGraph[O](m: Task[O], success: Boolean) + { + if(!success) + { + // clear m from the forward dependency map + // for each dependency d of m, remove m from the set of tasks that depend on d + for(depSet <- forwardDeps.removeKey(m); dep <- depSet; reverseSet <- reverseDeps.get(dep)) + reverseSet -= m + } + // m is complete, so remove its entry from reverseDeps and update all tasks that depend on m + for(mReverseDeps <- reverseDeps.removeKey(m); dependsOnM <- mReverseDeps) + { + if(success) + { + val on = forwardDeps(dependsOnM) + on -= m // m has completed, so remove it from the set of tasks that must complete before 'on' can run + if(on.isEmpty) // m was the last dependency of on, so make it runnable + { + forwardDeps.removeKey(dependsOnM) + addReady(dependsOnM) + } + } + else // cancel dependsOnM because dependency (m) failed + retire(dependsOnM, None) + } + } + + private def success[O](task: Task[O], value: Result[O]): Unit = + value match + { + case NewTask(t) => + if(t == task) + { + failureReports += WorkFailure(t, CircularDependency(t, task)) + retire(task, None) + } + else if(addGraph(t, task)) + { + calls(t) = task + listener.calling(task, t) + } + else + retire(task, None) + case Value(v) => retire(task, Some(v)) + } + } +} +final case class CircularDependency(node: Task[_], context: Task[_]) + extends RuntimeException("Task " + context + " provided task " + node + " already in calling stack") + +private final class CalledByMap extends NotNull +{ + private[this] val calling = new mutable.HashSet[Task[_]] + private[this] val callMap = new mutable.HashMap[Task[_], Task[_]] + def update[O](called: Task[O], by: Task[O]) + { + calling += by + callMap(called) = by + } + final def isCallerOf(check: Task[_], frame: Task[_]): Boolean = + { + if(check eq frame) true + else + callMap.get(frame) match + { + case Some(nextFrame) => isCallerOf(check, nextFrame) + case None => false + } + } + def isEmpty = calling.isEmpty && callMap.isEmpty + def isCalled(task: Task[_]): Boolean = callMap.contains(task) + def isCalling(caller: Task[_]): Boolean = calling(caller) + def remove[O](called: Task[O]): Option[Task[O]] = + for(caller <- callMap.removeKey(called)) yield + { + calling -= caller + caller.asInstanceOf[Task[O]] + } +} +private final class ResultMap(private val map: mutable.HashMap[Task[_], Any]) extends Results +{ + def this() = this(new mutable.HashMap) + def update[O](task: Task[O], value: O) { map(task) = value } + def apply[O](task: Task[O]): O = map(task).asInstanceOf[O] + def contains(task: Task[_]) = map.contains(task) +} + +private final class Work[I,O](val source: ITask[I,O], input: I) extends Identity with NotNull +{ + final def apply = Task.compute(source, input) +} +private object Work +{ + type Job[A] = Work[_,A] +} \ No newline at end of file diff --git a/tasks/src/test/scala/TListCompileTest.scala b/tasks/src/test/scala/TListCompileTest.scala new file mode 100644 index 000000000..b559fb200 --- /dev/null +++ b/tasks/src/test/scala/TListCompileTest.scala @@ -0,0 +1,17 @@ +//import metascala.HLists._ +import xsbt.{HLists,Task} +import HLists._ +import Task._ + +/** This test just verifies that the HList support compiles.*/ +object TListCompileTest +{ + val n = Task(1) + val s = Task("3") + val t = Task(true) + val mapped = (n :: s :: t :: TNil) map { case n :: s :: t :: HNil => n } + val bound = (n :: s :: t :: TNil) bind { case n :: s :: t :: HNil => (Task(n*4) :: Task("Hi " + t) :: TNil).join } + + val plusOne = mapped map { _ + 1 } + val forkN = plusOne bind { count => (0 until count) fork { i => Task(println(i)) } join } +} \ No newline at end of file diff --git a/tasks/src/test/scala/TaskRunnerCircular.scala b/tasks/src/test/scala/TaskRunnerCircular.scala new file mode 100644 index 000000000..6452cadee --- /dev/null +++ b/tasks/src/test/scala/TaskRunnerCircular.scala @@ -0,0 +1,63 @@ +import xsbt._ + +import org.scalacheck._ +import Prop._ + +object TaskRunnerCircularTest extends Properties("TaskRunner Circular") +{ + specify("Catches circular references", (intermediate: Int, workers: Int) => + (workers > 0 && intermediate >= 0) ==> checkCircularReferences(intermediate, workers) + ) + /*specify("Check root complete", (intermediate: Int, workers: Int) => + (workers > 0 && intermediate >= 0) ==> checkRootComplete(intermediate, workers) + )*/ + specify("Allows noncircular references", (intermediate: Int, workers: Int) => + (workers > 0 && intermediate >= 0) ==> allowedReference(intermediate, workers) + ) + final def allowedReference(intermediate: Int, workers: Int) = + { + val top = Task(intermediate) named("top") + def iterate(task: Task[Int]): Task[Int] = + task bind { t => + if(t <= 0) + top + else + iterate(Task(t-1) named (t-1).toString) + } + try { checkResult(TaskRunner(iterate(top), workers), 0) } + catch { case e: CircularDependency => ("Unexpected exception: " + e) |: false } + } + final def checkCircularReferences(intermediate: Int, workers: Int) = + { + lazy val top = iterate(Task(intermediate) named"bottom", intermediate) + def iterate(task: Task[Int], i: Int): Task[Int] = + { + lazy val it: Task[Int] = + task bind { t => + if(t <= 0) + top + else + iterate(Task(t-1) named (t-1).toString, i-1) + } named("it_" + i) + it + } + TaskRunner(top, workers).fold(_.exists(_.exception.isInstanceOf[CircularDependency]), x => false) + } + final def checkRootComplete(intermediate: Int, workers: Int) = + { + val top = Task(intermediate) + def iterate(task: Task[Int]): Task[Int] = + { + lazy val it: Task[Int] = + task bind { t => + if(t <= 0) + it + else + iterate(Task(t-1) named (t-1).toString) + } named("it") + it + } + try { TaskRunner(iterate(top), workers); false } + catch { case e: CircularDependency => true } + } +} \ No newline at end of file diff --git a/tasks/src/test/scala/TaskRunnerFork.scala b/tasks/src/test/scala/TaskRunnerFork.scala new file mode 100644 index 000000000..b1b49e00f --- /dev/null +++ b/tasks/src/test/scala/TaskRunnerFork.scala @@ -0,0 +1,32 @@ +import xsbt._ + +import org.scalacheck._ +import Prop._ +import Task._ +import Math.abs + +object TaskRunnerForkTest extends Properties("TaskRunner Fork") +{ + specify("fork m tasks and wait for all to complete", (m: Int, workers: Int) => + (workers > 0 && m >= 0) ==> { + val values = (0 until m).toList + checkResult(TaskRunner(values.fork(f => () ).join.map(_.toList),workers), values) + true + } + ) + specify("Double join", (a: Int, b: Int, workers: Int) => + (workers > 0) ==> { runDoubleJoin(abs(a),abs(b),workers); true } + ) + def runDoubleJoin(a: Int, b: Int, workers: Int) + { + def inner(i: Int) = List.range(0, b).map(j => Task(j) named(j.toString)).join.named("Join " + i) + TaskRunner( List.range(0,a).map(inner).join.named("Outermost join"), workers) + } + specify("fork and reduce", (m: List[Int], workers: Int) => { + (workers > 0 && !m.isEmpty) ==> { + val expected = m.reduceLeft(_+_) + checkResult(TaskRunner( m.reduce(_ + _), workers), expected) + } + } + ) +} \ No newline at end of file diff --git a/tasks/src/test/scala/TestRunner.scala b/tasks/src/test/scala/TestRunner.scala new file mode 100644 index 000000000..75c539926 --- /dev/null +++ b/tasks/src/test/scala/TestRunner.scala @@ -0,0 +1,52 @@ +import xsbt._ + +import org.scalacheck._ +import Prop._ + +object TaskRunnerSpec extends Properties("TaskRunner") +{ + specify("evaluates simple task", (i: Int, workers: Int) => + (workers > 0) ==> { + ("Workers: " + workers) |: + checkResult(TaskRunner(Task(i), workers), i) + } + ) + specify("evaluates simple static graph", (i: Int, workers: Int) => + (workers > 0) ==> { + ("Workers: " + workers) |: + { + def result = TaskRunner(Task(i) dependsOn(Task(false),Task("a")), workers) + checkResult(result, i) + } + } + ) + specify("evaluates simple mapped task", (i: Int, times: Int, workers: Int) => + (workers > 0) ==> { + ("Workers: " + workers) |: ("Value: " + i) |: ("Times: " + times) |: + { + def result = TaskRunner(Task(i).map(_*times), workers) + checkResult(result, i*times) + } + } + ) + specify("evaluates chained mapped task", (i: Int, times: Int, workers: Int) => + (workers > 0 && times >= 0) ==> { + ("Workers: " + workers) |: ("Value: " + i) |: ("Times: " + times) |: + { + val initial = Task(0) map(identity[Int]) + def task = ( initial /: (0 until times) )( (t,ignore) => t.map(_ + i)) + checkResult(TaskRunner(task, workers), i*times) + } + } + ) + + specify("evaluates simple bind", (i: Int, times: Int, workers: Int) => + (workers > 0) ==> { + ("Workers: " + workers) |: ("Value: " + i) |: ("Times: " + times) |: + { + def result = TaskRunner(Task(i).bind(x => Task(x*times)), workers) + checkResult(result, i*times) + } + } + ) +} \ No newline at end of file diff --git a/tasks/src/test/scala/TestRunnerCall.scala b/tasks/src/test/scala/TestRunnerCall.scala new file mode 100644 index 000000000..a9bc4fc23 --- /dev/null +++ b/tasks/src/test/scala/TestRunnerCall.scala @@ -0,0 +1,42 @@ +import xsbt._ + +import org.scalacheck._ +import Prop._ + +object TaskRunnerCallTest extends Properties("TaskRunner Call") +{ + specify("calculates fibonacci", (i: Int, workers: Int) => + (workers > 0 && i > 0) ==> { + val f = fibDirect(i) + ("Workers: " + workers) |: ("i: " + i) |: ("fib(i): " + f) |: + { + def result = TaskRunner( fibTask(i), workers) + ("Result: " + result) |: (result == Right(f)) + } + } + ) + final def fibTask(i: Int) = + { + require(i > 0) + lazy val next: (Int,Int,Int) => Task[Int] = + (index, x1, x2) => + { + if(index == i) + Task(x2) + else + iterate( (index+1, x2, x1+x2) ) + } + def iterate(iteration: (Int,Int,Int)) = Task( iteration ) bind Function.tupled(next) + iterate( (1, 0, 1) ) + } + final def fibDirect(i: Int): Int = + { + require(i > 0) + def build(index: Int, x1: Int, x2: Int): Int = + if(index == i) + x2 + else + build(index+1, x2, x1+x2) + build(1, 0, 1) + } +} \ No newline at end of file diff --git a/tasks/src/test/scala/TestRunnerSort.scala b/tasks/src/test/scala/TestRunnerSort.scala new file mode 100644 index 000000000..662c32400 --- /dev/null +++ b/tasks/src/test/scala/TestRunnerSort.scala @@ -0,0 +1,43 @@ +import xsbt._ + +import org.scalacheck._ +import Prop._ + +object TaskRunnerSortTest extends Properties("TaskRunnerSort") +{ + specify("sort", (a: Array[Int], workers: Int) => + (workers > 0) ==> { + val sorted = a.toArray + java.util.Arrays.sort(sorted) + ("Workers: " + workers) |: ("Array: " + a.toList) |: + { + def result = TaskRunner( sort(a.toArray), workers) + checkResult(result.right.map(_.toList), sorted.toList) + } + } + ) + final def sortDirect(a: RandomAccessSeq[Int]): RandomAccessSeq[Int] = + { + if(a.length < 2) + a + else + { + val pivot = a(0) + val (lt,gte) = a.projection.drop(1).partition(_ < pivot) + sortDirect(lt) ++ List(pivot) ++ sortDirect(gte) + } + } + final def sort(a: RandomAccessSeq[Int]): Task[RandomAccessSeq[Int]] = + { + if(a.length < 2) + Task(a) + else + { + Task(a) bind { a => + val pivot = a(0) + val (lt,gte) = a.projection.drop(1).partition(_ < pivot) + (sort(lt), sort(gte)) map { (l,g) => l ++ List(pivot) ++ g } + } + } + } +} \ No newline at end of file diff --git a/tasks/src/test/scala/checkResult.scala b/tasks/src/test/scala/checkResult.scala new file mode 100644 index 000000000..898fbddf5 --- /dev/null +++ b/tasks/src/test/scala/checkResult.scala @@ -0,0 +1,29 @@ +package xsbt + +import org.scalacheck.Prop._ + +object checkResult +{ + def apply[T](run: => Either[List[WorkFailure[Task[_]]],T], expected: T) = + { + ("Expected: " + expected) |: + (try + { + val actual = run + ("Actual: " + actual) |: + (actual match + { + case Right(a) => a == expected + case Left(failures) => + failures.foreach(f => f.exception.printStackTrace) + false + }) + } + catch + { + case e => + e.printStackTrace + "Error in framework" |: false + }) + } +} \ No newline at end of file diff --git a/util/classpath/ClassLoaders.scala b/util/classpath/ClassLoaders.scala new file mode 100644 index 000000000..b308fcd1a --- /dev/null +++ b/util/classpath/ClassLoaders.scala @@ -0,0 +1,43 @@ +/* sbt -- Simple Build Tool + * Copyright 2008, 2009 Mark Harrah + */ +package xsbt + +import java.io.File +import java.net.{URI, URL, URLClassLoader} + +/** This is a starting point for defining a custom ClassLoader. Override 'doLoadClass' to define +* loading a class that has not yet been loaded.*/ +abstract class LoaderBase(urls: Seq[URL], parent: ClassLoader) extends URLClassLoader(urls.toArray, parent) with NotNull +{ + require(parent != null) // included because a null parent is legitimate in Java + @throws(classOf[ClassNotFoundException]) + override final def loadClass(className: String, resolve: Boolean): Class[_] = + { + val loaded = findLoadedClass(className) + val found = + if(loaded == null) + doLoadClass(className) + else + loaded + + if(resolve) + resolveClass(found) + found + } + /** Provides the implementation of finding a class that has not yet been loaded.*/ + protected def doLoadClass(className: String): Class[_] + /** Provides access to the default implementation of 'loadClass'.*/ + protected final def defaultLoadClass(className: String): Class[_] = super.loadClass(className, false) +} + +/** Searches self first before delegating to the parent.*/ +class SelfFirstLoader(classpath: Seq[URL], parent: ClassLoader) extends LoaderBase(classpath, parent) +{ + @throws(classOf[ClassNotFoundException]) + override final def doLoadClass(className: String): Class[_] = + { + try { findClass(className) } + catch { case _: ClassNotFoundException => defaultLoadClass(className) } + } +} \ No newline at end of file diff --git a/util/collection/HLists.scala b/util/collection/HLists.scala new file mode 100644 index 000000000..4d4a00caa --- /dev/null +++ b/util/collection/HLists.scala @@ -0,0 +1,15 @@ +package xsbt + +import metascala.HLists.{HCons => metaHCons, HList => metaHList, HNil => metaHNil} + +object HLists extends HLists +// add an extractor to metascala.HLists and define aliases to the HList classes in the xsbt namespace +trait HLists extends NotNull +{ + object :: { def unapply[H,T<:HList](list: HCons[H,T]) = Some((list.head,list.tail)) } + final val HNil = metaHNil + final type ::[H, T <: HList] = metaHCons[H, T] + final type HNil = metaHNil + final type HList = metaHList + final type HCons[H, T <: HList] = metaHCons[H, T] +} \ No newline at end of file diff --git a/util/collection/TreeHashSet.scala b/util/collection/TreeHashSet.scala new file mode 100644 index 000000000..f84981174 --- /dev/null +++ b/util/collection/TreeHashSet.scala @@ -0,0 +1,22 @@ +package xsbt + +import scala.collection.{mutable,immutable} + + // immutable.HashSet is not suitable for multi-threaded access, so this +// implementation uses an underlying immutable.TreeHashMap, which is suitable +object TreeHashSet +{ + def apply[T](contents: T*) = new TreeHashSet(immutable.TreeHashMap( andUnit(contents) : _*)) + def andUnit[T](contents: Iterable[T]) = contents.map(c => (c,()) ).toSeq +} +final class TreeHashSet[T](backing: immutable.TreeHashMap[T,Unit]) extends immutable.Set[T] +{ + import TreeHashSet.andUnit + override def contains(t: T) = backing.contains(t) + override def ++(s: Iterable[T]) = new TreeHashSet(backing ++ andUnit(s)) + override def +(s: T) = ++( Seq(s) ) + override def -(s: T) = new TreeHashSet(backing - s) + override def elements = backing.keys + override def empty[A] = TreeHashSet[A]() + override def size = backing.size +} \ No newline at end of file diff --git a/util/collection/lib/metascala-0.1.jar b/util/collection/lib/metascala-0.1.jar new file mode 100644 index 0000000000000000000000000000000000000000..ea1d3a62b2590fa6231ee203c443348c971ee86a GIT binary patch literal 128005 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

!#){}~C#mysNP7ln5hX*rKA>TS2EzXO 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

I1?NL(); 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 T2Ui8apF`k+(rhbOMWg)>*U46h literal 0 HcmV?d00001 diff --git a/util/control/ErrorHandling.scala b/util/control/ErrorHandling.scala new file mode 100644 index 000000000..fd8b6e69c --- /dev/null +++ b/util/control/ErrorHandling.scala @@ -0,0 +1,18 @@ +package xsbt + +object ErrorHandling +{ + def translate[T](msg: => String)(f: => T) = + try { f } + catch { case e => throw new TranslatedException(msg + e.toString, e) } + def wideConvert[T](f: => T): Either[Throwable, T] = + try { Right(f) } + catch { case e => Left(e) } // TODO: restrict type of e + def convert[T](f: => T): Either[Exception, T] = + try { Right(f) } + catch { case e: Exception => Left(e) } +} +final class TranslatedException private[xsbt](msg: String, cause: Throwable) extends RuntimeException(msg, cause) +{ + override def toString = msg +} \ No newline at end of file diff --git a/util/io/Hash.scala b/util/io/Hash.scala new file mode 100644 index 000000000..49d95f740 --- /dev/null +++ b/util/io/Hash.scala @@ -0,0 +1,76 @@ +/* sbt -- Simple Build Tool + * Copyright 2009 Mark Harrah + */ +package xsbt + +import java.io.{ByteArrayInputStream, File, InputStream} + +object Hash +{ + private val BufferSize = 8192 + def toHex(bytes: Array[Byte]): String = + { + val buffer = new StringBuilder(bytes.length * 2) + for(i <- 0 until bytes.length) + { + val b = bytes(i) + val bi: Int = if(b < 0) b + 256 else b + buffer append toHex((bi >>> 4).asInstanceOf[Byte]) + buffer append toHex((bi & 0x0F).asInstanceOf[Byte]) + } + buffer.toString + } + def fromHex(hex: String): Array[Byte] = + { + require((hex.length & 1) == 0, "Hex string must have length 2n.") + val array = new Array[Byte](hex.length >> 1) + for(i <- 0 until hex.length by 2) + { + val c1 = hex.charAt(i) + val c2 = hex.charAt(i+1) + array(i >> 1) = ((fromHex(c1) << 4) | fromHex(c2)).asInstanceOf[Byte] + } + array + } + /** Calculates the SHA-1 hash of the given String.*/ + def apply(s: String): Array[Byte] = apply(new ByteArrayInputStream(s.getBytes("UTF-8"))) + /** Calculates the SHA-1 hash of the given file.*/ + def apply(file: File): Array[Byte] = OpenResource.fileInputStream(file)(apply) + /** Calculates the SHA-1 hash of the given stream, closing it when finished.*/ + def apply(stream: InputStream): Array[Byte] = + { + import java.security.{MessageDigest, DigestInputStream} + val digest = MessageDigest.getInstance("SHA") + try + { + val dis = new DigestInputStream(stream, digest) + val buffer = new Array[Byte](BufferSize) + while(dis.read(buffer) >= 0) {} + dis.close() + digest.digest + } + finally { stream.close() } + } + + private def toHex(b: Byte): Char = + { + require(b >= 0 && b <= 15, "Byte " + b + " was not between 0 and 15") + if(b < 10) + ('0'.asInstanceOf[Int] + b).asInstanceOf[Char] + else + ('a'.asInstanceOf[Int] + (b-10)).asInstanceOf[Char] + } + private def fromHex(c: Char): Int = + { + val b = + if(c >= '0' && c <= '9') + (c - '0') + else if(c >= 'a' && c <= 'f') + (c - 'a') + 10 + else if(c >= 'A' && c <= 'F') + (c - 'A') + 10 + else + throw new RuntimeException("Invalid hex character: '" + c + "'.") + b + } +} \ No newline at end of file diff --git a/util/io/OpenResource.scala b/util/io/OpenResource.scala new file mode 100644 index 000000000..ea0be13ce --- /dev/null +++ b/util/io/OpenResource.scala @@ -0,0 +1,109 @@ +/* sbt -- Simple Build Tool + * Copyright 2008, 2009 Mark Harrah + */ +package xsbt + +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 ErrorHandling.translate +import OpenResource._ + +object FileUtilities +{ + def createDirectory(dir: File): Unit = + translate("Could not create directory " + dir + ": ") + { + if(dir.exists) + { + if(!dir.isDirectory) + error("file exists and is not a directory.") + } + else if(!dir.mkdirs()) + error("") + } +} + +abstract class OpenResource[Source, T] extends NotNull +{ + protected def open(src: Source): T + def apply[R](src: Source)(f: T => R): R = + { + val resource = open(src) + try { f(resource) } + finally { close(resource) } + } + protected def close(out: T): Unit +} +import scala.reflect.{Manifest => SManifest} +abstract class WrapOpenResource[Source, T](implicit srcMf: SManifest[Source], targetMf: SManifest[T]) extends OpenResource[Source, T] +{ + protected def label[S](m: SManifest[S]) = m.erasure.getSimpleName + protected def openImpl(source: Source): T + protected final def open(source: Source): T = + translate("Error wrapping " + label(srcMf) + " in " + label(targetMf) + ": ") { openImpl(source) } +} +trait OpenFile[T] extends OpenResource[File, T] +{ + protected def openImpl(file: File): T + protected final def open(file: File): T = + { + val parent = file.getParentFile + if(parent != null) + FileUtilities.createDirectory(parent) + translate("Error opening " + file + ": ") { openImpl(file) } + } +} +object OpenResource +{ + def wrap[Source, T<: Closeable](openF: Source => T)(implicit srcMf: SManifest[Source], targetMf: SManifest[T]): OpenResource[Source,T] = + wrap(openF, _.close) + def wrap[Source, T](openF: Source => T, closeF: T => Unit)(implicit srcMf: SManifest[Source], targetMf: SManifest[T]): OpenResource[Source,T] = + new WrapOpenResource[Source, T] + { + def openImpl(source: Source) = openF(source) + def close(t: T) = closeF(t) + } + + def resource[Source, T <: Closeable](openF: Source => T): OpenResource[Source,T] = + resource(openF, _.close) + def resource[Source, T <: Closeable](openF: Source => T, closeF: T => Unit): OpenResource[Source,T] = + new OpenResource[Source,T] + { + def open(s: Source) = openF(s) + def close(s: T) = closeF(s) + } + def file[T <: Closeable](openF: File => T): OpenFile[T] = file(openF, _.close()) + def file[T](openF: File => T, closeF: T => Unit): OpenFile[T] = + new OpenFile[T] + { + def openImpl(file: File) = openF(file) + def close(t: T) = closeF(t) + } + + def fileOutputStream(append: Boolean) = file(f => new FileOutputStream(f, append)) + def fileInputStream = file(f => new FileInputStream(f)) + def urlInputStream = resource( (u: URL) => translate("Error opening " + u + ": ")(u.openStream)) + def fileOutputChannel = file(f => new FileOutputStream(f).getChannel) + def fileInputChannel = file(f => new FileInputStream(f).getChannel) + def fileWriter(charset: Charset, append: Boolean) = + file(f => new BufferedWriter(new OutputStreamWriter(new FileOutputStream(f, append), charset)) ) + def fileReader(charset: Charset) = file(f => new BufferedReader(new InputStreamReader(new FileInputStream(f), charset)) ) + def jarFile(verify: Boolean) = file(f => new JarFile(f, verify), (_: JarFile).close()) + def zipFile = file(f => new ZipFile(f), (_: ZipFile).close()) + def streamReader = wrap{ (_: (InputStream, Charset)) match { case (in, charset) => new InputStreamReader(in, charset) } } + def gzipInputStream = wrap( (in: InputStream) => new GZIPInputStream(in) ) + def zipInputStream = wrap( (in: InputStream) => new ZipInputStream(in)) + def gzipOutputStream = wrap((out: OutputStream) => new GZIPOutputStream(out), (_: GZIPOutputStream).finish()) + def jarOutputStream = wrap( (out: OutputStream) => new JarOutputStream(out)) + def jarInputStream = wrap( (in: InputStream) => new JarInputStream(in)) + def zipEntry(zip: ZipFile) = resource( (entry: ZipEntry) => + translate("Error opening " + entry.getName + " in " + zip + ": ") { zip.getInputStream(entry) } ) +} \ No newline at end of file diff --git a/util/log/Logger.scala b/util/log/Logger.scala new file mode 100644 index 000000000..b5203acb8 --- /dev/null +++ b/util/log/Logger.scala @@ -0,0 +1,71 @@ +/* sbt -- Simple Build Tool + * Copyright 2008, 2009 Mark Harrah + */ + package xsbt + +abstract class Logger extends NotNull +{ + def getLevel: Level.Value + def setLevel(newLevel: Level.Value) + def enableTrace(flag: Boolean) + def traceEnabled: Boolean + + def atLevel(level: Level.Value) = level.id >= getLevel.id + def trace(t: => Throwable): Unit + final def debug(message: => String): Unit = log(Level.Debug, message) + final def info(message: => String): Unit = log(Level.Info, message) + final def warn(message: => String): Unit = log(Level.Warn, message) + final def error(message: => String): Unit = log(Level.Error, message) + def success(message: => String): Unit + def log(level: Level.Value, message: => String): Unit + def control(event: ControlEvent.Value, message: => String): Unit + + def logAll(events: Seq[LogEvent]): Unit + /** Defined in terms of other methods in Logger and should not be called from them. */ + final def log(event: LogEvent) + { + event match + { + case s: Success => success(s.msg) + case l: Log => log(l.level, l.msg) + case t: Trace => trace(t.exception) + case setL: SetLevel => setLevel(setL.newLevel) + case setT: SetTrace => enableTrace(setT.enabled) + case c: ControlEvent => control(c.event, c.msg) + } + } +} + +sealed trait LogEvent extends NotNull +final class Success(val msg: String) extends LogEvent +final class Log(val level: Level.Value, val msg: String) extends LogEvent +final class Trace(val exception: Throwable) extends LogEvent +final class SetLevel(val newLevel: Level.Value) extends LogEvent +final class SetTrace(val enabled: Boolean) extends LogEvent +final class ControlEvent(val event: ControlEvent.Value, val msg: String) extends LogEvent + +object ControlEvent extends Enumeration +{ + val Start, Header, Finish = Value +} + +/** An enumeration defining the levels available for logging. A level includes all of the levels +* with id larger than its own id. For example, Warn (id=3) includes Error (id=4).*/ +object Level extends Enumeration with NotNull +{ + val Debug = Value(1, "debug") + val Info = Value(2, "info") + val Warn = Value(3, "warn") + val Error = Value(4, "error") + /** Defines the label to use for success messages. A success message is logged at the info level but + * uses this label. Because the label for levels is defined in this module, the success + * label is also defined here. */ + val SuccessLabel = "success" + + // added because elements was renamed to iterator in 2.8.0 nightly + def levels = Debug :: Info :: Warn :: Error :: Nil + /** Returns the level with the given name wrapped in Some, or None if no level exists for that name. */ + def apply(s: String) = levels.find(s == _.toString) + /** Same as apply, defined for use in pattern matching. */ + private[xsbt] def unapply(s: String) = apply(s) +} \ No newline at end of file