1
1
/* @flow */
2
+ import path from 'path' ;
3
+ import fs from 'mz/fs' ;
2
4
import { signAddon as defaultAddonSigner } from '../util/es6-modules' ;
3
5
4
6
import defaultBuilder from './build' ;
5
- import { InvalidManifest } from '../errors' ;
6
7
import { withTempDir } from '../util/temp-dir' ;
7
- import getValidatedManifest from '../util/manifest' ;
8
+ import { onlyErrorsWithCode , WebExtError } from '../errors' ;
9
+ import getValidatedManifest , { getManifestId } from '../util/manifest' ;
8
10
import { prepareArtifactsDir } from '../util/artifacts' ;
9
11
import { createLogger } from '../util/logger' ;
10
12
11
13
const log = createLogger ( __filename ) ;
12
-
14
+ export const extensionIdFile = '.web-extension-id' ;
13
15
14
16
export default function sign (
15
17
{ verbose, sourceDir, artifactsDir, apiKey, apiSecret,
16
- apiUrlPrefix, timeout} : Object ,
18
+ apiUrlPrefix, id , timeout} : Object ,
17
19
{ build= defaultBuilder , signAddon= defaultAddonSigner ,
18
20
preValidatedManifest= null } : Object = { } ) : Promise {
19
21
@@ -28,39 +30,102 @@ export default function sign(
28
30
}
29
31
} )
30
32
. then ( ( manifestData ) => {
31
- if ( ! manifestData . applications ) {
32
- // TODO: remove this when signing supports manifests
33
- // without IDs: https://github.com/mozilla/web-ext/issues/178
34
- throw new InvalidManifest (
35
- 'applications.gecko.id in manifest.json is required for signing' ) ;
33
+ return Promise . all ( [
34
+ build ( { sourceDir, artifactsDir : tmpDir . path ( ) } , { manifestData} ) ,
35
+ getIdFromSourceDir ( sourceDir ) ,
36
+ ] )
37
+ . then ( ( [ buildResult , idFromSourceDir ] ) => {
38
+ return { buildResult, manifestData, idFromSourceDir} ;
39
+ } ) ;
40
+ } )
41
+ . then ( ( { buildResult, manifestData, idFromSourceDir} ) => {
42
+ const manifestId = getManifestId ( manifestData ) ;
43
+ if ( id && manifestId ) {
44
+ throw new WebExtError (
45
+ `Cannot set custom ID ${ id } because manifest.json ` +
46
+ `declares ID ${ manifestId } ` ) ;
47
+ }
48
+ if ( manifestId ) {
49
+ id = manifestId ;
50
+ }
51
+ if ( ! id && idFromSourceDir ) {
52
+ log . info (
53
+ 'Using previously auto-generated extension ID: ' +
54
+ `${ idFromSourceDir } ` ) ;
55
+ id = idFromSourceDir ;
56
+ }
57
+ if ( ! id ) {
58
+ log . warn ( 'No extension ID specified (it will be auto-generated)' ) ;
36
59
}
37
- return manifestData ;
60
+ return signAddon ( {
61
+ apiKey,
62
+ apiSecret,
63
+ apiUrlPrefix,
64
+ timeout,
65
+ verbose,
66
+ id,
67
+ xpiPath : buildResult . extensionPath ,
68
+ version : manifestData . version ,
69
+ downloadDir : artifactsDir ,
70
+ } ) ;
38
71
} )
39
- . then ( ( manifestData ) => {
40
- return build (
41
- { sourceDir, artifactsDir : tmpDir . path ( ) } ,
42
- { manifestData } )
43
- . then ( ( buildResult ) => {
44
- return { buildResult , manifestData } ;
45
- } ) ;
72
+ . then ( ( signingResult ) => {
73
+ if ( signingResult . id ) {
74
+ return saveIdToSourceDir ( sourceDir , signingResult . id )
75
+ . then ( ( ) => signingResult ) ;
76
+ } else {
77
+ return signingResult ;
78
+ }
46
79
} )
47
- . then ( ( { buildResult, manifestData} ) => signAddon ( {
48
- apiKey,
49
- apiSecret,
50
- apiUrlPrefix,
51
- timeout,
52
- verbose,
53
- xpiPath : buildResult . extensionPath ,
54
- id : manifestData . applications . gecko . id ,
55
- version : manifestData . version ,
56
- downloadDir : artifactsDir ,
57
- } ) )
58
80
. then ( ( signingResult ) => {
59
81
// All information about the downloaded files would have
60
82
// already been logged by signAddon().
61
- log . info ( signingResult . success ? 'SUCCESS' : 'FAIL' ) ;
83
+ if ( signingResult . success ) {
84
+ log . info ( `Extension ID: ${ signingResult . id } ` ) ;
85
+ log . info ( 'SUCCESS' ) ;
86
+ } else {
87
+ log . info ( 'FAIL' ) ;
88
+ }
62
89
return signingResult ;
63
90
} ) ;
64
91
}
65
92
) ;
66
93
}
94
+
95
+
96
+ export function getIdFromSourceDir ( sourceDir : string ) : Promise {
97
+ const filePath = path . join ( sourceDir , extensionIdFile ) ;
98
+ return fs . readFile ( filePath )
99
+ . then ( ( content ) => {
100
+ let lines = content . toString ( ) . split ( '\n' ) ;
101
+ lines = lines . filter ( ( line ) => {
102
+ line = line . trim ( ) ;
103
+ if ( line && ! line . startsWith ( '#' ) ) {
104
+ return line ;
105
+ }
106
+ } ) ;
107
+ let id = lines [ 0 ] ;
108
+ log . debug ( `Found extension ID ${ id } in ${ filePath } ` ) ;
109
+ if ( ! id ) {
110
+ throw new WebExtError ( `No ID found in extension ID file ${ filePath } ` ) ;
111
+ }
112
+ return id ;
113
+ } )
114
+ . catch ( onlyErrorsWithCode ( 'ENOENT' , ( ) => {
115
+ log . debug ( `No ID file found at: ${ filePath } ` ) ;
116
+ } ) ) ;
117
+ }
118
+
119
+
120
+ export function saveIdToSourceDir ( sourceDir : string , id : string ) : Promise {
121
+ const filePath = path . join ( sourceDir , extensionIdFile ) ;
122
+ return fs . writeFile ( filePath ,
123
+ [
124
+ '# This file was created by https://github.com/mozilla/web-ext' ,
125
+ '# Your auto-generated extension ID for addons.mozilla.org is:' ,
126
+ id . toString ( ) ,
127
+ ] . join ( '\n' ) )
128
+ . then ( ( ) => {
129
+ log . debug ( `Saved auto-generated ID ${ id } to ${ filePath } ` ) ;
130
+ } ) ;
131
+ }
0 commit comments