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