최근 개발 도구를 JetBrain 라인의 제품을 사용하고 있습니다.
Android는 AndroidStudio를 이용해서 하고 Java는 IntelliJ를 이용하고 Python은 PyCharm을 이용해서 하고 있습니다.
같은 회사의 제품을 사용하니 단축키를 동일하게 할 수 있어 좋습니다.
물론 Android Studio에서 Eclipse 단축키를 제공하기는 하지만 저는 그냥 단축키를 바꾸는 편을 선호 합니다.
예전에 PC방에 가도 단축키를 모두 바꿔서 적응하면 게임방을 옮길때마다 변경해줘야 하는 불편함이 있어서 몸에 벤 방식이 기본을 그대로 사용하고 있습니다. (많이 불편하면 변경을 합니다.)
잡설은 빼고… 어쨌든 정적 분석도구를 이용해서 분석한 후 Export를 하려고 하니 HTML, XML 두가지 방식을 지원합니다. XML로 저장 후 Excel로 읽을려고 하니 안될꺼 같아. 내용만 뽑아 CSV형태로 저장하는 방식으로 했습니다.
[Problem]
AndroidStudio에서 Lint를 이용해 분석된 XML 결과를 Excel로 보고싶다.
[Solution]
XML을 파싱해서 분석 후 CSV 형태로 저장하자.
[Review]
너무 간단하게 파싱이 되서 당황했습니다. 지금은 Java로 작성하는게 훨씬 편한거 같은데 python이 익숙해지면 훨씬 쉽게 작성할 수 있을 것 같습니다.
그리고 Linux에서는 python을 기본으로 제공해주니 별도의 설치도 필요 없습니다.(Python3는 별도로 설치해야함)
""" # AndroidLintParser.py # Author: coozplz@gmail.com # Date: 2014. 08. 06 # Desc: Parse android stuidio's code analyze result(xml) to csv. # usage: AndroidLintParser.py [-h] input output positional arguments: input Android lint export path output Output csv path # Input: <problems> <problem> <file>....</file> <line>9</line> <module>...</module> <package>...</package> <entry_point TYPE="field" FQNAME="..." /> <problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES"> Declaration can have final modifier </problem_class> <hints /> <description>Declaration can have final modifier</description> </problem> </problems> # Output: ============================================================= SEVERITY, MODULE, PACKAGE, FILE_NAME, LINE, DESC ============================================================= """ from xml.etree.ElementTree import parse from xml.sax.saxutils import unescape from os import listdir from os import path import argparse import sys ''' # 입력 파라미터를 설정한다. ''' parser = argparse.ArgumentParser() parser.add_argument("input", help="Android lint export path", type=str) parser.add_argument("output", help="Output csv path", type=str) args = parser.parse_args() # 사용자가 input path의 마지막에 '/' 를 붙이지 않을 수도 있기 임의로 붙여준다. # 두개를 붙여도 상관은 없다 XML_INPUT = args.input+"/" CSV_OUTPUT = args.output def parse_android_lint_to_csv(element): """ AndroidLint 의 Problem Tag 를 분석하여 원하는 값을 추출한다. :param element: Problem Element :return: output String """ filename = element.findtext("file") filename = filename[filename.rfind("/")+1:] entry_point = element.find("entry_point").get("FQNAME") entry_point = entry_point.split(' ') if len(entry_point) > 1: entry_point = entry_point[1] line = element.findtext("line") module = element.findtext("module") package = element.findtext("package") severity = element.find("problem_class").get("severity") desc = unescape(element.findtext("description")) if severity == "TYPO" or severity is "None": return return "{0},{1},{2},{3},{4},{5},{6}\n".format(severity, module, package, filename, entry_point, line, desc) ''' #Main ''' try: f = open(CSV_OUTPUT, "w") except IOError: print('cannot open', CSV_OUTPUT) else: try: # 제외 파일명 저장용 배열 exceptFiles = [] # 제외된 파일의 개수 exceptFileCount = 0 # 총 파일의 개수 count = 0 for iterFileName in listdir(XML_INPUT): count += 1 if iterFileName.lower().find(".xml") < 0: ''' # 파일명이 Xml 형식이 아닌것은 제외 목록에 추가하고 처리하지 않는다. ''' exceptFileCount += 1 exceptFiles.append(iterFileName) continue xmlDoc = parse(XML_INPUT + iterFileName) problems = xmlDoc.getroot() for parent in problems: data = parse_android_lint_to_csv(parent) if data: # 데이터가 있는 경우에만 파일에 쓴다 f.write(data) except IOError as ioE: print("I/O error: {0}".format(ioE)) except ValueError as ve: print("Could not convert data: {0}".format(ve)) except: print("UnExpected error", sys.exc_info()[0]) raise finally: # 파일은 반드시 닫는다 f.close() # 결과를 출력 print("TOTAL={0}".format(count)) print("OUTPUT_FILE_NAME={0}".format(CSV_OUTPUT)) print("OUTPUT_FILE_SIZE=%0.2f KBytes" % (path.getsize(CSV_OUTPUT) / 1024)) if exceptFileCount > 0: print("EXCEPT={0}, EXCEPT_FILES={1}".format(exceptFileCount, exceptFiles))