Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
164 changes: 126 additions & 38 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -38,59 +38,147 @@ ENV TZ=$TIMEZONE
RUN cp /usr/share/zoneinfo/$TIMEZONE /etc/localtime && \
echo $TIMEZONE > /etc/timezone

#* Create a new user 'developer' with home directory and grant sudo privileges
RUN adduser -D -s /bin/zsh developer && \
echo "developer ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers

#* Switch to the 'developer' user for the rest of the setup
USER developer
WORKDIR /home/developer

#* Install Oh My Zsh for the 'developer' user
RUN sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)" || true
#* Create a developer user with dynamic UID/GID for Linux compatibility
ARG USER_UID=1000
ARG USER_GID=1000
RUN set -eux; \
echo "Setting up user with UID: $USER_UID, GID: $USER_GID"; \
# Handle group creation/selection
if getent group $USER_GID >/dev/null 2>&1; then \
GROUP_NAME=$(getent group $USER_GID | cut -d: -f1); \
echo "Using existing group: $GROUP_NAME (GID: $USER_GID)"; \
else \
# Check if developer group exists with different GID
if getent group developer >/dev/null 2>&1; then \
# Remove existing developer group if it has different GID
delgroup developer || true; \
fi; \
addgroup -g $USER_GID developer; \
GROUP_NAME="developer"; \
echo "Created group: $GROUP_NAME (GID: $USER_GID)"; \
fi; \
# Handle user creation/modification
if getent passwd $USER_UID >/dev/null 2>&1; then \
# User with this UID already exists
EXISTING_USER=$(getent passwd $USER_UID | cut -d: -f1); \
echo "User with UID $USER_UID already exists: $EXISTING_USER"; \
# Change the user's primary group to our target group
sed -i "s/^$EXISTING_USER:\([^:]*\):\([^:]*\):\([^:]*\):/$EXISTING_USER:\1:\2:$USER_GID:/" /etc/passwd; \
# Ensure the user has zsh shell
sed -i "s|^$EXISTING_USER:\([^:]*\):\([^:]*\):\([^:]*\):\([^:]*\):\([^:]*\):\(.*\)|$EXISTING_USER:\1:\2:\3:\4:\5:/bin/zsh|" /etc/passwd; \
# Add to sudoers if not already there
if ! grep -q "^$EXISTING_USER " /etc/sudoers; then \
echo "$EXISTING_USER ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers; \
fi; \
# Get user's home directory and set environment variable
USER_HOME=$(getent passwd $EXISTING_USER | cut -d: -f6); \
echo "export USER_HOME=$USER_HOME" >> /etc/environment; \
# Create developer symlink if the user isn't named developer
if [ "$EXISTING_USER" != "developer" ]; then \
# Create symlink for compatibility
if [ ! -e /home/developer ]; then \
ln -sf $USER_HOME /home/developer; \
fi; \
fi; \
echo "Using existing user: $EXISTING_USER with home: $USER_HOME"; \
else \
# No user with this UID, create new developer user
# First, remove any existing developer user with different UID
if getent passwd developer >/dev/null 2>&1; then \
deluser developer || true; \
fi; \
# Create the developer user
adduser -D -u $USER_UID -G $GROUP_NAME -s /bin/zsh developer; \
echo "Created user: developer (UID: $USER_UID, GID: $USER_GID)"; \
echo "developer ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers; \
fi

#* Switch to the developer user for the rest of the setup
USER $USER_UID:$USER_GID

#* Determine the actual home directory and set up environment
RUN USER_HOME=$(getent passwd $USER_UID | cut -d: -f6) && \
echo "Working with home directory: $USER_HOME" && \
# Ensure the home directory exists and has proper permissions
mkdir -p $USER_HOME && \
chown $USER_UID:$USER_GID $USER_HOME

#* Set dynamic WORKDIR based on actual user home
RUN USER_HOME=$(getent passwd $USER_UID | cut -d: -f6) && \
echo "Setting working directory to: $USER_HOME"
WORKDIR /home/node

#* Install Oh My Zsh for the current user
RUN USER_HOME=$(getent passwd $USER_UID | cut -d: -f6) && \
cd $USER_HOME && \
sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)" || true

#* Install useful zsh plugins
RUN git clone https://github.com/zsh-users/zsh-autosuggestions /home/developer/.oh-my-zsh/custom/plugins/zsh-autosuggestions && \
git clone https://github.com/zsh-users/zsh-syntax-highlighting /home/developer/.oh-my-zsh/custom/plugins/zsh-syntax-highlighting && \
git clone https://github.com/zsh-users/zsh-completions /home/developer/.oh-my-zsh/custom/plugins/zsh-completions && \
sed -i 's/plugins=(git)/plugins=(git zsh-autosuggestions zsh-syntax-highlighting zsh-completions)/' /home/developer/.zshrc
RUN USER_HOME=$(getent passwd $USER_UID | cut -d: -f6) && \
mkdir -p $USER_HOME/.oh-my-zsh/custom/plugins && \
git clone https://github.com/zsh-users/zsh-autosuggestions $USER_HOME/.oh-my-zsh/custom/plugins/zsh-autosuggestions && \
git clone https://github.com/zsh-users/zsh-syntax-highlighting $USER_HOME/.oh-my-zsh/custom/plugins/zsh-syntax-highlighting && \
git clone https://github.com/zsh-users/zsh-completions $USER_HOME/.oh-my-zsh/custom/plugins/zsh-completions && \
sed -i 's/plugins=(git)/plugins=(git zsh-autosuggestions zsh-syntax-highlighting zsh-completions)/' $USER_HOME/.zshrc

#* Install the Powerlevel10k theme
RUN git clone --depth=1 https://github.com/romkatv/powerlevel10k.git /home/developer/.oh-my-zsh/custom/themes/powerlevel10k && \
sed -i 's/ZSH_THEME=".*"/ZSH_THEME="powerlevel10k\/powerlevel10k"/' /home/developer/.zshrc
RUN USER_HOME=$(getent passwd $USER_UID | cut -d: -f6) && \
mkdir -p $USER_HOME/.oh-my-zsh/custom/themes && \
git clone --depth=1 https://github.com/romkatv/powerlevel10k.git $USER_HOME/.oh-my-zsh/custom/themes/powerlevel10k && \
sed -i 's/ZSH_THEME=".*"/ZSH_THEME="powerlevel10k\/powerlevel10k"/' $USER_HOME/.zshrc

#* Clone LazyVim for the 'developer' user
RUN git clone https://github.com/LazyVim/starter /home/developer/.config/nvim
#* Clone LazyVim for the current user
RUN USER_HOME=$(getent passwd $USER_UID | cut -d: -f6) && \
mkdir -p $USER_HOME/.config && \
git clone https://github.com/LazyVim/starter $USER_HOME/.config/nvim

#* Remove the .git folder, so you can add it to your own repo later
RUN rm -rf /home/developer/.config/nvim/.git
RUN USER_HOME=$(getent passwd $USER_UID | cut -d: -f6) && \
rm -rf $USER_HOME/.config/nvim/.git

#* Create useful aliases in .zshrc
RUN echo 'alias ll="exa -la"' >> /home/developer/.zshrc && \
echo 'alias cat="bat"' >> /home/developer/.zshrc && \
echo 'alias find="fd"' >> /home/developer/.zshrc && \
echo 'alias vim="nvim"' >> /home/developer/.zshrc && \
echo 'alias vi="nvim"' >> /home/developer/.zshrc && \
echo 'alias lg="lazygit"' >> /home/developer/.zshrc
RUN USER_HOME=$(getent passwd $USER_UID | cut -d: -f6) && \
echo 'alias ll="exa -la"' >> $USER_HOME/.zshrc && \
echo 'alias cat="bat"' >> $USER_HOME/.zshrc && \
echo 'alias find="fd"' >> $USER_HOME/.zshrc && \
echo 'alias vim="nvim"' >> $USER_HOME/.zshrc && \
echo 'alias vi="nvim"' >> $USER_HOME/.zshrc && \
echo 'alias lg="lazygit"' >> $USER_HOME/.zshrc

#* Add helpful environment variables
RUN echo 'export EDITOR=nvim' >> /home/developer/.zshrc && \
echo 'export VISUAL=nvim' >> /home/developer/.zshrc && \
echo 'export PAGER=bat' >> /home/developer/.zshrc
RUN USER_HOME=$(getent passwd $USER_UID | cut -d: -f6) && \
echo 'export EDITOR=nvim' >> $USER_HOME/.zshrc && \
echo 'export VISUAL=nvim' >> $USER_HOME/.zshrc && \
echo 'export PAGER=bat' >> $USER_HOME/.zshrc

#* Configure Powerlevel10k to avoid gitstatus issues
RUN USER_HOME=$(getent passwd $USER_UID | cut -d: -f6) && \
echo 'POWERLEVEL9K_DISABLE_GITSTATUS=true' >> $USER_HOME/.zshrc && \
echo 'POWERLEVEL9K_VCS_DISABLE_GITSTATUS_FORMATTING=true' >> $USER_HOME/.zshrc && \
echo 'typeset -g POWERLEVEL9K_INSTANT_PROMPT=quiet' >> $USER_HOME/.zshrc

#* Switch back to root to fix permissions and create directories
USER root

#* Create cache directories and ensure proper permissions
RUN mkdir -p /home/developer/.cache/nvim /home/developer/.cache/zsh /home/developer/.cache/pip \
/home/developer/.local/share/nvim /home/developer/.local/state/nvim && \
chown -R developer:developer /home/developer

#* Switch back to developer user
USER developer

#* Set the default working directory
WORKDIR /home/developer
#* Create cache directories and ensure proper permissions for the actual user home
RUN USER_HOME=$(getent passwd $USER_UID | cut -d: -f6) && \
echo "Creating cache directories in: $USER_HOME" && \
mkdir -p $USER_HOME/.cache/nvim $USER_HOME/.cache/zsh $USER_HOME/.cache/pip \
$USER_HOME/.local/share/nvim $USER_HOME/.local/state/nvim \
$USER_HOME/.cache/gitstatus $USER_HOME/.cache/p10k && \
chown -R $USER_UID:$USER_GID $USER_HOME && \
chmod -R 755 $USER_HOME/.cache $USER_HOME/.local && \
# Also ensure the developer symlink has proper permissions if it exists
if [ -L /home/developer ]; then \
chown -h $USER_UID:$USER_GID /home/developer; \
fi

#* Switch back to the container user
USER $USER_UID:$USER_GID

#* Set the default working directory to the actual user home
RUN USER_HOME=$(getent passwd $USER_UID | cut -d: -f6) && echo "Final working directory: $USER_HOME"
WORKDIR /home/node

#* Set the default shell to Zsh
CMD ["/bin/zsh"]
27 changes: 15 additions & 12 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
# LazyVim Docker - Makefile
# Provides easy-to-use commands for managing the LazyVim Docker environment

.PHONY: help build start enter stop destroy clean status update logs backup restore dev quick version bump-version restart
.PHONY: default build start enter stop destroy clean status update backup restore dev quick version bump-version restart
.PHONY: install-global uninstall install-remote remote-uninstall remote-update configure

# Default target
.DEFAULT_GOAL := help
.DEFAULT_GOAL := default

default: # Show all available commands (default when running 'make')
@echo "$(BLUE)LazyVim Docker Environment - Available Commands$(NC)"
@echo ""
@awk 'BEGIN {FS = ":.*##"} /^[a-zA-Z_-]+:.*##/ { printf "$(GREEN)%-15s$(NC) %s\n", $$1, $$2 }' $(MAKEFILE_LIST)
@echo ""
@echo "$(YELLOW)Current version: $(VERSION)$(NC)"

# Colors for output
RED := \033[0;31m
Expand All @@ -19,12 +26,12 @@ VERSION := $(shell cat VERSION 2>/dev/null || echo "1.0.0")
CONTAINER_NAME := lazyvim
COMPOSE_FILE := docker-compose.yml

help: ## Show this help message
@echo "$(BLUE)LazyVim Docker Environment - Available Commands$(NC)"
@echo ""
@awk 'BEGIN {FS = ":.*##"} /^[a-zA-Z_-]+:.*##/ { printf "$(GREEN)%-15s$(NC) %s\n", $$1, $$2 }' $(MAKEFILE_LIST)
@echo ""
@echo "$(YELLOW)Current version: $(VERSION)$(NC)"
# Detect user permissions for Linux compatibility
USER_UID := $(shell if [ "$(shell uname)" = "Linux" ]; then id -u; else echo "1000"; fi)
USER_GID := $(shell if [ "$(shell uname)" = "Linux" ]; then id -g; else echo "1000"; fi)

# Docker compose with environment variables for Linux permission compatibility
DOCKER_COMPOSE := USER_UID=$(USER_UID) USER_GID=$(USER_GID) docker compose

build: ## Build the Docker environment (clean build)
@echo "$(BLUE)Building LazyVim Docker environment v$(VERSION)...$(NC)"
Expand Down Expand Up @@ -110,10 +117,6 @@ status: ## Show container status
docker compose ps; \
fi

logs: ## Show container logs
@echo "$(BLUE)Container Logs:$(NC)"
@docker compose logs -f --tail=50

update: ## Update to latest version and rebuild
@echo "$(BLUE)Updating LazyVim environment...$(NC)"
@git pull origin main || echo "$(YELLOW)Could not pull latest changes$(NC)"
Expand Down
17 changes: 8 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,19 +73,18 @@ lazy status # Check container status
lazy build # Build/rebuild environment
lazy update # Update to latest version
lazy uninstall # Complete removal
lazy help # Show all available commands
```

### 📁 Local Commands (Traditional Installation)
From the project directory:
```bash
make help # Show all available commands
make enter # 🔥 DAILY USE: Enter container (starts automatically if stopped)
make start # Start existing container (preserves all data)
make stop # Stop container (saves all data and plugins)
make status # Check container status
make build # ⚠️ ONLY for first time or major updates
make destroy # ⚠️ DANGEROUS: Removes everything
make # Show all available commands (default target)
make enter # 🔥 DAILY USE: Enter container (starts automatically if stopped)
make start # Start existing container (preserves all data)
make stop # Stop container (saves all data and plugins)
make status # Check container status
make build # ⚠️ ONLY for first time or major updates
make destroy # ⚠️ DANGEROUS: Removes everything
```

> 💡 **For daily development**: Use `lazy enter` (remote) or `make enter` (traditional)
Expand Down Expand Up @@ -371,7 +370,7 @@ volumes:
### Health Check Commands
```bash
lazy status # Container status
lazy help # Available commands
lazy # Available commands
make health # Comprehensive diagnostics (traditional)
```

Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.3.2
1.3.3
2 changes: 2 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ services:
args:
VERSION: ${VERSION:-1.0.0}
TIMEZONE: America/Mexico_City
USER_UID: ${USER_UID:-1000}
USER_GID: ${USER_GID:-1000}
container_name: lazyvim
hostname: lazyvim-dev
restart: unless-stopped
Expand Down
4 changes: 1 addition & 3 deletions docs/COMMANDS.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ This document provides a comprehensive guide to all available commands in the La

| Command | Description | Example |
|---------|-------------|---------|
| `make help` | Show all available commands with descriptions | `make help` |
| `make` | Show all available commands with descriptions (default target) | `make` |
| `make version` | Show current project version | `make version` |
| `make status` | Show container and environment status | `make status` |
| `make health` | Run comprehensive health diagnostics | `make health` |
Expand All @@ -31,7 +31,6 @@ This document provides a comprehensive guide to all available commands in the La
| Command | Description | Example |
|---------|-------------|---------|
| `make dev` | Start in development mode with workspace mounted | `make dev` |
| `make logs` | Show container logs (follow mode) | `make logs` |
| `make update` | Update to latest version and rebuild | `make update` |

### Maintenance
Expand Down Expand Up @@ -156,7 +155,6 @@ make update # Update to latest
### Troubleshooting
```bash
./scripts/health-check.sh # Diagnose issues
make logs # Check container logs
make destroy && make build # Nuclear option - rebuild everything
```

Expand Down
13 changes: 10 additions & 3 deletions scripts/build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ VERSION_FILE="VERSION"
CONTAINER_NAME="lazyvim"
DOTFILES_DIR=".dotfiles"

# Source permission detection
source "$(dirname "$0")/detect-permissions.sh"

# Functions
log_info() {
printf "${BLUE}[INFO]${NC} %s\n" "$1"
Expand All @@ -45,10 +48,14 @@ fi

VERSION=$(cat "$VERSION_FILE")
# Get timezone from docker-compose.yml
TIMEZONE=$(grep -A 10 "args:" docker-compose.yml | grep "TIMEZONE:" | awk '{print $2}' || echo "America/Mexico_City")
TIMEZONE=$(grep -A 10 "args:" docker-compose.yml | grep "TIMEZONE:" | awk '{print $2}' || printf "America/Mexico_City")

# Detect and configure user permissions
detect_user_permissions

log_info "Building LazyVim Docker environment v$VERSION"
log_info "Timezone: $TIMEZONE"
log_info "User permissions: UID=$USER_UID, GID=$USER_GID"

# Create .dotfiles directory if it doesn't exist
if [[ ! -d "$DOTFILES_DIR" ]]; then
Expand All @@ -72,7 +79,7 @@ docker compose pull || log_warning "Could not pull some images, continuing..."

# Build the container
log_info "Building container with version $VERSION..."
if docker compose build --build-arg VERSION="$VERSION" --no-cache; then
if USER_UID=$USER_UID USER_GID=$USER_GID docker compose build --build-arg VERSION="$VERSION" --build-arg USER_UID="$USER_UID" --build-arg USER_GID="$USER_GID" --no-cache; then
log_success "Container built successfully"
else
log_error "Failed to build container"
Expand All @@ -81,7 +88,7 @@ fi

# Start the container
log_info "Starting the container..."
if docker compose up --force-recreate -d; then
if USER_UID=$USER_UID USER_GID=$USER_GID docker compose up --force-recreate -d; then
log_success "Container started successfully"
else
log_error "Failed to start container"
Expand Down
12 changes: 6 additions & 6 deletions scripts/configure.sh
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ get_current_mounts() {
export CURRENT_MOUNTS_DATA="${mounts_data[*]}"

# Return 0 always to avoid script termination
echo "$((counter - 1))" > /tmp/mount_count
printf "%d\n" "$((counter - 1))" > /tmp/mount_count
return 0
}

Expand Down Expand Up @@ -322,15 +322,15 @@ configure_timezone() {
# Detect system timezone
local system_tz=""
if command -v timedatectl >/dev/null 2>&1; then
system_tz=$(timedatectl show --property=Timezone --value 2>/dev/null || echo "")
system_tz=$(timedatectl show --property=Timezone --value 2>/dev/null || printf "")
elif [[ -f /etc/timezone ]]; then
system_tz=$(cat /etc/timezone 2>/dev/null || echo "")
system_tz=$(cat /etc/timezone 2>/dev/null || printf "")
elif [[ "$OSTYPE" == "darwin"* ]]; then
system_tz=$(ls -la /etc/localtime 2>/dev/null | sed 's/.*zoneinfo\///' || echo "")
system_tz=$(ls -la /etc/localtime 2>/dev/null | sed 's/.*zoneinfo\///' || printf "")
fi

# Get current timezone from docker-compose.yml
local current_tz=$(grep "TIMEZONE:" docker-compose.yml | awk '{print $2}' 2>/dev/null || echo "")
local current_tz=$(grep "TIMEZONE:" docker-compose.yml | awk '{print $2}' 2>/dev/null || printf "")
local default_tz="${system_tz:-America/Mexico_City}"

printf "🌍 Timezone Configuration:\n"
Expand Down Expand Up @@ -564,7 +564,7 @@ configure_additional_directories() {

# Get and show numbered list
get_current_mounts "true"
local mount_count=$(cat /tmp/mount_count 2>/dev/null || echo "0")
local mount_count=$(cat /tmp/mount_count 2>/dev/null || printf "0")

if [[ "$mount_count" -eq 0 ]]; then
printf "\n"
Expand Down
Loading