1 | "use strict"
|
2 |
|
3 | const res = require("path").resolve
|
4 | const Promise = require("bluebird")
|
5 | const Emitter = require("events")
|
6 | const wrapp = require("./wrapp")
|
7 | const util = require("./utils")
|
8 | const Task = require("./task")
|
9 | const $ = require("./fn")
|
10 |
|
11 | const co = Promise.coroutine
|
12 |
|
13 | class Taskr extends Emitter {
|
14 | constructor(opts) {
|
15 | super()
|
16 |
|
17 | opts = opts || {}
|
18 |
|
19 | const file = opts.file
|
20 | const plugins = opts.plugins || []
|
21 | const tasks = opts.tasks || file && require(file) || {}
|
22 |
|
23 |
|
24 | if (!$.isObject(tasks)) {
|
25 | this.emit("tasks_force_object")
|
26 | return
|
27 | }
|
28 |
|
29 | this.file = file
|
30 | this.root = res(opts.cwd || ".")
|
31 |
|
32 |
|
33 | this.tasks = {}
|
34 | this.plugins = {}
|
35 | this.plugNames = []
|
36 |
|
37 | this.start = co(this.start).bind(this)
|
38 | this.serial = co(this.serial).bind(this)
|
39 | this.parallel = co(this.parallel).bind(this)
|
40 |
|
41 |
|
42 | if (!file && $.isEmptyObj(tasks)) {
|
43 | return
|
44 | }
|
45 |
|
46 | for (const k in tasks) {
|
47 | if (!(tasks[k].call)) continue
|
48 | this.tasks[k] = {
|
49 | data: {files: [], globs: [], prevs: []},
|
50 | func: co(tasks[k])
|
51 | }
|
52 | }
|
53 |
|
54 | let fn, i = 0
|
55 | for (; i < plugins.length; i++) {
|
56 | if (!plugins[i]) continue
|
57 | fn = plugins[i]
|
58 | if ($.isObject(fn)) {
|
59 | this.plugin(fn)
|
60 | } else if (fn.call) {
|
61 | fn.call(this, this, util)
|
62 | }
|
63 | }
|
64 | }
|
65 |
|
66 | plugin(name, opts, func) {
|
67 |
|
68 | if ($.isObject(name)) {
|
69 | opts = name
|
70 | name = opts.name
|
71 | }
|
72 |
|
73 | const nxt = $.valUniq(name, this.plugNames)
|
74 |
|
75 | if (nxt !== name) {
|
76 | this.emit("plugin_rename", name, nxt)
|
77 | }
|
78 |
|
79 | this.plugNames.push(nxt)
|
80 |
|
81 | this.plugins[nxt] = wrapp(opts, func)
|
82 | }
|
83 |
|
84 | *start(name, opts) {
|
85 | name = name || "default"
|
86 | opts = Object.assign({src: null, val: null}, opts)
|
87 |
|
88 | const task = this.tasks[name]
|
89 |
|
90 | if (!task) {
|
91 | return this.emit("task_not_found", name)
|
92 | }
|
93 |
|
94 |
|
95 | const old = task.data.prevs || []
|
96 |
|
97 | task.data = {files: [], globs: [], prevs: old}
|
98 |
|
99 | try {
|
100 |
|
101 | const start = process.hrtime()
|
102 |
|
103 | this.emit("task_start", name)
|
104 |
|
105 | const val = yield new Task(this).exec(task.func, opts, task.data)
|
106 |
|
107 | const end = process.hrtime(start)
|
108 | this.emit("task_complete", name, end)
|
109 |
|
110 | return val
|
111 | } catch (err) {
|
112 | this.emit("task_error", name, err.message)
|
113 | throw err
|
114 | }
|
115 | }
|
116 |
|
117 | *parallel(tasks, opts) {
|
118 | try {
|
119 | yield Promise.all(tasks.map(t => this.start(t, opts)))
|
120 | } catch (err) {
|
121 |
|
122 | }
|
123 | }
|
124 |
|
125 | *serial(tasks, opts) {
|
126 | opts = opts || {}
|
127 | try {
|
128 | return yield Promise.reduce(tasks, (val, str) => {
|
129 | val && Object.assign(opts, { val })
|
130 | return this.start(str, opts)
|
131 | }, opts.val || null)
|
132 | } catch (err) {
|
133 | this.emit("serial_error")
|
134 | }
|
135 | }
|
136 | }
|
137 |
|
138 | module.exports = Taskr
|