mirror of
https://github.com/meta-llama/llama-stack.git
synced 2025-07-26 06:07:43 +00:00
168 lines
5.7 KiB
Python
168 lines
5.7 KiB
Python
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
# All rights reserved.
|
|
#
|
|
# This source code is licensed under the terms described in the LICENSE file in
|
|
# the root directory of this source tree.
|
|
|
|
import argparse
|
|
import shutil
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
from llama_stack.distribution.utils.xdg_utils import (
|
|
get_llama_stack_config_dir,
|
|
get_llama_stack_data_dir,
|
|
get_llama_stack_state_dir,
|
|
)
|
|
|
|
from .subcommand import Subcommand
|
|
|
|
|
|
class MigrateXDG(Subcommand):
|
|
"""CLI command for migrating from legacy ~/.llama to XDG-compliant directories."""
|
|
|
|
def __init__(self, subparsers: argparse._SubParsersAction):
|
|
super().__init__()
|
|
self.parser = subparsers.add_parser(
|
|
"migrate-xdg",
|
|
prog="llama migrate-xdg",
|
|
description="Migrate from legacy ~/.llama to XDG-compliant directories",
|
|
formatter_class=argparse.RawTextHelpFormatter,
|
|
)
|
|
|
|
self.parser.add_argument(
|
|
"--dry-run", action="store_true", help="Show what would be done without actually moving files"
|
|
)
|
|
|
|
self.parser.set_defaults(func=self._run_migrate_xdg_cmd)
|
|
|
|
@staticmethod
|
|
def create(subparsers: argparse._SubParsersAction):
|
|
return MigrateXDG(subparsers)
|
|
|
|
def _run_migrate_xdg_cmd(self, args: argparse.Namespace) -> None:
|
|
"""Run the migrate-xdg command."""
|
|
if not migrate_to_xdg(dry_run=args.dry_run):
|
|
sys.exit(1)
|
|
|
|
|
|
def migrate_to_xdg(dry_run: bool = False) -> bool:
|
|
"""
|
|
Migrate from legacy ~/.llama to XDG-compliant directories.
|
|
|
|
Args:
|
|
dry_run: If True, only show what would be done without actually moving files
|
|
|
|
Returns:
|
|
bool: True if migration was successful or not needed, False otherwise
|
|
"""
|
|
legacy_path = Path.home() / ".llama"
|
|
|
|
if not legacy_path.exists():
|
|
print("No legacy ~/.llama directory found. Nothing to migrate.")
|
|
return True
|
|
|
|
# Check if we're already using XDG paths
|
|
config_dir = get_llama_stack_config_dir()
|
|
data_dir = get_llama_stack_data_dir()
|
|
state_dir = get_llama_stack_state_dir()
|
|
|
|
if str(config_dir) == str(legacy_path):
|
|
print("Already using legacy directory. No migration needed.")
|
|
return True
|
|
|
|
print(f"Found legacy directory at: {legacy_path}")
|
|
print("Will migrate to XDG-compliant directories:")
|
|
print(f" Config: {config_dir}")
|
|
print(f" Data: {data_dir}")
|
|
print(f" State: {state_dir}")
|
|
print()
|
|
|
|
# Define migration mapping
|
|
migrations = [
|
|
# (source_subdir, target_base_dir, description)
|
|
("distributions", config_dir, "Distribution configurations"),
|
|
("providers.d", config_dir, "External provider configurations"),
|
|
("checkpoints", data_dir, "Model checkpoints"),
|
|
("runtime", state_dir, "Runtime state files"),
|
|
]
|
|
|
|
# Check what needs to be migrated
|
|
items_to_migrate = []
|
|
for subdir, target_base, description in migrations:
|
|
source_path = legacy_path / subdir
|
|
if source_path.exists():
|
|
target_path = target_base / subdir
|
|
items_to_migrate.append((source_path, target_path, description))
|
|
|
|
if not items_to_migrate:
|
|
print("No items found to migrate.")
|
|
return True
|
|
|
|
print("Items to migrate:")
|
|
for source_path, target_path, description in items_to_migrate:
|
|
print(f" {description}: {source_path} -> {target_path}")
|
|
|
|
if dry_run:
|
|
print("\nDry run mode: No files will be moved.")
|
|
return True
|
|
|
|
# Ask for confirmation
|
|
response = input("\nDo you want to proceed with the migration? (y/N): ")
|
|
if response.lower() not in ["y", "yes"]:
|
|
print("Migration cancelled.")
|
|
return False
|
|
|
|
# Perform the migration
|
|
print("\nMigrating files...")
|
|
|
|
for source_path, target_path, description in items_to_migrate:
|
|
try:
|
|
# Create target directory if it doesn't exist
|
|
target_path.parent.mkdir(parents=True, exist_ok=True)
|
|
|
|
# Check if target already exists
|
|
if target_path.exists():
|
|
print(f" Warning: Target already exists: {target_path}")
|
|
print(f" Skipping {description}")
|
|
continue
|
|
|
|
# Move the directory
|
|
shutil.move(str(source_path), str(target_path))
|
|
print(f" Moved {description}: {source_path} -> {target_path}")
|
|
|
|
except Exception as e:
|
|
print(f" Error migrating {description}: {e}")
|
|
return False
|
|
|
|
# Check if legacy directory is now empty (except for hidden files)
|
|
remaining_items = [item for item in legacy_path.iterdir() if not item.name.startswith(".")]
|
|
if not remaining_items:
|
|
print(f"\nMigration complete! Legacy directory {legacy_path} is now empty.")
|
|
response = input("Remove empty legacy directory? (y/N): ")
|
|
if response.lower() in ["y", "yes"]:
|
|
try:
|
|
shutil.rmtree(legacy_path)
|
|
print(f"Removed empty legacy directory: {legacy_path}")
|
|
except Exception as e:
|
|
print(f"Could not remove legacy directory: {e}")
|
|
else:
|
|
print(f"\nMigration complete! Some items remain in legacy directory: {remaining_items}")
|
|
|
|
print("\nMigration successful!")
|
|
print("You may need to update any custom scripts or configurations that reference the old paths.")
|
|
return True
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(description="Migrate from legacy ~/.llama to XDG-compliant directories")
|
|
parser.add_argument("--dry-run", action="store_true", help="Show what would be done without actually moving files")
|
|
|
|
args = parser.parse_args()
|
|
|
|
if not migrate_to_xdg(dry_run=args.dry_run):
|
|
sys.exit(1)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|