-
Notifications
You must be signed in to change notification settings - Fork 99
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
10 changed files
with
249 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,3 +6,4 @@ Gemfile.lock | |
/vendor/bundle | ||
css/main.css | ||
.sass-cache | ||
target |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
scalaVersion := "2.11.8" | ||
|
||
name := "typelevel-blog-tut" | ||
|
||
scalacOptions ++= Seq( | ||
"-deprecation", | ||
"-feature" | ||
) | ||
|
||
libraryDependencies ++= Seq( | ||
"io.get-coursier" %% "coursier" % "1.0.0-M14", | ||
"io.get-coursier" %% "coursier-cache" % "1.0.0-M14", | ||
"com.chuusai" %% "shapeless" % "2.3.0", | ||
"org.yaml" % "snakeyaml" % "1.17" | ||
) | ||
|
||
lazy val tutInput = SettingKey[File]("tutInput") | ||
lazy val tutOutput = SettingKey[File]("tutOutput") | ||
lazy val tutVersion = SettingKey[String]("tutVersion") | ||
|
||
tutInput := (baseDirectory in ThisBuild).value / "_tut" | ||
tutOutput := (baseDirectory in ThisBuild).value / "_posts" | ||
tutVersion := "0.4.4" | ||
|
||
watchSources ++= (tutInput.value ** "*.md").get | ||
|
||
enablePlugins(BuildInfoPlugin) | ||
|
||
buildInfoKeys := Seq[BuildInfoKey](tutInput, tutOutput, tutVersion) | ||
|
||
buildInfoPackage := "org.typelevel.blog" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
sbt.version=0.13.12 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
addSbtPlugin("com.eed3si9n" % "sbt-buildinfo" % "0.6.1") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
package org.typelevel.blog | ||
|
||
import coursier._ | ||
import coursier.util.Parse | ||
import java.io.File | ||
import java.net.URLClassLoader | ||
|
||
case class Tut(scala: String, binaryScala: String, dependencies: List[String]) { | ||
|
||
val tutResolution: Resolution = Resolution(Set( | ||
Dependency(Module("org.tpolecat", s"tut-core_$binaryScala"), BuildInfo.tutVersion) | ||
)) | ||
|
||
val libResolution: Resolution = Resolution(dependencies.map { dep => | ||
val (mod, v) = Parse.moduleVersion(dep, binaryScala).right.get | ||
Dependency(mod, v) | ||
}.toSet) | ||
|
||
def invoke(file: File): Unit = { | ||
val tutClasspath = resolve(tutResolution).get | ||
val libClasspath = resolve(libResolution).get | ||
|
||
val classLoader = new URLClassLoader(tutClasspath.map(_.toURI.toURL).toArray, null) | ||
val tutClass = classLoader.loadClass("tut.TutMain") | ||
val tutMain = tutClass.getDeclaredMethod("main", classOf[Array[String]]) | ||
|
||
val commandLine = Array( | ||
file.toString, | ||
BuildInfo.tutOutput.toString, | ||
".*", | ||
"-classpath", | ||
libClasspath.mkString(File.pathSeparator) | ||
) | ||
|
||
tutMain.invoke(null, commandLine) | ||
} | ||
} | ||
|
||
case class FrontMatter(tut: Tut) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package org.typelevel.blog | ||
|
||
import org.yaml.snakeyaml.Yaml | ||
|
||
object Main extends App { | ||
|
||
val posts = BuildInfo.tutInput.listFiles().toList.filter { file => | ||
file.isFile() && file.getName.endsWith(".md") | ||
}.map(Post(_)) | ||
|
||
posts.foreach(_.process()) | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
package org.typelevel.blog | ||
|
||
import coursier._ | ||
import java.io.{File, FileInputStream} | ||
import java.nio.file.Files | ||
import org.yaml.snakeyaml.Yaml | ||
import scala.util.Try | ||
|
||
case class Post(file: File) { | ||
|
||
lazy val frontMatter: Option[FrontMatter] = Try { | ||
val yaml = new Yaml() | ||
val stream = new FileInputStream(file) | ||
val any = yaml.loadAll(stream).iterator.next() | ||
stream.close() | ||
any | ||
}.flatMap(YAML.decodeTo[FrontMatter]).toOption | ||
|
||
lazy val out: File = | ||
new File(BuildInfo.tutOutput.toString + File.separator + file.getName) | ||
|
||
def outdated(): Boolean = | ||
!(out.exists() && out.isFile() && file.lastModified() <= out.lastModified()) | ||
|
||
def process(): Unit = | ||
if (outdated()) { | ||
println(s"Processing ${file.getName} ...") | ||
|
||
frontMatter match { | ||
case Some(FrontMatter(tut)) => | ||
tut.invoke(file) | ||
case None => | ||
println("No tut header, copying.") | ||
Files.copy(file.toPath, out.toPath) | ||
} | ||
} | ||
else { | ||
println(s"Skipping ${file.getName} (up to date).") | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
package org.typelevel.blog | ||
|
||
import org.yaml.snakeyaml.Yaml | ||
import scala.collection.JavaConverters._ | ||
import scala.util.Try | ||
import shapeless._ | ||
import shapeless.labelled.FieldType | ||
|
||
trait YAML[T] { | ||
def rawDecode(any: Any): T | ||
|
||
final def decode(any: Any): Try[T] = | ||
Try(rawDecode(any)) | ||
} | ||
|
||
trait LowPriorityYAML { | ||
|
||
implicit def deriveInstance[F, G](implicit gen: LabelledGeneric.Aux[F, G], yg: Lazy[YAML[G]]): YAML[F] = | ||
new YAML[F] { | ||
def rawDecode(any: Any) = gen.from(yg.value.rawDecode(any)) | ||
} | ||
|
||
} | ||
|
||
object YAML extends LowPriorityYAML { | ||
|
||
def apply[T](implicit T: YAML[T]): YAML[T] = T | ||
|
||
def decodeTo[T : YAML](any: Any): Try[T] = | ||
YAML[T].decode(any) | ||
|
||
implicit def listYAML[T : YAML]: YAML[List[T]] = | ||
new YAML[List[T]] { | ||
def rawDecode(any: Any) = | ||
any.asInstanceOf[java.util.List[_]].asScala.toList.map(YAML[T].rawDecode) | ||
} | ||
|
||
implicit def stringYAML: YAML[String] = | ||
new YAML[String] { | ||
def rawDecode(any: Any) = | ||
any.asInstanceOf[String] | ||
} | ||
|
||
implicit def deriveHNil: YAML[HNil] = | ||
new YAML[HNil] { | ||
def rawDecode(any: Any) = HNil | ||
} | ||
|
||
implicit def deriveHCons[K <: Symbol, V, T <: HList] | ||
(implicit | ||
key: Witness.Aux[K], | ||
yv: Lazy[YAML[V]], | ||
yt: Lazy[YAML[T]] | ||
): YAML[FieldType[K, V] :: T] = new YAML[FieldType[K, V] :: T] { | ||
def rawDecode(any: Any) = { | ||
val k = key.value.name | ||
val map = any.asInstanceOf[java.util.Map[String, _]] | ||
if (!map.containsKey(k)) | ||
throw new IllegalArgumentException(s"key $k not defined") | ||
val head: FieldType[K, V] = labelled.field(yv.value.rawDecode(map.get(k))) | ||
val tail = yt.value.rawDecode(map) | ||
head :: tail | ||
} | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
package org.typelevel.blog | ||
|
||
import coursier._ | ||
import java.io.File | ||
import scala.language.implicitConversions | ||
import scala.util.{Failure, Success, Try} | ||
import scalaz.\/ | ||
import scalaz.concurrent.Task | ||
import scalaz.std.list._ | ||
import scalaz.syntax.traverse._ | ||
|
||
object `package` { | ||
|
||
val repositories = Seq( | ||
Cache.ivy2Local, | ||
MavenRepository("https://repo1.maven.org/maven2"), | ||
MavenRepository("https://dl.bintray.com/tpolecat/maven/") | ||
) | ||
|
||
implicit def eitherToTry[T](e: Throwable \/ T): Try[T] = | ||
e.fold(Failure(_), Success(_)) | ||
|
||
def resolve(start: Resolution): Try[List[File]] = { | ||
val logger = new Cache.Logger { | ||
override def downloadingArtifact(url: String, file: File) = | ||
println(s"Downloading artifact from $url ...") | ||
override def downloadedArtifact(url: String, success: Boolean) = { | ||
val file = url.split('/').last | ||
if (success) | ||
println(s"Successfully downloaded $file") | ||
else | ||
println(s"Failed to download $file") | ||
} | ||
} | ||
|
||
val fetch = Fetch.from(repositories, Cache.fetch(logger = Some(logger))) | ||
|
||
start.process.run(fetch).unsafePerformSyncAttempt.flatMap { resolution => | ||
if (!resolution.isDone) | ||
\/.left(new RuntimeException("resolution did not converge")) | ||
else if (!resolution.conflicts.isEmpty) | ||
\/.left(new RuntimeException(s"resolution has conflicts: ${resolution.conflicts.mkString(", ")}")) | ||
else if (!resolution.errors.isEmpty) | ||
\/.left(new RuntimeException(s"resolution has errors: ${resolution.errors.mkString(", ")}")) | ||
else { | ||
Task.gatherUnordered( | ||
resolution.artifacts.map(artifact => | ||
Cache.file(artifact, logger = Some(logger)).run | ||
) | ||
).unsafePerformSyncAttempt.map(_.sequenceU).flatMap(_.leftMap(err => new RuntimeException(err.describe))) | ||
} | ||
} | ||
} | ||
|
||
} |