All Downloads are FREE. Search and download functionalities are using the official Maven repository.

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
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy