初心者向け,PCの環境をdotfilesで一瞬で構築する方法(mac)

# はじめに

　最近,大学院への入学祝いとして親から新しくM2のMacを買ってもらえることになりました

　というわけでこれを期にPCの環境をGitHubで管理したいなぁって思い、今回自分なりに構築してみることにしました!!

 自分のdotfilesは[こちら](https://github.com/yoshimi-I/dotfiles)です

## 1. まずdotfilesとはなんぞや

　皆さんのPCにはたくさんの設定ファイルが入っています,これらは全てホームディレクトリ直下に入っているはずです　
 これらのファイルは基本.から始まるファイルのため表示はされません

 見たい人は以下のコマンドを打ってみてください
```sh
cd ~ && ls -a
```

.から始まるたくさんのファイルが現れるわけですがあなたが使ってる色んなアプリやプログラミング言語の設定がここに書いています、そのためこれを新しいPCにもそのまま持っていけばいつでも同じ環境のPCが作れるってわけですね〜

## 2.というわけでディレクトリ構成

　今回は以下のような構成で行なっていきます〜
```
.
├── .bin
│   ├── .Brewfile
│   ├── .gitconfig
│   ├── .gitignore_global
│   ├── .zprofile
│   ├── .zshrc
│   ├── brew.sh
│   ├── default.sh
│   ├── github.sh
│   ├── init.sh
│   └── link.sh
├── Makefile
├── README.md
├── chrome
│   └── extensions
├── .vscode
│   ├── extensions
│   ├── setting.json
│   └── sync.sh
└── iterm2
    └── com.googlecode.iterm2.plist

```



## 3. まずはinstallを行うshellのfileを作ろう!

　ここでは主にターミナル上でインストールするアプリケーションをinstall.shに記載していきます

　今回は主に以下をインストールしたいので、最初にこれらのツールをインストールする記述を行なっていきます！！
### 1. homebrew 
  言わずと知れたmacのパッケージ管理ツールです
### 2. Xcode
   iosのアプリ開発に必要であったり、C言語の環境構築にも必要だったりととりあえず入れておかないとお話になりません
### 3. Rosetta
   Intel版のアプリケーションをM1で動かすために必要です

　ここまでの処理をinit.shに記載します
```init.sh
#!/bin/zsh

# Install brew
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
if [ "$(uname -m)" = "arm64" ] ; then
  (echo; echo 'eval "$(/opt/homebrew/bin/brew shellenv)"') >> /Users/${USER}/.zprofile
eval "$(/opt/homebrew/bin/brew shellenv)"
fi

# Install xcode
# Check if command line tools are installed
if ! xcode-select --print-path &> /dev/null; then
  # Install command line tools
  echo "Command line tools not found. Installing..."
  xcode-select --install
else
  echo "Command line tools are already installed."
fi

# Install Rosetta 2 for Apple Silicon
# Check if Rosetta 2 is installed
if [[ $(sysctl -n machdep.cpu.brand_string) != *"Apple M"* ]]; then
  echo "Rosetta 2 is already installed."
  exit 0
fi

# Install Rosetta 2
/usr/sbin/softwareupdate --install-rosetta --agree-to-license
if [ $? -ne 0 ]; then
  echo "Error: Failed to install Rosetta 2."
  exit 1
fi

echo "Rosetta 2 has been installed successfully."
exit 0
```
### ちょっと解説
簡単に解説していきましょう!

```shell
#!/bin/zsh
```
　とりあえずここで使うターミナルを指定します、そのため別にzshでもshでもbashでもなんでも大丈夫です

```bash
if [ "$(uname -m)" = "arm64" ] ; then
  (echo; echo 'eval "$(/opt/homebrew/bin/brew shellenv)"') >> /Users/${USER}/.zprofile
eval "$(/opt/homebrew/bin/brew shellenv)"
fi
```

　ここはif文でmacがM1かどうかの判断をしており、もしもM1であればthenの処理を実行します

　M1のcpuはarm64という名前なのでここで条件を絞ります、試しに以下のshellを実行してみてください
```sh
echo $(uname -m)
>>> arm64
```

　そしてM1であることがわかった場合にHomebrewをインストールするコマンドを打ちます

　ここはへんはhomebrewをインストールするときに次に出てくるコマンドをそのまま打ち込んでいるだけです、詳しく知りたい方はhomebrewのインストール方法を調べてみてください、以下のコマンドを打ち込めと書いてあるはず
```sh
(echo; echo 'eval "$(/opt/homebrew/bin/brew shellenv)"') >> /Users/${USER}/.zprofile
eval "$(/opt/homebrew/bin/brew shellenv)"
```

また人によってはechoの部分を記載しない場合があると思いますが、これは最初からこの記載が書いてある.zprofileを使っているからです

## 4. シンボリックリンクを作成しよう

　ここではシンボリックリンクを作成していきます、とその前にシンボリックリンクってなんやねんって思う方がいらっしゃると思うのでそちらの説明から進めていきたいと思います

### シンボリックリンクとは

　プログラミングをしている方にわかりやすく説明すると参照です
　ファイルを参照しただけのファイルを作成することができそれをシンボリックリンクと呼びます

以下のコードをみてください
```sh
> echo "test" >> a.txt
> cat a.txt
test
```
 ここでは簡単にtestと記載されただけのa.txtを作成しました、今からここにa.txtのシンボリックリンクを作成します
```sh
ln -s a.txt b.txt
> cat b.txt
test
```
ではa.txtを書き換えてみましょう、その結果b.txtはどうなるでしょうか？
```sh
> echo "add comment" >> a.txt && cat b.txt
test
add comment
```
という風にあくまでb.txtはa.txtへの参照なためa.txtを書き換えるとb.txtの値も書き変わります

### じゃあdotfilesのシンボリックリンクはどこに使うのか

基本的に設定ファイルはホームディレクトリ直下に置かれていますが、GitHubから持ってきた場合はそれが反映されません

そこでそのままGitHub上で管理するファイルにシンボリックリンクを作成することにより、あたかもホームディレクトリに配置してあるような挙動を取らせればいいのです

ここまでの処理を実装します

```link.sh
#!/bin/zsh

SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
echo SCRIPT_DIR


for dotfile in "${SCRIPT_DIR}"/.??* ; do
    [[ "$dotfile" == "${SCRIPT_DIR}/.git" ]] && continue
    [[ "$dotfile" == "${SCRIPT_DIR}/.github" ]] && continue
    [[ "$dotfile" == "${SCRIPT_DIR}/.DS_Store" ]] && continue

    ln -fnsv "$dotfile" "$HOME"
done
```

試しに上のコードの実行結果を見てみましょう
```sh
/Users/username/Desktop/dotfiles/.bin
/Users/username/.Brewfile -> /Users/username/Desktop/dotfiles/.bin/.Brewfile
/Users/username/.gitconfig -> /Users/username/Desktop/dotfiles/.bin/.gitconfig
/Users/username/.gitignore_global -> /Users/username/Desktop/dotfiles/.bin/.gitignore_global
/Users/username/.zprofile -> /Users/username/Desktop/dotfiles/.bin/.zprofile
/Users/username/.zshrc -> /Users/username/Desktop/dotfiles/.bin/.zshrc
```
左を見てみるとわかりますがちゃんとホームディレクトリ直下(usernameの下)にできていることがわかりますね

## 5. アプリケーションをインストールしていこう

アプリケーションにはさまざまなインストール方法があると思います

例えば,AppStoreでインストールするもの、インストーラーを用いてインストールするもの,CLIでインストールするものなどです

これらを全て一発でインストールするのがBrewfileです
Mac移行時はホームディレクトリにBrewfileを置いて下記コマンドを実行します
```sh
brew bundle --global
```

以下はホームディレクトリ直下にあるBrewfileを見つけてそこに記載してあるアプリを入れてくれます、ここでさっき作ったシンボリックリンクの有用性がわかったと思います

ではインストールするアプリを書いていきます

1. AppStore経由のアプリ
   - Line
   - Microsoft PowerPoint
   - Microsoft Word
   - Microsoft Excel
   - Kindle
2. インストーラー経由でインストールするアプリ
   - VScode
   - IntelliJ
   - Goland
   - PyCharm
   - Postman
   - zoom
   - wrap
   - slack
   - google-chrome
   - deepl
   - Docker
   - Notion
   - Discord
   - DBeaver
   - SourceTree
   - alfred
3. Homebrewライブラリでインストールするもの
   - git
   - tree
   - wget

僕はこれくらいのアプリしか使いませんが他の方は必要に応じてここに追加していってください
詳しくは[ここをみてください.](https://kakakakakku.hatenablog.com/entry/2020/09/17/124653)

またインストール可能なアプリケーションを見つける方法は以下のコマンドでわかります
```sh
brew casks | grep 探したいアプリ  
```
こうすることで探したいアプリの名前を含むものを見つけることができます

ではここまでを記載したコードが以下になります
```.Brewfile
cask_args appdir: "/Applications"

tap "heroku/brew"
tap "homebrew/bundle"
tap "homebrew/cask"
tap "homebrew/cask-versions"
tap "homebrew/core"
tap "sanemat/font"

brew "git"
brew "gitmoji"
brew "mas"
brew "shellcheck"
brew "tree"
brew "volta"
brew "wget"
brew "gh"

cask "intellij-idea"
cask "goland"
cask "pycharm"
cask "cheatsheet"
cask "deepl"
cask "discord"
cask "docker"
cask "figma"
cask "google-chrome"
cask "google-drive"
cask "keyboardcleantool"
cask "raycast"
cask "ngrok"
cask "notion"
cask "postman"
cask "scroll-reverser"
cask "slack"
cask "sourcetree"
cask "visual-studio-code"
cask "warp"
cask "zoom"
cask "alfred"

mas "LINE", id: 539883307
mas "Microsoft Excel", id: 462058435
mas "Microsoft PowerPoint", id: 462062816
mas "Microsoft Remote Desktop", id: 1295203466
mas "Microsoft Word", id: 462054704
mas 'Kindle', id: 405399194
```

ではこれを実行するためのshellファイルも記載していきます

```brew.sh
#!/bin/zsh

# Check operating system
if [ "$(uname)" != "Darwin" ] ; then
	echo "Not macOS!"
	exit 1
fi

function login_check {
  sleep 1; echo "Open the App Store." && open -a App\ Store
  while true; do
    echo -n "$* [Y/n]: (default: n) "
    read ANS
    case $ANS in
      [Yy]*)
        return 0
        ;;
      *)
        open_app_store
        ;;
    esac
  done
}

if login_check "Did you login?"; then
  brew bundle --global
fi
```

今回はappstoreからもインストールする必要があるため、appstoreを立ち上げで成功した場合にbrewをインストールする処理にしています

## 6. インストールしたアプリケーションをカスタムするためのファイルを作成しよう

今インストールしたものは全てが初期のアプリケーションのためここから自分の設定ファイルを反映させていく必要があります

僕の場合はChromeとVScode,iterm2の拡張機能を入れていく必要があるためこれらを反映させるファイルを書いていきます

今回はVscodeの設定ファイルのみを解説していきます


iterm2の設定ファイルに関しては以下の記事を参考指定いただけたらと思います
- https://zenn.dev/ripopo23/articles/2d1baf1a97e136

### Vscodeの設定方法
Vscodeで設定するのは大きく2つあるかと思います
1. フォントの大きさや自動保存,ターミナルや使用するテーマやアイコンの設定などといった基本的な設定
2. 拡張機能

これら2つをファイル管理することでどの環境でも同じVscode環境を作ることができます

それを踏まえて上記の2つを反映していくコードを書いていきます

1. extentisions
2. setting.json
3. sync.sh
  
### 1. extentisions
これらは拡張機能を管理するファイルとなります

vscodeは拡張機能を以下のようにコマンドからインストールすることができます 
```sh
code --install-extension  拡張機能
```
- [参考URL](https://qiita.com/m-tmatma/items/6d36d8c191dcbe4650a1)


そのため拡張機能をインストールする手順としては
1. まずはローカルPCに入っているすべての拡張機能をどこかしらのファイルに出力する
2. 出力された拡張機能をもとにfor文を回して```code --install-extension  拡張機能```の処理を実行していく

と言った形になります

ではファイルに拡張機能を出力していきましょう


以下のshellを実行することでローカルのPCのvscodeの設定を取得できます

```sh
code --list-extensions > extensions
```
- 今回であればextensionsというファイルに出力していますが,これは自分のextensionsファイルがあるディレクトリで実行してください

こうすることでローカルにある拡張機能をすべてファイルに出力することができます

すべての拡張機能をextentionsに出力した後はsync.shを使ってインストールしていきます
```sync.sh
if [ "$(which code)" != "" ]; then
  if [ "$(code --list-extensions)" != "$(cat "${SCRIPT_DIR}/extensions")" ]; then
    cat < "${SCRIPT_DIR}/extensions" | while read -r line
    do
      code --install-extension "$line"
    done
  fi
else
  echo "Install the code command from the command palette to add your extensions."
fi
```
この部分ですべての拡張機能をインストールしていきます

### 2. setting.json
これは主にフォントサイズであったり自動保存などのVScode自体の設定を行うファイルとなります

ファイルは以下のディレクトリに保存されているため先ほどのようにシンボリックリンクを作成していく必要があります
```sh
/Users/username/Library/Application Support/Code/User/settings.json
```

### 3. sync.sh
先ほどのextentionsのインストールのほかにもやるべきことがあります

それは２つのファイルのシンボリックリンクを作成することです

このようにどこに設定ファイルが存在するのかを把握した後にシンボリックリンクで反映される所に配置していくというような流れを他の2つもとってください

## 7. GitHubのSSH設定をしよう

これはGitHubとSSHの接続をするものとなります、SSH接続をする理由に関しては[こちら](https://hnavi.co.jp/knowledge/blog/ssh/)を参照してください

では今回はコードを基に解説していきます
```github.sh
#!/bin/zsh

# GitHub SSH Setup
echo -e "\033[0;34m- GitHub SSH Setup...\033[0m"
echo "Create SSH key"
SSH_KEY_PATH="$HOME/.ssh"
if [ ! -d "$SSH_KEY_PATH" ]; then
    mkdir "$SSH_KEY_PATH"
fi
# create SSH key
ssh-keygen -N '' -f ${SSH_KEY_PATH}/id_rsa
pbcopy < ${SSH_KEY_PATH}/id_rsa.pub

# GitHub login
echo -e "\033[0;34m- GitHub login start...\033[0m"
echo "First you need to choice SSH"
echo "Second you need to choice id_rsa.pub"

gh auth login -w
```
先ほど入れたHomebrewのghというCLIでGitHubと接続できるものを用いておりこの流れに沿って進めていきます

これはSSHのための公開鍵を見つけるとそれを自動でpushしてくれる機能があるため、あらかじめ秘密鍵と公開鍵を作っておき、それに沿って設定を行なっているという形になります

## 8. PC自体設定をしよう

これはdefault.shに記載されており、これを反映させることでMac自体の設定を引き継ぐことができます

### 9. 最後にMakeで一発実行

ついに最後になりました、ここでは今まで作ったshellファイルを全て実行するコードを記載します

```Makefile
# Run all shell files
all:link init brew github

# run init.sh
init:
	@echo "\033[0;34mRun init.sh\033[0m"
	@.bin/init.sh
	@echo "\033[0;34mDone.\033[0m"

# next create symbolic links
link:
	@echo "\033[0;34mRun link.sh\033[0m"
	@.bin/link.sh
	@echo "\033[0;34mDone.\033[0m"

# Set macOS system preferences.
defaults:
	@echo "\033[0;34mRun defaults.sh\033[0m"
	@.bin/defaults.sh
	@echo "\033[0;32mDone.\033[0m"

# Install macOS applications.
brew:
	@echo "\033[0;34mRun brew.sh\033[0m"
	@.bin/brew.sh
	@echo "\033[0;32mDone.\033[0m"

# Set GitHub
github:
	@echo "\033[0;34mRun github.sh\033[0m"
	@.bin/setup.sh
	@echo "\033[0;32mDone.\033[0m"
```

これを実行するにはディレクトリで
```
make
```
と打ち込むだけとなります、いやー簡単ですねぇ

### 最後に
これで次回以降も初期化した場合のセットアップが簡単になりますねぇ助かりますぅ

### 追記(2023/9/11)
- 今回はインストールするアプリを拡張機能で管理しましたがMac側の設定もどうやらファイル管理ができるようです
- [参考URL](https://zenn.dev/keyamin/articles/970af2dca9c4c5)