unitysvc-services 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,186 @@
1
+ """Populate command - populate services by executing provider scripts."""
2
+
3
+ import json
4
+ import os
5
+ import subprocess
6
+ import tomllib
7
+ from pathlib import Path
8
+
9
+ import typer
10
+ from rich.console import Console
11
+
12
+ from .utils import find_files_by_schema
13
+
14
+ app = typer.Typer(help="Populate services")
15
+ console = Console()
16
+
17
+
18
+ @app.command()
19
+ def populate(
20
+ data_dir: Path | None = typer.Argument(
21
+ None,
22
+ help="Directory containing provider data files (default: ./data or UNITYSVC_DATA_DIR env var)",
23
+ ),
24
+ provider_name: str | None = typer.Option(
25
+ None,
26
+ "--provider",
27
+ "-p",
28
+ help="Only populate services for a specific provider",
29
+ ),
30
+ dry_run: bool = typer.Option(
31
+ False,
32
+ "--dry-run",
33
+ help="Show what would be executed without actually running commands",
34
+ ),
35
+ ):
36
+ """
37
+ Populate services by executing provider-specific update scripts.
38
+
39
+ This command scans provider files for 'services_populator' configuration and executes
40
+ the specified commands with environment variables from 'provider_access_info'.
41
+ """
42
+ # Set data directory
43
+ if data_dir is None:
44
+ data_dir_str = os.getenv("UNITYSVC_DATA_DIR")
45
+ if data_dir_str:
46
+ data_dir = Path(data_dir_str)
47
+ else:
48
+ data_dir = Path.cwd() / "data"
49
+
50
+ if not data_dir.is_absolute():
51
+ data_dir = Path.cwd() / data_dir
52
+
53
+ if not data_dir.exists():
54
+ console.print(f"[red]✗[/red] Data directory not found: {data_dir}", style="bold red")
55
+ raise typer.Exit(code=1)
56
+
57
+ console.print(f"[blue]Scanning for provider configurations in:[/blue] {data_dir}\n")
58
+
59
+ # Find all provider files by schema
60
+ provider_results = find_files_by_schema(data_dir, "provider_v1")
61
+ provider_files = [file_path for file_path, _, _ in provider_results]
62
+
63
+ if not provider_files:
64
+ console.print("[yellow]No provider files found.[/yellow]")
65
+ raise typer.Exit(code=0)
66
+
67
+ console.print(f"[cyan]Found {len(provider_files)} provider file(s)[/cyan]\n")
68
+
69
+ # Process each provider
70
+ total_executed = 0
71
+ total_skipped = 0
72
+ total_failed = 0
73
+
74
+ for provider_file in provider_files:
75
+ try:
76
+ # Load provider configuration
77
+ if provider_file.suffix == ".toml":
78
+ with open(provider_file, "rb") as f:
79
+ provider_config = tomllib.load(f)
80
+ else:
81
+ with open(provider_file) as f:
82
+ provider_config = json.load(f)
83
+
84
+ provider_name_in_file = provider_config.get("name", "unknown")
85
+
86
+ # Skip if provider filter is set and doesn't match
87
+ if provider_name and provider_name_in_file != provider_name:
88
+ console.print(f"[dim]Skipping provider: {provider_name_in_file} (filter: {provider_name})[/dim]")
89
+ total_skipped += 1
90
+ continue
91
+
92
+ # Check if services_populator is configured
93
+ services_populator = provider_config.get("services_populator")
94
+ if not services_populator:
95
+ console.print(f"[yellow]⏭️ Skipping {provider_name_in_file}: No services_populator configured[/yellow]")
96
+ total_skipped += 1
97
+ continue
98
+
99
+ command = services_populator.get("command")
100
+ if not command:
101
+ console.print(
102
+ f"[yellow]⏭️ Skipping {provider_name_in_file}: No command specified in services_populator[/yellow]"
103
+ )
104
+ total_skipped += 1
105
+ continue
106
+
107
+ console.print(f"[bold cyan]Processing provider:[/bold cyan] {provider_name_in_file}")
108
+
109
+ # Prepare environment variables from provider_access_info
110
+ env = os.environ.copy()
111
+ provider_access_info = provider_config.get("provider_access_info", {})
112
+ if provider_access_info:
113
+ for key, value in provider_access_info.items():
114
+ env[key] = str(value)
115
+ console.print(
116
+ f"[dim] Set {len(provider_access_info)} environment variable(s) from provider_access_info[/dim]"
117
+ )
118
+
119
+ # Get the provider directory (parent of provider file)
120
+ provider_dir = provider_file.parent
121
+
122
+ # Build command - handle both string and list formats
123
+ if isinstance(command, str):
124
+ cmd_parts = command.split()
125
+ else:
126
+ cmd_parts = command
127
+
128
+ # Resolve script path relative to provider directory
129
+ script_path = provider_dir / cmd_parts[0]
130
+ if script_path.exists():
131
+ cmd_parts[0] = str(script_path)
132
+
133
+ full_command = ["python3"] + cmd_parts
134
+
135
+ console.print(f"[blue] Command:[/blue] {' '.join(full_command)}")
136
+ console.print(f"[blue] Working directory:[/blue] {provider_dir}")
137
+
138
+ if dry_run:
139
+ console.print("[yellow] [DRY-RUN] Would execute command[/yellow]\n")
140
+ total_skipped += 1
141
+ continue
142
+
143
+ # Execute the command
144
+ try:
145
+ result = subprocess.run(
146
+ full_command,
147
+ cwd=provider_dir,
148
+ env=env,
149
+ capture_output=False,
150
+ text=True,
151
+ )
152
+
153
+ if result.returncode == 0:
154
+ console.print(f"[green]✓[/green] Successfully populated services for {provider_name_in_file}\n")
155
+ total_executed += 1
156
+ else:
157
+ console.print(
158
+ f"[red]✗[/red] Command failed for {provider_name_in_file} (exit code: {result.returncode})\n",
159
+ style="bold red",
160
+ )
161
+ total_failed += 1
162
+
163
+ except subprocess.SubprocessError as e:
164
+ console.print(
165
+ f"[red]✗[/red] Failed to execute command for {provider_name_in_file}: {e}\n",
166
+ style="bold red",
167
+ )
168
+ total_failed += 1
169
+
170
+ except Exception as e:
171
+ console.print(
172
+ f"[red]✗[/red] Error processing {provider_file}: {e}\n",
173
+ style="bold red",
174
+ )
175
+ total_failed += 1
176
+
177
+ # Print summary
178
+ console.print("\n" + "=" * 50)
179
+ console.print("[bold]Populate Services Summary:[/bold]")
180
+ console.print(f" Total providers found: {len(provider_files)}")
181
+ console.print(f" [green]✓ Successfully executed: {total_executed}[/green]")
182
+ console.print(f" [yellow]⏭️ Skipped: {total_skipped}[/yellow]")
183
+ console.print(f" [red]✗ Failed: {total_failed}[/red]")
184
+
185
+ if total_failed > 0:
186
+ raise typer.Exit(code=1)