xref: /expo/tools/src/vendoring/devmenu/steps/Clone.ts (revision a272999e)
1import spawnAsync from '@expo/spawn-async';
2import chalk from 'chalk';
3import fs from 'fs-extra';
4
5import { Task } from './Task';
6
7type CloneSettings =
8  | {
9      branch: string;
10    }
11  | {
12      tag: string;
13    }
14  | {
15      commit: string;
16    }
17  | object;
18
19export type CloneRepoSettings = {
20  url: string;
21  destination?: string;
22} & CloneSettings;
23
24/**
25 * A task which will clone repository into the provided destination or into the working directory.
26 */
27export class Clone extends Task {
28  private readonly url: string;
29  private readonly options: CloneSettings;
30  private destination?: string;
31
32  constructor({ url, destination, ...options }: CloneRepoSettings) {
33    super();
34    this.url = url;
35    this.destination = destination;
36    this.options = options;
37  }
38
39  protected overrideWorkingDirectory(): string {
40    return this.destination || '<workingDirectory>';
41  }
42
43  async execute() {
44    const workDirectory = this.getWorkingDirectory();
45
46    this.logSubStep(`�� remove ${chalk.yellow(this.overrideWorkingDirectory())}`);
47    await fs.remove(workDirectory);
48
49    this.logSubStep(
50      `�� clone repo ${chalk.green(this.url)} into ${chalk.yellow(this.overrideWorkingDirectory())}`
51    );
52
53    const cloneArguments = this.cloneArguments();
54    this.logDebugInfo(`run git clone ${cloneArguments.join(' ')}`);
55    await spawnAsync('git', ['clone', ...cloneArguments, this.url, workDirectory]);
56
57    if ('commit' in this.options) {
58      this.logDebugInfo(`run git checkout ${this.options.commit}`);
59      await spawnAsync('git', ['checkout', this.options.commit], { cwd: workDirectory });
60    }
61  }
62
63  cloneArguments(): string[] {
64    // if a branch or tag was provided, we don't need to clone the whole repo.
65    const args = ['--depth', '1'];
66    if ('branch' in this.options) {
67      args.push('--branch', this.options.branch);
68    } else if ('tag' in this.options) {
69      args.push('--branch', this.options.tag);
70    } else if ('commit' in this.options) {
71      return [];
72    }
73    return args;
74  }
75}
76