Skip to content

Commit

Permalink
feat: CLIN-1179 - total average size from manifest
Browse files Browse the repository at this point in the history
  • Loading branch information
creativeyann17 committed Jun 17, 2022
1 parent a28847a commit 24fd334
Show file tree
Hide file tree
Showing 4 changed files with 39 additions and 22 deletions.
1 change: 1 addition & 0 deletions src/main/resources/application.conf
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ ferload-client {
abbreviate=30
config-name=".ferload-client.properties"
manifest-header="url"
manifest-size="size"
manifest-separator="\t"
download-files-pool=10
download-agreement="yes"
Expand Down
50 changes: 33 additions & 17 deletions src/main/scala/ca/ferlab/ferload/client/commands/Download.scala
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import picocli.CommandLine.{Command, IExitCodeGenerator, Option}

import java.io.{File, FileReader}
import java.util.Optional
import scala.collection.mutable
import scala.util.{Failure, Success, Try, Using}

@Command(name = "download", mixinStandardHelpOptions = true, description = Array("Download files based on provided manifest."),
Expand All @@ -31,6 +32,8 @@ class Download(userConfig: UserConfig,

@Option(names = Array("-p", "--password"), description = Array("password"))
var password: Optional[String] = Optional.empty

private val NO_SIZE = 0L;

override def run(): Unit = {

Expand Down Expand Up @@ -58,7 +61,7 @@ class Download(userConfig: UserConfig,

val padding = appConfig.getInt("padding")

val manifestContent: String = CommandBlock("Checking manifest file", successEmoji, padding) {
val manifestContent: ManifestContent = CommandBlock("Checking manifest file", successEmoji, padding) {
extractManifestContent
}

Expand All @@ -78,7 +81,7 @@ class Download(userConfig: UserConfig,
}

val links: Map[String, String] = CommandBlock("Retrieve Ferload download link(s)", successEmoji, padding) {
Try(ferload.getDownloadLinks(token, manifestContent)) match {
Try(ferload.getDownloadLinks(token, manifestContent.urls)) match {
case Success(links) => links
case Failure(e) => {
// always refresh token if failed
Expand All @@ -90,16 +93,17 @@ class Download(userConfig: UserConfig,
}

val totalExpectedDownloadSize = CommandBlock("Compute total average expected download size", successEmoji, padding) {
Try(s3.getTotalExpectedDownloadSize(links, appConfig.getLong("size-estimation-timeout"))) match {
case Success(size) => size
case Failure(e) => {
println()
println()
println(s"Failed to compute total average expected download size, reason: ${e.getMessage}")
print(s"You can still proceed with the download, verify you have remaining disk-space available.")
0L
}
}
manifestContent.totalSize.getOrElse(
Try(s3.getTotalExpectedDownloadSize(links, appConfig.getLong("size-estimation-timeout"))) match {
case Success(size) => size
case Failure(e) => {
println()
println()
println(s"Failed to compute total average expected download size, reason: ${e.getMessage}")
print(s"You can still proceed with the download, verify you have remaining disk-space available.")
NO_SIZE
}
})
}

val totalExpectedDownloadSizeStr = if(totalExpectedDownloadSize > 0) FileUtils.byteCountToDisplaySize(totalExpectedDownloadSize) else "-"
Expand Down Expand Up @@ -127,8 +131,9 @@ class Download(userConfig: UserConfig,
}
}

private def extractManifestContent: String = {
private def extractManifestContent: ManifestContent = {
val manifestHeader = appConfig.getString("manifest-header")
val manifestSize = appConfig.getString("manifest-size")
val manifestSeparator = appConfig.getString("manifest-separator").charAt(0)

if (!manifest.exists()) {
Expand All @@ -142,8 +147,10 @@ class Download(userConfig: UserConfig,
.withTrim()
.withFirstRecordAsHeader()
.parse(reader)
val builder = new StringBuilder
val urls = new mutable.StringBuilder
var totalSize = NO_SIZE
val fileIdColumnIndex = parser.getHeaderMap.getOrDefault(manifestHeader, -1)
val sizeColumnIndex = parser.getHeaderMap.getOrDefault(manifestSize, -1)

if (fileIdColumnIndex == -1) {
throw new IllegalStateException("Missing column: " + manifestHeader)
Expand All @@ -152,21 +159,30 @@ class Download(userConfig: UserConfig,
parser.getRecords.stream().forEach(record => {
val url = record.get(fileIdColumnIndex)
if (StringUtils.isNotBlank(url)) {
builder.append(s"$url\n")
urls.append(s"$url\n")
}
if (sizeColumnIndex != -1) { // size column exist (optional)
val size = record.get(sizeColumnIndex)
if (StringUtils.isNotBlank(size)) {
totalSize += size.toLong
}
}
})

if (builder.isEmpty) {
if (urls.isEmpty) {
throw new IllegalStateException("Empty content")
}

builder.toString()

ManifestContent(urls.toString(), if(totalSize == NO_SIZE) None else Some(totalSize))

} match {
case Success(value) => value
case Failure(e) => throw new IllegalStateException(s"Invalid manifest file: " + e.getMessage, e)
}
}

case class ManifestContent(urls: String, totalSize: scala.Option[Long])

override def getExitCode: Int = 1
}
8 changes: 4 additions & 4 deletions src/test/resources/manifest-valid.tsv
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
file_id
file1
file2
file3
file_id size
file1 1
file2 1
file3 1
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ class DownloadTest extends AnyFunSuite with BeforeAndAfter {
Set(new File("f1"), new File("f2"))
}

override def getTotalExpectedDownloadSize(links: Map[String, String], timeout: Long): Long = 2L
override def getTotalExpectedDownloadSize(links: Map[String, String], timeout: Long): Long = ???

override def getTotalAvailableDiskSpaceAt(manifest: File): Long = 1L
}
Expand Down

0 comments on commit 24fd334

Please sign in to comment.