@@ -12,7 +12,7 @@ import { TheiaBrowserGenerator } from 'generator-theia/generators/browser/browse
12
12
import { TheiaElectronGenerator } from 'generator-theia/generators/electron/electron-generator' ;
13
13
import {
14
14
MaybePromise , Disposable , DisposableCollection , Event , Emitter , ILogger ,
15
- CancellationTokenSource , CancellationToken , isCancelled
15
+ CancellationTokenSource , CancellationToken , isCancelled , isDisposed , checkDisposed
16
16
} from "@theia/core" ;
17
17
import { FileUri , ServerProcess } from "@theia/core/lib/node" ;
18
18
@@ -65,11 +65,19 @@ export class AppProject implements Disposable {
65
65
} ) ;
66
66
this . toDispose . push ( this . onWillInstallEmitter ) ;
67
67
this . toDispose . push ( this . onDidInstallEmitter ) ;
68
+ this . toDispose . push ( Disposable . create ( ( ) => this . installationTokenSource . cancel ( ) ) ) ;
68
69
}
69
70
70
71
dispose ( ) : void {
71
72
this . toDispose . dispose ( ) ;
72
73
}
74
+ get onDispose ( ) : Promise < void > {
75
+ if ( this . toDispose . disposed ) {
76
+ return this . installed ;
77
+ }
78
+ const disposed = new Promise < void > ( resolve => this . toDispose . onDispose ( resolve ) ) ;
79
+ return Promise . all ( [ disposed , this . installed ] ) . then ( ( ) => { } ) ;
80
+ }
73
81
74
82
get onDidChangePackage ( ) : Event < void > {
75
83
return this . onChangePackageEmitter . event ;
@@ -92,9 +100,10 @@ export class AppProject implements Disposable {
92
100
}
93
101
94
102
load ( ) : Promise < ProjectModel > {
95
- return this . generator . then ( generator => generator . model ) ;
103
+ return this . getGenerator ( ) . then ( generator => generator . model ) ;
96
104
}
97
- protected get generator ( ) : Promise < CommonAppGenerator > {
105
+ protected async getGenerator ( ) : Promise < CommonAppGenerator > {
106
+ await this . ensureProjectConfigExists ( ) ;
98
107
const generatorConstructor = this . options . target === 'browser' ? TheiaBrowserGenerator : TheiaElectronGenerator ;
99
108
const generator = new generatorConstructor ( [ ] , {
100
109
env : {
@@ -106,6 +115,17 @@ export class AppProject implements Disposable {
106
115
generator . initializing ( ) ;
107
116
return generator . configuring ( ) . then ( ( ) => generator ) ;
108
117
}
118
+ /**
119
+ * If the project config does not exist yeoman will pick the parent directory with the config as a project directory.
120
+ */
121
+ protected async ensureProjectConfigExists ( ) : Promise < void > {
122
+ const projectConfig = FileUri . create ( this . options . path ) . resolve ( '.yo-rc.json' ) . toString ( ) ;
123
+ try {
124
+ await this . fileSystem . createFile ( projectConfig , {
125
+ content : '{}'
126
+ } ) ;
127
+ } catch { /* exist */ }
128
+ }
109
129
110
130
async save ( model : MaybePromise < ProjectModel > ) : Promise < void > {
111
131
const resolved = await model ;
@@ -148,9 +168,9 @@ export class AppProject implements Disposable {
148
168
protected installed : Promise < void > = Promise . resolve ( ) ;
149
169
protected installationTokenSource = new CancellationTokenSource ( ) ;
150
170
async scheduleInstall ( params : InstallParams = { force : false } ) : Promise < void > {
151
- if ( this . installationTokenSource ) {
152
- this . installationTokenSource . cancel ( ) ;
153
- }
171
+ checkDisposed ( this . toDispose ) ;
172
+ this . installationTokenSource . cancel ( ) ;
173
+
154
174
this . installationTokenSource = new CancellationTokenSource ( ) ;
155
175
const token = this . installationTokenSource . token ;
156
176
this . installed = this . installed . then ( ( ) => this . install ( params , token ) ) ;
@@ -169,6 +189,9 @@ export class AppProject implements Disposable {
169
189
this . fireDidInstall ( ) ;
170
190
this . serverProcess . restart ( ) ;
171
191
} catch ( err ) {
192
+ if ( isDisposed ( err ) ) {
193
+ throw err ;
194
+ }
172
195
if ( isCancelled ( err ) ) {
173
196
this . logger . info ( 'The app installation is cancelled' ) ;
174
197
return ;
@@ -184,7 +207,9 @@ export class AppProject implements Disposable {
184
207
}
185
208
186
209
protected async installer ( token ?: CancellationToken ) : Promise < AppProjectInstaller > {
187
- const generator = await this . generator ;
210
+ checkDisposed ( this . toDispose ) ;
211
+
212
+ const generator = await this . getGenerator ( ) ;
188
213
return this . installerFactory ( {
189
214
generator,
190
215
projectPath : this . options . path ,
0 commit comments