Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #133 from eed3si9n/wip/content_hash
Include content hash into File hash value
- Loading branch information
Showing
14 changed files
with
350 additions
and
93 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
/* | ||
* Copyright (C) 2023 Eugene Yokota | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package sjsonnew | ||
|
||
import java.io.File | ||
import java.net.URI | ||
import java.nio.file.{ Path, Paths } | ||
|
||
trait FileIsoStringLongs { | ||
implicit lazy val fileStringLongIso: IsoStringLong[File] = IsoStringLong.iso[File]( | ||
(file: File) => (IsoStringLong.fileToString(file), HashUtil.farmHash(file.toPath())), | ||
(p: (String, Long)) => IsoStringLong.uriToFile(new URI(p._1))) | ||
|
||
implicit lazy val pathStringLongIso: IsoStringLong[Path] = IsoStringLong.iso[Path]( | ||
(file: Path) => (file.toString, HashUtil.farmHash(file)), | ||
(p: (String, Long)) => Paths.get(p._1)) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
/* | ||
* Copyright (C) 2023 Eugene Yokota | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package sjsonnew | ||
|
||
import java.io.File | ||
import java.net.{ URI, URL } | ||
import java.util.Locale | ||
|
||
trait IsoStringLong[A] { | ||
def to(a: A): (String, Long) | ||
def from(p: (String, Long)): A | ||
} | ||
|
||
object IsoStringLong { | ||
def iso[A](to0: A => (String, Long), from0: ((String, Long)) => A): IsoStringLong[A] = new IsoStringLong[A] { | ||
def to(a: A): (String, Long) = to0(a) | ||
def from(p: (String, Long)): A = from0(p) | ||
} | ||
|
||
private[sjsonnew] lazy val isWindows: Boolean = | ||
System.getProperty("os.name").toLowerCase(Locale.ENGLISH).contains("windows") | ||
|
||
private[sjsonnew] final val FileScheme = "file" | ||
|
||
private[sjsonnew] def fileToString(file: File): String = { | ||
val p = file.getPath | ||
if (p.startsWith(File.separatorChar.toString) && isWindows) { | ||
if (p.startsWith("""\\""")) { | ||
// supports \\laptop\My Documents\Some.doc on Windows | ||
new URI(FileScheme, normalizeName(p), null).toASCIIString | ||
} | ||
else { | ||
// supports /tmp on Windows | ||
new URI(FileScheme, "", normalizeName(p), null).toASCIIString | ||
} | ||
} else if (file.isAbsolute) { | ||
//not using f.toURI to avoid filesystem syscalls | ||
//we use empty string as host to force file:// instead of just file: | ||
new URI(FileScheme, "", normalizeName(ensureHeadSlash(file.getAbsolutePath)), null).toASCIIString | ||
} else { | ||
new URI(null, normalizeName(file.getPath), null).toASCIIString | ||
} | ||
} | ||
|
||
private[this] def ensureHeadSlash(name: String) = { | ||
if(name.nonEmpty && name.head != File.separatorChar) s"${File.separatorChar}$name" | ||
else name | ||
} | ||
private[this] def normalizeName(name: String) = { | ||
val sep = File.separatorChar | ||
if (sep == '/') name else name.replace(sep, '/') | ||
} | ||
|
||
private[sjsonnew] def uriToFile(uri: URI): File = { | ||
val part = uri.getSchemeSpecificPart | ||
// scheme might be omitted for relative URI reference. | ||
assert( | ||
Option(uri.getScheme) match { | ||
case None | Some(FileScheme) => true | ||
case _ => false | ||
}, | ||
s"Expected protocol to be '$FileScheme' or empty in URI $uri" | ||
) | ||
Option(uri.getAuthority) match { | ||
case None if part startsWith "/" => new File(uri) | ||
case _ => | ||
if (!(part startsWith "/") && (part contains ":")) new File("//" + part) | ||
else new File(part) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
/* | ||
* Copyright (C) 2023 Eugene Yokota | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package sjsonnew | ||
|
||
trait IsoStringLongFormats { | ||
implicit def isoStringLongFormat[A: IsoStringLong]: JsonFormat[A] = new JsonFormat[A] { | ||
val iso = implicitly[IsoStringLong[A]] | ||
def write[J](a: A, builder: Builder[J]): Unit = { | ||
val p = iso.to(a) | ||
builder.beginObject() | ||
builder.addFieldName("first") | ||
builder.writeString(p._1) | ||
builder.addFieldName("second") | ||
builder.writeLong(p._2) | ||
builder.endObject() | ||
} | ||
def read[J](jsOpt: Option[J], unbuilder: Unbuilder[J]): A = | ||
jsOpt match { | ||
case Some(js) => | ||
unbuilder.beginObject(js) | ||
val first = unbuilder.readField[String]("first") | ||
val second = unbuilder.readField[Long]("second") | ||
unbuilder.endObject() | ||
iso.from((first, second)) | ||
case None => deserializationError(s"Expected JsObject but got None") | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
/* | ||
* Copyright (C) 2023 Eugene Yokota | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package sjsonnew | ||
|
||
import java.io.File | ||
import java.net.URI | ||
import java.nio.file.{ Path, Paths } | ||
|
||
trait PathOnlyFormats { | ||
implicit val pathOnlyFileFormat: JsonFormat[File] = new JsonFormat[File] { | ||
def write[J](file: File, builder: Builder[J]): Unit = | ||
builder.writeString(IsoStringLong.fileToString(file)) | ||
def read[J](jsOpt: Option[J], unbuilder: Unbuilder[J]): File = | ||
jsOpt match { | ||
case Some(js) => IsoStringLong.uriToFile(new URI(unbuilder.readString(js))) | ||
case None => deserializationError(s"Expected JsString but got None") | ||
} | ||
} | ||
|
||
implicit val pathOnlyPathFormat: JsonFormat[Path] = new JsonFormat[Path] { | ||
def write[J](file: Path, builder: Builder[J]): Unit = | ||
builder.writeString(file.toString) | ||
def read[J](jsOpt: Option[J], unbuilder: Unbuilder[J]): Path = | ||
jsOpt match { | ||
case Some(js) => Paths.get(unbuilder.readString(js)) | ||
case None => deserializationError(s"Expected JsString but got None") | ||
} | ||
} | ||
} | ||
|
||
object PathOnlyFormats extends PathOnlyFormats |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.