direnv + direnv-mode 이맥스 지원 + C/C++/Python등 프로젝트 설정 적용하기

Posted on Dec 29, 2019

프로젝트의 빌드 디렉토리, virtualenv와 같은 경로의 설정, 경로 설정에 따른 빌드/실행/테스팅/스크립트을 편하게 하려고 만든 moonshot.el 와 유사한걸 검색해봤다.

몇 가지

이런 비슷한게 몇 가지 있는데, 내 상황에 쓸만한 것은 direnv

NPM: dotenv

https://www.npmjs.com/package/dotenv

Node.js에서 Unix environment variable으로 .env 파일을 로딩해주는 역할인 듯.

Shell에서 Hook 걸어서 사용하기엔 별로 인거 같았다.

그리고 Node.js 이외의 프로젝트에 적용하려면 매번 JS으로 wrapper을 짜주고 하기 싫었고,

.env 파일이 그냥 정적인 key-value 문자열의 나열이라, 파일시스템에서 경로를 조립하고 하는데 별로라는 생각이 들었다. 항상 절대 경로만 표기하거나, getenv 해서 문자열을 가져와서 상대 경로 등으로 지정된 값을 매번 절대 경로로 만드는 작업을 해야할테니까.

Python: autoenv

https://github.com/inishchith/autoenv

파이썬으로 작성되어 있고, .env 파일이 있는 디렉토리에 들어가면 내용을 스크립트로서 실행해준다.

그리고 그 디렉토리를 떠나면, .env.leave 에 지정된 스크립트를 실행.

..딱 바라는 일들을 할만하게 생겼는데,

  1. .env.leave 을 매번 작성해주기 귀찮다.

    • 설정한 환경 변수를 역으로 해제해주는걸 일일이 해줘야 하는 것 같다.
  2. autoenv의 프로젝트 페이지에서 direnv을 쓰라고 추천해줬다.

범용성도 좋고, 성능도 좋고, 기능도 강력하고: direnv

https://direnv.net/

우선 파이썬이나 Node.js이 아니라, Golang으로 작성해서 디렉토리에 진입할 때 가볍다.

그리고 자동으로 디렉토리를 떠날 때, 설정됐던 내용들을 되돌려준다. (아마 진입 전후의 envrionment variables을 비교해서 자동으로 처리해주는 것 같다.)

zsh와도 연동이 깔끔했다.

direnv + Python virtualenv

Virtualenv을 사용하는 파이썬 프로젝트를 만들려면,

다음과 같은 .envrc 파일을 프로젝트 디렉토리에 하나 만든다.

layout python

그리고 direnv 프로젝트 페이지에 설명된 Shell와 연동하는 부분 을 잘 해놓았다면, 그리고 다음을 실행하면, 바로 위 내용이 활성화된다.

direnv allow

layout python 만으로 자동으로 .direnv/python-... 디렉토리에 virtualenv을 조성하고, 활성화까지 해준다.

사실, layout python 한 줄은 대충 다음과 같은 내용과 같다:

export VIRTUAL_ENV="$(pwd)/venv/"

if [ ! -d "${VIRTUAL_ENV}" ]; then
  virtualenv "${VIRTUAL_ENV}"
fi

source "${VIRTUAL_ENV}/bin/activate"

위 예제에서는 virtualenv의 디렉토리만 조금 다르게 지정한 것을 제외하고, virtualenv환경을 만들고, VIRTUAL_ENV 환경변수를 설정해주는 것, 마지막에 활성화해주는 것 모두 동일하다.

유연하고 강력.

이맥스에서 적용

이맥스에도 연동이 가능하다.

어차피 이맥스에서 파이썬 프로그램을 작성한다고 하더라도, virtualenv에만 존재하는 모듈이나 툴을 이용해야 할테니까 적용이 자동으로 되는게 속편하다.

https://github.com/wbolster/emacs-direnv

설치와 설정을 마치고, dired (C-x d)으로 프로젝트 디렉토리를 열면, PATH, VIRTUAL_ENV 등 환경변수가 자동으로 적용된다.

;; 다음을 M-: 누르고 입력해서 확인:
(getenv "VIRTUAL_ENV")

파이썬 프로젝트 디렉토리나 파일을 열 때 자동으로 Virtualenv을 활성화 하도록 설정해봤다:

  (add-hook 'python-mode-hook
                    (lambda ()
                      (when (getenv "VIRTUAL_ENV")
                        (pyvenv-activate (getenv "VIRTUAL_ENV")))))

그래서,

파이썬 프로젝트를 예제로 만들고, Emacs와 연동해봤다.

이맥스쪽에는 lsp-python-mselpy 에 적용해서 테스트해봤다.

몇 가지 문제가 있어서 lsp-python-ms은 접어두고, 그냥 기능적으로 잘 동작하고 부족한거 없는 elpy와 direnv-mode을 쓰기로 했다.1

파이썬의 예시만 들었지만 C/C++ 프로젝트를 위한 부분들도 적용을 해나가면 moonshot.el 만을 쓸 때보다 훨씬 깔끔하게 프로젝트 빌드나 경로 관리가 가능해질거 같다.

Footnotes


1

lsp-python-ms은 virtualenv의 경로를 venv 으로만 인식하거나, flycheck의 내장된 flake8, pylint등의 checker와 잘 어울리지 못해서 짜증났다. 아직 LSP으로 바꿀 이유도 없는거 같다. elpy만으로 모든 기능들이 거의 동일하거나 더 완성도 높게 동작하니까.