Repository navigation
Expand file tree
/
Copy pathDockerfile
More file actions
160 lines (140 loc) · 8.81 KB
/
Copy pathDockerfile
File metadata and controls
160 lines (140 loc) · 8.81 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
# =====================================================================
# DevToolbox: portable development station (Debian + Docker)
# 构建一次,处处一致;运行时零网络依赖(插件/LSP 全部构建期固化)
# =====================================================================
FROM debian:trixie-slim
# ---------------------------------------------------------------- proxy passthrough
# 经 /root/.docker/config.json(proxies 段)或 --build-arg http_proxy=... 注入,
# RUN 步骤的 curl/git/npm/apt 自动生效
ARG HTTP_PROXY
ARG HTTPS_PROXY
ARG http_proxy
ARG https_proxy
ARG NO_PROXY
ARG no_proxy
ENV DEBIAN_FRONTEND=noninteractive \
TZ=Asia/Shanghai \
LANG=C.UTF-8 \
SHELL=/usr/bin/zsh \
ZDOTDIR=/home/dev/.config/zsh \
DEVTOOLBOX=1
# ---------------------------------------------------------------- core utils
RUN apt-get update && apt-get install -y --no-install-recommends \
zsh git curl wget ca-certificates tmux fzf fd-find bat ripgrep eza zoxide \
w3m build-essential unzip xz-utils clang-format nodejs npm \
gdb-multiarch openocd \
&& ln -s /usr/bin/fdfind /usr/local/bin/fd \
&& rm -rf /var/lib/apt/lists/*
# ---------------------------------------------------------------- optional GitHub mirror (flaky network)
# 用法: sudo docker build --build-arg GH_MIRROR=gh-proxy.com/ ...
ARG GH_MIRROR=
RUN if [ -n "$GH_MIRROR" ]; then \
git config --system url."https://${GH_MIRROR}github.com/".insteadOf "https://github.com/"; \
fi
# ---------------------------------------------------------------- npm registry mirror (claude code / tree-sitter-cli)
# 经 NPM_CONFIG_REGISTRY 环境变量对 root 与 dev 的 npm 同时生效
ARG NPM_REGISTRY=
ENV NPM_CONFIG_REGISTRY=${NPM_REGISTRY:-https://registry.npmjs.org/}
# ---------------------------------------------------------------- tree-sitter CLI (latex parser 需从 grammar 生成,prefer_git 路线依赖)
RUN npm install -g tree-sitter-cli
# ---------------------------------------------------------------- dev user (UID aligned to host at runtime)
RUN useradd -m -u 1000 -s /usr/bin/zsh dev \
&& mkdir -p /home/dev/.cache/zsh /home/dev/.local/state/zsh \
&& chown -R dev:dev /home/dev
# ---------------------------------------------------------------- neovim (apt 版本过老,配置需要 >=0.11 的 vim.lsp API)
ARG NVIM_ARCH=x86_64
RUN curl --retry 8 --retry-delay 3 --retry-all-errors -fsSL -o /tmp/nvim.tar.gz \
"https://${GH_MIRROR}github.com/neovim/neovim/releases/download/stable/nvim-linux-${NVIM_ARCH}.tar.gz" \
&& tar -xzf /tmp/nvim.tar.gz -C /opt \
&& ln -s "/opt/nvim-linux-${NVIM_ARCH}/bin/nvim" /usr/local/bin/nvim \
&& rm /tmp/nvim.tar.gz
# ---------------------------------------------------------------- lazygit (pin for reproducible builds)
ARG LAZYGIT_VERSION=v0.64.0
RUN curl --retry 8 --retry-delay 3 --retry-all-errors -fsSL -o /tmp/lazygit.tar.gz \
"https://${GH_MIRROR}github.com/jesseduffield/lazygit/releases/download/${LAZYGIT_VERSION}/lazygit_${LAZYGIT_VERSION#v}_Linux_${NVIM_ARCH}.tar.gz" \
&& tar -xzf /tmp/lazygit.tar.gz -C /usr/local/bin lazygit \
&& rm /tmp/lazygit.tar.gz
# ---------------------------------------------------------------- starship prompt
ARG STARSHIP_VERSION=v1.26.0
RUN curl --retry 8 --retry-delay 3 --retry-all-errors -fsSL \
"https://${GH_MIRROR}github.com/starship/starship/releases/download/${STARSHIP_VERSION}/starship-${NVIM_ARCH}-unknown-linux-musl.tar.gz" \
| tar -xz -C /tmp starship \
&& install -m 755 /tmp/starship /usr/local/bin/starship \
&& rm /tmp/starship
# ---------------------------------------------------------------- tectonic (轻量 LaTeX 引擎,vimtex 编译用;宿主 texlive 的容器替代)
ARG TECTONIC_VERSION=0.17.0
RUN curl --retry 8 --retry-delay 3 --retry-all-errors -fsSL -o /tmp/tectonic.tar.gz \
"https://${GH_MIRROR}github.com/tectonic-typesetting/tectonic/releases/download/tectonic%40${TECTONIC_VERSION}/tectonic-${TECTONIC_VERSION}-x86_64-unknown-linux-gnu.tar.gz" \
&& tar -xzf /tmp/tectonic.tar.gz -C /usr/local/bin \
&& rm /tmp/tectonic.tar.gz
# ---------------------------------------------------------------- zsh plugins (pre-clone, pinned commits)
COPY zsh-plugin-versions /tmp/zsh-plugin-versions
RUN mkdir -p /home/dev/.config/zsh/plugins \
&& cd /home/dev/.config/zsh/plugins \
&& while read -r owner repo commit; do \
git clone -q --depth=1 "https://github.com/${owner}/${repo}" "$repo" \
&& git -C "$repo" fetch -q --depth=1 origin "$commit" \
&& git -C "$repo" checkout -q "$commit"; \
done < /tmp/zsh-plugin-versions \
&& rm /tmp/zsh-plugin-versions \
&& chown -R dev:dev /home/dev/.config/zsh
# ---------------------------------------------------------------- rust toolchain (rustaceanvim 依赖 rustup 组件)
# 从本步起全部以 dev 执行:rustup/插件固化/claude 的产物必须落在 /home/dev
USER dev
ENV HOME=/home/dev
RUN curl --retry 5 --retry-delay 2 --retry-all-errors --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs \
| sh -s -- -y --profile minimal --default-toolchain stable --no-modify-path \
&& "$HOME/.cargo/bin/rustup" component add rust-analyzer
# ---------------------------------------------------------------- dotfiles
COPY --chown=dev:dev config/zsh /home/dev/.config/zsh
COPY --chown=dev:dev config/tmux /home/dev/.config/tmux
COPY --chown=dev:dev config/nvim /home/dev/.config/nvim
# ---------------------------------------------------------------- bake nvim plugins/LSP/treesitter (runtime needs zero network)
# 预克隆 lazy.nvim(commit 与 lazy-lock.json 一致),规避构建期自举克隆的网络抖动
RUN mkdir -p /home/dev/.local/share/nvim/lazy \
&& git clone -q --depth=1 https://github.com/folke/lazy.nvim.git /home/dev/.local/share/nvim/lazy/lazy.nvim \
&& git -C /home/dev/.local/share/nvim/lazy/lazy.nvim fetch -q --depth=1 origin 306a05526ada86a7b30af95c5cc81ffba93fef97 \
&& git -C /home/dev/.local/share/nvim/lazy/lazy.nvim checkout -q 306a05526ada86a7b30af95c5cc81ffba93fef97 \
&& chown -R dev:dev /home/dev/.local/share/nvim
# 拆成独立步骤:网络不稳时失败一步只需重跑一步,不会牵连其他
# Lazy restore 整体重试 3 次(30+ 插件克隆,网络抖动高发)
RUN for i in 1 2 3; do \
nvim --headless "+Lazy! restore" +qa && break; \
[ "$i" = 3 ] && exit 1; \
done
# blink.cmp 预编译模糊匹配库:构建期直接下载(复刻插件下载器的 URL 模式:
# <tag>/<triple>.so + .sha256,version 文件写 tag),运行时零下载
RUN BLINK_DIR="$HOME/.local/share/nvim/lazy/blink.cmp" \
&& TAG=$(git -C "$BLINK_DIR" describe --tags --abbrev=0) \
&& TRIPLE=x86_64-unknown-linux-gnu \
&& mkdir -p "$BLINK_DIR/target/release" \
&& curl --retry 5 --retry-delay 2 --retry-all-errors -fsSL \
-o "$BLINK_DIR/target/release/libblink_cmp_fuzzy.so" \
"https://${GH_MIRROR}github.com/saghen/blink.cmp/releases/download/${TAG}/${TRIPLE}.so" \
&& curl --retry 5 --retry-delay 2 --retry-all-errors -fsSL \
-o "$BLINK_DIR/target/release/libblink_cmp_fuzzy.so.sha256" \
"https://${GH_MIRROR}github.com/saghen/blink.cmp/releases/download/${TAG}/${TRIPLE}.so.sha256" \
&& printf '%s' "$TAG" > "$BLINK_DIR/target/release/version" \
&& test -f "$BLINK_DIR/target/release/libblink_cmp_fuzzy.so"
RUN nvim --headless -c "Lazy! load nvim-treesitter" -c "TSUpdateSync" -c "qa"
RUN if [ -n "$GH_MIRROR" ]; then export MASON_GH_MIRROR="https://${GH_MIRROR}"; fi \
&& nvim --headless -c "Lazy! load mason.nvim" \
-c "MasonInstall clangd pyright ruff" -c "qa"
# ---------------------------------------------------------------- claude code CLI (npm 安装;claude.ai 原生安装器网络不稳)
# 放在 bake 之后:此步骤易受网络影响,失败重跑时不牵连插件固化层
RUN npm install -g --prefix "$HOME/.local" @anthropic-ai/claude-code \
&& test -x "$HOME/.local/bin/claude" \
|| { echo "ERROR: claude binary missing after npm install"; exit 1; }
# ---------------------------------------------------------------- 镜像瘦身:剥离运行期不需要的构建缓存
# 插件 .git 历史最大头(30+ 仓库),运行期更新=重建镜像,直接删除
# blink.cmp 例外:运行时需 git tag 校验预编译库版本,保留其 .git(仅几 MB)
RUN find "$HOME/.local/share/nvim" -name .git -type d -prune ! -path "*/blink.cmp/*" -exec rm -rf {} + \
&& "$HOME/.cargo/bin/rustup" component remove rust-docs 2>/dev/null || true \
&& rm -rf "$HOME/.rustup/downloads" "$HOME/.rustup/tmp" \
&& npm cache clean --force 2>/dev/null || true
# ---------------------------------------------------------------- entrypoint: align UID/GID then drop into zsh
USER root
COPY entrypoint.sh /usr/local/bin/entrypoint.sh
RUN chmod +x /usr/local/bin/entrypoint.sh
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
CMD ["zsh", "-l", "-i"]