Last active
August 23, 2025 07:22
-
-
Save yonta/c1e341f644e7a1c0482a856a9533d08e to your computer and use it in GitHub Desktop.
Initialize environment script for WSL with Ubuntu or openSUSE
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash -eu | |
# https://qiita.com/youcune/items/fcfb4ad3d7c1edf9dc96 | |
# -euでエラーか未定義変数でストップする | |
# Color message | |
NORMAL=$(tput sgr0) | |
YELLOW=$(tput setaf 3) | |
GRAY=$(tput setaf 8) | |
function message() { | |
echo -e "$GRAY$*$NORMAL" | |
} | |
function header() { | |
echo -e "$GRAY##### $* ###############$NORMAL" | |
} | |
function warning() { | |
echo -e "$YELLOW$*$NORMAL" | |
} | |
########## Base Upgrade ########## | |
# Ubuntu japanese mirror repository | |
header "Ubuntu Japanese mirror repository" | |
codename=$(grep DISTRIB_CODENAME /etc/lsb-release | awk --field-separator '=' '{print $2}') | |
if [ ! -f "/etc/apt/sources.list.d/ubuntu-jp-mirror.sources" ]; then | |
message "Update Ubuntu repositories to Japanese mirror" | |
apt_sources="Types: deb | |
URIs: https://ftp.udx.icscoe.jp/Linux/ubuntu/ | |
Suites: ${codename} ${codename}-updates ${codename}-backports ${codename}-security | |
Components: main universe restricted multiverse | |
Signed-By: /usr/share/keyrings/ubuntu-archive-keyring.gpg | |
Types: deb-src | |
URIs: https://ftp.udx.icscoe.jp/Linux/ubuntu/ | |
Suites: ${codename} ${codename}-updates ${codename}-backports ${codename}-security | |
Components: main universe restricted multiverse | |
Signed-By: /usr/share/keyrings/ubuntu-archive-keyring.gpg | |
# Enabled: no | |
" | |
sudo sh -c "echo \"${apt_sources}\" > /etc/apt/sources.list.d/ubuntu-jp-mirror.sources" | |
message "Disabled default ubuntu.sources" | |
sudo sed --in-place '/Signed-By:/a Enabled: no' /etc/apt/sources.list.d/ubuntu.sources | |
fi | |
# Ubuntu Japanese Team repositories | |
header "Ubuntu Japanese Team repository" | |
if [ ! -f "/etc/apt/sources.list.d/ubuntu-ja.sources" ] && | |
[ "${codename}" = "noble" ]; then # nobleまでサポート | |
message "Add Ubuntu Japanese Team repositories" | |
apt_sources="## Ubuntu Japanese LoCo Team's repository | |
## Please report any bugs to https://bugs.launchpad.net/ubuntu-jp-improvement | |
Types: deb | |
URIs: http://archive.ubuntulinux.jp/ubuntu/ | |
Suites: ${codename} | |
Components: main | |
Signed-By: /etc/apt/keyrings/ubuntu-jp-ppa-keyring.gpg | |
Types: deb-src | |
URIs: http://archive.ubuntulinux.jp/ubuntu/ | |
Suites: ${codename} | |
Components: main | |
Enabled: no | |
Signed-By: /etc/apt/keyrings/ubuntu-jp-ppa-keyring.gpg | |
Types: deb | |
URIs: http://archive.ubuntulinux.jp/ubuntu-ja-non-free/ | |
Suites: ${codename} | |
Components: multiverse | |
Enabled: no | |
Signed-By: /etc/apt/keyrings/ubuntu-ja-archive-keyring.gpg | |
Types: deb-src | |
URIs: http://archive.ubuntulinux.jp/ubuntu-ja-non-free/ | |
Suites: ${codename} | |
Components: multiverse | |
Enabled: no | |
Signed-By: /etc/apt/keyrings/ubuntu-ja-archive-keyring.gpg | |
" | |
sudo sh -c "echo \"${apt_sources}\" > /etc/apt/sources.list.d/ubuntu-ja.sources" | |
sudo wget https://www.ubuntulinux.jp/ubuntu-jp-ppa-keyring.gpg -P /etc/apt/keyrings/ | |
sudo wget https://www.ubuntulinux.jp/ubuntu-ja-archive-keyring.gpg -P /etc/apt/keyrings/ | |
fi | |
# Update & Upgrade packages | |
header "Update & Upgrade packages" | |
sudo apt update | |
sudo apt full-upgrade -y | |
########## OS Configuration ########## | |
# XDG environment | |
export XDG_CONFIG_HOME="${HOME}/.config" | |
export XDG_CACHE_HOME="${HOME}/.cache" | |
export XDG_DATA_HOME="${HOME}/.local/share" | |
export XDG_STATE_HOME="${HOME}/.local/state" | |
# mkdir | |
header "Home directories" | |
if [ ! -d "${HOME}/.config" ]; then | |
message "Make XDG Base directories" | |
mkdir --parents "${XDG_CONFIG_HOME}" "${XDG_CACHE_HOME}" "${XDG_DATA_HOME}" | |
fi | |
if [ ! -d "${HOME}/git" ]; then | |
message "Make git and tmp directories" | |
cd "${HOME}" | |
mkdir --parents git tmp bin | |
fi | |
# ssh-key (First, because of user interaction) | |
header "SSH key" | |
keytype="ed25519" | |
if [ ! -f "${HOME}/.ssh/id_${keytype}" ]; then | |
message "Make ssh-key" | |
cd "${HOME}" | |
ssh-keygen -P '' -t ${keytype} -f "${HOME}/.ssh/id_${keytype}" | |
cat "${HOME}/.ssh/id_${keytype}.pub" | |
warning "Press [ENTER] to continue, after register SSH key to GitHub and BitBucket:" | |
read -r | |
fi | |
# Update locale | |
# language-pack-ja が必要 | |
header "Locale" | |
if ! dpkg -s "language-pack-ja" > /dev/null 2>&1; then | |
message "Install language-pack-ja" | |
sudo apt install -y language-pack-ja | |
fi | |
if locale | grep 'LANG=' | grep -v 'ja_JP.UTF-8' > /dev/null 2>&1; then | |
message "Update Locale" | |
# If it is not Japanese environment now, this updates locale to Japanese | |
sudo update-locale LANG=ja_JP.UTF-8 | |
message "LANG environment is set to Japanese." | |
warning "Press [ENTER] to continue, after running \`dpkg-reconfigure tzdata\` to change time zone Tokyo." | |
read -r | |
fi | |
# Write /etc/wsl.conf | |
header "wsl.conf" | |
if uname -a | grep '\-microsoft' > /dev/null 2>&1; then # WSL | |
message "Install wsl.conf" | |
# MEMO: Windows側の.exeファイルのみを実行権限付きにする方法がない。 | |
# かといってfmask=113のようなxなしで使うとexeファイルが実行できず、 | |
# wslviewなどが動かない。 | |
# 残念だがすべて+x状態のファイルで取り扱う。 | |
wslconf='[boot] | |
systemd = true | |
# command = service docker start | |
[automount] | |
options = "metadata,dmask=002,fmask=002" | |
[interop] | |
appendWindowsPath = false | |
[wsl2] | |
# memory = 16GB | |
# swap = 4GB | |
[user] | |
default = kei | |
' | |
sudo sh -c "echo \"${wslconf}\" > /etc/wsl.conf" | |
message "wsl.conf is updated" | |
fi | |
########## Install by apt ########## | |
# Install needed packages | |
header "base needed packages" | |
packages=(aptitude gitk build-essential autoconf automake unzip zip httpie jq | |
rlwrap clang direnv | |
fonts-vlgothic fonts-noto-cjk-extra fonts-noto-color-emoji | |
fonts-symbola | |
language-pack-ja manpages-ja manpages-ja-dev aptitude-doc-ja | |
markdown) # imagemagick graphviz | |
if uname -a | grep '\-microsoft' > /dev/null 2>&1 ; then # WSL | |
packages+=(x11-xserver-utils wslu) | |
if [ ! -f "/etc/apt/sources.list.d/wslutilities-ubuntu-wslu-${codename}.sources" ] ; then | |
# add-apt-repositoryがapt updateしてくれる | |
sudo add-apt-repository --yes ppa:wslutilities/wslu | |
fi | |
fi | |
if ! dpkg -s "${packages[@]}" > /dev/null 2>&1; then | |
message "Install packages" | |
sudo apt install -y "${packages[@]}" | |
fi | |
########## Install config ########## | |
# config | |
header "dotfiles" | |
if [ ! -d "${HOME}/git/config" ]; then | |
message "Clone config" | |
cd "${HOME}/git" | |
git clone [email protected]:yonta/dotfiles.git config | |
cd config | |
./sym_link.sh copy | |
mv "${HOME}"/.profile "${HOME}/.profile.orig" | |
message "Bash configuration files are linked." | |
fi | |
########## Install 3rd party apt packages ########## | |
# SML# | |
header "SML#" | |
if ! type smlsharp > /dev/null 2>&1; then | |
message "Add SML# repository" | |
# add-apt-repositoryがapt updateしてくれる | |
sudo apt-add-repository --yes ppa:smlsharp/ppa | |
message "Install SML#" | |
sudo apt install -y smlsharp | |
message "SML# is installed" | |
fi | |
# Install Dcoker | |
header "Docker" | |
if ! dpkg -s 'docker-ce' > /dev/null 2>&1; then | |
message "Install Docker dependencies" | |
packages=(ca-certificates curl) | |
if ! dpkg -s "${packages[@]}" > /dev/null 2>&1; then | |
sudo apt install -y "${packages[@]}" | |
fi | |
message "Add Docker GPG key" | |
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc | |
sudo chmod a+r /etc/apt/keyrings/docker.asc | |
message "Add Docker repository" | |
docker_source="Types: deb | |
URIs: https://download.docker.com/linux/ubuntu/ | |
Suites: ${codename} | |
Components: stable | |
Signed-By: /etc/apt/keyrings/docker.asc | |
" | |
sudo sh -c "echo \"${docker_source}\" > /etc/apt/sources.list.d/docker.sources" | |
message "Install Docker comunity edition" | |
sudo apt update | |
sudo apt install -y docker-ce docker-compose-plugin | |
message "Docker is installed." | |
fi | |
# PostgreSQL library | |
header "PostgreSQL" | |
if ! dpkg -s 'libpq-dev' > /dev/null 2>&1; then | |
message "Install PostgreSQL keyring" | |
sudo curl -o /etc/apt/keyrings/pgdg.asc --fail https://www.postgresql.org/media/keys/ACCC4CF8.asc | |
message "Add PostgreSQL repository" | |
pgdg_source="Types: deb | |
URIs: http://apt.postgresql.org/pub/repos/apt/ | |
Suites: ${codename}-pgdg | |
Components: main | |
Signed-By: /etc/apt/keyrings/pgdg.asc | |
" | |
sudo sh -c "echo \"${pgdg_source}\" > /etc/apt/sources.list.d/pgdg.sources" | |
message "Install PostgreSQL dev files" | |
sudo apt update | |
sudo apt install -y libpq-dev | |
message "libpq-dev is installed." | |
fi | |
# GitHub CLI | |
header "GitHub CLI" | |
if ! type gh > /dev/null 2>&1; then | |
message "Add GitHub GPG key" | |
wget -qO- https://cli.github.com/packages/githubcli-archive-keyring.gpg | sudo tee /etc/apt/keyrings/githubcli-archive-keyring.gpg > /dev/null | |
message "Add GitHub repository" | |
gh_source="Types: deb | |
URIs: https://cli.github.com/packages/ | |
Suites: stable | |
Architectures: amd64 | |
Components: main | |
Signed-By: /etc/apt/keyrings/githubcli-archive-keyring.gpg | |
" | |
sudo sh -c "echo \"${gh_source}\" > /etc/apt/sources.list.d/github-cli.sources" | |
message "Install GitHub CLI" | |
sudo apt update | |
sudo apt install -y gh | |
message "gh is installed." | |
fi | |
########## Install by mise ########## | |
mise="${HOME}/.local/bin/mise" | |
if [ ! -f "${mise}" ]; then | |
message "Install mise" | |
curl https://mise.run | sh | |
message "Activate mise" | |
eval "$(${mise} activate bash)" | |
message "Activate mise completeions" | |
# completion に使う | |
${mise} use --global usage | |
eval "$(${mise} completions --include-bash-completion-lib bash)" | |
fi | |
if type mise > /dev/null 2>&1; then | |
message "Install by mise" | |
mise use --global \ | |
act mold zig uv aws-cli aws-vault aws-copilot terraform tflint \ | |
fzf biome rust-analyzer cloudflared ecspresso go hugo jq \ | |
shfmt shellcheck hivemind hadolint ghalint actionlint yt-dlp \ | |
[email protected] \ | |
npm:typescript-language-server npm:typescript npm:ts-node \ | |
npm:vscode-langservers-extracted npm:bash-language-server \ | |
npm:elm npm:elm-format npm:elm-review npm:elm-test \ | |
npm:@elm-tooling/elm-language-server \ | |
npm:browser-sync npm:prettier \ | |
npm:@anthropic-ai/claude-code | |
fi | |
########## Install by original script ########## | |
# Rust | |
header "Rust" | |
export CARGO_HOME="${XDG_DATA_HOME}/cargo" | |
export RUSTUP_HOME="${XDG_DATA_HOME}/rustup" | |
if [ ! -f "${CARGO_HOME}/bin/cargo" ]; then | |
message "Install Rust Dependencies" | |
sudo apt install -y libssl-dev pkg-config cmake bubblewrap | |
message "Install Rustup and Rust" | |
# プロンプト無しでbash設定ファイルを書き換えずに進む | |
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --no-modify-path | |
message "Rust is installed." | |
fi | |
cargo="${CARGO_HOME}/bin/cargo" | |
if [ ! -f "${CARGO_HOME}/bin/bat" ]; then | |
message "Install Rust tools" | |
${cargo} install ripgrep --features "pcre2" | |
${cargo} install \ | |
bat bottom cargo-update du-dust eza fd-find git-delta hyperfine \ | |
pipr procs ripgrep_all starship tokei | |
message "Rust tools are installed." | |
fi | |
# shfmt が必要 | |
if ! type batman > /dev/null 2>&1; then | |
message "Install bat-extras" | |
git clone --depth 1 https://github.com/eth-p/bat-extras.git \ | |
"${HOME}/git/bat-extras" | |
cd "${HOME}/git/bat-extras" | |
# batのパスが通っていないとテストが落ちる対策 | |
PATH="${CARGO_HOME}/bin:${PATH}" | |
./build.sh --minify=all --compress | |
sudo ./build.sh --minify=all --compress --no-verify --install | |
message "bat-extras is installed." | |
fi | |
# fzf | |
# Node | |
header "Node" | |
export NVM_DIR="${XDG_CONFIG_HOME}/nvm" | |
if [ ! -f "${NVM_DIR}/nvm.sh" ]; then | |
message "Install nvm" | |
# 特定のブランチのみdepth 1はできるが、タグは難しい。 | |
# 具体的には空レポを作って、タグをdepth 1でfetch/checkoutするといけるらしい。 | |
# 複雑なので採用せず、--depth 1なしcloneで最新tagを利用する。 | |
git clone https://github.com/nvm-sh/nvm.git "${NVM_DIR}" | |
cd "${NVM_DIR}" | |
git checkout "$(git tags | sort --version-sort | tail --lines 1)" | |
message "NVM is installed." | |
fi | |
# HACK: クローンした状態ではnvm/versionsが存在しないのを利用 | |
if [ ! -d "${NVM_DIR}/versions" ]; then | |
message "Install node" | |
# shellcheck disable=SC1091 | |
. "${NVM_DIR}/nvm.sh" | |
nvm install --lts | |
message "Enable corepack" | |
corepack enable | |
# MEMO: npm install --global は使わず、mise use --global npm:[HOGE] で使う | |
message "Node is installed." | |
fi | |
# Ruby | |
header "rbenv" | |
export RBENV_ROOT="${XDG_DATA_HOME}/rbenv" | |
if [ ! -f "${RBENV_ROOT}/bin/rbenv" ]; then | |
message "Install rbenv" | |
git clone --depth 1 https://github.com/rbenv/rbenv.git "${RBENV_ROOT}" | |
message "Install rbenv plugins" | |
mkdir --parents "${RBENV_ROOT}/plugins" | |
git clone --depth 1 https://github.com/rbenv/ruby-build.git "${RBENV_ROOT}"/plugins/ruby-build | |
git clone --depth 1 https://github.com/ianheggie/rbenv-binstubs.git "${RBENV_ROOT}"/plugins/rbenv-binstubs | |
git clone --depth 1 https://github.com/meowsus/rbenv-clean "${RBENV_ROOT}"/plugins/rbenv-clean | |
message "rbenv is installed." | |
fi | |
if ! type rbenv > /dev/null 2>&1; then | |
message "Set up rbenv." | |
eval "$("${RBENV_ROOT}/bin/rbenv" init -)" | |
fi | |
header "Ruby" | |
if [ ! -f "${RBENV_ROOT}/shims/ruby" ]; then | |
message "Install Ruby dependencies" | |
# readline, for japanese input in REPL | |
if ! (dpkg-query --show "libreadline-dev" > /dev/null 2>&1 && | |
dpkg-query --show "libyaml-dev" > /dev/null 2>&1 && | |
dpkg-query --show "libpq-dev" > /dev/null 2>&1) ; then | |
sudo apt install -y libreadline-dev libyaml-dev libpq-dev libvips | |
fi | |
message "Install the latest Ruby" | |
# 最新バージョン番号、jruby/mrubyなどの文字列を省くようにしている | |
ruby_version="$(rbenv install --list | grep '^[0-9]' | sort --version-sort | tail --lines 1)" | |
rbenv install "${ruby_version}" | |
rbenv global "${ruby_version}" | |
message "Ruby is installed." | |
fi | |
if [ ! -f "${RBENV_ROOT}/shims/rubocop" ]; then | |
message "Install Ruby gems" | |
gem install yard | |
yard config --gem-install-yri | |
gem install solargraph --version 0.49.0 | |
gem install rubocop rufo bundler_bash_completion \ | |
solargraph-rails solargraph-rails-patch-for-rails71 solargraph-rspec \ | |
seeing_is_believing irb htmlbeautifier | |
# yardのバグによりパターンマッチを含むとエラーする | |
# solargraphの補完情報にまだ使っている | |
# そのため、手動でyard gemsを実行する | |
# yard gems | |
message "Ruby gems are installed." | |
warning "Press [ENTER] to continue, after run \`yard gems\`." | |
fi | |
if [ ! -f "${HOME}/bin/git_rails" ]; then | |
message "Install git_rails" | |
wget --output-document "${HOME}/bin/git_rails" https://raw.githubusercontent.com/brysgo/git-rails/refs/heads/master/bin/git_rails | |
chmod +x "${HOME}/bin/git_rails" | |
message "git_rails is installed" | |
fi | |
########## Install by build source ########## | |
# Build cmigemo | |
header "cmigemo" | |
if ! type cmigemo > /dev/null 2>&1; then | |
message "Build and Install cmigemo" | |
sudo apt install -y nkf | |
cd "${HOME}/git" | |
git clone --depth 1 https://github.com/koron/cmigemo.git | |
cd "${HOME}/git/cmigemo" | |
./configure | |
make gcc | |
sudo make gcc-install | |
message "cmigemo is installed." | |
fi | |
# Build Emacs from source | |
header "Emacs" | |
emacs_version="30.1" | |
if ! type "emacs-${emacs_version}" > /dev/null 2>&1; then | |
mkdir --parents "${HOME}/tmp/emacs" | |
cd "${HOME}/tmp/emacs" | |
emacs_dir="${HOME}/tmp/emacs/emacs-${emacs_version}" | |
message "Download Emacs" | |
if [ ! -d "${emacs_dir}" ] && | |
[ ! -f "${emacs_dir}.tar" ] && | |
[ ! -f "${emacs_dir}.tar.xz" ]; then | |
wget http://ftp.jaist.ac.jp/pub/GNU/emacs/emacs-${emacs_version}.tar.xz | |
fi | |
if [ ! -d "${emacs_dir}" ] && | |
[ ! -f "${emacs_dir}.tar" ]; then | |
xz -d "${emacs_dir}.tar.xz" | |
fi | |
if [ ! -d "${emacs_dir}" ]; then | |
tar xf "${emacs_dir}.tar" | |
fi | |
cd "${emacs_dir}" | |
message "Install Emacs dependencies" | |
sudo apt build-dep -y emacs | |
packages=(emacs-mozc-bin aspell-en) # gnome-tweaks libmagick++-dev | |
if ! dpkg -s "${packages[@]}" > /dev/null 2>&1; then | |
sudo apt install -y "${packages[@]}" | |
fi | |
message "Build and Install Emacs" | |
# WSL2でXwidgetを使うなら、libwebkit2gtk-4.0-devを入れて、 | |
# export WEBKIT_FORCE_SANDBOX=0を設定し、 | |
# --with-x-toolkit=gtk3 --with-xwidgetsでビルドする必要がある | |
./configure --without-selinux --with-x \ | |
--with-native-compilation=aot --with-tree-sitter | |
# --with-imagemagick | |
make -j | |
sudo make install | |
message "Emacs is installed." | |
fi | |
if [ ! -f "${HOME}/bin/em" ]; then | |
message "Install em command" | |
wget --output-document "${HOME}/bin/em" https://raw.githubusercontent.com/susam/emfy/refs/heads/main/em | |
chmod +x "${HOME}/bin/em" | |
message "em is installed" | |
fi | |
if [ ! -f "${HOME}/bin/emacs-lsp-booster" ]; then | |
message "Install emacs-lsp-booster" | |
git clone --depth 1 https://github.com/blahgeek/emacs-lsp-booster.git \ | |
"${HOME}/git/emacs-lsp-booster/" | |
cd "${HOME}/git/emacs-lsp-booster" | |
${cargo} build --release | |
cp target/release/emacs-lsp-booster "${HOME}/bin/" | |
message "emacs-lsp-booster is installed" | |
fi | |
if [ ! -f "${XDG_CONFIG_HOME}/emacs/lisp/hotfuzz-module.so" ]; then | |
message "Install native hotfuzz" | |
git clone --depth 1 https://github.com/axelf4/hotfuzz.git \ | |
"${HOME}/git/hotfuzz" | |
cd "${HOME}/git/hotfuzz" | |
cmake -B build -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_FLAGS=-march=native \ | |
&& cmake --build build | |
cp "${HOME}/git/hotfuzz/hotfuzz-module.so" "${XDG_CONFIG_HOME}/emacs/lisp/" | |
message "hotfuzz is installed" | |
fi | |
header "All is Done!!" | |
warning "Please restart bash." |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# repl | |
ipython | |
# virutalize pip environment | |
virtualenv | |
# linter, reformatter | |
# flake8 | |
# flake8-quotes | |
# autopep8 | |
# importmagic3 | |
# epc | |
# isort | |
# mypy type stub | |
# mypy | |
# data-science-types | |
# test | |
# pytest | |
# markdown | |
grip |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment