dotfiles 만들기 share

today 2016-05-22 face Posted by appkr turned_in Work & Play forum 0

dotfiles는 개발자들이 사용하는 .bash_profile, .ssh 등 dot(.)으로 시작하는 파일 또는 디렉터리의 모음이다. dotfiles는 콘솔용 바이너리(e.g. gcc), 라이브러리, 애플리케이션의 설치 뿐만아니라, 그들의 설정을 잘 저장해 두었다가 컴퓨터를 빠르게 재구성하기 위한 워크플로우다.

dotfiles를 구성해두면, 예를 들어 gulp, git-flow, sublime-text3, google-chrome 등, 내가 사용하는 애플리케이션 및 개발 도구의 목록과 설정을 저장해 두었다가 다른 컴퓨터 또는 새 운영체제에서 애플리케이션 설치뿐만아니라, 심지어 코드 에디터의 설정까지도 다른/이전 컴퓨터와 똑같이 ‘바로’ 사용할 수 있다.

이번에 맥을 밀고 다시 설치할 일이 있어서, 오랫 동안 미루어 두었던 dotfiles를 시전했다. 필자도 이번 경험을 통해 알게된 사실인데, 운영체제를 다시 설치할 때만 dotfiles를 만들거나 적용할 수 있다고 생각하지만, 사실이 아니다. dotfiles는 운영체제를 다시 설치하지 않더라도 언제든 준비할 수 있다.

유명한 dotfiles들을 검토했는데 정석은 없더라. 쉘 스크립트만 이용한 사람, 주제별로 디렉터리를 분리한 사람, 다른 툴을 이용하는 사람, 운영체제도 제각각이더라. 이 포스트에서는 맥 운영체제 기준으로 dotfiles를 준비하는 방법을 공유한다. 다음 도구들을 이용한다. 앞서 말했듯이 정석은 없으므로 꼭 이렇게 할 필요는 없다.

  1. Homebrew
  2. Homebrew Bundler
  3. Mackup
  4. .osx
  5. Shell Script

시전하는 과정에서 운영체제를 두 번 설치해 봤는데, 이 정도 경험으로는 다른 이의 맥에서도 동작하는 은총알 dotfiles How-to를 쓰기에는 무리다. 어쨌든 진리는 ‘평상시에 dotfiles를 준비해 두면, 불의의 사고에 빠르게 대처할 수 있다’라는 점이다.

• • •

1. Homebrew

2012년에 생애 처음으로 맥을 영접했다. MS Office for Mac을 설치했다는 사실만으로도 맥 초보라는 것을 알 수 있을 것이다. 그러던 중 소프트웨어 개발을 다시 해야 할 상황이 닥쳤다. 필요한 것들이 너무 많았는데(e.g. rsync), 맥과 리눅스의 대가인 Peter님이 MacPorts를 쓰라고 했다. 사실 뭔지 모르고 썼다.

MacPorts를 채 알기도 전에 ‘Homebrew-The missing package manager for OS X’로 전환했다. 적절한 비유인지 모르겠지만, MacPorts와 Homebrew는 Grunt와 Gulp, Bower와 Npm의 관계와 비슷해 보인다.

맥을 개발용 컴퓨터로 사용하면서 Homebrew를 아직도 사용하지 않는다면… GG. 지금이라도 늦지 않았다. Homebrew 바이너리 설치는 아래 한 줄을 복사해서, 콘솔에 붙여 넣는 것으로 끝이다.

$ /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

1.1. 뭘 할 수 있을까?

예를 들어, PHP7과 확장모듈을 쉽게 설치할 수 있다.

$ brew search php7
# homebrew/php/php70    ...    homebrew/php/php70-xdebug

$ brew install homebrew/php/php70 homebrew/php/php70-xdebug

다른 명령들도 살펴 보자.

Homebrew Ubuntu equivalent 설명
$ brew search php7 $ apt-cache search php 패키지를 검색한다. /text/처럼 정규표현식도 쓸 수 있다.
$ brew install php70 $ sudo apt-get install php 패키지를 설치한다.
$ brew info php $ apt-cache show php 설치한 패키지의 정보를 확인한다.
$ brew list $ dpkg -l 현재 컴퓨터에 설치한 모든 패키지 목록을 출력한다.
$ brew uninstall php70 $ sudo apt-get remove php 패키지를 삭제한다.
$ brew doctor $ sudo apt-get check 설치한 패키지의 문제점을 확인한다.
$ brew cleanup $ sudo apt-get clean 로컬 캐시를 삭제한다.
$ brew update $ sudo apt-get update 설치한 모든 패키지를 업데이트한다.
$ brew outdated   오래된 패키지 목록을 출력한다.

한 가지 단점이라면, 설치할 패키지의 버전을 지정할 수 없다는 점이다. 현재 설치한 패키지의 버전을 고정하고, 더 이상 업데이트하지 않는 방법이 있긴 하다.

$ brew pin php70    # 버전 고정
$ brew unpin php70  # 버전 고정 해제

버전을 고정할 패키지가 PHP와 같은 프로그래밍 언어라면, 하나로 고정하기보다는 다른 대안을 찾아 보라. caskrook/versions Tap이나, homebrew/php/phpenv와 같은 도구를 사용하는 것이 더 낫다. 개발 환경 전체를 고정하려면, Docker 컨테이너나 Vagrant 박스를 사용하는 것이 좋다.

1.2. Tap

탭(Tap)은 Ubuntu의 apt-repository의 PPA(Personal Package Archive, 사설 패키지 저장소)와 비슷한 개념이다. 또 어떻게 보면 카테고리 또는 네임스페이스라 할 수도 있다. 앞서 본 homebrew/php가 사실은 하나의 탭이다.

다음에 소개하는 탭에 관한 내용을 읽고 나면, 탭으로 나누어 놓은 이유와 유용성을 짐작할 수 있을 것이다.

1.2.1. Services

맥에서 MySQL을 시작하려면 다음과 같이 해야 한다.

$ launchctl load ~/Library/LaunchAgents/homebrew.mxcl.mysql.plist

웨에에엑~~ 이걸 외우라고? Ubuntu를 사용해 본 사람이라면, 이 이상하고 긴 명령이 정말 마음에 들지 않을 것이다. 물론 별칭(alias)를 만들 수도 있겠지만, 더 쉬운 방법이 있다. Services Tap을 설치하는 것이다.

$ brew tap homebrew/services
$ brew services start mysql

# 설치한 전체 서비스를 재시작하고 싶을 때는
$ brew services restart --all

Ubuntu와는 순서가 다르니 유의한다($ sudo service mysql start). start|stop|restart 명령을 모두 쓸 수 있다.

서비스 목록은 list 명령으로 확인한다. 계속 써 보면 알겠지만, Homebrew의 명령들은 일관성이 있다.

$ brew services list
# Name    Status  User  Plist
# mysql   started appkr /Users/appkr/Library/LaunchAgents/homebrew.mxcl.mysql.plist

1.2.2. Caskroom

Caskroom 하위의 Tap을 이용하면, IntelliJ와 같은 애플리케이션이나 Source Code Pro와 같은 폰트를 ‘콘솔’로 설치할 수 있다.

$ brew tap caskroom/cask
$ brew tap caskroom/fonts

Services Tap과 마찬가지로 Cask Tap도 Homebrew의 명령 체계를 그대로 이용한다. IntelliJ를 설치할 수 있는 지 먼저 확인하고, 설치해 보자.

$ brew cask search intellij
# ==> Exact match
# intellij-idea
# ==> Partial matches
# intellij-idea-ce	  intellij-idea-ce-eap	    intellij-idea-eap

$ brew cask install intellij-idea

폰트도 설치하자.

$ brew cask search /font-source/
# ==> Regexp matches
# font-source-code-pro	  font-source-han-sans	    font-source-serif-pro
# font-source-han-code-jp	  font-source-sans-pro

$ brew cask install font-source-code-pro

2. Homebrew Bundler

composer.json, package.json, Gemfile, … 뭐하는 파일들인가? 의존성을 기록해 놓는 레지스트리다.

Homebrew Bundler는 앞서 본 Homebrew 패키지들을 콘솔에서 한 줄씩 명령해서 설치할 필요 없이, Brewfile이란 레지스트리를 이용해서 관리하는 편리함을 제공한다. dotfiles 구성을 위해 수십 개의 brew installbrew cask install 명령을 쉘 스크립트로 쓰고 관리해야 하는 번거로움을 덜어 준다.

2.1. Brewfile 만들기

먼저 Homebrew Bundler를 설치한다.

$ brew tap homebrew/bundle

그간에 Homebrew를 이용해서 맥을 관리해 왔다면, 다음 명령으로 쉽게 Brewfile을 만들 수 있다. 기존의 Brewfile을 덮어 쓰려면 --force 옵션을 준다.

$ brew bundle dump [--force]

그간에 Homebrew와 Cask를 이용하지 않았다면, Brewfile 파일을 직접 만들고, 패키지(애플리케이션/바이너리) 목록을 작성한다. $ brew list, $ brew cask list 명령과 /Applications 디렉터리를 열어 맥에 설치된 패키지를 확인해서 하나씩 써 준다. 애플리케이션 중에서는 Cask Tap으로 설치할 수 없고 꼭 앱 스토어를 이용해야만 하는 녀석들이 있는데, 기억력을 보조하기 위해 별도의 파일에 목록화해 놓고 dotfiles에 넣어서 관리하면 좋다.

# dotfiles/Brewfile

# Taps
tap 'caskroom/cask'
tap 'caskroom/fonts'
tap 'homebrew/dupes'    # 맥에 기본 설치된 툴을 대체하기 위한 Tap (e.g. nano 등)
tap 'homebrew/php'
tap 'homebrew/services'

# 중요! 이 줄이 없으면, ~/Applications에 설치하므로 꼭 넣어야 한다.
cask_args appdir: '/Applications'

# Binaries/Libraries
brew 'zsh'
brew 'git'
# ...

# Applications
cask 'intellij-idea'
cask 'iterm2'
# ...

설치 옵션을 지정하거나, 서비스를 재시작할 수도 있는데, 공식문서를 참고한다.

그리고 Homebrew를 통해 설치할 수 있는 패키지의 설치 옵션은 다음 명령으로 확인한다.

$ brew options php70
# --with-cgi   Enable building of the CGI executable (implies --without-fpm)
# --with-debug Compile with debugging symbols
# ...

2.2. Homebrew Bundler 실행하기

다음 명령 한 줄로 Brewfile에 정의한 패키지들을 한 방에 설치할 수 있다. Brewfile이 다른 경로에 있다면 --file=$HOME/dotfiles/Brewfile처럼 경로를 지정할 수 있다.

$ brew bundle [--file=<path>]

현재 설치된 패키지들이 최신 상태인지 확인하려면 다음 명령을 이용한다.

$ brew bundle check [--file=<path>]

3. Mackup

맥에 설치한 애플리케이션의 설정을 백업하는 도구다. 백업 저장소의 기본값은 Dropbox이며, Google Drive, iCloud, 파일 시스템을 이용할 수도 있다.

맥은 설치한 애플리케이션의 사용자 설정을 전부 ~/Library/Preferences 디렉터리에 저장하기에 가능한 일이다. Mackup의 백업으로 부터 애플리케이션 설정을 복원하면, 새로 설치한 맥의 IntelliJ에서 이전과 똑같은 플러그인, 에디터 설정 등을 바로 사용할 수 있다. 업무용 맥에서 쓰던 환경을 집에 있는 세컨드 맥에서도 그대로 쓸 수 있단 말이다.

3.1. Mackup 환경 설정

Mackup도 Homebrew로 설치한다.

$ brew install mackup

기본값을 그대로 쓴다면 환경 설정은 필요 없다. 필자는 Dropbox 대신 Google Drive를 사용하고, 백업하고 싶은 파일들이 몇가지 더 있어서 .mackup.cfg 환경 설정 파일을 만들었다.

# dotfiles/.mackup.cfg

[storage]
engine=google_drive

[configuration_files]
.homestead
.valet
# ...

3.2. 백업과 복원

백업을 실행하기 전에 Google Drive(또는 Dropbox, iCloud)를 사용할 수 있는 상태여야 한다. 설치가 끝나면 Google Drive를 열어 로그인을 하고, 동기화할 디렉터리까지 지정해 주어야 한다.

$ brew cask install google-drive

백업은 간단하다.

$ mackup backup

디렉터리 목록을 확인해 보면 다음 그림과 같다.

List of files backup-ed by Mackup

복원도 간단하다.

$ mackup restore

4. .osx

Mac OS의 여러 가지 설정은 명령 줄에서도 할 수 있다. .osx 파일은 이런 Mac OS 환경 설정을 모아서 담아 놓은 파일이다. 가령 휴지통 비우기할 때 정말로 삭제할 지를 묻는 대화상자등을 나오지 않게 하는 설정 말이다.

$ defaults write com.apple.finder WarnOnEmptyTrash -bool false

.osx 파일의 내용은 Mathias Bynen의 dotfiles를 참고했다.

5. Shell Script

필요한 도구들을 모두 살펴 봤다. 이제 이 도구들을 잘 조합해서 깔금하게 동작하는 부트스트랩 스크립트를 만들고, Git 저장소로 관리하면 될 것이다.

Git이나 클라우드로 관리하면 안되는 민감한 파일들은 반드시 별도로 보관해야 한다. 예를 들어 SSH Key 같은 파일들이 해당한다.

5.1. Bootstrap Script

Mac OS를 처음 설치했다고 가정하고, 앞서 살펴본 모든 과정을 자동화해서, 빠르게 작업 환경을 구축하는 dotfiles/bootstrap.sh 스크립트를 만들어 보자. 코드 -> 설명 순으로 작성했다.

#!/bin/sh

if test ! $(which brew); then
  ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
fi

#!(‘쉬뱅’이라 읽음)으로 이 스크립트를 실행할 바이너리를 지정한다. 시스템에 Homebrew가 없으면 설치한다.

brew update
brew tap homebrew/bundle
brew bundle --file=$HOME/dotfiles/Brewfile
brew cleanup
brew cask cleanup

Brewfile을 읽어서 지정한 패키지를 설치한다. 설치가 끝난 후, 디스크 절약을 위해 로컬 캐시를 전부 삭제했다.

[ ! -f $HOME/.gitconfig ] && ln -nfs $HOME/dotfiles/.gitconfig $HOME/.gitconfig
[ ! -f $HOME/.gitignore_global ] && ln -nfs $HOME/dotfiles/.gitignore_global $HOME/.gitignore_global

홈 디렉터리에 .gitconfig, .gitignore_global 파일이 없으면, dotfiles 하위에 있는 파일을 홈 디렉터리로 링크한다.

chsh -s $(which zsh)
sh -c "$(wget https://raw.githubusercontent.com/robbyrussell/oh-my-zsh/master/tools/install.sh -O -)"
[ ! -f $HOME/.zshrc ] && ln -nfs $HOME/dotfiles/.zshrc $HOME/.zshrc
source $HOME/.zshrc

기본으로 실행할 쉘을 Zsh으로 변경한다. Oh-my-zsh를 설치하고, 홈 디렉터리에 .zshrc 파일을 링크하고, 실행한다. Zsh와 Oh-my-zsh의 관계는 프로그래밍 언어와 프레임워크의 관계로 비유할 수 있다.

참고 필자는 Bash(Bourne Again Shell)보다 Zsh를 더 선호한다. .zshrc.bash_profile과 같은 일을 담당한다.

[ ! -f $HOME/.mackup.cfg ] && ln -nfs $HOME/dotfiles/.mackup.cfg $HOME/.mackup.cfg

Mackup 환경 설정 파일(.mackup.cfg)파일을 홈 디렉터리에 링크한다.

/usr/local/bin/composer global require laravel/installer laravel/envoy laravel/valet tightenco/jigsaw
$HOME/.composer/vendor/bin/valet install
git clone git@github.com:laravel/homestead.git $HOME/Homestead
[ $(basename $(pwd)) == "Homestead" ] && cd $HOME/Homestead
vagrant box add laravel/homestead

[OPTIONAL] PHP 개발 환경을 셋팅했다.

npm install gulp-cli gulp yo http-server --global --save

[OPTIONAL] Node 글로벌 패키지를 설치했다.

gem install rails
gem install jekyll

[OPTIONAL] 글로벌 Ruby Gem을 설치했다.

source $HOME/dotfiles/.osx

.osx 파일을 실행한다.

5.2. dotfiles

다음과 같은 디렉터리 구조로 만들어 봤다. .alias, .export, .extra, .functions, .path 등의 파일은 .zshrc가 로드하도록 구성되어 있다.

# ~/dotfiles

~/dotfiles
├── bin                 # 쉘 스크립트 저장소 (e.g. subl 등)
├── .aliases            # 별칭 모음 (e.g. ll 등)
├── .export             # 환경 변수 모음
├── .extra              # 커밋하면 안되는 민감한 내용 (e.g. Github personal token 등)
├── .functions          # 함수 (e.g. homestead() 등)
├── .gitignore          # dotfiles용 .gitignore
├── .gitconfig          # Global git 설정
├── .gitignore_global   # 글로벌 gitignore
├── .mackup.cfg         # Mackup 환경 설정
├── .osx                # Mac OS Preference 자동 설정 스크립트
├── .path               # 경로 모음
├── .zshrc              # Zsh Profile
├── Brewfile            # Homebrew Bundler용 레지스트리 파일
├── bootstrap.sh        # 메인 스크립트
└── manual_install_applications # 수동 설치해야 할 애플리케이션 목록

준비가 되었다면, Git 저장소로 만들고 원격 저장소에 동기화해 둔다.

~/dotfiles $ git init
~/dotfiles $ git add . && git commit -m 'YOUR MESSAGE' && git push origin master

5.3. 복원 프로세스

새로 설치한 Mac OS 또는 세컨드 맥 앞에 앉아서 해야 할 일 목록이다.

  1. 앱 스토어를 방문해서 Xcode를 설치한다.

  2. 설치가 끝나면 Xcode 라이선스에 동의하고, Command Line Tool을 설치해야 한다.

    $ sudo xcodebuild -license # 콘솔에서 라이선스 동의하기
    $ xcode-select --install   # Command Line Tool 설치
    
  3. SSH Key 설치

    $ cp SUPER_SAFE_DIRECTORY/.ssh/* ~/.ssh
    $ chmod -R 600 ~/.ssh
    
  4. dotfiles 설치 및 실행

    실행하기 전에 /etc/shells 파일을 열어 파일 끝에 Zsh을 추가해 둔다.

    # etc/shells
    
    /usr/local/bin/zsh
    

    각자의 dotfiles를 클론하고 부트스트랩 스크립트를 실행한다.

    $ git clone git@github.com:GITHUB_USER_NAME/dotfiles.git
    $ dotfiles/bootstrap.sh
    

    재부팅이 필요할 수 있다.

  5. Mackup으로 복원한다.

    $ mackup restore
    
  6. 맥을 재부팅 해 준다.

6. 결론

해외의 유명한 개발자들이 자신만의 dotfiles를 만들고 Github에 공개하는 것이 단순히 유행인 줄 알았다. 그런데 이번에 해 보고 왜 dotfiles를 만드는 지 대~충~ 알았다.

서두에 언급했듯이 이 사실을 절대 놓치지 말자. 꼭 Mac OS를 다시 설치할 때만 dotfiles를 준비할 수 있는 것은 아니며, 평상시에 꾸준히 관리해 두면 불의의 사고에 대한 두려움을 줄일 수 있다. 또, 빠른 작업 환경 셋업의 잇점도 누릴 수 있다.

이제 dotfiles 아래의 파일을 이용해서 맥을 계속 관리해야 한다. 가령, 새로운 애플리케이션을 설치하면 Brewfile에 써 놓는 식으로 말이다.

Linux에서는 apt-get, yum 명령을 쉘 스크립트에 직접 쓰거나, Linux Brew를 이용해서 dotfiles를 구성할 수 있을 것이다. Windows에서는 Bash Shell이 기본 내장되기 전까지는, 내장 명령 프롬프트를 대체할 Babun를 설치하고, Babun에 내장된 pact라는 패키지 관리자를 이용할 수 있다.

필자의 dotfiles는 https://github.com/appkr/dotfiles에서 참고해 볼 수 있다.

comments powered by Disqus
keyboard_arrow_up