@@ -83,6 +83,85 @@ export abstract class TargetEx extends Target {
83
83
abstract async build ( appOutDir : string , arch : Arch ) : Promise < any >
84
84
}
85
85
86
+ export interface FilePattern {
87
+ from ?: string
88
+ to ?: string
89
+ filter ?: Array < string > | string
90
+ }
91
+
92
+ export interface FileMatchOptions {
93
+ arch : string ,
94
+ os : string
95
+ }
96
+
97
+ export class FileMatcher {
98
+ readonly from : string
99
+ readonly to : string
100
+ readonly options : FileMatchOptions
101
+
102
+ readonly patterns : Array < string >
103
+
104
+ constructor ( from : string , to : string , options : FileMatchOptions , patterns ?: Array < string > | string | n ) {
105
+ this . options = options
106
+ this . patterns = [ ]
107
+
108
+ this . from = this . expandPattern ( from )
109
+ this . to = this . expandPattern ( to )
110
+
111
+ if ( patterns != null && ! Array . isArray ( patterns ) ) {
112
+ this . patterns = [ patterns ]
113
+ }
114
+ else if ( patterns != null ) {
115
+ this . patterns = patterns
116
+ }
117
+ }
118
+
119
+ addPattern ( pattern : string ) {
120
+ this . patterns . push ( pattern )
121
+ }
122
+
123
+ isEmpty ( ) {
124
+ return this . patterns . length === 0
125
+ }
126
+
127
+ getParsedPatterns ( fromDir ?: string ) : Array < Minimatch > {
128
+ const minimatchOptions = { }
129
+
130
+ const parsedPatterns : Array < Minimatch > = [ ]
131
+ const pathDifference = fromDir ? path . relative ( fromDir , this . from ) : null
132
+
133
+ for ( let i = 0 ; i < this . patterns . length ; i ++ ) {
134
+ let expandedPattern = this . expandPattern ( this . patterns [ i ] )
135
+
136
+ if ( pathDifference ) {
137
+ expandedPattern = path . join ( pathDifference , expandedPattern )
138
+ }
139
+
140
+ const parsedPattern = new Minimatch ( expandedPattern , minimatchOptions )
141
+ parsedPatterns . push ( parsedPattern )
142
+
143
+ if ( ! hasMagic ( parsedPattern ) ) {
144
+ // https://github.com/electron-userland/electron-builder/issues/545
145
+ // add **/*
146
+ parsedPatterns . push ( new Minimatch ( `${ expandedPattern } /*/**` , minimatchOptions ) )
147
+ }
148
+ }
149
+
150
+ return parsedPatterns
151
+ }
152
+
153
+ createFilter ( ignoreFiles ?: Set < string > , rawFilter ?: ( file : string ) => boolean , excludePatterns ?: Array < Minimatch > | n ) : ( file : string ) => boolean {
154
+ return createFilter ( this . from , this . getParsedPatterns ( ) , ignoreFiles , rawFilter , excludePatterns )
155
+ }
156
+
157
+ private expandPattern ( pattern : string ) : string {
158
+ return pattern
159
+ . replace ( / \$ \{ a r c h } / g, this . options . arch )
160
+ . replace ( / \$ \{ o s } / g, this . options . os )
161
+ . replace ( / \$ \{ \/ \* } / g, "{,/**/*,/**/.*}" )
162
+ }
163
+ }
164
+
86
165
export abstract class PlatformPackager < DC extends PlatformSpecificBuildOptions > {
87
166
readonly options : PackagerOptions
88
167
@@ -156,16 +235,22 @@ export abstract class PlatformPackager<DC extends PlatformSpecificBuildOptions>
156
235
157
236
abstract pack ( outDir : string , arch : Arch , targets : Array < Target > , postAsyncTasks : Array < Promise < any > > ) : Promise < any >
158
237
159
- private getExtraFilePatterns ( isResources : boolean , arch : Arch , customBuildOptions : DC ) : Array < Minimatch > | null {
160
- const patterns = this . getFilePatterns ( isResources ? "extraResources" : "extraFiles" , customBuildOptions )
161
- return patterns == null || patterns . length === 0 ? null : this . getParsedPatterns ( patterns , arch )
238
+ private getExtraFilePatterns ( isResources : boolean , appOutDir : string , fileMatchOptions : FileMatchOptions , customBuildOptions : DC ) : Array < FileMatcher > | n {
239
+ const base = isResources ? this . getResourcesDir ( appOutDir ) : ( this . platform === Platform . MAC ? path . join ( appOutDir , ` ${ this . appInfo . productFilename } .app` , "Contents" ) : appOutDir )
240
+ return this . getFilePatterns ( isResources ? "extraResources" : "extraFiles" , this . projectDir , base , true , fileMatchOptions , customBuildOptions )
162
241
}
163
242
164
243
protected async doPack ( options : ElectronPackagerOptions , outDir : string , appOutDir : string , platformName : string , arch : Arch , platformSpecificBuildOptions : DC ) {
165
244
const asarOptions = this . computeAsarOptions ( platformSpecificBuildOptions )
245
+ const fileMatchOptions : FileMatchOptions = {
246
+ arch : Arch [ arch ] ,
247
+ os : this . platform . buildConfigurationKey
248
+ }
249
+
250
+ const extraResourcePatterns = this . getExtraFilePatterns ( true , appOutDir , fileMatchOptions , platformSpecificBuildOptions )
251
+ const extraFilePatterns = this . getExtraFilePatterns ( false , appOutDir , fileMatchOptions , platformSpecificBuildOptions )
166
252
167
- const extraResourcePatterns = this . getExtraFilePatterns ( true , arch , platformSpecificBuildOptions )
168
- const extraFilePatterns = this . getExtraFilePatterns ( false , arch , platformSpecificBuildOptions )
253
+ const resourcesPath = this . platform === Platform . MAC ? path . join ( appOutDir , "Electron.app" , "Contents" , "Resources" ) : path . join ( appOutDir , "resources" )
169
254
170
255
const p = pack ( options , appOutDir , platformName , Arch [ arch ] , this . info . electronVersion , async ( ) => {
171
256
const ignoreFiles = new Set ( [ path . resolve ( this . info . appDir , outDir ) , path . resolve ( this . info . appDir , this . buildResourcesDir ) ] )
@@ -176,11 +261,13 @@ export abstract class PlatformPackager<DC extends PlatformSpecificBuildOptions>
176
261
}
177
262
}
178
263
179
- let patterns = this . getFilePatterns ( "files" , platformSpecificBuildOptions )
180
- if ( patterns == null || patterns . length === 0 ) {
181
- patterns = [ "**/*" ]
264
+ let patterns = this . getFilePatterns ( "files" , this . info . appDir , path . join ( resourcesPath , "app" ) , false , fileMatchOptions , platformSpecificBuildOptions )
265
+ let defaultMatcher = patterns != null ? patterns [ 0 ] : new FileMatcher ( this . info . appDir , path . join ( resourcesPath , "app" ) , fileMatchOptions )
266
+
267
+ if ( defaultMatcher . isEmpty ( ) ) {
268
+ defaultMatcher . addPattern ( "**/*" )
182
269
}
183
- patterns . push ( "!**/node_modules/*/{README.md,README,readme.md,readme,test}" )
270
+ defaultMatcher . addPattern ( "!**/node_modules/*/{README.md,README,readme.md,readme,test}" )
184
271
185
272
let rawFilter : any = null
186
273
const deprecatedIgnore = ( < any > this . devMetadata . build ) . ignore
@@ -194,24 +281,21 @@ export abstract class PlatformPackager<DC extends PlatformSpecificBuildOptions>
194
281
rawFilter = deprecatedUserIgnoreFilter ( options , this . info . appDir )
195
282
}
196
283
197
- const filePatterns = this . getParsedPatterns ( patterns , arch )
198
- let excludePatterns : Array < Minimatch > | null = null
199
- if ( ! this . info . isTwoPackageJsonProjectLayoutUsed ) {
200
- if ( extraResourcePatterns != null ) {
201
- excludePatterns = extraResourcePatterns
284
+ let excludePatterns : Array < Minimatch > = [ ]
285
+ if ( extraResourcePatterns ! = null ) {
286
+ for ( let i = 0 ; i < extraResourcePatterns . length ; i ++ ) {
287
+ const patterns = extraResourcePatterns [ i ] . getParsedPatterns ( this . info . projectDir )
288
+ excludePatterns = excludePatterns . concat ( patterns )
202
289
}
203
- if ( extraFilePatterns != null ) {
204
- if ( excludePatterns == null ) {
205
- excludePatterns = extraFilePatterns
206
- }
207
- else {
208
- excludePatterns = excludePatterns . concat ( extraFilePatterns )
209
- }
290
+ }
291
+ if ( extraFilePatterns != null ) {
292
+ for ( let i = 0 ; i < extraFilePatterns . length ; i ++ ) {
293
+ const patterns = extraFilePatterns [ i ] . getParsedPatterns ( this . info . projectDir )
294
+ excludePatterns = excludePatterns . concat ( patterns )
210
295
}
211
296
}
212
297
213
- const resourcesPath = this . platform === Platform . MAC ? path . join ( appOutDir , "Electron.app" , "Contents" , "Resources" ) : path . join ( appOutDir , "resources" )
214
- const filter = createFilter ( this . info . appDir , filePatterns , ignoreFiles , rawFilter , excludePatterns )
298
+ const filter = defaultMatcher . createFilter ( ignoreFiles , rawFilter , excludePatterns . length ? excludePatterns : null )
215
299
const promise = asarOptions == null ?
216
300
copyFiltered ( this . info . appDir , path . join ( resourcesPath , "app" ) , filter , this . platform === Platform . WINDOWS )
217
301
: createAsarArchive ( this . info . appDir , resourcesPath , asarOptions , filter )
@@ -227,8 +311,8 @@ export abstract class PlatformPackager<DC extends PlatformSpecificBuildOptions>
227
311
} )
228
312
await task ( `Packaging for platform ${ platformName } ${ Arch [ arch ] } using electron ${ this . info . electronVersion } to ${ path . relative ( this . projectDir , appOutDir ) } ` , p )
229
313
230
- await this . doCopyExtraFiles ( true , appOutDir , extraResourcePatterns )
231
- await this . doCopyExtraFiles ( false , appOutDir , extraFilePatterns )
314
+ await this . doCopyExtraFiles ( extraResourcePatterns )
315
+ await this . doCopyExtraFiles ( extraFilePatterns )
232
316
233
317
const afterPack = this . devMetadata . build . afterPack
234
318
if ( afterPack != null ) {
@@ -294,54 +378,63 @@ export abstract class PlatformPackager<DC extends PlatformSpecificBuildOptions>
294
378
} )
295
379
}
296
380
297
- private expandPattern ( pattern : string , arch : Arch ) : string {
298
- return pattern
299
- . replace ( / \$ \{ a r c h } / g, Arch [ arch ] )
300
- . replace ( / \$ \{ o s } / g, this . platform . buildConfigurationKey )
301
- . replace ( / \$ \{ \/ \* } / g, "{,/**/*,/**/.*}" )
302
- }
303
-
304
- private doCopyExtraFiles ( isResources : boolean , appOutDir : string , patterns : Array < Minimatch > | null ) : Promise < any > {
305
- const base = isResources ? this . getResourcesDir ( appOutDir ) : ( this . platform === Platform . MAC ? path . join ( appOutDir , `${ this . appInfo . productFilename } .app` , "Contents" ) : appOutDir )
381
+ private doCopyExtraFiles ( patterns : Array < FileMatcher > | n ) : Promise < any > {
306
382
if ( patterns == null || patterns . length === 0 ) {
307
383
return BluebirdPromise . resolve ( )
308
384
}
309
385
else {
310
- return copyFiltered ( this . projectDir , base , createFilter ( this . projectDir , patterns ) , this . platform === Platform . WINDOWS )
386
+ const promises : Array < Promise < any > > = [ ]
387
+ for ( let i = 0 ; i < patterns . length ; i ++ ) {
388
+ if ( patterns [ i ] . isEmpty ( ) ) {
389
+ patterns [ i ] . addPattern ( "**/*" )
390
+ }
391
+ promises . push ( copyFiltered ( patterns [ i ] . from , patterns [ i ] . to , patterns [ i ] . createFilter ( ) , this . platform === Platform . WINDOWS ) )
392
+ }
393
+ return BluebirdPromise . all ( promises )
311
394
}
312
395
}
313
396
314
- private getParsedPatterns ( patterns : Array < string > , arch : Arch ) : Array < Minimatch > {
315
- const minimatchOptions = { }
316
- const parsedPatterns : Array < Minimatch > = [ ]
317
- for ( let i = 0 ; i < patterns . length ; i ++ ) {
318
- const pattern = this . expandPattern ( patterns [ i ] , arch )
319
- const parsedPattern = new Minimatch ( pattern , minimatchOptions )
320
- parsedPatterns . push ( parsedPattern )
321
- if ( ! hasMagic ( parsedPattern ) ) {
322
- // https://github.com/electron-userland/electron-builder/issues/545
323
- // add **/*
324
- parsedPatterns . push ( new Minimatch ( `${ pattern } /*/**` , minimatchOptions ) )
397
+ private getFilePatterns ( name : "files" | "extraFiles" | "extraResources" , defaultSrc : string , defaultDest : string , allowAdvancedMatching : boolean , fileMatchOptions : FileMatchOptions , customBuildOptions : DC ) : Array < FileMatcher > | n {
398
+ let globalPatterns : Array < string | FilePattern > | string | n = ( < any > this . devMetadata . build ) [ name ]
399
+ let platformSpecificPatterns : Array < string | FilePattern > | string | n = ( < any > customBuildOptions ) [ name ]
400
+
401
+ const defaultMatcher = new FileMatcher ( defaultSrc , defaultDest , fileMatchOptions )
402
+ const fileMatchers : Array < FileMatcher > = [ ]
403
+
404
+ function addPatterns ( patterns : Array < string | FilePattern > | string | n ) {
405
+ if ( patterns == null ) {
406
+ return
407
+ }
408
+ else if ( ! Array . isArray ( patterns ) ) {
409
+ defaultMatcher . addPattern ( patterns )
410
+ return
411
+ }
412
+
413
+ for ( let i = 0 ; i < patterns . length ; i ++ ) {
414
+ const pattern = patterns [ i ]
415
+ if ( typeof pattern === "string" ) {
416
+ defaultMatcher . addPattern ( pattern )
417
+ }
418
+ else if ( allowAdvancedMatching ) {
419
+ const from = pattern . from ? ( path . isAbsolute ( pattern . from ) ? pattern . from : path . join ( defaultSrc , pattern . from ) ) : defaultSrc
420
+ const to = pattern . to ? ( path . isAbsolute ( pattern . to ) ? pattern . to : path . join ( defaultDest , pattern . to ) ) : defaultDest
421
+ fileMatchers . push ( new FileMatcher ( from , to , fileMatchOptions , pattern . filter ) )
422
+ }
423
+ else {
424
+ throw new Error ( `Advanced file copying not supported for "${ name } "` )
425
+ }
325
426
}
326
427
}
327
428
328
- return parsedPatterns
329
- }
429
+ addPatterns ( globalPatterns )
430
+ addPatterns ( platformSpecificPatterns )
330
431
331
- private getFilePatterns ( name : "files" | "extraFiles" | "extraResources" , customBuildOptions : DC ) : Array < string > | n {
332
- let patterns : Array < string > | string | n = ( < any > this . devMetadata . build ) [ name ]
333
- if ( patterns != null && ! Array . isArray ( patterns ) ) {
334
- patterns = [ patterns ]
432
+ if ( ! defaultMatcher . isEmpty ( ) ) {
433
+ // Default matcher should be first in the array
434
+ fileMatchers . unshift ( defaultMatcher )
335
435
}
336
436
337
- let platformSpecificPatterns : Array < string > | string | n = ( < any > customBuildOptions ) [ name ]
338
- if ( platformSpecificPatterns != null ) {
339
- if ( ! Array . isArray ( platformSpecificPatterns ) ) {
340
- platformSpecificPatterns = [ platformSpecificPatterns ]
341
- }
342
- return patterns == null ? platformSpecificPatterns : Array . from ( new Set ( patterns . concat ( platformSpecificPatterns ) ) )
343
- }
344
- return patterns
437
+ return fileMatchers . length ? fileMatchers : null
345
438
}
346
439
347
440
private getResourcesDir ( appOutDir : string ) : string {
0 commit comments