Skip to content

Commit 192fcf5

Browse files
committed
SbtProcess supports multifile
1 parent 3650c0f commit 192fcf5

7 files changed

Lines changed: 39 additions & 63 deletions

File tree

api/src/main/scala/org/scastie/api/FileOrFolder.scala

Lines changed: 22 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import io.circe.syntax._
77
sealed trait FileOrFolder {
88
val name: String
99
val path: String
10+
1011
def isFolder: Boolean
1112
}
1213

@@ -40,63 +41,41 @@ object File {
4041
implicit val fileDecoder: Decoder[File] = deriveDecoder[File]
4142
}
4243

43-
object Folder {
44-
45-
def singleton(code: String): Folder = {
46-
Folder("root", List(File("Main.scala", code, "/root/Main.scala")), "/root", isRoot = true)
47-
}
48-
49-
implicit val folderEncoder: Encoder[Folder] =
50-
deriveEncoder[Folder].mapJson(_.deepMerge(Json.obj("isFolder" -> Json.fromBoolean(true))))
51-
implicit val folderDecoder: Decoder[Folder] = deriveDecoder[Folder]
52-
}
53-
5444
case class Folder(
5545
override val name: String,
5646
children: List[FileOrFolder] = List(),
57-
override val path: String = "",
58-
isRoot: Boolean = false
47+
override val path: String = ""
5948
) extends FileOrFolder {
6049
def isFolder: Boolean = true
6150

6251
def isEmpty: Boolean = children.isEmpty
6352

53+
def summary: String = {
54+
import System.{lineSeparator => nl}
55+
children.headOption match {
56+
case Some(File(_, content, _)) => content.split(nl).take(3).mkString(nl)
57+
case _ => this.toString.take(200) + "..."
58+
}
59+
}
60+
6461
def childHeadFileContent: String = {
6562
children.headOption match {
6663
case Some(f: File) => f.content
6764
case _ => ""
6865
}
6966
}
7067

71-
def take(i: Int): String = childHeadFileContent.take(i)
72-
73-
def split(nl: String): Array[String] = childHeadFileContent.split(nl)
68+
}
7469

75-
def add(ff: FileOrFolder): Folder = {
76-
if (this.path.nonEmpty) {
77-
val f = FileOrFolderUtils.prependPath(this.path, ff)
78-
this.copy(children = this.children :+ f)
79-
} else {
80-
val rootName = name
81-
val f = if (isRoot) FileOrFolderUtils.prependPath(rootName, ff) else ff
82-
this.copy(children = this.children :+ f)
83-
}
84-
}
70+
object Folder {
8571

86-
def add2(path: String, isFolder: Boolean = false): Folder = {
87-
path.split("/").toList match {
88-
case Nil => this
89-
case head :: Nil =>
90-
val newFilePath = this.path + "/" + head
91-
val newFile = if (isFolder) Folder(head, path = newFilePath) else File(head, newFilePath)
92-
copy(children = children :+ newFile)
93-
case head :: tail =>
94-
val newIntermediate = Folder(head, path = this.path + "/" + head)
95-
val folder = children.find(_.name.equals(head)).getOrElse(newIntermediate).asInstanceOf[Folder]
96-
copy(children = children.filterNot(_.name == head) :+ folder.add2(tail.mkString("/"), isFolder))
97-
}
72+
def singleton(code: String): Folder = {
73+
Folder("", List(File("code.scala", code, "/code.scala")), "/")
9874
}
9975

76+
implicit val folderEncoder: Encoder[Folder] =
77+
deriveEncoder[Folder].mapJson(_.deepMerge(Json.obj("isFolder" -> Json.fromBoolean(true))))
78+
implicit val folderDecoder: Decoder[Folder] = deriveDecoder[Folder]
10079
}
10180

10281
object FileOrFolderUtils {
@@ -159,11 +138,13 @@ object FileOrFolderUtils {
159138
}
160139

161140
def recomputePaths(f: Folder, prefix: String = ""): Folder = {
141+
val isRoot = f.name.isEmpty
142+
val currFolderPath = if (isRoot) prefix else prefix + "/" + f.name
162143
f.copy(
163-
path = prefix + "/" + f.name,
144+
path = if (isRoot) "/" else currFolderPath,
164145
children = f.children.map {
165-
case folder: Folder => recomputePaths(folder, prefix + "/" + f.name)
166-
case file: File => file.copy(path = prefix + "/" + f.name + "/" + file.name)
146+
case folder: Folder => recomputePaths(folder, prefix = currFolderPath)
147+
case file: File => file.copy(path = currFolderPath + "/" + file.name)
167148
}
168149
)
169150
}
@@ -183,15 +164,4 @@ object FileOrFolderUtils {
183164
})
184165
}
185166

186-
def prependPath(p: String, fileOrFolder: FileOrFolder): FileOrFolder = {
187-
fileOrFolder match {
188-
case f: File =>
189-
val nonEmptyPath = if (f.path.isEmpty) f.name else f.path
190-
f.copy(path = p + "/" + nonEmptyPath)
191-
case f: Folder =>
192-
val nonEmptyPath = if (f.path.isEmpty) f.name else f.path
193-
f.copy(children = f.children.map(x => prependPath(p + "/" + f.name, x)), path = p + "/" + nonEmptyPath)
194-
}
195-
}
196-
197167
}

client/src/main/scala/org/scastie/client/ScastieBackend.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ case class ScastieBackend(scastieId: UUID, serverUrl: Option[String], scope: Bac
154154
scope.modState(ss => {
155155
def updateTab(tab: Tab): Tab = {
156156
if (tab.tabId == f.path)
157-
tab.copy(tabId = dstFolderPath + "/" + f.name)
157+
tab.copy(tabId = dstFolderPath.stripSuffix("/") + "/" + f.name)
158158
else tab
159159
}
160160

client/src/main/scala/org/scastie/client/components/fileHierarchy/FileHierarchy.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ object FileHierarchy {
4545
Callback.empty
4646
} else {
4747
moveFileOrFolder(src, dstPath) >>
48-
fhs.setState(FileHierarchyState(selectedFile = dstPath + "/" + src.name, dragOver = ""))
48+
fhs.setState(FileHierarchyState(selectedFile = dstPath.stripSuffix("/") + "/" + src.name, dragOver = ""))
4949
}
5050
} else {
5151
fhs.modState(_.copy(dragOver = dragInfo.fileOrFolder.path))

sbt-runner/src/main/scala/org/scastie/sbt/SbtProcess.scala

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import org.scastie.util._
1818
import org.scastie.instrumentation.PositionMapper
1919

2020
import scala.concurrent.duration._
21+
import scala.reflect.io.Directory
2122
import scala.util.Random
2223

2324
object SbtProcess {
@@ -129,8 +130,8 @@ class SbtProcess(runTimeout: FiniteDuration,
129130
// log.info(s"sbtVersion: $sbtVersion")
130131
write(projectDir.resolve("build.properties"), s"sbt.version = ${org.scastie.buildinfo.BuildInfo.sbtVersion}")
131132
private val pluginFile = projectDir.resolve("plugins.sbt")
132-
private val codeFile = sbtDir.resolve("src/main/scala/main.scala")
133-
Files.createDirectories(codeFile.getParent)
133+
private val scalaDir = sbtDir.resolve("src/main/scala")
134+
Files.createDirectories(scalaDir)
134135

135136
private def scalaJsContent(): Option[String] = {
136137
slurp(sbtDir.resolve(Js.targetFilename))
@@ -210,7 +211,7 @@ class SbtProcess(runTimeout: FiniteDuration,
210211

211212
when(Ready) {
212213
case Event(task @ SbtTask(snippetId, taskInputs, ip, login, progressActor), SbtData(stateInputs)) =>
213-
println(s"Running: (login: $login, ip: $ip) \n ${taskInputs.code.take(30)}")
214+
println(s"Running: (login: $login, ip: $ip) \n ${taskInputs.code.toString.take(30)}")
214215

215216
val _sbtRun = SbtRun(
216217
snippetId = snippetId,
@@ -323,7 +324,14 @@ class SbtProcess(runTimeout: FiniteDuration,
323324
writeFile(buildFile, prompt + "\n" + inputs.sbtConfig)
324325
Files.deleteIfExists(sbtDir.resolve(Js.targetFilename))
325326
Files.deleteIfExists(sbtDir.resolve(Js.sourceMapFilename))
326-
write(codeFile, inputs.code.childHeadFileContent, truncate = true)
327+
new Directory(scalaDir.toFile).deleteRecursively()
328+
Files.createDirectories(scalaDir)
329+
330+
FileOrFolderUtils.allFiles(inputs.code).foreach(f => {
331+
val path = scalaDir.resolve(f.path.substring(1))
332+
Files.createDirectories(path.getParent)
333+
write(path, f.content, truncate = true)
334+
})
327335
}
328336

329337
private def writeFile(path: Path, content: String): Unit = {

storage/src/main/scala/org/scastie/storage/filesystem/FilesystemSnippetsContainer.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ trait FilesystemSnippetsContainer extends SnippetsContainer with GenericFilesyst
113113
List(
114114
SnippetSummary(
115115
snippetId,
116-
inputs.code.split(nl).take(3).mkString(nl),
116+
inputs.code.summary,
117117
getFileTimestamp(snippetId)
118118
)
119119
)

storage/src/main/scala/org/scastie/storage/inmemory/InMemorySnippetsContainer.scala

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import org.scastie.storage.UserLogin
77
import scala.collection.mutable
88
import scala.concurrent.Future
99

10-
import System.{lineSeparator => nl}
1110

1211

1312
trait InMemorySnippetsContainer extends SnippetsContainer {
@@ -41,7 +40,7 @@ trait InMemorySnippetsContainer extends SnippetsContainer {
4140
.map { m =>
4241
SnippetSummary(
4342
m.snippetId,
44-
m.inputs.code.split(nl).take(3).mkString(nl),
43+
m.inputs.code.summary,
4544
m.time
4645
)
4746
}

storage/src/main/scala/org/scastie/storage/mongodb/MongoDBSnippetsContainer.scala

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import org.mongodb.scala.model._
1010
import org.scastie.api._
1111
import org.scastie.storage._
1212

13-
import java.lang.System.{lineSeparator => nl}
1413
import scala.concurrent.Await
1514
import scala.concurrent.Future
1615
import scala.concurrent.duration._
@@ -156,7 +155,7 @@ trait MongoDBSnippetsContainer extends SnippetsContainer with GenericMongoContai
156155
val sortedSnippets = results.getOrElse(Nil).flatten.sortBy(-_.time)
157156
sortedSnippets
158157
.map(result =>
159-
SnippetSummary(result.snippetId, result.inputs.code.split(nl).take(3).mkString(nl), result.time)
158+
SnippetSummary(result.snippetId, result.inputs.code.summary, result.time)
160159
)
161160
.toList
162161
})

0 commit comments

Comments
 (0)