shipit-cli 0.21.0__tar.gz → 0.21.2__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.
- {shipit_cli-0.21.0 → shipit_cli-0.21.2}/PKG-INFO +1 -1
- {shipit_cli-0.21.0 → shipit_cli-0.21.2}/pyproject.toml +1 -1
- {shipit_cli-0.21.0 → shipit_cli-0.21.2}/src/shipit/builders/docker.py +9 -4
- {shipit_cli-0.21.0 → shipit_cli-0.21.2}/src/shipit/builders/local.py +9 -3
- {shipit_cli-0.21.0 → shipit_cli-0.21.2}/src/shipit/cli.py +82 -15
- {shipit_cli-0.21.0 → shipit_cli-0.21.2}/src/shipit/runners/local.py +8 -2
- {shipit_cli-0.21.0 → shipit_cli-0.21.2}/src/shipit/runners/wasmer.py +19 -17
- shipit_cli-0.21.2/src/shipit/version.py +5 -0
- {shipit_cli-0.21.0 → shipit_cli-0.21.2}/src/shipit/volumes.py +27 -13
- {shipit_cli-0.21.0 → shipit_cli-0.21.2}/tests/test_subdir.py +184 -4
- {shipit_cli-0.21.0 → shipit_cli-0.21.2}/tests/test_volumes.py +37 -0
- shipit_cli-0.21.0/src/shipit/version.py +0 -5
- {shipit_cli-0.21.0 → shipit_cli-0.21.2}/.gitignore +0 -0
- {shipit_cli-0.21.0 → shipit_cli-0.21.2}/README.md +0 -0
- {shipit_cli-0.21.0 → shipit_cli-0.21.2}/src/shipit/__init__.py +0 -0
- {shipit_cli-0.21.0 → shipit_cli-0.21.2}/src/shipit/assets/node/optimize-node-modules.sh +0 -0
- {shipit_cli-0.21.0 → shipit_cli-0.21.2}/src/shipit/assets/php/php.ini +0 -0
- {shipit_cli-0.21.0 → shipit_cli-0.21.2}/src/shipit/assets/wordpress/.htaccess +0 -0
- {shipit_cli-0.21.0 → shipit_cli-0.21.2}/src/shipit/assets/wordpress/install.sh +0 -0
- {shipit_cli-0.21.0 → shipit_cli-0.21.2}/src/shipit/assets/wordpress/start.php +0 -0
- {shipit_cli-0.21.0 → shipit_cli-0.21.2}/src/shipit/assets/wordpress/wp-config.php +0 -0
- {shipit_cli-0.21.0 → shipit_cli-0.21.2}/src/shipit/builders/__init__.py +0 -0
- {shipit_cli-0.21.0 → shipit_cli-0.21.2}/src/shipit/builders/base.py +0 -0
- {shipit_cli-0.21.0 → shipit_cli-0.21.2}/src/shipit/generator.py +0 -0
- {shipit_cli-0.21.0 → shipit_cli-0.21.2}/src/shipit/procfile.py +0 -0
- {shipit_cli-0.21.0 → shipit_cli-0.21.2}/src/shipit/providers/base.py +0 -0
- {shipit_cli-0.21.0 → shipit_cli-0.21.2}/src/shipit/providers/go.py +0 -0
- {shipit_cli-0.21.0 → shipit_cli-0.21.2}/src/shipit/providers/hugo.py +0 -0
- {shipit_cli-0.21.0 → shipit_cli-0.21.2}/src/shipit/providers/install_context.py +0 -0
- {shipit_cli-0.21.0 → shipit_cli-0.21.2}/src/shipit/providers/jekyll.py +0 -0
- {shipit_cli-0.21.0 → shipit_cli-0.21.2}/src/shipit/providers/laravel.py +0 -0
- {shipit_cli-0.21.0 → shipit_cli-0.21.2}/src/shipit/providers/mkdocs.py +0 -0
- {shipit_cli-0.21.0 → shipit_cli-0.21.2}/src/shipit/providers/node.py +0 -0
- {shipit_cli-0.21.0 → shipit_cli-0.21.2}/src/shipit/providers/node_static.py +0 -0
- {shipit_cli-0.21.0 → shipit_cli-0.21.2}/src/shipit/providers/php.py +0 -0
- {shipit_cli-0.21.0 → shipit_cli-0.21.2}/src/shipit/providers/python.py +0 -0
- {shipit_cli-0.21.0 → shipit_cli-0.21.2}/src/shipit/providers/registry.py +0 -0
- {shipit_cli-0.21.0 → shipit_cli-0.21.2}/src/shipit/providers/staticfile.py +0 -0
- {shipit_cli-0.21.0 → shipit_cli-0.21.2}/src/shipit/providers/wordpress.py +0 -0
- {shipit_cli-0.21.0 → shipit_cli-0.21.2}/src/shipit/runners/__init__.py +0 -0
- {shipit_cli-0.21.0 → shipit_cli-0.21.2}/src/shipit/runners/base.py +0 -0
- {shipit_cli-0.21.0 → shipit_cli-0.21.2}/src/shipit/shipit_types.py +0 -0
- {shipit_cli-0.21.0 → shipit_cli-0.21.2}/src/shipit/ui.py +0 -0
- {shipit_cli-0.21.0 → shipit_cli-0.21.2}/src/shipit/utils.py +0 -0
- {shipit_cli-0.21.0 → shipit_cli-0.21.2}/tests/test_cli_after_deploy.py +0 -0
- {shipit_cli-0.21.0 → shipit_cli-0.21.2}/tests/test_e2e.py +0 -0
- {shipit_cli-0.21.0 → shipit_cli-0.21.2}/tests/test_generate_shipit_examples.py +0 -0
- {shipit_cli-0.21.0 → shipit_cli-0.21.2}/tests/test_install_context.py +0 -0
- {shipit_cli-0.21.0 → shipit_cli-0.21.2}/tests/test_node_provider.py +0 -0
- {shipit_cli-0.21.0 → shipit_cli-0.21.2}/tests/test_node_static_provider.py +0 -0
- {shipit_cli-0.21.0 → shipit_cli-0.21.2}/tests/test_php_provider.py +0 -0
- {shipit_cli-0.21.0 → shipit_cli-0.21.2}/tests/test_staticfile_provider.py +0 -0
- {shipit_cli-0.21.0 → shipit_cli-0.21.2}/tests/test_version.py +0 -0
- {shipit_cli-0.21.0 → shipit_cli-0.21.2}/tests/test_wasmer_annotations.py +0 -0
- {shipit_cli-0.21.0 → shipit_cli-0.21.2}/tests/test_wordpress_phpix.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: shipit-cli
|
|
3
|
-
Version: 0.21.
|
|
3
|
+
Version: 0.21.2
|
|
4
4
|
Summary: Shipit CLI is the best way to build, serve and deploy your projects anywhere.
|
|
5
5
|
Project-URL: homepage, https://wasmer.io
|
|
6
6
|
Project-URL: repository, https://github.com/wasmerio/shipit
|
|
@@ -45,12 +45,17 @@ class DockerBuildBackend:
|
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
def __init__(
|
|
48
|
-
self,
|
|
49
|
-
|
|
48
|
+
self,
|
|
49
|
+
src_dir: Path,
|
|
50
|
+
assets_path: Path,
|
|
51
|
+
docker_client: Optional[str] = None,
|
|
52
|
+
docker_opts: Optional[str] = None,
|
|
53
|
+
shipit_dir: Optional[Path] = None,
|
|
50
54
|
) -> None:
|
|
51
55
|
self.src_dir = src_dir
|
|
52
56
|
self.assets_path = assets_path
|
|
53
|
-
self.
|
|
57
|
+
self.shipit_dir = shipit_dir or self.src_dir / ".shipit"
|
|
58
|
+
self.docker_path = self.shipit_dir / "docker"
|
|
54
59
|
self.docker_path.mkdir(parents=True, exist_ok=True)
|
|
55
60
|
self.docker_out_path = self.docker_path / "out"
|
|
56
61
|
self.docker_file_path = self.docker_path / "Dockerfile"
|
|
@@ -77,7 +82,7 @@ class DockerBuildBackend:
|
|
|
77
82
|
return self.docker_out_path / self.get_mount_path(name)
|
|
78
83
|
|
|
79
84
|
def get_volume_path(self, name: str) -> Path:
|
|
80
|
-
return self.
|
|
85
|
+
return self.shipit_dir / "volumes" / name
|
|
81
86
|
|
|
82
87
|
@property
|
|
83
88
|
def is_depot(self) -> bool:
|
|
@@ -25,10 +25,16 @@ from shipit.utils import download_file
|
|
|
25
25
|
|
|
26
26
|
|
|
27
27
|
class LocalBuildBackend:
|
|
28
|
-
def __init__(
|
|
28
|
+
def __init__(
|
|
29
|
+
self,
|
|
30
|
+
src_dir: Path,
|
|
31
|
+
assets_path: Path,
|
|
32
|
+
shipit_dir: Optional[Path] = None,
|
|
33
|
+
) -> None:
|
|
29
34
|
self.src_dir = src_dir
|
|
30
35
|
self.assets_path = assets_path
|
|
31
|
-
self.
|
|
36
|
+
self.shipit_dir = shipit_dir or self.src_dir / ".shipit"
|
|
37
|
+
self.local_path = self.shipit_dir / "local"
|
|
32
38
|
self.build_path = self.local_path / "build"
|
|
33
39
|
self.workdir = self.build_path
|
|
34
40
|
self.runtime_path: Optional[str] = None
|
|
@@ -46,7 +52,7 @@ class LocalBuildBackend:
|
|
|
46
52
|
return self.get_mount_path(name)
|
|
47
53
|
|
|
48
54
|
def get_volume_path(self, name: str) -> Path:
|
|
49
|
-
return self.
|
|
55
|
+
return self.shipit_dir / "volumes" / name
|
|
50
56
|
|
|
51
57
|
def execute_step(self, step: Step, env: Dict[str, str]) -> None:
|
|
52
58
|
build_path = self.workdir
|
|
@@ -79,6 +79,13 @@ def default_shipit_path(project_paths: ProjectPaths) -> Path:
|
|
|
79
79
|
)
|
|
80
80
|
|
|
81
81
|
|
|
82
|
+
def default_shipit_dir(project_paths: ProjectPaths) -> Path:
|
|
83
|
+
shipit_dir = project_paths.workspace_root / ".shipit"
|
|
84
|
+
if project_paths.subdir is None:
|
|
85
|
+
return shipit_dir
|
|
86
|
+
return shipit_dir / shipit_subdir_slug(project_paths.subdir)
|
|
87
|
+
|
|
88
|
+
|
|
82
89
|
def resolve_project_paths(path: Path, subdir: Optional[Path] = None) -> ProjectPaths:
|
|
83
90
|
workspace_root = path.resolve()
|
|
84
91
|
if subdir is None:
|
|
@@ -673,6 +680,7 @@ def auto(
|
|
|
673
680
|
):
|
|
674
681
|
run(
|
|
675
682
|
project_paths.workspace_root,
|
|
683
|
+
subdir=Path(project_paths.subdir) if project_paths.subdir else None,
|
|
676
684
|
wasmer=wasmer,
|
|
677
685
|
wasmer_bin=wasmer_bin,
|
|
678
686
|
docker=docker,
|
|
@@ -685,10 +693,11 @@ def auto(
|
|
|
685
693
|
wasmer_registry=wasmer_registry,
|
|
686
694
|
serve_port=serve_port,
|
|
687
695
|
)
|
|
688
|
-
|
|
696
|
+
|
|
689
697
|
if wasmer_deploy or wasmer_deploy_config:
|
|
690
698
|
deploy(
|
|
691
699
|
project_paths.workspace_root,
|
|
700
|
+
subdir=Path(project_paths.subdir) if project_paths.subdir else None,
|
|
692
701
|
wasmer_deploy=wasmer_deploy,
|
|
693
702
|
wasmer_deploy_config=wasmer_deploy_config,
|
|
694
703
|
wasmer_bin=wasmer_bin,
|
|
@@ -809,6 +818,11 @@ def deploy(
|
|
|
809
818
|
help="Project path (defaults to current directory).",
|
|
810
819
|
show_default=False,
|
|
811
820
|
),
|
|
821
|
+
subdir: Optional[Path] = typer.Option(
|
|
822
|
+
None,
|
|
823
|
+
"--subdir",
|
|
824
|
+
help="App subdirectory relative to the project path.",
|
|
825
|
+
),
|
|
812
826
|
wasmer_deploy: bool = typer.Option(
|
|
813
827
|
True,
|
|
814
828
|
help="Deploy the project to Wasmer.",
|
|
@@ -840,14 +854,21 @@ def deploy(
|
|
|
840
854
|
) -> None:
|
|
841
855
|
if not path.exists():
|
|
842
856
|
raise Exception(f"The path {path} does not exist")
|
|
857
|
+
project_paths = resolve_project_paths(path, subdir)
|
|
858
|
+
shipit_dir = default_shipit_dir(project_paths)
|
|
843
859
|
|
|
844
|
-
build_backend = LocalBuildBackend(
|
|
860
|
+
build_backend = LocalBuildBackend(
|
|
861
|
+
project_paths.workspace_root,
|
|
862
|
+
ASSETS_PATH,
|
|
863
|
+
shipit_dir=shipit_dir,
|
|
864
|
+
)
|
|
845
865
|
runner = WasmerRunner(
|
|
846
866
|
build_backend,
|
|
847
|
-
|
|
867
|
+
project_paths.workspace_root,
|
|
848
868
|
registry=wasmer_registry,
|
|
849
869
|
token=wasmer_token,
|
|
850
870
|
bin=wasmer_bin,
|
|
871
|
+
shipit_dir=shipit_dir,
|
|
851
872
|
)
|
|
852
873
|
|
|
853
874
|
if wasmer_deploy_config:
|
|
@@ -863,6 +884,11 @@ def run(
|
|
|
863
884
|
help="Project path (defaults to current directory).",
|
|
864
885
|
show_default=False,
|
|
865
886
|
),
|
|
887
|
+
subdir: Optional[Path] = typer.Option(
|
|
888
|
+
None,
|
|
889
|
+
"--subdir",
|
|
890
|
+
help="App subdirectory relative to the project path.",
|
|
891
|
+
),
|
|
866
892
|
wasmer: bool = typer.Option(
|
|
867
893
|
False,
|
|
868
894
|
help="Use Wasmer to run the project.",
|
|
@@ -915,23 +941,38 @@ def run(
|
|
|
915
941
|
) -> None:
|
|
916
942
|
if not path.exists():
|
|
917
943
|
raise Exception(f"The path {path} does not exist")
|
|
944
|
+
project_paths = resolve_project_paths(path, subdir)
|
|
945
|
+
shipit_dir = default_shipit_dir(project_paths)
|
|
918
946
|
|
|
919
947
|
if docker or docker_client:
|
|
920
948
|
build_backend: BuildBackend = DockerBuildBackend(
|
|
921
|
-
|
|
949
|
+
project_paths.workspace_root,
|
|
950
|
+
ASSETS_PATH,
|
|
951
|
+
docker_client,
|
|
952
|
+
docker_opts,
|
|
953
|
+
shipit_dir=shipit_dir,
|
|
922
954
|
)
|
|
923
955
|
else:
|
|
924
|
-
build_backend = LocalBuildBackend(
|
|
956
|
+
build_backend = LocalBuildBackend(
|
|
957
|
+
project_paths.workspace_root,
|
|
958
|
+
ASSETS_PATH,
|
|
959
|
+
shipit_dir=shipit_dir,
|
|
960
|
+
)
|
|
925
961
|
|
|
926
962
|
if wasmer:
|
|
927
963
|
runner: Runner = WasmerRunner(
|
|
928
964
|
build_backend,
|
|
929
|
-
|
|
965
|
+
project_paths.workspace_root,
|
|
930
966
|
registry=wasmer_registry,
|
|
931
967
|
bin=wasmer_bin,
|
|
968
|
+
shipit_dir=shipit_dir,
|
|
932
969
|
)
|
|
933
970
|
else:
|
|
934
|
-
runner = LocalRunner(
|
|
971
|
+
runner = LocalRunner(
|
|
972
|
+
build_backend,
|
|
973
|
+
project_paths.workspace_root,
|
|
974
|
+
shipit_dir=shipit_dir,
|
|
975
|
+
)
|
|
935
976
|
|
|
936
977
|
commands_to_run = resolve_run_commands(
|
|
937
978
|
command_names=command_names,
|
|
@@ -941,11 +982,12 @@ def run(
|
|
|
941
982
|
|
|
942
983
|
if commands_to_run:
|
|
943
984
|
run_serve_commands(
|
|
944
|
-
|
|
985
|
+
project_paths.workspace_root,
|
|
945
986
|
runner,
|
|
946
987
|
commands_to_run,
|
|
947
988
|
volume_specs=volume_specs,
|
|
948
989
|
env=runtime_serve_env(serve_port),
|
|
990
|
+
shipit_dir=shipit_dir,
|
|
949
991
|
)
|
|
950
992
|
else:
|
|
951
993
|
console.print("[bold]No commands specified. Use `--command` to run a command.[/bold]")
|
|
@@ -1066,13 +1108,21 @@ def plan(
|
|
|
1066
1108
|
project_paths.workspace_root,
|
|
1067
1109
|
read_shipit_subdir(shipit_file),
|
|
1068
1110
|
)
|
|
1111
|
+
shipit_dir = default_shipit_dir(project_paths)
|
|
1069
1112
|
|
|
1070
1113
|
if docker or docker_client:
|
|
1071
1114
|
build_backend: BuildBackend = DockerBuildBackend(
|
|
1072
|
-
project_paths.workspace_root,
|
|
1115
|
+
project_paths.workspace_root,
|
|
1116
|
+
ASSETS_PATH,
|
|
1117
|
+
docker_client,
|
|
1118
|
+
shipit_dir=shipit_dir,
|
|
1073
1119
|
)
|
|
1074
1120
|
else:
|
|
1075
|
-
build_backend = LocalBuildBackend(
|
|
1121
|
+
build_backend = LocalBuildBackend(
|
|
1122
|
+
project_paths.workspace_root,
|
|
1123
|
+
ASSETS_PATH,
|
|
1124
|
+
shipit_dir=shipit_dir,
|
|
1125
|
+
)
|
|
1076
1126
|
if wasmer:
|
|
1077
1127
|
runner: Runner = WasmerRunner(
|
|
1078
1128
|
build_backend,
|
|
@@ -1080,9 +1130,14 @@ def plan(
|
|
|
1080
1130
|
registry=wasmer_registry,
|
|
1081
1131
|
token=wasmer_token,
|
|
1082
1132
|
bin=wasmer_bin,
|
|
1133
|
+
shipit_dir=shipit_dir,
|
|
1083
1134
|
)
|
|
1084
1135
|
else:
|
|
1085
|
-
runner = LocalRunner(
|
|
1136
|
+
runner = LocalRunner(
|
|
1137
|
+
build_backend,
|
|
1138
|
+
project_paths.workspace_root,
|
|
1139
|
+
shipit_dir=shipit_dir,
|
|
1140
|
+
)
|
|
1086
1141
|
|
|
1087
1142
|
base_config = Config()
|
|
1088
1143
|
base_config.commands.enrich_from_path(project_paths.app_path)
|
|
@@ -1244,6 +1299,7 @@ def build(
|
|
|
1244
1299
|
path,
|
|
1245
1300
|
read_shipit_subdir(shipit_file),
|
|
1246
1301
|
)
|
|
1302
|
+
shipit_dir = default_shipit_dir(project_paths)
|
|
1247
1303
|
|
|
1248
1304
|
if docker or docker_client:
|
|
1249
1305
|
build_backend: BuildBackend = DockerBuildBackend(
|
|
@@ -1251,9 +1307,14 @@ def build(
|
|
|
1251
1307
|
ASSETS_PATH,
|
|
1252
1308
|
docker_client,
|
|
1253
1309
|
docker_opts=docker_opts,
|
|
1310
|
+
shipit_dir=shipit_dir,
|
|
1254
1311
|
)
|
|
1255
1312
|
else:
|
|
1256
|
-
build_backend = LocalBuildBackend(
|
|
1313
|
+
build_backend = LocalBuildBackend(
|
|
1314
|
+
project_paths.workspace_root,
|
|
1315
|
+
ASSETS_PATH,
|
|
1316
|
+
shipit_dir=shipit_dir,
|
|
1317
|
+
)
|
|
1257
1318
|
if wasmer:
|
|
1258
1319
|
runner: Runner = WasmerRunner(
|
|
1259
1320
|
build_backend,
|
|
@@ -1261,9 +1322,14 @@ def build(
|
|
|
1261
1322
|
registry=wasmer_registry,
|
|
1262
1323
|
token=wasmer_token,
|
|
1263
1324
|
bin=wasmer_bin,
|
|
1325
|
+
shipit_dir=shipit_dir,
|
|
1264
1326
|
)
|
|
1265
1327
|
else:
|
|
1266
|
-
runner = LocalRunner(
|
|
1328
|
+
runner = LocalRunner(
|
|
1329
|
+
build_backend,
|
|
1330
|
+
project_paths.workspace_root,
|
|
1331
|
+
shipit_dir=shipit_dir,
|
|
1332
|
+
)
|
|
1267
1333
|
|
|
1268
1334
|
base_config = Config()
|
|
1269
1335
|
base_config.commands.enrich_from_path(project_paths.app_path)
|
|
@@ -1344,7 +1410,7 @@ def build(
|
|
|
1344
1410
|
|
|
1345
1411
|
# Build and serve
|
|
1346
1412
|
build_backend.build(serve.name, env, serve.mounts or [], build_steps)
|
|
1347
|
-
build_volumes(project_paths.workspace_root, serve)
|
|
1413
|
+
build_volumes(project_paths.workspace_root, serve, shipit_dir=shipit_dir)
|
|
1348
1414
|
runner.build(serve)
|
|
1349
1415
|
if serve.prepare and not skip_prepare:
|
|
1350
1416
|
console.print("\n[bold]Running prepare step[/bold]")
|
|
@@ -1390,9 +1456,10 @@ def run_serve_commands(
|
|
|
1390
1456
|
commands: List[str],
|
|
1391
1457
|
volume_specs: Optional[List[str]] = None,
|
|
1392
1458
|
env: Optional[Dict[str, str]] = None,
|
|
1459
|
+
shipit_dir: Optional[Path] = None,
|
|
1393
1460
|
) -> None:
|
|
1394
1461
|
volume_mappings = merge_volume_mappings(
|
|
1395
|
-
load_volume_mappings(path),
|
|
1462
|
+
load_volume_mappings(path, shipit_dir=shipit_dir),
|
|
1396
1463
|
parse_cli_volume_mappings(volume_specs),
|
|
1397
1464
|
)
|
|
1398
1465
|
for command in commands:
|
|
@@ -18,10 +18,16 @@ if TYPE_CHECKING:
|
|
|
18
18
|
|
|
19
19
|
|
|
20
20
|
class LocalRunner:
|
|
21
|
-
def __init__(
|
|
21
|
+
def __init__(
|
|
22
|
+
self,
|
|
23
|
+
build_backend: BuildBackend,
|
|
24
|
+
src_dir: Path,
|
|
25
|
+
shipit_dir: Optional[Path] = None,
|
|
26
|
+
) -> None:
|
|
22
27
|
self.build_backend = build_backend
|
|
23
28
|
self.src_dir = src_dir
|
|
24
|
-
self.
|
|
29
|
+
self.shipit_dir = shipit_dir or self.src_dir / ".shipit"
|
|
30
|
+
self.runner_path = self.shipit_dir / "runner" / "local"
|
|
25
31
|
self.serve_bin_path = self.runner_path / "bin"
|
|
26
32
|
self.prepare_bash_script = self.runner_path / "prepare" / "prepare.sh"
|
|
27
33
|
|
|
@@ -167,28 +167,28 @@ class WasmerRunner:
|
|
|
167
167
|
},
|
|
168
168
|
"phpix": {
|
|
169
169
|
"dependencies": {
|
|
170
|
-
"latest": "phpix/phpix-83-32bit@=0.2.0
|
|
171
|
-
"8.3": "phpix/phpix-83-32bit@=0.2.0
|
|
172
|
-
"8.3.29": "phpix/phpix-83-32bit@=0.2.0
|
|
173
|
-
"8.2": "phpix/phpix-82-32bit@=0.2.0
|
|
174
|
-
"8.1": "phpix/phpix-81-32bit@=0.2.0
|
|
170
|
+
"latest": "phpix/phpix-83-32bit@=0.2.0",
|
|
171
|
+
"8.3": "phpix/phpix-83-32bit@=0.2.0",
|
|
172
|
+
"8.3.29": "phpix/phpix-83-32bit@=0.2.0",
|
|
173
|
+
"8.2": "phpix/phpix-82-32bit@=0.2.0",
|
|
174
|
+
"8.1": "phpix/phpix-81-32bit@=0.2.0",
|
|
175
175
|
"7.4": "php/php-32@=7.4.3301", # Note, we don't have PHPix + PHP 7.4 and never will
|
|
176
176
|
},
|
|
177
177
|
"architecture_dependencies": {
|
|
178
178
|
"64-bit": {
|
|
179
|
-
"latest": "phpix/phpix-83-64bit@=0.2.0
|
|
180
|
-
"8.3": "phpix/phpix-83-64bit@=0.2.0
|
|
181
|
-
"8.3.29": "phpix/phpix-83-64bit@=0.2.0
|
|
182
|
-
"8.2": "phpix/phpix-82-64bit@=0.2.0
|
|
183
|
-
"8.1": "phpix/phpix-81-64bit@=0.2.0
|
|
179
|
+
"latest": "phpix/phpix-83-64bit@=0.2.0",
|
|
180
|
+
"8.3": "phpix/phpix-83-64bit@=0.2.0",
|
|
181
|
+
"8.3.29": "phpix/phpix-83-64bit@=0.2.0",
|
|
182
|
+
"8.2": "phpix/phpix-82-64bit@=0.2.0",
|
|
183
|
+
"8.1": "phpix/phpix-81-64bit@=0.2.0",
|
|
184
184
|
"7.4": "php/php-64@=7.4.3301",
|
|
185
185
|
},
|
|
186
186
|
"32-bit": {
|
|
187
|
-
"latest": "phpix/phpix-83-32bit@=0.2.0
|
|
188
|
-
"8.3": "phpix/phpix-83-32bit@=0.2.0
|
|
189
|
-
"8.3.29": "phpix/phpix-83-32bit@=0.2.0
|
|
190
|
-
"8.2": "phpix/phpix-82-32bit@=0.2.0
|
|
191
|
-
"8.1": "phpix/phpix-81-32bit@=0.2.0
|
|
187
|
+
"latest": "phpix/phpix-83-32bit@=0.2.0",
|
|
188
|
+
"8.3": "phpix/phpix-83-32bit@=0.2.0",
|
|
189
|
+
"8.3.29": "phpix/phpix-83-32bit@=0.2.0",
|
|
190
|
+
"8.2": "phpix/phpix-82-32bit@=0.2.0",
|
|
191
|
+
"8.1": "phpix/phpix-81-32bit@=0.2.0",
|
|
192
192
|
"7.4": "php/php-32@=7.4.3301",
|
|
193
193
|
},
|
|
194
194
|
},
|
|
@@ -224,10 +224,12 @@ class WasmerRunner:
|
|
|
224
224
|
registry: Optional[str] = None,
|
|
225
225
|
token: Optional[str] = None,
|
|
226
226
|
bin: Optional[str] = None,
|
|
227
|
+
shipit_dir: Optional[Path] = None,
|
|
227
228
|
) -> None:
|
|
228
229
|
self.build_backend = build_backend
|
|
229
230
|
self.src_dir = src_dir
|
|
230
|
-
self.
|
|
231
|
+
self.shipit_dir = shipit_dir or self.src_dir / ".shipit"
|
|
232
|
+
self.wasmer_dir_path = self.shipit_dir / "wasmer"
|
|
231
233
|
self.wasmer_registry = registry
|
|
232
234
|
self.wasmer_token = token
|
|
233
235
|
self.bin = bin or "wasmer"
|
|
@@ -342,7 +344,7 @@ class WasmerRunner:
|
|
|
342
344
|
self.run_serve_command(
|
|
343
345
|
"bash /prepare/prepare.sh",
|
|
344
346
|
volume_mappings={
|
|
345
|
-
**load_volume_mappings(self.src_dir),
|
|
347
|
+
**load_volume_mappings(self.src_dir, shipit_dir=self.shipit_dir),
|
|
346
348
|
"/prepare": prepare_dir,
|
|
347
349
|
},
|
|
348
350
|
)
|
|
@@ -1,22 +1,29 @@
|
|
|
1
1
|
import json
|
|
2
2
|
import shutil
|
|
3
3
|
from pathlib import Path
|
|
4
|
-
from typing import Dict
|
|
4
|
+
from typing import Dict, Optional
|
|
5
5
|
|
|
6
6
|
from shipit.builders.base import BuildBackend
|
|
7
7
|
from shipit.shipit_types import Serve, Volume
|
|
8
8
|
|
|
9
9
|
|
|
10
|
-
def get_volumes_dir(src_dir: Path) -> Path:
|
|
11
|
-
return src_dir / ".shipit" / "volumes"
|
|
10
|
+
def get_volumes_dir(src_dir: Path, shipit_dir: Optional[Path] = None) -> Path:
|
|
11
|
+
return (shipit_dir or src_dir / ".shipit") / "volumes"
|
|
12
12
|
|
|
13
13
|
|
|
14
|
-
def get_volume_mappings_path(
|
|
15
|
-
|
|
14
|
+
def get_volume_mappings_path(
|
|
15
|
+
src_dir: Path,
|
|
16
|
+
shipit_dir: Optional[Path] = None,
|
|
17
|
+
) -> Path:
|
|
18
|
+
return get_volumes_dir(src_dir, shipit_dir=shipit_dir) / "mappings.json"
|
|
16
19
|
|
|
17
20
|
|
|
18
|
-
def build_volumes(
|
|
19
|
-
|
|
21
|
+
def build_volumes(
|
|
22
|
+
src_dir: Path,
|
|
23
|
+
serve: Serve,
|
|
24
|
+
shipit_dir: Optional[Path] = None,
|
|
25
|
+
) -> Dict[str, str]:
|
|
26
|
+
volumes_dir = get_volumes_dir(src_dir, shipit_dir=shipit_dir)
|
|
20
27
|
volumes_dir.mkdir(parents=True, exist_ok=True)
|
|
21
28
|
|
|
22
29
|
mappings = {
|
|
@@ -25,17 +32,20 @@ def build_volumes(src_dir: Path, serve: Serve) -> Dict[str, str]:
|
|
|
25
32
|
}
|
|
26
33
|
for volume in serve.volumes or []:
|
|
27
34
|
volume.path.mkdir(parents=True, exist_ok=True)
|
|
28
|
-
if _should_link_local_volume(src_dir, volume):
|
|
35
|
+
if _should_link_local_volume(src_dir, volume, shipit_dir=shipit_dir):
|
|
29
36
|
_link_local_volume(volume)
|
|
30
37
|
|
|
31
|
-
get_volume_mappings_path(src_dir).write_text(
|
|
38
|
+
get_volume_mappings_path(src_dir, shipit_dir=shipit_dir).write_text(
|
|
32
39
|
json.dumps(mappings, indent=2, sort_keys=True) + "\n"
|
|
33
40
|
)
|
|
34
41
|
return mappings
|
|
35
42
|
|
|
36
43
|
|
|
37
|
-
def load_volume_mappings(
|
|
38
|
-
|
|
44
|
+
def load_volume_mappings(
|
|
45
|
+
src_dir: Path,
|
|
46
|
+
shipit_dir: Optional[Path] = None,
|
|
47
|
+
) -> Dict[str, str]:
|
|
48
|
+
mappings_path = get_volume_mappings_path(src_dir, shipit_dir=shipit_dir)
|
|
39
49
|
if not mappings_path.is_file():
|
|
40
50
|
return {}
|
|
41
51
|
|
|
@@ -98,8 +108,12 @@ def _parse_volume_spec(spec: str) -> tuple[str, str]:
|
|
|
98
108
|
return name, guest_path
|
|
99
109
|
|
|
100
110
|
|
|
101
|
-
def _should_link_local_volume(
|
|
102
|
-
|
|
111
|
+
def _should_link_local_volume(
|
|
112
|
+
src_dir: Path,
|
|
113
|
+
volume: Volume,
|
|
114
|
+
shipit_dir: Optional[Path] = None,
|
|
115
|
+
) -> bool:
|
|
116
|
+
shipit_dir = (shipit_dir or src_dir / ".shipit").absolute()
|
|
103
117
|
return volume.serve_path.is_absolute() and volume.serve_path.is_relative_to(
|
|
104
118
|
shipit_dir
|
|
105
119
|
)
|
|
@@ -52,20 +52,26 @@ def _patch_fake_build_runner(monkeypatch: pytest.MonkeyPatch):
|
|
|
52
52
|
runner_instances = []
|
|
53
53
|
|
|
54
54
|
class FakeBuildBackend:
|
|
55
|
-
def __init__(
|
|
55
|
+
def __init__(
|
|
56
|
+
self,
|
|
57
|
+
src_dir: Path,
|
|
58
|
+
assets_path: Path,
|
|
59
|
+
shipit_dir: Path | None = None,
|
|
60
|
+
) -> None:
|
|
56
61
|
self.src_dir = src_dir
|
|
57
62
|
self.assets_path = assets_path
|
|
63
|
+
self.shipit_dir = shipit_dir or src_dir / ".shipit"
|
|
58
64
|
self.runtime_path = None
|
|
59
65
|
build_backend_instances.append(self)
|
|
60
66
|
|
|
61
67
|
def get_build_mount_path(self, name: str) -> Path:
|
|
62
|
-
return self.
|
|
68
|
+
return self.shipit_dir / "fake" / "build" / name
|
|
63
69
|
|
|
64
70
|
def get_artifact_mount_path(self, name: str) -> Path:
|
|
65
71
|
return self.get_build_mount_path(name)
|
|
66
72
|
|
|
67
73
|
def get_volume_path(self, name: str) -> Path:
|
|
68
|
-
return self.
|
|
74
|
+
return self.shipit_dir / "volumes" / name
|
|
69
75
|
|
|
70
76
|
def get_runtime_path(self) -> str | None:
|
|
71
77
|
return self.runtime_path
|
|
@@ -79,9 +85,16 @@ def _patch_fake_build_runner(monkeypatch: pytest.MonkeyPatch):
|
|
|
79
85
|
}
|
|
80
86
|
|
|
81
87
|
class FakeRunner:
|
|
82
|
-
def __init__(
|
|
88
|
+
def __init__(
|
|
89
|
+
self,
|
|
90
|
+
build_backend,
|
|
91
|
+
src_dir: Path,
|
|
92
|
+
shipit_dir: Path | None = None,
|
|
93
|
+
) -> None:
|
|
83
94
|
self.build_backend = build_backend
|
|
84
95
|
self.src_dir = src_dir
|
|
96
|
+
self.shipit_dir = shipit_dir or src_dir / ".shipit"
|
|
97
|
+
self.calls = []
|
|
85
98
|
runner_instances.append(self)
|
|
86
99
|
|
|
87
100
|
def prepare_config(self, provider_config):
|
|
@@ -99,6 +112,23 @@ def _patch_fake_build_runner(monkeypatch: pytest.MonkeyPatch):
|
|
|
99
112
|
def prepare(self, env, prepare) -> None:
|
|
100
113
|
self.prepare_args = (env, prepare)
|
|
101
114
|
|
|
115
|
+
def has_serve_command(self, command: str) -> bool:
|
|
116
|
+
return True
|
|
117
|
+
|
|
118
|
+
def run_serve_command(
|
|
119
|
+
self,
|
|
120
|
+
command: str,
|
|
121
|
+
volume_mappings=None,
|
|
122
|
+
env=None,
|
|
123
|
+
) -> None:
|
|
124
|
+
self.calls.append(
|
|
125
|
+
{
|
|
126
|
+
"command": command,
|
|
127
|
+
"volume_mappings": volume_mappings,
|
|
128
|
+
"env": env,
|
|
129
|
+
}
|
|
130
|
+
)
|
|
131
|
+
|
|
102
132
|
monkeypatch.setattr(cli, "LocalBuildBackend", FakeBuildBackend)
|
|
103
133
|
monkeypatch.setattr(cli, "LocalRunner", FakeRunner)
|
|
104
134
|
return build_backend_instances, runner_instances
|
|
@@ -430,6 +460,12 @@ def test_build_recovers_subdir_from_generated_shipit(
|
|
|
430
460
|
|
|
431
461
|
assert result.exit_code == 0, result.output
|
|
432
462
|
assert build_backend_instances[-1].src_dir == tmp_path.resolve()
|
|
463
|
+
assert build_backend_instances[-1].shipit_dir == (
|
|
464
|
+
tmp_path.resolve() / ".shipit" / "apps-site"
|
|
465
|
+
)
|
|
466
|
+
assert runner_instances[-1].shipit_dir == (
|
|
467
|
+
tmp_path.resolve() / ".shipit" / "apps-site"
|
|
468
|
+
)
|
|
433
469
|
serve = runner_instances[-1].serve
|
|
434
470
|
assert serve.cwd.endswith("/app")
|
|
435
471
|
install_step = next(
|
|
@@ -463,9 +499,107 @@ def test_build_subdir_uses_app_specific_shipit_by_default(
|
|
|
463
499
|
|
|
464
500
|
assert result.exit_code == 0, result.output
|
|
465
501
|
assert build_backend_instances[-1].src_dir == tmp_path.resolve()
|
|
502
|
+
assert build_backend_instances[-1].shipit_dir == (
|
|
503
|
+
tmp_path.resolve() / ".shipit" / "apps-site"
|
|
504
|
+
)
|
|
505
|
+
assert runner_instances[-1].shipit_dir == (
|
|
506
|
+
tmp_path.resolve() / ".shipit" / "apps-site"
|
|
507
|
+
)
|
|
466
508
|
assert runner_instances[-1].serve.cwd.endswith("/app")
|
|
467
509
|
|
|
468
510
|
|
|
511
|
+
def test_run_subdir_uses_app_specific_shipit_dir(
|
|
512
|
+
tmp_path: Path,
|
|
513
|
+
monkeypatch: pytest.MonkeyPatch,
|
|
514
|
+
) -> None:
|
|
515
|
+
_write_node_workspace(tmp_path)
|
|
516
|
+
build_backend_instances, runner_instances = _patch_fake_build_runner(
|
|
517
|
+
monkeypatch
|
|
518
|
+
)
|
|
519
|
+
|
|
520
|
+
result = runner.invoke(
|
|
521
|
+
cli.app,
|
|
522
|
+
["run", str(tmp_path), "--subdir=apps/site", "--start"],
|
|
523
|
+
)
|
|
524
|
+
|
|
525
|
+
assert result.exit_code == 0, result.output
|
|
526
|
+
assert build_backend_instances[-1].shipit_dir == (
|
|
527
|
+
tmp_path.resolve() / ".shipit" / "apps-site"
|
|
528
|
+
)
|
|
529
|
+
assert runner_instances[-1].shipit_dir == (
|
|
530
|
+
tmp_path.resolve() / ".shipit" / "apps-site"
|
|
531
|
+
)
|
|
532
|
+
assert runner_instances[-1].calls == [
|
|
533
|
+
{
|
|
534
|
+
"command": "start",
|
|
535
|
+
"volume_mappings": {},
|
|
536
|
+
"env": {"PORT": "8080"},
|
|
537
|
+
}
|
|
538
|
+
]
|
|
539
|
+
|
|
540
|
+
|
|
541
|
+
def test_deploy_subdir_uses_app_specific_shipit_dir(
|
|
542
|
+
tmp_path: Path,
|
|
543
|
+
monkeypatch: pytest.MonkeyPatch,
|
|
544
|
+
) -> None:
|
|
545
|
+
_write_node_workspace(tmp_path)
|
|
546
|
+
build_backend_instances, _runner_instances = _patch_fake_build_runner(
|
|
547
|
+
monkeypatch
|
|
548
|
+
)
|
|
549
|
+
wasmer_runner_instances = []
|
|
550
|
+
|
|
551
|
+
class FakeWasmerRunner:
|
|
552
|
+
def __init__(
|
|
553
|
+
self,
|
|
554
|
+
build_backend,
|
|
555
|
+
src_dir: Path,
|
|
556
|
+
registry=None,
|
|
557
|
+
token=None,
|
|
558
|
+
bin=None,
|
|
559
|
+
shipit_dir: Path | None = None,
|
|
560
|
+
) -> None:
|
|
561
|
+
self.build_backend = build_backend
|
|
562
|
+
self.src_dir = src_dir
|
|
563
|
+
self.registry = registry
|
|
564
|
+
self.token = token
|
|
565
|
+
self.bin = bin
|
|
566
|
+
self.shipit_dir = shipit_dir or src_dir / ".shipit"
|
|
567
|
+
self.deploy_calls = []
|
|
568
|
+
wasmer_runner_instances.append(self)
|
|
569
|
+
|
|
570
|
+
def deploy_config(self, config_path: Path) -> None:
|
|
571
|
+
self.deploy_config_path = config_path
|
|
572
|
+
|
|
573
|
+
def deploy(self, app_owner=None, app_name=None) -> None:
|
|
574
|
+
self.deploy_calls.append(
|
|
575
|
+
{
|
|
576
|
+
"app_owner": app_owner,
|
|
577
|
+
"app_name": app_name,
|
|
578
|
+
}
|
|
579
|
+
)
|
|
580
|
+
|
|
581
|
+
monkeypatch.setattr(cli, "WasmerRunner", FakeWasmerRunner)
|
|
582
|
+
|
|
583
|
+
result = runner.invoke(
|
|
584
|
+
cli.app,
|
|
585
|
+
["deploy", str(tmp_path), "--subdir=apps/site"],
|
|
586
|
+
)
|
|
587
|
+
|
|
588
|
+
assert result.exit_code == 0, result.output
|
|
589
|
+
assert build_backend_instances[-1].shipit_dir == (
|
|
590
|
+
tmp_path.resolve() / ".shipit" / "apps-site"
|
|
591
|
+
)
|
|
592
|
+
assert wasmer_runner_instances[-1].shipit_dir == (
|
|
593
|
+
tmp_path.resolve() / ".shipit" / "apps-site"
|
|
594
|
+
)
|
|
595
|
+
assert wasmer_runner_instances[-1].deploy_calls == [
|
|
596
|
+
{
|
|
597
|
+
"app_owner": None,
|
|
598
|
+
"app_name": None,
|
|
599
|
+
}
|
|
600
|
+
]
|
|
601
|
+
|
|
602
|
+
|
|
469
603
|
def test_plan_accepts_subdir_and_reports_app_provider(tmp_path: Path) -> None:
|
|
470
604
|
_write_node_workspace(tmp_path)
|
|
471
605
|
|
|
@@ -537,6 +671,52 @@ def test_auto_passes_subdir_to_generate_and_build(
|
|
|
537
671
|
assert not (tmp_path / "Shipit").exists()
|
|
538
672
|
|
|
539
673
|
|
|
674
|
+
def test_auto_passes_subdir_to_run_and_deploy(
|
|
675
|
+
tmp_path: Path,
|
|
676
|
+
monkeypatch: pytest.MonkeyPatch,
|
|
677
|
+
) -> None:
|
|
678
|
+
_write_node_workspace(tmp_path)
|
|
679
|
+
calls = {}
|
|
680
|
+
|
|
681
|
+
def fake_generate(path: Path, **kwargs) -> None:
|
|
682
|
+
calls["generate"] = (path, kwargs)
|
|
683
|
+
out = kwargs["out"] or cli.default_shipit_path(
|
|
684
|
+
cli.resolve_project_paths(path, kwargs["subdir"])
|
|
685
|
+
)
|
|
686
|
+
out.write_text('app_subdir = "apps/site"\n')
|
|
687
|
+
|
|
688
|
+
def fake_build(path: Path, **kwargs) -> None:
|
|
689
|
+
calls["build"] = (path, kwargs)
|
|
690
|
+
|
|
691
|
+
def fake_run(path: Path, **kwargs) -> None:
|
|
692
|
+
calls["run"] = (path, kwargs)
|
|
693
|
+
|
|
694
|
+
def fake_deploy(path: Path, **kwargs) -> None:
|
|
695
|
+
calls["deploy"] = (path, kwargs)
|
|
696
|
+
|
|
697
|
+
monkeypatch.setattr(cli, "generate", fake_generate)
|
|
698
|
+
monkeypatch.setattr(cli, "build", fake_build)
|
|
699
|
+
monkeypatch.setattr(cli, "run", fake_run)
|
|
700
|
+
monkeypatch.setattr(cli, "deploy", fake_deploy)
|
|
701
|
+
|
|
702
|
+
result = runner.invoke(
|
|
703
|
+
cli.app,
|
|
704
|
+
[
|
|
705
|
+
"auto",
|
|
706
|
+
str(tmp_path),
|
|
707
|
+
"--subdir=apps/site",
|
|
708
|
+
"--start",
|
|
709
|
+
"--wasmer-deploy",
|
|
710
|
+
],
|
|
711
|
+
)
|
|
712
|
+
|
|
713
|
+
assert result.exit_code == 0, result.output
|
|
714
|
+
assert calls["run"][0] == tmp_path.resolve()
|
|
715
|
+
assert calls["run"][1]["subdir"] == Path("apps/site")
|
|
716
|
+
assert calls["deploy"][0] == tmp_path.resolve()
|
|
717
|
+
assert calls["deploy"][1]["subdir"] == Path("apps/site")
|
|
718
|
+
|
|
719
|
+
|
|
540
720
|
@pytest.mark.parametrize(
|
|
541
721
|
"subdir",
|
|
542
722
|
[
|
|
@@ -89,6 +89,43 @@ def test_build_volumes_links_runtime_volume_to_host_directory(
|
|
|
89
89
|
assert load_volume_mappings(tmp_path) == {"wp-content": str(target)}
|
|
90
90
|
|
|
91
91
|
|
|
92
|
+
def test_build_volumes_can_use_namespaced_shipit_directory(
|
|
93
|
+
tmp_path: Path,
|
|
94
|
+
) -> None:
|
|
95
|
+
src_dir = tmp_path / "src"
|
|
96
|
+
src_dir.mkdir()
|
|
97
|
+
assets_path = tmp_path / "assets"
|
|
98
|
+
assets_path.mkdir()
|
|
99
|
+
shipit_dir = src_dir / ".shipit" / "apps-site"
|
|
100
|
+
build_backend = LocalBuildBackend(src_dir, assets_path, shipit_dir=shipit_dir)
|
|
101
|
+
|
|
102
|
+
target = build_backend.get_artifact_mount_path("app") / "wp-content"
|
|
103
|
+
target.mkdir(parents=True, exist_ok=True)
|
|
104
|
+
|
|
105
|
+
volume = Volume(
|
|
106
|
+
name="wp-content",
|
|
107
|
+
path=build_backend.get_volume_path("wp-content"),
|
|
108
|
+
serve_path=target,
|
|
109
|
+
)
|
|
110
|
+
serve = Serve(
|
|
111
|
+
name="wordpress",
|
|
112
|
+
provider="wordpress",
|
|
113
|
+
build=[],
|
|
114
|
+
deps=[],
|
|
115
|
+
commands={"start": "php -S localhost:8080 -t /app"},
|
|
116
|
+
volumes=[volume],
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
mappings = build_volumes(src_dir, serve, shipit_dir=shipit_dir)
|
|
120
|
+
|
|
121
|
+
assert volume.path == shipit_dir / "volumes" / "wp-content"
|
|
122
|
+
assert mappings == {"wp-content": str(target)}
|
|
123
|
+
assert load_volume_mappings(src_dir, shipit_dir=shipit_dir) == {
|
|
124
|
+
"wp-content": str(target)
|
|
125
|
+
}
|
|
126
|
+
assert not (src_dir / ".shipit" / "volumes" / "mappings.json").exists()
|
|
127
|
+
|
|
128
|
+
|
|
92
129
|
def test_wasmer_runner_passes_volume_paths_into_wasmer_run(
|
|
93
130
|
tmp_path: Path,
|
|
94
131
|
monkeypatch: pytest.MonkeyPatch,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|