Commit 0759508b authored by 神楽坂玲奈's avatar 神楽坂玲奈

Merge branch 'v3' of github.com:mycard/mycard into v3

parents 4b0bf09a 783edb27
......@@ -83,7 +83,7 @@
<!--安装modal-->
<div class="modal fade" id="install-modal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true" *ngIf="installOption">
<div class="modal-dialog" role="document">
<form id="install-form" class="modal-content" (ngSubmit)="install(currentApp)" #theForm="ngForm">
<form id="install-form" class="modal-content" (ngSubmit)="install(currentApp,installOption,referencesInstall)" #theForm="ngForm">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span>&times;</span>
......
......@@ -95,8 +95,9 @@ export class AppDetailComponent implements OnInit {
}
async installMod(mod: App) {
this.updateInstallOption(mod);
await this.install(mod);
let option = new InstallOption(mod, path.dirname(mod.parent.local!.path));
await this.install(mod, option, {});
}
......@@ -107,19 +108,16 @@ export class AppDetailComponent implements OnInit {
}
}
async install(targetApp: App) {
async install(targetApp: App, options: InstallOption, referencesInstall: {[id: string]: boolean}) {
$('#install-modal').modal('hide');
let options = this.installOption;
try {
await this.appsService.install(targetApp, options);
if (this.references.length > 0) {
for (let [id,isInstalled] of Object.entries(this.referencesInstall)) {
if (isInstalled) {
let reference = targetApp.references.get(id)!;
await this.appsService.install(reference, options);
}
for (let [id,install] of Object.entries(referencesInstall)) {
if (install) {
let reference = targetApp.references.get(id)!;
console.log("reference install ", id, targetApp, targetApp.references, reference);
await this.appsService.install(reference, options);
}
}
} catch (e) {
......
......@@ -3,7 +3,6 @@ import {App} from "./app";
* Created by zh99998 on 16/9/6.
*/
export class AppLocal {
library: string;
path: string;
version: string;
files: Map<string,string>;
......
......@@ -100,8 +100,9 @@ export class App {
isDownloading(): boolean {
return this.status.status === "downloading";
}
isUninstalling():boolean{
return this.status.status==="uninstalling";
isUninstalling(): boolean {
return this.status.status === "uninstalling";
}
runable(): boolean {
......@@ -146,4 +147,9 @@ export class App {
return [];
}
readyForInstall(): boolean {
let dependencies = this.findDependencies();
return dependencies.every((dependency) => dependency.isReady());
}
}
\ No newline at end of file
......@@ -216,26 +216,35 @@ export class AppsService {
});
};
if (!app.isInstalled()) {
let apps: App[] = [];
let dependencies = app.findDependencies().filter((dependency) => {
return !dependency.isInstalled();
});
apps.push(...dependencies, app);
try {
let apps: App[] = [];
let dependencies = app.findDependencies().filter((dependency) => {
return !dependency.isInstalled();
});
apps.push(...dependencies, app);
let downloadPath = path.join(option.installLibrary, 'downloading');
let tasks: Promise<any>[] = [];
for (let a of apps) {
tasks.push(addDownloadTask(a, downloadPath));
}
let downloadResults = await Promise.all(tasks);
let installTasks: Promise<void>[] = [];
for (let result of downloadResults) {
console.log(result);
let o = new InstallOption(result.app, option.installLibrary);
o.downloadFiles = result.files;
this.installService.push({app: result.app, option: o});
let task = this.installService.push({app: result.app, option: o});
installTasks.push(task);
}
await Promise.all(installTasks);
} catch (e) {
app.status.status = 'init';
for (let a of apps) {
if (!a.isReady()) {
a.status.status = 'init';
}
}
console.log(e);
throw e;
}
......
/**
* Created by weijian on 2016/11/2.
*/
import {Injectable, ApplicationRef} from "@angular/core";
import {Injectable, ApplicationRef, EventEmitter} from "@angular/core";
import {App, Category} from "./app";
import {InstallOption} from "./install-option";
import * as path from "path";
......@@ -9,7 +9,6 @@ import * as child_process from "child_process";
import * as mkdirp from "mkdirp";
import * as readline from "readline";
import * as fs from "fs";
import {EventEmitter} from "events";
import {AppLocal} from "./app-local";
import {Http} from "@angular/http";
import {ComparableSet} from "./shared/ComparableSet"
......@@ -31,7 +30,7 @@ export interface InstallStatus {
export class InstallService {
tarPath: string;
installingId: string = '';
eventEmitter: EventEmitter = new EventEmitter();
eventEmitter = new EventEmitter<void>();
readonly checksumURL = "https://thief.mycard.moe/checksums/";
readonly updateServerURL = 'https://thief.mycard.moe/update/metalinks';
......@@ -70,86 +69,87 @@ export class InstallService {
// }
// }
push(task: InstallTask): string {
let id = this.createId();
this.installQueue.set(id, task);
if (this.installQueue.size > 0 && this.installingId == '') {
this.doInstall();
async push(task: InstallTask): Promise<void> {
if (!task.app.readyForInstall()) {
await new Promise((resolve, reject) => {
this.eventEmitter.subscribe(() => {
if (task.app.readyForInstall()) {
resolve();
} else if (task.app.findDependencies().find((dependency: App) => !dependency.isInstalled())) {
reject("Dependencies failed");
}
});
});
}
return id;
await this.doInstall(task);
}
async doInstall() {
if (this.installQueue.size > 0 && this.installingId == '') {
let [id,task] = this.installQueue.entries().next().value!;
this.installingId = id;
try {
let app = task.app;
let dependencies = app.findDependencies();
let readyForInstall = dependencies.every((dependency) => {
return dependency.isReady();
});
if (readyForInstall) {
let option = task.option;
let installDir = option.installDir;
// if (!app.isInstalled()) {
let checksumFile = await this.getChecksumFile(app);
if (app.parent) {
// mod需要安装到parent路径
installDir = app.parent.local!.path;
let parentFiles = new ComparableSet(Array.from(app.parent.local!.files.keys()));
let appFiles = new ComparableSet(Array.from(checksumFile.keys()));
let conflictFiles = appFiles.intersection(parentFiles);
if (conflictFiles.size > 0) {
let backupPath = path.join(option.installLibrary, "backup", app.parent.id);
await this.backupFiles(app.parent.local!.path, backupPath, conflictFiles);
}
}
let allFiles = new Set(checksumFile.keys());
app.status.status = "installing";
app.status.total = allFiles.size;
app.status.progress = 0;
// let timeNow = new Date().getTime();
for (let file of option.downloadFiles) {
await this.createDirectory(installDir);
let interval = setInterval(() => {
}, 500);
await new Promise((resolve, reject) => {
this.extract(file, installDir).subscribe(
(lastItem: string) => {
app.status.progress += 1;
app.status.progressMessage = lastItem;
},
(error) => {
reject(error);
},
() => {
resolve();
});
});
clearInterval(interval);
async doInstall(task: InstallTask) {
try {
let app = task.app;
let dependencies = app.findDependencies();
let readyForInstall = dependencies.every((dependency) => {
return dependency.isReady();
});
if (readyForInstall) {
let option = task.option;
let installDir = option.installDir;
// if (!app.isInstalled()) {
let checksumFile = await this.getChecksumFile(app);
if (app.parent) {
// mod需要安装到parent路径
installDir = app.parent.local!.path;
let parentFiles = new ComparableSet(Array.from(app.parent.local!.files.keys()));
let appFiles = new ComparableSet(Array.from(checksumFile.keys()));
let conflictFiles = appFiles.intersection(parentFiles);
if (conflictFiles.size > 0) {
let backupPath = path.join(option.installLibrary, "backup", app.parent.id);
await this.backupFiles(app.parent.local!.path, backupPath, conflictFiles);
}
await this.postInstall(app, installDir);
let local = new AppLocal();
local.path = installDir;
local.files = checksumFile;
local.version = app.version;
app.local = local;
this.saveAppLocal(app);
app.status.status = "ready";
}
// }
} catch (e) {
throw e;
}
finally {
this.installQueue.delete(id);
this.installingId = '';
if (this.installQueue.size > 0) {
this.doInstall();
let allFiles = new Set(checksumFile.keys());
app.status.status = "installing";
app.status.total = allFiles.size;
app.status.progress = 0;
// let timeNow = new Date().getTime();
for (let file of option.downloadFiles) {
await this.createDirectory(installDir);
let interval = setInterval(() => {
}, 500);
await new Promise((resolve, reject) => {
this.extract(file, installDir).subscribe(
(lastItem: string) => {
app.status.progress += 1;
app.status.progressMessage = lastItem;
},
(error) => {
reject(error);
},
() => {
resolve();
});
});
clearInterval(interval);
}
await this.postInstall(app, installDir);
console.log("post install success");
let local = new AppLocal();
local.path = installDir;
local.files = checksumFile;
local.version = app.version;
app.local = local;
this.saveAppLocal(app);
app.status.status = "ready";
}
// }
} catch (e) {
console.log("exception in doInstall", e);
throw e;
}
finally {
this.eventEmitter.emit();
}
}
createDirectory(dir: string) {
......@@ -158,14 +158,6 @@ export class InstallService {
})
}
getComplete(app: App): Promise<App> {
return new Promise((resolve, reject) => {
this.eventEmitter.once(app.id, (complete: any) => {
resolve();
});
});
}
extract(file: string, dir: string): Observable<string> {
return Observable.create((observer: Observer<string>) => {
let tarProcess = child_process.spawn(this.tarPath, ['xvf', file, '-C', dir]);
......@@ -208,13 +200,13 @@ export class InstallService {
shell: true,
});
child.on('error', (error) => {
console.log(error);
reject(error);
});
child.on('exit', (code) => {
if (code === 0) {
resolve();
resolve(code);
} else {
reject();
reject(code);
}
})
})
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment