1import chalk from 'chalk';
2import fs from 'fs-extra';
3import path from 'path';
4
5import { toRepoPath, findFiles } from '../utils';
6import { Task } from './Task';
7
8export type CopyFilesSettings = {
9  from?: string;
10  subDirectory?: string;
11  filePattern: string | string[];
12  to: string;
13};
14
15/**
16 *  A task which will copy files from `workingDirectory()/subDirectory/filePatterns` to the provided path.
17 *
18 * It's searching for file names which match `filePatterns` and then it copies them into `to/<matched_part_of_file_name>`.
19 * So the `subDirectory` part won't be copied.
20 *
21 * If for this file structure:
22 *
23 * ```
24 * android/
25 *   src/
26 *     main.java
27 *   lib/
28 *     lib.java
29 * ```
30 *
31 * you runs CopyFiles with:
32 * ```
33 * {
34 *   from: 'android',
35 *   subDirectory: 'src|lib',
36 *   to: 'copied',
37 *   filePatterns: '*'
38 * }
39 * ```
40 * you gets:
41 * ```
42 * android/
43 *   src/
44 *     main.java
45 *   lib/
46 *     lib.java
47 * lib/
48 *   main.java
49 *   lib.java
50 * ```
51 */
52export class CopyFiles extends Task {
53  private from?: string;
54  private subDirectory?: string;
55  private readonly filePattern: string[];
56  private readonly to: string;
57
58  /**
59   * Using `from` key, you can override the work directory.
60   * @param settings
61   */
62  constructor({ from, subDirectory, filePattern, to }: CopyFilesSettings) {
63    super();
64    this.from = from;
65    this.subDirectory = subDirectory;
66    this.to = toRepoPath(to);
67    if (typeof filePattern === 'string') {
68      this.filePattern = [filePattern];
69    } else {
70      this.filePattern = filePattern;
71    }
72  }
73
74  protected overrideWorkingDirectory(): string {
75    return this.from || '<workingDirectory>';
76  }
77
78  async execute() {
79    const workDirectory = this.getWorkingDirectory();
80
81    for (const pattern of this.filePattern) {
82      const subPath = this.subDirectory
83        ? path.join(workDirectory, this.subDirectory)
84        : workDirectory;
85
86      this.logSubStep(
87        `�� copy ${chalk.green(this.overrideWorkingDirectory())}/${chalk.green(
88          this.subDirectory ? this.subDirectory + '/' : ''
89        )}${chalk.yellow(pattern)} into ${chalk.magenta(this.to)}`
90      );
91
92      const files = await findFiles(subPath, pattern);
93      await Promise.all(
94        files.map(async (file) => {
95          const relativeFilePath = path.relative(subPath, file);
96          const destinationFullPath = path.join(this.to, relativeFilePath);
97
98          await fs.mkdirs(path.dirname(destinationFullPath));
99          return await fs.copy(file, destinationFullPath);
100        })
101      );
102    }
103  }
104}
105