diff --git a/src/main/kotlin/ley/anvil/modpacktools/command/AbstractCommand.kt b/src/main/kotlin/ley/anvil/modpacktools/command/AbstractCommand.kt index 9d3ebed..63ff48f 100644 --- a/src/main/kotlin/ley/anvil/modpacktools/command/AbstractCommand.kt +++ b/src/main/kotlin/ley/anvil/modpacktools/command/AbstractCommand.kt @@ -20,9 +20,7 @@ constructor( ArgumentParsers.newFor(displayName) .build() .description(helpMessage) - .apply { - addArgs() - } + .apply {addArgs()} } /** @@ -31,5 +29,5 @@ constructor( * * @receiver the parser to add the args to */ - open fun ArgumentParser.addArgs() {} + protected open fun ArgumentParser.addArgs() {} } diff --git a/src/main/kotlin/ley/anvil/modpacktools/commands/BuildTechnic.kt b/src/main/kotlin/ley/anvil/modpacktools/commands/BuildTechnic.kt index b087ac2..eca7431 100644 --- a/src/main/kotlin/ley/anvil/modpacktools/commands/BuildTechnic.kt +++ b/src/main/kotlin/ley/anvil/modpacktools/commands/BuildTechnic.kt @@ -8,6 +8,7 @@ import ley.anvil.modpacktools.command.AbstractCommand import ley.anvil.modpacktools.command.CommandReturn import ley.anvil.modpacktools.command.CommandReturn.Companion.fail import ley.anvil.modpacktools.command.LoadCommand +import ley.anvil.modpacktools.util.FileToDownload import ley.anvil.modpacktools.util.addonscript.installFile import ley.anvil.modpacktools.util.downloadFiles import ley.anvil.modpacktools.util.fPrintln @@ -16,7 +17,6 @@ import net.sourceforge.argparse4j.inf.Namespace import org.apache.commons.io.FileUtils import java.io.File import java.io.FileOutputStream -import java.net.URL import java.util.zip.ZipOutputStream @LoadCommand @@ -37,39 +37,51 @@ object BuildTechnic : AbstractCommand("BuildTechnic") { } val fileList = mutableListOf() - val toDownload = mutableMapOf>() - MPJH.asWrapper!!.defaultVersion.getRelations {"client" in it.options}.forEach { - if(it.hasFile()) - fileList.add(it.file.get()) - } + //Map of File to Installer + val toDownload = mutableMapOf() + + //RELATIONS + fileList.addAll( + MPJH.asWrapper!!.defaultVersion.getRelations {"client" in it.options}.filter {it.hasFile()} + .map {it.file.get()} + ) + //FILES + fileList.addAll(MPJH.asWrapper!!.defaultVersion.getFiles {true}.map {it.get()}) + + //FORGE + @Suppress("DEPRECATION") //no idea why this is deprecated. Too Bad! + val forge = MPJH.asWrapper!!.defaultVersion.getRelations {it.id.toLowerCase() == "forge"}.first().forgeUniversal + toDownload[ + FileToDownload( + //Technic wants it to be called modpack.jar + File(download, "modpack.jar"), + forge.url + ) + ] = "internal.dir:bin" fileList.forEach { when { - it.isFile -> { + !it.isURL -> { if(!it.isASDirSet) it.setASDir(srcDir) - if(it.file.exists()) installFile(it.installer, it.file, tmp).printf() } - it.isURL -> toDownload[it.url] = it.installer to download + it.isURL -> toDownload[FileToDownload(download, it.url, true)] = it.installer else -> return fail("${it.link} is neither a file nor an URL") } } - downloadFiles( - toDownload.mapValues {it.value.second}, - { - if(it.exception == null) { - fPrintln("downloaded file ${it.file}", TERMC.brightBlue) - installFile(toDownload[it.url]!!.first, it.file, tmp).printf() - } else { - fPrintln("ERROR DOWNLOADING ${it.url}") - it.exception.printStackTrace() - } - }, - resolveFileName = true - ) + downloadFiles(toDownload.keys.toList()) { + if(it.downloadedFile != null) { + fPrintln("${it.responseCode} ${it.responseMessage} ${it.file.url} ${it.downloadedFile}", TERMC.brightBlue) + //Use map of file to installer to get installer for given file + installFile(toDownload[it.file]!!, it.downloadedFile, tmp).printf() + } else if(it.exception != null) { + fPrintln("ERROR DOWNLOADING ${it.file.url}") + it.exception.printStackTrace() + } + } fPrintln("Making Zip", TERMC.brightGreen) ZipOutputStream(FileOutputStream("build/${MPJH.asWrapper!!.json.id}-${MPJH.asWrapper!!.defaultVersion.versionName}-technic.zip")) diff --git a/src/main/kotlin/ley/anvil/modpacktools/commands/BuildTwitch.kt b/src/main/kotlin/ley/anvil/modpacktools/commands/BuildTwitch.kt index 53b968e..6c6ea40 100644 --- a/src/main/kotlin/ley/anvil/modpacktools/commands/BuildTwitch.kt +++ b/src/main/kotlin/ley/anvil/modpacktools/commands/BuildTwitch.kt @@ -8,6 +8,7 @@ import ley.anvil.modpacktools.command.CommandReturn import ley.anvil.modpacktools.command.CommandReturn.Companion.fail import ley.anvil.modpacktools.command.CommandReturn.Companion.success import ley.anvil.modpacktools.command.LoadCommand +import ley.anvil.modpacktools.util.FileToDownload import ley.anvil.modpacktools.util.addonscript.installFile import ley.anvil.modpacktools.util.arg import ley.anvil.modpacktools.util.downloadFiles @@ -18,11 +19,9 @@ import net.sourceforge.argparse4j.impl.Arguments.storeTrue import net.sourceforge.argparse4j.inf.ArgumentParser import net.sourceforge.argparse4j.inf.Namespace import org.apache.commons.io.FileUtils -import org.apache.commons.io.FilenameUtils import java.io.File import java.io.FileOutputStream import java.io.FileWriter -import java.net.URL import java.util.zip.ZipOutputStream @LoadCommand @@ -45,7 +44,7 @@ object BuildTwitch : AbstractCommand("BuildTwitch") { val ml = convertAStoManifest(wr) {args.getBoolean("all") || "required" in it.options} val archiveName = "${wr.json.id}-${wr.defaultVersion.versionName}-twitch" val dir = File("./build") - val toDownload = mutableMapOf>() + val toDownload = mutableMapOf() val srcDir by lazy {File(CONFIG.config.pathOrException("Locations/src"))} val overrides by lazy {File(tmp, "overrides")} dir.mkdirs() @@ -67,21 +66,23 @@ object BuildTwitch : AbstractCommand("BuildTwitch") { installFile(uf.value, file, overrides).printf() } } else if(uf.key.isURL) { - val filePath = URL(uf.key.link) - toDownload[filePath] = Pair(File(downloadDir, FilenameUtils.getName(filePath.toString())), uf.value) + toDownload[FileToDownload(downloadDir, uf.key.url, true)] = uf.value } else { return fail("{$uf.key.link} is neither a file nor an URL") } } downloadFiles( - toDownload.mapValues {it.value.first}, - { - fPrintln("downloaded file ${it.file}", TERMC.brightBlue) - installFile(toDownload[it.url]!!.second, it.file, overrides).printf() - }, - false - ) + toDownload.keys.toList() + ) { + if(it.downloadedFile != null) { + fPrintln("downloaded file ${it.file.url}", TERMC.brightBlue) + installFile(toDownload[it.file]!!, it.downloadedFile, overrides).printf() + } else if(it.exception != null) { + fPrintln("ERROR DOWNLOADING ${it.file}") + it.exception.printStackTrace() + } + } fPrintln("Creating zip", TERMC.brightGreen) val zip = ZipOutputStream(FileOutputStream("${dir.path}/$archiveName.zip")) diff --git a/src/main/kotlin/ley/anvil/modpacktools/commands/DownloadMods.kt b/src/main/kotlin/ley/anvil/modpacktools/commands/DownloadMods.kt index e66cc07..2bd7703 100644 --- a/src/main/kotlin/ley/anvil/modpacktools/commands/DownloadMods.kt +++ b/src/main/kotlin/ley/anvil/modpacktools/commands/DownloadMods.kt @@ -6,7 +6,7 @@ import ley.anvil.modpacktools.command.AbstractCommand import ley.anvil.modpacktools.command.CommandReturn import ley.anvil.modpacktools.command.CommandReturn.Companion.success import ley.anvil.modpacktools.command.LoadCommand -import ley.anvil.modpacktools.util.DownloadFileTask +import ley.anvil.modpacktools.util.FileToDownload import ley.anvil.modpacktools.util.arg import ley.anvil.modpacktools.util.downloadFiles import ley.anvil.modpacktools.util.fPrintln @@ -15,8 +15,6 @@ import net.sourceforge.argparse4j.impl.type.FileArgumentType import net.sourceforge.argparse4j.inf.ArgumentParser import net.sourceforge.argparse4j.inf.Namespace import java.io.File -import java.net.URL -import java.util.stream.Collectors.toMap @LoadCommand object DownloadMods : AbstractCommand("DownloadMods") { @@ -42,46 +40,36 @@ object DownloadMods : AbstractCommand("DownloadMods") { override fun execute(args: Namespace): CommandReturn { val json = MPJH.asWrapper val fileList = mutableListOf() - for( - rel in json!!.defaultVersion!!.getRelations { - "client" in it.options && (args.getBoolean("all") || it.type == "mod") - } - ) + for(rel in json!!.defaultVersion!!.getRelations {"client" in it.options && (args.getBoolean("all") || it.type == "mod")}) if(rel.hasFile()) fileList.add(rel.file.get()) downloadFiles( - fileList.stream() + fileList .filter {it.isURL} .filter { val (installer, dir) = it.installer.split(':') installer == "internal.dir" && (args.getBoolean("all") || dir == "mods") } - .collect( - toMap( - {URL(it.link)}, - { - val dir = it.installer.split(':').last() - - if(args.getBoolean("all")) - File(args.get("dir"), dir) - else - args.get("dir") - }, - {_: File, f: File -> f} + .map { + FileToDownload( + if(args.getBoolean("all")) + File(args.get("dir"), it.installer.split(':')[1]) + else + args.get("dir"), + it.url, + true, + !args.getBoolean("force") ) - ), - {r: DownloadFileTask.Return -> - println("${r.responseCode} ${r.responseMessage} ${r.url} ${r.file}") - if(r.exception != null) { - fPrintln("ERROR DOWNLOADING ${r.url}") - r.exception.printStackTrace() } - }, - !args.getBoolean("force"), - true - ) + ) { + println("${it.responseCode} ${it.responseMessage} ${it.file.url} ${it.downloadedFile}") + if(it.exception != null) { + fPrintln("ERROR DOWNLOADING ${it.file.url}") + it.exception.printStackTrace() + } + } return success() } } diff --git a/src/main/kotlin/ley/anvil/modpacktools/util/FileDownloader.kt b/src/main/kotlin/ley/anvil/modpacktools/util/FileDownloader.kt index c509df5..e9c4883 100644 --- a/src/main/kotlin/ley/anvil/modpacktools/util/FileDownloader.kt +++ b/src/main/kotlin/ley/anvil/modpacktools/util/FileDownloader.kt @@ -11,57 +11,58 @@ import java.io.IOException import java.net.URL import java.nio.file.Paths import java.util.concurrent.CountDownLatch -import java.util.stream.Collectors - -private var latch: CountDownLatch? = null /** * Downloads all supplied urls to the given files * - * @param files the files to download and the file to save them to + * @param files the files to download * @param callback the callback which will be called once a download finishes - * @param skipExistingFiles if true, files that already exist will not be downloaded - * @param resolveFileName if true, the file name will be resolved using the URL (target file will now serve as directory) */ -@JvmOverloads fun downloadFiles( - files: Map, - callback: (DownloadFileTask.Return) -> Unit, - skipExistingFiles: Boolean = false, - resolveFileName: Boolean = false + files: List, + callback: (DownloadFileTask.Return) -> Unit ) { - val tasks = files.entries.stream() - //remove if it should be skipped - .filter {!skipExistingFiles || !it.value.exists()} - .collect(Collectors.toList()) - latch = CountDownLatch(tasks.size) - tasks.forEach { - val req = DownloadFileTask(it.key, it.value, callback, latch!!, resolveFileName) + val latch = CountDownLatch(files.size) + files.forEach { + val req = DownloadFileTask(callback, latch, it) HTTP_CLIENT.newCall(req.request).enqueue(req) } - latch!!.await() + latch.await() } +/** + * A file that should be downloaded + * + * @param fileOrDir the file to save to + * @param url the url to download from + * @param shouldResolveFileName if true, the fileOrDir will be treated as directory and the file name will be resolved from the URL + */ +data class FileToDownload( + val fileOrDir: File, + val url: URL, + val shouldResolveFileName: Boolean = false, + val shouldSkipIfExists: Boolean = false +) + open class DownloadFileTask( - protected open val url: URL, - protected open val file: File, protected open val callback: (Return) -> Unit, protected open val latch: CountDownLatch, - protected open val resolveFileName: Boolean + protected open val file: FileToDownload ) : Callback { open val request = Request.Builder() .get() - .url(url) + .url(file.url) .build() override fun onFailure(call: Call, e: IOException) { callback( Return( - url, file, null, null, - e + null, + e, + true ) ) latch.countDown() @@ -69,31 +70,28 @@ open class DownloadFileTask( override fun onResponse(call: Call, response: Response) { callback( - try { + run { + var wasSkipped = true val outFile = - if(resolveFileName) - file mergeTo Paths.get(response.request.url.toUri().path).fileName.toFile() + if(file.shouldResolveFileName) + file.fileOrDir mergeTo Paths.get(response.request.url.toUri().path).fileName.toFile() else - file + file.fileOrDir - val stream = response.body?.byteStream() - FileUtils.copyInputStreamToFile(stream, outFile) - stream!!.close() + if(!file.shouldSkipIfExists || !outFile.exists()) { + response.body?.byteStream().use { + FileUtils.copyInputStreamToFile(it, outFile) + } + wasSkipped = false + } Return( - url, + file, outFile, response.code, response.message, - null - ) - } catch(e: NullPointerException) { - Return( - url, - file, - response.code, - response.message, - e + null, + wasSkipped ) } ) @@ -101,10 +99,11 @@ open class DownloadFileTask( } data class Return( - val url: URL, - val file: File, + val file: FileToDownload, + val downloadedFile: File?, val responseCode: Int?, val responseMessage: String?, - val exception: Exception? + val exception: Exception?, + val wasSkipped: Boolean ) }