diff --git a/app/Jobs/ApplicationDeploymentJob.php b/app/Jobs/ApplicationDeploymentJob.php
index 473cbc679..0163ae013 100644
--- a/app/Jobs/ApplicationDeploymentJob.php
+++ b/app/Jobs/ApplicationDeploymentJob.php
@@ -157,7 +157,7 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
private ?string $coolify_variables = null;
- private bool $preserveRepository = true;
+ private bool $preserveRepository = false;
public $tries = 1;
@@ -480,6 +480,7 @@ private function deploy_docker_compose_buildpack()
}
// Start compose file
+ $server_workdir = $this->application->workdir();
if ($this->application->settings->is_raw_compose_deployment_enabled) {
if ($this->docker_compose_custom_start_command) {
$this->write_deployment_configurations();
@@ -488,7 +489,6 @@ private function deploy_docker_compose_buildpack()
);
} else {
$this->write_deployment_configurations();
- $server_workdir = $this->application->workdir();
$this->docker_compose_location = '/docker-compose.yaml';
$command = "{$this->coolify_variables} docker compose";
@@ -508,15 +508,26 @@ private function deploy_docker_compose_buildpack()
);
} else {
$command = "{$this->coolify_variables} docker compose";
- if ($this->env_filename) {
- $command .= " --env-file {$this->workdir}/{$this->env_filename}";
- }
- $command .= " --project-name {$this->application->uuid} --project-directory {$this->workdir} -f {$this->workdir}{$this->docker_compose_location} up -d";
+ if ($this->preserveRepository) {
+ if ($this->env_filename) {
+ $command .= " --env-file {$server_workdir}/{$this->env_filename}";
+ }
+ $command .= " --project-name {$this->application->uuid} --project-directory {$server_workdir} -f {$server_workdir}{$this->docker_compose_location} up -d";
+ $this->write_deployment_configurations();
+
+ $this->execute_remote_command(
+ ['command' => $command, 'hidden' => true],
+ );
+ } else {
+ if ($this->env_filename) {
+ $command .= " --env-file {$this->workdir}/{$this->env_filename}";
+ }
+ $command .= " --project-name {$this->application->uuid} --project-directory {$this->workdir} -f {$this->workdir}{$this->docker_compose_location} up -d";
+ $this->execute_remote_command(
+ [executeInDocker($this->deployment_uuid, $command), 'hidden' => true],
+ );
+ }
- $this->write_deployment_configurations();
- $this->execute_remote_command(
- [executeInDocker($this->deployment_uuid, $command), 'hidden' => true],
- );
}
}
@@ -619,6 +630,11 @@ private function write_deployment_configurations()
],
);
}
+ $this->application->fileStorages()->each(function ($fileStorage) {
+ if (! $fileStorage->is_based_on_git && ! $fileStorage->is_directory) {
+ $fileStorage->saveStorageOnServer();
+ }
+ });
if ($this->use_build_server) {
$this->server = $this->build_server;
}
diff --git a/app/Livewire/Project/Application/General.php b/app/Livewire/Project/Application/General.php
index 9b4c074c1..cf5f0979a 100644
--- a/app/Livewire/Project/Application/General.php
+++ b/app/Livewire/Project/Application/General.php
@@ -3,7 +3,6 @@
namespace App\Livewire\Project\Application;
use App\Models\Application;
-use App\Models\LocalFileVolume;
use Illuminate\Support\Collection;
use Livewire\Component;
use Visus\Cuid2\Cuid2;
@@ -30,6 +29,8 @@ class General extends Component
public ?string $ports_exposes = null;
+ public bool $is_preserve_repository_enabled = false;
+
public bool $is_container_label_escape_enabled = true;
public $customLabels;
@@ -145,6 +146,7 @@ public function mount()
}
$this->parsedServiceDomains = $this->application->docker_compose_domains ? json_decode($this->application->docker_compose_domains, true) : [];
$this->ports_exposes = $this->application->ports_exposes;
+ $this->is_preserve_repository_enabled = $this->application->settings->is_preserve_repository_enabled;
$this->is_container_label_escape_enabled = $this->application->settings->is_container_label_escape_enabled;
$this->customLabels = $this->application->parseContainerLabels();
if (! $this->customLabels && $this->application->destination->server->proxyType() !== 'NONE' && ! $this->application->settings->is_container_label_readonly_enabled) {
@@ -168,9 +170,21 @@ public function instantSave()
$this->application->settings->save();
$this->dispatch('success', 'Settings saved.');
$this->application->refresh();
+
+ // If port_exposes changed, reset default labels
if ($this->ports_exposes !== $this->application->ports_exposes || $this->is_container_label_escape_enabled !== $this->application->settings->is_container_label_escape_enabled) {
$this->resetDefaultLabels(false);
}
+ if ($this->is_preserve_repository_enabled !== $this->application->settings->is_preserve_repository_enabled) {
+ if ($this->application->settings->is_preserve_repository_enabled === false) {
+ $this->application->fileStorages->each(function ($storage) {
+ $storage->is_based_on_git = $this->application->settings->is_preserve_repository_enabled;
+ $storage->save();
+ });
+ }
+
+ }
+
}
public function loadComposeFile($isInit = false)
@@ -191,32 +205,6 @@ public function loadComposeFile($isInit = false)
return;
}
$compose = $this->application->parseCompose();
- $services = data_get($compose, 'services');
- if ($services) {
- $volumes = collect($services)->map(function ($service) {
- return data_get($service, 'volumes');
- })->flatten()->filter(function ($volume) {
- return str($volume)->startsWith('/data/coolify');
- })->unique()->values();
- foreach ($volumes as $volume) {
- $source = str($volume)->before(':');
- $target = str($volume)->after(':')->beforeLast(':');
-
- LocalFileVolume::updateOrCreate(
- [
- 'mount_path' => $target,
- 'resource_id' => $this->application->id,
- 'resource_type' => get_class($this->application),
- ],
- [
- 'fs_path' => $source,
- 'mount_path' => $target,
- 'resource_id' => $this->application->id,
- 'resource_type' => get_class($this->application),
- ]
- );
- }
- }
$this->dispatch('success', 'Docker compose file loaded.');
$this->dispatch('compose_loaded');
$this->dispatch('refreshStorages');
diff --git a/app/Livewire/Project/Service/FileStorage.php b/app/Livewire/Project/Service/FileStorage.php
index 2d9c95daa..438383a8d 100644
--- a/app/Livewire/Project/Service/FileStorage.php
+++ b/app/Livewire/Project/Service/FileStorage.php
@@ -33,6 +33,7 @@ class FileStorage extends Component
'fileStorage.fs_path' => 'required',
'fileStorage.mount_path' => 'required',
'fileStorage.content' => 'nullable',
+ 'fileStorage.is_based_on_git' => 'required|boolean',
];
public function mount()
@@ -45,6 +46,7 @@ public function mount()
$this->workdir = null;
$this->fs_path = $this->fileStorage->fs_path;
}
+ $this->fileStorage->loadStorageOnServer();
}
public function convertToDirectory()
@@ -68,6 +70,9 @@ public function convertToFile()
$this->fileStorage->deleteStorageOnServer();
$this->fileStorage->is_directory = false;
$this->fileStorage->content = null;
+ if (data_get($this->resource, 'settings.is_preserve_repository_enabled')) {
+ $this->fileStorage->is_based_on_git = true;
+ }
$this->fileStorage->save();
$this->fileStorage->saveStorageOnServer();
} catch (\Throwable $e) {
diff --git a/app/Models/LocalFileVolume.php b/app/Models/LocalFileVolume.php
index a436f5797..0fe48c5c4 100644
--- a/app/Models/LocalFileVolume.php
+++ b/app/Models/LocalFileVolume.php
@@ -24,6 +24,32 @@ public function service()
return $this->morphTo('resource');
}
+ public function loadStorageOnServer()
+ {
+ $this->load(['service']);
+ $isService = data_get($this->resource, 'service');
+ if ($isService) {
+ $workdir = $this->resource->service->workdir();
+ $server = $this->resource->service->server;
+ } else {
+ $workdir = $this->resource->workdir();
+ $server = $this->resource->destination->server;
+ }
+ $commands = collect([]);
+ $path = data_get_str($this, 'fs_path');
+ if ($path->startsWith('.')) {
+ $path = $path->after('.');
+ $path = $workdir.$path;
+ }
+ $isFile = instant_remote_process(["test -f $path && echo OK || echo NOK"], $server);
+ if ($isFile === 'OK') {
+ $content = instant_remote_process(["cat $path"], $server, false);
+ $this->content = $content;
+ $this->is_directory = false;
+ $this->save();
+ }
+ }
+
public function deleteStorageOnServer()
{
$isService = data_get($this->resource, 'service');
@@ -35,17 +61,20 @@ public function deleteStorageOnServer()
$server = $this->resource->destination->server;
}
$commands = collect([]);
- $fs_path = data_get($this, 'fs_path');
- $isFile = instant_remote_process(["test -f $fs_path && echo OK || echo NOK"], $server);
- $isDir = instant_remote_process(["test -d $fs_path && echo OK || echo NOK"], $server);
- if ($fs_path && $fs_path != '/' && $fs_path != '.' && $fs_path != '..') {
- ray($isFile, $isDir);
+ $path = data_get_str($this, 'fs_path');
+ if ($path->startsWith('.')) {
+ $path = $path->after('.');
+ $path = $workdir.$path;
+ }
+ $isFile = instant_remote_process(["test -f $path && echo OK || echo NOK"], $server);
+ $isDir = instant_remote_process(["test -d $path && echo OK || echo NOK"], $server);
+ if ($path && $path != '/' && $path != '.' && $path != '..') {
if ($isFile === 'OK') {
- $commands->push("rm -rf $fs_path > /dev/null 2>&1 || true");
+ $commands->push("rm -rf $path > /dev/null 2>&1 || true");
} elseif ($isDir === 'OK') {
- $commands->push("rm -rf $fs_path > /dev/null 2>&1 || true");
- $commands->push("rmdir $fs_path > /dev/null 2>&1 || true");
+ $commands->push("rm -rf $path > /dev/null 2>&1 || true");
+ $commands->push("rmdir $path > /dev/null 2>&1 || true");
}
}
if ($commands->count() > 0) {
@@ -55,6 +84,7 @@ public function deleteStorageOnServer()
public function saveStorageOnServer()
{
+ $this->load(['service']);
$isService = data_get($this->resource, 'service');
if ($isService) {
$workdir = $this->resource->service->workdir();
@@ -74,30 +104,36 @@ public function saveStorageOnServer()
$commands->push("mkdir -p $parent_dir > /dev/null 2>&1 || true");
}
}
- $fileVolume = $this;
- $path = str(data_get($fileVolume, 'fs_path'));
- $content = data_get($fileVolume, 'content');
+ $path = data_get_str($this, 'fs_path');
+ $content = data_get($this, 'content');
if ($path->startsWith('.')) {
$path = $path->after('.');
$path = $workdir.$path;
}
$isFile = instant_remote_process(["test -f $path && echo OK || echo NOK"], $server);
$isDir = instant_remote_process(["test -d $path && echo OK || echo NOK"], $server);
- if ($isFile == 'OK' && $fileVolume->is_directory) {
+ if ($isFile == 'OK' && $this->is_directory) {
$content = instant_remote_process(["cat $path"], $server, false);
- $fileVolume->is_directory = false;
- $fileVolume->content = $content;
- $fileVolume->save();
+ $this->is_directory = false;
+ $this->content = $content;
+ $this->save();
FileStorageChanged::dispatch(data_get($server, 'team_id'));
throw new \Exception('The following file is a file on the server, but you are trying to mark it as a directory. Please delete the file on the server or mark it as directory.');
- } elseif ($isDir == 'OK' && ! $fileVolume->is_directory) {
- $fileVolume->is_directory = true;
- $fileVolume->save();
- throw new \Exception('The following file is a directory on the server, but you are trying to mark it as a file.
Please delete the directory on the server or mark it as directory.');
+ } elseif ($isDir == 'OK' && ! $this->is_directory) {
+ if ($path == '/' || $path == '.' || $path == '..' || $path == '' || str($path)->isEmpty() || is_null($path)) {
+ $this->is_directory = true;
+ $this->save();
+ throw new \Exception('The following file is a directory on the server, but you are trying to mark it as a file.
Please delete the directory on the server or mark it as directory.');
+ }
+ instant_remote_process([
+ "rm -fr $path",
+ "touch $path",
+ ], $server, false);
+ FileStorageChanged::dispatch(data_get($server, 'team_id'));
}
- if ($isDir == 'NOK' && ! $fileVolume->is_directory) {
- $chmod = data_get($fileVolume, 'chmod');
- $chown = data_get($fileVolume, 'chown');
+ if ($isDir == 'NOK' && ! $this->is_directory) {
+ $chmod = data_get($this, 'chmod');
+ $chown = data_get($this, 'chown');
if ($content) {
$content = base64_encode($content);
$commands->push("echo '$content' | base64 -d | tee $path > /dev/null");
@@ -111,7 +147,7 @@ public function saveStorageOnServer()
if ($chmod) {
$commands->push("chmod $chmod $path");
}
- } elseif ($isDir == 'NOK' && $fileVolume->is_directory) {
+ } elseif ($isDir == 'NOK' && $this->is_directory) {
$commands->push("mkdir -p $path > /dev/null 2>&1 || true");
}
diff --git a/bootstrap/helpers/shared.php b/bootstrap/helpers/shared.php
index aae4fafd4..55ecf223c 100644
--- a/bootstrap/helpers/shared.php
+++ b/bootstrap/helpers/shared.php
@@ -794,7 +794,7 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
}
$topLevelVolumes = collect($tempTopLevelVolumes);
}
- $services = collect($services)->map(function ($service, $serviceName) use ($topLevelVolumes, $topLevelNetworks, $definedNetwork, $isNew, $generatedServiceFQDNS, $resource, $allServices) {
+ $services = collect($services)->map(function ($service, $serviceName) use ($topLevelNetworks, $definedNetwork, $isNew, $generatedServiceFQDNS, $resource, $allServices, $topLevelVolumes) {
// Workarounds for beta users.
if ($serviceName === 'registry') {
$tempServiceName = 'docker-registry';
@@ -963,102 +963,7 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
// Collect/create/update volumes
if ($serviceVolumes->count() > 0) {
- $serviceVolumes = $serviceVolumes->map(function ($volume) use ($savedService, $topLevelVolumes) {
- $type = null;
- $source = null;
- $target = null;
- $content = null;
- $isDirectory = false;
- if (is_string($volume)) {
- $source = str($volume)->before(':');
- $target = str($volume)->after(':')->beforeLast(':');
- if ($source->startsWith('./') || $source->startsWith('/') || $source->startsWith('~')) {
- $type = str('bind');
- // By default, we cannot determine if the bind is a directory or not, so we set it to directory
- $isDirectory = true;
- } else {
- $type = str('volume');
- }
- } elseif (is_array($volume)) {
- $type = data_get_str($volume, 'type');
- $source = data_get_str($volume, 'source');
- $target = data_get_str($volume, 'target');
- $content = data_get($volume, 'content');
- $isDirectory = (bool) data_get($volume, 'isDirectory', null) || (bool) data_get($volume, 'is_directory', null);
- $foundConfig = $savedService->fileStorages()->whereMountPath($target)->first();
- if ($foundConfig) {
- $contentNotNull = data_get($foundConfig, 'content');
- if ($contentNotNull) {
- $content = $contentNotNull;
- }
- $isDirectory = (bool) data_get($volume, 'isDirectory', null) || (bool) data_get($volume, 'is_directory', null);
- }
- if (is_null($isDirectory) && is_null($content)) {
- // if isDirectory is not set & content is also not set, we assume it is a directory
- ray('setting isDirectory to true');
- $isDirectory = true;
- }
- }
- if ($type?->value() === 'bind') {
- if ($source->value() === '/var/run/docker.sock') {
- return $volume;
- }
- if ($source->value() === '/tmp' || $source->value() === '/tmp/') {
- return $volume;
- }
- LocalFileVolume::updateOrCreate(
- [
- 'mount_path' => $target,
- 'resource_id' => $savedService->id,
- 'resource_type' => get_class($savedService),
- ],
- [
- 'fs_path' => $source,
- 'mount_path' => $target,
- 'content' => $content,
- 'is_directory' => $isDirectory,
- 'resource_id' => $savedService->id,
- 'resource_type' => get_class($savedService),
- ]
- );
- } elseif ($type->value() === 'volume') {
- if ($topLevelVolumes->has($source->value())) {
- $v = $topLevelVolumes->get($source->value());
- if (data_get($v, 'driver_opts.type') === 'cifs') {
- return $volume;
- }
- }
- $slugWithoutUuid = Str::slug($source, '-');
- $name = "{$savedService->service->uuid}_{$slugWithoutUuid}";
- if (is_string($volume)) {
- $source = str($volume)->before(':');
- $target = str($volume)->after(':')->beforeLast(':');
- $source = $name;
- $volume = "$source:$target";
- } elseif (is_array($volume)) {
- data_set($volume, 'source', $name);
- }
- $topLevelVolumes->put($name, [
- 'name' => $name,
- ]);
- LocalPersistentVolume::updateOrCreate(
- [
- 'mount_path' => $target,
- 'resource_id' => $savedService->id,
- 'resource_type' => get_class($savedService),
- ],
- [
- 'name' => $name,
- 'mount_path' => $target,
- 'resource_id' => $savedService->id,
- 'resource_type' => get_class($savedService),
- ]
- );
- }
- dispatch(new ServerFilesFromServerJob($savedService));
-
- return $volume;
- });
+ $serviceVolumes = parseServiceVolumes($serviceVolumes, $savedService, $topLevelVolumes);
data_set($service, 'volumes', $serviceVolumes->toArray());
}
@@ -1645,131 +1550,261 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
}
} elseif ($resource->compose_parsing_version === '2') {
if (count($serviceVolumes) > 0) {
- $serviceVolumes = $serviceVolumes->map(function ($volume) use ($resource, $topLevelVolumes, $pull_request_id) {
- if (is_string($volume)) {
- $volume = str($volume);
- if ($volume->contains(':') && ! $volume->startsWith('/')) {
- $name = $volume->before(':');
- $mount = $volume->after(':');
- if ($name->startsWith('.') || $name->startsWith('~')) {
- $dir = base_configuration_dir().'/applications/'.$resource->uuid;
- if ($name->startsWith('.')) {
- $name = $name->replaceFirst('.', $dir);
- }
- if ($name->startsWith('~')) {
- $name = $name->replaceFirst('~', $dir);
- }
- if ($pull_request_id !== 0) {
- $name = $name."-pr-$pull_request_id";
- }
- $volume = str("$name:$mount");
- } else {
- if ($pull_request_id !== 0) {
- $uuid = $resource->uuid;
- $name = $uuid."-$name-pr-$pull_request_id";
- $volume = str("$name:$mount");
- if ($topLevelVolumes->has($name)) {
- $v = $topLevelVolumes->get($name);
- if (data_get($v, 'driver_opts.type') === 'cifs') {
- // Do nothing
- } else {
- if (is_null(data_get($v, 'name'))) {
- data_set($v, 'name', $name);
- data_set($topLevelVolumes, $name, $v);
- }
- }
- } else {
- $topLevelVolumes->put($name, [
- 'name' => $name,
- ]);
- }
- } else {
- $uuid = $resource->uuid;
- $name = str($uuid."-$name");
- $volume = str("$name:$mount");
- if ($topLevelVolumes->has($name->value())) {
- $v = $topLevelVolumes->get($name->value());
- if (data_get($v, 'driver_opts.type') === 'cifs') {
- // Do nothing
- } else {
- if (is_null(data_get($v, 'name'))) {
- data_set($topLevelVolumes, $name->value(), $v);
- }
- }
- } else {
- $topLevelVolumes->put($name->value(), [
- 'name' => $name->value(),
- ]);
- }
- }
- }
- } else {
- if ($volume->startsWith('/')) {
- $name = $volume->before(':');
- $mount = $volume->after(':');
- if ($pull_request_id !== 0) {
- $name = $name."-pr-$pull_request_id";
- }
- $volume = str("$name:$mount");
- }
- }
- } elseif (is_array($volume)) {
- $source = data_get($volume, 'source');
- $target = data_get($volume, 'target');
- $read_only = data_get($volume, 'read_only');
- if ($source && $target) {
- $uuid = $resource->uuid;
- if ((str($source)->startsWith('.') || str($source)->startsWith('~') || str($source)->startsWith('/'))) {
- $dir = base_configuration_dir().'/applications/'.$resource->uuid;
- if (str($source, '.')) {
- $source = str($source)->replaceFirst('.', $dir);
- }
- if (str($source, '~')) {
- $source = str($source)->replaceFirst('~', $dir);
- }
- if ($read_only) {
- data_set($volume, 'source', $source.':'.$target.':ro');
- } else {
- data_set($volume, 'source', $source.':'.$target);
- }
- } else {
- if ($pull_request_id === 0) {
- $source = $uuid."-$source";
- } else {
- $source = $uuid."-$source-pr-$pull_request_id";
- }
- if ($read_only) {
- data_set($volume, 'source', $source.':'.$target.':ro');
- } else {
- data_set($volume, 'source', $source.':'.$target);
- }
- if (! str($source)->startsWith('/')) {
- if ($topLevelVolumes->has($source)) {
- $v = $topLevelVolumes->get($source);
- if (data_get($v, 'driver_opts.type') === 'cifs') {
- // Do nothing
- } else {
- if (is_null(data_get($v, 'name'))) {
- data_set($v, 'name', $source);
- data_set($topLevelVolumes, $source, $v);
- }
- }
- } else {
- $topLevelVolumes->put($source, [
- 'name' => $source,
- ]);
- }
- }
- }
- }
- }
- if (is_array($volume)) {
- return data_get($volume, 'source');
- }
- dispatch(new ServerFilesFromServerJob($resource));
+ $serviceVolumes = parseServiceVolumes($serviceVolumes, $resource, $topLevelVolumes, $pull_request_id);
+ ray($serviceVolumes);
- return $volume->value();
- });
+ data_set($service, 'volumes', $serviceVolumes->toArray());
+ // $serviceVolumes = $serviceVolumes->map(function ($volume) use ($resource, $topLevelVolumes, $pull_request_id) {
+ // if (is_string($volume)) {
+ // $volume = str($volume);
+ // if ($volume->contains(':')) {
+ // $name = $volume->before(':');
+ // $mount = $volume->after(':')->beforeLast(':');
+ // if ($name->startsWith('.') || $name->startsWith('~') || $name->startsWith('/')) {
+ // // File or dir mount from the host system
+ // $dir = base_configuration_dir().'/applications/'.$resource->uuid;
+ // if ($name->startsWith('.')) {
+ // $name = $name->replaceFirst('.', $dir);
+ // }
+ // if ($name->startsWith('~')) {
+ // $name = $name->replaceFirst('~', $dir);
+ // }
+ // if ($pull_request_id !== 0) {
+ // $name = $name."-pr-$pull_request_id";
+ // }
+
+ // $volume = str("$name:$mount");
+ // LocalFileVolume::updateOrCreate(
+ // [
+ // 'mount_path' => $mount,
+ // 'resource_id' => $resource->id,
+ // 'resource_type' => get_class($resource),
+ // ],
+ // [
+ // 'fs_path' => $name,
+ // 'mount_path' => $mount,
+ // 'is_directory' => true,
+ // 'resource_id' => $resource->id,
+ // 'resource_type' => get_class($resource),
+ // ]
+ // );
+ // } else {
+ // // Docker Volume part
+ // if ($pull_request_id == 0) {
+ // $uuid = $resource->uuid;
+ // $name = str($uuid."-$name");
+ // $volume = str("$name:$mount");
+ // if ($topLevelVolumes->has($name->value())) {
+ // $v = $topLevelVolumes->get($name->value());
+ // if (data_get($v, 'driver_opts.type') === 'cifs') {
+ // // Do nothing
+ // } else {
+ // if (is_null(data_get($v, 'name'))) {
+ // data_set($topLevelVolumes, $name->value(), $v);
+ // }
+ // }
+ // } else {
+ // $topLevelVolumes->put($name->value(), [
+ // 'name' => $name->value(),
+ // ]);
+ // }
+ // LocalPersistentVolume::updateOrCreate(
+ // [
+ // 'mount_path' => $mount,
+ // 'resource_id' => $resource->id,
+ // 'resource_type' => get_class($resource),
+ // ],
+ // [
+ // 'name' => $name,
+ // 'mount_path' => $mount,
+ // 'resource_id' => $resource->id,
+ // 'resource_type' => get_class($resource),
+ // ]
+ // );
+ // } else {
+ // $uuid = $resource->uuid;
+ // $name = $uuid."-$name-pr-$pull_request_id";
+ // $volume = str("$name:$mount");
+ // if ($topLevelVolumes->has($name)) {
+ // $v = $topLevelVolumes->get($name);
+ // if (data_get($v, 'driver_opts.type') === 'cifs') {
+ // // Do nothing
+ // } else {
+ // if (is_null(data_get($v, 'name'))) {
+ // data_set($v, 'name', $name);
+ // data_set($topLevelVolumes, $name, $v);
+ // }
+ // }
+ // } else {
+ // $topLevelVolumes->put($name, [
+ // 'name' => $name,
+ // ]);
+ // }
+ // LocalPersistentVolume::updateOrCreate(
+ // [
+ // 'mount_path' => $mount,
+ // 'resource_id' => $resource->id,
+ // 'resource_type' => get_class($resource),
+ // ],
+ // [
+ // 'name' => $name,
+ // 'mount_path' => $mount,
+ // 'resource_id' => $resource->id,
+ // 'resource_type' => get_class($resource),
+ // ]
+ // );
+ // }
+
+ // }
+ // }
+ // } elseif (is_array($volume)) {
+ // $source = data_get($volume, 'source');
+ // $target = data_get($volume, 'target');
+ // $type = data_get($volume, 'type');
+ // $read_only = data_get($volume, 'read_only');
+ // $content = data_get_str($volume, 'content');
+ // if ($source && $target) {
+ // if ($type?->value() === 'bind') {
+ // if ($source->value() === '/var/run/docker.sock') {
+ // return $volume;
+ // }
+ // if ($source->value() === '/tmp' || $source->value() === '/tmp/') {
+ // return $volume;
+ // }
+ // LocalFileVolume::updateOrCreate(
+ // [
+ // 'mount_path' => $target,
+ // 'resource_id' => $savedService->id,
+ // 'resource_type' => get_class($savedService),
+ // ],
+ // [
+ // 'fs_path' => $source,
+ // 'mount_path' => $target,
+ // 'content' => $content,
+ // 'is_directory' => $isDirectory,
+ // 'resource_id' => $savedService->id,
+ // 'resource_type' => get_class($savedService),
+ // ]
+ // );
+ // } elseif ($type->value() === 'volume') {
+ // if ($topLevelVolumes->has($source->value())) {
+ // $v = $topLevelVolumes->get($source->value());
+ // if (data_get($v, 'driver_opts.type') === 'cifs') {
+ // return $volume;
+ // }
+ // }
+ // $slugWithoutUuid = Str::slug($source, '-');
+ // $name = "{$savedService->service->uuid}_{$slugWithoutUuid}";
+ // if (is_string($volume)) {
+ // $source = str($volume)->before(':');
+ // $target = str($volume)->after(':')->beforeLast(':');
+ // $source = $name;
+ // $volume = "$source:$target";
+ // } elseif (is_array($volume)) {
+ // data_set($volume, 'source', $name);
+ // }
+ // $topLevelVolumes->put($name, [
+ // 'name' => $name,
+ // ]);
+ // LocalPersistentVolume::updateOrCreate(
+ // [
+ // 'mount_path' => $target,
+ // 'resource_id' => $savedService->id,
+ // 'resource_type' => get_class($savedService),
+ // ],
+ // [
+ // 'name' => $name,
+ // 'mount_path' => $target,
+ // 'resource_id' => $savedService->id,
+ // 'resource_type' => get_class($savedService),
+ // ]
+ // );
+ // }
+
+ // $uuid = $resource->uuid;
+ // if ((str($source)->startsWith('.') || str($source)->startsWith('~') || str($source)->startsWith('/'))) {
+ // $dir = base_configuration_dir().'/applications/'.$resource->uuid;
+ // if (str($source, '.')) {
+ // $source = str($source)->replaceFirst('.', $dir);
+ // }
+ // if (str($source, '~')) {
+ // $source = str($source)->replaceFirst('~', $dir);
+ // }
+ // if ($read_only) {
+ // data_set($volume, 'source', $source.':'.$target.':ro');
+ // } else {
+ // data_set($volume, 'source', $source.':'.$target);
+ // }
+ // } else {
+ // if ($pull_request_id === 0) {
+ // $source = $uuid."-$source";
+ // } else {
+ // $source = $uuid."-$source-pr-$pull_request_id";
+ // }
+ // if ($read_only) {
+ // data_set($volume, 'source', $source.':'.$target.':ro');
+ // } else {
+ // data_set($volume, 'source', $source.':'.$target);
+ // }
+ // if (! str($source)->startsWith('/')) {
+ // if ($topLevelVolumes->has($source)) {
+ // $v = $topLevelVolumes->get($source);
+ // if (data_get($v, 'driver_opts.type') === 'cifs') {
+ // // Do nothing
+ // } else {
+ // if (is_null(data_get($v, 'name'))) {
+ // data_set($v, 'name', $source);
+ // data_set($topLevelVolumes, $source, $v);
+ // }
+ // }
+ // } else {
+ // $topLevelVolumes->put($source, [
+ // 'name' => $source,
+ // ]);
+ // }
+ // }
+ // }
+ // if ($content->isNotEmpty()) {
+ // LocalFileVolume::updateOrCreate(
+ // [
+ // 'mount_path' => $target,
+ // 'resource_id' => $resource->id,
+ // 'resource_type' => get_class($resource),
+ // ],
+ // [
+ // 'fs_path' => $source,
+ // 'mount_path' => $target,
+ // 'content' => $content,
+ // 'is_directory' => false,
+ // 'resource_id' => $resource->id,
+ // 'resource_type' => get_class($resource),
+ // ]
+ // );
+ // } else {
+ // LocalFileVolume::updateOrCreate(
+ // [
+ // 'mount_path' => $target,
+ // 'resource_id' => $resource->id,
+ // 'resource_type' => get_class($resource),
+ // ],
+ // [
+ // 'fs_path' => $source,
+ // 'mount_path' => $target,
+ // 'is_directory' => true,
+ // 'resource_id' => $resource->id,
+ // 'resource_type' => get_class($resource),
+ // ]
+ // );
+ // }
+ // }
+ // }
+ // if (is_array($volume)) {
+ // return data_get($volume, 'source');
+ // }
+ // dispatch(new ServerFilesFromServerJob($resource));
+
+ // return $volume->value();
+ // });
data_set($service, 'volumes', $serviceVolumes->toArray());
}
}
@@ -2662,3 +2697,124 @@ function customApiValidator(Collection|array $item, array $rules)
'required' => 'This field is required.',
]);
}
+
+function parseServiceVolumes($serviceVolumes, $resource, $topLevelVolumes, $pull_request_id = 0)
+{
+ return $serviceVolumes->map(function ($volume) use ($resource, $topLevelVolumes, $pull_request_id) {
+ $type = null;
+ $source = null;
+ $target = null;
+ $content = null;
+ $isDirectory = false;
+ if (is_string($volume)) {
+ $source = str($volume)->before(':');
+ $target = str($volume)->after(':')->beforeLast(':');
+ if ($source->startsWith('./') || $source->startsWith('/') || $source->startsWith('~')) {
+ $type = str('bind');
+ // By default, we cannot determine if the bind is a directory or not, so we set it to directory
+ $isDirectory = true;
+ } else {
+ $type = str('volume');
+ }
+ } elseif (is_array($volume)) {
+ $type = data_get_str($volume, 'type');
+ $source = data_get_str($volume, 'source');
+ $target = data_get_str($volume, 'target');
+ $content = data_get($volume, 'content');
+ $isDirectory = (bool) data_get($volume, 'isDirectory', null) || (bool) data_get($volume, 'is_directory', null);
+ $foundConfig = $resource->fileStorages()->whereMountPath($target)->first();
+ if ($foundConfig) {
+ $contentNotNull = data_get($foundConfig, 'content');
+ if ($contentNotNull) {
+ $content = $contentNotNull;
+ }
+ $isDirectory = (bool) data_get($volume, 'isDirectory', null) || (bool) data_get($volume, 'is_directory', null);
+ }
+ if ((is_null($isDirectory) || ! $isDirectory) && is_null($content)) {
+ // if isDirectory is not set (or false) & content is also not set, we assume it is a directory
+ ray('setting isDirectory to true');
+ $isDirectory = true;
+ }
+ }
+ if ($type?->value() === 'bind') {
+ if ($source->value() === '/var/run/docker.sock') {
+ return $volume;
+ }
+ if ($source->value() === '/tmp' || $source->value() === '/tmp/') {
+ return $volume;
+ }
+ if (get_class($resource) === "App\Models\Application") {
+ $dir = base_configuration_dir().'/applications/'.$resource->uuid;
+ } else {
+ $dir = base_configuration_dir().'/services/'.$resource->service->uuid;
+ }
+
+ if ($source->startsWith('.')) {
+ $source = $source->replaceFirst('.', $dir);
+ }
+ if ($source->startsWith('~')) {
+ $source = $source->replaceFirst('~', $dir);
+ }
+ if ($pull_request_id !== 0) {
+ $source = $source."-pr-$pull_request_id";
+ }
+
+ $volume = str("$source:$target");
+ LocalFileVolume::updateOrCreate(
+ [
+ 'mount_path' => $target,
+ 'resource_id' => $resource->id,
+ 'resource_type' => get_class($resource),
+ ],
+ [
+ 'fs_path' => $source,
+ 'mount_path' => $target,
+ 'content' => $content,
+ 'is_directory' => $isDirectory,
+ 'resource_id' => $resource->id,
+ 'resource_type' => get_class($resource),
+ ]
+ );
+ } elseif ($type->value() === 'volume') {
+ if ($topLevelVolumes->has($source->value())) {
+ $v = $topLevelVolumes->get($source->value());
+ if (data_get($v, 'driver_opts.type') === 'cifs') {
+ return $volume;
+ }
+ }
+ $slugWithoutUuid = Str::slug($source, '-');
+ if (get_class($resource) === "App\Models\Application") {
+ $name = "{$resource->uuid}_{$slugWithoutUuid}";
+ } else {
+ $name = "{$resource->service->uuid}_{$slugWithoutUuid}";
+ }
+ if (is_string($volume)) {
+ $source = str($volume)->before(':');
+ $target = str($volume)->after(':')->beforeLast(':');
+ $source = $name;
+ $volume = "$source:$target";
+ } elseif (is_array($volume)) {
+ data_set($volume, 'source', $name);
+ }
+ $topLevelVolumes->put($name, [
+ 'name' => $name,
+ ]);
+ LocalPersistentVolume::updateOrCreate(
+ [
+ 'mount_path' => $target,
+ 'resource_id' => $resource->id,
+ 'resource_type' => get_class($resource),
+ ],
+ [
+ 'name' => $name,
+ 'mount_path' => $target,
+ 'resource_id' => $resource->id,
+ 'resource_type' => get_class($resource),
+ ]
+ );
+ }
+ dispatch(new ServerFilesFromServerJob($resource));
+
+ return str($volume)->value();
+ });
+}
diff --git a/database/migrations/2024_08_12_131659_add_local_file_volume_based_on_git.php b/database/migrations/2024_08_12_131659_add_local_file_volume_based_on_git.php
new file mode 100644
index 000000000..d180c7ec2
--- /dev/null
+++ b/database/migrations/2024_08_12_131659_add_local_file_volume_based_on_git.php
@@ -0,0 +1,28 @@
+boolean('is_based_on_git')->default(false);
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ */
+ public function down(): void
+ {
+ Schema::table('local_file_volumes', function (Blueprint $table) {
+ $table->dropColumn('is_based_on_git');
+ });
+ }
+};
diff --git a/resources/views/livewire/project/service/file-storage.blade.php b/resources/views/livewire/project/service/file-storage.blade.php
index 96590cada..78cf70429 100644
--- a/resources/views/livewire/project/service/file-storage.blade.php
+++ b/resources/views/livewire/project/service/file-storage.blade.php
@@ -10,6 +10,7 @@
@endif