Ant javac 실패한 파일목록 추출

처음에 Ant 스크립트를 이용하여 컴파일 실패 목록을 추리는 로직을 구상했을 때는 매끄럽게 잘 흘러갈 줄 알았다.

아마도 javac 속성중에 수행 결과를 property나 file로 내보내는 속성이 있으며, 그것만 잘 파싱하면 되는 줄 알았는데, Ant자체의 기능보다는  javac의 근본적인 제약 사항 때문에 끝내 어찌 어찌 작성은 했지만, 그닥 매끄럽지 않은 과정이었다.

컴파일 실패 발생 시 성공한 잔여 class파일 생성여부
javavc 수행 결과는 각각 컴파일러 마다 다르다. sun 컴파일러인 경우, java파일 하나라도 실패하면, 아예 class파일을 하나도 생성하지 않는다.(여기 참조)
타 컴파일러들도 마찬가지 인지 모르겠지만,(이제 더 이상 개발이 중지된 오픈소스 컴파일러인) jikes경우 컴파일 실패한 파일을 제외한 나머지 성공파일의 class를 생성한다.

record 타스크 사용
javac는 exec나  java 타스크처럼 타스크 수행 결과를 별도의 property나 file로 내보내는 기능이 없다. 따라서 실패 파일을 추출할 로그 파일을 생성할려면 record 타스크를 사용해야 한다.
하기 예제에서 javac의 수행결과는 record타스크에서 지정된 파일에 기록되는데, Ant 내부적으로 record 타스크의 PrintStream은 finshed이벤트 (buildFinished, targetFinished and taskFinished)때 flush되며,  buildFinished 이벤트 때 close된다.(Ant Recrod 타스크)
이는 record 타스크가 들어가 있는 타겟(target)  수행 중간에 예기치 못한 종료가 발생하면, record의 buffer에 있는 마지막 내용이 파일에 기록이 안 될 수 있음을 의미한다.  (그래서 record만 별도의 타겟에서 구현을 권장한다.) 웹에서 검색해 보면, taskfinished가 발생하지 않아 buffer에 남아 있는 내용이 파일에 안 찍히는 경우에 대한 문의를 쉽게 찾아 볼수 있다.

javac 속성
javac의 failonerror 속성은 false로 설정해야 만  javac  이후 다음 스크립트 내용으로 진행이 가능하며, 이후 단계에서 컴파일 로그를 파싱할 수 있다.
failonerror와 별도로, errorProperyt 속성을 사용하면, javac(컴파일) 실패 시 지정한 속성에 true값을 세팅하므로, 다음 단계에서 javac(컴파일) 실패 여부를 별도로 확인할 수 있다.

컴파일 에러 메세지 한도
기본적으로 javac는 컴파일 에러 메시지를 100으로 제한한다. 이 이상의 실패 메시지를 로그에 남길려면 -Xmaxerrs 1000 옵션을 주어야 한다.
javac에서는 <compilerarg line=”-Xmaxerrs 1000″/> 이처럼 사용한다.
이 옵션이 sun의 컴파일러 말고 공통적으로 적용되는 옵션인지 확인이 필요하다.

filterReader와 filterChain을 이용한 컴파일 결과 파싱
컴파일 로그 파일에서 “[javac]~~~~~*.java:1128:컴파일 실패이유 어쩌고 저쩌교.
1. containregex로 java파일 이름이 들어간 라인을 추출하고,
2.replaceregex로 해당라인에서 (경로명 포함)java파일명이외의 내용을 제거한다.
3.trim으로 앞뒤 공백들을 제거한다.
4.sortfilter를 이용 라인별로 정렬을 한 후,
5.uniqfilter로 중복된 라인을 제거하면 실패 파일 목록이 생성된다.
(6.ignoreblank는 공백라인 제거)
위에서 반드시 sortfilter를 적용한 후에, uniqfilter를 적용해야 한다. 그렇지 않으면, unique하게 중복이 되지 않는다.(두줄씩 생김)

제약 사항
한 번에 1000개 이상의 컴파일 실패가 발생하는 경우, 컴파일 실패 파일이 누락될 수 있다.
보다 근본적으로 파싱로직이 \[javac\] (.*\.java):[0-9]{1}이라 문제가 발생할 수 도 있다.
(만약에 주석에 해당 구문이 들어가 있으며 오류가 발생할 수 도 있다.)

그림1

	<!--
	빌드실패파일 목록읽어서 실패한 파일리스트 추출
	-->
	<target name="compile">
		<record name="log.txt" action="start"/>
		<javac 
			srcdir="${src.dir}" listfiles="true" verbose="true"
			destdir="${bin.dir}" debug="on" includeantruntime="false"  failonerror="false" errorProperty="is.javac.fail">
			<compilerarg line="-Xmaxerrs 1000"/> 
		</javac>
		 <record name="log.txt" action="stop"/>
		<echo>is javac failed:${is.javac.fail}</echo>
	</target>

	<target name="parse.javac.result" depends="compile">
		<copy todir="${build.home}" overwrite="true" verbose="true" force="true" encoding="ISO-8859-1">
			<fileset dir="${build.home}/script">
				<include name="log.txt"/>
			</fileset>
			<filterchain>
				<tokenfilter>
					<containsregex pattern="\[javac\] (.*\.java):[0-9]{1}"  flags="gs"/>
					<replaceregex pattern="\[javac\]" replace="" flags="g" byline="true"/>
					<replaceregex pattern="\.java:(.*)$" replace=".java" flags="g" byline="true"/>
					<trim/>
				</tokenfilter>
				<sortfilter/>
				<tokenfilter>
					<uniqfilter/>
				</tokenfilter>
				<ignoreblank/>	
			</filterchain>
		</copy>
	</target>

 

댓글 남기기