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
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,11 @@ mlh docker in web
```

> **💡 Note:** `mlh docker in` automatically detects if Docker requires sudo permissions and uses `sudo docker` when needed. You don't need to run `sudo mlh docker in` - just run `mlh docker in <pattern>` and it will handle sudo automatically if required.
>
> **⚠️ Troubleshooting:** If you get `mlh: command not found` when running `sudo mlh docker in`, it's because `sudo` resets the PATH. Solutions:
> - **Recommended:** Run without sudo: `mlh docker in <pattern>` (script handles sudo internally)
> - **Alternative:** Use `sudo -E env PATH=$PATH mlh docker in <pattern>` to preserve PATH
> - **Best long-term:** Add your user to the docker group: `sudo usermod -aG docker $USER` (then logout/login)

---

Expand Down
48 changes: 40 additions & 8 deletions get-mlh.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ set -euo pipefail
# ====== Your repo ======
REPO_OWNER="melihcelenk"
REPO_NAME="MyLinuxHelper"
REPO_BRANCH="release/test"
REPO_BRANCH="bookmark-list-category-hierarchy"
# =======================

REPO_TARBALL_URL="https://codeload.github.com/${REPO_OWNER}/${REPO_NAME}/tar.gz/refs/heads/${REPO_BRANCH}"
Expand Down Expand Up @@ -64,26 +64,58 @@ download_repo() {
if command -v git >/dev/null 2>&1; then
if [ -d "${INSTALL_DIR}/.git" ]; then
green "Updating repo (git pull)…"
git -C "${INSTALL_DIR}" fetch --all --depth=1
git -C "${INSTALL_DIR}" checkout "${REPO_BRANCH}"
git -C "${INSTALL_DIR}" reset --hard "origin/${REPO_BRANCH}"
# First, fetch all branches to ensure we have the remote branch
git -C "${INSTALL_DIR}" fetch origin 2>/dev/null || true
# Try to checkout the branch
if git -C "${INSTALL_DIR}" checkout "${REPO_BRANCH}" 2>/dev/null; then
# Branch exists locally, pull latest changes
git -C "${INSTALL_DIR}" pull origin "${REPO_BRANCH}" 2>/dev/null || \
git -C "${INSTALL_DIR}" reset --hard "origin/${REPO_BRANCH}" 2>/dev/null
elif git -C "${INSTALL_DIR}" checkout -b "${REPO_BRANCH}" "origin/${REPO_BRANCH}" 2>/dev/null; then
# Successfully created tracking branch
:
else
# Branch doesn't exist, remove and re-clone
green "Branch not found, re-cloning repository…"
rm -rf "${INSTALL_DIR}"
git clone --depth=1 --branch "${REPO_BRANCH}" "${REPO_GIT_URL}" "${INSTALL_DIR}" 2>/dev/null || \
git clone --branch "${REPO_BRANCH}" "${REPO_GIT_URL}" "${INSTALL_DIR}"
fi
else
green "Cloning repo (git)…"
git clone --depth=1 --branch "${REPO_BRANCH}" "${REPO_GIT_URL}" "${INSTALL_DIR}"
git clone --depth=1 --branch "${REPO_BRANCH}" "${REPO_GIT_URL}" "${INSTALL_DIR}" 2>/dev/null || {
# If shallow clone fails, try full clone
git clone --branch "${REPO_BRANCH}" "${REPO_GIT_URL}" "${INSTALL_DIR}"
}
fi
else
green "Downloading repo (tarball)…"
rm -rf "${INSTALL_DIR}.tmp"
mkdir -p "${INSTALL_DIR}.tmp"
local dlr
dlr="$(ensure_downloader)"
# GitHub tarball URL (no encoding needed for simple branch names)
local tarball_url="https://codeload.github.com/${REPO_OWNER}/${REPO_NAME}/tar.gz/refs/heads/${REPO_BRANCH}"
if [ "$dlr" = "curl" ]; then
curl -fsSL "${REPO_TARBALL_URL}" | tar -xz -C "${INSTALL_DIR}.tmp"
curl -fsSL "${tarball_url}" | tar -xz -C "${INSTALL_DIR}.tmp"
else
wget -qO- "${REPO_TARBALL_URL}" | tar -xz -C "${INSTALL_DIR}.tmp"
wget -qO- "${tarball_url}" | tar -xz -C "${INSTALL_DIR}.tmp"
fi
rm -rf "${INSTALL_DIR}"
mv "${INSTALL_DIR}.tmp/${REPO_NAME}-${REPO_BRANCH}" "${INSTALL_DIR}"
# Tarball extracts to directory with branch name
if [ -d "${INSTALL_DIR}.tmp/${REPO_NAME}-${REPO_BRANCH}" ]; then
mv "${INSTALL_DIR}.tmp/${REPO_NAME}-${REPO_BRANCH}" "${INSTALL_DIR}"
else
# Find the extracted directory (fallback)
local extracted_dir
extracted_dir=$(find "${INSTALL_DIR}.tmp" -mindepth 1 -maxdepth 1 -type d | head -1)
if [ -n "$extracted_dir" ]; then
mv "$extracted_dir" "${INSTALL_DIR}"
else
echo "Error: Could not find extracted directory"
exit 1
fi
fi
rm -rf "${INSTALL_DIR}.tmp"
fi
}
Expand Down
124 changes: 101 additions & 23 deletions plugins/mlh-docker.sh
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@
# Examples:
# mlh docker in mycontainer # Enter container with 'mycontainer' in name

set -euo pipefail
set -uo pipefail
# Note: We don't use 'set -e' because we need to handle errors manually
# for proper sudo detection and error messages

print_help() {
cat <<'EOF'
Expand Down Expand Up @@ -69,6 +71,18 @@ in)
DOCKER_BIN=""
USE_SUDO=0

# Force use of system Docker daemon at /var/run/docker.sock
# Docker Desktop socket may be configured but not running
# Check if system Docker socket exists, if so use it
if [ -S "/var/run/docker.sock" ]; then
# Use system Docker daemon explicitly
export DOCKER_HOST="unix:///var/run/docker.sock"
elif [ -n "${DOCKER_HOST:-}" ] && echo "$DOCKER_HOST" | grep -q "docker-desktop\|\.docker/desktop"; then
# Docker Desktop socket configured but may not be running
# Unset it to let Docker client use default
unset DOCKER_HOST
fi

if command -v docker >/dev/null 2>&1; then
DOCKER_BIN="docker"
elif [ -x "/usr/bin/docker" ]; then
Expand All @@ -87,66 +101,115 @@ in)
PATTERN="$1"

# Helper function to run docker command (with or without sudo)
# Use sudo -E to preserve environment variables (especially PATH)
run_docker() {
if [ "$USE_SUDO" -eq 1 ]; then
sudo "$DOCKER_BIN" "$@"
sudo -E "$DOCKER_BIN" "$@"
else
"$DOCKER_BIN" "$@"
fi
}

# Test Docker access and determine if sudo is needed
# First, try without sudo
DOCKER_TEST_OUTPUT=$("$DOCKER_BIN" ps --format "{{.ID}}" 2>&1)
# Strategy: Always try without sudo first, if it fails with permission error, use sudo
DOCKER_TEST_CMD="$DOCKER_BIN ps --format '{{.ID}}'"
DOCKER_TEST_OUTPUT=$($DOCKER_TEST_CMD 2>&1)
DOCKER_TEST_EXIT=$?

# Check if we need sudo
if [ $DOCKER_TEST_EXIT -ne 0 ]; then
# Docker command failed - check if it's a permission/connection error
# Common error patterns: permission denied, cannot connect, permission denied while trying to connect
if echo "$DOCKER_TEST_OUTPUT" | grep -qiE "permission denied|cannot connect to the docker daemon|Got permission denied|permission denied while trying to connect"; then
# Permission/connection error - try with sudo
# Check if it's a permission error
if echo "$DOCKER_TEST_OUTPUT" | grep -qiE "permission denied|cannot connect to the docker daemon|Got permission denied|permission denied while trying to connect|dial unix.*permission denied"; then
# Try with sudo (but handle password prompts gracefully)
if command -v sudo >/dev/null 2>&1; then
# Test if sudo docker works
SUDO_TEST_OUTPUT=$(sudo "$DOCKER_BIN" ps --format "{{.ID}}" 2>&1)
SUDO_TEST_EXIT=$?
if [ $SUDO_TEST_EXIT -eq 0 ]; then
USE_SUDO=1
# Check if we're in an interactive terminal (TTY)
if [ -t 0 ] && [ -t 1 ]; then
# Interactive mode: Try sudo (may prompt for password)
SUDO_TEST_OUTPUT=$(sudo $DOCKER_TEST_CMD 2>&1)
SUDO_TEST_EXIT=$?
if [ $SUDO_TEST_EXIT -eq 0 ]; then
USE_SUDO=1
else
# Check if it's a password prompt error
if echo "$SUDO_TEST_OUTPUT" | grep -qiE "password is required|a terminal is required"; then
die "Docker requires sudo permissions, but password authentication failed. Please run: sudo mlh docker in $PATTERN"
else
die "Cannot access Docker daemon even with sudo. Error: $SUDO_TEST_OUTPUT"
fi
fi
else
# Sudo also failed - show the error
die "Cannot access Docker daemon even with sudo. Error: $SUDO_TEST_OUTPUT"
# Non-interactive mode: Cannot prompt for password
# Check if sudo can work without password (NOPASSWD)
SUDO_TEST_OUTPUT=$(sudo -n $DOCKER_TEST_CMD 2>&1)
SUDO_TEST_EXIT=$?
if [ $SUDO_TEST_EXIT -eq 0 ]; then
USE_SUDO=1
else
# Sudo requires password but we're non-interactive
die "Docker requires sudo permissions, but we're in a non-interactive session. Please either:
1. Run this command in an interactive terminal: mlh docker in $PATTERN
2. Or run with sudo directly: sudo mlh docker in $PATTERN
3. Or add your user to the docker group: sudo usermod -aG docker \$USER (then logout/login)
Original error: $DOCKER_TEST_OUTPUT"
fi
fi
else
die "Docker requires sudo permissions but sudo is not available. Install sudo or add user to docker group. Original error: $DOCKER_TEST_OUTPUT"
die "Docker requires sudo permissions, but sudo is not available. Error: $DOCKER_TEST_OUTPUT"
fi
else
# Other error (not permission related) - could be daemon not running, etc.
# Other error
die "Docker command failed: $DOCKER_TEST_OUTPUT"
fi
fi

# Find matching containers (running only)
# Use run_docker function which handles sudo automatically
# Important: Use run_docker here, not direct docker command
CONTAINERS_OUTPUT=$(run_docker ps --format "{{.ID}}|{{.Names}}" 2>&1)
CONTAINERS_EXIT=$?

if [ $CONTAINERS_EXIT -ne 0 ]; then
die "Failed to list Docker containers: $CONTAINERS_OUTPUT"
die "Failed to list Docker containers. Exit code: $CONTAINERS_EXIT. Error: $CONTAINERS_OUTPUT"
fi

# Check if we got any output at all (even empty line means no containers)
if [ -z "$CONTAINERS_OUTPUT" ] || [ "$(echo "$CONTAINERS_OUTPUT" | tr -d '\n' | tr -d ' ')" = "" ]; then
die "No containers are currently running. Start a container first."
fi

# Filter containers by pattern (case-insensitive)
mapfile -t CONTAINERS < <(echo "$CONTAINERS_OUTPUT" | grep -i "$PATTERN" || true)

if [ ${#CONTAINERS[@]} -eq 0 ]; then
die "No running containers found matching pattern: $PATTERN"
# Show available containers to help user
AVAILABLE=$(echo "$CONTAINERS_OUTPUT" | cut -d'|' -f2 | tr '\n' ',' | sed 's/,$//' | sed 's/,/, /g')
die "No running containers found matching pattern: $PATTERN. Available containers: $AVAILABLE"
fi

if [ ${#CONTAINERS[@]} -eq 1 ]; then
# Single match - enter directly
CONTAINER_ID="${CONTAINERS[0]%%|*}"
CONTAINER_NAME="${CONTAINERS[0]##*|}"
echo "Entering container: $CONTAINER_NAME"
# Try bash first, then sh if bash is not available
if [ "$USE_SUDO" -eq 1 ]; then
exec sudo "$DOCKER_BIN" exec -it "$CONTAINER_ID" bash
# Check if bash is available in container
if sudo "$DOCKER_BIN" exec "$CONTAINER_ID" which bash >/dev/null 2>&1; then
exec sudo "$DOCKER_BIN" exec -it "$CONTAINER_ID" bash
elif sudo "$DOCKER_BIN" exec "$CONTAINER_ID" which sh >/dev/null 2>&1; then
exec sudo "$DOCKER_BIN" exec -it "$CONTAINER_ID" sh
else
die "Neither bash nor sh found in container $CONTAINER_NAME"
fi
else
exec "$DOCKER_BIN" exec -it "$CONTAINER_ID" bash
# Check if bash is available in container
if "$DOCKER_BIN" exec "$CONTAINER_ID" which bash >/dev/null 2>&1; then
exec "$DOCKER_BIN" exec -it "$CONTAINER_ID" bash
elif "$DOCKER_BIN" exec "$CONTAINER_ID" which sh >/dev/null 2>&1; then
exec "$DOCKER_BIN" exec -it "$CONTAINER_ID" sh
else
die "Neither bash nor sh found in container $CONTAINER_NAME"
fi
fi
else
# Multiple matches - show menu
Expand Down Expand Up @@ -176,10 +239,25 @@ in)

echo ""
echo "Entering container: $CONTAINER_NAME"
# Try bash first, then sh if bash is not available
if [ "$USE_SUDO" -eq 1 ]; then
exec sudo "$DOCKER_BIN" exec -it "$CONTAINER_ID" bash
# Check if bash is available in container
if sudo "$DOCKER_BIN" exec "$CONTAINER_ID" which bash >/dev/null 2>&1; then
exec sudo "$DOCKER_BIN" exec -it "$CONTAINER_ID" bash
elif sudo "$DOCKER_BIN" exec "$CONTAINER_ID" which sh >/dev/null 2>&1; then
exec sudo "$DOCKER_BIN" exec -it "$CONTAINER_ID" sh
else
die "Neither bash nor sh found in container $CONTAINER_NAME"
fi
else
exec "$DOCKER_BIN" exec -it "$CONTAINER_ID" bash
# Check if bash is available in container
if "$DOCKER_BIN" exec "$CONTAINER_ID" which bash >/dev/null 2>&1; then
exec "$DOCKER_BIN" exec -it "$CONTAINER_ID" bash
elif "$DOCKER_BIN" exec "$CONTAINER_ID" which sh >/dev/null 2>&1; then
exec "$DOCKER_BIN" exec -it "$CONTAINER_ID" sh
else
die "Neither bash nor sh found in container $CONTAINER_NAME"
fi
fi
fi
;;
Expand Down
Loading