-
-
Save viktorklang/a09aad920c1a4072cfe6 to your computer and use it in GitHub Desktop.
| /* | |
| Copyright 2015 Viktor Klang | |
| Licensed under the Apache License, Version 2.0 (the "License"); | |
| you may not use this file except in compliance with the License. | |
| You may obtain a copy of the License at | |
| http://www.apache.org/licenses/LICENSE-2.0 | |
| Unless required by applicable law or agreed to in writing, software | |
| distributed under the License is distributed on an "AS IS" BASIS, | |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| See the License for the specific language governing permissions and | |
| limitations under the License. | |
| */ | |
| /** | |
| * Documentation | |
| * | |
| * Install: | |
| * | |
| * `wget -P <sbt-project-base-dir>/project https://gist.githubusercontent.com/viktorklang/a09aad920c1a4072cfe6/raw/Gistard.scala` | |
| * | |
| * Or visit the above address with your web browser of choice and save the file in your `<sbt-project-basedir>/project` folder as `Gistard.scala` (important) | |
| * | |
| * | |
| * Configuration: | |
| * | |
| * **It is recommended to configure Gistard to update itself using Gistard** so add this to your `build.sbt`: | |
| * | |
| * If you want to make sure you are always on the latest version, omit the revision as below: | |
| * | |
| * GistardKeys.gistardDependencies += gist("viktorklang", "a09aad920c1a4072cfe6", "", "Gistard.scala", baseDirectory.value / "project") | |
| * | |
| * If you want to update to a specific revision, use this instead: | |
| * | |
| * GistardKeys.gistardDependencies += gist("viktorklang", "a09aad920c1a4072cfe6", "<insert revision here>", "Gistard.scala", baseDirectory.value / "project") | |
| * | |
| * To see available revisions, have a look here: https://gist.github.com/viktorklang/a09aad920c1a4072cfe6/revisions | |
| * | |
| * | |
| * `Gistard` has three tasks for maintaining the dependencies, `gistardUpdate` which downloads the gist dependencies if they are not already downloaded, | |
| * `gistardClean` which deletes all gist dependencies, and `gistardReload` which downloads the gist dependencies and replaces the existing versions. | |
| * | |
| * `Gistard` by default hooks `gistardUpdate` into the `update` task and `gistardClean` into the `clean` task. | |
| * | |
| * | |
| * Usage: | |
| * | |
| * So you've found a Gist that you want to automatically pull into your `sbt` project, fantastic! | |
| * | |
| * Example: | |
| * | |
| * You were browsing `viktorklang`s Gists when you saw `GistardVerify` (https://gist.github.com/viktorklang/3fdb2ec2709b79fdc7a4), | |
| * and now you want to add that snippet to your `build.sbt` using `Gistard`. | |
| * | |
| * In the URL, the "viktorklang" part will be the value of the `owner` field of the Gist, | |
| * and "3fdb2ec2709b79fdc7a4" is the `id` field value. | |
| * You note that the file you want to depend on is named `GistardVerify.scala`, | |
| * this will be the `fileName` field value. | |
| * | |
| * First you decide if you want to depend on a specific revision of that Gist, you can see them at: | |
| * https://gist.github.com/viktorklang/3fdb2ec2709b79fdc7a4/revisions | |
| * | |
| * You decide that you want to have "the latest" revision (empty String for revision below), | |
| * and that you want to place it in `main/scala/gistard/verify` so you add the following to your `build.sbt`: | |
| * | |
| * GistardKeys.gistardDependencies += gist(owner = "viktorklang", | |
| * id = "3fdb2ec2709b79fdc7a4", | |
| * revision = "", | |
| * fileName = "GistardVerify.scala", | |
| * localDirectory = scalaSource.value / "gistard" / "verify") | |
| * | |
| * Then you either restart `sbt` or run the `reload` command to see this change take effect and all that is left to do is to | |
| * run the `update` task to have `Gistard` download the `GistardVerify.scala` file. | |
| * | |
| * | |
| * | |
| * | |
| **/ | |
| package gistard | |
| import sbt._ | |
| import sbt.Keys._ | |
| import scala.collection.immutable | |
| import java.net.URL | |
| import java.io.{File => JFile} | |
| /** | |
| * Gistard is a GitHub Gist hosted sbt autoplugin that allows you to depend on GitHub Gist files as source dependencies. | |
| * Gistard itself is a GitHub Gist and can use Gistard to update itself. | |
| **/ | |
| object Gistard { | |
| /** | |
| * Gist represents a specific revision of a specific file in a specific Gist for a specific owner. | |
| * If the revision is empty, it will fetch the latest revision. | |
| **/ | |
| final case class Gist(owner: String, id: String, revision: String, fileName: String, localDirectory: File) { | |
| if (fileName.isEmpty) throw new IllegalArgumentException("Gist file must be non-empty!") | |
| if (id.isEmpty) throw new IllegalArgumentException("Gist ID must be non-empty!") | |
| if (!revision.isEmpty && Hash.toHex(Hash.fromHex(revision)) != revision) | |
| throw new IllegalArgumentException("Gist revision must be hexadecimal or empty!") | |
| if (owner.isEmpty) throw new IllegalArgumentException("Gist owner must be non-empty!") | |
| override def toString = "Gist[owner=%s,id=%s,revision=%s,fileName=%s,localDirectory=%s]".format(owner, id, revision, fileName, localDirectory) | |
| } | |
| /** | |
| * APIVersion is the API for Github, | |
| * it is possible, if needed, to provide your own implementation of this, | |
| * see the `gistardAPIVersion` SettingKey. | |
| **/ | |
| trait APIVersion { | |
| /** | |
| * @return the URL to the contents of the given Gist | |
| **/ | |
| def contentURLFor(gist: Gist): URL | |
| /** | |
| * @return the URL to the summary of the given Gist | |
| **/ | |
| def summaryURLFor(gist: Gist): URL | |
| /** | |
| * Downloads all Gists given as the `gistDependencies` parameter, | |
| * doesn't update already existing files unless `force` is set to true. | |
| **/ | |
| def update(gistDependencies: Set[Gist], force: Boolean, log: Logger): Seq[File] = | |
| gistDependencies.flatMap(update(_, force, log))(scala.collection.breakOut) | |
| /** | |
| * Downloads all Gists given as the `gist` parameter, | |
| * doesn't update already existing files unless `force` is set to true. | |
| **/ | |
| def update(gist: Gist, force: Boolean, log: Logger): Option[File] = { | |
| val file = gist.localDirectory / gist.fileName | |
| if (file.isDirectory) { | |
| log.error("Gistard: Can't download %s since the file already exists but is a directory: %s".format(gist, file)) | |
| None | |
| } else if (force || !file.exists) { | |
| log.info("Gistard: downloading %s as %s".format(gist, file)) | |
| IO.withTemporaryFile("gistard", gist.fileName) { | |
| temp => | |
| IO.download(contentURLFor(gist), temp) | |
| if (file.exists) IO.delete(file) | |
| IO.move(temp, file) | |
| Some(file) | |
| } | |
| } else { | |
| log.info("Gistard: Using cached version of %s instead of downloading".format(file)) | |
| Some(file) | |
| } | |
| } | |
| /** | |
| * Deletes all Gists given as the `gistDependencies` parameter | |
| **/ | |
| def clean(gistDependencies: Set[Gist], log: Logger): Set[File] = | |
| gistDependencies.flatMap(clean(_, log)) | |
| /** | |
| * Deletes the Gist given as the `gist` parameter. | |
| **/ | |
| def clean(gist: Gist, log: Logger): Option[File] = { | |
| val file = gist.localDirectory / gist.fileName | |
| if (!file.exists) None | |
| else if (!file.isFile) { | |
| log.error("Gistard: Could not delete %s since it is a directory and not a file".format(file)) | |
| None | |
| } else if (!file.delete()) { | |
| log.error("Gistard: Could not delete: %s".format(file)) | |
| None | |
| } else { | |
| log.info("Gistard: Deleting %s".format(file)) | |
| Some(file) | |
| } | |
| } | |
| } | |
| object GithubV3 extends APIVersion { | |
| override def contentURLFor(gist: Gist): URL = | |
| if (gist.revision.isEmpty) | |
| new URL("https://gist.githubusercontent.com/%s/%s/raw/%s".format(gist.owner, gist.id, gist.fileName)) | |
| else | |
| new URL("https://gist.githubusercontent.com/%s/%s/raw/%s/%s".format(gist.owner, gist.id, gist.revision, gist.fileName)) | |
| override def summaryURLFor(gist: Gist): URL = | |
| if (gist.revision.isEmpty) | |
| new URL("https://api.github.com/gists/%d".format(gist.id)) | |
| else | |
| new URL("https://api.github.com/gists/%d/%s".format(gist.id, gist.revision)) | |
| } | |
| } | |
| object GistardPlugin extends AutoPlugin { | |
| import Gistard._ | |
| object autoImport { | |
| object GistardKeys { | |
| val gistardUpdate = TaskKey[Seq[JFile]]("gistard-update", "Downloads all Gist dependencies that aren't already downloaded") | |
| val gistardClean = TaskKey[Set[JFile]]("gistard-clean", "Deletes all Gist Dependencies") | |
| val gistardReload = TaskKey[Seq[JFile]]("gistard-reload", "Downloads all Gist dependencies") | |
| val gistardDependencies = SettingKey[Set[Gist]]("gistard-dependencies", "All Gist Dependencies") | |
| val gistardAPIVersion = SettingKey[APIVersion]("gistard-api-version", "What version of the Github API to use") | |
| } | |
| /** | |
| * Auto-imported convenience method to create a new `Gist` from the given parameters. | |
| **/ | |
| def gist(owner: String, id: String, revision: String, fileName: String, localDirectory: File): Gist = | |
| Gist(owner, id, revision, fileName, localDirectory) | |
| } | |
| import autoImport._ | |
| import GistardKeys._ | |
| override def requires = sbt.plugins.JvmPlugin | |
| override def trigger = allRequirements | |
| override lazy val projectSettings = Seq( | |
| gistardAPIVersion := GithubV3, | |
| gistardDependencies := Set(), | |
| gistardUpdate := (gistardAPIVersion).value.update(gistardDependencies.value, false, streams.value.log), | |
| gistardClean := (gistardAPIVersion).value.clean(gistardDependencies.value, streams.value.log), | |
| gistardReload := (gistardAPIVersion).value.update(gistardDependencies.value, true, streams.value.log), | |
| update <<= update dependsOn(gistardUpdate), | |
| clean <<= clean dependsOn(gistardClean) | |
| ) | |
| } |
Thanks @sschaef, I've updated Gistard (https://gist.github.com/viktorklang/a09aad920c1a4072cfe6/3cd3eb4131e6302d3a365d7919e810443012b331), so if you have enabled Gistard auto updating, you should get it when you do gistardReload.
Problem: cleaning with auto-updating enabled deletes Gistard itself.
> clean
[info] Gistard: Deleting /Users/pgiarrusso/.sbt/0.13/plugins/Gistard.scala
Restarting sbt now triggers a build failure, because the auto-update config references the now-deleted Gistard.
That was with the following in /Users/pgiarrusso/.sbt/0.13/gistard.sbt:
gistard.GistardPlugin.autoImport.GistardKeys.gistardDependencies += gistard.GistardPlugin.autoImport.gist("viktorklang", "a09aad920c1a4072cfe6", "", "Gistard.scala", new File(System.getProperty("user.home")) / ".sbt" / "0.13" / "plugins")(This looks awkward, but autoimports don't work in ~/.sbt — there was a ticket for that).
And with Gistard installed as:
cd ~/.sbt/0.13/plugins
wget https://gist.githubusercontent.com/viktorklang/a09aad920c1a4072cfe6/raw/Gistard.scalaWould that problem not show-up with a per-project installation?
@Blaisorblade Omg, I just saw your comment, 1 year late. :(
I haven't seen that problem in a per-project installation, could most definitely be related to having it in ~/.sbt
bug in https://gist.github.com/viktorklang/a09aad920c1a4072cfe6#file-gistard-scala-L191