3
3
import shutil
4
4
import typing
5
5
6
+ from pathlib import Path
7
+ import os
8
+
6
9
import pyaml
7
10
import questionary
8
11
import typer
11
14
from openllm .common import INTERACTIVE , REPO_DIR , VERBOSE_LEVEL , RepoInfo , load_config , output , save_config
12
15
13
16
UPDATE_INTERVAL = datetime .timedelta (days = 3 )
17
+ TEST_REPO = os .getenv ('OPENLLM_TEST_REPO' , None ) # for testing
18
+
14
19
15
20
app = OpenLLMTyper (help = 'manage repos' )
16
21
17
22
18
23
@app .command (name = 'list' , help = 'list available repo' )
19
- def list_repo (verbose : bool = False ):
24
+ def cmd_list (verbose : bool = False ):
20
25
if verbose :
21
26
VERBOSE_LEVEL .set (20 )
22
- config = load_config ()
23
27
pyaml .pprint (
24
- [ parse_repo_url ( repo , name ) for name , repo in config . repos . items ()] , sort_dicts = False , sort_keys = False
28
+ list_repo () , sort_dicts = False , sort_keys = False
25
29
)
26
30
27
31
28
- @app .command (help = 'remove given repo' )
29
- def remove (name : str ):
32
+ @app .command (name = 'remove' , help = 'remove given repo' )
33
+ def cmd_remove (name : str ):
34
+ if TEST_REPO :
35
+ return
30
36
config = load_config ()
31
37
if name not in config .repos :
32
38
output (f'Repo { name } does not exist' , style = 'red' )
@@ -37,6 +43,92 @@ def remove(name: str):
37
43
output (f'Repo { name } removed' , style = 'green' )
38
44
39
45
46
+ @app .command (name = 'update' , help = 'update default repo' )
47
+ def cmd_update ():
48
+ if TEST_REPO :
49
+ return
50
+ repos_in_use = set ()
51
+ for repo in list_repo ():
52
+ repos_in_use .add ((repo .server , repo .owner , repo .repo , repo .branch ))
53
+ if repo .path .exists ():
54
+ shutil .rmtree (repo .path , ignore_errors = True )
55
+ repo .path .parent .mkdir (parents = True , exist_ok = True )
56
+ try :
57
+ _clone_repo (repo )
58
+ output ('' )
59
+ output (f'Repo `{ repo .name } ` updated' , style = 'green' )
60
+ except Exception as e :
61
+ shutil .rmtree (repo .path , ignore_errors = True )
62
+ output (f'Failed to clone repo { repo .name } ' , style = 'red' )
63
+ output (e )
64
+ for c in REPO_DIR .glob ('*/*/*/*' ):
65
+ repo_spec = tuple (c .parts [- 4 :])
66
+ if repo_spec not in repos_in_use :
67
+ shutil .rmtree (c , ignore_errors = True )
68
+ output (f'Removed unused repo cache { c } ' )
69
+ with open (REPO_DIR / 'last_update' , 'w' ) as f :
70
+ f .write (datetime .datetime .now ().isoformat ())
71
+ for repo in list_repo ():
72
+ _complete_alias (repo .name )
73
+
74
+
75
+ @app .command (name = 'add' , help = 'add new repo' )
76
+ def cmd_add (name : str , repo : str ):
77
+ if TEST_REPO :
78
+ return
79
+ name = name .lower ()
80
+ if not name .isidentifier ():
81
+ output (f'Invalid repo name: { name } , should only contain letters, numbers and underscores' , style = 'red' )
82
+ return
83
+
84
+ try :
85
+ parse_repo_url (repo )
86
+ except ValueError :
87
+ output (f'Invalid repo url: { repo } ' , style = 'red' )
88
+ return
89
+
90
+ config = load_config ()
91
+ if name in config .repos :
92
+ override = questionary .confirm (f'Repo { name } already exists({ config .repos [name ]} ), override?' ).ask ()
93
+ if not override :
94
+ return
95
+
96
+ config .repos [name ] = repo
97
+ save_config (config )
98
+ output (f'Repo { name } added' , style = 'green' )
99
+
100
+
101
+ @app .command (name = 'default' , help = 'get default repo path' )
102
+ def default ():
103
+ if TEST_REPO :
104
+ return
105
+ output ((info := parse_repo_url (load_config ().repos ['default' ], 'default' )).path )
106
+ return info .path
107
+
108
+
109
+ def list_repo (repo_name : typing .Optional [str ]= None ) -> typing .List [RepoInfo ]:
110
+ if TEST_REPO :
111
+ return [
112
+ RepoInfo (
113
+ name = 'default' ,
114
+ url = '' ,
115
+ server = 'test' ,
116
+ owner = 'test' ,
117
+ repo = 'test' ,
118
+ branch = 'main' ,
119
+ path = Path (TEST_REPO ),
120
+ )
121
+ ]
122
+ config = load_config ()
123
+ repos = []
124
+ for _repo_name , repo_url in config .repos .items ():
125
+ if repo_name is not None and _repo_name != repo_name :
126
+ continue
127
+ repo = parse_repo_url (repo_url , _repo_name )
128
+ repos .append (repo )
129
+ return repos
130
+
131
+
40
132
def _complete_alias (repo_name : str ):
41
133
from openllm .model import list_bento
42
134
@@ -63,35 +155,6 @@ def _clone_repo(repo: RepoInfo):
63
155
dulwich .porcelain .clone (repo .url , str (repo .path ), checkout = True , depth = 1 , branch = repo .branch )
64
156
65
157
66
- @app .command (help = 'update default repo' )
67
- def update ():
68
- config = load_config ()
69
- repos_in_use = set ()
70
- for repo_name , repo in config .repos .items ():
71
- repo = parse_repo_url (repo , repo_name )
72
- repos_in_use .add ((repo .server , repo .owner , repo .repo , repo .branch ))
73
- if repo .path .exists ():
74
- shutil .rmtree (repo .path , ignore_errors = True )
75
- repo .path .parent .mkdir (parents = True , exist_ok = True )
76
- try :
77
- _clone_repo (repo )
78
- output ('' )
79
- output (f'Repo `{ repo .name } ` updated' , style = 'green' )
80
- except Exception as e :
81
- shutil .rmtree (repo .path , ignore_errors = True )
82
- output (f'Failed to clone repo { repo .name } ' , style = 'red' )
83
- output (e )
84
- for c in REPO_DIR .glob ('*/*/*/*' ):
85
- repo_spec = tuple (c .parts [- 4 :])
86
- if repo_spec not in repos_in_use :
87
- shutil .rmtree (c , ignore_errors = True )
88
- output (f'Removed unused repo cache { c } ' )
89
- with open (REPO_DIR / 'last_update' , 'w' ) as f :
90
- f .write (datetime .datetime .now ().isoformat ())
91
- for repo_name in config .repos :
92
- _complete_alias (repo_name )
93
-
94
-
95
158
def ensure_repo_updated ():
96
159
last_update_file = REPO_DIR / 'last_update'
97
160
if not last_update_file .exists ():
@@ -182,35 +245,5 @@ def parse_repo_url(repo_url: str, repo_name: typing.Optional[str] = None) -> Rep
182
245
)
183
246
184
247
185
- @app .command (help = 'add new repo' )
186
- def add (name : str , repo : str ):
187
- name = name .lower ()
188
- if not name .isidentifier ():
189
- output (f'Invalid repo name: { name } , should only contain letters, numbers and underscores' , style = 'red' )
190
- return
191
-
192
- try :
193
- parse_repo_url (repo )
194
- except ValueError :
195
- output (f'Invalid repo url: { repo } ' , style = 'red' )
196
- return
197
-
198
- config = load_config ()
199
- if name in config .repos :
200
- override = questionary .confirm (f'Repo { name } already exists({ config .repos [name ]} ), override?' ).ask ()
201
- if not override :
202
- return
203
-
204
- config .repos [name ] = repo
205
- save_config (config )
206
- output (f'Repo { name } added' , style = 'green' )
207
-
208
-
209
- @app .command (help = 'get default repo path' )
210
- def default ():
211
- output ((info := parse_repo_url (load_config ().repos ['default' ], 'default' )).path )
212
- return info .path
213
-
214
-
215
248
if __name__ == '__main__' :
216
249
app ()
0 commit comments