devservices 1.2.4__tar.gz → 1.3.0__tar.gz
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.
- {devservices-1.2.4 → devservices-1.3.0}/PKG-INFO +1 -7
- {devservices-1.2.4 → devservices-1.3.0}/README.md +9 -1
- {devservices-1.2.4 → devservices-1.3.0}/devservices/__init__.py +1 -0
- {devservices-1.2.4 → devservices-1.3.0}/devservices/commands/down.py +13 -12
- {devservices-1.2.4 → devservices-1.3.0}/devservices/commands/foreground.py +5 -6
- {devservices-1.2.4 → devservices-1.3.0}/devservices/commands/list_dependencies.py +4 -2
- {devservices-1.2.4 → devservices-1.3.0}/devservices/commands/logs.py +63 -20
- {devservices-1.2.4 → devservices-1.3.0}/devservices/commands/reset.py +5 -6
- {devservices-1.2.4 → devservices-1.3.0}/devservices/commands/serve.py +2 -2
- {devservices-1.2.4 → devservices-1.3.0}/devservices/commands/status.py +17 -17
- {devservices-1.2.4 → devservices-1.3.0}/devservices/commands/toggle.py +8 -9
- {devservices-1.2.4 → devservices-1.3.0}/devservices/commands/up.py +11 -9
- {devservices-1.2.4 → devservices-1.3.0}/devservices/configs/service_config.py +6 -3
- {devservices-1.2.4 → devservices-1.3.0}/devservices/main.py +6 -0
- {devservices-1.2.4 → devservices-1.3.0}/devservices/utils/console.py +6 -4
- {devservices-1.2.4 → devservices-1.3.0}/devservices/utils/dependencies.py +10 -12
- {devservices-1.2.4 → devservices-1.3.0}/devservices/utils/docker.py +46 -0
- devservices-1.3.0/devservices/utils/services.py +116 -0
- {devservices-1.2.4 → devservices-1.3.0}/devservices/utils/state.py +16 -0
- {devservices-1.2.4 → devservices-1.3.0}/devservices.egg-info/PKG-INFO +1 -7
- {devservices-1.2.4 → devservices-1.3.0}/devservices.egg-info/SOURCES.txt +0 -1
- {devservices-1.2.4 → devservices-1.3.0}/devservices.egg-info/requires.txt +0 -7
- {devservices-1.2.4 → devservices-1.3.0}/pyproject.toml +22 -3
- devservices-1.3.0/setup.cfg +4 -0
- {devservices-1.2.4 → devservices-1.3.0}/tests/commands/test_down.py +55 -3
- {devservices-1.2.4 → devservices-1.3.0}/tests/commands/test_list_dependencies.py +6 -4
- {devservices-1.2.4 → devservices-1.3.0}/tests/commands/test_logs.py +116 -9
- {devservices-1.2.4 → devservices-1.3.0}/tests/commands/test_status.py +8 -8
- {devservices-1.2.4 → devservices-1.3.0}/tests/commands/test_toggle.py +13 -5
- {devservices-1.2.4 → devservices-1.3.0}/tests/commands/test_up.py +43 -15
- {devservices-1.2.4 → devservices-1.3.0}/tests/configs/test_service_config.py +1 -1
- {devservices-1.2.4 → devservices-1.3.0}/tests/utils/test_dependencies.py +57 -5
- {devservices-1.2.4 → devservices-1.3.0}/tests/utils/test_docker.py +115 -3
- {devservices-1.2.4 → devservices-1.3.0}/tests/utils/test_services.py +27 -1
- devservices-1.2.4/devservices/utils/services.py +0 -75
- devservices-1.2.4/setup.cfg +0 -9
- {devservices-1.2.4 → devservices-1.3.0}/LICENSE.md +0 -0
- {devservices-1.2.4 → devservices-1.3.0}/devservices/commands/__init__.py +0 -0
- {devservices-1.2.4 → devservices-1.3.0}/devservices/commands/list_services.py +1 -1
- {devservices-1.2.4 → devservices-1.3.0}/devservices/commands/purge.py +1 -1
- {devservices-1.2.4 → devservices-1.3.0}/devservices/commands/update.py +1 -1
- {devservices-1.2.4 → devservices-1.3.0}/devservices/constants.py +0 -0
- {devservices-1.2.4 → devservices-1.3.0}/devservices/exceptions.py +0 -0
- {devservices-1.2.4 → devservices-1.3.0}/devservices/utils/__init__.py +0 -0
- {devservices-1.2.4 → devservices-1.3.0}/devservices/utils/check_for_update.py +0 -0
- {devservices-1.2.4 → devservices-1.3.0}/devservices/utils/devenv.py +0 -0
- {devservices-1.2.4 → devservices-1.3.0}/devservices/utils/docker_compose.py +2 -2
- {devservices-1.2.4 → devservices-1.3.0}/devservices/utils/file_lock.py +0 -0
- {devservices-1.2.4 → devservices-1.3.0}/devservices/utils/git.py +0 -0
- {devservices-1.2.4 → devservices-1.3.0}/devservices/utils/install_binary.py +0 -0
- {devservices-1.2.4 → devservices-1.3.0}/devservices/utils/supervisor.py +0 -0
- {devservices-1.2.4 → devservices-1.3.0}/devservices.egg-info/dependency_links.txt +0 -0
- {devservices-1.2.4 → devservices-1.3.0}/devservices.egg-info/entry_points.txt +0 -0
- {devservices-1.2.4 → devservices-1.3.0}/devservices.egg-info/top_level.txt +0 -0
- {devservices-1.2.4 → devservices-1.3.0}/testing/__init__.py +0 -0
- {devservices-1.2.4 → devservices-1.3.0}/testing/utils.py +0 -0
- {devservices-1.2.4 → devservices-1.3.0}/tests/__init__.py +0 -0
- {devservices-1.2.4 → devservices-1.3.0}/tests/commands/test_foreground.py +1 -1
- {devservices-1.2.4 → devservices-1.3.0}/tests/commands/test_list_services.py +0 -0
- {devservices-1.2.4 → devservices-1.3.0}/tests/commands/test_purge.py +0 -0
- {devservices-1.2.4 → devservices-1.3.0}/tests/commands/test_reset.py +0 -0
- {devservices-1.2.4 → devservices-1.3.0}/tests/commands/test_serve.py +1 -1
- {devservices-1.2.4 → devservices-1.3.0}/tests/commands/test_update.py +0 -0
- {devservices-1.2.4 → devservices-1.3.0}/tests/conftest.py +0 -0
- {devservices-1.2.4 → devservices-1.3.0}/tests/utils/test_check_for_update.py +0 -0
- {devservices-1.2.4 → devservices-1.3.0}/tests/utils/test_docker_compose.py +1 -1
- {devservices-1.2.4 → devservices-1.3.0}/tests/utils/test_git.py +0 -0
- {devservices-1.2.4 → devservices-1.3.0}/tests/utils/test_install_binary.py +0 -0
- {devservices-1.2.4 → devservices-1.3.0}/tests/utils/test_state.py +0 -0
- {devservices-1.2.4 → devservices-1.3.0}/tests/utils/test_supervisor.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: devservices
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.3.0
|
|
4
4
|
Requires-Python: >=3.11
|
|
5
5
|
License-File: LICENSE.md
|
|
6
6
|
Requires-Dist: pyyaml
|
|
@@ -8,10 +8,4 @@ Requires-Dist: sentry-devenv
|
|
|
8
8
|
Requires-Dist: sentry-sdk
|
|
9
9
|
Requires-Dist: packaging
|
|
10
10
|
Requires-Dist: supervisor
|
|
11
|
-
Provides-Extra: dev
|
|
12
|
-
Requires-Dist: black; extra == "dev"
|
|
13
|
-
Requires-Dist: mypy; extra == "dev"
|
|
14
|
-
Requires-Dist: pre-commit; extra == "dev"
|
|
15
|
-
Requires-Dist: pytest; extra == "dev"
|
|
16
|
-
Requires-Dist: types-PyYAML; extra == "dev"
|
|
17
11
|
Dynamic: license-file
|
|
@@ -33,7 +33,7 @@ NOTE: service-name is an optional parameter. If not provided, devservices will a
|
|
|
33
33
|
The recommended way to install devservices is through a virtualenv in the requirements.txt. Once that is installed and a devservices config file is added, you should be able to run `devservices up` to begin local development.
|
|
34
34
|
|
|
35
35
|
```
|
|
36
|
-
devservices==1.
|
|
36
|
+
devservices==1.3.0
|
|
37
37
|
```
|
|
38
38
|
|
|
39
39
|
### 2. Add devservices config files
|
|
@@ -167,3 +167,11 @@ networks:
|
|
|
167
167
|
name: devservices
|
|
168
168
|
external: true
|
|
169
169
|
```
|
|
170
|
+
|
|
171
|
+
## Dev
|
|
172
|
+
|
|
173
|
+
```sh
|
|
174
|
+
uv sync
|
|
175
|
+
direnv allow
|
|
176
|
+
pytest
|
|
177
|
+
```
|
|
@@ -3,19 +3,19 @@ from __future__ import annotations
|
|
|
3
3
|
import concurrent.futures
|
|
4
4
|
import os
|
|
5
5
|
import subprocess
|
|
6
|
-
from argparse import _SubParsersAction
|
|
7
6
|
from argparse import ArgumentParser
|
|
8
7
|
from argparse import Namespace
|
|
8
|
+
from argparse import _SubParsersAction
|
|
9
9
|
|
|
10
10
|
from sentry_sdk import capture_exception
|
|
11
11
|
from sentry_sdk import logger as sentry_logger
|
|
12
12
|
|
|
13
13
|
from devservices.constants import CONFIG_FILE_NAME
|
|
14
14
|
from devservices.constants import DEPENDENCY_CONFIG_VERSION
|
|
15
|
-
from devservices.constants import DependencyType
|
|
16
15
|
from devservices.constants import DEVSERVICES_DEPENDENCIES_CACHE_DIR
|
|
17
16
|
from devservices.constants import DEVSERVICES_DEPENDENCIES_CACHE_DIR_KEY
|
|
18
17
|
from devservices.constants import DEVSERVICES_DIR_NAME
|
|
18
|
+
from devservices.constants import DependencyType
|
|
19
19
|
from devservices.exceptions import ConfigError
|
|
20
20
|
from devservices.exceptions import ConfigNotFoundError
|
|
21
21
|
from devservices.exceptions import DependencyError
|
|
@@ -25,16 +25,17 @@ from devservices.exceptions import SupervisorConfigError
|
|
|
25
25
|
from devservices.exceptions import SupervisorError
|
|
26
26
|
from devservices.utils.console import Console
|
|
27
27
|
from devservices.utils.console import Status
|
|
28
|
-
from devservices.utils.dependencies import construct_dependency_graph
|
|
29
28
|
from devservices.utils.dependencies import DependencyNode
|
|
29
|
+
from devservices.utils.dependencies import InstalledRemoteDependency
|
|
30
|
+
from devservices.utils.dependencies import construct_dependency_graph
|
|
30
31
|
from devservices.utils.dependencies import get_non_shared_remote_dependencies
|
|
31
32
|
from devservices.utils.dependencies import install_and_verify_dependencies
|
|
32
|
-
from devservices.utils.dependencies import InstalledRemoteDependency
|
|
33
33
|
from devservices.utils.docker_compose import DockerComposeCommand
|
|
34
34
|
from devservices.utils.docker_compose import get_docker_compose_commands_to_run
|
|
35
35
|
from devservices.utils.docker_compose import run_cmd
|
|
36
|
-
from devservices.utils.services import find_matching_service
|
|
37
36
|
from devservices.utils.services import Service
|
|
37
|
+
from devservices.utils.services import find_matching_service
|
|
38
|
+
from devservices.utils.services import get_active_service_names
|
|
38
39
|
from devservices.utils.state import ServiceRuntime
|
|
39
40
|
from devservices.utils.state import State
|
|
40
41
|
from devservices.utils.state import StateTables
|
|
@@ -71,7 +72,9 @@ def down(args: Namespace) -> None:
|
|
|
71
72
|
console = Console()
|
|
72
73
|
service_name = args.service_name
|
|
73
74
|
try:
|
|
74
|
-
service = find_matching_service(
|
|
75
|
+
service = find_matching_service(
|
|
76
|
+
service_name, config_path=getattr(args, "config", None)
|
|
77
|
+
)
|
|
75
78
|
except ConfigNotFoundError as e:
|
|
76
79
|
capture_exception(e, level="info")
|
|
77
80
|
console.failure(
|
|
@@ -90,9 +93,7 @@ def down(args: Namespace) -> None:
|
|
|
90
93
|
exclude_local = getattr(args, "exclude_local", False)
|
|
91
94
|
|
|
92
95
|
state = State()
|
|
93
|
-
|
|
94
|
-
started_services = set(state.get_service_entries(StateTables.STARTED_SERVICES))
|
|
95
|
-
active_services = starting_services.union(started_services)
|
|
96
|
+
active_services = get_active_service_names(clean_stale_entries=True)
|
|
96
97
|
if service.name not in active_services:
|
|
97
98
|
console.warning(f"{service.name} is not running")
|
|
98
99
|
return # Since exit(0) is captured as an internal_error by sentry
|
|
@@ -232,9 +233,9 @@ def bring_down_service(
|
|
|
232
233
|
|
|
233
234
|
# Set the environment variable for the local dependencies directory to be used by docker compose
|
|
234
235
|
current_env = os.environ.copy()
|
|
235
|
-
current_env[
|
|
236
|
-
|
|
237
|
-
|
|
236
|
+
current_env[DEVSERVICES_DEPENDENCIES_CACHE_DIR_KEY] = (
|
|
237
|
+
relative_local_dependency_directory
|
|
238
|
+
)
|
|
238
239
|
state = State()
|
|
239
240
|
|
|
240
241
|
# We want to ignore any dependencies that are set to run locally if we are excluding local dependencies
|
|
@@ -3,15 +3,15 @@ from __future__ import annotations
|
|
|
3
3
|
import os
|
|
4
4
|
import pty
|
|
5
5
|
import shlex
|
|
6
|
-
from argparse import _SubParsersAction
|
|
7
6
|
from argparse import ArgumentParser
|
|
8
7
|
from argparse import Namespace
|
|
8
|
+
from argparse import _SubParsersAction
|
|
9
9
|
|
|
10
10
|
from sentry_sdk import capture_exception
|
|
11
11
|
|
|
12
12
|
from devservices.constants import CONFIG_FILE_NAME
|
|
13
|
-
from devservices.constants import DependencyType
|
|
14
13
|
from devservices.constants import DEVSERVICES_DIR_NAME
|
|
14
|
+
from devservices.constants import DependencyType
|
|
15
15
|
from devservices.exceptions import ConfigError
|
|
16
16
|
from devservices.exceptions import ConfigNotFoundError
|
|
17
17
|
from devservices.exceptions import ServiceNotFoundError
|
|
@@ -19,6 +19,7 @@ from devservices.exceptions import SupervisorConfigError
|
|
|
19
19
|
from devservices.exceptions import SupervisorProcessError
|
|
20
20
|
from devservices.utils.console import Console
|
|
21
21
|
from devservices.utils.services import find_matching_service
|
|
22
|
+
from devservices.utils.services import get_active_service_names
|
|
22
23
|
from devservices.utils.state import State
|
|
23
24
|
from devservices.utils.state import StateTables
|
|
24
25
|
from devservices.utils.supervisor import SupervisorManager
|
|
@@ -39,7 +40,7 @@ def foreground(args: Namespace) -> None:
|
|
|
39
40
|
console = Console()
|
|
40
41
|
program_name = args.program_name
|
|
41
42
|
try:
|
|
42
|
-
service = find_matching_service()
|
|
43
|
+
service = find_matching_service(config_path=getattr(args, "config", None))
|
|
43
44
|
except ConfigNotFoundError as e:
|
|
44
45
|
capture_exception(e, level="info")
|
|
45
46
|
console.failure(
|
|
@@ -60,9 +61,7 @@ def foreground(args: Namespace) -> None:
|
|
|
60
61
|
)
|
|
61
62
|
return
|
|
62
63
|
state = State()
|
|
63
|
-
|
|
64
|
-
started_services = set(state.get_service_entries(StateTables.STARTED_SERVICES))
|
|
65
|
-
active_services = starting_services.union(started_services)
|
|
64
|
+
active_services = get_active_service_names()
|
|
66
65
|
if service.name not in active_services:
|
|
67
66
|
console.warning(f"{service.name} is not running")
|
|
68
67
|
return
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from argparse import _SubParsersAction
|
|
4
3
|
from argparse import ArgumentParser
|
|
5
4
|
from argparse import Namespace
|
|
5
|
+
from argparse import _SubParsersAction
|
|
6
6
|
|
|
7
7
|
from sentry_sdk import capture_exception
|
|
8
8
|
|
|
@@ -32,7 +32,9 @@ def list_dependencies(args: Namespace) -> None:
|
|
|
32
32
|
service_name = args.service_name
|
|
33
33
|
|
|
34
34
|
try:
|
|
35
|
-
service = find_matching_service(
|
|
35
|
+
service = find_matching_service(
|
|
36
|
+
service_name, config_path=getattr(args, "config", None)
|
|
37
|
+
)
|
|
36
38
|
except ConfigNotFoundError as e:
|
|
37
39
|
capture_exception(e, level="info")
|
|
38
40
|
console.failure(
|
|
@@ -3,19 +3,19 @@ from __future__ import annotations
|
|
|
3
3
|
import concurrent.futures
|
|
4
4
|
import os
|
|
5
5
|
import subprocess
|
|
6
|
-
from argparse import _SubParsersAction
|
|
7
6
|
from argparse import ArgumentParser
|
|
8
7
|
from argparse import Namespace
|
|
8
|
+
from argparse import _SubParsersAction
|
|
9
9
|
|
|
10
10
|
from sentry_sdk import capture_exception
|
|
11
11
|
|
|
12
12
|
from devservices.constants import CONFIG_FILE_NAME
|
|
13
13
|
from devservices.constants import DEPENDENCY_CONFIG_VERSION
|
|
14
|
-
from devservices.constants import DependencyType
|
|
15
14
|
from devservices.constants import DEVSERVICES_DEPENDENCIES_CACHE_DIR
|
|
16
15
|
from devservices.constants import DEVSERVICES_DEPENDENCIES_CACHE_DIR_KEY
|
|
17
16
|
from devservices.constants import DEVSERVICES_DIR_NAME
|
|
18
17
|
from devservices.constants import MAX_LOG_LINES
|
|
18
|
+
from devservices.constants import DependencyType
|
|
19
19
|
from devservices.exceptions import ConfigError
|
|
20
20
|
from devservices.exceptions import ConfigNotFoundError
|
|
21
21
|
from devservices.exceptions import DependencyError
|
|
@@ -24,12 +24,16 @@ from devservices.exceptions import ServiceNotFoundError
|
|
|
24
24
|
from devservices.exceptions import SupervisorConfigError
|
|
25
25
|
from devservices.exceptions import SupervisorError
|
|
26
26
|
from devservices.utils.console import Console
|
|
27
|
-
from devservices.utils.dependencies import install_and_verify_dependencies
|
|
28
27
|
from devservices.utils.dependencies import InstalledRemoteDependency
|
|
28
|
+
from devservices.utils.dependencies import install_and_verify_dependencies
|
|
29
|
+
from devservices.utils.docker import get_container_health
|
|
30
|
+
from devservices.utils.docker_compose import DockerComposeCommand
|
|
31
|
+
from devservices.utils.docker_compose import get_container_names_for_project
|
|
29
32
|
from devservices.utils.docker_compose import get_docker_compose_commands_to_run
|
|
30
33
|
from devservices.utils.docker_compose import run_cmd
|
|
31
|
-
from devservices.utils.services import find_matching_service
|
|
32
34
|
from devservices.utils.services import Service
|
|
35
|
+
from devservices.utils.services import find_matching_service
|
|
36
|
+
from devservices.utils.services import get_active_service_names
|
|
33
37
|
from devservices.utils.state import State
|
|
34
38
|
from devservices.utils.state import StateTables
|
|
35
39
|
from devservices.utils.supervisor import SupervisorManager
|
|
@@ -51,7 +55,9 @@ def logs(args: Namespace) -> None:
|
|
|
51
55
|
console = Console()
|
|
52
56
|
service_name = args.service_name
|
|
53
57
|
try:
|
|
54
|
-
service = find_matching_service(
|
|
58
|
+
service = find_matching_service(
|
|
59
|
+
service_name, config_path=getattr(args, "config", None)
|
|
60
|
+
)
|
|
55
61
|
except ConfigNotFoundError as e:
|
|
56
62
|
capture_exception(e, level="info")
|
|
57
63
|
console.failure(
|
|
@@ -84,9 +90,7 @@ def logs(args: Namespace) -> None:
|
|
|
84
90
|
if not mode_dependencies and "default" in modes:
|
|
85
91
|
mode_dependencies.update(modes["default"])
|
|
86
92
|
|
|
87
|
-
|
|
88
|
-
started_services = set(state.get_service_entries(StateTables.STARTED_SERVICES))
|
|
89
|
-
running_services = starting_services.union(started_services)
|
|
93
|
+
running_services = get_active_service_names()
|
|
90
94
|
if service.name not in running_services:
|
|
91
95
|
console.warning(f"Service {service.name} is not running")
|
|
92
96
|
return
|
|
@@ -102,7 +106,9 @@ def logs(args: Namespace) -> None:
|
|
|
102
106
|
)
|
|
103
107
|
exit(1)
|
|
104
108
|
try:
|
|
105
|
-
logs_output = _logs(
|
|
109
|
+
logs_output, docker_compose_commands = _logs(
|
|
110
|
+
service, list(remote_dependencies), list(mode_dependencies)
|
|
111
|
+
)
|
|
106
112
|
except DockerComposeError as dce:
|
|
107
113
|
capture_exception(dce, level="info")
|
|
108
114
|
console.failure(f"Failed to get logs for {service.name}: {dce.stderr}")
|
|
@@ -128,12 +134,14 @@ def logs(args: Namespace) -> None:
|
|
|
128
134
|
console.info(f"=== Logs for supervisor program: {program_name} ===")
|
|
129
135
|
console.info(log_content)
|
|
130
136
|
|
|
137
|
+
_print_health_logs(console, docker_compose_commands)
|
|
138
|
+
|
|
131
139
|
|
|
132
140
|
def _logs(
|
|
133
141
|
service: Service,
|
|
134
|
-
remote_dependencies:
|
|
142
|
+
remote_dependencies: list[InstalledRemoteDependency],
|
|
135
143
|
mode_dependencies: list[str],
|
|
136
|
-
) -> list[subprocess.CompletedProcess[str]]:
|
|
144
|
+
) -> tuple[list[subprocess.CompletedProcess[str]], list[DockerComposeCommand]]:
|
|
137
145
|
relative_local_dependency_directory = os.path.relpath(
|
|
138
146
|
os.path.join(DEVSERVICES_DEPENDENCIES_CACHE_DIR, DEPENDENCY_CONFIG_VERSION),
|
|
139
147
|
service.repo_path,
|
|
@@ -141,23 +149,20 @@ def _logs(
|
|
|
141
149
|
service_config_file_path = os.path.join(
|
|
142
150
|
service.repo_path, DEVSERVICES_DIR_NAME, CONFIG_FILE_NAME
|
|
143
151
|
)
|
|
144
|
-
# Set the environment variable for the local dependencies directory to be used by docker compose
|
|
145
152
|
current_env = os.environ.copy()
|
|
146
|
-
current_env[
|
|
147
|
-
|
|
148
|
-
|
|
153
|
+
current_env[DEVSERVICES_DEPENDENCIES_CACHE_DIR_KEY] = (
|
|
154
|
+
relative_local_dependency_directory
|
|
155
|
+
)
|
|
149
156
|
docker_compose_commands = get_docker_compose_commands_to_run(
|
|
150
157
|
service=service,
|
|
151
|
-
remote_dependencies=
|
|
158
|
+
remote_dependencies=remote_dependencies,
|
|
152
159
|
current_env=current_env,
|
|
153
160
|
command="logs",
|
|
154
|
-
options=["-n", MAX_LOG_LINES],
|
|
161
|
+
options=["--timestamps", "-n", MAX_LOG_LINES],
|
|
155
162
|
service_config_file_path=service_config_file_path,
|
|
156
163
|
mode_dependencies=mode_dependencies,
|
|
157
164
|
)
|
|
158
|
-
|
|
159
165
|
cmd_outputs = []
|
|
160
|
-
|
|
161
166
|
with concurrent.futures.ThreadPoolExecutor() as executor:
|
|
162
167
|
futures = [
|
|
163
168
|
executor.submit(run_cmd, cmd.full_command, current_env)
|
|
@@ -165,8 +170,46 @@ def _logs(
|
|
|
165
170
|
]
|
|
166
171
|
for future in concurrent.futures.as_completed(futures):
|
|
167
172
|
cmd_outputs.append(future.result())
|
|
173
|
+
return cmd_outputs, docker_compose_commands
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
def _print_health_logs(
|
|
177
|
+
console: Console, docker_compose_commands: list[DockerComposeCommand]
|
|
178
|
+
) -> None:
|
|
179
|
+
container_names: list[str] = []
|
|
180
|
+
for cmd in docker_compose_commands:
|
|
181
|
+
try:
|
|
182
|
+
container_names += [
|
|
183
|
+
c.name
|
|
184
|
+
for c in get_container_names_for_project(
|
|
185
|
+
cmd.project_name, cmd.config_path, cmd.services
|
|
186
|
+
)
|
|
187
|
+
]
|
|
188
|
+
except Exception:
|
|
189
|
+
continue
|
|
190
|
+
|
|
191
|
+
if not container_names:
|
|
192
|
+
return
|
|
193
|
+
|
|
194
|
+
health_results = get_container_health(container_names)
|
|
195
|
+
if not health_results:
|
|
196
|
+
return
|
|
168
197
|
|
|
169
|
-
|
|
198
|
+
console.info("=== Container health ===")
|
|
199
|
+
for h in health_results:
|
|
200
|
+
if h.status == "healthy":
|
|
201
|
+
console.success(f" {h.name}: {h.status}")
|
|
202
|
+
elif h.status in ("unhealthy", "starting"):
|
|
203
|
+
console.warning(f" {h.name}: {h.status}")
|
|
204
|
+
else:
|
|
205
|
+
console.info(f" {h.name}: no healthcheck")
|
|
206
|
+
|
|
207
|
+
for h in health_results:
|
|
208
|
+
if not h.log or h.status == "healthy":
|
|
209
|
+
continue
|
|
210
|
+
console.info(f"\n--- {h.name} health check log ---")
|
|
211
|
+
for entry in h.log:
|
|
212
|
+
console.info(f" exit={entry.exit_code} {entry.output}")
|
|
170
213
|
|
|
171
214
|
|
|
172
215
|
def _supervisor_logs(
|
|
@@ -1,25 +1,26 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from argparse import _SubParsersAction
|
|
4
3
|
from argparse import ArgumentParser
|
|
5
4
|
from argparse import Namespace
|
|
5
|
+
from argparse import _SubParsersAction
|
|
6
6
|
|
|
7
7
|
from sentry_sdk import capture_exception
|
|
8
8
|
|
|
9
9
|
from devservices.commands.down import down
|
|
10
|
-
from devservices.constants import DependencyType
|
|
11
10
|
from devservices.constants import DEVSERVICES_ORCHESTRATOR_LABEL
|
|
11
|
+
from devservices.constants import DependencyType
|
|
12
12
|
from devservices.exceptions import DockerDaemonNotRunningError
|
|
13
13
|
from devservices.exceptions import DockerError
|
|
14
14
|
from devservices.utils.console import Console
|
|
15
15
|
from devservices.utils.console import Status
|
|
16
|
-
from devservices.utils.dependencies import construct_dependency_graph
|
|
17
16
|
from devservices.utils.dependencies import DependencyNode
|
|
17
|
+
from devservices.utils.dependencies import construct_dependency_graph
|
|
18
18
|
from devservices.utils.docker import get_matching_containers
|
|
19
19
|
from devservices.utils.docker import get_volumes_for_containers
|
|
20
20
|
from devservices.utils.docker import remove_docker_resources
|
|
21
21
|
from devservices.utils.docker import stop_containers
|
|
22
22
|
from devservices.utils.services import find_matching_service
|
|
23
|
+
from devservices.utils.services import get_active_service_names
|
|
23
24
|
from devservices.utils.state import State
|
|
24
25
|
from devservices.utils.state import StateTables
|
|
25
26
|
|
|
@@ -69,9 +70,7 @@ def reset(args: Namespace) -> None:
|
|
|
69
70
|
exit(1)
|
|
70
71
|
|
|
71
72
|
state = State()
|
|
72
|
-
|
|
73
|
-
starting_services = set(state.get_service_entries(StateTables.STARTING_SERVICES))
|
|
74
|
-
active_service_names = starting_services.union(started_services)
|
|
73
|
+
active_service_names = get_active_service_names(clean_stale_entries=True)
|
|
75
74
|
|
|
76
75
|
# TODO: We should add threading here to speed up the process
|
|
77
76
|
for active_service_name in active_service_names:
|
|
@@ -3,9 +3,9 @@ from __future__ import annotations
|
|
|
3
3
|
import os
|
|
4
4
|
import pty
|
|
5
5
|
import shlex
|
|
6
|
-
from argparse import _SubParsersAction
|
|
7
6
|
from argparse import ArgumentParser
|
|
8
7
|
from argparse import Namespace
|
|
8
|
+
from argparse import _SubParsersAction
|
|
9
9
|
|
|
10
10
|
from sentry_sdk import capture_exception
|
|
11
11
|
|
|
@@ -35,7 +35,7 @@ def serve(args: Namespace) -> None:
|
|
|
35
35
|
console = Console()
|
|
36
36
|
|
|
37
37
|
try:
|
|
38
|
-
service = find_matching_service()
|
|
38
|
+
service = find_matching_service(config_path=getattr(args, "config", None))
|
|
39
39
|
except ConfigNotFoundError as e:
|
|
40
40
|
console.failure(
|
|
41
41
|
f"{str(e)}. Please run the command from a directory with a valid devservices configuration."
|
|
@@ -4,22 +4,22 @@ import concurrent.futures
|
|
|
4
4
|
import json
|
|
5
5
|
import os
|
|
6
6
|
import subprocess
|
|
7
|
-
from argparse import _SubParsersAction
|
|
8
7
|
from argparse import ArgumentParser
|
|
9
8
|
from argparse import Namespace
|
|
9
|
+
from argparse import _SubParsersAction
|
|
10
10
|
from collections import namedtuple
|
|
11
11
|
from datetime import timedelta
|
|
12
12
|
from typing import TypedDict
|
|
13
13
|
|
|
14
14
|
from sentry_sdk import capture_exception
|
|
15
15
|
|
|
16
|
-
from devservices.constants import Color
|
|
17
16
|
from devservices.constants import CONFIG_FILE_NAME
|
|
18
17
|
from devservices.constants import DEPENDENCY_CONFIG_VERSION
|
|
19
|
-
from devservices.constants import DependencyType
|
|
20
18
|
from devservices.constants import DEVSERVICES_DEPENDENCIES_CACHE_DIR
|
|
21
19
|
from devservices.constants import DEVSERVICES_DEPENDENCIES_CACHE_DIR_KEY
|
|
22
20
|
from devservices.constants import DEVSERVICES_DIR_NAME
|
|
21
|
+
from devservices.constants import Color
|
|
22
|
+
from devservices.constants import DependencyType
|
|
23
23
|
from devservices.exceptions import ConfigError
|
|
24
24
|
from devservices.exceptions import ConfigNotFoundError
|
|
25
25
|
from devservices.exceptions import DependencyError
|
|
@@ -27,15 +27,16 @@ from devservices.exceptions import DockerComposeError
|
|
|
27
27
|
from devservices.exceptions import ServiceNotFoundError
|
|
28
28
|
from devservices.exceptions import SupervisorConfigError
|
|
29
29
|
from devservices.utils.console import Console
|
|
30
|
-
from devservices.utils.dependencies import construct_dependency_graph
|
|
31
30
|
from devservices.utils.dependencies import DependencyGraph
|
|
32
31
|
from devservices.utils.dependencies import DependencyNode
|
|
33
|
-
from devservices.utils.dependencies import install_and_verify_dependencies
|
|
34
32
|
from devservices.utils.dependencies import InstalledRemoteDependency
|
|
33
|
+
from devservices.utils.dependencies import construct_dependency_graph
|
|
34
|
+
from devservices.utils.dependencies import install_and_verify_dependencies
|
|
35
35
|
from devservices.utils.docker_compose import get_docker_compose_commands_to_run
|
|
36
36
|
from devservices.utils.docker_compose import run_cmd
|
|
37
|
-
from devservices.utils.services import find_matching_service
|
|
38
37
|
from devservices.utils.services import Service
|
|
38
|
+
from devservices.utils.services import find_matching_service
|
|
39
|
+
from devservices.utils.services import get_active_service_names
|
|
39
40
|
from devservices.utils.state import ServiceRuntime
|
|
40
41
|
from devservices.utils.state import State
|
|
41
42
|
from devservices.utils.state import StateTables
|
|
@@ -80,7 +81,9 @@ def status(args: Namespace) -> None:
|
|
|
80
81
|
console = Console()
|
|
81
82
|
service_name = args.service_name
|
|
82
83
|
try:
|
|
83
|
-
service = find_matching_service(
|
|
84
|
+
service = find_matching_service(
|
|
85
|
+
service_name, config_path=getattr(args, "config", None)
|
|
86
|
+
)
|
|
84
87
|
except ConfigNotFoundError as e:
|
|
85
88
|
capture_exception(e)
|
|
86
89
|
console.failure(
|
|
@@ -95,10 +98,7 @@ def status(args: Namespace) -> None:
|
|
|
95
98
|
console.failure(str(e))
|
|
96
99
|
exit(1)
|
|
97
100
|
|
|
98
|
-
|
|
99
|
-
starting_services = set(state.get_service_entries(StateTables.STARTING_SERVICES))
|
|
100
|
-
started_services = set(state.get_service_entries(StateTables.STARTED_SERVICES))
|
|
101
|
-
active_services = starting_services.union(started_services)
|
|
101
|
+
active_services = get_active_service_names()
|
|
102
102
|
if service.name not in active_services:
|
|
103
103
|
console.warning(f"Status unavailable. {service.name} is not running standalone")
|
|
104
104
|
return # Since exit(0) is captured as an internal_error by sentry
|
|
@@ -182,9 +182,9 @@ def get_status_json_results(
|
|
|
182
182
|
)
|
|
183
183
|
# Set the environment variable for the local dependencies directory to be used by docker compose
|
|
184
184
|
current_env = os.environ.copy()
|
|
185
|
-
current_env[
|
|
186
|
-
|
|
187
|
-
|
|
185
|
+
current_env[DEVSERVICES_DEPENDENCIES_CACHE_DIR_KEY] = (
|
|
186
|
+
relative_local_dependency_directory
|
|
187
|
+
)
|
|
188
188
|
docker_compose_commands = get_docker_compose_commands_to_run(
|
|
189
189
|
service=service,
|
|
190
190
|
remote_dependencies=list(remote_dependencies),
|
|
@@ -318,9 +318,9 @@ def parse_docker_compose_status(
|
|
|
318
318
|
docker_compose_service_status
|
|
319
319
|
)
|
|
320
320
|
compose_service = docker_compose_service_status_json["Service"]
|
|
321
|
-
docker_compose_service_to_status[
|
|
322
|
-
|
|
323
|
-
|
|
321
|
+
docker_compose_service_to_status[compose_service] = (
|
|
322
|
+
docker_compose_service_status_json
|
|
323
|
+
)
|
|
324
324
|
|
|
325
325
|
return docker_compose_service_to_status
|
|
326
326
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from argparse import _SubParsersAction
|
|
4
3
|
from argparse import ArgumentParser
|
|
5
4
|
from argparse import Namespace
|
|
5
|
+
from argparse import _SubParsersAction
|
|
6
6
|
|
|
7
7
|
from sentry_sdk import capture_exception
|
|
8
8
|
|
|
@@ -19,8 +19,9 @@ from devservices.utils.console import Status
|
|
|
19
19
|
from devservices.utils.dependencies import construct_dependency_graph
|
|
20
20
|
from devservices.utils.dependencies import get_non_shared_remote_dependencies
|
|
21
21
|
from devservices.utils.dependencies import install_and_verify_dependencies
|
|
22
|
-
from devservices.utils.services import find_matching_service
|
|
23
22
|
from devservices.utils.services import Service
|
|
23
|
+
from devservices.utils.services import find_matching_service
|
|
24
|
+
from devservices.utils.services import get_active_service_names
|
|
24
25
|
from devservices.utils.state import ServiceRuntime
|
|
25
26
|
from devservices.utils.state import State
|
|
26
27
|
from devservices.utils.state import StateTables
|
|
@@ -52,7 +53,9 @@ def toggle(args: Namespace) -> None:
|
|
|
52
53
|
console = Console()
|
|
53
54
|
service_name = args.service_name
|
|
54
55
|
try:
|
|
55
|
-
service = find_matching_service(
|
|
56
|
+
service = find_matching_service(
|
|
57
|
+
service_name, config_path=getattr(args, "config", None)
|
|
58
|
+
)
|
|
56
59
|
except ConfigNotFoundError as e:
|
|
57
60
|
capture_exception(e, level="info")
|
|
58
61
|
console.failure(
|
|
@@ -97,9 +100,7 @@ def handle_transition_to_local_runtime(service_to_transition: Service) -> None:
|
|
|
97
100
|
console = Console()
|
|
98
101
|
state = State()
|
|
99
102
|
|
|
100
|
-
|
|
101
|
-
started_services = set(state.get_service_entries(StateTables.STARTED_SERVICES))
|
|
102
|
-
active_services = starting_services.union(started_services)
|
|
103
|
+
active_services = get_active_service_names(clean_stale_entries=True)
|
|
103
104
|
|
|
104
105
|
# If the service is already running standalone, we can just update the runtime
|
|
105
106
|
if service_to_transition.name in active_services:
|
|
@@ -158,9 +159,7 @@ def handle_transition_to_containerized_runtime(service: Service) -> None:
|
|
|
158
159
|
"""Handle the transition to a containerized runtime for a service."""
|
|
159
160
|
console = Console()
|
|
160
161
|
state = State()
|
|
161
|
-
|
|
162
|
-
started_services = set(state.get_service_entries(StateTables.STARTED_SERVICES))
|
|
163
|
-
active_services = starting_services.union(started_services)
|
|
162
|
+
active_services = get_active_service_names(clean_stale_entries=True)
|
|
164
163
|
if service.name in active_services:
|
|
165
164
|
console.warning(f"{service.name} is running, please stop it first")
|
|
166
165
|
return
|
|
@@ -3,9 +3,9 @@ from __future__ import annotations
|
|
|
3
3
|
import concurrent.futures
|
|
4
4
|
import os
|
|
5
5
|
import subprocess
|
|
6
|
-
from argparse import _SubParsersAction
|
|
7
6
|
from argparse import ArgumentParser
|
|
8
7
|
from argparse import Namespace
|
|
8
|
+
from argparse import _SubParsersAction
|
|
9
9
|
|
|
10
10
|
from sentry_sdk import capture_exception
|
|
11
11
|
from sentry_sdk import logger as sentry_logger
|
|
@@ -14,10 +14,10 @@ from sentry_sdk import start_span
|
|
|
14
14
|
|
|
15
15
|
from devservices.constants import CONFIG_FILE_NAME
|
|
16
16
|
from devservices.constants import DEPENDENCY_CONFIG_VERSION
|
|
17
|
-
from devservices.constants import DependencyType
|
|
18
17
|
from devservices.constants import DEVSERVICES_DEPENDENCIES_CACHE_DIR
|
|
19
18
|
from devservices.constants import DEVSERVICES_DEPENDENCIES_CACHE_DIR_KEY
|
|
20
19
|
from devservices.constants import DEVSERVICES_DIR_NAME
|
|
20
|
+
from devservices.constants import DependencyType
|
|
21
21
|
from devservices.exceptions import ConfigError
|
|
22
22
|
from devservices.exceptions import ConfigNotFoundError
|
|
23
23
|
from devservices.exceptions import ContainerHealthcheckFailedError
|
|
@@ -29,17 +29,17 @@ from devservices.exceptions import SupervisorConfigError
|
|
|
29
29
|
from devservices.exceptions import SupervisorError
|
|
30
30
|
from devservices.utils.console import Console
|
|
31
31
|
from devservices.utils.console import Status
|
|
32
|
-
from devservices.utils.dependencies import construct_dependency_graph
|
|
33
32
|
from devservices.utils.dependencies import DependencyNode
|
|
34
|
-
from devservices.utils.dependencies import install_and_verify_dependencies
|
|
35
33
|
from devservices.utils.dependencies import InstalledRemoteDependency
|
|
34
|
+
from devservices.utils.dependencies import construct_dependency_graph
|
|
35
|
+
from devservices.utils.dependencies import install_and_verify_dependencies
|
|
36
36
|
from devservices.utils.docker import check_all_containers_healthy
|
|
37
37
|
from devservices.utils.docker_compose import DockerComposeCommand
|
|
38
38
|
from devservices.utils.docker_compose import get_container_names_for_project
|
|
39
39
|
from devservices.utils.docker_compose import get_docker_compose_commands_to_run
|
|
40
40
|
from devservices.utils.docker_compose import run_cmd
|
|
41
|
-
from devservices.utils.services import find_matching_service
|
|
42
41
|
from devservices.utils.services import Service
|
|
42
|
+
from devservices.utils.services import find_matching_service
|
|
43
43
|
from devservices.utils.state import ServiceRuntime
|
|
44
44
|
from devservices.utils.state import State
|
|
45
45
|
from devservices.utils.state import StateTables
|
|
@@ -76,7 +76,9 @@ def up(args: Namespace, existing_status: Status | None = None) -> None:
|
|
|
76
76
|
console = Console()
|
|
77
77
|
service_name = args.service_name
|
|
78
78
|
try:
|
|
79
|
-
service = find_matching_service(
|
|
79
|
+
service = find_matching_service(
|
|
80
|
+
service_name, config_path=getattr(args, "config", None)
|
|
81
|
+
)
|
|
80
82
|
except ConfigNotFoundError as e:
|
|
81
83
|
capture_exception(e, level="info")
|
|
82
84
|
console.failure(
|
|
@@ -318,9 +320,9 @@ def bring_up_docker_compose_services(
|
|
|
318
320
|
)
|
|
319
321
|
# Set the environment variable for the local dependencies directory to be used by docker compose
|
|
320
322
|
current_env = os.environ.copy()
|
|
321
|
-
current_env[
|
|
322
|
-
|
|
323
|
-
|
|
323
|
+
current_env[DEVSERVICES_DEPENDENCIES_CACHE_DIR_KEY] = (
|
|
324
|
+
relative_local_dependency_directory
|
|
325
|
+
)
|
|
324
326
|
dependency_graph = construct_dependency_graph(service, modes=modes)
|
|
325
327
|
starting_order = dependency_graph.get_starting_order()
|
|
326
328
|
sorted_remote_dependencies = sorted(
|
|
@@ -8,8 +8,8 @@ import yaml
|
|
|
8
8
|
from supervisor.options import ServerOptions
|
|
9
9
|
|
|
10
10
|
from devservices.constants import CONFIG_FILE_NAME
|
|
11
|
-
from devservices.constants import DependencyType
|
|
12
11
|
from devservices.constants import DEVSERVICES_DIR_NAME
|
|
12
|
+
from devservices.constants import DependencyType
|
|
13
13
|
from devservices.exceptions import ConfigNotFoundError
|
|
14
14
|
from devservices.exceptions import ConfigParseError
|
|
15
15
|
from devservices.exceptions import ConfigValidationError
|
|
@@ -69,8 +69,11 @@ class ServiceConfig:
|
|
|
69
69
|
)
|
|
70
70
|
|
|
71
71
|
|
|
72
|
-
def load_service_config_from_file(
|
|
73
|
-
config_path
|
|
72
|
+
def load_service_config_from_file(
|
|
73
|
+
repo_path: str, config_path: str | None = None
|
|
74
|
+
) -> ServiceConfig:
|
|
75
|
+
if config_path is None:
|
|
76
|
+
config_path = os.path.join(repo_path, DEVSERVICES_DIR_NAME, CONFIG_FILE_NAME)
|
|
74
77
|
if not os.path.exists(config_path):
|
|
75
78
|
raise ConfigNotFoundError(
|
|
76
79
|
f"No devservices configuration found in {config_path}"
|
|
@@ -142,6 +142,12 @@ def main() -> None:
|
|
|
142
142
|
usage="devservices [-h] [--version] COMMAND ...",
|
|
143
143
|
)
|
|
144
144
|
parser.add_argument("--version", action="version", version=current_version)
|
|
145
|
+
parser.add_argument(
|
|
146
|
+
"-c",
|
|
147
|
+
"--config",
|
|
148
|
+
help="Path to a custom devservices config file",
|
|
149
|
+
default=None,
|
|
150
|
+
)
|
|
145
151
|
|
|
146
152
|
subparsers = parser.add_subparsers(dest="command", title="commands", metavar="")
|
|
147
153
|
|