1import execa = require('execa');
2import * as fs from 'fs';
3import chalk from 'chalk';
4import { useSpinner } from '../utils/useSpinner';
5import { Task, TaskRunner } from './task';
6
7const path = require('path');
8
9let distDir: string, cwd: string;
10
11const clean = () => useSpinner('Cleaning', () => execa('npm', ['run', 'clean']));
12
13const compile = () =>
14  useSpinner('Compiling sources', async () => {
15    try {
16      await execa('tsc', ['-p', './tsconfig.json']);
17    } catch (e) {
18      console.log(e);
19      throw e;
20    }
21  });
22
23const savePackage = ({ path, pkg }: { path: string; pkg: {} }) =>
24  useSpinner('Updating package.json', async () => {
25    new Promise<void>((resolve, reject) => {
26      fs.writeFile(path, JSON.stringify(pkg, null, 2), (err) => {
27        if (err) {
28          reject(err);
29          return;
30        }
31        resolve();
32      });
33    });
34  });
35
36const preparePackage = async (pkg: any) => {
37  pkg.bin = {
38    'grafana-toolkit': './bin/grafana-toolkit.js',
39  };
40
41  await savePackage({
42    path: `${cwd}/dist/package.json`,
43    pkg,
44  });
45};
46
47const copyFiles = () => {
48  const files = [
49    'README.md',
50    'CHANGELOG.md',
51    'config/circleci/config.yml',
52    'bin/grafana-toolkit.js',
53    'src/config/prettier.plugin.config.json',
54    'src/config/prettier.plugin.rc.js',
55    'src/config/tsconfig.plugin.json',
56    'src/config/tsconfig.plugin.local.json',
57    'src/config/eslint.plugin.js',
58    'src/config/styles.mock.js',
59    'src/config/jest.plugin.config.local.js',
60    'src/config/matchMedia.js',
61    'src/config/react-inlinesvg.tsx',
62  ];
63
64  return useSpinner(`Moving ${files.join(', ')} files`, async () => {
65    const promises = files.map((file) => {
66      return new Promise<void>((resolve, reject) => {
67        const basedir = path.dirname(`${distDir}/${file}`);
68        if (!fs.existsSync(basedir)) {
69          fs.mkdirSync(basedir, { recursive: true });
70        }
71        fs.copyFile(`${cwd}/${file}`, `${distDir}/${file}`, (err) => {
72          if (err) {
73            reject(err);
74            return;
75          }
76          resolve();
77        });
78      });
79    });
80
81    await Promise.all(promises);
82  });
83};
84
85const copySassFiles = () => {
86  const files = ['_variables.generated.scss', '_variables.dark.generated.scss', '_variables.light.generated.scss'];
87  return useSpinner(`Copy scss files ${files.join(', ')} files`, async () => {
88    const sassDir = path.resolve(cwd, '../../public/sass/');
89    const promises = files.map((file) => {
90      return new Promise<void>((resolve, reject) => {
91        const name = file.replace('.generated', '');
92        fs.copyFile(`${sassDir}/${file}`, `${distDir}/sass/${name}`, (err) => {
93          if (err) {
94            reject(err);
95            return;
96          }
97          resolve();
98        });
99      });
100    });
101
102    await Promise.all(promises);
103  });
104};
105
106interface ToolkitBuildOptions {}
107
108const toolkitBuildTaskRunner: TaskRunner<ToolkitBuildOptions> = async () => {
109  cwd = path.resolve(__dirname, '../../../');
110  distDir = `${cwd}/dist`;
111  const pkg = require(`${cwd}/package.json`);
112  console.log(chalk.yellow(`Building ${pkg.name} (package.json version: ${pkg.version})`));
113
114  await clean();
115  await compile();
116  await preparePackage(pkg);
117  fs.mkdirSync('./dist/bin');
118  fs.mkdirSync('./dist/sass');
119  await copyFiles();
120  await copySassFiles();
121};
122
123export const toolkitBuildTask = new Task<ToolkitBuildOptions>('@grafana/toolkit build', toolkitBuildTaskRunner);
124