From ad0ede8acd761c5e55d73f5c20a51c2789688888 Mon Sep 17 00:00:00 2001 From: Bui Dai Date: Thu, 11 Dec 2025 23:33:42 +0700 Subject: [PATCH 1/8] feat: implement unified logging and blocking zrok tunnel --- logging_utils.sh | 120 +++++++++++++++++++++++++ setup.sh | 47 ++++------ setup_kaggle_zrok.sh | 65 +++++++------- start_zrok.sh | 57 +++++++++--- tests/unit/test_argument_parsing.bats | 3 +- tests/unit/test_logging.bats | 125 ++++++++++++++++++++++++++ tests/unit/test_url_validation.bats | 10 ++- 7 files changed, 354 insertions(+), 73 deletions(-) create mode 100644 logging_utils.sh create mode 100644 tests/unit/test_logging.bats diff --git a/logging_utils.sh b/logging_utils.sh new file mode 100644 index 0000000..8099961 --- /dev/null +++ b/logging_utils.sh @@ -0,0 +1,120 @@ +#!/bin/bash +# Shared logging utilities for kagglelink scripts +# +# This library provides consistent logging functions with emojis, +# timestamps, and error categorization for all kagglelink scripts. +# +# Usage: +# source logging_utils.sh +# log_info "Starting operation..." +# log_success "Operation completed" +# log_error "Something went wrong" + +# Store step start times for elapsed time calculation +declare -A _STEP_START_TIMES + +# Log an informational message with ⏳ emoji and timestamp +# Args: +# $1: Message to log +# Output: Formatted message to stdout +log_info() { + echo "⏳ [$(date +%H:%M:%S)] $1" +} + +# Log a success message with ✅ emoji and timestamp +# Args: +# $1: Message to log +# Output: Formatted message to stdout +log_success() { + echo "✅ [$(date +%H:%M:%S)] $1" +} + +# Log an error message with ❌ emoji and timestamp to stderr +# Args: +# $1: Message to log +# Output: Formatted error message to stderr +log_error() { + echo "❌ [$(date +%H:%M:%S)] ERROR: $1" >&2 +} + +# Start tracking a step for elapsed time calculation +# Args: +# $1: Step name +# Output: Informational log message +log_step_start() { + local step_name="$1" + _STEP_START_TIMES["$step_name"]=$(date +%s) + log_info "$step_name..." +} + +# Complete a step and display elapsed time +# Args: +# $1: Step name +# Output: Success message with elapsed time +log_step_complete() { + local step_name="$1" + local start_time="${_STEP_START_TIMES[$step_name]}" + if [ -n "$start_time" ]; then + local elapsed=$(($(date +%s) - start_time)) + log_success "$step_name completed (${elapsed}s)" + else + log_success "$step_name completed" + fi +} + +# Categorize and display error with contextual guidance +# Args: +# $1: Error type (prerequisite, network, upstream) +# $2: Error message +# $3: Suggested action +# Output: Formatted error with category-specific emoji and guidance to stderr +categorize_error() { + local error_type="$1" + local message="$2" + local suggestion="$3" + + case "$error_type" in + "prerequisite") + log_error "$message" + echo " 💡 Action required: $suggestion" >&2 + ;; + "network") + log_error "$message" + echo " 🌐 Check connectivity: $suggestion" >&2 + ;; + "upstream") + log_error "$message" + echo " 🔧 Upstream issue: $suggestion" >&2 + ;; + *) + log_error "$message" + ;; + esac +} + +# Display success banner with Zrok share token and connection instructions +# Args: +# $1: Zrok share token +# Output: Formatted success banner to stdout +show_success_banner() { + local share_token="$1" + echo "" + echo "╔════════════════════════════════════════════════════════════════╗" + echo "║ ✅ Setup Complete! ║" + echo "╠════════════════════════════════════════════════════════════════╣" + echo "║ ║" + echo "║ Your Kaggle instance is ready for remote access! ║" + echo "║ ║" + echo "║ 📡 Zrok Share Token: $share_token" + echo "║ ║" + echo "║ 🖥️ On your LOCAL machine, run: ║" + echo "║ ║" + echo "║ zrok access private $share_token" + echo "║ ║" + echo "║ Then connect via SSH: ║" + echo "║ ║" + echo "║ ssh -p 9191 root@127.0.0.1 ║" + echo "║ ║" + echo "╚════════════════════════════════════════════════════════════════╝" + echo "" +} diff --git a/setup.sh b/setup.sh index 5c07748..aa4d963 100755 --- a/setup.sh +++ b/setup.sh @@ -2,6 +2,10 @@ set -e +# Source logging utilities +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +source "$SCRIPT_DIR/logging_utils.sh" + # Version and branch configuration KAGGLELINK_VERSION="1.1.0" KAGGLELINK_BRANCH="${BRANCH:-main}" @@ -9,18 +13,13 @@ KAGGLELINK_BRANCH="${BRANCH:-main}" # Security: Validate KAGGLELINK_BRANCH to prevent argument injection # Branch names must not start with '-' to prevent git argument injection if [[ "$KAGGLELINK_BRANCH" =~ ^- ]]; then - echo "❌ Error: Invalid branch name '$KAGGLELINK_BRANCH'" - echo " Branch names cannot start with '-' (security: prevents argument injection)" + categorize_error "prerequisite" "Invalid branch name '$KAGGLELINK_BRANCH'" "Branch names cannot start with '-' (security: prevents argument injection)" exit 1 fi # Reliability: Check for git installation if ! command -v git &> /dev/null; then - echo "❌ Error: git is not installed" - echo " Please install git and try again" - echo " - Debian/Ubuntu: sudo apt-get install git" - echo " - RHEL/CentOS: sudo yum install git" - echo " - macOS: brew install git" + categorize_error "prerequisite" "git is not installed" "Install git: apt-get install git (Debian/Ubuntu), yum install git (RHEL/CentOS), or brew install git (macOS)" exit 1 fi @@ -117,45 +116,35 @@ fi # Validate that AUTH_KEYS_URL uses HTTPS (security requirement) if [[ ! "$AUTH_KEYS_URL" =~ ^https:// ]]; then - echo "❌ Error: Keys URL must use HTTPS (not HTTP)" - echo " Insecure URL: $AUTH_KEYS_URL" + categorize_error "prerequisite" "Keys URL must use HTTPS (not HTTP): $AUTH_KEYS_URL" "Use HTTPS URL instead" if [[ "$AUTH_KEYS_URL" =~ ^http:// ]]; then - echo " Use: ${AUTH_KEYS_URL/http:/https:}" - else - echo " URL must start with https://" + echo " Suggested: ${AUTH_KEYS_URL/http:/https:}" >&2 fi exit 1 fi -echo "⏳ Cloning repository..." +log_step_start "Cloning repository" if [ -d "$INSTALL_DIR" ]; then - echo "Repository directory already exists. Removing it..." + log_info "Repository directory already exists. Removing it..." rm -rf "$INSTALL_DIR" fi if ! git clone -b "$KAGGLELINK_BRANCH" "$REPO_URL" "$INSTALL_DIR"; then - echo "❌ Error: Failed to clone branch '$KAGGLELINK_BRANCH'" - echo " Possible reasons:" - echo " - Branch does not exist" - echo " - Network connectivity issues" - echo " - GitHub is unreachable" + categorize_error "network" "Failed to clone branch '$KAGGLELINK_BRANCH'" "Check branch exists and network connectivity" exit 1 fi -echo "✅ Cloned repository (branch: ${KAGGLELINK_BRANCH})" +log_step_complete "Cloning repository" -echo "⏳ Changing to repository directory..." +log_info "Changing to repository directory..." cd "$INSTALL_DIR" -echo "⏳ Making scripts executable..." +log_info "Making scripts executable..." chmod +x setup_kaggle_zrok.sh start_zrok.sh -echo "⏳ Setting up SSH with your public keys..." +log_step_start "Setting up SSH with your public keys" ./setup_kaggle_zrok.sh "$AUTH_KEYS_URL" +log_step_complete "Setting up SSH with your public keys" -echo "⏳ Starting zrok service with your token..." +log_info "Starting zrok service with your token..." +# Note: start_zrok.sh is a blocking process that will display success banner ./start_zrok.sh "$ZROK_TOKEN" - -echo "✅ Setup complete!" -echo "✅ You should now be able to connect to your Kaggle instance via SSH." -echo "✅ If you see a URL above, use that to connect from your local machine." -echo "✅ For more information, visit: https://github.com/bhdai/kagglelink" diff --git a/setup_kaggle_zrok.sh b/setup_kaggle_zrok.sh index 6694aa2..89718b3 100644 --- a/setup_kaggle_zrok.sh +++ b/setup_kaggle_zrok.sh @@ -2,6 +2,10 @@ set -e +# Source logging utilities +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +source "$SCRIPT_DIR/logging_utils.sh" + if [ "$#" -ne 1 ]; then echo "Usage: ./setup_kaggle_zrok.sh " exit 1 @@ -10,16 +14,16 @@ fi AUTH_KEYS_URL=$1 setup_ssh_directory() { - echo "Setting up SSH directory in user's home..." + log_info "Setting up SSH directory in user's home..." # If running as root, $HOME/.ssh becomes /root/.ssh local ssh_dir_path="$HOME/.ssh" mkdir -p "$ssh_dir_path" if wget -qO "$ssh_dir_path/authorized_keys" "$AUTH_KEYS_URL"; then chmod 700 "$ssh_dir_path" chmod 600 "$ssh_dir_path/authorized_keys" - echo "SSH directory and authorized_keys set up in $ssh_dir_path" + log_success "SSH directory and authorized_keys set up in $ssh_dir_path" else - echo "Failed to download authorized keys from $AUTH_KEYS_URL to $ssh_dir_path/authorized_keys." + categorize_error "network" "Failed to download authorized keys from $AUTH_KEYS_URL" "Check URL is accessible and internet connectivity" exit 1 fi } @@ -30,26 +34,26 @@ copy_vscode_dir() { [ -d "/kaggle/.vscode" ] && rm -rf "/kaggle/.vscode" mkdir -p "/kaggle/.vscode" cp -r "$vscode_dir_in_repo/"* "/kaggle/.vscode/" - echo ".vscode folder copied to /kaggle directory." + log_info ".vscode folder copied to /kaggle directory." mkdir -p "/kaggle/tmp" [ -d "/kaggle/working/.vscode" ] && rm -rf "/kaggle/working/.vscode" mkdir -p "/kaggle/working/.vscode" cp -r "$vscode_dir_in_repo/"* "/kaggle/working/.vscode/" - echo ".vscode folder copied to /kaggle/working directory." + log_info ".vscode folder copied to /kaggle/working directory." - echo "Contents of /kaggle/.vscode:" + log_info "Contents of /kaggle/.vscode:" ls -l "/kaggle/.vscode" - echo "Contents of /kaggle/working/.vscode:" + log_info "Contents of /kaggle/working/.vscode:" ls -l "/kaggle/working/.vscode" else - echo ".vscode directory not found in repository at $vscode_dir_in_repo." + log_error ".vscode directory not found in repository at $vscode_dir_in_repo." fi } configure_sshd() { mkdir -p /var/run/sshd - echo "Configuring sshd..." + log_info "Configuring sshd..." cat <>/etc/ssh/sshd_config Port 22 Protocol 2 @@ -73,22 +77,22 @@ ClientAliveInterval 60 ClientAliveCountMax 2 EOF echo "" >>/etc/ssh/sshd_config - echo "sshd_config updated. Note: Appended settings. Ensure no conflicting duplicates exist if run multiple times." + log_success "sshd_config updated. Note: Appended settings. Ensure no conflicting duplicates exist if run multiple times." - echo "Configuring debconf for non-interactive mode..." + log_info "Configuring debconf for non-interactive mode..." echo 'debconf debconf/frontend select Noninteractive' | debconf-set-selections - echo "debconf configured to use Noninteractive frontend." + log_success "debconf configured to use Noninteractive frontend." # Disable pam_systemd for container compatibility - echo "Disabling pam_systemd..." + log_info "Disabling pam_systemd..." sed -i 's/^session.*pam_systemd.so/#&/' /etc/pam.d/common-session # Disable man-db postinst to prevent crashes - echo "Disabling man-db postinst script..." + log_info "Disabling man-db postinst script..." dpkg-divert --quiet --local --rename --add /var/lib/dpkg/info/man-db.postinst ln -sf /bin/true /var/lib/dpkg/info/man-db.postinst - echo "Container compatibility fixes applied." + log_success "Container compatibility fixes applied." } setup_environment_variables() { @@ -142,40 +146,42 @@ EOT } install_packages() { - echo "Installing openssh-server..." + log_step_start "Installing packages" sudo apt-get update sudo apt-get install -y openssh-server nvtop screen lshw + log_step_complete "Installing packages" + log_info "Installing uv..." curl -LsSf https://astral.sh/uv/install.sh | sh } install_zrok() { - echo "Downloading latest zrok release" + log_step_start "Downloading and installing Zrok" curl -s https://api.github.com/repos/openziti/zrok/releases/latest | grep "browser_download_url.*linux_amd64.tar.gz" | cut -d : -f 2,3 | tr -d \" | wget -qi - - echo "Extracting Zrok" + log_info "Extracting Zrok" if ! tar -xzf zrok_*_linux_amd64.tar.gz -C /usr/local/bin/; then - echo "ERROR: Failed to extract Zrok" + categorize_error "network" "Failed to extract Zrok" "Check downloaded tar file integrity" exit 1 fi rm zrok_*_linux_amd64.tar.gz # check if zrok is installed correctly if ! zrok version &>/dev/null; then - echo "Error: Zrok install failed" + categorize_error "upstream" "Zrok install failed" "Try manual installation or check Zrok service" exit 1 fi - echo "Zrok installed successfully:" - zrok version + log_step_complete "Downloading and installing Zrok" + log_success "Zrok version: $(zrok version)" } setup_install_extensions_command() { - echo "Setting up 'install_extensions' command..." + log_info "Setting up 'install_extensions' command..." # SCRIPT_DIR will point to the directory where setup_kaggle_zrok.sh is located local SCRIPT_DIR SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd) @@ -186,16 +192,15 @@ setup_install_extensions_command() { mkdir -p /usr/local/bin # Ensure target directory exists cp "$install_script_source" "$install_script_target" chmod +x "$install_script_target" - echo "'install_extensions' command is now available from $install_script_target." - echo "You can run 'install_extensions' in your terminal after SSHing." + log_success "'install_extensions' command is now available from $install_script_target." else - echo "Warning: $install_script_source not found. 'install_extensions' command not set up." + log_error "$install_script_source not found. 'install_extensions' command not set up." fi } start_ssh_service() { service ssh start - echo "SSH service should be running." + log_success "SSH service is running." } copy_screenrc() { @@ -203,9 +208,9 @@ copy_screenrc() { local dest="$HOME/.screenrc" if [ -f "$src" ]; then cp "$src" "$dest" - echo ".screenrc installed to $dest" + log_info ".screenrc installed to $dest" else - echo "Warning: $src not found; skipping .screenrc install." + log_error "$src not found; skipping .screenrc install." fi } @@ -222,4 +227,4 @@ copy_screenrc() { start_ssh_service ) -echo "Setup script completed. SSH service is running. Use start_zrok.sh to start zrok service." +log_success "Setup script completed. SSH service is running. Use start_zrok.sh to start zrok service." diff --git a/start_zrok.sh b/start_zrok.sh index 160754a..5ea927f 100755 --- a/start_zrok.sh +++ b/start_zrok.sh @@ -2,6 +2,10 @@ set -e +# Source logging utilities +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +source "$SCRIPT_DIR/logging_utils.sh" + if [ "$#" -ne 1 ]; then echo "Usage: ./start_zrok.sh " exit 1 @@ -10,27 +14,58 @@ fi ZROK_TOKEN=$1 cleanup() { - echo "Disabling zrok environment..." + log_info "Disabling zrok environment..." zrok disable - echo "Cleanup complete." + log_success "Cleanup complete." } # trap the exit signal to run the cleanup function trap cleanup EXIT -echo "Starting zrok service..." +log_info "Starting zrok service..." if [ -z "$ZROK_TOKEN" ]; then - echo "Error: ZROK_TOKEN not provided." + categorize_error "prerequisite" "ZROK_TOKEN not provided" "Provide token via -t flag" exit 1 fi -echo "Enabling zrok with provided token..." -zrok enable "$ZROK_TOKEN" || { - echo "Failed to enable zrok with provided token." +log_step_start "Enabling zrok with provided token" +if ! zrok enable "$ZROK_TOKEN"; then + categorize_error "upstream" "Failed to enable zrok with provided token" "Verify token is valid or try again later" exit 1 -} +fi +log_step_complete "Enabling zrok with provided token" + +# CRITICAL: Start zrok share in background to capture token BEFORE blocking +log_info "Starting zrok tunnel (capturing share token)..." +SHARE_OUTPUT=$(mktemp) +# Redirect both stdout and stderr, but filter out verbose INFO logs +zrok share private --headless --backend-mode tcpTunnel localhost:22 2>&1 | grep -v "^\[.*INFO.*\]" > "$SHARE_OUTPUT" & +ZROK_PID=$! + +# Poll for share token with timeout (max 30 seconds) +SHARE_TOKEN="" +for i in {1..30}; do + # Look for the access command pattern in output + SHARE_TOKEN=$(grep -oP 'access your share with.*zrok access private \K\S+' "$SHARE_OUTPUT" 2>/dev/null || true) + if [ -n "$SHARE_TOKEN" ]; then + break + fi + sleep 1 +done + +# Clean up temp file +rm -f "$SHARE_OUTPUT" + +if [ -z "$SHARE_TOKEN" ]; then + categorize_error "upstream" "Failed to capture share token within timeout" "Check Zrok service status and logs" + kill $ZROK_PID 2>/dev/null || true + exit 1 +fi + +# Display success banner NOW (before blocking on tunnel) +show_success_banner "$SHARE_TOKEN" -echo "Starting zrok share in headless mode..." -echo "Starting zrok share now..." -zrok share private --headless --backend-mode tcpTunnel localhost:22 +# Keep tunnel alive - wait on background process (blocks here) +log_info "Tunnel is active..." +wait $ZROK_PID diff --git a/tests/unit/test_argument_parsing.bats b/tests/unit/test_argument_parsing.bats index 91a7cc1..c420123 100644 --- a/tests/unit/test_argument_parsing.bats +++ b/tests/unit/test_argument_parsing.bats @@ -8,8 +8,9 @@ load '../test_helper/common' # Setup runs before each test setup() { create_test_dir - # Copy setup.sh to temp dir for isolated testing + # Copy setup.sh and logging_utils.sh to temp dir for isolated testing cp "${PROJECT_ROOT}/setup.sh" "${TEST_TEMP_DIR}/" + cp "${PROJECT_ROOT}/logging_utils.sh" "${TEST_TEMP_DIR}/" cd "${TEST_TEMP_DIR}" } diff --git a/tests/unit/test_logging.bats b/tests/unit/test_logging.bats new file mode 100644 index 0000000..d3a0802 --- /dev/null +++ b/tests/unit/test_logging.bats @@ -0,0 +1,125 @@ +#!/usr/bin/env bats + +# Unit Tests for Logging Utilities +# Story: 1-3-unified-logging-and-user-feedback-system +# Tests AC1-3 and AC5 + +load '../test_helper/common.bash' + +setup() { + # Create temporary test directory + TEST_TEMP_DIR="$(mktemp -d)" + + # Set PROJECT_ROOT for sourcing + PROJECT_ROOT="${BATS_TEST_DIRNAME}/../.." +} + +teardown() { + # Clean up temporary directory + rm -rf "$TEST_TEMP_DIR" +} + +# Task 7.1: Test log_info outputs ⏳ emoji and timestamp +@test "P0: log_info should include ⏳ emoji and timestamp" { + source "${PROJECT_ROOT}/logging_utils.sh" + + run log_info "Test message" + + [ "$status" -eq 0 ] + [[ "$output" == *"⏳"* ]] + [[ "$output" =~ \[[0-9]{2}:[0-9]{2}:[0-9]{2}\] ]] + [[ "$output" == *"Test message"* ]] +} + +# Task 7.2: Test log_success outputs ✅ emoji +@test "P0: log_success should include ✅ emoji and timestamp" { + source "${PROJECT_ROOT}/logging_utils.sh" + + run log_success "Operation completed" + + [ "$status" -eq 0 ] + [[ "$output" == *"✅"* ]] + [[ "$output" =~ \[[0-9]{2}:[0-9]{2}:[0-9]{2}\] ]] + [[ "$output" == *"Operation completed"* ]] +} + +# Task 7.3: Test log_error outputs ❌ emoji to stderr +@test "P0: log_error should output ❌ emoji to stderr" { + source "${PROJECT_ROOT}/logging_utils.sh" + + run bash -c "source ${PROJECT_ROOT}/logging_utils.sh; log_error 'Error occurred' 2>&1 1>/dev/null" + + [ "$status" -eq 0 ] + [[ "$output" == *"❌"* ]] + [[ "$output" == *"ERROR:"* ]] + [[ "$output" == *"Error occurred"* ]] +} + +# Task 7.4: Test elapsed time calculation +@test "P0: log_step_start and log_step_complete should calculate elapsed time" { + # Run in a bash subshell to maintain context between start and complete + run bash -c " + source ${PROJECT_ROOT}/logging_utils.sh + log_step_start 'Test Step' > /dev/null + sleep 1 + log_step_complete 'Test Step' + " + + [ "$status" -eq 0 ] + [[ "$output" == *"✅"* ]] + [[ "$output" == *"Test Step completed"* ]] + [[ "$output" =~ \([0-9]+s\) ]] +} + +# Test categorize_error function with different types +@test "P0: categorize_error should format prerequisite errors" { + source "${PROJECT_ROOT}/logging_utils.sh" + + run bash -c "source ${PROJECT_ROOT}/logging_utils.sh; categorize_error 'prerequisite' 'git is not installed' 'Install git: apt-get install git' 2>&1" + + [ "$status" -eq 0 ] + [[ "$output" == *"❌"* ]] + [[ "$output" == *"git is not installed"* ]] + [[ "$output" == *"💡 Action required:"* ]] + [[ "$output" == *"Install git: apt-get install git"* ]] +} + +@test "P0: categorize_error should format network errors" { + source "${PROJECT_ROOT}/logging_utils.sh" + + run bash -c "source ${PROJECT_ROOT}/logging_utils.sh; categorize_error 'network' 'Failed to download keys' 'Check URL is accessible' 2>&1" + + [ "$status" -eq 0 ] + [[ "$output" == *"❌"* ]] + [[ "$output" == *"Failed to download keys"* ]] + [[ "$output" == *"🌐 Check connectivity:"* ]] + [[ "$output" == *"Check URL is accessible"* ]] +} + +@test "P0: categorize_error should format upstream errors" { + source "${PROJECT_ROOT}/logging_utils.sh" + + run bash -c "source ${PROJECT_ROOT}/logging_utils.sh; categorize_error 'upstream' 'Zrok API failed' 'Try again later' 2>&1" + + [ "$status" -eq 0 ] + [[ "$output" == *"❌"* ]] + [[ "$output" == *"Zrok API failed"* ]] + [[ "$output" == *"🔧 Upstream issue:"* ]] + [[ "$output" == *"Try again later"* ]] +} + +# Task 7.5: Test success banner format +@test "P0: show_success_banner should display formatted banner with token" { + source "${PROJECT_ROOT}/logging_utils.sh" + + test_token="abc123xyz" + run show_success_banner "$test_token" + + [ "$status" -eq 0 ] + [[ "$output" == *"✅ Setup Complete!"* ]] + [[ "$output" == *"$test_token"* ]] + [[ "$output" == *"zrok access private $test_token"* ]] + [[ "$output" == *"ssh -p 9191 root@127.0.0.1"* ]] + [[ "$output" == *"╔"* ]] # Box drawing characters + [[ "$output" == *"╚"* ]] +} diff --git a/tests/unit/test_url_validation.bats b/tests/unit/test_url_validation.bats index 80be210..c0297e1 100755 --- a/tests/unit/test_url_validation.bats +++ b/tests/unit/test_url_validation.bats @@ -18,8 +18,14 @@ setup() { if [[ "$*" == *"clone"* ]]; then target="${@: -1}" mkdir -p "$target" + # Copy logging_utils.sh to mocked repo directory + cp /workspace/logging_utils.sh "$target/" 2>/dev/null || true echo '#!/bin/bash' > "$target/setup_kaggle_zrok.sh" + echo 'source "$(dirname "$0")/logging_utils.sh" 2>/dev/null || true' >> "$target/setup_kaggle_zrok.sh" + echo 'exit 0' >> "$target/setup_kaggle_zrok.sh" echo '#!/bin/bash' > "$target/start_zrok.sh" + echo 'source "$(dirname "$0")/logging_utils.sh" 2>/dev/null || true' >> "$target/start_zrok.sh" + echo 'exit 0' >> "$target/start_zrok.sh" chmod +x "$target/setup_kaggle_zrok.sh" "$target/start_zrok.sh" exit 0 fi @@ -77,8 +83,8 @@ teardown() { @test "P1: error message should explain why HTTP is rejected" { run bash "${PROJECT_ROOT}/setup.sh" -k "http://example.com/keys" -t "test-token" [ "$status" -ne 0 ] - # Should have actionable error message - [[ "$output" == *"Error"* ]] + # Should have actionable error message (case-insensitive check for ERROR or Error) + [[ "$output" =~ [Ee][Rr][Rr][Oo][Rr] ]] [[ "$output" == *"HTTPS"* ]] || [[ "$output" == *"secure"* ]] } From 9b532a0516e9ab565d217e081b726f4430897197 Mon Sep 17 00:00:00 2001 From: Bui Dai Date: Thu, 11 Dec 2025 23:45:08 +0700 Subject: [PATCH 2/8] fix: bootstrap issue - use inline logging in `setup.sh` --- setup.sh | 66 +++++++++++++++++++++++++-- tests/unit/test_argument_parsing.bats | 4 +- 2 files changed, 65 insertions(+), 5 deletions(-) diff --git a/setup.sh b/setup.sh index aa4d963..b911b59 100755 --- a/setup.sh +++ b/setup.sh @@ -2,9 +2,69 @@ set -e -# Source logging utilities -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -source "$SCRIPT_DIR/logging_utils.sh" +# ============================================================================ +# Inline Logging Functions (embedded for bootstrap phase) +# ============================================================================ +# These are embedded directly in setup.sh because this script is downloaded +# standalone before the repository is cloned. Other scripts (setup_kaggle_zrok.sh, +# start_zrok.sh) source logging_utils.sh from the cloned repository. + +# Store step start times for elapsed time calculation +declare -A _STEP_START_TIMES + +log_info() { + echo "⏳ [$(date +%H:%M:%S)] $1" +} + +log_success() { + echo "✅ [$(date +%H:%M:%S)] $1" +} + +log_error() { + echo "❌ [$(date +%H:%M:%S)] ERROR: $1" >&2 +} + +log_step_start() { + local step_name="$1" + _STEP_START_TIMES["$step_name"]=$(date +%s) + log_info "$step_name..." +} + +log_step_complete() { + local step_name="$1" + local start_time="${_STEP_START_TIMES[$step_name]}" + if [ -n "$start_time" ]; then + local elapsed=$(($(date +%s) - start_time)) + log_success "$step_name completed (${elapsed}s)" + else + log_success "$step_name completed" + fi +} + +categorize_error() { + local error_type="$1" + local message="$2" + local suggestion="$3" + + case "$error_type" in + "prerequisite") + log_error "$message" + echo " 💡 Action required: $suggestion" >&2 + ;; + "network") + log_error "$message" + echo " 🌐 Check connectivity: $suggestion" >&2 + ;; + "upstream") + log_error "$message" + echo " 🔧 Upstream issue: $suggestion" >&2 + ;; + *) + log_error "$message" + ;; + esac +} +# ============================================================================ # Version and branch configuration KAGGLELINK_VERSION="1.1.0" diff --git a/tests/unit/test_argument_parsing.bats b/tests/unit/test_argument_parsing.bats index c420123..3a242d4 100644 --- a/tests/unit/test_argument_parsing.bats +++ b/tests/unit/test_argument_parsing.bats @@ -8,9 +8,9 @@ load '../test_helper/common' # Setup runs before each test setup() { create_test_dir - # Copy setup.sh and logging_utils.sh to temp dir for isolated testing + # Copy setup.sh to temp dir for isolated testing + # Note: setup.sh has inline logging functions, no need to copy logging_utils.sh cp "${PROJECT_ROOT}/setup.sh" "${TEST_TEMP_DIR}/" - cp "${PROJECT_ROOT}/logging_utils.sh" "${TEST_TEMP_DIR}/" cd "${TEST_TEMP_DIR}" } From e29407d74bc3deae630086f7fd516a098befab35 Mon Sep 17 00:00:00 2001 From: Bui Dai Date: Thu, 11 Dec 2025 23:52:53 +0700 Subject: [PATCH 3/8] debug --- start_zrok.sh | 49 +++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 41 insertions(+), 8 deletions(-) diff --git a/start_zrok.sh b/start_zrok.sh index 5ea927f..3679b7f 100755 --- a/start_zrok.sh +++ b/start_zrok.sh @@ -38,23 +38,55 @@ log_step_complete "Enabling zrok with provided token" # CRITICAL: Start zrok share in background to capture token BEFORE blocking log_info "Starting zrok tunnel (capturing share token)..." SHARE_OUTPUT=$(mktemp) -# Redirect both stdout and stderr, but filter out verbose INFO logs -zrok share private --headless --backend-mode tcpTunnel localhost:22 2>&1 | grep -v "^\[.*INFO.*\]" > "$SHARE_OUTPUT" & +SHARE_OUTPUT_RAW=$(mktemp) + +# Redirect all output to raw file for debugging, and filtered to regular output +zrok share private --headless --backend-mode tcpTunnel localhost:22 > "$SHARE_OUTPUT_RAW" 2>&1 & ZROK_PID=$! -# Poll for share token with timeout (max 30 seconds) +# Give zrok a moment to start +sleep 2 + +# Poll for share token with timeout (max 60 seconds - increased from 30) SHARE_TOKEN="" -for i in {1..30}; do - # Look for the access command pattern in output +for i in {1..60}; do + # Copy current output for parsing + cp "$SHARE_OUTPUT_RAW" "$SHARE_OUTPUT" 2>/dev/null || true + + # Try multiple regex patterns to find the token + # Pattern 1: "access your share with ... zrok access private TOKEN" SHARE_TOKEN=$(grep -oP 'access your share with.*zrok access private \K\S+' "$SHARE_OUTPUT" 2>/dev/null || true) + + # Pattern 2: Just look for "zrok access private TOKEN" anywhere + if [ -z "$SHARE_TOKEN" ]; then + SHARE_TOKEN=$(grep -oP 'zrok access private \K\S+' "$SHARE_OUTPUT" 2>/dev/null || true) + fi + + # Pattern 3: Look for any token-like string (alphanumeric, starts after "private") + if [ -z "$SHARE_TOKEN" ]; then + SHARE_TOKEN=$(grep -oP 'private\s+\K[a-zA-Z0-9]+' "$SHARE_OUTPUT" 2>/dev/null || true) + fi + if [ -n "$SHARE_TOKEN" ]; then + log_success "Token captured: $SHARE_TOKEN (attempt $i)" break fi + + # Debug output every 10 seconds + if [ $((i % 10)) -eq 0 ]; then + log_info "Still waiting for token... (${i}s elapsed)" + log_info "DEBUG: Output file size: $(wc -l < "$SHARE_OUTPUT" 2>/dev/null || echo 0) lines" + log_info "DEBUG: Full raw output so far:" + cat "$SHARE_OUTPUT" 2>/dev/null | while read line; do + log_info " > $line" + done + fi + sleep 1 done -# Clean up temp file -rm -f "$SHARE_OUTPUT" +# Clean up temp files +rm -f "$SHARE_OUTPUT" "$SHARE_OUTPUT_RAW" if [ -z "$SHARE_TOKEN" ]; then categorize_error "upstream" "Failed to capture share token within timeout" "Check Zrok service status and logs" @@ -66,6 +98,7 @@ fi show_success_banner "$SHARE_TOKEN" # Keep tunnel alive - wait on background process (blocks here) -log_info "Tunnel is active..." +log_info "Tunnel is active. Keeping connection alive..." +log_info "Press Ctrl+C to stop the tunnel and clean up." wait $ZROK_PID From b8e779ca405b2ca8fe09801cf3bdd454db549a10 Mon Sep 17 00:00:00 2001 From: Bui Dai Date: Fri, 12 Dec 2025 00:02:56 +0700 Subject: [PATCH 4/8] fix: token parse regex --- start_zrok.sh | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/start_zrok.sh b/start_zrok.sh index 3679b7f..09172eb 100755 --- a/start_zrok.sh +++ b/start_zrok.sh @@ -55,16 +55,21 @@ for i in {1..60}; do # Try multiple regex patterns to find the token # Pattern 1: "access your share with ... zrok access private TOKEN" - SHARE_TOKEN=$(grep -oP 'access your share with.*zrok access private \K\S+' "$SHARE_OUTPUT" 2>/dev/null || true) + SHARE_TOKEN=$(grep -oP 'access your share with.*zrok access private \K[a-zA-Z0-9]+' "$SHARE_OUTPUT" 2>/dev/null || true) - # Pattern 2: Just look for "zrok access private TOKEN" anywhere + # Pattern 2: Just look for "zrok access private TOKEN" anywhere (stop at first non-alphanumeric) if [ -z "$SHARE_TOKEN" ]; then - SHARE_TOKEN=$(grep -oP 'zrok access private \K\S+' "$SHARE_OUTPUT" 2>/dev/null || true) + SHARE_TOKEN=$(grep -oP 'zrok access private \K[a-zA-Z0-9]+' "$SHARE_OUTPUT" 2>/dev/null || true) fi - # Pattern 3: Look for any token-like string (alphanumeric, starts after "private") + # Pattern 3: Look for token in JSON format: "token":"VALUE" if [ -z "$SHARE_TOKEN" ]; then - SHARE_TOKEN=$(grep -oP 'private\s+\K[a-zA-Z0-9]+' "$SHARE_OUTPUT" 2>/dev/null || true) + SHARE_TOKEN=$(grep -oP '"token"\s*:\s*"\K[a-zA-Z0-9]+' "$SHARE_OUTPUT" 2>/dev/null || true) + fi + + # Pattern 4: Look for "private" followed by alphanumeric token (stop at quote or comma) + if [ -z "$SHARE_TOKEN" ]; then + SHARE_TOKEN=$(grep -oP 'private\s+\K[a-zA-Z0-9]+(?=[",\s])' "$SHARE_OUTPUT" 2>/dev/null || true) fi if [ -n "$SHARE_TOKEN" ]; then From 3e9a2dfafde8e8f4749e7d34c236bbb6b1dd553f Mon Sep 17 00:00:00 2001 From: Bui Dai Date: Fri, 12 Dec 2025 00:22:28 +0700 Subject: [PATCH 5/8] perf: better token parsing --- start_zrok.sh | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/start_zrok.sh b/start_zrok.sh index 09172eb..0c6f976 100755 --- a/start_zrok.sh +++ b/start_zrok.sh @@ -40,36 +40,31 @@ log_info "Starting zrok tunnel (capturing share token)..." SHARE_OUTPUT=$(mktemp) SHARE_OUTPUT_RAW=$(mktemp) -# Redirect all output to raw file for debugging, and filtered to regular output +# Redirect all output to raw file for debugging zrok share private --headless --backend-mode tcpTunnel localhost:22 > "$SHARE_OUTPUT_RAW" 2>&1 & ZROK_PID=$! -# Give zrok a moment to start -sleep 2 +# Give zrok more time to establish tunnel and output token (increased from 2s to 8s) +sleep 8 -# Poll for share token with timeout (max 60 seconds - increased from 30) +# Poll for share token with timeout (max 60 seconds) SHARE_TOKEN="" for i in {1..60}; do # Copy current output for parsing cp "$SHARE_OUTPUT_RAW" "$SHARE_OUTPUT" 2>/dev/null || true # Try multiple regex patterns to find the token - # Pattern 1: "access your share with ... zrok access private TOKEN" - SHARE_TOKEN=$(grep -oP 'access your share with.*zrok access private \K[a-zA-Z0-9]+' "$SHARE_OUTPUT" 2>/dev/null || true) + # Pattern 1: JSON format (non-TTY) - look inside "msg" field for "zrok access private TOKEN" + SHARE_TOKEN=$(grep -oP '"msg":"[^"]*zrok access private \K[a-zA-Z0-9]+' "$SHARE_OUTPUT" 2>/dev/null || true) - # Pattern 2: Just look for "zrok access private TOKEN" anywhere (stop at first non-alphanumeric) + # Pattern 2: Plain text format (TTY) - look for "zrok access private TOKEN" if [ -z "$SHARE_TOKEN" ]; then SHARE_TOKEN=$(grep -oP 'zrok access private \K[a-zA-Z0-9]+' "$SHARE_OUTPUT" 2>/dev/null || true) fi - # Pattern 3: Look for token in JSON format: "token":"VALUE" + # Pattern 3: Look for token on line containing "allow other to access" if [ -z "$SHARE_TOKEN" ]; then - SHARE_TOKEN=$(grep -oP '"token"\s*:\s*"\K[a-zA-Z0-9]+' "$SHARE_OUTPUT" 2>/dev/null || true) - fi - - # Pattern 4: Look for "private" followed by alphanumeric token (stop at quote or comma) - if [ -z "$SHARE_TOKEN" ]; then - SHARE_TOKEN=$(grep -oP 'private\s+\K[a-zA-Z0-9]+(?=[",\s])' "$SHARE_OUTPUT" 2>/dev/null || true) + SHARE_TOKEN=$(grep "allow other to access" "$SHARE_OUTPUT" 2>/dev/null | grep -oP 'zrok access private \K[a-zA-Z0-9]+' || true) fi if [ -n "$SHARE_TOKEN" ]; then From 806688f5e2a02c209995d47a9dafc0fc0d866299 Mon Sep 17 00:00:00 2001 From: Bui Dai Date: Fri, 12 Dec 2025 01:00:45 +0700 Subject: [PATCH 6/8] feat: use gum for make prettier banner --- logging_utils.sh | 59 ++++++++++++++++++++++++++++++-------------- setup_kaggle_zrok.sh | 9 ++++++- 2 files changed, 48 insertions(+), 20 deletions(-) diff --git a/logging_utils.sh b/logging_utils.sh index 8099961..7e6b53b 100644 --- a/logging_utils.sh +++ b/logging_utils.sh @@ -98,23 +98,44 @@ categorize_error() { # Output: Formatted success banner to stdout show_success_banner() { local share_token="$1" - echo "" - echo "╔════════════════════════════════════════════════════════════════╗" - echo "║ ✅ Setup Complete! ║" - echo "╠════════════════════════════════════════════════════════════════╣" - echo "║ ║" - echo "║ Your Kaggle instance is ready for remote access! ║" - echo "║ ║" - echo "║ 📡 Zrok Share Token: $share_token" - echo "║ ║" - echo "║ 🖥️ On your LOCAL machine, run: ║" - echo "║ ║" - echo "║ zrok access private $share_token" - echo "║ ║" - echo "║ Then connect via SSH: ║" - echo "║ ║" - echo "║ ssh -p 9191 root@127.0.0.1 ║" - echo "║ ║" - echo "╚════════════════════════════════════════════════════════════════╝" - echo "" + + if command -v gum &> /dev/null; then + local header=$(gum style --foreground 212 --border double --border-foreground 212 --padding "1 2" --align center --width 60 "✅ Setup Complete!") + local message=$(gum style --foreground 255 --align center --width 60 "Your Kaggle instance is ready for remote access!") + + local token_label=$(gum style --foreground 99 "📡 Zrok Share Token:") + local token_value=$(gum style --foreground 212 --bold "$share_token") + local token_section=$(gum join --vertical --align center "$token_label" "$token_value") + local token_box=$(gum style --border rounded --padding "1 2" --border-foreground 99 --width 60 --align center "$token_section") + + local instr_label=$(gum style --foreground 255 "🖥️ On your LOCAL machine, run:") + local cmd1=$(gum style --foreground 212 "zrok access private $share_token") + local cmd2_label=$(gum style --foreground 255 "Then connect via SSH:") + local cmd2=$(gum style --foreground 212 "ssh -p 9191 root@127.0.0.1") + + local cmds_content=$(gum join --vertical --align center "$instr_label" " " "$cmd1" " " "$cmd2_label" " " "$cmd2") + local cmds_box=$(gum style --border rounded --padding "1 2" --border-foreground 255 --width 60 --align center "$cmds_content") + + gum join --vertical --align center "$header" " " "$message" " " "$token_box" " " "$cmds_box" + else + echo "" + echo "╔════════════════════════════════════════════════════════════════╗" + echo "║ ✅ Setup Complete! ║" + echo "╠════════════════════════════════════════════════════════════════╣" + echo "║ ║" + echo "║ Your Kaggle instance is ready for remote access! ║" + echo "║ ║" + echo "║ 📡 Zrok Share Token: $share_token" + echo "║ ║" + echo "║ 🖥️ On your LOCAL machine, run: ║" + echo "║ ║" + echo "║ zrok access private $share_token" + echo "║ ║" + echo "║ Then connect via SSH: ║" + echo "║ ║" + echo "║ ssh -p 9191 root@127.0.0.1 ║" + echo "║ ║" + echo "╚════════════════════════════════════════════════════════════════╝" + echo "" + fi } diff --git a/setup_kaggle_zrok.sh b/setup_kaggle_zrok.sh index 89718b3..ebb69f6 100644 --- a/setup_kaggle_zrok.sh +++ b/setup_kaggle_zrok.sh @@ -147,8 +147,15 @@ EOT install_packages() { log_step_start "Installing packages" + + # Install gum + log_info "Installing gum..." + sudo mkdir -p /etc/apt/keyrings + curl -fsSL https://repo.charm.sh/apt/gpg.key | sudo gpg --dearmor -o /etc/apt/keyrings/charm.gpg + echo "deb [signed-by=/etc/apt/keyrings/charm.gpg] https://repo.charm.sh/apt/ * *" | sudo tee /etc/apt/sources.list.d/charm.list + sudo apt-get update - sudo apt-get install -y openssh-server nvtop screen lshw + sudo apt-get install -y openssh-server nvtop screen lshw gum log_step_complete "Installing packages" log_info "Installing uv..." From adb79e53ccbbc1863bed2c570c715168b15aca7a Mon Sep 17 00:00:00 2001 From: Bui Dai Date: Fri, 12 Dec 2025 09:31:35 +0700 Subject: [PATCH 7/8] style: lint + format --- logging_utils.sh | 43 ++++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/logging_utils.sh b/logging_utils.sh index 7e6b53b..42a2d1c 100644 --- a/logging_utils.sh +++ b/logging_utils.sh @@ -1,6 +1,6 @@ #!/bin/bash # Shared logging utilities for kagglelink scripts -# +# # This library provides consistent logging functions with emojis, # timestamps, and error categorization for all kagglelink scripts. # @@ -72,23 +72,23 @@ categorize_error() { local error_type="$1" local message="$2" local suggestion="$3" - + case "$error_type" in - "prerequisite") - log_error "$message" - echo " 💡 Action required: $suggestion" >&2 - ;; - "network") - log_error "$message" - echo " 🌐 Check connectivity: $suggestion" >&2 - ;; - "upstream") - log_error "$message" - echo " 🔧 Upstream issue: $suggestion" >&2 - ;; - *) - log_error "$message" - ;; + "prerequisite") + log_error "$message" + echo " 💡 Action required: $suggestion" >&2 + ;; + "network") + log_error "$message" + echo " 🌐 Check connectivity: $suggestion" >&2 + ;; + "upstream") + log_error "$message" + echo " 🔧 Upstream issue: $suggestion" >&2 + ;; + *) + log_error "$message" + ;; esac } @@ -98,11 +98,11 @@ categorize_error() { # Output: Formatted success banner to stdout show_success_banner() { local share_token="$1" - - if command -v gum &> /dev/null; then + + if command -v gum &>/dev/null; then local header=$(gum style --foreground 212 --border double --border-foreground 212 --padding "1 2" --align center --width 60 "✅ Setup Complete!") local message=$(gum style --foreground 255 --align center --width 60 "Your Kaggle instance is ready for remote access!") - + local token_label=$(gum style --foreground 99 "📡 Zrok Share Token:") local token_value=$(gum style --foreground 212 --bold "$share_token") local token_section=$(gum join --vertical --align center "$token_label" "$token_value") @@ -112,10 +112,11 @@ show_success_banner() { local cmd1=$(gum style --foreground 212 "zrok access private $share_token") local cmd2_label=$(gum style --foreground 255 "Then connect via SSH:") local cmd2=$(gum style --foreground 212 "ssh -p 9191 root@127.0.0.1") - + local cmds_content=$(gum join --vertical --align center "$instr_label" " " "$cmd1" " " "$cmd2_label" " " "$cmd2") local cmds_box=$(gum style --border rounded --padding "1 2" --border-foreground 255 --width 60 --align center "$cmds_content") + printf "\n" gum join --vertical --align center "$header" " " "$message" " " "$token_box" " " "$cmds_box" else echo "" From e05469440860e51e8c4a337dd261806e164f90cb Mon Sep 17 00:00:00 2001 From: Bui Dai Date: Fri, 12 Dec 2025 09:45:36 +0700 Subject: [PATCH 8/8] fix: shellcheck issues --- logging_utils.sh | 36 ++++++++++++++++++++++++------------ setup_kaggle_zrok.sh | 1 + start_zrok.sh | 6 +----- 3 files changed, 26 insertions(+), 17 deletions(-) diff --git a/logging_utils.sh b/logging_utils.sh index 42a2d1c..d15885d 100644 --- a/logging_utils.sh +++ b/logging_utils.sh @@ -100,21 +100,33 @@ show_success_banner() { local share_token="$1" if command -v gum &>/dev/null; then - local header=$(gum style --foreground 212 --border double --border-foreground 212 --padding "1 2" --align center --width 60 "✅ Setup Complete!") - local message=$(gum style --foreground 255 --align center --width 60 "Your Kaggle instance is ready for remote access!") + local header + header=$(gum style --foreground 212 --border double --border-foreground 212 --padding "1 2" --align center --width 60 "✅ Setup Complete!") + local message + message=$(gum style --foreground 255 --align center --width 60 "Your Kaggle instance is ready for remote access!") - local token_label=$(gum style --foreground 99 "📡 Zrok Share Token:") - local token_value=$(gum style --foreground 212 --bold "$share_token") - local token_section=$(gum join --vertical --align center "$token_label" "$token_value") - local token_box=$(gum style --border rounded --padding "1 2" --border-foreground 99 --width 60 --align center "$token_section") + local token_label + token_label=$(gum style --foreground 99 "📡 Zrok Share Token:") + local token_value + token_value=$(gum style --foreground 212 --bold "$share_token") + local token_section + token_section=$(gum join --vertical --align center "$token_label" "$token_value") + local token_box + token_box=$(gum style --border rounded --padding "1 2" --border-foreground 99 --width 60 --align center "$token_section") - local instr_label=$(gum style --foreground 255 "🖥️ On your LOCAL machine, run:") - local cmd1=$(gum style --foreground 212 "zrok access private $share_token") - local cmd2_label=$(gum style --foreground 255 "Then connect via SSH:") - local cmd2=$(gum style --foreground 212 "ssh -p 9191 root@127.0.0.1") + local instr_label + instr_label=$(gum style --foreground 255 "🖥️ On your LOCAL machine, run:") + local cmd1 + cmd1=$(gum style --foreground 212 "zrok access private $share_token") + local cmd2_label + cmd2_label=$(gum style --foreground 255 "Then connect via SSH:") + local cmd2 + cmd2=$(gum style --foreground 212 "ssh -p 9191 root@127.0.0.1") - local cmds_content=$(gum join --vertical --align center "$instr_label" " " "$cmd1" " " "$cmd2_label" " " "$cmd2") - local cmds_box=$(gum style --border rounded --padding "1 2" --border-foreground 255 --width 60 --align center "$cmds_content") + local cmds_content + cmds_content=$(gum join --vertical --align center "$instr_label" " " "$cmd1" " " "$cmd2_label" " " "$cmd2") + local cmds_box + cmds_box=$(gum style --border rounded --padding "1 2" --border-foreground 255 --width 60 --align center "$cmds_content") printf "\n" gum join --vertical --align center "$header" " " "$message" " " "$token_box" " " "$cmds_box" diff --git a/setup_kaggle_zrok.sh b/setup_kaggle_zrok.sh index ebb69f6..7da9144 100644 --- a/setup_kaggle_zrok.sh +++ b/setup_kaggle_zrok.sh @@ -4,6 +4,7 @@ set -e # Source logging utilities SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +# shellcheck source=logging_utils.sh source "$SCRIPT_DIR/logging_utils.sh" if [ "$#" -ne 1 ]; then diff --git a/start_zrok.sh b/start_zrok.sh index 0c6f976..28f9329 100755 --- a/start_zrok.sh +++ b/start_zrok.sh @@ -4,6 +4,7 @@ set -e # Source logging utilities SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +# shellcheck source=logging_utils.sh source "$SCRIPT_DIR/logging_utils.sh" if [ "$#" -ne 1 ]; then @@ -75,11 +76,6 @@ for i in {1..60}; do # Debug output every 10 seconds if [ $((i % 10)) -eq 0 ]; then log_info "Still waiting for token... (${i}s elapsed)" - log_info "DEBUG: Output file size: $(wc -l < "$SHARE_OUTPUT" 2>/dev/null || echo 0) lines" - log_info "DEBUG: Full raw output so far:" - cat "$SHARE_OUTPUT" 2>/dev/null | while read line; do - log_info " > $line" - done fi sleep 1