|
1 |
| -const fs=require("fs"); |
2 |
| -const path=require("path"); |
3 |
| -class CntEvent{ |
4 |
| - constructor(){ |
5 |
| - this.cnt=0; |
6 |
| - this.emptyEvent=[]; |
7 |
| - this.encount=this.encount.bind(this); |
8 |
| - this.decount=this.decount.bind(this); |
9 |
| - this.add=this.add.bind(this); |
10 |
| - } |
11 |
| - encount(delta=1){ |
12 |
| - this.cnt+=delta; |
13 |
| - } |
14 |
| - decount(){ |
15 |
| - if(this.cnt>0)--this.cnt; |
16 |
| - if(this.cnt==0){ |
17 |
| - for(let info of this.emptyEvent)info[0](...info[1]); |
18 |
| - this.emptyEvent=[]; |
19 |
| - } |
20 |
| - } |
21 |
| - add(cb,...attach){ |
22 |
| - this.emptyEvent.push([cb,attach]); |
23 |
| - } |
24 |
| - check(cb,...attach){ |
25 |
| - if(this.cnt==0)cb(...attach); |
26 |
| - else this.add(cb,...attach); |
27 |
| - } |
28 |
| -} |
29 |
| -class LimitedRunner{ |
30 |
| - constructor(limit){ |
31 |
| - this.limit=limit; |
32 |
| - this.cnt=0; |
33 |
| - this.funcs=[]; |
34 |
| - } |
35 |
| - run(func){ |
36 |
| - if(this.cnt<this.limit){ |
37 |
| - this.cnt++; |
38 |
| - setTimeout(func,0); |
39 |
| - }else{ |
40 |
| - this.funcs.push(func); |
41 |
| - } |
42 |
| - } |
43 |
| - done(){ |
44 |
| - if(this.cnt>0)this.cnt--; |
45 |
| - if(this.funcs.length>0){ |
46 |
| - this.cnt++; |
47 |
| - setTimeout(this.funcs.shift(),0); |
48 |
| - } |
49 |
| - } |
50 |
| - runWithCb(func,...args){ |
51 |
| - let cb=args.pop(),self=this; |
52 |
| - function agent(...args){ |
53 |
| - self.done(); |
54 |
| - return cb.apply(this,args); |
55 |
| - } |
56 |
| - args.push(agent); |
57 |
| - this.run(()=>func(...args)); |
58 |
| - } |
59 |
| -} |
60 |
| -let ioEvent=new CntEvent; |
61 |
| -let ioLimit=new LimitedRunner(4096); |
62 |
| -function mkdirs(dir,cb){ |
63 |
| - ioLimit.runWithCb(fs.stat.bind(fs),dir,(err,stats)=>{ |
64 |
| - if(err)mkdirs(path.dirname(dir),()=>fs.mkdir(dir,cb)); |
65 |
| - else if(stats.isFile())throw Error(dir+" was created as a file, so we cannot put file into it."); |
66 |
| - else cb(); |
67 |
| - }); |
68 |
| -} |
69 |
| -function save(name,content){ |
70 |
| - ioEvent.encount(); |
71 |
| - mkdirs(path.dirname(name),()=>ioLimit.runWithCb(fs.writeFile.bind(fs),name,content,err=>{ |
72 |
| - if(err)throw Error("Save file error: "+err); |
73 |
| - ioEvent.decount(); |
74 |
| - })); |
75 |
| -} |
76 |
| -function get(name,cb,opt={encoding:'utf8'}){ |
77 |
| - ioEvent.encount(); |
78 |
| - ioLimit.runWithCb(fs.readFile.bind(fs),name,opt,(err,data)=>{ |
79 |
| - if(err)throw Error("Read file error: "+err); |
80 |
| - else cb(data); |
81 |
| - ioEvent.decount(); |
82 |
| - }); |
83 |
| -} |
84 |
| -function del(name){ |
85 |
| - ioEvent.encount(); |
86 |
| - ioLimit.runWithCb(fs.unlink.bind(fs),name,ioEvent.decount); |
87 |
| -} |
88 |
| -function changeExt(name,ext=""){ |
89 |
| - return name.slice(0,name.lastIndexOf("."))+ext; |
90 |
| -} |
91 |
| -function scanDirByExt(dir,ext,cb){ |
92 |
| - let result=[],scanEvent=new CntEvent; |
93 |
| - function helper(dir){ |
94 |
| - scanEvent.encount(); |
95 |
| - ioLimit.runWithCb(fs.readdir.bind(fs),dir,(err,files)=>{ |
96 |
| - if(err)throw Error("Scan dir error: "+err); |
97 |
| - for(let file of files){ |
98 |
| - scanEvent.encount(); |
99 |
| - let name=path.resolve(dir,file); |
100 |
| - fs.stat(name,(err,stats)=>{ |
101 |
| - if(err)throw Error("Scan dir error: "+err); |
102 |
| - if(stats.isDirectory())helper(name); |
103 |
| - else if(stats.isFile()&&name.endsWith(ext))result.push(name); |
104 |
| - scanEvent.decount(); |
105 |
| - }); |
106 |
| - } |
107 |
| - scanEvent.decount(); |
108 |
| - }); |
109 |
| - } |
110 |
| - scanEvent.add(cb,result); |
111 |
| - helper(dir,ext,scanEvent); |
112 |
| -} |
113 |
| -function toDir(to,from){//get relative path without posix/win32 problem |
114 |
| - if(from[0]==".")from=from.slice(1); |
115 |
| - if(to[0]==".")to=to.slice(1); |
116 |
| - from=from.replace(/\\/g,'/');to=to.replace(/\\/g,'/'); |
117 |
| - let a=Math.min(to.length,from.length); |
118 |
| - for(let i=1,m=Math.min(to.length,from.length);i<=m;i++)if(!to.startsWith(from.slice(0,i))){a=i-1;break;} |
119 |
| - let pub=from.slice(0,a); |
120 |
| - let len=pub.lastIndexOf("/")+1; |
121 |
| - let k=from.slice(len); |
122 |
| - let ret=""; |
123 |
| - for(let i=0;i<k.length;i++)if(k[i]=='/')ret+='../'; |
124 |
| - return ret+to.slice(len); |
125 |
| -} |
126 |
| -function commonDir(pathA,pathB){ |
127 |
| - if(pathA[0]==".")pathA=pathA.slice(1); |
128 |
| - if(pathB[0]==".")pathB=pathB.slice(1); |
129 |
| - pathA=pathA.replace(/\\/g,'/');pathB=pathB.replace(/\\/g,'/'); |
130 |
| - let a=Math.min(pathA.length,pathB.length); |
131 |
| - for(let i=1,m=Math.min(pathA.length,pathB.length);i<=m;i++)if(!pathA.startsWith(pathB.slice(0,i))){a=i-1;break;} |
132 |
| - let pub=pathB.slice(0,a); |
133 |
| - let len=pub.lastIndexOf("/")+1; |
134 |
| - return pathA.slice(0,len); |
135 |
| -} |
136 |
| -function commandExecute(cb,helper){ |
137 |
| - console.time("Total use"); |
138 |
| - function endTime(){ |
139 |
| - ioEvent.check(()=>console.timeEnd("Total use")); |
140 |
| - } |
141 |
| - let orders=[]; |
142 |
| - for(let order of process.argv)if(order.startsWith("-"))orders.push(order.slice(1)); |
143 |
| - let iter=process.argv[Symbol.iterator](),nxt=iter.next(),called=false,faster=orders.includes("f"),fastCnt; |
144 |
| - if(faster){ |
145 |
| - fastCnt=new CntEvent; |
146 |
| - fastCnt.add(endTime); |
147 |
| - } |
148 |
| - function doNext(){ |
149 |
| - let nxt=iter.next(); |
150 |
| - while(!nxt.done&&nxt.value.startsWith("-"))nxt=iter.next(); |
151 |
| - if(nxt.done){ |
152 |
| - if(!called)console.log("Command Line Helper:\n\n"+helper); |
153 |
| - else if(!faster)endTime(); |
154 |
| - }else{ |
155 |
| - called=true; |
156 |
| - if(faster)fastCnt.encount(),cb(nxt.value,fastCnt.decount,orders),doNext(); |
157 |
| - else cb(nxt.value,doNext,orders); |
158 |
| - } |
159 |
| - } |
160 |
| - while(!nxt.done&&!nxt.value.endsWith(".js"))nxt=iter.next(); |
161 |
| - doNext(); |
162 |
| -} |
163 |
| -module.exports={mkdirs:mkdirs,get:get,save:save,toDir:toDir,del:del,addIO:ioEvent.add, |
164 |
| - changeExt:changeExt,CntEvent:CntEvent,scanDirByExt:scanDirByExt,commonDir:commonDir, |
165 |
| - commandExecute:commandExecute}; |
| 1 | +const fs = require("fs"); |
| 2 | +const path = require("path"); |
| 3 | + |
| 4 | +class CntEvent { |
| 5 | + constructor() { |
| 6 | + this.cnt = 0; |
| 7 | + this.emptyEvent = []; |
| 8 | + this.encount = this.encount.bind(this); |
| 9 | + this.decount = this.decount.bind(this); |
| 10 | + this.add = this.add.bind(this); |
| 11 | + } |
| 12 | + |
| 13 | + encount(delta = 1) { |
| 14 | + this.cnt += delta; |
| 15 | + } |
| 16 | + |
| 17 | + decount() { |
| 18 | + if (this.cnt > 0) --this.cnt; |
| 19 | + if (this.cnt == 0) { |
| 20 | + for (let info of this.emptyEvent) info[0](...info[1]); |
| 21 | + this.emptyEvent = []; |
| 22 | + } |
| 23 | + } |
| 24 | + |
| 25 | + add(cb, ...attach) { |
| 26 | + this.emptyEvent.push([cb, attach]); |
| 27 | + } |
| 28 | + |
| 29 | + check(cb, ...attach) { |
| 30 | + if (this.cnt == 0) cb(...attach); |
| 31 | + else this.add(cb, ...attach); |
| 32 | + } |
| 33 | +} |
| 34 | + |
| 35 | +class LimitedRunner { |
| 36 | + constructor(limit) { |
| 37 | + this.limit = limit; |
| 38 | + this.cnt = 0; |
| 39 | + this.funcs = []; |
| 40 | + } |
| 41 | + |
| 42 | + run(func) { |
| 43 | + if (this.cnt < this.limit) { |
| 44 | + this.cnt++; |
| 45 | + setTimeout(func, 0); |
| 46 | + } else { |
| 47 | + this.funcs.push(func); |
| 48 | + } |
| 49 | + } |
| 50 | + |
| 51 | + done() { |
| 52 | + if (this.cnt > 0) this.cnt--; |
| 53 | + if (this.funcs.length > 0) { |
| 54 | + this.cnt++; |
| 55 | + setTimeout(this.funcs.shift(), 0); |
| 56 | + } |
| 57 | + } |
| 58 | + |
| 59 | + runWithCb(func, ...args) { |
| 60 | + let cb = args.pop(), self = this; |
| 61 | + |
| 62 | + function agent(...args) { |
| 63 | + self.done(); |
| 64 | + return cb.apply(this, args); |
| 65 | + } |
| 66 | + |
| 67 | + args.push(agent); |
| 68 | + this.run(() => func(...args)); |
| 69 | + } |
| 70 | +} |
| 71 | + |
| 72 | +let ioEvent = new CntEvent; |
| 73 | +let ioLimit = new LimitedRunner(4096); |
| 74 | + |
| 75 | +function mkdirs(dir, cb) { |
| 76 | + ioLimit.runWithCb(fs.stat.bind(fs), dir, (err, stats) => { |
| 77 | + if (err) mkdirs(path.dirname(dir), () => fs.mkdir(dir, cb)); |
| 78 | + else if (stats.isFile()) throw Error(dir + " was created as a file, so we cannot put file into it."); |
| 79 | + else cb(); |
| 80 | + }); |
| 81 | +} |
| 82 | + |
| 83 | +function save(name, content) { |
| 84 | + ioEvent.encount(); |
| 85 | + mkdirs(path.dirname(name), () => ioLimit.runWithCb(fs.writeFile.bind(fs), name, content, err => { |
| 86 | + if (err) throw Error("Save file error: " + err); |
| 87 | + ioEvent.decount(); |
| 88 | + })); |
| 89 | +} |
| 90 | + |
| 91 | +function get(name, cb, opt = {encoding: 'utf8'}) { |
| 92 | + ioEvent.encount(); |
| 93 | + ioLimit.runWithCb(fs.readFile.bind(fs), name, opt, (err, data) => { |
| 94 | + if (err) throw Error("Read file error: " + err); |
| 95 | + else cb(data); |
| 96 | + ioEvent.decount(); |
| 97 | + }); |
| 98 | +} |
| 99 | + |
| 100 | +function del(name) { |
| 101 | + ioEvent.encount(); |
| 102 | + ioLimit.runWithCb(fs.unlink.bind(fs), name, ioEvent.decount); |
| 103 | +} |
| 104 | + |
| 105 | +function changeExt(name, ext = "") { |
| 106 | + return name.slice(0, name.lastIndexOf(".")) + ext; |
| 107 | +} |
| 108 | + |
| 109 | +function scanDirByExt(dir, ext, cb) { |
| 110 | + let result = [], scanEvent = new CntEvent; |
| 111 | + |
| 112 | + function helper(dir) { |
| 113 | + scanEvent.encount(); |
| 114 | + ioLimit.runWithCb(fs.readdir.bind(fs), dir, (err, files) => { |
| 115 | + if (err) throw Error("Scan dir error: " + err); |
| 116 | + for (let file of files) { |
| 117 | + scanEvent.encount(); |
| 118 | + let name = path.resolve(dir, file); |
| 119 | + fs.stat(name, (err, stats) => { |
| 120 | + if (err) throw Error("Scan dir error: " + err); |
| 121 | + if (stats.isDirectory()) helper(name); |
| 122 | + else if (stats.isFile() && name.endsWith(ext)) result.push(name); |
| 123 | + scanEvent.decount(); |
| 124 | + }); |
| 125 | + } |
| 126 | + scanEvent.decount(); |
| 127 | + }); |
| 128 | + } |
| 129 | + |
| 130 | + scanEvent.add(cb, result); |
| 131 | + helper(dir, ext, scanEvent); |
| 132 | +} |
| 133 | + |
| 134 | +function toDir(to, from) {//get relative path without posix/win32 problem |
| 135 | + if (from[0] == ".") from = from.slice(1); |
| 136 | + if (to[0] == ".") to = to.slice(1); |
| 137 | + from = from.replace(/\\/g, '/'); |
| 138 | + to = to.replace(/\\/g, '/'); |
| 139 | + let a = Math.min(to.length, from.length); |
| 140 | + for (let i = 1, m = Math.min(to.length, from.length); i <= m; i++) if (!to.startsWith(from.slice(0, i))) { |
| 141 | + a = i - 1; |
| 142 | + break; |
| 143 | + } |
| 144 | + let pub = from.slice(0, a); |
| 145 | + let len = pub.lastIndexOf("/") + 1; |
| 146 | + let k = from.slice(len); |
| 147 | + let ret = ""; |
| 148 | + for (let i = 0; i < k.length; i++) if (k[i] == '/') ret += '../'; |
| 149 | + return ret + to.slice(len); |
| 150 | +} |
| 151 | + |
| 152 | +function commonDir(pathA, pathB) { |
| 153 | + if (pathA[0] == ".") pathA = pathA.slice(1); |
| 154 | + if (pathB[0] == ".") pathB = pathB.slice(1); |
| 155 | + pathA = pathA.replace(/\\/g, '/'); |
| 156 | + pathB = pathB.replace(/\\/g, '/'); |
| 157 | + let a = Math.min(pathA.length, pathB.length); |
| 158 | + for (let i = 1, m = Math.min(pathA.length, pathB.length); i <= m; i++) if (!pathA.startsWith(pathB.slice(0, i))) { |
| 159 | + a = i - 1; |
| 160 | + break; |
| 161 | + } |
| 162 | + let pub = pathB.slice(0, a); |
| 163 | + let len = pub.lastIndexOf("/") + 1; |
| 164 | + return pathA.slice(0, len); |
| 165 | +} |
| 166 | + |
| 167 | +function commandExecute(cb, helper) { |
| 168 | + console.time("Total use"); |
| 169 | + |
| 170 | + function endTime() { |
| 171 | + ioEvent.check(() => console.timeEnd("Total use")); |
| 172 | + } |
| 173 | + |
| 174 | + let orders = []; |
| 175 | + for (let order of process.argv) if (order.startsWith("-")) orders.push(order.slice(1)); |
| 176 | + let iter = process.argv[Symbol.iterator](), nxt = iter.next(), called = false, faster = orders.includes("f"), |
| 177 | + fastCnt; |
| 178 | + if (faster) { |
| 179 | + fastCnt = new CntEvent; |
| 180 | + fastCnt.add(endTime); |
| 181 | + } |
| 182 | + |
| 183 | + function doNext() { |
| 184 | + let nxt = iter.next(); |
| 185 | + while (!nxt.done && nxt.value.startsWith("-")) nxt = iter.next(); |
| 186 | + if (nxt.done) { |
| 187 | + if (!called) console.log("Command Line Helper:\n\n" + helper); |
| 188 | + else if (!faster) endTime(); |
| 189 | + } else { |
| 190 | + called = true; |
| 191 | + if (faster) fastCnt.encount(), cb(nxt.value, fastCnt.decount, orders), doNext(); |
| 192 | + else cb(nxt.value, doNext, orders); |
| 193 | + } |
| 194 | + } |
| 195 | + |
| 196 | + while (!nxt.done && !nxt.value.endsWith(".js")) nxt = iter.next(); |
| 197 | + doNext(); |
| 198 | +} |
| 199 | + |
| 200 | +module.exports = { |
| 201 | + mkdirs: mkdirs, get: get, save: save, toDir: toDir, del: del, addIO: ioEvent.add, |
| 202 | + changeExt: changeExt, CntEvent: CntEvent, scanDirByExt: scanDirByExt, commonDir: commonDir, |
| 203 | + commandExecute: commandExecute |
| 204 | +}; |
0 commit comments