2727import os
2828import os .path
2929
30+ from ._logger import log
3031
3132class UnsupportedPlatformError (Exception ):
3233 pass
@@ -69,7 +70,7 @@ class UnsupportedPlatformError(Exception):
6970 USER_FOLDER = os .path .expanduser ("~" )
7071
7172
72- def get_platform_python (venv_folder ):
73+ def get_platform_python (venv_folder : str ):
7374 if sys .platform == "win32" :
7475 if sys .stdout :
7576 return os .path .join (venv_folder , "Scripts" , "python.exe" )
@@ -79,31 +80,70 @@ def get_platform_python(venv_folder):
7980 return os .path .join (venv_folder , "bin" , "python" )
8081
8182
82- def get_platform_folder (name ) :
83+ def get_platform_folder (name : str , config : bool = False ) -> str :
8384 if sys .platform == "win32" :
84- return os .path .join (USER_FOLDER , name )
85+ platform_folder = os .path .join (USER_FOLDER , name )
86+ elif config :
87+ platform_folder = os .path .join (USER_FOLDER , ".config" , name )
8588 else :
86- return os .path .join (USER_FOLDER , f".{ name } " )
89+ platform_folder = os .path .join (USER_FOLDER , ".local" , "share" , name )
90+
91+ return platform_folder
92+
93+
94+ def migrate_old_env (name : str , mode = "error" ):
95+ if sys .platform != "win32" :
96+ old_folder = os .path .join (USER_FOLDER , f".{ name } " )
97+ new_folder = os .path .join (USER_FOLDER , ".local" , "share" , name )
98+ if os .path .exists (old_folder ):
99+ print (f"Migrating from { old_folder !r} to { new_folder !r} " )
100+ import shutil
101+ if os .path .exists (new_folder ):
102+ if mode == "delete" :
103+ print (f"Removing old data folder as new folder detected." )
104+ shutil .rmtree (old_folder )
105+ elif mode == "overwrite" :
106+ print (f"Overwriting new folder with old folder data" )
107+ shutil .rmtree (new_folder )
108+ shutil .move (old_folder , new_folder )
109+ else :
110+ raise RuntimeError (
111+ "Error: Both old and new env folders exist.\n "
112+ "Use --delete to remove the old folder or --overwrite to replace the new folder"
113+ )
114+ else :
115+ os .makedirs (os .path .dirname (new_folder ), exist_ok = True )
116+ shutil .move (old_folder , new_folder )
117+ print (f"Moved old data to new folder" )
118+
119+ # Try to remove the old folder, will only succeed if empty
120+ try :
121+ os .rmdir (os .path .dirname (old_folder ))
122+ except OSError :
123+ pass
87124
88125
89126class ManagedPaths :
90127 project_name : str
91128 project_folder : str
129+
130+ # WIN32: %LOCALAPPDATA%\ducktools\env
131+ # OTHER: ~/.config/ducktools/env
92132 config_path : str
93133
134+ # WIN32: %LOCALAPPDATA%\ducktools\env
135+ # OTHER: ~/.local/share/ducktools/env
94136 manager_folder : str
95137 pip_zipapp : str
96138 uv_executable : str
97139 env_folder : str
140+ register_db : str
98141
99142 application_folder : str
100143 application_db : str
101-
102144 cache_folder : str
103145 cache_db : str
104146
105- register_db : str
106-
107147 build_base : str
108148
109149 def __init__ (self , project_name = "ducktools" ):
@@ -112,7 +152,18 @@ def __init__(self, project_name="ducktools"):
112152 folder_base = os .path .join (self .project_name , PACKAGE_SUBFOLDER )
113153
114154 self .project_folder = get_platform_folder (folder_base )
115- self .config_path = os .path .join (self .project_folder , CONFIG_FILENAME )
155+
156+ if sys .platform != "win32" :
157+ if os .path .exists (os .path .join (USER_FOLDER , f".{ folder_base } " )):
158+ log (
159+ "Old ducktools-env folder detected, "
160+ "use the migrate subcommand to copy data to the new path."
161+ )
162+
163+ self .config_path = os .path .join (
164+ get_platform_folder (folder_base , config = True ),
165+ CONFIG_FILENAME
166+ )
116167
117168 self .manager_folder = os .path .join (self .project_folder , MANAGER_FOLDERNAME )
118169 self .pip_zipapp = os .path .join (self .manager_folder , "pip.pyz" )
0 commit comments