| 363 | } |
| 364 | |
| 365 | static async downloadIncludeProjectFile (opts: ParserIncludesInitOptions, project: string, ref: string, file: string): Promise<void> { |
| 366 | const {cwd, stateDir, gitData, fetchIncludes, writeStreams} = opts; |
| 367 | const remote = gitData.remote; |
| 368 | const normalizedFile = file.replace(/^\/+/, ""); |
| 369 | let tmpDir = null; |
| 370 | try { |
| 371 | const target = `${stateDir}/includes/${remote.host}/${project}/${ref}`; |
| 372 | if (await fs.pathExists(`${cwd}/${target}/${normalizedFile}`) && !fetchIncludes) return; |
| 373 | const time = process.hrtime(); |
| 374 | |
| 375 | if (remote.schema.startsWith("http")) { |
| 376 | const ext = "tmp-" + Math.random(); |
| 377 | await fs.mkdirp(path.dirname(`${cwd}/${target}/${normalizedFile}`)); |
| 378 | tmpDir = `${cwd}/${target}.${ext}`; |
| 379 | |
| 380 | const gitCloneBranch = (ref === "HEAD") ? "" : `--branch ${ref}`; |
| 381 | await Utils.bashMulti([ |
| 382 | `cd ${cwd}/${stateDir}`, |
| 383 | `git clone ${gitCloneBranch} -n --depth=1 --filter=tree:0 ${remote.schema}://${remote.host}:${remote.port}/${project}.git ${tmpDir}`, |
| 384 | `cd ${tmpDir}`, |
| 385 | `git sparse-checkout set --no-cone ${normalizedFile}`, |
| 386 | "git checkout", |
| 387 | `cd ${cwd}/${stateDir}`, |
| 388 | `cp ${tmpDir}/${normalizedFile} ${cwd}/${target}/${normalizedFile}`, |
| 389 | ], cwd); |
| 390 | } else { |
| 391 | await fs.mkdirp(`${cwd}/${target}`); |
| 392 | await Utils.bash(`set -eou pipefail; git archive --remote=ssh://git@${remote.host}:${remote.port}/${project}.git ${ref} ${normalizedFile} | tar -f - -xC ${target}/`, cwd); |
| 393 | } |
| 394 | writeStreams.stderr(chalk`{grey downloaded ${project} ${ref} ${normalizedFile} in ${prettyHrtime(process.hrtime(time))}}\n`); |
| 395 | } catch (e) { |
| 396 | throw new AssertionError({message: `Project include could not be fetched { project: ${project}, ref: ${ref}, file: ${normalizedFile} }\n${e}`}); |
| 397 | } finally { |
| 398 | if (tmpDir !== null) { |
| 399 | // always cleanup temporary directory (if created) |
| 400 | await fs.rm(tmpDir, {recursive: true, force: true}); |
| 401 | } |
| 402 | } |
| 403 | } |
| 404 | |
| 405 | static async downloadIncludeComponent (opts: ParserIncludesInitOptions, project: string, ref: string, componentName: string): Promise<void> { |
| 406 | const {cwd, stateDir, gitData, fetchIncludes, writeStreams} = opts; |