jove.notebook.components.Content.scala Maven / Gradle / Ivy
The newest version!
package jove
package notebook.components
import java.io.{PrintWriter, File}
import java.net.URLDecoder
import scalaz._, Scalaz._
import argonaut._, Argonaut._, Shapeless._
import jove.protocol.Notebook
import jove.notebook.Protocol.{FileModel, NotebookModel, DirectoryModel, Model}
import org.joda.time.DateTime
import jove.helpers.Kernels
class Content(kernelComponent: => Kernels, notebookPath: File) extends LazyLogging {
lazy val contentDir = {
val d = notebookPath .getAbsoluteFile
if (d.exists()) {
if (!d.isDirectory)
throw new Exception(s"${d.getAbsolutePath} is not a directory")
} else {
if (d.mkdirs())
logger debug s"Created root content directory ${d.getAbsolutePath}"
else {
logger error s"Cannot create root content directory ${d.getAbsolutePath}"
Console.err println
s"""Warning: cannot create root notebook directory ${d.getPath}
|Do you have the permissions to create it?
|This will likely result in server errors in the notebook UI.""".stripMargin
}
}
d
}
def splitPath(path: String): List[String] =
if (path.isEmpty)
Nil
else
URLDecoder.decode(path, "UTF-8").split('/').toList
def fileFor(path: String): String \/ File =
fileFor(splitPath(path))
def fileFor(parts: List[String]): String \/ File =
if (parts.isEmpty)
contentDir.right
else if (parts.exists(_ startsWith "."))
"Invalid path".left
else
(contentDir /: parts)(new File(_, _)).right
def model(path: List[String], withContent: Boolean): String \/ Model =
for {
f <- fileFor(path)
m <- model(f, path, withContent)
} yield m
def model(f: File, path: List[String], withContent: Boolean): String \/ Model =
if (f.isDirectory)
DirectoryModel(
"directory",
if (withContent)
Option(f.list()).getOrElse(Array.empty[String]).toList.map(n => model(path :+ n, withContent = false)).collect{case \/-(m) => m}
else
Nil,
Some("json"),
f.getName,
path mkString "/",
new DateTime(f.lastModified()).toString,
"", // new DateTime(Files.readAttributes(f.getAbsoluteFile.toPath, classOf[BasicFileAttributes]).creationTime().toMillis) .toString,
None,
writable = true
).right
else if (f.isFile) {
if (kernelComponent.isNotebookFilename(f.getName))
io.Source.fromFile(f).getLines().mkString("\n").decodeEither[Json].map(json =>
NotebookModel(
"notebook",
json,
Some("json"),
f.getName,
path mkString "/",
new DateTime(f.lastModified()) .toString,
"", // new DateTime(Files.readAttributes(f.toPath, classOf[BasicFileAttributes]).creationTime().toMillis) .toString,
None,
writable = true
)
)
else
FileModel(
"file",
io.Source.fromFile(f).getLines().mkString("\n"),
Some("json"),
f.getName,
path mkString "/",
new DateTime(f.lastModified()).toString,
"", // new DateTime(Files.readAttributes(f.toPath, classOf[BasicFileAttributes]).creationTime().toMillis) .toString,
None,
writable = true
).right
} else
s"File ${f.getAbsolutePath} does not exist or is not a file or directory".left
private val checkpointDirName = ".ipynb_checkpoints"
val checkpointId = "checkpoint"
def checkpointFile(f: File, checkpointId: String): File = {
val d = f.getParentFile
val n = f.getName
val idx = n lastIndexOf '.'
val (base, extOpt) =
if (idx < 0)
(n, None)
else
(n take idx, Some(n drop idx + 1))
new File(new File(d, checkpointDirName), s"$base-$checkpointId${extOpt.map(".".+).mkString}")
}
private val defaultUntitledDirectory = "new_directory"
private val defaultUntitledFile = "new_file"
private val defaultUntitledNotebook = "new_notebook"
def create(_type: String, f: File): Unit =
_type match {
case "directory" =>
f.mkdirs()
case "notebook" =>
val w = new PrintWriter(f)
w write Notebook(4, 1, Map.empty, Nil).asJson.spaces2
w.close()
case _ =>
val w = new PrintWriter(f)
w.close()
}
def newIn(dir: File, _type: String, extOpt: Option[String], count: Int = 0): String = {
val base = _type match {
case "directory" =>
defaultUntitledDirectory
case "notebook" =>
defaultUntitledNotebook
case _ =>
defaultUntitledFile
}
val name =
if (count == 0)
s"$base${extOpt.map(".".+).mkString}"
else
s"$base $count${extOpt.map(".".+).mkString}"
val f = new File(dir, name)
if (f.exists())
newIn(dir, _type, extOpt, count + 1)
else {
create(_type, f)
name
}
}
}