thestage 0.6.1__py3-none-any.whl → 0.6.3__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.
- thestage/.env +4 -5
- thestage/__init__.py +3 -3
- thestage/__main__.py +9 -9
- thestage/cli_command.py +56 -56
- thestage/cli_command_helper.py +51 -51
- thestage/color_scheme/color_scheme.py +7 -7
- thestage/config/__init__.py +18 -18
- thestage/config/config_storage.py +5 -5
- thestage/config/env_base.py +7 -7
- thestage/controllers/__init__.py +0 -0
- thestage/controllers/base_controller.py +67 -67
- thestage/controllers/config_controller.py +137 -137
- thestage/controllers/container_controller.py +389 -389
- thestage/controllers/instance_controller.py +183 -183
- thestage/controllers/project_controller.py +810 -802
- thestage/controllers/utils_controller.py +32 -32
- thestage/debug_main.dist.py +28 -28
- thestage/entities/__init__.py +0 -0
- thestage/entities/container.py +17 -17
- thestage/entities/enums/__init__.py +0 -0
- thestage/entities/enums/order_direction_type.py +6 -6
- thestage/entities/enums/shell_type.py +7 -7
- thestage/entities/enums/tail_output_type.py +6 -6
- thestage/entities/enums/yes_no_response.py +7 -7
- thestage/entities/file_item.py +27 -27
- thestage/entities/project_inference_simulator.py +18 -18
- thestage/entities/project_inference_simulator_model.py +16 -16
- thestage/entities/project_task.py +19 -19
- thestage/entities/rented_instance.py +19 -19
- thestage/entities/self_hosted_instance.py +18 -18
- thestage/exceptions/__init__.py +0 -0
- thestage/exceptions/auth_exception.py +6 -6
- thestage/exceptions/base_exception.py +13 -13
- thestage/exceptions/business_logic_exception.py +6 -6
- thestage/exceptions/config_exception.py +6 -6
- thestage/exceptions/file_system_exception.py +6 -6
- thestage/exceptions/git_access_exception.py +17 -17
- thestage/exceptions/remote_server_exception.py +24 -24
- thestage/git/ProgressPrinter.py +22 -22
- thestage/helpers/__init__.py +0 -0
- thestage/helpers/error_handler.py +115 -115
- thestage/helpers/exception_hook.py +14 -14
- thestage/helpers/logger/__init__.py +0 -0
- thestage/helpers/logger/app_logger.py +50 -50
- thestage/helpers/ssh_util.py +38 -38
- thestage/i18n/en_GB/messages.po +947 -947
- thestage/i18n/translation.py +9 -9
- thestage/main.py +36 -36
- thestage/services/.env +6 -6
- thestage/services/__init__.py +0 -0
- thestage/services/abstract_mapper.py +9 -9
- thestage/services/abstract_service.py +87 -87
- thestage/services/app_config_service.py +52 -52
- thestage/services/clients/__init__.py +0 -0
- thestage/services/clients/git/__init__.py +0 -0
- thestage/services/clients/git/git_client.py +436 -433
- thestage/services/clients/thestage_api/__init__.py +0 -0
- thestage/services/clients/thestage_api/api_client.py +718 -718
- thestage/services/clients/thestage_api/core/api_client_core.py +108 -108
- thestage/services/clients/thestage_api/core/http_client_exception.py +12 -12
- thestage/services/clients/thestage_api/dtos/__init__.py +0 -0
- thestage/services/clients/thestage_api/dtos/base_response.py +13 -13
- thestage/services/clients/thestage_api/dtos/cloud_provider_region.py +19 -19
- thestage/services/clients/thestage_api/dtos/container_param_request.py +11 -11
- thestage/services/clients/thestage_api/dtos/container_response.py +67 -67
- thestage/services/clients/thestage_api/dtos/docker_container_assigned_device.py +10 -10
- thestage/services/clients/thestage_api/dtos/docker_container_controller/docker_container_list_request.py +13 -13
- thestage/services/clients/thestage_api/dtos/docker_container_controller/docker_container_list_response.py +13 -13
- thestage/services/clients/thestage_api/dtos/docker_container_mapping.py +10 -10
- thestage/services/clients/thestage_api/dtos/entity_filter_request.py +14 -14
- thestage/services/clients/thestage_api/dtos/enums/__init__.py +0 -0
- thestage/services/clients/thestage_api/dtos/enums/container_pending_action.py +10 -10
- thestage/services/clients/thestage_api/dtos/enums/container_status.py +17 -17
- thestage/services/clients/thestage_api/dtos/enums/cpu_type.py +8 -8
- thestage/services/clients/thestage_api/dtos/enums/currency_type.py +10 -10
- thestage/services/clients/thestage_api/dtos/enums/daemon_status.py +9 -9
- thestage/services/clients/thestage_api/dtos/enums/disk_type.py +7 -7
- thestage/services/clients/thestage_api/dtos/enums/drive_type.py +7 -7
- thestage/services/clients/thestage_api/dtos/enums/gpu_name.py +8 -8
- thestage/services/clients/thestage_api/dtos/enums/inference_model_status.py +9 -9
- thestage/services/clients/thestage_api/dtos/enums/inference_simulator_status.py +15 -15
- thestage/services/clients/thestage_api/dtos/enums/instance_rented_status.py +17 -17
- thestage/services/clients/thestage_api/dtos/enums/instance_type.py +7 -7
- thestage/services/clients/thestage_api/dtos/enums/location_region.py +11 -11
- thestage/services/clients/thestage_api/dtos/enums/power_status.py +10 -10
- thestage/services/clients/thestage_api/dtos/enums/provider_name.py +11 -11
- thestage/services/clients/thestage_api/dtos/enums/selfhosted_status.py +10 -10
- thestage/services/clients/thestage_api/dtos/enums/task_execution_status.py +12 -12
- thestage/services/clients/thestage_api/dtos/enums/task_status.py +12 -12
- thestage/services/clients/thestage_api/dtos/frontend_status.py +10 -10
- thestage/services/clients/thestage_api/dtos/inference_controller/deploy_inference_model_to_instance_request.py +13 -13
- thestage/services/clients/thestage_api/dtos/inference_controller/deploy_inference_model_to_instance_response.py +13 -13
- thestage/services/clients/thestage_api/dtos/inference_controller/deploy_inference_model_to_sagemaker_request.py +12 -12
- thestage/services/clients/thestage_api/dtos/inference_controller/deploy_inference_model_to_sagemaker_response.py +12 -12
- thestage/services/clients/thestage_api/dtos/inference_controller/get_inference_simulator_request.py +10 -10
- thestage/services/clients/thestage_api/dtos/inference_controller/get_inference_simulator_response.py +13 -13
- thestage/services/clients/thestage_api/dtos/inference_controller/inference_simulator_list_for_project_request.py +14 -14
- thestage/services/clients/thestage_api/dtos/inference_controller/inference_simulator_list_for_project_response.py +12 -12
- thestage/services/clients/thestage_api/dtos/inference_controller/inference_simulator_model_list_for_project_request.py +12 -12
- thestage/services/clients/thestage_api/dtos/inference_controller/inference_simulator_model_list_for_project_response.py +13 -13
- thestage/services/clients/thestage_api/dtos/inference_simulator_model_response.py +11 -11
- thestage/services/clients/thestage_api/dtos/inference_simulator_response.py +11 -11
- thestage/services/clients/thestage_api/dtos/installed_service.py +17 -17
- thestage/services/clients/thestage_api/dtos/instance_detected_gpus.py +20 -20
- thestage/services/clients/thestage_api/dtos/instance_rented_response.py +71 -71
- thestage/services/clients/thestage_api/dtos/logging_controller/docker_container_log_stream_request.py +7 -7
- thestage/services/clients/thestage_api/dtos/logging_controller/log_polling_request.py +13 -13
- thestage/services/clients/thestage_api/dtos/logging_controller/log_polling_response.py +14 -14
- thestage/services/clients/thestage_api/dtos/logging_controller/task_log_stream_request.py +7 -7
- thestage/services/clients/thestage_api/dtos/logging_controller/user_logs_query_request.py +21 -21
- thestage/services/clients/thestage_api/dtos/logging_controller/user_logs_query_response.py +14 -14
- thestage/services/clients/thestage_api/dtos/paginated_entity_list.py +11 -11
- thestage/services/clients/thestage_api/dtos/pagination_data.py +10 -10
- thestage/services/clients/thestage_api/dtos/price_definition.py +14 -14
- thestage/services/clients/thestage_api/dtos/project_controller/project_get_deploy_ssh_key_request.py +7 -7
- thestage/services/clients/thestage_api/dtos/project_controller/project_get_deploy_ssh_key_response.py +10 -10
- thestage/services/clients/thestage_api/dtos/project_controller/project_push_inference_simulator_model_request.py +8 -8
- thestage/services/clients/thestage_api/dtos/project_controller/project_push_inference_simulator_model_response.py +6 -6
- thestage/services/clients/thestage_api/dtos/project_controller/project_run_task_request.py +15 -15
- thestage/services/clients/thestage_api/dtos/project_controller/project_run_task_response.py +10 -10
- thestage/services/clients/thestage_api/dtos/project_controller/project_start_inference_simulator_request.py +13 -13
- thestage/services/clients/thestage_api/dtos/project_controller/project_start_inference_simulator_response.py +10 -10
- thestage/services/clients/thestage_api/dtos/project_response.py +32 -32
- thestage/services/clients/thestage_api/dtos/selfhosted_instance_response.py +56 -56
- thestage/services/clients/thestage_api/dtos/sftp_path_helper.py +13 -13
- thestage/services/clients/thestage_api/dtos/ssh_key_controller/add_ssh_key_to_user_request.py +8 -8
- thestage/services/clients/thestage_api/dtos/ssh_key_controller/add_ssh_key_to_user_response.py +11 -11
- thestage/services/clients/thestage_api/dtos/ssh_key_controller/add_ssh_public_key_to_instance_request.py +8 -8
- thestage/services/clients/thestage_api/dtos/ssh_key_controller/add_ssh_public_key_to_instance_response.py +11 -11
- thestage/services/clients/thestage_api/dtos/ssh_key_controller/is_user_has_public_ssh_key_request.py +7 -7
- thestage/services/clients/thestage_api/dtos/ssh_key_controller/is_user_has_public_ssh_key_response.py +12 -12
- thestage/services/clients/thestage_api/dtos/task_controller/task_list_for_project_request.py +10 -10
- thestage/services/clients/thestage_api/dtos/task_controller/task_list_for_project_response.py +12 -12
- thestage/services/clients/thestage_api/dtos/task_controller/task_status_localized_map_response.py +9 -9
- thestage/services/clients/thestage_api/dtos/task_controller/task_view_response.py +12 -12
- thestage/services/clients/thestage_api/dtos/user_controller/user_profile.py +12 -12
- thestage/services/clients/thestage_api/dtos/validate_token_response.py +11 -11
- thestage/services/config_provider/__init__.py +0 -0
- thestage/services/config_provider/config_provider.py +237 -237
- thestage/services/connect/connect_service.py +193 -196
- thestage/services/connect/dto/remote_server_config.py +9 -9
- thestage/services/container/__init__.py +0 -0
- thestage/services/container/container_service.py +374 -374
- thestage/services/container/mapper/__init__.py +0 -0
- thestage/services/container/mapper/container_mapper.py +30 -30
- thestage/services/core_files/config_entity.py +26 -26
- thestage/services/filesystem_service.py +133 -133
- thestage/services/instance/__init__.py +0 -0
- thestage/services/instance/instance_service.py +303 -303
- thestage/services/instance/mapper/__init__.py +0 -0
- thestage/services/instance/mapper/instance_mapper.py +24 -24
- thestage/services/instance/mapper/selfhosted_mapper.py +33 -33
- thestage/services/logging/byte_print_style.py +5 -5
- thestage/services/logging/dto/log_message.py +15 -15
- thestage/services/logging/dto/log_type.py +6 -6
- thestage/services/logging/exception/log_polling_exception.py +6 -6
- thestage/services/logging/logging_constants.py +3 -3
- thestage/services/logging/logging_service.py +367 -367
- thestage/services/project/__init__.py +0 -0
- thestage/services/project/dto/inference_simulator_dto.py +22 -22
- thestage/services/project/dto/inference_simulator_model_dto.py +20 -20
- thestage/services/project/dto/project_config.py +14 -14
- thestage/services/project/mapper/__init__.py +0 -0
- thestage/services/project/mapper/project_inference_simulator_mapper.py +21 -21
- thestage/services/project/mapper/project_inference_simulator_model_mapper.py +21 -21
- thestage/services/project/mapper/project_task_mapper.py +22 -22
- thestage/services/project/project_service.py +1253 -1260
- thestage/services/remote_server_service.py +609 -609
- thestage/services/service_factory.py +97 -97
- thestage/services/task/dto/task_dto.py +40 -40
- thestage/services/validation_service.py +61 -61
- {thestage-0.6.1.dist-info → thestage-0.6.3.dist-info}/LICENSE.txt +12 -12
- {thestage-0.6.1.dist-info → thestage-0.6.3.dist-info}/METADATA +3 -2
- thestage-0.6.3.dist-info/RECORD +176 -0
- {thestage-0.6.1.dist-info → thestage-0.6.3.dist-info}/WHEEL +1 -1
- thestage-0.6.1.dist-info/RECORD +0 -176
- {thestage-0.6.1.dist-info → thestage-0.6.3.dist-info}/entry_points.txt +0 -0
|
File without changes
|
|
@@ -1,30 +1,30 @@
|
|
|
1
|
-
from typing import Optional, Tuple
|
|
2
|
-
|
|
3
|
-
from thestage.services.clients.thestage_api.dtos.container_response import DockerContainerDto
|
|
4
|
-
from thestage.entities.container import DockerContainerEntity
|
|
5
|
-
from thestage.services.abstract_mapper import AbstractMapper
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
class ContainerMapper(AbstractMapper):
|
|
9
|
-
|
|
10
|
-
def build_entity(self, item: DockerContainerDto) -> Optional[DockerContainerEntity]:
|
|
11
|
-
if not item:
|
|
12
|
-
return None
|
|
13
|
-
|
|
14
|
-
instance_type = ''
|
|
15
|
-
instance_slug = ''
|
|
16
|
-
if item.instance_rented:
|
|
17
|
-
instance_type = 'RENTED'
|
|
18
|
-
instance_slug = item.instance_rented.slug
|
|
19
|
-
if item.selfhosted_instance:
|
|
20
|
-
instance_type = 'SELF-HOSTED'
|
|
21
|
-
instance_slug = item.selfhosted_instance.slug
|
|
22
|
-
|
|
23
|
-
return DockerContainerEntity(
|
|
24
|
-
status=item.frontend_status.status_translation if item.frontend_status else '',
|
|
25
|
-
slug=item.slug or '',
|
|
26
|
-
title=item.title or '',
|
|
27
|
-
instance_type=instance_type,
|
|
28
|
-
instance_slug=instance_slug,
|
|
29
|
-
docker_image=item.docker_image or '',
|
|
30
|
-
)
|
|
1
|
+
from typing import Optional, Tuple
|
|
2
|
+
|
|
3
|
+
from thestage.services.clients.thestage_api.dtos.container_response import DockerContainerDto
|
|
4
|
+
from thestage.entities.container import DockerContainerEntity
|
|
5
|
+
from thestage.services.abstract_mapper import AbstractMapper
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class ContainerMapper(AbstractMapper):
|
|
9
|
+
|
|
10
|
+
def build_entity(self, item: DockerContainerDto) -> Optional[DockerContainerEntity]:
|
|
11
|
+
if not item:
|
|
12
|
+
return None
|
|
13
|
+
|
|
14
|
+
instance_type = ''
|
|
15
|
+
instance_slug = ''
|
|
16
|
+
if item.instance_rented:
|
|
17
|
+
instance_type = 'RENTED'
|
|
18
|
+
instance_slug = item.instance_rented.slug
|
|
19
|
+
if item.selfhosted_instance:
|
|
20
|
+
instance_type = 'SELF-HOSTED'
|
|
21
|
+
instance_slug = item.selfhosted_instance.slug
|
|
22
|
+
|
|
23
|
+
return DockerContainerEntity(
|
|
24
|
+
status=item.frontend_status.status_translation if item.frontend_status else '',
|
|
25
|
+
slug=item.slug or '',
|
|
26
|
+
title=item.title or '',
|
|
27
|
+
instance_type=instance_type,
|
|
28
|
+
instance_slug=instance_slug,
|
|
29
|
+
docker_image=item.docker_image or '',
|
|
30
|
+
)
|
|
@@ -1,26 +1,26 @@
|
|
|
1
|
-
from typing import Optional, Dict
|
|
2
|
-
|
|
3
|
-
from pydantic import BaseModel, Field
|
|
4
|
-
|
|
5
|
-
from thestage.cli_command import CliCommand, CliCommandAvailability
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
# saved to file
|
|
9
|
-
class MainConfigEntity(BaseModel):
|
|
10
|
-
thestage_auth_token: Optional[str] = Field(None, alias='thestage_auth_token')
|
|
11
|
-
thestage_api_url: Optional[str] = Field(None, alias='thestage_api_url')
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
# not saved to file
|
|
15
|
-
class RuntimeConfigEntity(BaseModel):
|
|
16
|
-
working_directory: Optional[str] = Field(None, alias='working_directory')
|
|
17
|
-
config_global_path: Optional[str] = Field(None, alias='config_global_path')
|
|
18
|
-
allowed_commands: Dict[CliCommand, CliCommandAvailability] = {}
|
|
19
|
-
is_token_valid: bool = Field(None, alias='is_token_valid')
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
class ConfigEntity(BaseModel):
|
|
23
|
-
global_config_path: str = Field(None, alias='global_config_path')
|
|
24
|
-
can_use_inference: bool = Field(None, alias='can_use_inference')
|
|
25
|
-
main: MainConfigEntity = Field(default_factory=MainConfigEntity, alias='main')
|
|
26
|
-
runtime: RuntimeConfigEntity = Field(default_factory=RuntimeConfigEntity, alias="runtime") # TODO merge with main
|
|
1
|
+
from typing import Optional, Dict
|
|
2
|
+
|
|
3
|
+
from pydantic import BaseModel, Field
|
|
4
|
+
|
|
5
|
+
from thestage.cli_command import CliCommand, CliCommandAvailability
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
# saved to file
|
|
9
|
+
class MainConfigEntity(BaseModel):
|
|
10
|
+
thestage_auth_token: Optional[str] = Field(None, alias='thestage_auth_token')
|
|
11
|
+
thestage_api_url: Optional[str] = Field(None, alias='thestage_api_url')
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
# not saved to file
|
|
15
|
+
class RuntimeConfigEntity(BaseModel):
|
|
16
|
+
working_directory: Optional[str] = Field(None, alias='working_directory')
|
|
17
|
+
config_global_path: Optional[str] = Field(None, alias='config_global_path')
|
|
18
|
+
allowed_commands: Dict[CliCommand, CliCommandAvailability] = {}
|
|
19
|
+
is_token_valid: bool = Field(None, alias='is_token_valid')
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class ConfigEntity(BaseModel):
|
|
23
|
+
global_config_path: str = Field(None, alias='global_config_path')
|
|
24
|
+
can_use_inference: bool = Field(None, alias='can_use_inference')
|
|
25
|
+
main: MainConfigEntity = Field(default_factory=MainConfigEntity, alias='main')
|
|
26
|
+
runtime: RuntimeConfigEntity = Field(default_factory=RuntimeConfigEntity, alias="runtime") # TODO merge with main
|
|
@@ -1,133 +1,133 @@
|
|
|
1
|
-
import json
|
|
2
|
-
import os
|
|
3
|
-
import shutil
|
|
4
|
-
from json import JSONDecodeError
|
|
5
|
-
from pathlib import Path
|
|
6
|
-
from typing import Optional, List, Dict, Any
|
|
7
|
-
|
|
8
|
-
from thestage.entities.file_item import FileItemEntity
|
|
9
|
-
from thestage.exceptions.file_system_exception import FileSystemException
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
class FileSystemService:
|
|
13
|
-
|
|
14
|
-
def get_ssh_path(self) -> Optional[Path]:
|
|
15
|
-
home_path = self.get_home_path()
|
|
16
|
-
ssh_path = home_path.joinpath('.ssh')
|
|
17
|
-
if not ssh_path.exists():
|
|
18
|
-
raise FileSystemException(f"Path does not exist: {ssh_path}")
|
|
19
|
-
return ssh_path
|
|
20
|
-
|
|
21
|
-
def get_home_path(self) -> Optional[Path]:
|
|
22
|
-
try:
|
|
23
|
-
return Path.home()
|
|
24
|
-
except RuntimeError | OSError as ex1:
|
|
25
|
-
raise FileSystemException("Error getting user home path") from ex1
|
|
26
|
-
|
|
27
|
-
def create_if_not_exists_dir(self, path: Path) -> Path:
|
|
28
|
-
if not path.exists():
|
|
29
|
-
try:
|
|
30
|
-
path.mkdir(exist_ok=True, parents=True)
|
|
31
|
-
except FileNotFoundError as ex1:
|
|
32
|
-
raise FileSystemException(message=f"FileNotFoundError (dir): {path}") from ex1
|
|
33
|
-
except OSError as ex2:
|
|
34
|
-
raise FileSystemException(message=f"Could not create directory: {path}") from ex2
|
|
35
|
-
return path
|
|
36
|
-
|
|
37
|
-
def create_if_not_exists_file(self, path: Path) -> Path:
|
|
38
|
-
if not path.exists():
|
|
39
|
-
try:
|
|
40
|
-
path.touch(exist_ok=True)
|
|
41
|
-
except FileNotFoundError as ex1:
|
|
42
|
-
raise FileSystemException(message=f"FileNotFoundError (file): {path}") from ex1
|
|
43
|
-
except OSError as ex2:
|
|
44
|
-
raise FileSystemException(message=f"Could not create file: {path}") from ex2
|
|
45
|
-
return path
|
|
46
|
-
|
|
47
|
-
def get_path(self, directory: str, auto_create: bool = True) -> Path:
|
|
48
|
-
path = Path(directory)
|
|
49
|
-
if auto_create:
|
|
50
|
-
self.create_if_not_exists_dir(path)
|
|
51
|
-
return path
|
|
52
|
-
|
|
53
|
-
def is_folder_empty(self, folder: str, auto_create: bool) -> bool:
|
|
54
|
-
path = self.get_path(folder, auto_create)
|
|
55
|
-
if not path.exists():
|
|
56
|
-
return True
|
|
57
|
-
if not path.is_dir():
|
|
58
|
-
raise FileSystemException(message=f"Expected directory but found a file: {path}")
|
|
59
|
-
objects = os.listdir(path)
|
|
60
|
-
if len(objects) == 0:
|
|
61
|
-
return True
|
|
62
|
-
else:
|
|
63
|
-
return False
|
|
64
|
-
|
|
65
|
-
def is_folder_exists(self, folder: str, auto_create: bool = True) -> bool:
|
|
66
|
-
path = self.get_path(folder, auto_create=auto_create)
|
|
67
|
-
if path.exists():
|
|
68
|
-
return True
|
|
69
|
-
else:
|
|
70
|
-
return False
|
|
71
|
-
|
|
72
|
-
def find_line_in_text_file(self, file: str, find: str) -> bool:
|
|
73
|
-
path = self.get_path(file, auto_create=False)
|
|
74
|
-
if path and path.exists():
|
|
75
|
-
with open(path, 'r') as file:
|
|
76
|
-
for line in file.readlines():
|
|
77
|
-
if (find + "\n") == line:
|
|
78
|
-
return True
|
|
79
|
-
return False
|
|
80
|
-
|
|
81
|
-
def add_line_to_text_file(self, file: str, new_line: str):
|
|
82
|
-
path = self.get_path(file, auto_create=False)
|
|
83
|
-
if path and path.exists():
|
|
84
|
-
with open(path, 'a') as file:
|
|
85
|
-
file.write(new_line)
|
|
86
|
-
file.write('\n')
|
|
87
|
-
|
|
88
|
-
# TODO remove this fucking useless shit
|
|
89
|
-
def check_if_path_exist(self, file: str) -> bool:
|
|
90
|
-
path = self.get_path(file, auto_create=False)
|
|
91
|
-
if path.exists():
|
|
92
|
-
return True
|
|
93
|
-
else:
|
|
94
|
-
return False
|
|
95
|
-
|
|
96
|
-
def get_path_items(self, folder: str) -> List[FileItemEntity]:
|
|
97
|
-
path = self.get_path(folder, auto_create=False)
|
|
98
|
-
path_items = []
|
|
99
|
-
if not path.exists():
|
|
100
|
-
return path_items
|
|
101
|
-
|
|
102
|
-
parent = FileItemEntity.build_from_path(path=path)
|
|
103
|
-
path_items.append(parent)
|
|
104
|
-
if path.is_dir():
|
|
105
|
-
objects = os.listdir(path)
|
|
106
|
-
if objects:
|
|
107
|
-
for item in objects:
|
|
108
|
-
elem = path.joinpath(item)
|
|
109
|
-
if elem.is_dir():
|
|
110
|
-
parent.children.extend(self.get_path_items(folder=str(elem)))
|
|
111
|
-
else:
|
|
112
|
-
parent.children.append(FileItemEntity.build_from_path(path=elem))
|
|
113
|
-
return path_items
|
|
114
|
-
|
|
115
|
-
def remove_folder(self, path: str):
|
|
116
|
-
real_path = self.get_path(directory=path, auto_create=False)
|
|
117
|
-
if real_path and real_path.exists():
|
|
118
|
-
shutil.rmtree(real_path)
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
def read_config_file(self, path: Path) -> Dict[str, Any]:
|
|
122
|
-
result = {}
|
|
123
|
-
try:
|
|
124
|
-
if path and path.exists():
|
|
125
|
-
with path.open("r") as file:
|
|
126
|
-
try:
|
|
127
|
-
if os.stat(path).st_size != 0:
|
|
128
|
-
result = json.load(file)
|
|
129
|
-
except JSONDecodeError as e:
|
|
130
|
-
raise Exception(f"Config file is malformed: {path}") from e
|
|
131
|
-
except OSError:
|
|
132
|
-
raise FileSystemException(f"Could not open config file: {path}")
|
|
133
|
-
return result
|
|
1
|
+
import json
|
|
2
|
+
import os
|
|
3
|
+
import shutil
|
|
4
|
+
from json import JSONDecodeError
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import Optional, List, Dict, Any
|
|
7
|
+
|
|
8
|
+
from thestage.entities.file_item import FileItemEntity
|
|
9
|
+
from thestage.exceptions.file_system_exception import FileSystemException
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class FileSystemService:
|
|
13
|
+
|
|
14
|
+
def get_ssh_path(self) -> Optional[Path]:
|
|
15
|
+
home_path = self.get_home_path()
|
|
16
|
+
ssh_path = home_path.joinpath('.ssh')
|
|
17
|
+
if not ssh_path.exists():
|
|
18
|
+
raise FileSystemException(f"Path does not exist: {ssh_path}")
|
|
19
|
+
return ssh_path
|
|
20
|
+
|
|
21
|
+
def get_home_path(self) -> Optional[Path]:
|
|
22
|
+
try:
|
|
23
|
+
return Path.home()
|
|
24
|
+
except RuntimeError | OSError as ex1:
|
|
25
|
+
raise FileSystemException("Error getting user home path") from ex1
|
|
26
|
+
|
|
27
|
+
def create_if_not_exists_dir(self, path: Path) -> Path:
|
|
28
|
+
if not path.exists():
|
|
29
|
+
try:
|
|
30
|
+
path.mkdir(exist_ok=True, parents=True)
|
|
31
|
+
except FileNotFoundError as ex1:
|
|
32
|
+
raise FileSystemException(message=f"FileNotFoundError (dir): {path}") from ex1
|
|
33
|
+
except OSError as ex2:
|
|
34
|
+
raise FileSystemException(message=f"Could not create directory: {path}") from ex2
|
|
35
|
+
return path
|
|
36
|
+
|
|
37
|
+
def create_if_not_exists_file(self, path: Path) -> Path:
|
|
38
|
+
if not path.exists():
|
|
39
|
+
try:
|
|
40
|
+
path.touch(exist_ok=True)
|
|
41
|
+
except FileNotFoundError as ex1:
|
|
42
|
+
raise FileSystemException(message=f"FileNotFoundError (file): {path}") from ex1
|
|
43
|
+
except OSError as ex2:
|
|
44
|
+
raise FileSystemException(message=f"Could not create file: {path}") from ex2
|
|
45
|
+
return path
|
|
46
|
+
|
|
47
|
+
def get_path(self, directory: str, auto_create: bool = True) -> Path:
|
|
48
|
+
path = Path(directory)
|
|
49
|
+
if auto_create:
|
|
50
|
+
self.create_if_not_exists_dir(path)
|
|
51
|
+
return path
|
|
52
|
+
|
|
53
|
+
def is_folder_empty(self, folder: str, auto_create: bool) -> bool:
|
|
54
|
+
path = self.get_path(folder, auto_create)
|
|
55
|
+
if not path.exists():
|
|
56
|
+
return True
|
|
57
|
+
if not path.is_dir():
|
|
58
|
+
raise FileSystemException(message=f"Expected directory but found a file: {path}")
|
|
59
|
+
objects = os.listdir(path)
|
|
60
|
+
if len(objects) == 0:
|
|
61
|
+
return True
|
|
62
|
+
else:
|
|
63
|
+
return False
|
|
64
|
+
|
|
65
|
+
def is_folder_exists(self, folder: str, auto_create: bool = True) -> bool:
|
|
66
|
+
path = self.get_path(folder, auto_create=auto_create)
|
|
67
|
+
if path.exists():
|
|
68
|
+
return True
|
|
69
|
+
else:
|
|
70
|
+
return False
|
|
71
|
+
|
|
72
|
+
def find_line_in_text_file(self, file: str, find: str) -> bool:
|
|
73
|
+
path = self.get_path(file, auto_create=False)
|
|
74
|
+
if path and path.exists():
|
|
75
|
+
with open(path, 'r') as file:
|
|
76
|
+
for line in file.readlines():
|
|
77
|
+
if (find + "\n") == line:
|
|
78
|
+
return True
|
|
79
|
+
return False
|
|
80
|
+
|
|
81
|
+
def add_line_to_text_file(self, file: str, new_line: str):
|
|
82
|
+
path = self.get_path(file, auto_create=False)
|
|
83
|
+
if path and path.exists():
|
|
84
|
+
with open(path, 'a') as file:
|
|
85
|
+
file.write(new_line)
|
|
86
|
+
file.write('\n')
|
|
87
|
+
|
|
88
|
+
# TODO remove this fucking useless shit
|
|
89
|
+
def check_if_path_exist(self, file: str) -> bool:
|
|
90
|
+
path = self.get_path(file, auto_create=False)
|
|
91
|
+
if path.exists():
|
|
92
|
+
return True
|
|
93
|
+
else:
|
|
94
|
+
return False
|
|
95
|
+
|
|
96
|
+
def get_path_items(self, folder: str) -> List[FileItemEntity]:
|
|
97
|
+
path = self.get_path(folder, auto_create=False)
|
|
98
|
+
path_items = []
|
|
99
|
+
if not path.exists():
|
|
100
|
+
return path_items
|
|
101
|
+
|
|
102
|
+
parent = FileItemEntity.build_from_path(path=path)
|
|
103
|
+
path_items.append(parent)
|
|
104
|
+
if path.is_dir():
|
|
105
|
+
objects = os.listdir(path)
|
|
106
|
+
if objects:
|
|
107
|
+
for item in objects:
|
|
108
|
+
elem = path.joinpath(item)
|
|
109
|
+
if elem.is_dir():
|
|
110
|
+
parent.children.extend(self.get_path_items(folder=str(elem)))
|
|
111
|
+
else:
|
|
112
|
+
parent.children.append(FileItemEntity.build_from_path(path=elem))
|
|
113
|
+
return path_items
|
|
114
|
+
|
|
115
|
+
def remove_folder(self, path: str):
|
|
116
|
+
real_path = self.get_path(directory=path, auto_create=False)
|
|
117
|
+
if real_path and real_path.exists():
|
|
118
|
+
shutil.rmtree(real_path)
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def read_config_file(self, path: Path) -> Dict[str, Any]:
|
|
122
|
+
result = {}
|
|
123
|
+
try:
|
|
124
|
+
if path and path.exists():
|
|
125
|
+
with path.open("r") as file:
|
|
126
|
+
try:
|
|
127
|
+
if os.stat(path).st_size != 0:
|
|
128
|
+
result = json.load(file)
|
|
129
|
+
except JSONDecodeError as e:
|
|
130
|
+
raise Exception(f"Config file is malformed: {path}") from e
|
|
131
|
+
except OSError:
|
|
132
|
+
raise FileSystemException(f"Could not open config file: {path}")
|
|
133
|
+
return result
|
|
File without changes
|