Skip to content

Commit 79e54a7

Browse files
authored
Merge branch 'dev' into dev
2 parents 9d64ee4 + 6e1e566 commit 79e54a7

File tree

3 files changed

+131
-17
lines changed

3 files changed

+131
-17
lines changed

.github/workflows/ai-pr-review.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,16 @@ jobs:
1717
uses: actions/checkout@v4
1818
with:
1919
fetch-depth: 0
20+
ref: ${{ github.event.pull_request.base.ref }}
2021

2122
- name: Install dependencies
2223
run: |
2324
pip install requests jq
2425
26+
- name: Fetch PR head
27+
run: |
28+
git fetch origin ${{ github.event.pull_request.head.sha }}
29+
2530
- name: Get incremental diff
2631
id: diff
2732
run: |

mlc/index.py

Lines changed: 110 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ def __init__(self, repos_path, repos):
2727
"""
2828
self.repos_path = repos_path
2929
self.repos = repos
30-
#logger.info(repos)
3130

3231
logger.debug(f"Repos path for Index: {self.repos_path}")
3332
self.index_files = {
@@ -152,7 +151,64 @@ def get_item_mtime(self,file):
152151
if t > latest:
153152
latest = t
154153
return latest
155-
154+
155+
def _index_single_repo(self, repo, repos_changed=False, current_item_keys=None):
156+
repo_path = repo.path
157+
if not os.path.isdir(repo_path):
158+
return False
159+
160+
changed = False
161+
162+
for folder_type in ["script", "cache", "experiment"]:
163+
folder_path = os.path.join(repo_path, folder_type)
164+
if not os.path.isdir(folder_path):
165+
continue
166+
167+
for automation_dir in os.listdir(folder_path):
168+
automation_path = os.path.join(folder_path, automation_dir)
169+
if not os.path.isdir(automation_path):
170+
continue
171+
172+
yaml_path = os.path.join(automation_path, "meta.yaml")
173+
json_path = os.path.join(automation_path, "meta.json")
174+
175+
if os.path.isfile(yaml_path):
176+
config_path = yaml_path
177+
elif os.path.isfile(json_path):
178+
config_path = json_path
179+
else:
180+
#logger.debug(f"No config file found in {automation_path}, skipping")
181+
delete_flag = False
182+
if automation_dir in self.modified_times:
183+
del self.modified_times[automation_dir]
184+
if any(automation_dir in item["path"] for item in self.indices[folder_type]):
185+
logger.debug(f"Removed index entry (if it exists) for {folder_type} : {automation_dir}")
186+
delete_flag = True
187+
self._remove_index_entry(automation_path)
188+
if delete_flag:
189+
self._save_indices()
190+
continue
191+
if current_item_keys is not None:
192+
current_item_keys.add(config_path)
193+
mtime = self.get_item_mtime(config_path)
194+
old = self.modified_times.get(config_path)
195+
old_mtime = old["mtime"] if isinstance(old, dict) else old
196+
197+
# skip if unchanged
198+
if old_mtime == mtime and repos_changed != 1:
199+
continue
200+
201+
self.modified_times[config_path] = {
202+
"mtime": mtime,
203+
"date_time": datetime.fromtimestamp(mtime).strftime("%Y-%m-%d %H:%M:%S")
204+
}
205+
206+
# meta file changed, so reindex
207+
self._process_config_file(config_path, folder_type, automation_path, repo)
208+
changed = True
209+
210+
return changed
211+
156212
def build_index(self):
157213
"""
158214
Build shared indices for script, cache, and experiment folders across all repositories.
@@ -164,19 +220,15 @@ def build_index(self):
164220
# track all currently detected item paths
165221
current_item_keys = set()
166222
changed = False
167-
repos_changed = False
168-
169-
# load existing modified times
223+
force_rebuild = False
224+
225+
# load modified times
170226
self.modified_times = self._load_modified_times()
171227

228+
# if missing index file, then force full rebuild
172229
index_json_path = os.path.join(self.repos_path, "index_script.json")
173-
174-
rebuild_index = False
175-
176-
#file does not exist, rebuild
177230
if not os.path.exists(index_json_path):
178231
logger.warning("index_script.json missing. Forcing full index rebuild...")
179-
#logger.debug("Resetting modified_times...")
180232
self.modified_times = {}
181233
self._save_modified_times()
182234
#else:
@@ -211,6 +263,7 @@ def build_index(self):
211263
#else:
212264
# logger.debug("Repos.json not modified")
213265

266+
# index each repo
214267
for repo in self.repos:
215268
repo_path = repo.path #os.path.join(self.repos_path, repo)
216269
if not os.path.isdir(repo_path):
@@ -287,8 +340,7 @@ def build_index(self):
287340
self._process_config_file(config_path, folder_type, automation_path, repo)
288341

289342
# remove deleted scripts
290-
old_keys = set(self.modified_times.keys())
291-
deleted_keys = old_keys - current_item_keys
343+
deleted_keys = set(self.modified_times) - current_item_keys
292344
for key in deleted_keys:
293345
logger.warning(f"Detected deleted item, removing entry from modified times: {key}")
294346
del self.modified_times[key]
@@ -299,13 +351,10 @@ def build_index(self):
299351
if deleted_keys:
300352
logger.debug(f"Deleted keys removed from modified times and indices: {deleted_keys}")
301353

302-
if changed:
354+
if force_rebuild or changed:
303355
logger.debug("Changes detected, saving updated index and modified times.")
304356
self._save_modified_times()
305357
self._save_indices()
306-
#logger.debug("**************Index updated (changes detected).*************************")
307-
#else:
308-
#logger.debug("**************Index unchanged (no changes detected).********************")
309358

310359
def _remove_index_entry(self, key):
311360
logger.debug(f"Removing index entry for {key}")
@@ -399,3 +448,48 @@ def _save_indices(self):
399448
#logger.debug(f"Shared index for {folder_type} saved to {output_file}.")
400449
except Exception as e:
401450
logger.error(f"Error saving shared index for {folder_type}: {e}")
451+
452+
453+
def add_repo(self, repo):
454+
"""
455+
Incrementally index a newly registered repository.
456+
"""
457+
changed = self._index_single_repo(repo, repos_changed=True)
458+
459+
if changed:
460+
self._save_indices()
461+
self._save_modified_times()
462+
463+
464+
def remove_repo_from_index(self, repo_path):
465+
"""
466+
Remove all index entries and modified times belonging to a repo.
467+
Called when a repo is unregistered from repos.json.
468+
"""
469+
470+
logger.info(f"Removing repo from index: {repo_path}")
471+
changed = False
472+
473+
# remove index entries
474+
for folder_type in self.indices:
475+
before = len(self.indices[folder_type])
476+
self.indices[folder_type] = [
477+
item for item in self.indices[folder_type]
478+
if not item["path"].startswith(repo_path)
479+
]
480+
if len(self.indices[folder_type]) != before:
481+
changed = True
482+
483+
# remove modified times
484+
keys_to_delete = [
485+
k for k in self.modified_times
486+
if k.startswith(repo_path)
487+
]
488+
489+
for k in keys_to_delete:
490+
del self.modified_times[k]
491+
changed = True
492+
493+
if changed:
494+
self._save_indices()
495+
self._save_modified_times()

mlc/repo_action.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
from . import utils
99
from .logger import logger
1010
from urllib.parse import urlparse
11+
from .repo import Repo
12+
from .index import Index
1113

1214
class RepoAction(Action):
1315
"""
@@ -166,6 +168,16 @@ def register_repo(self, repo_path, repo_meta, ignore_on_conflict=False):
166168
json.dump(repos_list, f, indent=2)
167169
logger.info(f"Updated repos.json at {repos_file_path}")
168170

171+
self.repos = self.load_repos_and_meta()
172+
repo_obj = next(
173+
(r for r in self.repos if r.path == repo_path),
174+
None
175+
)
176+
177+
if repo_obj:
178+
index = Action.get_index(self)
179+
index.add_repo(repo_obj)
180+
logger.debug("Index file has been updated")
169181

170182
return {'return': 0}
171183

@@ -507,7 +519,8 @@ def rm(self, run_args):
507519
Action: rm
508520
####################################################################################################################
509521
510-
The `rm` action removes a specified repository from MLCFlow, deleting both the repo folder and its registration.
522+
The `rm` action removes a specified repository from MLCFlow, deleting the repository folder, its index entries,
523+
and its registration.
511524
If there are any modified local changes, the user will be prompted for confirmation unless the `-f` flag is used
512525
for force removal.
513526
@@ -554,6 +567,8 @@ def rm(self, run_args):
554567
repos_file_path = os.path.join(self.repos_path, 'repos.json')
555568

556569
force_remove = True if run_args.get('f') else False
570+
index = Action.get_index(self)
571+
index.remove_repo_from_index(repo_path)
557572

558573
return rm_repo(repo_path, repos_file_path, force_remove)
559574

0 commit comments

Comments
 (0)