Files
devbox-images/devbox/ruby/Dockerfile

91 lines
4.8 KiB
Docker

FROM coder-devbox-base-config:latest AS base-default
USER root
RUN DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends libpq-dev libffi-dev zlib1g-dev libedit-dev libyaml-dev redis-server libicu-dev postgresql-client psmisc
USER coder
# RUN echo "[ Installing nvm ]" \
# curl -o- "https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh" | bash \
# echo "[ Installing Node.js $NODE_VERSION ]" \
# nvm install "$NODE_VERSION" \
# # Write alias file directly so persisted home volumes respect it on restart
# mkdir -p "$NVM_DIR/alias" \
# echo "$NODE_VERSION" > "$NVM_DIR/alias/default" \
# nvm use "$NODE_VERSION" \
# echo "[ Node active: $(node --version) ]"
RUN git clone https://github.com/rbenv/rbenv.git ~/.rbenv && \
cd ~/.rbenv && src/configure && make -C src && \
git clone https://github.com/rbenv/ruby-build.git ~/.rbenv/plugins/ruby-build && \
export PATH="$HOME/.rbenv/bin:$PATH" && \
eval "$(rbenv init -)" && \
rbenv install -s 3.2.2 && \
rbenv global 3.2.2 && \
gem install bundler ruby-lsp --no-document
USER root
# rbenv's ruby lives entirely under /home/coder/.rbenv, exposed on PATH only
# via ~/.bashrc — invisible to Kilo's own agent process, which is spawned
# non-interactively and never sources .bashrc (needed for the ruby-lsp
# built-in LSP, which auto-installs rubocop via `gem` if `ruby`/`gem` are
# found on PATH). Copy the installed version out to image-owned territory and
# add it to PATH via ENV, so it works regardless of the home volume's state.
# bundler/ruby-lsp were installed BEFORE this copy deliberately: gem installs
# done AFTER copying (via the copied `gem` binary) still land back under
# /home/coder — Ruby's own RbConfig bakes in the interpreter's original
# build-time prefix, which `cp -a` doesn't rewrite, so gem defaults to that
# original path regardless of where the files physically now live. Confirmed
# live: `gem install ruby-lsp` run here (after the copy) installed to
# /home/coder/.rbenv/... same as before, not /usr/local/rbenv-ruby, leaving
# `ruby-lsp` off PATH entirely.
#
# That same RbConfig-prefix behavior means EVERY workspace's own `bundle
# install` (the normal, universal first step for any real Ruby project —
# not something this template automates, see devenv/main.tf) writes its
# gems' executables back under /home/coder/.rbenv/versions/<ver>/bin, never
# to /usr/local/rbenv-ruby/bin — confirmed live (real user report): `bin/dev`'s
# `exec foreman start -f Procfile.dev` failed with "foreman: not found" even
# after a clean `bundle install` showed `Bundle complete!` and `bundle
# list`/`gem list` both showed `foreman (0.89.1)` installed; the real
# executable was sitting under /home/coder/.rbenv/versions/<ver>/bin,
# invisible to $PATH (and thus to `bundle exec foreman` too — Bundler's own
# exec lookup is $PATH-based). Same root cause as bare `rails` not being
# found (also documented in devenv/README.md's Ruby section) — anything a
# project's own Gemfile pulls in beyond the two gems baked into this image
# was always going to hit this.
#
# Fixed at the root instead of papering over it with a second PATH entry:
# once the real files are copied out, the *original* versioned rbenv
# directory is deleted and replaced with a symlink back to the copy. Ruby's
# baked-in RbConfig prefix still resolves to the same absolute path either
# way, so every future `bundle install`/`gem install` (which only ever
# knows about that original path, never /usr/local/rbenv-ruby directly)
# transparently lands in the one real, already-on-PATH location instead —
# no second copy, no drift, and no new place a future ruby-version bump has
# to be kept in sync (the version string is read from rbenv's own
# `~/.rbenv/version` file, set by `rbenv global` above, not re-hardcoded
# here).
RUN RBENV_RUBY_VERSION="$(cat /home/coder/.rbenv/version)" \
&& mkdir -p /usr/local/rbenv-ruby \
&& cp -a "/home/coder/.rbenv/versions/$RBENV_RUBY_VERSION/." /usr/local/rbenv-ruby/ \
&& chown -R coder:coder /usr/local/rbenv-ruby \
&& rm -rf "/home/coder/.rbenv/versions/$RBENV_RUBY_VERSION" \
&& ln -s /usr/local/rbenv-ruby "/home/coder/.rbenv/versions/$RBENV_RUBY_VERSION"
ENV PATH="/usr/local/rbenv-ruby/bin:${PATH}"
USER coder
RUN ruby --version && gem --version && ruby-lsp --version
# Claude Code's plugin wrapper around ruby-lsp (installed above, before the
# copy-out) — same pattern as php-lsp/intelephense. Codex gets the same
# plugin from the same marketplace — see base-config's Dockerfile for why
# this works.
RUN "$HOME/.local/bin/claude" plugin install ruby-lsp@claude-plugins-official \
&& codex plugin add ruby-lsp@claude-plugins-official
RUN curl https://cli-assets.heroku.com/install.sh | sh