I wrote
implicit object ManagedResourceApplicative extends Applicative[ManagedResource] {
override def pure[A](x: A): ManagedResource[A] = {
implicit val disposer: better.files.Disposable[A] = better.files.Disposable[A]((_: A) => {})
new ManagedResource(x)
}
override def ap[A, B](ff: ManagedResource[A => B])(fa: ManagedResource[A]): ManagedResource[B] = {
for {
f <- ff
a <- fa
} yield f(a)
}
}
with use cats
And use
val mFiles: List[ManagedResource[File]] = ...
for {
files <- mFiles.sequence
} doSomesing
Its work. But I'm not sure it's right.
Hey, does anyone know of a way to handle malformed characters when using better files?
I'm getting this error
Exception in thread "main" java.nio.charset.MalformedInputException: Input length = 1
at java.nio.charset.CoderResult.throwException(CoderResult.java:281)
at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:339)
at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:178)
at java.io.InputStreamReader.read(InputStreamReader.java:184)
at java.io.BufferedReader.fill(BufferedReader.java:161)
at java.io.BufferedReader.readLine(BufferedReader.java:324)
at java.io.BufferedReader.readLine(BufferedReader.java:389)
at java.nio.file.Files.readAllLines(Files.java:3205)
at better.files.File.lines(File.scala:282)
def linesSkipMalformed(file: File)(implicit charset: Charset = better.files.DefaultCharset): Traversable[String] = {
@throws[IOException]
def skippingBufferedReader(path: Path, cs: Charset): BufferedReader = {
val decoder = cs.newDecoder.onMalformedInput(CodingErrorAction.IGNORE)
val reader = new InputStreamReader(Files.newInputStream(path), decoder)
new BufferedReader(reader)
}
@throws[IOException]
def readAllLines(path: Path, cs: Charset): util.List[String] = {
val reader: BufferedReader = skippingBufferedReader(path,cs)
val result: util.List[String] = new util.ArrayList[String]
var line: String = ""
do {
line = reader.readLine
if(line != null) result.add(line)
} while(line != null)
if(reader != null) reader.close()
result
}
readAllLines(file.path,charset).asScala
}
File => Boolean
option to accept or reject. But, then you can see that so many other APIs would deserve that filter and not just copyTo and now we made the interface of better-files crazy because of your one use case.
package services
import javax.inject._
import sun.misc.{ BASE64Encoder, BASE64Decoder }
import better.files.{File => ScalaFile}
import java.io.{ FileInputStream, FileOutputStream }
import org.apache.commons.codec.binary.Base64
import com.google.common.io.CharStreams
import java.io.{ InputStream, InputStreamReader }
import com.google.common.base.Charsets
/**
* FileEncoder.scala
*
* Context:
* The service aim to provide easy-to-use file R/W operations throughout Stormwind.io code base.
* It will have utilities such as getActionAsBase64
*/
class FileSystem () {
/**
* Map ScalaFile to File for test mocking
*/
val File = ScalaFile
/**
* Read file as a string
*
* @example
* val fs = new FileSystem
* fs.readFileAsString("~/tmp/test.txt")
* // returns a base64 representation of the file
*
* @param path
* @return
* @sideEffect
*/
def readFileAsString(path: String): String = {
// Reading the file as a FileInputStream
val fileInputStream = new FileInputStream(File(path).toJava)
// TODO: Is there a way to read as Bytes directly?
val str = CharStreams.toString(new InputStreamReader(fileInputStream, Charsets.UTF_8))
return str
}
/**
* Zips an action if a zip file under the action directory doesn't already exist
* Also you can forcefully zip the task, which deletes already existing ones
*
* @example
* fs.zipDirIfNotExist("github", "triggers", "list_webhooks")
* // creates a zip file under tasks/github/list_webhooks/list_webhooks.zip
*
* @param appName
* @param taskType
* @param taskName
* @param force - Forcefully delete the existing zip file
*/
def zipTaskIfNotExist(
appName: String,
taskType: String,
taskName: String,
force: Boolean = true
): Boolean = {
val pwd = System.getProperty("user.dir")
val dirPath = s"${pwd}/tasks/${appName}/${taskType}/${taskName}"
val zipPath = s"${dirPath}/${taskName}.zip"
val dir = File(dirPath)
val zipFile = File(zipPath)
if (force && zipFile.exists()) {
zipFile.delete()
}
if (!zipFile.exists()) {
dir.zipTo(zipFile.path)
}
true
}
/**
* Get the zip folder of action as Base64.
* This is typically need to interact with the OpenWhisk API for creating actions
* by passing in the base64 representation of the ZIP file.
*
* @example
* val fs = new FileSystem
* // Execution of the code below return a base64 representation of the task
* val result = fs.getActionAsBase64("github", "triggers", "list_webhooks")
*
* @param appName - application name such as Github
* @param taskType - taskType can be either actions or triggers
* @param taskName - name of the task such as create_issue
* @return
*/
def getActionAsBase64(
appName: String,
taskType: String,
taskName: String,
// Use the default method if possible
readFileAsString: (String) => String = this.readFileAsString
): String = {
val pwd = System.getProperty("user.dir")
val dirPath = s"${pwd}/tasks/${appName}/${taskType}/${taskName}"
val zipPath = s"${dirPath}/${taskName}.zip"
val content: String = readFileAsString(zipPath)
// Encoding the file using Base64encoder
val encoded = new BASE64Encoder().encode(content.getBytes(Charsets.UTF_8))
return encoded.toString
}
}
I have above class in my source code
zipTaskIfNotExist
; how would you mock ScalaFile or how would you write a unit test for it?
class FakeFile(val path: String) {
def exists(): Boolean = {
if (path.endsWith(".zip")) {
return true
} else {
return true
}
}
def delete(): Unit = {}
}
/**
* Unit tests can run without a full Play application.
*/
class FileSystemSpec extends PlaySpec {
"zipTaskIfNotExist" should {
"return true without errors" in {
val fs = new FileSystem {
override val File = FakeFile
}
val result = fs.zipTaskIfNotExist("github", "hello", "zz")
result must equal(true)
}
}
}
}
[error] /home/jason/Desktop/stormwind.io/test/unit/services/FileSystemSpec.scala:53:31: not found: value FakeFile
[error] override val File = FakeFile
[error] ^
[error] one error found
AccessDeniedError
means you don't have permission to write to that folder. This is not coming from better-file but from the JDK std lib itself (in the case of I/O from the OS itself)