1
+ from enum import Enum
1
2
import os
2
3
import pathlib
3
4
import subprocess
7
8
from .config import CONDA_ENV_PREFIX_PATH , CONDAX_LINK_DESTINATION , DEFAULT_CHANNELS
8
9
from .paths import mkpath
9
10
11
+ class LinkConflictAction (Enum ):
12
+ ERROR = "error"
13
+ OVERWRITE = "overwrite"
14
+ SKIP = "skip"
10
15
11
- def create_link (exe ):
16
+
17
+ def create_link_windows (exe , link_conflict_action ):
12
18
executable_name = os .path .basename (exe )
13
- if os .name == "nt" :
14
- # create a batch file to run our application
15
- win_path = pathlib .PureWindowsPath (exe )
16
- name_only , _ = os .path .splitext (executable_name )
17
- with open (f"{ CONDAX_LINK_DESTINATION } /{ name_only } .bat" , "w" ) as fo :
18
- fo .writelines (
19
- [
20
- "@echo off\n " ,
21
- "REM Entrypoint created by condax\n " ,
22
- f'CALL "{ win_path } " %*' ,
23
- ]
19
+ # create a batch file to run our application
20
+ win_path = pathlib .PureWindowsPath (exe )
21
+ name_only , _ = os .path .splitext (executable_name )
22
+ bat_path = f"{ CONDAX_LINK_DESTINATION } /{ name_only } .bat"
23
+ if os .path .exists (bat_path ):
24
+ if link_conflict_action == LinkConflictAction .ERROR :
25
+ print (
26
+ f"Error: link already exists for { executable_name } , use --link-conflict to overwrite or skip" ,
27
+ file = sys .stderr ,
24
28
)
25
- else :
26
- print (os .listdir (CONDAX_LINK_DESTINATION ))
29
+ sys .exit (1 )
30
+ elif link_conflict_action == LinkConflictAction .SKIP :
31
+ print (f"Skipping link for { executable_name } because it already exists" , file = sys .stderr )
32
+ return False
33
+ elif link_conflict_action == LinkConflictAction .OVERWRITE :
34
+ print (f"Overwriting existing link { bat_path } " , file = sys .stderr )
35
+ os .remove (bat_path )
36
+ with open (bat_path , "w" ) as fo :
37
+ fo .writelines (
38
+ [
39
+ "@echo off\n " ,
40
+ "REM Entrypoint created by condax\n " ,
41
+ f'CALL "{ win_path } " %*' ,
42
+ ]
43
+ )
44
+ return True
45
+
46
+
47
+ def create_link_unix (exe , link_conflict_action ):
48
+ executable_name = os .path .basename (exe )
49
+ dst = f"{ CONDAX_LINK_DESTINATION } /{ executable_name } "
50
+ if link_conflict_action == LinkConflictAction .OVERWRITE and os .path .exists (dst ):
51
+ print (f"Overwriting existing link { dst } " , file = sys .stderr )
52
+ os .remove (dst )
53
+ try :
27
54
os .symlink (exe , f"{ CONDAX_LINK_DESTINATION } /{ executable_name } " )
55
+ return True
56
+ except FileExistsError :
57
+ if link_conflict_action == LinkConflictAction .ERROR :
58
+ print (
59
+ f"Error: link already exists for { executable_name } , use --link-conflict to overwrite or skip" ,
60
+ file = sys .stderr ,
61
+ )
62
+ sys .exit (1 )
63
+ elif link_conflict_action == LinkConflictAction .SKIP :
64
+ print (f"Skipping link for { executable_name } because it already exists" , file = sys .stderr )
65
+ return False
66
+
28
67
68
+ def create_link (exe , link_conflict_action ):
69
+ create_link_func = create_link_windows if sys .platform == "nt" else create_link_unix
70
+ return create_link_func (exe , link_conflict_action )
29
71
30
- def create_links (executables_to_link ):
72
+ def create_links (executables_to_link , link_conflict_action ):
73
+ print (os .listdir (CONDAX_LINK_DESTINATION ))
74
+ link_succeeded = {}
31
75
for exe in executables_to_link :
32
- create_link (exe )
76
+ link_succeeded [ exe ] = create_link (exe , link_conflict_action )
33
77
if len (executables_to_link ):
34
78
print ("Created the following entrypoint links:" , file = sys .stderr )
35
79
for exe in executables_to_link :
36
- executable_name = os .path .basename (exe )
37
- print (f" { executable_name } " , file = sys .stderr )
80
+ if link_succeeded [exe ]:
81
+ executable_name = os .path .basename (exe )
82
+ print (f" { executable_name } " , file = sys .stderr )
38
83
39
84
40
85
def remove_links (executables_to_unlink ):
@@ -50,11 +95,11 @@ def remove_links(executables_to_unlink):
50
95
print (f" { executable_name } " , file = sys .stderr )
51
96
52
97
53
- def install_package (package , channels = DEFAULT_CHANNELS ):
98
+ def install_package (package , channels = DEFAULT_CHANNELS , link_conflict_action = LinkConflictAction . ERROR ):
54
99
conda .create_conda_environment (package , channels = channels )
55
100
executables_to_link = conda .detemine_executables_from_env (package )
56
101
mkpath (CONDAX_LINK_DESTINATION )
57
- create_links (executables_to_link )
102
+ create_links (executables_to_link , link_conflict_action )
58
103
print (f"`{ package } ` has been installed by condax" , file = sys .stderr )
59
104
60
105
@@ -74,13 +119,13 @@ def remove_package(package):
74
119
print (f"`{ package } ` has been removed from condax" , file = sys .stderr )
75
120
76
121
77
- def update_all_packages ():
122
+ def update_all_packages (link_conflict_action = LinkConflictAction . ERROR ):
78
123
for package in os .listdir (CONDA_ENV_PREFIX_PATH ):
79
124
if os .path .isdir (os .path .join (CONDA_ENV_PREFIX_PATH , package )):
80
- update_package (package )
125
+ update_package (package , link_conflict_action )
81
126
82
127
83
- def update_package (package ):
128
+ def update_package (package , link_conflict_action = LinkConflictAction . ERROR ):
84
129
exit_if_not_installed (package )
85
130
try :
86
131
executables_already_linked = set (conda .detemine_executables_from_env (package ))
@@ -93,7 +138,7 @@ def update_package(package):
93
138
to_create = executables_already_linked - executables_linked_in_updated
94
139
95
140
remove_links (to_delete )
96
- create_links (to_create )
141
+ create_links (to_create , link_conflict_action )
97
142
print (f"{ package } update successfully" )
98
143
99
144
except subprocess .CalledProcessError :
0 commit comments