Add BundledExtensionUpdater class

Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com>
This commit is contained in:
Alex Andreev committed 2022-02-07 13:15:18 +03:00
1 parent 0732346f6a
commit 9da3d06ce2
4 files changed
+137

No files matched your search

@@ -0,0 +1,44 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { BundledExtensionUpdater } from "../bundled-extension-updater";
import fs from "fs";
import mockFs from "mock-fs";
import nock from "nock";
const mockOpts = {
"some-user-data-directory": {
"some-file.tgz": "file content here",
},
"extension-updates": {
"file.txt": "text",
},
};
describe("BundledExtensionUpdater", () => {
afterEach(() => {
mockFs.restore();
});
it("Should download file from server", async () => {
mockFs(mockOpts);
const scope = nock("http://my-example-url.com")
.get("/node-menu-0.0.1.tgz")
.replyWithFile(200, `./some-user-data-directory/some-file.tgz`, {
"Content-Type": "application/tar",
});
await new BundledExtensionUpdater({
name: "node-menu",
version: "0.0.1",
downloadUrl: "http://my-example-url.com/node-menu-0.0.1.tgz",
}, "./extension-updates").update();
const exist = await fs.promises.access(mockFs.bypass(() => "./extension-updates/node-menu-0.0.1.tgz"), fs.constants.F_OK);
expect(exist).toBeTruthy();
});
});
@@ -0,0 +1,72 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import fs from "fs";
import { ensureDir } from "fs-extra";
import request from "request";
import logger from "../logger";
import path from "path";
import { noop } from "../../common/utils";
type Extension = {
name: string
version: string
downloadUrl: string
};
export class BundledExtensionUpdater {
private extension: Extension;
private updateFolderPath: string;
constructor(extension: Extension, updateFolderPath: string) {
this.extension = extension;
this.updateFolderPath = updateFolderPath;
}
public async update() {
await this.download();
}
private get filePath() {
return `${this.updateFolderPath}/${this.extension.name}-${this.extension.version}.tgz`;
}
private async download() {
const { downloadUrl, name } = this.extension;
await ensureDir(path.dirname(this.updateFolderPath), 0o755);
const file = fs.createWriteStream(this.filePath);
logger.info(`[EXTENSION-UPDATER]: Downloading extension ${name} from ${downloadUrl} to ${this.filePath}`);
const requestOpts: request.UriOptions & request.CoreOptions = {
uri: downloadUrl,
gzip: true,
};
const stream = request.get(requestOpts);
stream.on("complete", () => {
logger.info(`[EXTENSION-UPDATER]: Download extension ${name} tgz file completed`);
file.end(noop);
});
stream.on("error", (error) => {
logger.error(error);
fs.unlink(this.filePath, noop);
throw error;
});
return new Promise<void>((resolve, reject) => {
file.on("close", () => {
logger.info(`[EXTENSION-UPDATER]: Download extension ${name} tgz file closed`);
fs.chmod(downloadUrl, 0o755, (err) => {
if (err) reject(err);
});
resolve();
});
stream.pipe(file);
});
}
}