Open books from Github (#10670)

* Add open book option in UI

* Add dropdowns option on dialog

* Add flow logic

* Fetch releases and validate URL

* Add class for github books and shared file books

* Change code structure

* Unblock local copy + stack overflows

* Download books from github

* Remove unused files

* Clean code and use the openNotebookFolder command to open remote book

* Checkpoint

* Refactor remote book dialog model to only hold data

* Remove ApiWrapper and refactor createlocalcopy method

* Use sinon js framework instead of typemoq for testing remotebookController

* Remove api wrapper

* Add some tests

* Add more tests and address pr comments

* Address PR comments

* Fix remotebook broken tests

* Add download location in output channel and use openBook command

* Address PR comments

* Fix typos, print error message and remove failing test

* Print error message

* Separate tests in different files

* Declare controller variable inside extension.tst

Co-authored-by: chlafreniere <hichise@gmail.com>
This commit is contained in:
Barbara Valdez
2020-07-24 19:39:03 -07:00
committed by GitHub
parent 56d1a1c1af
commit 6d9efbd603
17 changed files with 866 additions and 8 deletions

View File

@@ -0,0 +1,96 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as request from 'request';
import * as fs from 'fs-extra';
import * as loc from '../common/localizedConstants';
import * as vscode from 'vscode';
import * as path from 'path';
import * as zip from 'adm-zip';
import * as tar from 'tar';
import * as utils from '../common/utils';
import { RemoteBook } from './remoteBook';
import { IAsset } from './remoteBookController';
import * as constants from '../common/constants';
export class GitHubRemoteBook extends RemoteBook {
constructor(public remotePath: URL, public outputChannel: vscode.OutputChannel, protected _asset: IAsset) {
super(remotePath, outputChannel, _asset);
}
public async createLocalCopy(): Promise<void> {
this.outputChannel.show(true);
this.setLocalPath();
this.outputChannel.appendLine(loc.msgDownloadLocation(this._localPath.href));
this.outputChannel.appendLine(loc.msgRemoteBookDownloadProgress);
this.createDirectory();
let notebookConfig = vscode.workspace.getConfiguration(constants.notebookConfigKey);
let downloadTimeout = notebookConfig[constants.remoteBookDownloadTimeout];
return new Promise((resolve, reject) => {
let options = {
headers: {
'User-Agent': 'request',
'timeout': downloadTimeout
}
};
let downloadRequest = request.get(this._asset.browserDownloadUrl.href, options)
.on('error', (error) => {
this.outputChannel.appendLine(loc.msgRemoteBookDownloadError);
this.outputChannel.appendLine(error.message);
reject(error);
})
.on('response', (response) => {
if (response.statusCode !== 200) {
this.outputChannel.appendLine(loc.msgRemoteBookDownloadError);
return reject(new Error(loc.httpRequestError(response.statusCode, response.statusMessage)));
}
});
let remoteBookFullPath = new URL(this._localPath.href.concat('.zip'));
downloadRequest.pipe(fs.createWriteStream(remoteBookFullPath.href))
.on('close', async () => {
resolve(this.extractFiles(remoteBookFullPath));
})
.on('error', (error) => {
this.outputChannel.appendLine(loc.msgRemoteBookDownloadError);
this.outputChannel.appendLine(error.message);
reject(error);
downloadRequest.abort();
});
});
}
public async createDirectory(): Promise<void> {
let fileName = this._asset.book.concat('-').concat(this._asset.version).concat('-').concat(this._asset.language);
this._localPath = new URL(path.join(this._localPath.href, fileName));
try {
let exists = await fs.pathExists(this._localPath.href);
if (exists) {
await fs.remove(this._localPath.href);
}
await fs.promises.mkdir(this._localPath.href);
} catch (error) {
this.outputChannel.appendLine(loc.msgRemoteBookDirectoryError);
this.outputChannel.appendLine(error.message);
}
}
public async extractFiles(remoteBookFullPath: URL): Promise<void> {
try {
if (utils.getOSPlatform() === utils.Platform.Windows || utils.getOSPlatform() === utils.Platform.Mac) {
let zippedFile = new zip(remoteBookFullPath.href);
zippedFile.extractAllTo(this._localPath.href);
} else {
tar.extract({ file: remoteBookFullPath.href, cwd: this._localPath.href }).catch(error => {
this.outputChannel.appendLine(loc.msgRemoteBookUnpackingError);
this.outputChannel.appendLine(error.message);
});
}
await fs.promises.unlink(remoteBookFullPath.href);
this.outputChannel.appendLine(loc.msgRemoteBookDownloadComplete);
vscode.commands.executeCommand('notebook.command.openNotebookFolder', this._localPath.href, undefined, true);
}
catch (err) {
this.outputChannel.appendLine(err.message);
}
}
}