Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 4 additions & 5 deletions src/porcelain/install.test.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import { useTestConfig } from "../hooks/useTestConfig.ts"
import { assert, assertArrayIncludes } from "deno/testing/asserts.ts"
import { ConsoleLogger } from "../plumbing/install.ts"
import type { Package } from "../types.ts";
import type { Resolution } from "../plumbing/resolve.ts";
import { useTestConfig } from "../hooks/useTestConfig.ts"
import type { Resolution } from "../plumbing/resolve.ts"
import install, { ConsoleLogger } from "./install.ts"
import * as semver from "../utils/semver.ts"
import install from "./install.ts"
import type { Package } from "../types.ts"

Deno.test("porcelain.install.1", async () => {
useTestConfig()
Expand Down
76 changes: 68 additions & 8 deletions src/porcelain/install.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import install, { Logger as InstallLogger } from "../plumbing/install.ts"
import install, { Logger as BaseLogger, ConsoleLogger as BaseConsoleLogger } from "../plumbing/install.ts"
import { Installation, PackageSpecification } from "../types.ts"
import resolve, { Resolution } from "../plumbing/resolve.ts"
import usePantry from "../hooks/usePantry.ts"
Expand All @@ -9,8 +9,21 @@ import link from "../plumbing/link.ts"
import { is_what } from "../deps.ts"
const { isString } = is_what

export interface Logger extends InstallLogger {
export interface Logger extends BaseLogger {
resolved?(resolution: Resolution): void
/// from 0.0–1.0
/// currently you won’t get this immediately since we are waiting for all our
/// network requests to return before we know the final download size
progress?(completion: number): void
}

// deno-lint-ignore no-explicit-any
export function ConsoleLogger(prefix?: any): Logger {
prefix = prefix ? `${prefix}: ` : ""
return {
...BaseConsoleLogger(prefix),
progress: function() { console.error(`${prefix}progress`, ...arguments) },
}
}

/// eg. install("python.org~3.10")
Expand All @@ -31,12 +44,59 @@ export default async function(pkgs: PackageSpecification[] | string[] | string,
const resolution = await resolve(pkgs)
logger?.resolved?.(resolution)

const { pending, installed} = resolution
for (const pkg of pending) {
const installation = await install(pkg, logger)
await link(installation)
installed.push(installation)
}
const { pending, installed } = resolution
logger = WrapperLogger(pending, logger)
const installers = pending
.map(pkg => install(pkg, logger)
.then(i => link(i).then(() => i)))

installed.push(...await Promise.all(installers))

return installed
}

function WrapperLogger(pending: PackageSpecification[], logger?: Logger): Logger | undefined {
if (!logger?.progress) return logger

const projects = pending.map(pkg => pkg.project)
const totals: Record<string, number> = {}
const progresses: Record<string, number> = {}
return {
...logger,
downloading: args => {
const { pkg: {project}, total } = args
if (total) {
totals[project] = total
updateProgress()
}
if (logger?.downloading) {
logger.downloading(args)
}
},
installing: args => {
const { pkg: {project}, progress } = args
if (progress) {
progresses[project] = progress
updateProgress()
}
if (logger?.installing) {
logger.installing(args)
}
}
}

function updateProgress() {
let total_untard_bytes = 0
let grand_total = 0
for (const project of projects) {
const total = totals[project]
const bytes = progresses[project] * total
total_untard_bytes += bytes
grand_total += total
}
const rv = total_untard_bytes / grand_total
if (!isNaN(rv)) {
logger!.progress!(total_untard_bytes / grand_total)
}
}
}