Skip to content

Commit afe1878

Browse files
committed
Add contents to file object, Echo command implementation
1 parent eb96b7e commit afe1878

File tree

4 files changed

+128
-4
lines changed

4 files changed

+128
-4
lines changed

filesystem/src/main/scala/com/codingmaniacs/scala/exercises/fs/commands/Command.scala

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ object Command {
3535
val TOUCH = "touch"
3636
val CD = "cd"
3737
val RM = "rm"
38+
val ECHO = "echo"
3839

3940
def emptyCommand: Command = new Command {
4041
override def apply(state: State): State = state
@@ -77,6 +78,12 @@ object Command {
7778
} else {
7879
new Rm(tokens(1))
7980
}
81+
} else if (ECHO.equals(tokens(0))) {
82+
if (tokens.length < 2) {
83+
incompleteCommand(ECHO)
84+
} else {
85+
new Echo(tokens.tail)
86+
}
8087
} else {
8188
new UnknownCommand
8289
}
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
/*
2+
* Copyright (c) 2019 Geektimus
3+
*
4+
* Permission is hereby granted, free of charge, to any person obtaining a copy of
5+
* this software and associated documentation files (the "Software"), to deal in
6+
* the Software without restriction, including without limitation the rights to
7+
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
8+
* the Software, and to permit persons to whom the Software is furnished to do so,
9+
* subject to the following conditions:
10+
*
11+
* The above copyright notice and this permission notice shall be included in all
12+
* copies or substantial portions of the Software.
13+
*
14+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
16+
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
17+
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
18+
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19+
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20+
*/
21+
22+
package com.codingmaniacs.scala.exercises.fs.commands
23+
24+
import com.codingmaniacs.scala.exercises.fs.State
25+
import com.codingmaniacs.scala.exercises.fs.directories.Directory
26+
import com.codingmaniacs.scala.exercises.fs.files.File
27+
28+
import scala.annotation.tailrec
29+
30+
class Echo(items: Array[String]) extends Command {
31+
32+
def createContent(items: Array[String], topIndex: Int): String = {
33+
34+
@tailrec
35+
def createContentRec(currIdx: Int, acc: String): String =
36+
currIdx match {
37+
case i if i >= topIndex => acc
38+
case i => createContentRec(i + 1, acc + items(currIdx))
39+
}
40+
41+
createContentRec(0, "")
42+
}
43+
44+
def getRootAfterEcho(
45+
currentDir: Directory,
46+
path: List[String],
47+
contents: String,
48+
append: Boolean
49+
): Directory =
50+
if (path.isEmpty) {
51+
currentDir
52+
} else if (path.tail.isEmpty) {
53+
val dirEntry = currentDir.findEntry(path.head)
54+
if (dirEntry == null) {
55+
currentDir.addEntry(new File(currentDir.path, path.head, contents))
56+
} else if (dirEntry.isDirectory) {
57+
currentDir
58+
} else {
59+
if (append) {
60+
currentDir.replaceEntry(path.head, dirEntry.asFile.appendContents(contents))
61+
} else {
62+
currentDir.replaceEntry(path.head, dirEntry.asFile.setContents(contents))
63+
}
64+
}
65+
} else {
66+
val nextDir = currentDir.findEntry(path.head).asDirectory
67+
val newNextDir = getRootAfterEcho(nextDir, path.tail, contents, append)
68+
69+
if (newNextDir == nextDir) {
70+
currentDir
71+
} else {
72+
currentDir.replaceEntry(path.head, newNextDir)
73+
}
74+
}
75+
76+
def doEcho(state: State, contents: String, filename: String, append: Boolean): State =
77+
if (filename.contains(Directory.SEPARATOR)) {
78+
state.setMessage("Echo: Filename must not contain separators")
79+
} else {
80+
val newRoot: Directory = getRootAfterEcho(
81+
state.root,
82+
state.workingDir.getAllFoldersInPath :+ filename,
83+
contents,
84+
append
85+
)
86+
if (newRoot == state.root) {
87+
state.setMessage(s"$filename: no such file")
88+
} else {
89+
State(newRoot, newRoot.findDescendant(state.workingDir.getAllFoldersInPath))
90+
}
91+
}
92+
93+
override def apply(state: State): State =
94+
if (items.isEmpty) {
95+
state
96+
} else if (items.size == 1) {
97+
state.setMessage(items(0))
98+
} else {
99+
val op = items(items.length - 2)
100+
val filename = items(items.length - 1)
101+
val contents = createContent(items, items.length - 2)
102+
if (">>".equals(op)) {
103+
doEcho(state, contents, filename, append = true)
104+
} else if (">".equals(op)) {
105+
doEcho(state, contents, filename, append = false)
106+
} else {
107+
state.setMessage(createContent(items, items.length))
108+
}
109+
}
110+
}

filesystem/src/main/scala/com/codingmaniacs/scala/exercises/fs/directories/Directory.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,8 @@ class Directory(
5959
findEntryHelper(entryName, contents)
6060
}
6161

62-
def replaceEntry(entryName: String, newEntry: Directory): Directory =
63-
new Directory(parentPath, name, contents.filter(p => !p.name.equals(entryName)) :+ newEntry)
62+
def replaceEntry(entryName: String, newEntry: DirEntry): Directory =
63+
new Directory(parentPath, name, contents.filter(e => !e.name.equals(entryName)) :+ newEntry)
6464

6565
def isRoot: Boolean = parentPath.isEmpty
6666

filesystem/src/main/scala/com/codingmaniacs/scala/exercises/fs/files/File.scala

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ package com.codingmaniacs.scala.exercises.fs.files
2323

2424
import com.codingmaniacs.scala.exercises.fs.directories.{ DirEntry, Directory }
2525

26-
class File(override val parentPath: String, override val name: String)
26+
class File(override val parentPath: String, override val name: String, val contents: String)
2727
extends DirEntry(parentPath, name) {
2828
override def asDirectory: Directory =
2929
throw new FileSystemException("A file cannot be converted to a directory!")
@@ -34,10 +34,17 @@ class File(override val parentPath: String, override val name: String)
3434

3535
override def isDirectory: Boolean = false
3636
override def isFile: Boolean = !isDirectory
37+
38+
def setContents(newContents: String): File =
39+
new File(parentPath, name, newContents)
40+
41+
def appendContents(newContents: String): File =
42+
setContents(contents + "\n" + newContents)
43+
3744
}
3845

3946
object File {
4047

4148
def empty(parentPath: String, name: String): File =
42-
new File(parentPath, name)
49+
new File(parentPath, name, "")
4350
}

0 commit comments

Comments
 (0)