Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions sdk/python/feast/cli/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -412,21 +412,26 @@ def materialize_incremental_command(ctx: click.Context, end_ts: str, views: List
"milvus",
"ray",
"ray_rag",
"pytorch_nlp",
],
case_sensitive=False,
),
help="Specify a template for the created project",
default="local",
)
def init_command(project_directory, minimal: bool, template: str):
@click.option(
"--repo-path",
help="Directory path where the repository will be created (default: create subdirectory with project name)",
)
def init_command(project_directory, minimal: bool, template: str, repo_path: str):
"""Create a new Feast repository"""
if not project_directory:
project_directory = generate_project_name()

if minimal:
template = "minimal"

init_repo(project_directory, template)
init_repo(project_directory, template, repo_path)


@cli.command("listen")
Expand Down
36 changes: 23 additions & 13 deletions sdk/python/feast/repo_operations.py
Original file line number Diff line number Diff line change
Expand Up @@ -445,27 +445,37 @@ def cli_check_repo(repo_path: Path, fs_yaml_file: Path):
sys.exit(1)


def init_repo(repo_name: str, template: str):
def init_repo(repo_name: str, template: str, repo_path: Optional[str] = None):
import os
from pathlib import Path
from shutil import copytree

from colorama import Fore, Style

# Validate project name
if not is_valid_name(repo_name):
raise BadParameter(
message="Name should be alphanumeric values, underscores, and hyphens but not start with an underscore or hyphen",
param_hint="PROJECT_DIRECTORY",
)
repo_path = Path(os.path.join(Path.cwd(), repo_name))
repo_path.mkdir(exist_ok=True)
repo_config_path = repo_path / "feature_store.yaml"

if repo_config_path.exists():
new_directory = os.path.relpath(repo_path, os.getcwd())
# Determine where to create the repository
if repo_path:
# User specified a custom path
target_path = Path(repo_path).resolve()
target_path.mkdir(parents=True, exist_ok=True)
display_path = repo_path
else:
# Default behavior: create subdirectory with project name
target_path = Path(os.path.join(Path.cwd(), repo_name))
target_path.mkdir(exist_ok=True)
display_path = repo_name

repo_config_path = target_path / "feature_store.yaml"

if repo_config_path.exists():
print(
f"The directory {Style.BRIGHT + Fore.GREEN}{new_directory}{Style.RESET_ALL} contains an existing feature "
f"The directory {Style.BRIGHT + Fore.GREEN}{display_path}{Style.RESET_ALL} contains an existing feature "
f"store repository that may cause a conflict"
)
print()
Expand All @@ -475,14 +485,14 @@ def init_repo(repo_name: str, template: str):
template_path = str(Path(Path(__file__).parent / "templates" / template).absolute())
if not os.path.exists(template_path):
raise IOError(f"Could not find template {template}")
copytree(template_path, str(repo_path), dirs_exist_ok=True)
copytree(template_path, str(target_path), dirs_exist_ok=True)

# Rename gitignore files back to .gitignore
for gitignore_path in repo_path.rglob("gitignore"):
for gitignore_path in target_path.rglob("gitignore"):
gitignore_path.rename(gitignore_path.with_name(".gitignore"))

# Seed the repository
bootstrap_path = repo_path / "bootstrap.py"
bootstrap_path = target_path / "bootstrap.py"
if os.path.exists(bootstrap_path):
import importlib.util

Expand All @@ -495,21 +505,21 @@ def init_repo(repo_name: str, template: str):
os.remove(bootstrap_path)

# Template the feature_store.yaml file
feature_store_yaml_path = repo_path / "feature_repo" / "feature_store.yaml"
feature_store_yaml_path = target_path / "feature_repo" / "feature_store.yaml"
replace_str_in_file(
feature_store_yaml_path, "project: my_project", f"project: {repo_name}"
)

# Remove the __pycache__ folder if it exists
import shutil

shutil.rmtree(repo_path / "__pycache__", ignore_errors=True)
shutil.rmtree(target_path / "__pycache__", ignore_errors=True)

import click

click.echo()
click.echo(
f"Creating a new Feast repository in {Style.BRIGHT + Fore.GREEN}{repo_path}{Style.RESET_ALL}."
f"Creating a new Feast repository in {Style.BRIGHT + Fore.GREEN}{target_path}{Style.RESET_ALL}."
)
click.echo()

Expand Down
Loading
Loading