From 33d29a4768032c6d4ef44da0ab16b6ff587547f7 Mon Sep 17 00:00:00 2001 From: Mark Harrah Date: Sun, 2 May 2010 19:15:01 -0400 Subject: [PATCH] * can now set 'offline' property to 'true' to not refresh dynamic revisions (not needed if no -SNAPSHOT versions used) * more control over Ivy logging: override ivyUpdateLogging = UpdateLogging.Full,DownloadOnly (default), or Quiet --- ivy/Ivy.scala | 42 ++++++++++++------- ivy/IvyActions.scala | 31 ++++++++++---- ivy/IvyCache.scala | 2 +- ivy/IvyConfigurations.scala | 10 +++-- .../main/scala/sbt/BasicProjectTypes.scala | 18 ++++---- sbt/src/main/scala/sbt/Project.scala | 1 + .../main/scala/sbt/processor/Handler.scala | 2 +- .../main/scala/sbt/processor/Manager.scala | 10 ++--- .../main/scala/sbt/processor/Retrieve.scala | 8 ++-- 9 files changed, 79 insertions(+), 45 deletions(-) diff --git a/ivy/Ivy.scala b/ivy/Ivy.scala index 7065e5603..b2d59c60d 100644 --- a/ivy/Ivy.scala +++ b/ivy/Ivy.scala @@ -59,8 +59,8 @@ final class IvySbt(configuration: IvyConfiguration) { case e: ExternalIvyConfiguration => is.load(e.file) case i: InlineIvyConfiguration => - IvySbt.configureCache(is, i.paths.cacheDirectory) - IvySbt.setResolvers(is, i.resolvers, i.otherResolvers, log) + IvySbt.configureCache(is, i.paths.cacheDirectory, i.localOnly) + IvySbt.setResolvers(is, i.resolvers, i.otherResolvers, i.localOnly, log) IvySbt.setModuleConfigurations(is, i.moduleConfigurations) } is @@ -171,23 +171,28 @@ private object IvySbt /** Sets the resolvers for 'settings' to 'resolvers'. This is done by creating a new chain and making it the default. * 'other' is for resolvers that should be in a different chain. These are typically used for publishing or other actions. */ - private def setResolvers(settings: IvySettings, resolvers: Seq[Resolver], other: Seq[Resolver], log: IvyLogger) + private def setResolvers(settings: IvySettings, resolvers: Seq[Resolver], other: Seq[Resolver], localOnly: Boolean, log: IvyLogger) { - val otherChain = resolverChain("sbt-other", other) - settings.addResolver(otherChain) - val newDefault = resolverChain("sbt-chain", resolvers) - settings.addResolver(newDefault) - settings.setDefaultResolver(newDefault.getName) - log.debug("Using repositories:\n" + resolvers.mkString("\n\t")) - log.debug("Using other repositories:\n" + other.mkString("\n\t")) + def makeChain(label: String, name: String, rs: Seq[Resolver]) = { + log.debug(label + " repositories:") + val chain = resolverChain(name, rs, localOnly, log) + settings.addResolver(chain) + chain + } + val otherChain = makeChain("Other", "sbt-other", other) + val mainChain = makeChain("Default", "sbt-chain", resolvers) + settings.setDefaultResolver(mainChain.getName) } - private def resolverChain(name: String, resolvers: Seq[Resolver]): ChainResolver = + private def resolverChain(name: String, resolvers: Seq[Resolver], localOnly: Boolean, log: IvyLogger): ChainResolver = { val newDefault = new ChainResolver newDefault.setName(name) newDefault.setReturnFirst(true) - newDefault.setCheckmodified(true) - resolvers.foreach(r => newDefault.add(ConvertResolver(r))) + newDefault.setCheckmodified(!localOnly) + for(sbtResolver <- resolvers) { + log.debug("\t" + sbtResolver) + newDefault.add(ConvertResolver(sbtResolver)) + } newDefault } private def setModuleConfigurations(settings: IvySettings, moduleConfigurations: Seq[ModuleConfiguration]) @@ -204,13 +209,18 @@ private object IvySbt settings.addModuleConfiguration(attributes, settings.getMatcher(EXACT_OR_REGEXP), resolver.name, null, null, null) } } - private def configureCache(settings: IvySettings, dir: Option[File]) + private def configureCache(settings: IvySettings, dir: Option[File], localOnly: Boolean) { val cacheDir = dir.getOrElse(settings.getDefaultRepositoryCacheBasedir()) val manager = new DefaultRepositoryCacheManager("default-cache", settings, cacheDir) manager.setUseOrigin(true) - manager.setChangingMatcher(PatternMatcher.REGEXP); - manager.setChangingPattern(".*-SNAPSHOT"); + if(localOnly) + manager.setDefaultTTL(java.lang.Long.MAX_VALUE); + else + { + manager.setChangingMatcher(PatternMatcher.REGEXP); + manager.setChangingPattern(".*-SNAPSHOT"); + } settings.addRepositoryCacheManager(manager) settings.setDefaultRepositoryCacheManager(manager) dir.foreach(dir => settings.setDefaultResolutionCacheBasedir(dir.getAbsolutePath)) diff --git a/ivy/IvyActions.scala b/ivy/IvyActions.scala index e478df5eb..d80b12e13 100644 --- a/ivy/IvyActions.scala +++ b/ivy/IvyActions.scala @@ -19,7 +19,7 @@ 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 +final class UpdateConfiguration(val retrieveDirectory: File, val outputPattern: String, val synchronize: Boolean, val logging: UpdateLogging.Value) extends NotNull final class MakePomConfiguration(val extraDependencies: Iterable[ModuleID], val configurations: Option[Iterable[Configuration]], val extra: NodeSeq, val process: Node => Node, val filterRepositories: MavenRepository => Boolean) extends NotNull object MakePomConfiguration @@ -27,6 +27,14 @@ object MakePomConfiguration def apply(extraDependencies: Iterable[ModuleID], configurations: Option[Iterable[Configuration]], extra: NodeSeq) = new MakePomConfiguration(extraDependencies, configurations, extra, identity, _ => true) } +/** Configures logging during an 'update'. `level` determines the amount of other information logged. +* `Full` is the default and logs the most. +* `DownloadOnly` only logs what is downloaded. +* `Quiet` only displays errors.*/ +object UpdateLogging extends Enumeration +{ + val Full, DownloadOnly, Quiet = Value +} object IvyActions { @@ -71,11 +79,11 @@ object IvyActions IvySbt.addDependencies(module, extraDependencies, parser) } - def deliver(module: IvySbt#Module, status: String, deliverIvyPattern: String, extraDependencies: Iterable[ModuleID], configurations: Option[Iterable[Configuration]], quiet: Boolean) + def deliver(module: IvySbt#Module, status: String, deliverIvyPattern: String, extraDependencies: Iterable[ModuleID], configurations: Option[Iterable[Configuration]], logging: UpdateLogging.Value) { module.withModule { case (ivy, md, default) => addLateDependencies(ivy, md, default, extraDependencies) - resolve(quiet)(ivy, md, default) // todo: set download = false for resolve + resolve(logging)(ivy, md, default) // todo: set download = false for resolve val revID = md.getModuleRevisionId val options = DeliverOptions.newInstance(ivy.getSettings).setStatus(status) options.setConfs(IvySbt.getConfigurations(md, configurations)) @@ -101,7 +109,7 @@ object IvyActions { module.withModule { case (ivy, md, default) => import configuration._ - resolve(quiet)(ivy, md, default) + resolve(logging)(ivy, md, default) val retrieveOptions = new RetrieveOptions retrieveOptions.setSync(synchronize) val patternBase = retrieveDirectory.getAbsolutePath @@ -113,14 +121,23 @@ object IvyActions ivy.retrieve(md.getModuleRevisionId, pattern, retrieveOptions) } } - private def resolve(quiet: Boolean)(ivy: Ivy, module: DefaultModuleDescriptor, defaultConf: String) = + private def resolve(logging: UpdateLogging.Value)(ivy: Ivy, module: DefaultModuleDescriptor, defaultConf: String) = { val resolveOptions = new ResolveOptions - if(quiet) - resolveOptions.setLog(LogOptions.LOG_DOWNLOAD_ONLY) + resolveOptions.setLog(ivyLogLevel(logging)) val resolveReport = ivy.resolve(module, resolveOptions) if(resolveReport.hasError) throw new ResolveException(resolveReport.getAllProblemMessages.toArray.map(_.toString).toList.removeDuplicates) } + + import UpdateLogging.{Quiet, Full, DownloadOnly} + import LogOptions.{LOG_QUIET, LOG_DEFAULT, LOG_DOWNLOAD_ONLY} + private def ivyLogLevel(level: UpdateLogging.Value) = + level match + { + case Quiet => LOG_QUIET + case DownloadOnly => LOG_DOWNLOAD_ONLY + case Full => LOG_DEFAULT + } } final class ResolveException(messages: List[String]) extends RuntimeException(messages.mkString("\n")) \ No newline at end of file diff --git a/ivy/IvyCache.scala b/ivy/IvyCache.scala index b7c18c0ba..43b714231 100644 --- a/ivy/IvyCache.scala +++ b/ivy/IvyCache.scala @@ -86,7 +86,7 @@ object IvyCache { val local = Resolver.defaultLocal(None) val paths = new IvyPaths(new File("."), None) - val conf = new InlineIvyConfiguration(paths, Seq(local), Nil, Nil, lock, log) + val conf = new InlineIvyConfiguration(paths, Seq(local), Nil, Nil, false, lock, log) (new IvySbt(conf), local) } /** Creates a default jar artifact based on the given ID.*/ diff --git a/ivy/IvyConfigurations.scala b/ivy/IvyConfigurations.scala index 7b57364cd..c047f1dda 100644 --- a/ivy/IvyConfigurations.scala +++ b/ivy/IvyConfigurations.scala @@ -19,11 +19,13 @@ sealed trait IvyConfiguration extends NotNull def withBase(newBaseDirectory: File): This } final class InlineIvyConfiguration(val paths: IvyPaths, val resolvers: Seq[Resolver], val otherResolvers: Seq[Resolver], - val moduleConfigurations: Seq[ModuleConfiguration], val lock: Option[xsbti.GlobalLock], val log: IvyLogger) extends IvyConfiguration + val moduleConfigurations: Seq[ModuleConfiguration], val localOnly: Boolean, val lock: Option[xsbti.GlobalLock], + val log: IvyLogger) extends IvyConfiguration { type This = InlineIvyConfiguration def baseDirectory = paths.baseDirectory - def withBase(newBase: File) = new InlineIvyConfiguration(paths.withBase(newBase), resolvers, otherResolvers, moduleConfigurations, lock, log) + def withBase(newBase: File) = new InlineIvyConfiguration(paths.withBase(newBase), resolvers, otherResolvers, moduleConfigurations, localOnly, lock, log) + def changeResolvers(newResolvers: Seq[Resolver]) = new InlineIvyConfiguration(paths, newResolvers, otherResolvers, moduleConfigurations, localOnly, lock, log) } final class ExternalIvyConfiguration(val baseDirectory: File, val file: File, val lock: Option[xsbti.GlobalLock], val log: IvyLogger) extends IvyConfiguration { @@ -35,14 +37,14 @@ object IvyConfiguration { /** 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.*/ - def apply(paths: IvyPaths, lock: Option[xsbti.GlobalLock], log: IvyLogger): IvyConfiguration = + def apply(paths: IvyPaths, lock: Option[xsbti.GlobalLock], localOnly: Boolean, log: IvyLogger): IvyConfiguration = { log.debug("Autodetecting configuration.") val defaultIvyConfigFile = IvySbt.defaultIvyConfiguration(paths.baseDirectory) if(defaultIvyConfigFile.canRead) new ExternalIvyConfiguration(paths.baseDirectory, defaultIvyConfigFile, lock, log) else - new InlineIvyConfiguration(paths, Resolver.withDefaultResolvers(Nil), Nil, Nil, lock, log) + new InlineIvyConfiguration(paths, Resolver.withDefaultResolvers(Nil), Nil, Nil, localOnly, lock, log) } } diff --git a/sbt/src/main/scala/sbt/BasicProjectTypes.scala b/sbt/src/main/scala/sbt/BasicProjectTypes.scala index 183a79d70..e8a646912 100644 --- a/sbt/src/main/scala/sbt/BasicProjectTypes.scala +++ b/sbt/src/main/scala/sbt/BasicProjectTypes.scala @@ -85,12 +85,12 @@ trait IvyTasks extends Project val deliveredIvy = if(publishIvy) Some(deliveredPattern) else None IvyActions.publish(module, resolverName, srcArtifactPatterns, deliveredIvy, configurations) } - def deliverTask(module: => IvySbt#Module, deliverConfiguration: => PublishConfiguration, quiet: Boolean) = + def deliverTask(module: => IvySbt#Module, deliverConfiguration: => PublishConfiguration, logging: => UpdateLogging.Value) = ivyTask { val deliverConfig = deliverConfiguration import deliverConfig._ - IvyActions.deliver(module, status, deliveredPattern, extraDependencies, configurations, quiet) + IvyActions.deliver(module, status, deliveredPattern, extraDependencies, configurations, logging) } @deprecated def makePomTask(module: => IvySbt#Module, output: => Path, extraDependencies: => Iterable[ModuleID], pomExtra: => NodeSeq, configurations: => Option[Iterable[Configuration]]): Task = makePomTask(module, MakePomConfiguration(extraDependencies, configurations, pomExtra), output) @@ -180,7 +180,9 @@ object ManagedStyle extends Enumeration import ManagedStyle.{Auto, Ivy, Maven, Value => ManagedType} trait BasicManagedProject extends ManagedProject with ReflectiveManagedProject with BasicDependencyPaths { - def ivyUpdateConfiguration = new UpdateConfiguration(managedDependencyPath.asFile, outputPattern, true/*sync*/, true/*quiet*/) + def ivyUpdateConfiguration = new UpdateConfiguration(managedDependencyPath.asFile, outputPattern, true/*sync*/, ivyUpdateLogging) + def ivyUpdateLogging = UpdateLogging.DownloadOnly + def ivyLocalOnly: Boolean = offline.value def ivyRepositories: Seq[Resolver] = { @@ -193,7 +195,7 @@ trait BasicManagedProject extends ManagedProject with ReflectiveManagedProject w def ivyCacheDirectory: Option[Path] = None def ivyPaths: IvyPaths = new IvyPaths(info.projectPath.asFile, ivyCacheDirectory.map(_.asFile)) - def inlineIvyConfiguration = new InlineIvyConfiguration(ivyPaths, ivyRepositories.toSeq, otherRepositories, moduleConfigurations.toSeq, Some(info.launcher.globalLock), log) + def inlineIvyConfiguration = new InlineIvyConfiguration(ivyPaths, ivyRepositories.toSeq, otherRepositories, moduleConfigurations.toSeq, ivyLocalOnly, Some(info.launcher.globalLock), log) def ivyConfiguration: IvyConfiguration = { val in = inlineIvyConfiguration @@ -203,14 +205,14 @@ trait BasicManagedProject extends ManagedProject with ReflectiveManagedProject w { if(in.moduleConfigurations.isEmpty && in.otherResolvers.isEmpty) { - IvyConfiguration(in.paths, in.lock, in.log) match + IvyConfiguration(in.paths, in.lock, in.localOnly, in.log) match { case e: ExternalIvyConfiguration => e case i => info.parent map(parentIvyConfiguration(i)) getOrElse(i) } } else - new InlineIvyConfiguration(in.paths, Resolver.withDefaultResolvers(Nil), in.otherResolvers, in.moduleConfigurations, in.lock, in.log) + in.changeResolvers(Resolver.withDefaultResolvers(Nil)) } else in @@ -381,14 +383,14 @@ trait BasicManagedProject extends ManagedProject with ReflectiveManagedProject w def makePomConfiguration = new MakePomConfiguration(deliverProjectDependencies, None, pomExtra, pomPostProcess, pomIncludeRepository) protected def deliverScalaDependencies: Iterable[ModuleID] = Nil protected def makePomAction = makePomTask(deliverIvyModule, makePomConfiguration, pomPath) - protected def deliverLocalAction = deliverTask(deliverIvyModule, publishLocalConfiguration, true /*quiet*/) + protected def deliverLocalAction = deliverTask(deliverIvyModule, publishLocalConfiguration, ivyUpdateLogging) protected def publishLocalAction = { val dependencies = deliverLocal :: publishPomDepends publishTask(publishIvyModule, publishLocalConfiguration) dependsOn(dependencies : _*) } protected def publishLocalConfiguration = new DefaultPublishConfiguration("local", "release", true) - protected def deliverAction = deliverTask(deliverIvyModule, publishConfiguration, true) + protected def deliverAction = deliverTask(deliverIvyModule, publishConfiguration, ivyUpdateLogging) protected def publishAction = { val dependencies = deliver :: publishPomDepends diff --git a/sbt/src/main/scala/sbt/Project.scala b/sbt/src/main/scala/sbt/Project.scala index 3b6730d14..6bcf4d3b9 100644 --- a/sbt/src/main/scala/sbt/Project.scala +++ b/sbt/src/main/scala/sbt/Project.scala @@ -221,6 +221,7 @@ trait Project extends TaskManager with Dag[Project] with BasicEnvironment final val sbtVersion = property[String] final val projectInitialize = propertyOptional[Boolean](false) final val projectScratch = propertyOptional[Boolean](false, true) + final val offline = propertyOptional[Boolean](false) /** The property that defines the versions of Scala to build this project against as a comma separated string. This can be * different from the version of Scala used to build and run the project definition (defined by defScalaVersion). * This property is only read by `sbt` on startup and reload. The definitive source for the version of Scala currently diff --git a/sbt/src/main/scala/sbt/processor/Handler.scala b/sbt/src/main/scala/sbt/processor/Handler.scala index 8cd349f98..fc32fb8d0 100644 --- a/sbt/src/main/scala/sbt/processor/Handler.scala +++ b/sbt/src/main/scala/sbt/processor/Handler.scala @@ -30,6 +30,6 @@ class Handler(baseProject: Project) extends NotNull def files = new ManagerFiles(base.asFile, retrieveLockFile.asFile, definitionsFile.asFile) lazy val defParser = new DefinitionParser - lazy val manager = new ManagerImpl(files, scalaVersion, new Persist(lock, persistLockFile.asFile, defParser), baseProject.log) + lazy val manager = new ManagerImpl(files, scalaVersion, new Persist(lock, persistLockFile.asFile, defParser), baseProject.offline.value, baseProject.log) } class ParsedProcessor(val label: String, val processor: Processor, val arguments: String) extends NotNull \ No newline at end of file diff --git a/sbt/src/main/scala/sbt/processor/Manager.scala b/sbt/src/main/scala/sbt/processor/Manager.scala index ac7254ad9..fd46c128e 100644 --- a/sbt/src/main/scala/sbt/processor/Manager.scala +++ b/sbt/src/main/scala/sbt/processor/Manager.scala @@ -13,7 +13,7 @@ import ProcessorException.error * `definitionsFile` is the file to save repository and processor definitions to. It is usually per-user instead of per-project.*/ class ManagerFiles(val retrieveBaseDirectory: File, val retrieveLockFile: File, val definitionsFile: File) -class ManagerImpl(files: ManagerFiles, scalaVersion: String, persist: Persist, log: Logger) extends Manager +class ManagerImpl(files: ManagerFiles, scalaVersion: String, persist: Persist, localOnly: Boolean, log: Logger) extends Manager { import files._ @@ -26,7 +26,7 @@ class ManagerImpl(files: ManagerFiles, scalaVersion: String, persist: Persist, l // try to load the processor. It will succeed here if the processor has already been retrieved tryProcessor.left.flatMap { _ => // if it hasn't been retrieved, retrieve the processor and its dependencies - retrieveProcessor(pdef) + retrieveProcessor(pdef, localOnly) // try to load the processor now that it has been retrieved tryProcessor.left.map { // if that fails, log a warning case p: ProcessorException => log.warn(p.getMessage) @@ -37,7 +37,7 @@ class ManagerImpl(files: ManagerFiles, scalaVersion: String, persist: Persist, l def defineProcessor(p: ProcessorDefinition) { checkExisting(p) - retrieveProcessor(p) + retrieveProcessor(p, localOnly) add(p) } def defineRepository(r: RepositoryDefinition) @@ -54,11 +54,11 @@ class ManagerImpl(files: ManagerFiles, scalaVersion: String, persist: Persist, l case None => error("Label '" + label + "' not defined.") } - private def retrieveProcessor(p: ProcessorDefinition): Unit = + private def retrieveProcessor(p: ProcessorDefinition, localOnly: Boolean): Unit = { val resolvers = repositories.values.toList.map(toResolver) val module = p.toModuleID(scalaVersion) - ( new Retrieve(retrieveDirectory(p), module, persist.lock, retrieveLockFile, resolvers, log) ).retrieve() + ( new Retrieve(retrieveDirectory(p), module, persist.lock, retrieveLockFile, resolvers, log) ).retrieve(localOnly) } private def add(d: Definition) { diff --git a/sbt/src/main/scala/sbt/processor/Retrieve.scala b/sbt/src/main/scala/sbt/processor/Retrieve.scala index ee91f79f0..663c21a69 100644 --- a/sbt/src/main/scala/sbt/processor/Retrieve.scala +++ b/sbt/src/main/scala/sbt/processor/Retrieve.scala @@ -7,14 +7,14 @@ import java.io.File class Retrieve(retrieveDirectory: File, module: ModuleID, lock: xsbti.GlobalLock, lockFile: File, repositories: Seq[Resolver], log: IvyLogger) extends NotNull { - def retrieve() + def retrieve(localOnly: Boolean) { val paths = new IvyPaths(retrieveDirectory, None) val ivyScala = new IvyScala("", Nil, false, true) val fullRepositories = Resolver.withDefaultResolvers(repositories) // TODO: move this somewhere under user control - val configuration = new InlineIvyConfiguration(paths, fullRepositories, Nil, Nil, Some(lock), log) + val configuration = new InlineIvyConfiguration(paths, fullRepositories, Nil, Nil, localOnly, Some(lock), log) val moduleConfiguration = new InlineConfiguration(thisID, module :: Nil, scala.xml.NodeSeq.Empty, Nil, None, Some(ivyScala), false) - val update = new UpdateConfiguration(retrieveDirectory, retrievePattern, true, true) + val update = new UpdateConfiguration(retrieveDirectory, retrievePattern, true, logging) val ivySbt = new IvySbt(configuration) val ivyModule = new ivySbt.Module(moduleConfiguration) @@ -22,6 +22,8 @@ class Retrieve(retrieveDirectory: File, module: ModuleID, lock: xsbti.GlobalLock } def thisID = ModuleID("org.scala-tools.sbt", "retrieve-processor", "1.0") def retrievePattern = "[artifact](-[revision])(-[classifier]).[ext]" + + def logging = UpdateLogging.DownloadOnly } object Callable