comfy-env 0.1.15__py3-none-any.whl → 0.1.17__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.
- comfy_env/__init__.py +117 -40
- comfy_env/cli.py +122 -311
- comfy_env/config/__init__.py +12 -4
- comfy_env/config/parser.py +30 -79
- comfy_env/config/types.py +37 -0
- comfy_env/detection/__init__.py +77 -0
- comfy_env/detection/cuda.py +61 -0
- comfy_env/detection/gpu.py +230 -0
- comfy_env/detection/platform.py +70 -0
- comfy_env/detection/runtime.py +103 -0
- comfy_env/environment/__init__.py +53 -0
- comfy_env/environment/cache.py +141 -0
- comfy_env/environment/libomp.py +41 -0
- comfy_env/environment/paths.py +38 -0
- comfy_env/environment/setup.py +91 -0
- comfy_env/install.py +134 -331
- comfy_env/isolation/__init__.py +32 -2
- comfy_env/isolation/tensor_utils.py +83 -0
- comfy_env/isolation/workers/__init__.py +16 -0
- comfy_env/{workers → isolation/workers}/mp.py +1 -1
- comfy_env/{workers → isolation/workers}/subprocess.py +1 -1
- comfy_env/isolation/wrap.py +128 -509
- comfy_env/packages/__init__.py +60 -0
- comfy_env/packages/apt.py +36 -0
- comfy_env/packages/cuda_wheels.py +97 -0
- comfy_env/packages/node_dependencies.py +77 -0
- comfy_env/packages/pixi.py +85 -0
- comfy_env/packages/toml_generator.py +88 -0
- comfy_env-0.1.17.dist-info/METADATA +225 -0
- comfy_env-0.1.17.dist-info/RECORD +36 -0
- comfy_env/cache.py +0 -203
- comfy_env/nodes.py +0 -187
- comfy_env/pixi/__init__.py +0 -48
- comfy_env/pixi/core.py +0 -587
- comfy_env/pixi/cuda_detection.py +0 -303
- comfy_env/pixi/platform/__init__.py +0 -21
- comfy_env/pixi/platform/base.py +0 -96
- comfy_env/pixi/platform/darwin.py +0 -53
- comfy_env/pixi/platform/linux.py +0 -68
- comfy_env/pixi/platform/windows.py +0 -284
- comfy_env/pixi/resolver.py +0 -198
- comfy_env/prestartup.py +0 -208
- comfy_env/workers/__init__.py +0 -38
- comfy_env/workers/tensor_utils.py +0 -188
- comfy_env-0.1.15.dist-info/METADATA +0 -291
- comfy_env-0.1.15.dist-info/RECORD +0 -31
- /comfy_env/{workers → isolation/workers}/base.py +0 -0
- {comfy_env-0.1.15.dist-info → comfy_env-0.1.17.dist-info}/WHEEL +0 -0
- {comfy_env-0.1.15.dist-info → comfy_env-0.1.17.dist-info}/entry_points.txt +0 -0
- {comfy_env-0.1.15.dist-info → comfy_env-0.1.17.dist-info}/licenses/LICENSE +0 -0
comfy_env/cli.py
CHANGED
|
@@ -1,23 +1,4 @@
|
|
|
1
|
-
"""
|
|
2
|
-
CLI for comfy-env.
|
|
3
|
-
|
|
4
|
-
Provides the `comfy-env` command with subcommands:
|
|
5
|
-
- init: Create a default comfy-env.toml
|
|
6
|
-
- generate: Generate pixi.toml from comfy-env.toml
|
|
7
|
-
- install: Install dependencies from config
|
|
8
|
-
- info: Show runtime environment information
|
|
9
|
-
- doctor: Verify installation
|
|
10
|
-
|
|
11
|
-
Usage:
|
|
12
|
-
comfy-env init ---> creates template comfy-env.toml
|
|
13
|
-
comfy-env generate nodes/cgal/comfy-env.toml ---> nodes/cgal/pixi.toml
|
|
14
|
-
comfy-env install ---> installs from comfy
|
|
15
|
-
comfy-env install --dry-run
|
|
16
|
-
|
|
17
|
-
comfy-env info
|
|
18
|
-
|
|
19
|
-
comfy-env doctor
|
|
20
|
-
"""
|
|
1
|
+
"""CLI for comfy-env."""
|
|
21
2
|
|
|
22
3
|
import argparse
|
|
23
4
|
import sys
|
|
@@ -25,139 +6,56 @@ from pathlib import Path
|
|
|
25
6
|
from typing import List, Optional
|
|
26
7
|
|
|
27
8
|
from . import __version__
|
|
9
|
+
from .config import ROOT_CONFIG_FILE_NAME, CONFIG_FILE_NAME
|
|
28
10
|
|
|
29
11
|
|
|
30
12
|
def main(args: Optional[List[str]] = None) -> int:
|
|
31
|
-
"""
|
|
32
|
-
parser =
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
)
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
)
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
)
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
)
|
|
65
|
-
generate_parser.add_argument(
|
|
66
|
-
"--force", "-f",
|
|
67
|
-
action="store_true",
|
|
68
|
-
help="Overwrite existing pixi.toml",
|
|
69
|
-
)
|
|
70
|
-
|
|
71
|
-
# install command
|
|
72
|
-
install_parser = subparsers.add_parser(
|
|
73
|
-
"install",
|
|
74
|
-
help="Install dependencies from config",
|
|
75
|
-
description="Install CUDA wheels and dependencies from comfy-env.toml",
|
|
76
|
-
)
|
|
77
|
-
install_parser.add_argument(
|
|
78
|
-
"--config", "-c",
|
|
79
|
-
type=str,
|
|
80
|
-
help="Path to config file (default: auto-discover)",
|
|
81
|
-
)
|
|
82
|
-
install_parser.add_argument(
|
|
83
|
-
"--dry-run",
|
|
84
|
-
action="store_true",
|
|
85
|
-
help="Show what would be installed without installing",
|
|
86
|
-
)
|
|
87
|
-
install_parser.add_argument(
|
|
88
|
-
"--dir", "-d",
|
|
89
|
-
type=str,
|
|
90
|
-
help="Directory containing the config (default: current directory)",
|
|
91
|
-
)
|
|
92
|
-
|
|
93
|
-
# info command
|
|
94
|
-
info_parser = subparsers.add_parser(
|
|
95
|
-
"info",
|
|
96
|
-
help="Show runtime environment information",
|
|
97
|
-
description="Display detected Python, CUDA, PyTorch, and GPU information",
|
|
98
|
-
)
|
|
99
|
-
info_parser.add_argument(
|
|
100
|
-
"--json",
|
|
101
|
-
action="store_true",
|
|
102
|
-
help="Output as JSON",
|
|
103
|
-
)
|
|
104
|
-
|
|
105
|
-
# doctor command
|
|
106
|
-
doctor_parser = subparsers.add_parser(
|
|
107
|
-
"doctor",
|
|
108
|
-
help="Verify installation and diagnose issues",
|
|
109
|
-
description="Check if packages are properly installed and importable",
|
|
110
|
-
)
|
|
111
|
-
doctor_parser.add_argument(
|
|
112
|
-
"--package", "-p",
|
|
113
|
-
type=str,
|
|
114
|
-
help="Check specific package",
|
|
115
|
-
)
|
|
116
|
-
doctor_parser.add_argument(
|
|
117
|
-
"--config", "-c",
|
|
118
|
-
type=str,
|
|
119
|
-
help="Path to config file",
|
|
120
|
-
)
|
|
121
|
-
|
|
122
|
-
# apt-install command
|
|
123
|
-
apt_parser = subparsers.add_parser(
|
|
124
|
-
"apt-install",
|
|
125
|
-
help="Install system packages from [apt] section (Linux only)",
|
|
126
|
-
description="Read [apt] packages from comfy-env.toml and install via apt-get",
|
|
127
|
-
)
|
|
128
|
-
apt_parser.add_argument(
|
|
129
|
-
"--config", "-c",
|
|
130
|
-
type=str,
|
|
131
|
-
help="Path to comfy-env.toml (default: auto-discover)",
|
|
132
|
-
)
|
|
133
|
-
apt_parser.add_argument(
|
|
134
|
-
"--dry-run",
|
|
135
|
-
action="store_true",
|
|
136
|
-
help="Show what would be installed without installing",
|
|
137
|
-
)
|
|
13
|
+
parser = argparse.ArgumentParser(prog="comfy-env", description="Environment management for ComfyUI")
|
|
14
|
+
parser.add_argument("--version", action="version", version=f"comfy-env {__version__}")
|
|
15
|
+
sub = parser.add_subparsers(dest="command", help="Commands")
|
|
16
|
+
|
|
17
|
+
# init
|
|
18
|
+
p = sub.add_parser("init", help=f"Create {ROOT_CONFIG_FILE_NAME}")
|
|
19
|
+
p.add_argument("--force", "-f", action="store_true", help="Overwrite existing")
|
|
20
|
+
p.add_argument("--isolated", action="store_true", help=f"Create {CONFIG_FILE_NAME} instead (for isolated folders)")
|
|
21
|
+
|
|
22
|
+
# generate
|
|
23
|
+
p = sub.add_parser("generate", help="Generate pixi.toml from config")
|
|
24
|
+
p.add_argument("config", type=str, help="Path to config file")
|
|
25
|
+
p.add_argument("--force", "-f", action="store_true", help="Overwrite existing")
|
|
26
|
+
|
|
27
|
+
# install
|
|
28
|
+
p = sub.add_parser("install", help="Install dependencies")
|
|
29
|
+
p.add_argument("--config", "-c", type=str, help="Config path")
|
|
30
|
+
p.add_argument("--dry-run", action="store_true", help="Preview only")
|
|
31
|
+
p.add_argument("--dir", "-d", type=str, help="Node directory")
|
|
32
|
+
|
|
33
|
+
# info
|
|
34
|
+
p = sub.add_parser("info", help="Show runtime info")
|
|
35
|
+
p.add_argument("--json", action="store_true", help="JSON output")
|
|
36
|
+
|
|
37
|
+
# doctor
|
|
38
|
+
p = sub.add_parser("doctor", help="Verify installation")
|
|
39
|
+
p.add_argument("--package", "-p", type=str, help="Check specific package")
|
|
40
|
+
p.add_argument("--config", "-c", type=str, help="Config path")
|
|
41
|
+
|
|
42
|
+
# apt-install
|
|
43
|
+
p = sub.add_parser("apt-install", help="Install apt packages (Linux)")
|
|
44
|
+
p.add_argument("--config", "-c", type=str, help="Config path")
|
|
45
|
+
p.add_argument("--dry-run", action="store_true", help="Preview only")
|
|
138
46
|
|
|
139
47
|
parsed = parser.parse_args(args)
|
|
140
|
-
|
|
141
|
-
if parsed.command is None:
|
|
48
|
+
if not parsed.command:
|
|
142
49
|
parser.print_help()
|
|
143
50
|
return 0
|
|
144
51
|
|
|
52
|
+
commands = {
|
|
53
|
+
"init": cmd_init, "generate": cmd_generate, "install": cmd_install,
|
|
54
|
+
"info": cmd_info, "doctor": cmd_doctor, "apt-install": cmd_apt_install,
|
|
55
|
+
}
|
|
56
|
+
|
|
145
57
|
try:
|
|
146
|
-
|
|
147
|
-
return cmd_init(parsed)
|
|
148
|
-
elif parsed.command == "generate":
|
|
149
|
-
return cmd_generate(parsed)
|
|
150
|
-
elif parsed.command == "install":
|
|
151
|
-
return cmd_install(parsed)
|
|
152
|
-
elif parsed.command == "info":
|
|
153
|
-
return cmd_info(parsed)
|
|
154
|
-
elif parsed.command == "doctor":
|
|
155
|
-
return cmd_doctor(parsed)
|
|
156
|
-
elif parsed.command == "apt-install":
|
|
157
|
-
return cmd_apt_install(parsed)
|
|
158
|
-
else:
|
|
159
|
-
parser.print_help()
|
|
160
|
-
return 1
|
|
58
|
+
return commands.get(parsed.command, lambda _: 1)(parsed)
|
|
161
59
|
except KeyboardInterrupt:
|
|
162
60
|
print("\nInterrupted")
|
|
163
61
|
return 130
|
|
@@ -166,114 +64,96 @@ def main(args: Optional[List[str]] = None) -> int:
|
|
|
166
64
|
return 1
|
|
167
65
|
|
|
168
66
|
|
|
169
|
-
|
|
170
|
-
# comfy-env.toml -
|
|
171
|
-
#
|
|
67
|
+
ROOT_DEFAULT_CONFIG = """\
|
|
68
|
+
# comfy-env-root.toml - Main node config
|
|
69
|
+
# PyPI deps go in requirements.txt
|
|
70
|
+
|
|
71
|
+
[cuda]
|
|
72
|
+
packages = []
|
|
73
|
+
|
|
74
|
+
[apt]
|
|
75
|
+
packages = []
|
|
76
|
+
|
|
77
|
+
[dependencies]
|
|
78
|
+
# cgal = "*"
|
|
79
|
+
|
|
80
|
+
[env_vars]
|
|
81
|
+
# KMP_DUPLICATE_LIB_OK = "TRUE"
|
|
172
82
|
|
|
173
|
-
[
|
|
174
|
-
#
|
|
175
|
-
|
|
83
|
+
[node_reqs]
|
|
84
|
+
# ComfyUI_essentials = "cubiq/ComfyUI_essentials"
|
|
85
|
+
"""
|
|
176
86
|
|
|
177
|
-
|
|
87
|
+
ISOLATED_DEFAULT_CONFIG = """\
|
|
88
|
+
# comfy-env.toml - Isolated folder config
|
|
178
89
|
python = "3.11"
|
|
179
|
-
cuda_version = "auto"
|
|
180
|
-
pytorch_version = "auto"
|
|
181
90
|
|
|
182
|
-
[
|
|
183
|
-
#
|
|
184
|
-
|
|
91
|
+
[dependencies]
|
|
92
|
+
# cgal = "*"
|
|
93
|
+
|
|
94
|
+
[pypi-dependencies]
|
|
95
|
+
# trimesh = { version = "*", extras = ["easy"] }
|
|
185
96
|
|
|
186
|
-
[
|
|
187
|
-
|
|
97
|
+
[env_vars]
|
|
98
|
+
# SOME_VAR = "value"
|
|
188
99
|
"""
|
|
189
100
|
|
|
190
101
|
|
|
191
102
|
def cmd_init(args) -> int:
|
|
192
|
-
|
|
193
|
-
|
|
103
|
+
if getattr(args, 'isolated', False):
|
|
104
|
+
config_path = Path.cwd() / CONFIG_FILE_NAME
|
|
105
|
+
content = ISOLATED_DEFAULT_CONFIG
|
|
106
|
+
else:
|
|
107
|
+
config_path = Path.cwd() / ROOT_CONFIG_FILE_NAME
|
|
108
|
+
content = ROOT_DEFAULT_CONFIG
|
|
194
109
|
|
|
195
110
|
if config_path.exists() and not args.force:
|
|
196
|
-
print(f"
|
|
197
|
-
print("Use --force to overwrite", file=sys.stderr)
|
|
111
|
+
print(f"Already exists: {config_path}\nUse --force to overwrite", file=sys.stderr)
|
|
198
112
|
return 1
|
|
199
|
-
|
|
200
|
-
config_path.write_text(DEFAULT_CONFIG)
|
|
113
|
+
config_path.write_text(content)
|
|
201
114
|
print(f"Created {config_path}")
|
|
202
115
|
return 0
|
|
203
116
|
|
|
204
117
|
|
|
205
118
|
def cmd_generate(args) -> int:
|
|
206
|
-
|
|
207
|
-
from .
|
|
208
|
-
from .pixi import create_pixi_toml
|
|
119
|
+
from .config import load_config
|
|
120
|
+
from .packages.toml_generator import write_pixi_toml
|
|
209
121
|
|
|
210
122
|
config_path = Path(args.config).resolve()
|
|
211
|
-
|
|
212
123
|
if not config_path.exists():
|
|
213
|
-
print(f"
|
|
124
|
+
print(f"Not found: {config_path}", file=sys.stderr)
|
|
214
125
|
return 1
|
|
215
126
|
|
|
216
|
-
if config_path.name != "comfy-env.toml":
|
|
217
|
-
print(f"Warning: Expected comfy-env.toml, got {config_path.name}", file=sys.stderr)
|
|
218
|
-
|
|
219
127
|
node_dir = config_path.parent
|
|
220
128
|
pixi_path = node_dir / "pixi.toml"
|
|
221
|
-
|
|
222
129
|
if pixi_path.exists() and not args.force:
|
|
223
|
-
print(f"
|
|
224
|
-
print("Use --force to overwrite", file=sys.stderr)
|
|
130
|
+
print(f"Already exists: {pixi_path}\nUse --force to overwrite", file=sys.stderr)
|
|
225
131
|
return 1
|
|
226
132
|
|
|
227
|
-
# Load the config
|
|
228
133
|
config = load_config(config_path)
|
|
229
|
-
if not config
|
|
230
|
-
print(f"
|
|
134
|
+
if not config:
|
|
135
|
+
print(f"Failed to load: {config_path}", file=sys.stderr)
|
|
231
136
|
return 1
|
|
232
137
|
|
|
233
|
-
# Use the first environment
|
|
234
|
-
env_name = next(iter(config.envs.keys()))
|
|
235
|
-
env_config = config.envs[env_name]
|
|
236
|
-
|
|
237
138
|
print(f"Generating pixi.toml from {config_path}")
|
|
238
|
-
|
|
239
|
-
print(f"
|
|
240
|
-
|
|
241
|
-
# Generate pixi.toml
|
|
242
|
-
result_path = create_pixi_toml(env_config, node_dir)
|
|
243
|
-
|
|
244
|
-
print(f"Created {result_path}")
|
|
245
|
-
print()
|
|
246
|
-
print("Next steps:")
|
|
247
|
-
print(f" cd {node_dir}")
|
|
248
|
-
print(" pixi install")
|
|
139
|
+
write_pixi_toml(config, node_dir)
|
|
140
|
+
print(f"Created {pixi_path}\nNext: cd {node_dir} && pixi install")
|
|
249
141
|
return 0
|
|
250
142
|
|
|
251
143
|
|
|
252
144
|
def cmd_install(args) -> int:
|
|
253
|
-
"""Handle install command."""
|
|
254
145
|
from .install import install
|
|
255
|
-
|
|
256
146
|
node_dir = Path(args.dir) if args.dir else Path.cwd()
|
|
257
|
-
|
|
258
147
|
try:
|
|
259
|
-
install(
|
|
260
|
-
config=args.config,
|
|
261
|
-
node_dir=node_dir,
|
|
262
|
-
dry_run=args.dry_run,
|
|
263
|
-
)
|
|
148
|
+
install(config=args.config, node_dir=node_dir, dry_run=args.dry_run)
|
|
264
149
|
return 0
|
|
265
|
-
except FileNotFoundError as e:
|
|
266
|
-
print(f"Error: {e}", file=sys.stderr)
|
|
267
|
-
return 1
|
|
268
150
|
except Exception as e:
|
|
269
|
-
print(f"
|
|
151
|
+
print(f"Failed: {e}", file=sys.stderr)
|
|
270
152
|
return 1
|
|
271
153
|
|
|
272
154
|
|
|
273
155
|
def cmd_info(args) -> int:
|
|
274
|
-
|
|
275
|
-
from .pixi import RuntimeEnv
|
|
276
|
-
|
|
156
|
+
from .detection import RuntimeEnv
|
|
277
157
|
env = RuntimeEnv.detect()
|
|
278
158
|
|
|
279
159
|
if args.json:
|
|
@@ -281,149 +161,80 @@ def cmd_info(args) -> int:
|
|
|
281
161
|
print(json.dumps(env.as_dict(), indent=2))
|
|
282
162
|
return 0
|
|
283
163
|
|
|
284
|
-
print("Runtime Environment")
|
|
285
|
-
print("
|
|
286
|
-
print(f"
|
|
287
|
-
print(f"
|
|
288
|
-
print(f"
|
|
289
|
-
|
|
290
|
-
if env.cuda_version:
|
|
291
|
-
print(f" CUDA: {env.cuda_version}")
|
|
292
|
-
else:
|
|
293
|
-
print(" CUDA: Not detected")
|
|
294
|
-
|
|
295
|
-
if env.torch_version:
|
|
296
|
-
print(f" PyTorch: {env.torch_version}")
|
|
297
|
-
else:
|
|
298
|
-
print(" PyTorch: Not installed")
|
|
299
|
-
|
|
164
|
+
print("Runtime Environment\n" + "=" * 40)
|
|
165
|
+
print(f" OS: {env.os_name}")
|
|
166
|
+
print(f" Platform: {env.platform_tag}")
|
|
167
|
+
print(f" Python: {env.python_version}")
|
|
168
|
+
print(f" CUDA: {env.cuda_version or 'Not detected'}")
|
|
169
|
+
print(f" PyTorch: {env.torch_version or 'Not installed'}")
|
|
300
170
|
if env.gpu_name:
|
|
301
|
-
print(f" GPU:
|
|
302
|
-
if env.gpu_compute:
|
|
303
|
-
print(f" Compute: {env.gpu_compute}")
|
|
304
|
-
|
|
171
|
+
print(f" GPU: {env.gpu_name}")
|
|
172
|
+
if env.gpu_compute: print(f" Compute: {env.gpu_compute}")
|
|
305
173
|
print()
|
|
306
174
|
return 0
|
|
307
175
|
|
|
308
176
|
|
|
309
177
|
def cmd_doctor(args) -> int:
|
|
310
|
-
"""Handle doctor command."""
|
|
311
178
|
from .install import verify_installation
|
|
312
|
-
from .config
|
|
313
|
-
|
|
314
|
-
print("Running diagnostics...")
|
|
315
|
-
print("=" * 40)
|
|
179
|
+
from .config import load_config, discover_config
|
|
316
180
|
|
|
317
|
-
|
|
181
|
+
print("Diagnostics\n" + "=" * 40)
|
|
318
182
|
print("\n1. Environment")
|
|
319
183
|
cmd_info(argparse.Namespace(json=False))
|
|
320
184
|
|
|
321
|
-
|
|
322
|
-
print("2. Package Verification")
|
|
323
|
-
|
|
185
|
+
print("2. Packages")
|
|
324
186
|
packages = []
|
|
325
187
|
if args.package:
|
|
326
188
|
packages = [args.package]
|
|
327
|
-
elif args.config:
|
|
328
|
-
config = load_config(Path(args.config))
|
|
329
|
-
if config:
|
|
330
|
-
# Get packages from pypi-dependencies
|
|
331
|
-
pypi_deps = config.pixi_passthrough.get("pypi-dependencies", {})
|
|
332
|
-
packages = list(pypi_deps.keys()) + config.cuda_packages
|
|
333
189
|
else:
|
|
334
|
-
|
|
335
|
-
if
|
|
336
|
-
|
|
337
|
-
packages = list(pypi_deps.keys()) + config.cuda_packages
|
|
190
|
+
cfg = load_config(Path(args.config)) if args.config else discover_config(Path.cwd())
|
|
191
|
+
if cfg:
|
|
192
|
+
packages = list(cfg.pixi_passthrough.get("pypi-dependencies", {}).keys()) + cfg.cuda_packages
|
|
338
193
|
|
|
339
194
|
if packages:
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
return 0
|
|
344
|
-
else:
|
|
345
|
-
print("\nSome packages failed verification.")
|
|
346
|
-
return 1
|
|
347
|
-
else:
|
|
348
|
-
print(" No packages to verify (no config found)")
|
|
349
|
-
return 0
|
|
195
|
+
return 0 if verify_installation(packages) else 1
|
|
196
|
+
print(" No packages to verify")
|
|
197
|
+
return 0
|
|
350
198
|
|
|
351
199
|
|
|
352
200
|
def cmd_apt_install(args) -> int:
|
|
353
|
-
|
|
354
|
-
import os
|
|
355
|
-
import shutil
|
|
356
|
-
import subprocess
|
|
357
|
-
import platform
|
|
358
|
-
|
|
201
|
+
import os, shutil, subprocess, platform
|
|
359
202
|
if platform.system() != "Linux":
|
|
360
|
-
print("apt-install
|
|
203
|
+
print("apt-install: Linux only", file=sys.stderr)
|
|
361
204
|
return 1
|
|
362
205
|
|
|
363
|
-
#
|
|
206
|
+
# Check root config first, then regular
|
|
364
207
|
if args.config:
|
|
365
208
|
config_path = Path(args.config).resolve()
|
|
366
209
|
else:
|
|
367
|
-
|
|
210
|
+
root_path = Path.cwd() / ROOT_CONFIG_FILE_NAME
|
|
211
|
+
config_path = root_path if root_path.exists() else Path.cwd() / CONFIG_FILE_NAME
|
|
368
212
|
|
|
369
213
|
if not config_path.exists():
|
|
370
|
-
print(f"
|
|
214
|
+
print(f"Not found: {config_path}", file=sys.stderr)
|
|
371
215
|
return 1
|
|
372
216
|
|
|
373
|
-
# Parse config to get apt packages
|
|
374
217
|
from .config.parser import load_config
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
print("No [apt] packages specified in config")
|
|
218
|
+
packages = load_config(config_path).apt_packages
|
|
219
|
+
if not packages:
|
|
220
|
+
print("No apt packages in config")
|
|
379
221
|
return 0
|
|
380
222
|
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
for pkg in packages:
|
|
384
|
-
print(f" - {pkg}")
|
|
385
|
-
|
|
386
|
-
# Determine if we need sudo
|
|
387
|
-
is_root = os.geteuid() == 0
|
|
388
|
-
has_sudo = shutil.which("sudo") is not None
|
|
389
|
-
use_sudo = not is_root and has_sudo
|
|
390
|
-
|
|
223
|
+
print(f"Packages: {', '.join(packages)}")
|
|
224
|
+
use_sudo = os.geteuid() != 0 and shutil.which("sudo")
|
|
391
225
|
prefix = ["sudo"] if use_sudo else []
|
|
392
226
|
|
|
393
227
|
if args.dry_run:
|
|
394
|
-
print("
|
|
395
|
-
prefix_str = "sudo " if use_sudo else ""
|
|
396
|
-
print(f" {prefix_str}apt-get update && {prefix_str}apt-get install -y {' '.join(packages)}")
|
|
228
|
+
print(f"Would run: {'sudo ' if use_sudo else ''}apt-get install -y {' '.join(packages)}")
|
|
397
229
|
return 0
|
|
398
230
|
|
|
399
|
-
if
|
|
400
|
-
print("
|
|
401
|
-
print("Run manually with:", file=sys.stderr)
|
|
402
|
-
print(f" sudo apt-get update && sudo apt-get install -y {' '.join(packages)}", file=sys.stderr)
|
|
231
|
+
if os.geteuid() != 0 and not shutil.which("sudo"):
|
|
232
|
+
print("Need root. Run: sudo apt-get install -y " + " ".join(packages), file=sys.stderr)
|
|
403
233
|
return 1
|
|
404
234
|
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
result
|
|
408
|
-
prefix + ["apt-get", "update"],
|
|
409
|
-
capture_output=False,
|
|
410
|
-
)
|
|
411
|
-
if result.returncode != 0:
|
|
412
|
-
print("Warning: apt-get update failed, continuing anyway...")
|
|
413
|
-
|
|
414
|
-
# Run apt-get install
|
|
415
|
-
print(f"\nInstalling: {' '.join(packages)}")
|
|
416
|
-
result = subprocess.run(
|
|
417
|
-
prefix + ["apt-get", "install", "-y"] + packages,
|
|
418
|
-
capture_output=False,
|
|
419
|
-
)
|
|
420
|
-
|
|
421
|
-
if result.returncode == 0:
|
|
422
|
-
print("\nSystem packages installed successfully!")
|
|
423
|
-
return 0
|
|
424
|
-
else:
|
|
425
|
-
print("\nFailed to install some packages", file=sys.stderr)
|
|
426
|
-
return result.returncode
|
|
235
|
+
subprocess.run(prefix + ["apt-get", "update"], capture_output=False)
|
|
236
|
+
result = subprocess.run(prefix + ["apt-get", "install", "-y"] + packages, capture_output=False)
|
|
237
|
+
return result.returncode
|
|
427
238
|
|
|
428
239
|
|
|
429
240
|
if __name__ == "__main__":
|
comfy_env/config/__init__.py
CHANGED
|
@@ -1,17 +1,25 @@
|
|
|
1
|
-
"""Config parsing
|
|
1
|
+
"""Config layer - Configuration parsing and types."""
|
|
2
2
|
|
|
3
|
-
from .
|
|
3
|
+
from .types import (
|
|
4
4
|
ComfyEnvConfig,
|
|
5
|
+
NodeDependency,
|
|
5
6
|
NodeReq,
|
|
7
|
+
)
|
|
8
|
+
from .parser import (
|
|
9
|
+
ROOT_CONFIG_FILE_NAME,
|
|
10
|
+
CONFIG_FILE_NAME,
|
|
6
11
|
load_config,
|
|
7
12
|
discover_config,
|
|
8
|
-
|
|
13
|
+
parse_config,
|
|
9
14
|
)
|
|
10
15
|
|
|
11
16
|
__all__ = [
|
|
12
17
|
"ComfyEnvConfig",
|
|
18
|
+
"NodeDependency",
|
|
13
19
|
"NodeReq",
|
|
20
|
+
"ROOT_CONFIG_FILE_NAME",
|
|
21
|
+
"CONFIG_FILE_NAME",
|
|
14
22
|
"load_config",
|
|
15
23
|
"discover_config",
|
|
16
|
-
"
|
|
24
|
+
"parse_config",
|
|
17
25
|
]
|