요즘에 젠킨스같은 CI 툴을 이용하면서 SVN에 커밋되어있는 소스와
실제 운영서버에 배포되어있는 소스가 동일한것이 당연하게 되었는데..
예전에는 종종 누군가 개발한 것을 운영서버에 배포하고 SVN에 커밋하지 않아서 SVN의 소스와 운영서버에 배포되어있는 소스가 불일치 하는 경우가 종종 있었다.
(개발한 당사자의 소스가 가장 최신버전의 소스가 되어버리는 상황인데 당사자가 퇴사하거나 해당 PC를 포멧해 버린다면 답이 없다;;)
위와같은 상황에서 할 수 있는 것은 서버에 올라가 있는 class 파일을 디컴파일 하여 java 소스와 일일히 비교해 보는건데 여간 고역이 아닐 수 없다.
그나마 비교해야 하는 파일이 몇개 정도라면 그냥 하면 되지만
소스가 불일치 하는 파일이 어떤건지 모르는 상황이라면 모든 소스를 일일히 비교해 보는 수 밖에 없다.
class파일을 디컴파일 하여 java 소스와 비교할 때 힘든점은 같은 소스라도 내용이 바뀔 수 있기 때문에 힘든게 아닐까 싶다.
java compiler가 java를 컴파일 시 소스 최적화를 하는데 이 때문에 소스가 미묘하게 바뀌거나 상황에 따라 완전 다른소스처럼 바뀌어 버린다.
최근에 인수인계를 해주고 떠난 이전 작업자가 소스를 SVN에 제대로 커밋하지 않는 바람에 프로젝트의 모든 소스를 디컴파일하여 소스를 맞추는 작업을 하게 되었다.
어떻게 작업을 할까 하다가 기막힌 방법이 떠올라 예상보다 적은 공수로 작업을 할 수가 있었다.
방법은 간단한데 아래와 같이 작업을 했다.
1004lucifer
1. (운영서버에)배포된 class를 모두 디컴파일 한다.
2. SVN의 소스를 내려받아 프로젝트 셋팅 후 빌드한다. (배포버전과 java 버전을 맞추는게 좋다.)
3. 빌드 후 생성된 class 파일을 디컴파일 한다.
4. 1번에서 디컴파일한 소스와 3번에서 디컴파일한 소스를 비교한다.
예를 들면 아래와 같다.
1004lucifer
샘플소스( 링크 , 다운로드 )
기존의 소스에서 아래 하이라이트 된 부분을 수정했다.
public synchronized Queueable dequeue(final int index) { if (index < 1 || index > this.size) { // throw new NoSuchElementException(); return null; } final Queueable result = this.elements[index]; setElement(index, this.elements[this.size]); this.elements[this.size] = null; this.size--; if (this.size != 0 && index <= this.size) { int compareToParent = 0; if (index > 1) { if (compareToParent == 0) { compareToParent = compare(this.elements[index], this.elements[index / 2]); } else { for (int i = 0; i < this.size; i++) { compareToParent++; } return result; } } if (index > 1 && compareToParent < 0) { percolateUpMinHeap(index); } else { percolateDownMinHeap(index); } } return result; }
위의 방법으로 두개의 디컴파일된 소스를 비교해보면 이렇게 나온다.
(왼쪽의 모습이 위의 수정된 소스이다. 컴파일 시 소스최적화가 되어 다른 소스처럼 보여지게 된다.)
1004lucifer
작업의 공수를 낮춰주는 부분은 배포버전의 소스와 현재 SVN 소스의 어느부분이 다른지 한눈에 볼 수가 있다는 점이다.
(원본소스와 컴파일된 소스가 완전 다른 소스같이 보여지긴 하나 해당 부분만 꼼꼼히 보면 된다는 장점이 생겼다.)
위와같이 작업하여 운영서버에 배포된 class파일에서 현재 SVN 소스에 반영해야 할 파일들을 쉽게 추릴 수 있었고 어느 부분만 작업을 하면 되는지 알 수가 있어서 예상했던 공수를 많이 줄일 수 있었다.
서버에 반영된 소스가 SVN에 커밋되지 않은 상황이라는게 일어나서는 안되는 일이지만 만일 발생한 경우라면 위와같은 방법으로 소스현행화를 적응 공수를 들이며 작업이 가능 할 것이다.
PS.
나의 경우에는 IntelliJ의 디컴파일 기능을 이용했는데 따로 디컴파일 작업 없이 class를 실시간 디컴파일해서 보여준다. eclipse 역시 비슷한 플러그인이 있지 않을까 싶다.아래와 같이 기존의 class를 classes_origin 이라는 디렉토리로 넣어서 빌드된 class와 파일비교를 해서 확인했다.
CVS, GIT 등등 다른 버전관리 프로그램 또한 마찬가지고 버전관리를 사용하고 있지 않다고해도 위의 방법은 마찬가지로 유효하다.
댓글
댓글 쓰기