diff --git a/docker-compose.yml b/docker-compose.yml index a0b1ca2b..e33b0d83 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -80,10 +80,10 @@ services: - AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID} - AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY} volumes: - - ./openrag-documents:/app/openrag-documents:Z - - ./keys:/app/keys:Z - - ./flows:/app/flows:U,z - - ./config:/app/config:Z + - ${OPENRAG_DOCUMENTS_PATH:-./openrag-documents}:/app/openrag-documents:Z + - ${OPENRAG_KEYS_PATH:-./keys}:/app/keys:Z + - ${OPENRAG_FLOWS_PATH:-./flows}:/app/flows:U,z + - ${OPENRAG_CONFIG_PATH:-./config}:/app/config:Z openrag-frontend: image: langflowai/openrag-frontend:${OPENRAG_VERSION:-latest} @@ -100,7 +100,7 @@ services: langflow: volumes: - - ./flows:/app/flows:U,z + - ${OPENRAG_FLOWS_PATH:-./flows}:/app/flows:U,z image: langflowai/openrag-langflow:${OPENRAG_VERSION:-latest} build: context: . diff --git a/src/tui/main.py b/src/tui/main.py index 9623f50e..a95ad0cf 100644 --- a/src/tui/main.py +++ b/src/tui/main.py @@ -541,6 +541,69 @@ def copy_compose_files(*, force: bool = False) -> None: logger.debug(f"Could not copy compose file {filename}: {error}") +def migrate_legacy_data_directories(): + """Migrate data from CWD-based directories to ~/.openrag/. + + This is a one-time migration for users upgrading from the old layout. + Migrates: documents, flows, keys, config, opensearch-data + """ + from pathlib import Path + import shutil + + cwd = Path.cwd() + target_base = Path.home() / ".openrag" + + # Define migration mappings: (source_path, target_path, description) + migrations = [ + (cwd / "openrag-documents", target_base / "documents" / "openrag-documents", "documents"), + (cwd / "flows", target_base / "flows", "flows"), + (cwd / "keys", target_base / "keys", "keys"), + (cwd / "config", target_base / "config", "config"), + (cwd / "opensearch-data", target_base / "data" / "opensearch-data", "OpenSearch data"), + ] + + migrated_any = False + for source, target, description in migrations: + if not source.exists(): + continue + + # If target exists, merge; otherwise move + try: + target.parent.mkdir(parents=True, exist_ok=True) + + if target.exists(): + # Target exists - merge contents + logger.info(f"Merging {description} from {source} to {target}") + if source.is_dir(): + for item in source.iterdir(): + src_item = source / item.name + dst_item = target / item.name + + if not dst_item.exists(): + if src_item.is_dir(): + shutil.copytree(src_item, dst_item) + else: + shutil.copy2(src_item, dst_item) + logger.debug(f"Copied {src_item} to {dst_item}") + else: + if not target.exists(): + shutil.copy2(source, target) + logger.debug(f"Copied {source} to {target}") + else: + # Target doesn't exist - move entire directory/file + logger.info(f"Migrating {description} from {source} to {target}") + shutil.move(str(source), str(target)) + + migrated_any = True + except Exception as e: + logger.warning(f"Failed to migrate {description}: {e}") + + if migrated_any: + logger.info("Data migration completed. Old directories can be safely deleted from CWD.") + + return migrated_any + + def setup_host_directories(): """Initialize OpenRAG directory structure on the host. @@ -583,6 +646,9 @@ def run_tui(): app = None try: + # Migrate legacy data directories from CWD to ~/.openrag/ + migrate_legacy_data_directories() + # Initialize host directory structure setup_host_directories() diff --git a/src/tui/managers/env_manager.py b/src/tui/managers/env_manager.py index 5640446c..b9124d8c 100644 --- a/src/tui/managers/env_manager.py +++ b/src/tui/managers/env_manager.py @@ -67,7 +67,11 @@ class EnvConfig: # Document paths (comma-separated) - use centralized location by default openrag_documents_paths: str = "$HOME/.openrag/documents/openrag-documents" - # OpenSearch data path - use centralized location by default + # Volume mount paths - use centralized location by default + openrag_documents_path: str = "$HOME/.openrag/documents/openrag-documents" # Primary documents path for compose + openrag_keys_path: str = "$HOME/.openrag/keys" + openrag_flows_path: str = "$HOME/.openrag/flows" + openrag_config_path: str = "$HOME/.openrag/config" opensearch_data_path: str = "$HOME/.openrag/data/opensearch-data" # Container version (linked to TUI version) @@ -174,6 +178,10 @@ class EnvManager: "AWS_SECRET_ACCESS_KEY": "aws_secret_access_key", # pragma: allowlist secret "LANGFLOW_PUBLIC_URL": "langflow_public_url", "OPENRAG_DOCUMENTS_PATHS": "openrag_documents_paths", + "OPENRAG_DOCUMENTS_PATH": "openrag_documents_path", + "OPENRAG_KEYS_PATH": "openrag_keys_path", + "OPENRAG_FLOWS_PATH": "openrag_flows_path", + "OPENRAG_CONFIG_PATH": "openrag_config_path", "OPENSEARCH_DATA_PATH": "opensearch_data_path", "LANGFLOW_AUTO_LOGIN": "langflow_auto_login", "LANGFLOW_NEW_USER_IS_ACTIVE": "langflow_new_user_is_active", @@ -370,6 +378,22 @@ class EnvManager: f.write( f"OPENRAG_DOCUMENTS_PATHS={self._quote_env_value(self.config.openrag_documents_paths)}\n" ) + f.write("\n") + + # Volume mount paths for Docker Compose + f.write("# Volume mount paths for Docker Compose\n") + f.write( + f"OPENRAG_DOCUMENTS_PATH={self._quote_env_value(self.config.openrag_documents_path)}\n" + ) + f.write( + f"OPENRAG_KEYS_PATH={self._quote_env_value(self.config.openrag_keys_path)}\n" + ) + f.write( + f"OPENRAG_FLOWS_PATH={self._quote_env_value(self.config.openrag_flows_path)}\n" + ) + f.write( + f"OPENRAG_CONFIG_PATH={self._quote_env_value(self.config.openrag_config_path)}\n" + ) f.write( f"OPENSEARCH_DATA_PATH={self._quote_env_value(self.config.opensearch_data_path)}\n" )