hint.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425
  1. #!/usr/bin/python
  2. #encoding=utf-8
  3. import sys,os
  4. import ConfigParser
  5. import commands
  6. import time
  7. import codecs
  8. htmlMap = {}
  9. def processHtml(filename):
  10. f = open(filename,"r")
  11. if f is None:
  12. raise Exception('open %s error!' % (filename))
  13. newName = os.sep.join(os.path.abspath(__file__).split(os.sep)[:-1]) + os.sep + "core" + os.sep + "data"+os.sep+os.path.basename(filename) + "." + str(time.time())
  14. #print newName
  15. tmp = ""
  16. flag=False
  17. orig_num = 0
  18. new_num = 0
  19. for ln in f:
  20. orig_num += 1
  21. if ln.find("<script type=\"text/javascript\">") != -1 and ln.find("</script>") == -1:
  22. flag=True
  23. continue
  24. if ln.find("<script type=\"text/javascript\">") != -1 and ln.find("</script>") != -1:
  25. flag=False
  26. continue
  27. if ln.find("<script>") != -1 and ln.find("</script>") == -1:
  28. flag=True
  29. continue
  30. if ln.find("<script>") != -1 and ln.find("</script>") != -1:
  31. flag=False
  32. continue
  33. if ln.find("</script>") != -1:
  34. flag=False
  35. continue
  36. if flag == True:
  37. tmp += ln
  38. new_num += 1
  39. htmlMap[filename+os.sep+str(orig_num)]=newName + os.sep + str(new_num)
  40. if tmp == "":
  41. print ('[WARNING]file %s not contain js code' % (filename))
  42. return ""
  43. outfile = open(newName,"w")
  44. if outfile is None:
  45. raise Exception('open %s error!' % (newName))
  46. outfile.write(tmp)
  47. #print htmlMap
  48. return newName
  49. def clearTmpFiles():
  50. dels=[]
  51. for key in htmlMap.keys():
  52. fn = os.sep.join(htmlMap[key].split(os.sep)[:-1])
  53. if not fn in dels:
  54. dels.append(fn)
  55. #print dels
  56. for item in dels:
  57. os.remove(item)
  58. def isHiddenFile(path):
  59. itms = path.split(os.sep)
  60. for itm in itms:
  61. if itm != "" and itm != "." and itm != ".." and itm[0]==".":
  62. return True
  63. return False
  64. '''
  65. @input
  66. a file (or a top dir) to be checked
  67. @process
  68. recuresively read all the files of a dir.only support .html and .js.
  69. if it is a html file then we only check the code between <script></script>
  70. if it is a js file then we check all the code
  71. @return
  72. file(or folder) to be checked
  73. '''
  74. def getFiles(paths):
  75. #print paths
  76. ret = []
  77. omitpath = os.path.dirname(__file__) + os.sep + "conf" + os.sep + "omitfiles.conf"
  78. for path in paths:
  79. path = path.rstrip(os.sep)
  80. if not os.path.isdir(path):
  81. omitfiles = getOmitedFiles(omitpath,os.sep.join(path.split(os.sep)[:-1])+os.sep)
  82. if (os.path.getsize(path)==0) or (path in omitfiles):
  83. continue
  84. if path.find(".js") != -1 and isHiddenFile(path)==False:
  85. ret.append(path)
  86. elif path.find(".html") != -1 and isHiddenFile(path)==False:
  87. np = processHtml(path)
  88. if np != "":
  89. ret.append(np)
  90. else:
  91. omitfiles = getOmitedFiles(omitpath,path)
  92. for root, dirs, files in os.walk(path):
  93. for f in files:
  94. if (os.path.getsize(root + os.sep + f)==0) or ((root + os.sep + f) in omitfiles):
  95. continue
  96. if f.find(".js") != -1 and isHiddenFile(root + os.sep + f) == False:
  97. ret.append(root + os.sep + f)
  98. elif f.find(".html") != -1 and isHiddenFile(root + os.sep + f) == False:
  99. np=processHtml(root + os.sep + f)
  100. if np != "":
  101. ret.append(np)
  102. else:
  103. continue
  104. return ret
  105. def getopt(path):
  106. _opt=[]
  107. _predef=[]
  108. conf = ConfigParser.ConfigParser()
  109. conf.read(path)
  110. for item in conf.options('option'):
  111. _opt.append("%s=%s"%(item,conf.get('option',item)))
  112. for item in conf.options('predef'):
  113. _predef.append("%s=%s"%(item,conf.get('predef',item)))
  114. return "%s %s"%(",".join(_opt),",".join(_predef))
  115. def getBlackList(path):
  116. lst={}
  117. conf = ConfigParser.ConfigParser()
  118. conf.read(path)
  119. for item in conf.options('level'):
  120. lst[item]=conf.get('level',item)
  121. return lst
  122. def printReport(rptstr):
  123. if rptstr=="":
  124. return
  125. array = rptstr.split('\n')
  126. for ln in array:
  127. items = ln.split("***")
  128. if items[1].find("Stopping") != -1:
  129. print items[1]
  130. else:
  131. print "文件:%s\t错误原因:%s\t错误位置:第%s行\t错误语句:%s"%(items[0],items[1],items[2],items[4])
  132. def processItem(item,blacklst,hp):
  133. itm = item
  134. for key in hp.keys():
  135. if item[0]+os.sep+item[2] == hp[key]:
  136. itm[0]=os.sep.join(key.split(os.sep)[:-1])
  137. itm[2]=key.split(os.sep)[-1]
  138. #print "====",itm,"======"
  139. itm.append("error")
  140. for err in blacklst.keys():
  141. if itm[1].lower().find(err.lower())!=-1:
  142. itm[5] = blacklst[err]
  143. break
  144. return itm
  145. '''
  146. parse jshint output
  147. '''
  148. def splitOutput(rptstr,blacklist,mp):
  149. if rptstr=="":
  150. return
  151. array = rptstr.split('\n')
  152. lst=[]
  153. parsecnt = 0;
  154. parsetotal=len(array)
  155. for ln in array:
  156. #print ln
  157. if ln.find("***") == -1:
  158. continue
  159. items = processItem(ln.split("***"),blacklist,mp)
  160. if items[1].find("Stopping") != -1:
  161. print items[1]
  162. else:
  163. lst.append(items)
  164. parsecnt = parsecnt + 1
  165. return (lst,parsecnt,parsetotal)
  166. '''
  167. get the table body according to the result-list
  168. '''
  169. def getBody(lst):
  170. files={}
  171. error=0
  172. warning=0
  173. ignore=0;
  174. count=0
  175. for item in lst:
  176. count = count + 1
  177. if len(item)<6:
  178. continue
  179. if not files.has_key(item[0]):
  180. if item[5] == "ignore":
  181. ignore = ignore + 1
  182. elif item[5] == "error":
  183. error = error + 1
  184. files[item[0]] = getLine(item,count)
  185. else:
  186. files[item[0]] = getLine(item,count)
  187. warning = warning + 1
  188. else:
  189. if item[5] == "ignore":
  190. ignore = ignore + 1
  191. elif item[5] == "error":
  192. error = error + 1
  193. files[item[0]] = files[item[0]] + getLine(item,count)
  194. else:
  195. files[item[0]] = files[item[0]] + getLine(item,count)
  196. warning = warning + 1
  197. return (files,ignore,warning,error)
  198. def generateHtml(rptstr,outfile,blacklst,mp):
  199. print "start parsing jshint output..."
  200. (lst,parsecnt,parsetotal) = splitOutput(rptstr,blacklst,mp)
  201. print "prepare main tpl..."
  202. tpl=""
  203. tplPath=os.sep.join(os.path.abspath(__file__).split(os.sep)[:-1])+os.sep+"core"+os.sep+"tpl"+os.sep+"toggle_tpl.html"
  204. if not os.path.exists(tplPath):
  205. raise Exception('%s file does not exists!'%(tplPath))
  206. f=open(tplPath,"r")
  207. if f is None:
  208. raise Exception('open %s error!' % (tplPath))
  209. for ln in f:
  210. tpl+=ln
  211. strStartTime = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())
  212. tpl=tpl.replace("{$pnumber}",str(len(lst)))
  213. tpl=tpl.replace("{$timeData}",strStartTime)
  214. f.close()
  215. print "blacklist filtering..."
  216. (files,ignore,warning,error) = getBody(lst)
  217. tpl=tpl.replace("{$ignumber}","%s(%5.1f%%)"%(str(ignore),(float(ignore)/len(lst)*100)))
  218. tpl=tpl.replace("{$errnumber}","%s(%5.1f%%)"%(str(error),(float(error)/len(lst)*100)))
  219. tpl=tpl.replace("{$warnumber}","%s(%5.1f%%)"%(str(warning),(float(warning)/len(lst)*100)))
  220. print "prepare body"
  221. bodys=""
  222. for key in files:
  223. tblPath=os.sep.join(os.path.abspath(__file__).split(os.sep)[:-1])+os.sep+"core"+os.sep+"tpl"+os.sep+"htmlpart.html"
  224. if not os.path.exists(tblPath):
  225. raise Exception('%s file does not exists!'%(tblPath))
  226. f=open(tblPath,"r")
  227. body=''''''
  228. for ln in f:
  229. body += ln
  230. body = body.replace("{$title}",key)
  231. body = body.replace("{$fname}",key)
  232. f.close()
  233. body = body.replace("[---to be replaced 2---]",files[key])
  234. bodys = bodys + body
  235. if bodys=="":
  236. #raise Exception('no report generated')
  237. bodys = "no informatin maybe they are filtered"
  238. tpl=tpl.replace("[---to be replace 1---]",bodys)
  239. ts=str(int(time.time()))
  240. resf=open(outfile,"w")
  241. if resf is None:
  242. raise Exception('open %s error!' % (outfile))
  243. resf.write(tpl)
  244. resf.close()
  245. print "generate html file %s OK!"%(outfile)
  246. return ts
  247. def getLine(item,no):
  248. #print item
  249. text = '''<tr><td width='10%%'>%s</td><td width='10%%'>%s</td><td width='20%%'>%s</td><td width='10%%'>%s</td><td width='50%%'>%s</td></tr>'''%(str(no),item[5],item[1],item[2],item[4].replace("<","&lt;").replace(">","&gt;"))
  250. return text
  251. def genReport(status,output,blackpath,outfile,htmlMap):
  252. #if status == 0:
  253. # print "[WARNING][NO ERROR DETECTED BY JSHUNTER]"
  254. #else:
  255. if output.find("open file") != -1:
  256. raise Exception("File Not Found Error!")
  257. print "[ERROR DETECTED BY JSHUNTER]"
  258. blacklist = getBlackList(blackpath)
  259. ts = generateHtml(output,outfile,blacklist,htmlMap)
  260. return ts
  261. def checkJavaExist():
  262. cmd="java"
  263. (status,output) = commands.getstatusoutput(cmd)
  264. if status != 0:
  265. raise Exception("jshunter depend on java enviroment.please make sure your java is OK")
  266. def checkPythonExist():
  267. cmd="python -h"
  268. (status,output) = commands.getstatusoutput(cmd)
  269. if status != 0:
  270. raise Exception("jshunter depend on python enviroment.please make sure your python is OK")
  271. def getCustomerCheckFiles(paths):
  272. omitpath = os.path.dirname(__file__) + os.sep + "conf" + os.sep + "omitfiles.conf"
  273. ret = []
  274. for path in paths:
  275. path = path.rstrip(os.sep)
  276. if not os.path.isdir(path):
  277. omitfiles = getOmitedFiles(omitpath,os.sep.join(path.split(os.sep)[:-1])+os.sep)
  278. if ((os.path.getsize(path)==0) or (path in omitfiles)):
  279. continue
  280. ret.append(path)
  281. else:
  282. omitfiles = getOmitedFiles(omitpath,path)
  283. for root, dirs, files in os.walk(path):
  284. for f in files:
  285. if (os.path.getsize(root + os.sep + f)==0) or ((root + os.sep + f) in omitfiles):
  286. continue
  287. else:
  288. ret.append(root + os.sep + f)
  289. return ret
  290. def getOmitedFiles(confpath,topdir):
  291. _res = []
  292. _opt = []
  293. conf = ConfigParser.ConfigParser()
  294. conf.read(confpath)
  295. for item in conf.options('omitfils'):
  296. if conf.get('omitfils',item) == "true":
  297. _opt.append(item)
  298. if (not os.path.isdir(topdir)) and (len(_opt) > 0):
  299. return []
  300. for item in _opt:
  301. cmd = 'find %s -name "%s"'%(topdir,item)
  302. #print cmd
  303. (status,output) = commands.getstatusoutput(cmd)
  304. if status != 0:
  305. raise Exception("[FATAL]cmd failed!%s"%(cmd))
  306. #print output
  307. for ln in output.split("\n"):
  308. _res.append(ln)
  309. return _res
  310. def usage():
  311. print "===================================================================================================================="
  312. print "[Usage]\n./hint outpath.html fileToCheck.js\t\t检查fileToCheck.js这个文件"
  313. print "./hint outpath.html folderToCheck\t\t检查folderToCheck这个目录内的所有js文件和html文件(递归检查)"
  314. print "./hint outpath.html folderToCheck/*.js\t\t检查folderToCheck一级目录下的所有js文件和html文件(忽略目录)"
  315. print "[Notice]使用时请确保当前目录中包含jshint.js文件,建议cd到jshunter的目录中执行./hint.py"
  316. print "[Contact] xxxxxxx@baidu.com xxxx@baidu.com"
  317. print "===================================================================================================================="
  318. def doJsHint(_path):
  319. fileToCheck=getFiles(_path)
  320. step = 50
  321. javapath = "java"
  322. jsjar = os.path.dirname(__file__) + os.sep + "core" + os.sep + "jshint" + os.sep + "js.jar"
  323. rhino = os.path.dirname(__file__) + os.sep + "core" + os.sep + "jshint" + os.sep + "jshint-rhino.js"
  324. confpath = os.path.dirname(__file__) + os.sep + "conf" + os.sep + "check.cfg"
  325. blackpath = os.path.dirname(__file__) + os.sep + "conf" + os.sep + "ignore.list"
  326. opt = getopt(confpath)
  327. sz = len(fileToCheck)
  328. if sz <= 0:
  329. print "[WARNING]no file to be checked in doJsHint"
  330. return ""
  331. print "Files to be checked Number: %d"%(sz)
  332. for i in range(0,sz):
  333. print (i+1),":",fileToCheck[i]
  334. output=""
  335. if sz <= step:
  336. opt = "%s %s"%(getopt(confpath)," ".join(fileToCheck[:]))
  337. cmd = "%s -jar %s %s %s %s"%(javapath,jsjar,rhino,os.path.dirname(__file__) + os.sep,opt)
  338. (status,output) = commands.getstatusoutput(cmd)
  339. else:
  340. rd=sz/step+1
  341. for j in range(0,rd):
  342. if (j+1)*step>sz:
  343. opt = "%s %s"%(getopt(confpath)," ".join(fileToCheck[j*step:sz]))
  344. else:
  345. opt = "%s %s"%(getopt(confpath)," ".join(fileToCheck[j*step:(j+1)*step]))
  346. cmd = "%s -jar %s %s %s %s"%(javapath,jsjar,rhino,os.path.dirname(__file__) + os.sep,opt)
  347. (status,output_tmp)=commands.getstatusoutput(cmd)
  348. if status != 0 and output_tmp.find("open file") != -1:
  349. raise Exception("File Not Found Error.ERRMSG:%s\n"%(output_tmp))
  350. else:
  351. output = output + output_tmp
  352. print "Finish %5.1f%%"%((j+1)*float(str(step))/sz*100.0)
  353. return output
  354. def doCustomerCheck(_path):
  355. confpath = os.path.dirname(__file__) + os.sep + "conf" + os.sep + "custcheck.conf"
  356. custpath = os.path.dirname(__file__) + os.sep + "core" + os.sep + "customcheck" + os.sep
  357. ops = getCustCheckOpt(confpath)
  358. fileToCheck = getCustomerCheckFiles(_path)
  359. sz = len(fileToCheck)
  360. if sz == 0:
  361. print "[WARNING]no file to be checked in doCustomerCheck"
  362. return ""
  363. custout = ''
  364. #print ops
  365. for item in ops:
  366. for i in range(0,sz):
  367. cmd = "%s %s"%(custpath+item,fileToCheck[i])
  368. #print cmd
  369. (status,output_tmp)=commands.getstatusoutput(cmd)
  370. for ln in output_tmp.split("\n"):
  371. #print ln
  372. if ln.find("***") != -1:
  373. custout += (ln+"\n")
  374. #print custout
  375. return custout
  376. def getCustCheckOpt(path):
  377. _opt=[]
  378. conf = ConfigParser.ConfigParser()
  379. conf.read(path)
  380. for item in conf.options('command'):
  381. if conf.get('command',item) == "true":
  382. _opt.append(item)
  383. return _opt
  384. if __name__ == "__main__":
  385. try:
  386. #checkJavaExist()
  387. #checkPythonExist()
  388. #print "check enviroment ok"
  389. if len(sys.argv) < 3:
  390. usage()
  391. raise Exception("arg number error!")
  392. outfile=sys.argv[1]
  393. if os.path.exists(outfile):
  394. raise Exception('%s already exist!In order to avoid overwrite the file,please change a none-exist file!'%(outfile))
  395. blackpath = os.path.dirname(__file__) + os.sep + "conf" + os.sep + "ignore.list"
  396. filepath = sys.argv[2:]
  397. output1 = doJsHint(filepath)
  398. output2 = doCustomerCheck(filepath)
  399. output = output1 + output2
  400. if output != "":
  401. ts = genReport(0,output,blackpath,outfile,htmlMap)
  402. else:
  403. print "[WARNING]%s"%("no error detected")
  404. clearTmpFiles()
  405. except Exception,err:
  406. print "[FATAL]%s"%(err)
  407. clearTmpFiles()
  408. sys.exit(1)