Skip to content

Commit

Permalink
refactor(debian): extract content-addressable storage logic to separa…
Browse files Browse the repository at this point in the history
…te module
  • Loading branch information
Nipheris committed Apr 3, 2024
1 parent 272d980 commit f356d3e
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 46 deletions.
45 changes: 45 additions & 0 deletions src/deb/cas.mts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import * as path from 'node:path';
import { PassThrough, Readable } from 'node:stream';
import { buffer } from 'node:stream/consumers';
import { createGzip } from 'node:zlib';
import { createHash } from 'node:crypto';
import { createWriteStream } from 'node:fs';
import { pipeline } from 'node:stream/promises';

import { createDir } from '../fs.mjs';

export interface ContentAddress {
sha256: Uint8Array;
}

export interface ContentDescription {
size: number;
address: ContentAddress;
}

export async function storeGzippedStream(root: string, stream: NodeJS.ReadableStream): Promise<ContentDescription> {
const gzip = createGzip({ level: 9 });
const gzippedStream = new PassThrough();
await pipeline(stream, gzip, gzippedStream);
return storeStream(root, gzippedStream);
}

// https://wiki.debian.org/DebianRepository/Format#indices_acquisition_via_hashsums_.28by-hash.29
export async function storeStream(root: string, stream: NodeJS.ReadableStream): Promise<ContentDescription> {
const contentBuffer = await buffer(stream);

// compute a digest
const sha256Hash = createHash('sha256');
await pipeline(Readable.from(contentBuffer), sha256Hash);
const sha256 = sha256Hash.read();

// store in a file
const sha256Dir = path.join(root, 'SHA256');
const fileName = path.join(sha256Dir, Buffer.from(sha256).toString('hex'));
createDir(sha256Dir);
await pipeline(Readable.from(contentBuffer), createWriteStream(fileName));
return {
size: contentBuffer.length,
address: { sha256 },
};
}
57 changes: 11 additions & 46 deletions src/deb/deb-builder.mts
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
import * as path from 'node:path';
import { appendFile, writeFile } from 'node:fs/promises';
import { createHash, randomBytes } from 'node:crypto';
import { createWriteStream, readdirSync, readFileSync, renameSync, unlinkSync } from 'node:fs';
import { PassThrough, Readable } from 'node:stream';
import { buffer } from 'node:stream/consumers';
import { createGzip } from 'node:zlib';
import { pipeline } from 'node:stream/promises';
import { readdirSync, readFileSync, renameSync, unlinkSync } from 'node:fs';
import { randomBytes } from 'node:crypto';
import { Readable } from 'node:stream';

import * as ini from 'ini';
import * as tar from 'tar';

import * as cas from './cas.mjs';
import type { Artifact, ArtifactProvider } from '../artifact-provider.mjs';
import { createDir, execToolToFile, removeDir } from '../fs.mjs';
import type { Deployer } from '../deployer.mjs';
Expand Down Expand Up @@ -231,13 +229,16 @@ export class DebBuilder implements Deployer {
unlinkSync(metaFile);
}

const storePackageIndex = async(shortName: string, store: (root: string, stream: NodeJS.ReadableStream) => Promise<ContentDescription>) => {
const storePackageIndex = async(
shortName: string,
store: (root: string, stream: NodeJS.ReadableStream) => Promise<cas.ContentDescription>,
) => {
const name = `${component}/${binarySubdir}/${shortName}`;
const { size, address } = await store(path.resolve(binaryPath, 'by-hash'), Readable.from(packagesContent));
binaryPackageIndices.push({ name, size, address });
};
await storePackageIndex('Packages', storeStreamInCas);
await storePackageIndex('Packages.gz', storeGzippedStreamInCas);
await storePackageIndex('Packages', cas.storeStream);
await storePackageIndex('Packages.gz', cas.storeGzippedStream);
}),
));
});
Expand All @@ -256,44 +257,8 @@ export class DebBuilder implements Deployer {
}
}

interface ContentAddress {
sha256: Uint8Array;
}

interface ContentDescription {
size: number;
address: ContentAddress;
}

async function storeGzippedStreamInCas(root: string, stream: NodeJS.ReadableStream): Promise<ContentDescription> {
const gzip = createGzip({ level: 9 });
const gzippedStream = new PassThrough();
await pipeline(stream, gzip, gzippedStream);
return storeStreamInCas(root, gzippedStream);
}

// https://wiki.debian.org/DebianRepository/Format#indices_acquisition_via_hashsums_.28by-hash.29
async function storeStreamInCas(root: string, stream: NodeJS.ReadableStream): Promise<ContentDescription> {
const contentBuffer = await buffer(stream);

// compute a digest
const sha256Hash = createHash('sha256');
await pipeline(Readable.from(contentBuffer), sha256Hash);
const sha256 = sha256Hash.read();

// store in a file
const sha256Dir = path.join(root, 'SHA256');
const fileName = path.join(sha256Dir, Buffer.from(sha256).toString('hex'));
createDir(sha256Dir);
await pipeline(Readable.from(contentBuffer), createWriteStream(fileName));
return {
size: contentBuffer.length,
address: { sha256 },
};
}

interface BinaryPackageIndexDescription {
name: string;
size: number;
address: ContentAddress;
address: cas.ContentAddress;
}

0 comments on commit f356d3e

Please sign in to comment.