diff --git a/pygeoweaver/jdk_utils.py b/pygeoweaver/jdk_utils.py index f3d6fc9..94dbab3 100644 --- a/pygeoweaver/jdk_utils.py +++ b/pygeoweaver/jdk_utils.py @@ -7,7 +7,7 @@ import zipfile import urllib.request -from pygeoweaver.utils import get_home_dir, get_java_bin_path, safe_exit +from pygeoweaver.utils import detect_rc_file, get_home_dir, get_java_bin_path, safe_exit def install_jdk(): @@ -149,21 +149,22 @@ def set_jdk_env_vars_for_windows(jdk_install_dir): def set_jdk_env_vars_for_linux_mac(jdk_install_dir): print(f"Setting JDK environment variables...") java_line = f'\nexport JAVA_HOME="{jdk_install_dir}"\n' + rc_file_path = detect_rc_file() check_java = False - with open(os.path.expanduser("~/.bashrc"), "r") as file: + with open(rc_file_path, "r") as file: for line in file: if line.strip() == java_line: check_java = True break if not check_java: - with open(os.path.expanduser("~/.bashrc"), "a") as bashrc: + with open(rc_file_path, "a") as bashrc: bashrc.write(f'export JAVA_HOME="{jdk_install_dir}"\n') bashrc.write(f'export PATH="$JAVA_HOME/bin:$PATH"\n') print("JDK environment variables set.") - subprocess.run(["bash", "-c", "source ~/.bashrc"]) + subprocess.run(["bash", "-c", "source", rc_file_path]) def set_jdk_env_vars(jdk_install_dir): diff --git a/pygeoweaver/server.py b/pygeoweaver/server.py index 80ee8e9..37bdb23 100644 --- a/pygeoweaver/server.py +++ b/pygeoweaver/server.py @@ -15,6 +15,7 @@ check_ipython, check_os, download_geoweaver_jar, + get_log_file_path, get_module_absolute_path, get_root_dir, get_spinner, @@ -95,11 +96,7 @@ def start_on_windows(force_restart=False, force_download=False, exit_on_finish=T try: response = requests.get(GEOWEAVER_DEFAULT_ENDPOINT_URL, allow_redirects=False) if response.status_code == 302: - log_file = os.path.join(home_dir, "geoweaver.log") - # Ensure the log file exists, create it if it doesn't - if not os.path.exists(log_file): - open(log_file, "a").close() # Create an empty file if it doesn't exist - + log_file = get_log_file_path() # Now you can safely open the log file for reading with open(log_file, "r") as f: print(f.read()) @@ -188,20 +185,34 @@ def start_on_mac_linux(force_restart: bool=False, force_download: bool=False, ex safe_exit(0) -def stop_on_mac_linux(exit_on_finish: bool=False) -> int: - with get_spinner(text=f'Stopping Geoweaver...', spinner='dots'): - logger.info("Stop running Geoweaver if any..") +def find_geoweaver_processes(current_uid): + """ + Find all Geoweaver-related processes started by the current user. + + :param current_uid: The UID of the current user. + :return: A list of matching process objects. + """ + processes = [] + for proc in psutil.process_iter(['pid', 'name', 'cmdline', 'uids']): + try: + if (proc.info and proc.info['cmdline'] and + ('geoweaver.jar' in " ".join(proc.info['cmdline']) or + 'GeoweaverApplication' in " ".join(proc.info['cmdline'])) and + proc.info['uids'] and proc.info['uids'].real == current_uid): + processes.append(proc) + except (psutil.NoSuchProcess, psutil.AccessDenied): + continue # Skip processes that have exited or are inaccessible + return processes + +def stop_on_mac_linux(exit_on_finish: bool = False) -> int: + with get_spinner(text='Stopping Geoweaver...', spinner='dots'): + logger.info("Stopping any running Geoweaver processes...") # Get current user's UID current_uid = os.getuid() - # Find all processes running geoweaver.jar that are started by the current user - processes = [] - for proc in psutil.process_iter(['pid', 'name', 'cmdline', 'uids']): - if proc and proc.info and proc.info['cmdline'] \ - and 'geoweaver.jar' in " ".join(proc.info['cmdline']) \ - and proc.info['uids'] and proc.info['uids'].real == current_uid: - processes.append(proc) + # Find all processes running geoweaver.jar or GeoweaverApplication that are started by the current user + processes = find_geoweaver_processes(current_uid) if not processes: print("No running Geoweaver processes found for the current user.") @@ -213,9 +224,16 @@ def stop_on_mac_linux(exit_on_finish: bool=False) -> int: try: proc.terminate() proc.wait(timeout=5) # Wait for the process to terminate - except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.TimeoutExpired) as e: - errors.append(f"Failed to kill process {proc.info['pid']}: {e}") - + logger.info(f"Successfully stopped process {proc.info['pid']}.") + except (psutil.NoSuchProcess, psutil.AccessDenied): + logger.error(f"Process {proc.info['pid']} has already exited or is inaccessible.") + errors.append(f"Process {proc.info['pid']} is not accessible.") + except psutil.TimeoutExpired: + logger.warning(f"Process {proc.info['pid']} did not terminate in time, forcing kill.") + proc.kill() # Forcefully kill if it didn't terminate in time + errors.append(f"Process {proc.info['pid']} was forcefully killed.") + + # Log errors if any if errors: for error in errors: logger.error(error) @@ -223,16 +241,17 @@ def stop_on_mac_linux(exit_on_finish: bool=False) -> int: return 1 # Check status of Geoweaver - status = subprocess.run(["curl", "-s", "-o", "/dev/null", - "-w", "%{http_code}\n", - GEOWEAVER_DEFAULT_ENDPOINT_URL], - capture_output=True, text=True).stdout.strip() - logger.info("status: "+ status) + status = subprocess.run( + ["curl", "-s", "-o", "/dev/null", "-w", "%{http_code}\n", GEOWEAVER_DEFAULT_ENDPOINT_URL], + capture_output=True, text=True + ).stdout.strip() + + logger.info("Geoweaver status: " + status) if status != "302": - print("Stopped.") + print("Stopped Geoweaver successfully.") return 0 else: - print("Error: unable to stop.") + print("Error: Unable to stop Geoweaver.") return 1 diff --git a/pygeoweaver/start.sh b/pygeoweaver/start.sh index 00af167..291e061 100755 --- a/pygeoweaver/start.sh +++ b/pygeoweaver/start.sh @@ -4,10 +4,37 @@ echo "Stop running Geoweaver if any.." pkill -f geoweaver.jar echo "Checking Java..." -if [ ! -f ~/.bashrc ]; then - touch ~/.bashrc + +# Detect the user's shell +USER_SHELL=$(basename "$SHELL") + +# Set the appropriate rc file based on the detected shell +if [ "$USER_SHELL" = "bash" ]; then + RC_FILE=~/.bashrc +elif [ "$USER_SHELL" = "zsh" ]; then + RC_FILE=~/.zshrc +elif [ "$USER_SHELL" = "fish" ]; then + RC_FILE=~/.config/fish/config.fish +else + # Default to .bashrc if unknown shell + RC_FILE=~/.bashrc +fi + +# Check if the rc file exists, if not, create it +if [ ! -f "$RC_FILE" ]; then + echo "$RC_FILE does not exist. Creating it..." + mkdir -p "$(dirname "$RC_FILE")" + touch "$RC_FILE" +fi + +# Source the rc file +if [ "$USER_SHELL" = "fish" ]; then + echo "Sourcing $RC_FILE with fish..." + fish -c "source $RC_FILE" +else + echo "Sourcing $RC_FILE..." + source "$RC_FILE" fi -source ~/.bashrc echo "Start Geoweaver.." nohup ~/jdk/jdk-11.0.18+10/bin/java -jar ~/geoweaver.jar > ~/geoweaver.log & diff --git a/pygeoweaver/utils.py b/pygeoweaver/utils.py index 5008c84..f322fb0 100644 --- a/pygeoweaver/utils.py +++ b/pygeoweaver/utils.py @@ -69,6 +69,38 @@ def get_root_dir(): return head +def detect_rc_file(): + """ + Detect the user's shell and return the appropriate shell configuration (rc) file path. + Create the rc file if it doesn't exist. + + Returns: + str: Path to the shell configuration file (e.g., .bashrc, .zshrc, config.fish). + """ + # Detect user's shell + user_shell = os.environ.get('SHELL', '/bin/bash') + + # Determine appropriate shell configuration file based on the detected shell + if 'bash' in user_shell: + rc_file = os.path.expanduser("~/.bashrc") + elif 'zsh' in user_shell: + rc_file = os.path.expanduser("~/.zshrc") + elif 'fish' in user_shell: + rc_file = os.path.expanduser("~/.config/fish/config.fish") + else: + # Default to bashrc if unknown shell + rc_file = os.path.expanduser("~/.bashrc") + + # Check if the shell configuration file exists, create if it doesn't + if not os.path.exists(rc_file): + print(f"{rc_file} does not exist. Creating it...") + # Ensure the directory exists (for fish, the config directory may not exist) + os.makedirs(os.path.dirname(rc_file), exist_ok=True) + open(rc_file, 'a').close() + + return rc_file + + def get_java_bin_from_which(): """ Get the path of the Java binary using the 'which' command. @@ -78,7 +110,7 @@ def get_java_bin_from_which(): if system == "Darwin" or system == "Linux": try: # Source ~/.bashrc (Assuming it's a non-login shell) - bashrc_path = os.path.expanduser("~/.bashrc") + bashrc_path = detect_rc_file() subprocess.run(["bash", "-c", f"source {bashrc_path}"]) # Check the location of Java executable @@ -216,3 +248,33 @@ def copy_files(source_folder, destination_folder): def get_geoweaver_port(): return os.getenv("GEOWEAVER_PORT", "8070") + +def get_log_file_path(): + """ + Determine the best location to store the geoweaver log file + based on the operating system. + + Returns: + str: The full path to the geoweaver log file. + """ + # Get the user's home directory + home_dir = os.path.expanduser("~") + + # Determine the log directory based on the platform + if os.name == 'nt': # Windows + log_dir = os.path.join(os.getenv('APPDATA'), 'Geoweaver', 'logs') + else: # macOS/Linux + log_dir = os.path.join(home_dir, '.local', 'share', 'geoweaver', 'logs') + + # Create the directory if it doesn't exist + os.makedirs(log_dir, exist_ok=True) + + # Define the full path to the log file + log_file = os.path.join(log_dir, "geoweaver.log") + + # Ensure the log file exists, create it if it doesn't + if not os.path.exists(log_file): + open(log_file, "a").close() # Create an empty log file if it doesn't exist + + return log_file +