🚀 Update getPatch to write files to disk
This commit is contained in:
parent
b6eccc2dab
commit
440611913d
2 changed files with 92 additions and 12 deletions
|
@ -29,10 +29,17 @@ if (!to.match(/^(0|[1-9][0-9]{0,2})$/)) {
|
||||||
//TODO: set target directory where patch should be installed
|
//TODO: set target directory where patch should be installed
|
||||||
//TODO: set temp directory where patch files should be stored.
|
//TODO: set temp directory where patch files should be stored.
|
||||||
//TODO: set location of xdelta3 executable
|
//TODO: set location of xdelta3 executable
|
||||||
//TODO: set from=any so it detects current version automatically
|
//TODO: set from=any so it detects current version automatically (based on .version files)
|
||||||
//TODO: set to=manifest/current to install whatever is the current version in manifest/on CDN
|
//TODO: set to=manifest/current to install whatever is the current version in manifest/on CDN
|
||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
const patch = await getPatch(product as Product, Number(from), Number(to));
|
await getPatch({
|
||||||
//console.log(patch);
|
/* tslint:disable:object-literal-sort-keys */
|
||||||
|
product: product as Product,
|
||||||
|
from: Number(from),
|
||||||
|
to: Number(to),
|
||||||
|
sourceDirectory: process.cwd(),
|
||||||
|
targetDirectory: process.cwd(),
|
||||||
|
/* tslint:enable:object-literal-sort-keys */
|
||||||
|
});
|
||||||
})();
|
})();
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
|
import * as fs from 'fs';
|
||||||
|
import * as path from 'path';
|
||||||
import downloadUrlContents from '../cdn/downloadUrlContents';
|
import downloadUrlContents from '../cdn/downloadUrlContents';
|
||||||
|
import createDirRecursively from '../cdn/funcs/createDirRecursively';
|
||||||
import getUrlContents from '../cdn/getUrlContents';
|
import getUrlContents from '../cdn/getUrlContents';
|
||||||
import { Product } from '../interfaces/ISettings';
|
import { Product } from '../interfaces/ISettings';
|
||||||
import { SsnDiffType } from '../interfaces/ISsnFileEntry';
|
import { SsnDiffType } from '../interfaces/ISsnFileEntry';
|
||||||
|
@ -6,10 +9,46 @@ import extractFileAsStream from './extractFileAsStream';
|
||||||
import getSolidpkg from './getSolidpkg';
|
import getSolidpkg from './getSolidpkg';
|
||||||
import readSsnFile from './reader/readSsnFile';
|
import readSsnFile from './reader/readSsnFile';
|
||||||
import getFileFromDisks from './streams/getFileFromDisks';
|
import getFileFromDisks from './streams/getFileFromDisks';
|
||||||
import streamToArrayBuffer from './streams/streamToArrayBuffer';
|
|
||||||
import verifyPatch from './verify/verifyPatch';
|
import verifyPatch from './verify/verifyPatch';
|
||||||
|
import verifyProductName from './verify/verifyProductName';
|
||||||
|
|
||||||
|
interface IGetPatchArgs {
|
||||||
|
/** The product that should be patched. */
|
||||||
|
product: Product;
|
||||||
|
/** The release that we want to patch from, or -1 if patching fresh. */
|
||||||
|
from: number;
|
||||||
|
/** The release that we want to patch to. */
|
||||||
|
to: number;
|
||||||
|
/** The source directory where the files from the "from" release are stored. Not needed if from=-1. */
|
||||||
|
sourceDirectory: string | undefined;
|
||||||
|
/** The target directory where the files should be extracted to. */
|
||||||
|
targetDirectory: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Downloads and applies the specified patch. */
|
||||||
|
export default async function getPatch({ product, from, to, sourceDirectory, targetDirectory }: IGetPatchArgs) {
|
||||||
|
//Verify function arguments
|
||||||
|
|
||||||
|
if (!verifyProductName(product)) {
|
||||||
|
throw new TypeError(`"${product}" is not a valid product.`);
|
||||||
|
}
|
||||||
|
if (typeof from !== 'number' || (from | 0) !== from || from < -1 || from > 999) {
|
||||||
|
throw new TypeError(`from must be an integer greater than or equal to -1 but it is "${from}"`);
|
||||||
|
}
|
||||||
|
if (typeof to !== 'number' || (to | 0) !== to || to < 0 || to > 999) {
|
||||||
|
throw new TypeError(`to must be an integer greater than or equal to 0 but it is "${to}"`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sourceDirectory === undefined && from !== -1) {
|
||||||
|
throw new Error('Must specify a sourceDirectory if patching from a release other than -1.');
|
||||||
|
}
|
||||||
|
const sourceDir = (from === -1) ? '' : path.resolve(sourceDirectory as string);
|
||||||
|
const targetDir = path.resolve(targetDirectory);
|
||||||
|
await createDirRecursively(targetDir);
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------------------
|
||||||
|
//Download and verify files
|
||||||
|
|
||||||
export default async function getPatch(product: Product, from: number, to: number) {
|
|
||||||
const solidpkg = await getSolidpkg(product, from, to);
|
const solidpkg = await getSolidpkg(product, from, to);
|
||||||
|
|
||||||
function createUrlObject({ name, length }: {name: string, length: number}) {
|
function createUrlObject({ name, length }: {name: string, length: number}) {
|
||||||
|
@ -33,13 +72,21 @@ export default async function getPatch(product: Product, from: number, to: numbe
|
||||||
|
|
||||||
//TODO: Verify that downloaded files match the hash in `solidpkg.pieces`
|
//TODO: Verify that downloaded files match the hash in `solidpkg.pieces`
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------------------
|
||||||
|
//Perform the patching
|
||||||
|
|
||||||
//Extract newly added files
|
//Extract newly added files
|
||||||
fileEntries.filter((file) => file.diffType === SsnDiffType.NewFile).forEach(async (file) => {
|
fileEntries.filter((file) => file.diffType === SsnDiffType.NewFile).forEach(async (file) => {
|
||||||
try {
|
try {
|
||||||
|
//extract file
|
||||||
const fileStream = await getFileFromDisks(diskFilenames, { diskStart: file.diskNumberStart, offset: file.offset, length: file.compressedSize });
|
const fileStream = await getFileFromDisks(diskFilenames, { diskStart: file.diskNumberStart, offset: file.offset, length: file.compressedSize });
|
||||||
const fileContents = await extractFileAsStream(file, fileStream);
|
const fileContents = await extractFileAsStream(file, fileStream);
|
||||||
console.debug(file.name, file.compressedSize, await streamToArrayBuffer(fileContents));
|
|
||||||
//TODO: need to write to disk
|
//write to disk
|
||||||
|
const outputName = path.join(targetDir, file.name);
|
||||||
|
await createDirRecursively(path.dirname(outputName));
|
||||||
|
const outputStream = fs.createWriteStream(outputName);
|
||||||
|
fileContents.pipe(outputStream);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(`Could not extract file "${file.name}"`, error);
|
console.error(`Could not extract file "${file.name}"`, error);
|
||||||
}
|
}
|
||||||
|
@ -48,17 +95,43 @@ export default async function getPatch(product: Product, from: number, to: numbe
|
||||||
//Extract changed files
|
//Extract changed files
|
||||||
fileEntries.filter((file) => file.diffType === SsnDiffType.Changed).forEach(async (file) => {
|
fileEntries.filter((file) => file.diffType === SsnDiffType.Changed).forEach(async (file) => {
|
||||||
try {
|
try {
|
||||||
|
//extract file
|
||||||
const fileStream = await getFileFromDisks(diskFilenames, { diskStart: file.diskNumberStart, offset: file.offset, length: file.compressedSize });
|
const fileStream = await getFileFromDisks(diskFilenames, { diskStart: file.diskNumberStart, offset: file.offset, length: file.compressedSize });
|
||||||
const fileContents = await extractFileAsStream(file, fileStream);
|
const fileContents = await extractFileAsStream(file, fileStream);
|
||||||
console.debug(file.name, file.compressedSize, await streamToArrayBuffer(fileContents));
|
|
||||||
//TODO: need to apply diffing, then write to disk
|
//TODO: need to apply xdelta3 diffing, then write to disk
|
||||||
|
//if source === target, need to create .temp file, and when it's done, delete source file and rename .temp to actual name
|
||||||
|
console.warn(`Could not extract "${file.name}"; xdelta3 diffing is not yet implemented.`);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(`Could not extract file "${file.name}"`, error);
|
console.error(`Could not extract file "${file.name}"`, error);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
//Need to delete deleted files
|
//Need to delete deleted files
|
||||||
fileEntries.filter((file) => file.diffType === SsnDiffType.Deleted).forEach((file) => {
|
if (sourceDirectory === targetDirectory) {
|
||||||
//TODO: need to delete file
|
fileEntries.filter((file) => file.diffType === SsnDiffType.Deleted).forEach((file) => {
|
||||||
});
|
//delete file
|
||||||
|
const fileName = path.join(targetDir, file.name);
|
||||||
|
fs.unlink(fileName, (error) => {
|
||||||
|
if (error) {
|
||||||
|
console.error(`Could not delete removed file "${file.name}"`, error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
//Need to copy unchanged files (if we are patching into a different directory)
|
||||||
|
if (sourceDirectory !== targetDirectory) {
|
||||||
|
fileEntries.filter((file) => file.diffType === SsnDiffType.Unchanged).forEach(async (file) => {
|
||||||
|
//copy file
|
||||||
|
const sourceName = path.join(sourceDir, file.name);
|
||||||
|
const targetName = path.join(targetDir, file.name);
|
||||||
|
await createDirRecursively(path.dirname(targetName));
|
||||||
|
fs.copyFile(sourceName, targetName, (error) => {
|
||||||
|
if (error) {
|
||||||
|
console.error(`Could not copy unchanged file "${file.name}"`, error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue