Skip to content

Commit e8224c5

Browse files
agentagent
agent
authored and
agent
committed
chore: add OPENLLM_TEST_REPO
1 parent c506b55 commit e8224c5

File tree

3 files changed

+106
-75
lines changed

3 files changed

+106
-75
lines changed

src/openllm/common.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
SUCCESS_STYLE = 'green'
2424

2525
OPENLLM_HOME = pathlib.Path(os.getenv('OPENLLM_HOME', pathlib.Path.home() / '.openllm'))
26+
2627
REPO_DIR = OPENLLM_HOME / 'repos'
2728
TEMP_DIR = OPENLLM_HOME / 'temp'
2829
VENV_DIR = OPENLLM_HOME / 'venv'

src/openllm/model.py

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77

88
from openllm.accelerator_spec import DeploymentTarget, can_run
99
from openllm.analytic import OpenLLMTyper
10-
from openllm.common import VERBOSE_LEVEL, BentoInfo, load_config, output
11-
from openllm.repo import ensure_repo_updated, parse_repo_url
10+
from openllm.common import VERBOSE_LEVEL, BentoInfo, output
11+
from openllm.repo import ensure_repo_updated, list_repo
1212

1313
app = OpenLLMTyper(help='manage models')
1414

@@ -95,11 +95,12 @@ def list_bento(
9595
if repo_name is None and tag and '/' in tag:
9696
repo_name, tag = tag.split('/', 1)
9797

98+
repo_list = list_repo(repo_name)
9899
if repo_name is not None:
99-
config = load_config()
100-
if repo_name not in config.repos:
100+
repo_map = {repo.name: repo for repo in repo_list}
101+
if repo_name not in repo_map:
101102
output(f'Repo `{repo_name}` not found, did you mean one of these?')
102-
for repo_name in config.repos:
103+
for repo_name in repo_map:
103104
output(f' {repo_name}')
104105
raise typer.Exit(1)
105106

@@ -112,12 +113,8 @@ def list_bento(
112113
glob_pattern = f'bentoml/bentos/{tag}/*'
113114

114115
model_list = []
115-
config = load_config()
116-
for _repo_name, repo_url in config.repos.items():
117-
if repo_name is not None and _repo_name != repo_name:
118-
continue
119-
repo = parse_repo_url(repo_url, _repo_name)
120-
116+
repo_list = list_repo(repo_name)
117+
for repo in repo_list:
121118
paths = sorted(
122119
repo.path.glob(glob_pattern),
123120
key=lambda x: (x.parent.name, _extract_first_number(x.name), len(x.name), x.name),

src/openllm/repo.py

Lines changed: 97 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
import shutil
44
import typing
55

6+
from pathlib import Path
7+
import os
8+
69
import pyaml
710
import questionary
811
import typer
@@ -11,22 +14,25 @@
1114
from openllm.common import INTERACTIVE, REPO_DIR, VERBOSE_LEVEL, RepoInfo, load_config, output, save_config
1215

1316
UPDATE_INTERVAL = datetime.timedelta(days=3)
17+
TEST_REPO = os.getenv('OPENLLM_TEST_REPO', None) # for testing
18+
1419

1520
app = OpenLLMTyper(help='manage repos')
1621

1722

1823
@app.command(name='list', help='list available repo')
19-
def list_repo(verbose: bool = False):
24+
def cmd_list(verbose: bool = False):
2025
if verbose:
2126
VERBOSE_LEVEL.set(20)
22-
config = load_config()
2327
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
2529
)
2630

2731

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
3036
config = load_config()
3137
if name not in config.repos:
3238
output(f'Repo {name} does not exist', style='red')
@@ -37,6 +43,92 @@ def remove(name: str):
3743
output(f'Repo {name} removed', style='green')
3844

3945

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+
40132
def _complete_alias(repo_name: str):
41133
from openllm.model import list_bento
42134

@@ -63,35 +155,6 @@ def _clone_repo(repo: RepoInfo):
63155
dulwich.porcelain.clone(repo.url, str(repo.path), checkout=True, depth=1, branch=repo.branch)
64156

65157

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-
95158
def ensure_repo_updated():
96159
last_update_file = REPO_DIR / 'last_update'
97160
if not last_update_file.exists():
@@ -182,35 +245,5 @@ def parse_repo_url(repo_url: str, repo_name: typing.Optional[str] = None) -> Rep
182245
)
183246

184247

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-
215248
if __name__ == '__main__':
216249
app()

0 commit comments

Comments
 (0)