(deployId: string, buildFilePaths: string[])
| 581 | } |
| 582 | |
| 583 | private async uploadFiles(deployId: string, buildFilePaths: string[]) { |
| 584 | const progressSpinner = this.effects.clack.spinner(); |
| 585 | progressSpinner.start(""); |
| 586 | |
| 587 | // upload a manifest before uploading the files |
| 588 | progressSpinner.message("Hashing local files"); |
| 589 | const manifestFileInfo: DeployManifestFile[] = []; |
| 590 | await runAllWithConcurrencyLimit(buildFilePaths, async (path) => { |
| 591 | const fullPath = join(this.deployOptions.config.output, path); |
| 592 | const statInfo = await stat(fullPath); |
| 593 | const hash = createHash("sha512") |
| 594 | .update(await readFile(fullPath)) |
| 595 | .digest("base64"); |
| 596 | manifestFileInfo.push({path, size: statInfo.size, hash}); |
| 597 | }); |
| 598 | progressSpinner.message("Sending file manifest to server"); |
| 599 | const instructions = await this.apiClient.postDeployManifest(deployId, manifestFileInfo); |
| 600 | const fileErrors: {path: string; detail: string | null}[] = []; |
| 601 | for (const fileInstruction of instructions.files) { |
| 602 | if (fileInstruction.status === "error") { |
| 603 | fileErrors.push({path: fileInstruction.path, detail: fileInstruction.detail}); |
| 604 | } |
| 605 | } |
| 606 | if (fileErrors.length) { |
| 607 | this.effects.clack.log.error( |
| 608 | "The server rejected some files from the upload:\n\n" + |
| 609 | fileErrors.map(({path, detail}) => ` - ${path} - ${detail ? `(${detail})` : "no details"}`).join("\n") |
| 610 | ); |
| 611 | } |
| 612 | if (instructions.status === "error" || fileErrors.length) { |
| 613 | throw new CliError(`Server rejected deploy manifest${instructions.detail ? `: ${instructions.detail}` : ""}`); |
| 614 | } |
| 615 | const filesToUpload: string[] = instructions.files |
| 616 | .filter((instruction) => instruction.status === "upload") |
| 617 | .map((instruction) => instruction.path); |
| 618 | |
| 619 | // Upload the files |
| 620 | const rateLimiter = new RateLimiter(5); |
| 621 | const waitForRateLimit = filesToUpload.length <= 300 ? async () => {} : () => rateLimiter.wait(); |
| 622 | |
| 623 | await runAllWithConcurrencyLimit( |
| 624 | filesToUpload, |
| 625 | async (path, i) => { |
| 626 | await waitForRateLimit(); |
| 627 | progressSpinner.message( |
| 628 | `${i + 1} / ${filesToUpload.length} ${faint("uploading")} ${path.slice(0, this.effects.outputColumns - 17)}` |
| 629 | ); |
| 630 | await this.apiClient.postDeployFile(deployId, join(this.deployOptions.config.output, path), path); |
| 631 | }, |
| 632 | {maxConcurrency: this.deployOptions.maxConcurrency} |
| 633 | ); |
| 634 | progressSpinner.stop( |
| 635 | `${filesToUpload.length} uploaded, ${buildFilePaths.length - filesToUpload.length} unchanged, ${ |
| 636 | buildFilePaths.length |
| 637 | } total.` |
| 638 | ); |
| 639 | } |
| 640 |
no test coverage detected