Sourcegraph로 코드 검색하기
원문은 Ben Hoyt님이 에 게재했습니다. 이 블로그 구독하기
Sourcegraph는 대규모 코드베이스를 검색하고 탐색하기 위한 도구다. 이 도구는 정규 표현식 검색과 언어를 인식하는 비교적 새로운 기법인 “structural search”를 비롯한 다양한 검색 방식을 제공한다. 도구의 오픈소스 코어에는 코드 검색, 정의로 이동 및 기타 “코드 인텔리전스” 기능이 포함되어 있어 개발자가 여러 저장소에 걸친 코드베이스를 파악할 수 있게 돕는다. Sourcegraph의 코드 검색 도구는 마우스를 올리면 함수와 메서드에 대한 문서를 표시하고, 개발자가 정의로 빠르게 이동하거나 특정 식별자에 대한 모든 참조를 찾을 수 있게 한다.
Sourcegraph 서버는 대부분 Go로 작성되었으며, 코어는 Apache License 2.0으로 공개되어 있다. 다양한 “enterprise” 확장 기능은 사유 라이선스로 제공된다. Sourcegraph를 만든 회사는 매달 새 버전을 출시하는데, 최신 릴리스(3.18)에서는 C++ 지원이 개선되었고 3.17 릴리스에서는 더 빠르고 정확한 코드 검색과 AND 및 OR 검색 연산자 지원이 추가되었다.
코드 검색
Sourcegraph의 핵심 기능은 하나 이상의 저장소에 걸쳐 코드를 검색하는 능력이다. 수백 개의 저장소를 검색해도 결과는 보통 1~2초 안에 돌아온다. 기본 쿼리 방식은 리터럴 검색으로, 따옴표를 포함해 검색 문자열 "foo bar"와 정확히 일치하는 결과를 찾는다. 검색창 오른쪽에 있는 .* 아이콘을 클릭하면 정규 표현식 검색으로 전환되며, 두 검색 모드 모두 Aa 아이콘을 클릭해 대소문자를 구분하는 검색을 할 수 있다.
[] 아이콘은 Sourcegraph에서 근무하는 Rijnard van Tonder가 자신의 Comby 프로젝트를 위해 만든 검색 구문인 “structural search”로 전환한다. Structural search는 언어를 인식하므로 중첩 표현식이나 여러 줄에 걸친 구문을 정규 표현식보다 더 잘 처리한다. Structural search 쿼리는 잠재적인 버그나 코드를 단순화할 수 있는 부분을 찾는 데 자주 사용된다. 예를 들어 다음에 대한 쿼리를 보자.
fmt.Sprintf(":[str]")이 쿼리는 단일 인자가 문자열 리터럴 하나뿐인 경우 불필요한 fmt.Sprintf() 호출을 제거할 수 있는 위치를 찾아준다.
문서에는 Sourcegraph 설치가 실행하는 다양한 프로세스를 보여주는 아키텍처 다이어그램이 있다. “검색 쿼리의 생애”에 대한 더 자세한 설명도 제공된다. 프론트엔드는 쿼리에서 repo: 필터를 찾아 어떤 저장소를 검색해야 할지 결정하는 것부터 시작한다. 서버는 대부분의 다른 Sourcegraph 메타데이터와 함께 저장소 목록을 PostgreSQL 데이터베이스에 저장하며, Git 저장소는 일반적인 방식으로 파일 시스템에 클론되어 저장된다.
다음으로 서버는 (검색 쿼리에서 특정 리비전이 지정된 경우 해당 리비전에 대해) 어떤 저장소가 인덱싱되어 있고 어떤 저장소가 인덱싱되어 있지 않은지를 판단한다. 저장소 인덱싱과 인덱싱된 검색은 모두 Go로 작성된 트라이그램(trigram) 기반 코드 검색 라이브러리인 zoekt가 처리한다. (트라이그램을 이용한 코드 검색이 궁금한 독자는 Go 테크 리드 Russ Cox가 쓴 글을 참고하면 좋다.)
인덱싱되지 않은 저장소 리비전은 별도의 “searcher” 프로세스가 처리한다(Kubernetes를 통해 수평 확장이 가능하다). 이 프로세스는 Sourcegraph 서버(즉, gitserver)로부터 저장소의 zip 아카이브를 가져와 그 안의 파일들을 순회하면서, 정규 표현식 검색에는 Go의 regexp 패키지를, structural search에는 Comby 라이브러리를 이용해 매칭한다. 기본적으로 저장소의 기본 브랜치만 인덱싱되지만, Sourcegraph 3.18에서는 기본이 아닌 브랜치를 인덱싱하는 기능이 추가되었다.
코드 인텔리전스
Sourcegraph의 두 번째 주요 기능은 회사가 “코드 인텔리전스”라고 부르는 기능으로, 커서 아래에 있는 변수나 함수의 정의로 이동하거나 해당 항목에 대한 모든 참조를 찾는 기능이다. 기본적으로 이러한 기능은 “코드를 AST[추상 구문 트리]로 파싱하는 대신 검색 기반 휴리스틱을 사용
”하지만, 필자가 테스트한 바로는 휴리스틱이 꽤 정확한 것으로 보였다. 이 도구는 C, Python, Go에서 문제없이 정의를 찾아냈고, 심지어 Python에서 동적으로 할당된 정의까지 찾아냈다(예를 들어 필자의 scandir 프로젝트에서 할당되고 재할당된 scandir_python이라는 이름의 정의로 이동할 수 있었다).
최근 Sourcegraph는 Microsoft의 Language Server Index Format(LSIF)을 이용해, 언어별 파스 트리를 사용하는(검색 휴리스틱 대신) 더 정밀한 코드 인텔리전스 기능을 구현했다. LSIF는 언어 도구용 인덱서가 추출한 데이터를 저장하는 데 사용되는 JSON 기반 파일 형식이다. Sourcegraph는 여러 언어용 LSIF 인덱서를 직접 작성하거나 유지 관리하고 있는데, 여기에는 Go, C/C++, Python(모두 MIT 라이선스)이 포함된다. 현재 Sourcegraph에서 LSIF 지원은 옵트인(opt-in) 방식이며, 문서에 따르면 “빠르고 정밀한 코드 인텔리전스를 제공하지만 주기적으로 생성해 Sourcegraph 인스턴스에 업로드해야 한다.
” Sourcegraph의 권장 사항은 매 커밋마다 LSIF 데이터를 생성해 업로드하는 것이지만, 개발자는 덜 빈번하게 인덱싱하도록 주기적인 작업을 설정할 수도 있다.
코드 인텔리전스 쿼리는 세 가지 유형으로 나뉜다. 호버 쿼리(심볼과 연관된 문서를 가져와 “호버 텍스트”로 표시), 정의로 이동 쿼리, 참조 찾기 쿼리다. 정밀한 LSIF 정보를 사용할 수 있으면 이를 사용하고, 그렇지 않으면 Sourcegraph는 Ctags와 검색을 조합한 “퍼지(fuzzy)” 결과를 반환한다.
오픈 소스?
Sourcegraph의 라이선싱은 오픈 코어 방식이지만, 배포 방식은 다소 특이하다. 사유 코드를 포함한 모든 소스가 단일 공개 저장소에 들어 있지만, enterprise/와 web/src/enterprise/ 디렉터리 아래의 코드는 Sourcegraph Enterprise 라이선스가 적용되고 나머지 코드는 Apache 라이선스가 적용된다. Sourcegraph가 제공하는 사전 빌드된 Docker 이미지는 “Sourcegraph Enterprise로의 원활한 업그레이드 경로를 제공하기 위해
” 엔터프라이즈 코드를 포함하고 있지만, 저장소에는 완전한 오픈소스 이미지를 빌드하는 빌드 스크립트가 제공된다. 엔터프라이즈 코드에는 10명 이상의 사용자를 허용하지 않는 검사가 포함되어 있지만, 오픈소스 빌드에는 포함되지 않는다. 전반적으로 오픈소스 버전을 빌드하고 설치하는 과정은 제대로 문서화되어 있지 않고 설정 스크립트에 일부 단계가 빠져 있을 수도 있다 — 확실히 2급 시민 취급을 받는 느낌이다.
Sourcegraph(회사)는 다양한 코드 호스트에서 “상위” 공개 저장소를 누구나 검색할 수 있도록 하는 시스템의 호스팅 버전을 운영한다. “상위”가 어떻게 정의되는지, 혹은 이 호스팅 버전에 정확히 어떤 저장소가 인덱싱되어 있는지는 불분명하지만, 이 버전은 제공되는 기능을 잘 보여준다. 회사의 가격 페이지에는 엔터프라이즈 버전에서만 제공되는 기능들이 나열되어 있는데, 여기에는 Campaigns 다중 저장소 리팩터링 도구, 다중 코드 호스트 지원, 커스텀 브랜딩, 실시간 교육 세션 등이 포함된다.
설치
사전 빌드된 Sourcegraph 이미지를 docker-compose 방식으로 설치하는 것은 설치 문서에 나온 대로 빠르게 진행됐다. 실행까지 몇 분, 설정까지 몇 분 더 걸렸다. 로컬 머신에서 실행하고 있었기 때문에 (임시로) https를 지원하는 인터넷 연결 도메인을 제공하기 위해 ngrok 터널을 사용했다(실행 자체에 꼭 필요한 것은 아니지만, 제공하면 일부 기능이 더 잘 동작한다). 더 빠른 단일 명령어 Docker 설치 방법도 잘 동작했지만, 필자는 docker-compose 방식을 시도해 보기로 했다. 이 방식이 소규모 및 중간 규모 프로덕션 배포에 권장되고 단순한 로컬 테스트용이 아니라는 점에서 조금 더 현실적으로 보였기 때문이다. 더 크고 고가용성이 필요한 배포의 경우 Sourcegraph는 Kubernetes 클러스터에 배포할 것을 권장한다.
설정에 필요한 구성은 거의 없었다. 관리자 사용자를 만들고 시스템을 코드 호스트에 연결하는 정도였다(필자의 경우 GitHub에 있는 공개 및 비공개 저장소에 Sourcegraph가 접근할 수 있도록 GitHub 액세스 토큰을 만들어야 했다). 액세스 토큰을 추가하자마자 Sourcegraph는 저장소를 클론하고 인덱싱하기 시작했다. 몇 분 후 검색할 준비가 되었다. 이 시스템은 셀프 호스팅에 최적화되어 있다. 아마도 회사는 개발자가 소수의 테스트 사용자를 위해 쉽게 설치하도록 한 뒤, 사용자가 10명을 넘어서면 유료로 전환하도록 유도하려는 의도일 것이다.
일부 사람들에게는 망설여지게 할 수 있는 “기능” 중 하나는 Sourcegraph가 “핑(pings)”이라고 부르는 것이다. 기본적으로 이 도구는 “제품 및 고객 팀을 돕기 위해
” 약 30분마다 https://sourcegraph.com/.api/updates.com에 POST 요청을 보낸다. 이 “핵심 텔레메트리
”에는 “초기 사이트 설치자의 이메일 주소
”와 “기존 사용자 계정의 총 개수
”가 포함되는데, 아마도 10명 임계값에 도달했을 때 회사에서 설치자에게 연락해 엔터프라이즈 제품 결제를 유도하기 위한 것으로 보인다. 이 기능은 소스 코드를 수정해야만 끌 수 있다(핑 코드는 오픈소스 코어에 있으므로 이 줄을 주석 처리하면 없앨 수 있다). 기본적으로 시스템은 일부 제품 기능에 대해 집계된 사용 정보도 보내지만, 이는 DisableNonCriticalTelemetry 구성 변수를 설정해 끌 수 있다. Sourcegraph는 자사의 “핑 철학”에 대해 솔직하게 공개하고 있으며, 소스 코드, 파일 이름 또는 특정 검색 쿼리는 절대 전송하지 않는다고 명확히 밝히고 있다.
브라우저 및 에디터 통합
검색 서버와 웹 UI 외에도 Sourcegraph는 GitHub나 GitLab 같은 호스트에서 브라우징할 때 해당 기능을 사용할 수 있게 하는 Chrome 및 Firefox용 브라우저 확장을 제공한다. 예를 들어 GitHub에서 풀 리퀘스트를 검토할 때 Sourcegraph 확장을 설치한 개발자는 정의로 빠르게 이동하거나, 모든 참조를 찾거나, 특정 인터페이스의 구현을 확인할 수 있다. 2019년 6월 기준으로 GitHub도 semantic 라이브러리를 이용한 유사한 기능을 제공하지만, Sourcegraph 브라우저 확장이 더 유능해 보인다(예를 들어 함수와 메서드뿐 아니라 구조체 필드도 찾는다). Sourcegraph 브라우저 확장은 가능하면 개발자를 github.com에 머물게 하려고 하지만, 특정 링크나 정의에 대해서는 Sourcegraph 인스턴스의 URL로 이동한다.
Sourcegraph는 네 가지 인기 에디터(Visual Studio Code, Atom, IntelliJ, Sublime Text)용 에디터 통합도 제공한다. 이 플러그인을 사용하면 개발자가 현재 파일을 Sourcegraph에서 열거나, 선택한 텍스트를 Sourcegraph로 검색할 수 있다(플러그인은 결과를 브라우저에서 연다). 브라우저 확장과 에디터 플러그인은 Sourcegraph의 원칙 중 하나와도 잘 맞는다. “우리는 결국 개발자가 사용하는 모든 도구를 연결하는 플랫폼이 되고 싶다
”.
결론
Sourcegraph의 개발 과정도 꽤 개방적이며, 다가오는 3.19 및 3.20 릴리스에 대한 트래킹 이슈와 작성 중인 로드맵이 공개되어 있다. “OpenGrok과의 동등성” 같은 코어(검색 및 코드 인텔리전스) 개선을 위한 많은 계획과 함께, 회사는 클라우드 제공과 Campaigns 기능의 대폭 개선을 준비 중인 것으로 보인다.
Sourcegraph는 특히 대규모 코드베이스와 큰 개발 팀에 유용한, 잘 설계된 시스템으로 보인다. 실제로 문서는 이 도구가 소규모 팀에는 적합하지 않을 수 있음을 시사한다. “Sourcegraph는 대규모 코드베이스나 팀(15명 이상의 개발자)에서 작업하는 개발자에게 더 유용하다.
” 제대로 지원되지 않는 오픈소스 빌드와 폰 홈(phone-home) 방식의 “핑” 때문에 꺼리는 사람도 있을 수 있다. 하지만 일부 사용자는 오픈소스 버전을 고집해 결국 동작하게 만드는 데 성공한 것으로 보인다.
글을 무작위로 읽기
![Sourcegraph 검색 [Sourcegraph 검색]](https://static.lwn.net/images/2020/sourcegraph-search-sm.png)
댓글
로그인하고 댓글 남기기