suspend fun downloadFileToCacheLocation()

in sources/core/src/org/jetbrains/amper/core/downloader/downloader.kt [68:141]


    suspend fun downloadFileToCacheLocation(
        url: String,
        userCacheRoot: AmperUserCacheRoot,
        infoLog: Boolean = true,
    ): Path {
        val target = getTargetFile(userCacheRoot, url)
        fileLocks.withLock(target) {
            if (target.exists()) {
                Span.current().addEvent(
                    "use asset from cache", Attributes.of(
                        AttributeKey.stringKey("url"), url,
                        AttributeKey.stringKey("target"), target.pathString,
                    )
                )

                // update file modification time to maintain FIFO caches, i.e., in persistent cache folder on TeamCity agent
                try {
                    target.setLastModifiedTime(FileTime.from(Instant.now()))
                } catch (t: Throwable) {
                    logger.warn("Unable to update mtime: $target", t)
                }

                return target
            }

            if (infoLog) {
                logger.info("Downloading $url to ${target.pathString}")
            }

            return spanBuilder("download").setAttribute("url", url).setAttribute("target", target.pathString).use {
                // TODO check if this is redundant with Ktor's retry mechanism.
                //  It might be necessary due to expectSuccess=false.
                suspendingRetryWithExponentialBackOff {
                    // save to the same disk to ensure that move will be atomic and not as a copy
                    val tempFile = target.parent
                        .resolve("${target.fileName}-${(Instant.now().epochSecond - 1634886185).toString(36)}-${Instant.now().nano.toString(36)}".take(255))
                    tempFile.deleteIfExists()
                    // Add a hook, so interruption won't leave garbage files.
                    tempFile.toFile().deleteOnExit()
                    target.parent.createDirectories()
                    try {
                        val response = archivesDownloadClient.prepareGet(url) {
                            // we manually handle errors below
                            expectSuccess = false
                        }.execute {
                            coroutineScope {
                                it.bodyAsChannel().copyAndClose(writeChannel(tempFile))
                            }
                            it
                        }

                        val statusCode = response.status.value
                        if (statusCode != 200) {
                            failWithResponseData(response, tempFile, statusCode, url)
                        }

                        checkContentLength(response, url, tempFile)
                        tempFile.moveTo(target, StandardCopyOption.ATOMIC_MOVE, StandardCopyOption.REPLACE_EXISTING)
                    } catch (httpException: HttpStatusException) {
                        if (httpException.statusCode == 404) {
                            // do not retry 404
                            throw NoMoreRetriesException(httpException.toString(), httpException)
                        } else {
                            throw httpException
                        }
                    } finally {
                        tempFile.deleteIfExists()
                    }
                }

                target
            }
        }
    }