diff --git a/README.md b/README.md index a0e0e18..238f303 100644 --- a/README.md +++ b/README.md @@ -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 ` 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 ` (script handles sudo internally) +> - **Alternative:** Use `sudo -E env PATH=$PATH mlh docker in ` to preserve PATH +> - **Best long-term:** Add your user to the docker group: `sudo usermod -aG docker $USER` (then logout/login) --- diff --git a/get-mlh.sh b/get-mlh.sh index 8d1bcc5..02ef58a 100755 --- a/get-mlh.sh +++ b/get-mlh.sh @@ -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}" @@ -64,12 +64,29 @@ 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)…" @@ -77,13 +94,28 @@ download_repo() { 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 } diff --git a/plugins/mlh-docker.sh b/plugins/mlh-docker.sh index 9eed635..83126b8 100755 --- a/plugins/mlh-docker.sh +++ b/plugins/mlh-docker.sh @@ -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' @@ -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 @@ -87,55 +101,89 @@ 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 @@ -143,10 +191,25 @@ in) 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 @@ -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 ;;