Merge pull request #426 from Nigel1992/fix/412-case-insensitive-cursor

Fix: improve Linux path handling and add case-insensitive Cursor directory detection
This commit is contained in:
Pin Studios 2025-03-31 00:59:50 +08:00 committed by GitHub
commit 67d3554664
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 155 additions and 17 deletions

103
config.py
View File

@ -68,6 +68,9 @@ def setup_config(translator=None):
'updater_path': os.path.join(localappdata, "cursor-updater"), 'updater_path': os.path.join(localappdata, "cursor-updater"),
'update_yml_path': os.path.join(localappdata, "Programs", "Cursor", "resources", "app-update.yml") 'update_yml_path': os.path.join(localappdata, "Programs", "Cursor", "resources", "app-update.yml")
} }
# Create storage directory
os.makedirs(os.path.dirname(default_config['WindowsPaths']['storage_path']), exist_ok=True)
elif sys.platform == "darwin": elif sys.platform == "darwin":
default_config['MacPaths'] = { default_config['MacPaths'] = {
'storage_path': os.path.abspath(os.path.expanduser("~/Library/Application Support/Cursor/User/globalStorage/storage.json")), 'storage_path': os.path.abspath(os.path.expanduser("~/Library/Application Support/Cursor/User/globalStorage/storage.json")),
@ -77,17 +80,91 @@ def setup_config(translator=None):
'updater_path': os.path.expanduser("~/Library/Application Support/cursor-updater"), 'updater_path': os.path.expanduser("~/Library/Application Support/cursor-updater"),
'update_yml_path': "/Applications/Cursor.app/Contents/Resources/app-update.yml" 'update_yml_path': "/Applications/Cursor.app/Contents/Resources/app-update.yml"
} }
elif sys.platform == "linux": # Create storage directory
sudo_user = os.environ.get('SUDO_USER') os.makedirs(os.path.dirname(default_config['MacPaths']['storage_path']), exist_ok=True)
actual_home = f"/home/{sudo_user}" if sudo_user else os.path.expanduser("~")
elif sys.platform == "linux":
# Get the actual user's home directory, handling both sudo and normal cases
current_user = os.getenv('USER') or os.getenv('USERNAME') or os.getenv('SUDO_USER')
if not current_user:
current_user = os.path.expanduser('~').split('/')[-1]
actual_home = f"/home/{current_user}"
if not os.path.exists(actual_home):
actual_home = os.path.expanduser("~")
# Define base config directory
config_base = os.path.join(actual_home, ".config")
# Try both "Cursor" and "cursor" directory names
cursor_dir = None
for dir_name in ["Cursor", "cursor"]:
test_dir = os.path.join(config_base, dir_name)
if os.path.exists(test_dir):
cursor_dir = test_dir
break
if not cursor_dir:
print(f"{Fore.YELLOW}{EMOJI['WARNING']} {translator.get('config.neither_cursor_nor_cursor_directory_found', config_base=config_base)}{Style.RESET_ALL}")
print(f"{Fore.YELLOW}{EMOJI['INFO']} {translator.get('config.please_make_sure_cursor_is_installed_and_has_been_run_at_least_once')}{Style.RESET_ALL}")
# Define Linux paths using the found cursor directory
storage_path = os.path.abspath(os.path.join(cursor_dir, "User/globalStorage/storage.json")) if cursor_dir else ""
storage_dir = os.path.dirname(storage_path) if storage_path else ""
# Verify paths and permissions
try:
# Check storage directory
if storage_dir and not os.path.exists(storage_dir):
print(f"{Fore.YELLOW}{EMOJI['WARNING']} {translator.get('config.storage_directory_not_found', storage_dir=storage_dir)}{Style.RESET_ALL}")
print(f"{Fore.YELLOW}{EMOJI['INFO']} {translator.get('config.please_make_sure_cursor_is_installed_and_has_been_run_at_least_once')}{Style.RESET_ALL}")
# Check storage.json with more detailed verification
if storage_path and os.path.exists(storage_path):
# Get file stats
try:
stat = os.stat(storage_path)
print(f"{Fore.GREEN}{EMOJI['INFO']} {translator.get('config.storage_file_found', storage_path=storage_path)}{Style.RESET_ALL}")
print(f"{Fore.GREEN}{EMOJI['INFO']} {translator.get('config.file_size', stat.st_size)}{Style.RESET_ALL}")
print(f"{Fore.GREEN}{EMOJI['INFO']} {translator.get('config.file_permissions', oct(stat.st_mode & 0o777))}{Style.RESET_ALL}")
print(f"{Fore.GREEN}{EMOJI['INFO']} {translator.get('config.file_owner', stat.st_uid)}{Style.RESET_ALL}")
print(f"{Fore.GREEN}{EMOJI['INFO']} {translator.get('config.file_group', stat.st_gid)}{Style.RESET_ALL}")
except Exception as e:
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('config.error_getting_file_stats', error=str(e))}{Style.RESET_ALL}")
# Check if file is readable and writable
if not os.access(storage_path, os.R_OK | os.W_OK):
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('config.permission_denied', storage_path=storage_path)}{Style.RESET_ALL}")
print(f"{Fore.YELLOW}{EMOJI['INFO']} {translator.get('config.try_running', current_user=current_user, storage_path=storage_path)}{Style.RESET_ALL}")
print(f"{Fore.YELLOW}{EMOJI['INFO']} {translator.get('config.and', storage_path=storage_path)}{Style.RESET_ALL}")
# Try to read the file to verify it's not corrupted
try:
with open(storage_path, 'r') as f:
content = f.read()
if not content.strip():
print(f"{Fore.YELLOW}{EMOJI['WARNING']} {translator.get('config.storage_file_is_empty', storage_path=storage_path)}{Style.RESET_ALL}")
print(f"{Fore.YELLOW}{EMOJI['INFO']} {translator.get('config.please_make_sure_cursor_is_installed_and_has_been_run_at_least_once')}{Style.RESET_ALL}")
else:
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {translator.get('config.storage_file_is_valid_and_contains_data')}{Style.RESET_ALL}")
except Exception as e:
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('config.error_reading_storage_file', error=str(e))}{Style.RESET_ALL}")
print(f"{Fore.YELLOW}{EMOJI['INFO']} {translator.get('config.the_file_might_be_corrupted_please_reinstall_cursor')}{Style.RESET_ALL}")
elif storage_path:
print(f"{Fore.YELLOW}{EMOJI['WARNING']} {translator.get('config.storage_file_not_found', storage_path=storage_path)}{Style.RESET_ALL}")
print(f"{Fore.YELLOW}{EMOJI['INFO']} {translator.get('config.please_make_sure_cursor_is_installed_and_has_been_run_at_least_once')}{Style.RESET_ALL}")
except (OSError, IOError) as e:
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('config.error_checking_linux_paths', error=str(e))}{Style.RESET_ALL}")
# Define all paths using the found cursor directory
default_config['LinuxPaths'] = { default_config['LinuxPaths'] = {
'storage_path': os.path.abspath(os.path.join(actual_home, ".config/cursor/User/globalStorage/storage.json")), 'storage_path': storage_path,
'sqlite_path': os.path.abspath(os.path.join(actual_home, ".config/cursor/User/globalStorage/state.vscdb")), 'sqlite_path': os.path.abspath(os.path.join(cursor_dir, "User/globalStorage/state.vscdb")) if cursor_dir else "",
'machine_id_path': os.path.expanduser("~/.config/cursor/machineid"), 'machine_id_path': os.path.join(cursor_dir, "machineid") if cursor_dir else "",
'cursor_path': get_linux_cursor_path(), 'cursor_path': get_linux_cursor_path(),
'updater_path': os.path.expanduser("~/.config/cursor-updater"), 'updater_path': os.path.join(config_base, "cursor-updater"),
'update_yml_path': "/Applications/Cursor.app/Contents/Resources/app-update.yml" 'update_yml_path': os.path.join(cursor_dir, "resources/app-update.yml") if cursor_dir else ""
} }
# Read existing configuration and merge # Read existing configuration and merge
@ -104,13 +181,13 @@ def setup_config(translator=None):
config.set(section, option, str(value)) config.set(section, option, str(value))
config_modified = True config_modified = True
if translator: if translator:
print(f"{Fore.YELLOW} {translator.get('register.config_option_added', option=f'{section}.{option}')}{Style.RESET_ALL}") print(f"{Fore.YELLOW}{EMOJI['INFO']} {translator.get('register.config_option_added', option=f'{section}.{option}')}{Style.RESET_ALL}")
if config_modified: if config_modified:
with open(config_file, 'w', encoding='utf-8') as f: with open(config_file, 'w', encoding='utf-8') as f:
config.write(f) config.write(f)
if translator: if translator:
print(f"{Fore.GREEN} {translator.get('register.config_updated')}{Style.RESET_ALL}") print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {translator.get('register.config_updated')}{Style.RESET_ALL}")
else: else:
for section, options in default_config.items(): for section, options in default_config.items():
config.add_section(section) config.add_section(section)
@ -120,15 +197,13 @@ def setup_config(translator=None):
with open(config_file, 'w', encoding='utf-8') as f: with open(config_file, 'w', encoding='utf-8') as f:
config.write(f) config.write(f)
if translator: if translator:
print(f"{Fore.GREEN} {translator.get('register.config_created')}: {config_file}{Style.RESET_ALL}") print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {translator.get('register.config_created')}: {config_file}{Style.RESET_ALL}")
return config return config
except Exception as e: except Exception as e:
if translator: if translator:
print(f"{Fore.RED}{translator.get('register.config_setup_error', error=str(e))}{Style.RESET_ALL}") print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('register.config_setup_error', error=str(e))}{Style.RESET_ALL}")
else:
print(f"{Fore.RED}❌ Error setting up config: {e}{Style.RESET_ALL}")
return None return None
def print_config(config, translator=None): def print_config(config, translator=None):

View File

@ -493,6 +493,27 @@
"configuration": "Configuration", "configuration": "Configuration",
"enabled": "Enabled", "enabled": "Enabled",
"disabled": "Disabled", "disabled": "Disabled",
"config_directory": "Config Directory" "config_directory": "Config Directory",
"neither_cursor_nor_cursor_directory_found": "Neither Cursor nor Cursor directory found in {config_base}",
"please_make_sure_cursor_is_installed_and_has_been_run_at_least_once": "Please make sure Cursor is installed and has been run at least once",
"storage_directory_not_found": "Storage directory not found: {storage_dir}",
"storage_file_found": "Storage file found: {storage_path}",
"file_size": "File size: {size}",
"file_permissions": "File permissions: {permissions}",
"file_owner": "File owner: {owner}",
"file_group": "File group: {group}",
"error_getting_file_stats": "Error getting file stats: {error}",
"permission_denied": "Permission denied: {storage_path}",
"try_running": "Try running 'cursor --help' to check if it's installed",
"and": "and",
"storage_file_is_empty": "Storage file is empty: {storage_path}",
"the_file_might_be_corrupted_please_reinstall_cursor": "The file might be corrupted, please reinstall Cursor",
"storage_file_not_found": "Storage file not found: {storage_path}",
"error_checking_linux_paths": "Error checking Linux paths: {error}",
"config_option_added": "Config option added: {option}",
"config_updated": "Config updated",
"config_created": "Config created: {config_file}",
"config_setup_error": "Error setting up config: {error}"
} }
} }

View File

@ -488,6 +488,27 @@
"configuration": "配置", "configuration": "配置",
"enabled": "已启用", "enabled": "已启用",
"disabled": "已禁用", "disabled": "已禁用",
"config_directory": "配置目录" "config_directory": "配置目录",
"neither_cursor_nor_cursor_directory_found": "未找到 Cursor 或 Cursor 目录",
"please_make_sure_cursor_is_installed_and_has_been_run_at_least_once": "请确保 Cursor 已安装并至少运行一次",
"storage_directory_not_found": "未找到存储目录",
"storage_file_found": "找到存储文件",
"file_size": "文件大小",
"file_permissions": "文件权限",
"file_owner": "文件所有者",
"file_group": "文件组",
"error_getting_file_stats": "获取文件统计信息时出错",
"permission_denied": "权限拒绝",
"try_running": "尝试运行 'cursor --help' 检查是否已安装",
"and": "和",
"storage_file_is_empty": "存储文件为空",
"the_file_might_be_corrupted_please_reinstall_cursor": "文件可能已损坏,请重新安装 Cursor",
"storage_file_not_found": "未找到存储文件",
"error_checking_linux_paths": "检查 Linux 路径时出错",
"config_option_added": "添加配置选项",
"config_updated": "配置更新",
"config_created": "配置已创建",
"config_setup_error": "配置设置错误"
} }
} }

View File

@ -467,6 +467,27 @@
"configuration": "配置", "configuration": "配置",
"enabled": "已啟用", "enabled": "已啟用",
"disabled": "已禁用", "disabled": "已禁用",
"config_directory": "配置目錄" "config_directory": "配置目錄",
"neither_cursor_nor_cursor_directory_found": "未找到 Cursor 或 Cursor 目錄",
"please_make_sure_cursor_is_installed_and_has_been_run_at_least_once": "請確保 Cursor 已安裝並至少運行一次",
"storage_directory_not_found": "未找到儲存目錄",
"storage_file_found": "找到儲存文件",
"file_size": "文件大小",
"file_permissions": "文件權限",
"file_owner": "文件所有者",
"file_group": "文件組",
"error_getting_file_stats": "獲取文件統計信息時出錯",
"permission_denied": "權限拒絕",
"try_running": "嘗試運行 'cursor --help' 檢查是否已安裝",
"and": "和",
"storage_file_is_empty": "儲存文件為空",
"the_file_might_be_corrupted_please_reinstall_cursor": "文件可能已損壞,請重新安裝 Cursor",
"storage_file_not_found": "未找到儲存文件",
"error_checking_linux_paths": "檢查 Linux 路徑時出錯",
"config_option_added": "添加配置選項",
"config_updated": "配置更新",
"config_created": "配置已創建",
"config_setup_error": "配置設置錯誤"
} }
} }