@@ -7,6 +7,10 @@ import Git from '../util/git.js';
7
7
import * as fsUtil from '../util/fs.js' ;
8
8
import * as constants from '../constants.js' ;
9
9
import * as crypto from '../util/crypto.js' ;
10
+ import { install } from '../cli/commands/install.js' ;
11
+ import Lockfile from '../lockfile/wrapper.js' ;
12
+ import Config from '../config.js' ;
13
+ import { packTarball } from '../cli/commands/pack.js' ;
10
14
11
15
const tarFs = require ( 'tar-fs' ) ;
12
16
const url = require ( 'url' ) ;
@@ -15,6 +19,8 @@ const fs = require('fs');
15
19
16
20
const invariant = require ( 'invariant' ) ;
17
21
22
+ const PACKED_FLAG = '1' ;
23
+
18
24
export default class GitFetcher extends BaseFetcher {
19
25
async getLocalAvailabilityStatus ( ) : Promise < boolean > {
20
26
// Some mirrors might still have files named "./reponame" instead of "./reponame-commit"
@@ -78,11 +84,7 @@ export default class GitFetcher extends BaseFetcher {
78
84
}
79
85
80
86
return new Promise ( ( resolve , reject ) => {
81
- const untarStream = tarFs . extract ( this . dest , {
82
- dmode : 0o555 , // all dirs should be readable
83
- fmode : 0o444 , // all files should be readable
84
- chown : false , // don't chown. just leave as it is
85
- } ) ;
87
+ const untarStream = this . _createUntarStream ( this . dest ) ;
86
88
87
89
const hashStream = new crypto . HashStream ( ) ;
88
90
@@ -117,22 +119,131 @@ export default class GitFetcher extends BaseFetcher {
117
119
const gitUrl = Git . npmUrlToGitUrl ( this . reference ) ;
118
120
const git = new Git ( this . config , gitUrl , hash ) ;
119
121
await git . init ( ) ;
120
- await git . clone ( this . dest ) ;
122
+
123
+ const manifestFile = await git . getFile ( 'package.json' ) ;
124
+ if ( ! manifestFile ) {
125
+ throw new MessageError ( this . reporter . lang ( 'couldntFindPackagejson' , gitUrl ) ) ;
126
+ }
127
+ const scripts = JSON . parse ( manifestFile ) . scripts ;
128
+ const hasPrepareScript = Boolean ( scripts && scripts . prepare ) ;
129
+
130
+ if ( hasPrepareScript ) {
131
+ await this . fetchFromInstallAndPack ( git ) ;
132
+ } else {
133
+ await this . fetchFromGitArchive ( git ) ;
134
+ }
135
+
136
+ return {
137
+ hash,
138
+ } ;
139
+ }
140
+
141
+ async fetchFromInstallAndPack ( git : Git ) : Promise < void > {
142
+ const prepareDirectory = this . config . getTemp (
143
+ `${ crypto . hash ( git . gitUrl . repository ) } .${ git . hash } .prepare` ) ;
144
+ await fsUtil . unlink ( prepareDirectory ) ;
145
+
146
+ await git . clone ( prepareDirectory ) ;
147
+
148
+ const [
149
+ prepareConfig ,
150
+ prepareLockFile ,
151
+ ] = await Promise . all ( [
152
+ Config . create ( {
153
+ cwd : prepareDirectory ,
154
+ gitDependency : true ,
155
+ } , this . reporter ) ,
156
+ Lockfile . fromDirectory ( prepareDirectory , this . reporter ) ,
157
+ ] ) ;
158
+ await install ( prepareConfig , this . reporter , { } , prepareLockFile ) ;
121
159
122
160
const tarballMirrorPath = this . getTarballMirrorPath ( ) ;
123
161
const tarballCachePath = this . getTarballCachePath ( ) ;
124
162
163
+ if ( tarballMirrorPath ) {
164
+ await this . _packToTarball ( prepareConfig , tarballMirrorPath ) ;
165
+ }
166
+ if ( tarballCachePath ) {
167
+ await this . _packToTarball ( prepareConfig , tarballCachePath ) ;
168
+ }
169
+
170
+ await this . _packToDirectory ( prepareConfig , this . dest ) ;
171
+
172
+ await fsUtil . unlink ( prepareDirectory ) ;
173
+ }
174
+
175
+ async _packToTarball ( config : Config , path : string ) : Promise < void > {
176
+ const tarballStream = await this . _createTarballStream ( config ) ;
177
+ await new Promise ( ( resolve , reject ) => {
178
+ const writeStream = fs . createWriteStream ( path ) ;
179
+ tarballStream . on ( 'error' , reject ) ;
180
+ writeStream . on ( 'error' , reject ) ;
181
+ writeStream . on ( 'end' , resolve ) ;
182
+ writeStream . on ( 'open' , ( ) => {
183
+ tarballStream . pipe ( writeStream ) ;
184
+ } ) ;
185
+ writeStream . once ( 'finish' , resolve ) ;
186
+ } ) ;
187
+ }
188
+
189
+ async _packToDirectory ( config : Config , dest : string ) : Promise < void > {
190
+ const tarballStream = await this . _createTarballStream ( config ) ;
191
+ await new Promise ( ( resolve , reject ) => {
192
+ const untarStream = this . _createUntarStream ( dest ) ;
193
+ tarballStream . on ( 'error' , reject ) ;
194
+ untarStream . on ( 'error' , reject ) ;
195
+ untarStream . on ( 'end' , resolve ) ;
196
+ untarStream . once ( 'finish' , resolve ) ;
197
+ tarballStream . pipe ( untarStream ) ;
198
+ } ) ;
199
+ }
200
+
201
+ _createTarballStream ( config : Config ) : Promise < stream$Duplex > {
202
+ let savedPackedHeader = false ;
203
+ return packTarball ( config , {
204
+ mapHeader ( header : Object ) : Object {
205
+ if ( ! savedPackedHeader ) {
206
+ savedPackedHeader = true ;
207
+ header . pax = header . pax || { } ;
208
+ // add a custom data on the first header
209
+ // in order to distinguish a tar from "git archive" and a tar from "pack" command
210
+ header . pax . packed = PACKED_FLAG ;
211
+ }
212
+ return header ;
213
+ } ,
214
+ } ) ;
215
+ }
216
+
217
+ _createUntarStream ( dest : string ) : stream$Writable {
218
+ const PREFIX = 'package/' ;
219
+ let isPackedTarball = undefined ;
220
+ return tarFs . extract ( dest , {
221
+ dmode : 0o555 , // all dirs should be readable
222
+ fmode : 0o444 , // all files should be readable
223
+ chown : false , // don't chown. just leave as it is
224
+ map : header => {
225
+ if ( isPackedTarball === undefined ) {
226
+ isPackedTarball = header . pax && header . pax . packed === PACKED_FLAG ;
227
+ }
228
+ if ( isPackedTarball ) {
229
+ header . name = header . name . substr ( PREFIX . length ) ;
230
+ }
231
+ } ,
232
+ } ) ;
233
+ }
234
+
235
+ async fetchFromGitArchive ( git : Git ) : Promise < void > {
236
+ await git . clone ( this . dest ) ;
237
+ const tarballMirrorPath = this . getTarballMirrorPath ( ) ;
238
+ const tarballCachePath = this . getTarballCachePath ( ) ;
239
+
125
240
if ( tarballMirrorPath ) {
126
241
await git . archive ( tarballMirrorPath ) ;
127
242
}
128
243
129
244
if ( tarballCachePath ) {
130
245
await git . archive ( tarballCachePath ) ;
131
246
}
132
-
133
- return {
134
- hash,
135
- } ;
136
247
}
137
248
138
249
async _fetch ( ) : Promise < FetchedOverride > {
0 commit comments