UNPKG

8.56 kBJavaScriptView Raw
1const path = require("path");
2const chalk = require("chalk");
3const fs = require("fs");
4const mm = require("micromatch");
5const requireFromString = require("require-from-string");
6const logger = require("./logger");
7const readMaidFile = require("./readMaidFile");
8const MaidError = require("./MaidError");
9const runCLICommand = require("./runCLICommand");
10const inquirer = require("inquirer");
11const moment = require("moment");
12const getColonTimeFromDate = () => new Date().toTimeString().slice(0, 8);
13const secretFilePath = path.join(process.cwd(), "./.secret.json");
14// const spawn = require('cross-spawn')
15let secretFile = { tasks: [] };
16let taskListSorted = [];
17
18if (fs.existsSync(secretFilePath)) {
19 secretFile = require(secretFilePath);
20 taskListSorted = secretFile.tasks
21 .sort((a, b) => (a.time > b.time ? 1 : b.time > a.time ? -1 : 0))
22 .reverse()
23 .slice(0, 3)
24 .map(e => {
25 if (e.task === undefined) {
26 return e;
27 }
28
29 let taskItem = e.task.split(" ")[0];
30 taskItem += "\t~\t" + moment(e.time).calendar() + "";
31 return taskItem;
32 });
33} else {
34 fs.writeFileSync(secretFilePath, JSON.stringify(secretFile), "utf8");
35}
36class FcScripts {
37 constructor(opts = {}) {
38 // logger.clear();
39 // logger.setOptions({ quiet: opts.quiet });
40 return this.loadAsync(opts);
41 }
42
43 async loadAsync(opts) {
44 this.maidfile = await readMaidFile(opts.section);
45 if (!this.maidfile) {
46 throw new MaidError("No maidfile was found. Stop.");
47 }
48 return this;
49 }
50
51 async runTasks(taskNames, inParallel) {
52 if (!taskNames || taskNames.length === 0) return;
53
54 if (inParallel) {
55 await Promise.all(
56 taskNames.map(taskName => {
57 return this.runTask(taskName);
58 })
59 );
60 } else {
61 for (const taskName of taskNames) {
62 await this.runTask(taskName);
63 }
64 }
65 }
66
67 async runFile(taskName) {
68 await this.runTask("beforeAll", false);
69 await this.runTask(taskName);
70 await this.runTask("afterAll", false);
71 }
72
73 async runTask(taskName, throwWhenNoMatchedTask = true) {
74 const task =
75 taskName && this.maidfile && this.maidfile.tasks.find(task => task.name === taskName);
76
77 if (!task) {
78 if (throwWhenNoMatchedTask) {
79 throw new MaidError(`No task called "${taskName}" was found. Stop.`);
80 } else {
81 return;
82 }
83 }
84
85 await this.runTaskHooks(task, "before");
86
87 const start = Date.now();
88 logger.l("Starting", '"' + task.name + '..."');
89
90 for (const script of task.scripts) {
91 await this.runScript(script, task);
92 }
93 await this.runTaskHooks(task, "after");
94
95 logger.l("Finished", '"' + task.name + ` after ${Date.now() - start} ms`);
96 }
97
98 runScript(script, task) {
99 return new Promise((resolve, reject) => {
100 const handleError = err => {
101 throw new MaidError(`Task '${task.name}' failed.\n${err.stack}`);
102 };
103 if (checkTypes(script, ["sh", "bash"])) {
104 return runCLICommand({ script, task, resolve, reject });
105 }
106 if (checkTypes(script, ["py", "python"])) {
107 return runCLICommand({ type: "python", script, task, resolve, reject });
108 }
109 if (checkTypes(script, ["js", "javascript"])) {
110 let res;
111 try {
112 res = requireFromString(script.src, this.maidfile.filepath);
113 } catch (err) {
114 return handleError(err);
115 }
116 res = res.default || res;
117 return resolve(
118 typeof res === "function" ? Promise.resolve(res()).catch(handleError) : res
119 );
120 }
121
122 return resolve();
123 });
124 }
125
126 async runTaskHooks(task, when) {
127 const prefix = when === "before" ? "pre" : "post";
128 const tasks = this.maidfile.tasks.filter(({ name }) => {
129 return name === `${prefix}${task.name}`;
130 });
131 await this.runTasks(tasks.map(task => task.name));
132 for (const item of task[when]) {
133 const { taskNames, inParallel } = item;
134 await this.runTasks(taskNames, inParallel);
135 }
136 }
137
138 getHelp(patterns) {
139 patterns = [].concat(patterns);
140 const tasks =
141 patterns.length > 0
142 ? this.maidfile.tasks.filter(task => {
143 return mm.some(task.name, patterns);
144 })
145 : this.maidfile.tasks;
146
147 if (tasks.length === 0) {
148 throw new MaidError(`No tasks for pattern "${patterns.join(" ")}" was found. Stop.`);
149 }
150
151 logger.log(
152 `\n ${chalk.magenta.bold(
153 `Task${tasks.length > 1 ? "s" : ""} in ${path.relative(
154 process.cwd(),
155 this.maidfile.filepath
156 )}:`
157 )}\n\n` +
158 tasks
159 .map(
160 task =>
161 ` ${chalk.bold(task.name)}\n${chalk.dim(
162 task.description
163 ? task.description
164 .split("\n")
165 .map(v => ` ${v.trim()}`)
166 .join("\n")
167 : " No description"
168 )}`
169 )
170 .join("\n\n") +
171 "\n"
172 );
173 }
174
175 runList(patterns) {
176 let choiceCategories = [
177 ...taskListSorted,
178 ...["-------------"],
179 ...Object.keys(this.maidfile.catScripts)
180 ];
181 inquirer
182 .prompt([
183 {
184 type: "list",
185 name: "category",
186 message: "What category do you want to run?",
187 choices: choiceCategories
188 }
189 ])
190 .then(({ category }) => {
191 let sepInd = choiceCategories.indexOf("-------------");
192 let chosenInd = choiceCategories.indexOf(category);
193 if (sepInd === chosenInd) {
194 console.log("NOPE");
195 } else if (chosenInd < sepInd) {
196 console.log(" RUUNNNING", category);
197 let taskToRun = category.split("\t~\t")[0].trim();
198 updateTimeTask(taskToRun, { category: "" });
199 this.runTask(taskToRun);
200 } else {
201 let taskNames = this.maidfile.catScripts[category].map(
202 task =>
203 `${task.name} ${
204 task.desc ? "\t~\t" + task.desc.replace(/\n/g, " ").trim() : ""
205 }`
206 );
207 inquirer
208 .prompt([
209 {
210 type: "list",
211 name: "taskToRun",
212 message: "Which task do you want to run",
213 choices: taskNames
214 }
215 ])
216 .then(({ taskToRun }) => {
217 // taskToRun.split(" ")[0] ?
218 taskToRun = taskToRun.split("\t~\t")[0].trim();
219 updateTimeTask(taskToRun, category);
220 this.runTask(taskToRun);
221 });
222 }
223 });
224 }
225
226 getList() {
227 const tasks = this.maidfile.tasks;
228 }
229}
230
231function updateTimeTask(taskToRun, category) {
232 let taskIndex = secretFile.tasks.findIndex(e => e.task.split(" ")[0] === taskToRun);
233 if (taskIndex === -1) {
234 secretFile.tasks.push({
235 category,
236 task: taskToRun,
237 time: Date.now()
238 });
239 } else {
240 secretFile.tasks[taskIndex].time = Date.now();
241 }
242 fs.writeFileSync(secretFilePath, JSON.stringify(secretFile), "utf8");
243}
244
245function checkTypes(task, types) {
246 return types.some(type => type === task.type);
247}
248
249module.exports = opts => new FcScripts(opts);