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

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

parents 4b0bf09a 783edb27
...@@ -83,7 +83,7 @@ ...@@ -83,7 +83,7 @@
<!--安装modal--> <!--安装modal-->
<div class="modal fade" id="install-modal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true" *ngIf="installOption"> <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"> <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"> <div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"> <button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span>&times;</span> <span>&times;</span>
......
...@@ -95,8 +95,9 @@ export class AppDetailComponent implements OnInit { ...@@ -95,8 +95,9 @@ export class AppDetailComponent implements OnInit {
} }
async installMod(mod: App) { 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 { ...@@ -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'); $('#install-modal').modal('hide');
let options = this.installOption;
try { try {
await this.appsService.install(targetApp, options); await this.appsService.install(targetApp, options);
if (this.references.length > 0) { for (let [id,install] of Object.entries(referencesInstall)) {
for (let [id,isInstalled] of Object.entries(this.referencesInstall)) { if (install) {
if (isInstalled) { let reference = targetApp.references.get(id)!;
let reference = targetApp.references.get(id)!; console.log("reference install ", id, targetApp, targetApp.references, reference);
await this.appsService.install(reference, options); await this.appsService.install(reference, options);
}
} }
} }
} catch (e) { } catch (e) {
......
...@@ -3,7 +3,6 @@ import {App} from "./app"; ...@@ -3,7 +3,6 @@ import {App} from "./app";
* Created by zh99998 on 16/9/6. * Created by zh99998 on 16/9/6.
*/ */
export class AppLocal { export class AppLocal {
library: string;
path: string; path: string;
version: string; version: string;
files: Map<string,string>; files: Map<string,string>;
......
...@@ -100,8 +100,9 @@ export class App { ...@@ -100,8 +100,9 @@ export class App {
isDownloading(): boolean { isDownloading(): boolean {
return this.status.status === "downloading"; return this.status.status === "downloading";
} }
isUninstalling():boolean{
return this.status.status==="uninstalling"; isUninstalling(): boolean {
return this.status.status === "uninstalling";
} }
runable(): boolean { runable(): boolean {
...@@ -146,4 +147,9 @@ export class App { ...@@ -146,4 +147,9 @@ export class App {
return []; 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 { ...@@ -216,26 +216,35 @@ export class AppsService {
}); });
}; };
if (!app.isInstalled()) { if (!app.isInstalled()) {
let apps: App[] = [];
let dependencies = app.findDependencies().filter((dependency) => {
return !dependency.isInstalled();
});
apps.push(...dependencies, app);
try { 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 downloadPath = path.join(option.installLibrary, 'downloading');
let tasks: Promise<any>[] = []; let tasks: Promise<any>[] = [];
for (let a of apps) { for (let a of apps) {
tasks.push(addDownloadTask(a, downloadPath)); tasks.push(addDownloadTask(a, downloadPath));
} }
let downloadResults = await Promise.all(tasks); let downloadResults = await Promise.all(tasks);
let installTasks: Promise<void>[] = [];
for (let result of downloadResults) { for (let result of downloadResults) {
console.log(result); console.log(result);
let o = new InstallOption(result.app, option.installLibrary); let o = new InstallOption(result.app, option.installLibrary);
o.downloadFiles = result.files; 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) { } catch (e) {
app.status.status = 'init'; for (let a of apps) {
if (!a.isReady()) {
a.status.status = 'init';
}
}
console.log(e); console.log(e);
throw e; throw e;
} }
......
/** /**
* Created by weijian on 2016/11/2. * 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 {App, Category} from "./app";
import {InstallOption} from "./install-option"; import {InstallOption} from "./install-option";
import * as path from "path"; import * as path from "path";
...@@ -9,7 +9,6 @@ import * as child_process from "child_process"; ...@@ -9,7 +9,6 @@ import * as child_process from "child_process";
import * as mkdirp from "mkdirp"; import * as mkdirp from "mkdirp";
import * as readline from "readline"; import * as readline from "readline";
import * as fs from "fs"; import * as fs from "fs";
import {EventEmitter} from "events";
import {AppLocal} from "./app-local"; import {AppLocal} from "./app-local";
import {Http} from "@angular/http"; import {Http} from "@angular/http";
import {ComparableSet} from "./shared/ComparableSet" import {ComparableSet} from "./shared/ComparableSet"
...@@ -31,7 +30,7 @@ export interface InstallStatus { ...@@ -31,7 +30,7 @@ export interface InstallStatus {
export class InstallService { export class InstallService {
tarPath: string; tarPath: string;
installingId: string = ''; installingId: string = '';
eventEmitter: EventEmitter = new EventEmitter(); eventEmitter = new EventEmitter<void>();
readonly checksumURL = "https://thief.mycard.moe/checksums/"; readonly checksumURL = "https://thief.mycard.moe/checksums/";
readonly updateServerURL = 'https://thief.mycard.moe/update/metalinks'; readonly updateServerURL = 'https://thief.mycard.moe/update/metalinks';
...@@ -70,86 +69,87 @@ export class InstallService { ...@@ -70,86 +69,87 @@ export class InstallService {
// } // }
// } // }
push(task: InstallTask): string { async push(task: InstallTask): Promise<void> {
let id = this.createId(); if (!task.app.readyForInstall()) {
this.installQueue.set(id, task); await new Promise((resolve, reject) => {
if (this.installQueue.size > 0 && this.installingId == '') { this.eventEmitter.subscribe(() => {
this.doInstall(); 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() { async doInstall(task: InstallTask) {
if (this.installQueue.size > 0 && this.installingId == '') { try {
let [id,task] = this.installQueue.entries().next().value!; let app = task.app;
this.installingId = id; let dependencies = app.findDependencies();
try { let readyForInstall = dependencies.every((dependency) => {
let app = task.app; return dependency.isReady();
let dependencies = app.findDependencies(); });
let readyForInstall = dependencies.every((dependency) => { if (readyForInstall) {
return dependency.isReady(); let option = task.option;
}); let installDir = option.installDir;
if (readyForInstall) { // if (!app.isInstalled()) {
let option = task.option; let checksumFile = await this.getChecksumFile(app);
let installDir = option.installDir; if (app.parent) {
// if (!app.isInstalled()) { // mod需要安装到parent路径
let checksumFile = await this.getChecksumFile(app); installDir = app.parent.local!.path;
if (app.parent) { let parentFiles = new ComparableSet(Array.from(app.parent.local!.files.keys()));
// mod需要安装到parent路径 let appFiles = new ComparableSet(Array.from(checksumFile.keys()));
installDir = app.parent.local!.path; let conflictFiles = appFiles.intersection(parentFiles);
let parentFiles = new ComparableSet(Array.from(app.parent.local!.files.keys())); if (conflictFiles.size > 0) {
let appFiles = new ComparableSet(Array.from(checksumFile.keys())); let backupPath = path.join(option.installLibrary, "backup", app.parent.id);
let conflictFiles = appFiles.intersection(parentFiles); await this.backupFiles(app.parent.local!.path, backupPath, conflictFiles);
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);
} }
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";
} }
// } let allFiles = new Set(checksumFile.keys());
} catch (e) { app.status.status = "installing";
throw e; app.status.total = allFiles.size;
} app.status.progress = 0;
finally { // let timeNow = new Date().getTime();
this.installQueue.delete(id); for (let file of option.downloadFiles) {
this.installingId = ''; await this.createDirectory(installDir);
if (this.installQueue.size > 0) { let interval = setInterval(() => {
this.doInstall(); }, 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) { createDirectory(dir: string) {
...@@ -158,14 +158,6 @@ export class InstallService { ...@@ -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> { extract(file: string, dir: string): Observable<string> {
return Observable.create((observer: Observer<string>) => { return Observable.create((observer: Observer<string>) => {
let tarProcess = child_process.spawn(this.tarPath, ['xvf', file, '-C', dir]); let tarProcess = child_process.spawn(this.tarPath, ['xvf', file, '-C', dir]);
...@@ -208,13 +200,13 @@ export class InstallService { ...@@ -208,13 +200,13 @@ export class InstallService {
shell: true, shell: true,
}); });
child.on('error', (error) => { child.on('error', (error) => {
console.log(error); reject(error);
}); });
child.on('exit', (code) => { child.on('exit', (code) => {
if (code === 0) { if (code === 0) {
resolve(); resolve(code);
} else { } 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