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