Primo Committ
This commit is contained in:
102
vendor/spatie/laravel-backup/src/BackupDestination/Backup.php
vendored
Normal file
102
vendor/spatie/laravel-backup/src/BackupDestination/Backup.php
vendored
Normal file
@@ -0,0 +1,102 @@
|
||||
<?php
|
||||
|
||||
namespace Spatie\Backup\BackupDestination;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Contracts\Filesystem\Filesystem;
|
||||
use InvalidArgumentException;
|
||||
use Spatie\Backup\Tasks\Backup\BackupJob;
|
||||
|
||||
class Backup
|
||||
{
|
||||
/** @var \Illuminate\Contracts\Filesystem\Filesystem */
|
||||
protected $disk;
|
||||
|
||||
/** @var string */
|
||||
protected $path;
|
||||
|
||||
/** @var bool */
|
||||
protected $exists;
|
||||
|
||||
/** @var Carbon */
|
||||
protected $date;
|
||||
|
||||
/** @var int */
|
||||
protected $size;
|
||||
|
||||
public function __construct(Filesystem $disk, string $path)
|
||||
{
|
||||
$this->disk = $disk;
|
||||
$this->path = $path;
|
||||
$this->exists = true;
|
||||
}
|
||||
|
||||
public function disk(): Filesystem
|
||||
{
|
||||
return $this->disk;
|
||||
}
|
||||
|
||||
public function path(): string
|
||||
{
|
||||
return $this->path;
|
||||
}
|
||||
|
||||
public function exists(): bool
|
||||
{
|
||||
if ($this->exists === null) {
|
||||
$this->exists = $this->disk->exists($this->path);
|
||||
}
|
||||
|
||||
return $this->exists;
|
||||
}
|
||||
|
||||
public function date(): Carbon
|
||||
{
|
||||
if ($this->date === null) {
|
||||
try {
|
||||
// try to parse the date from the filename
|
||||
$basename = basename($this->path);
|
||||
$this->date = Carbon::createFromFormat(BackupJob::FILENAME_FORMAT, $basename);
|
||||
} catch (InvalidArgumentException $e) {
|
||||
// if that fails, ask the (remote) filesystem
|
||||
$this->date = Carbon::createFromTimestamp($this->disk->lastModified($this->path));
|
||||
}
|
||||
}
|
||||
|
||||
return $this->date;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the size in bytes.
|
||||
*/
|
||||
public function size(): float
|
||||
{
|
||||
if ($this->size === null) {
|
||||
if (! $this->exists()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$this->size = $this->disk->size($this->path);
|
||||
}
|
||||
|
||||
return $this->size;
|
||||
}
|
||||
|
||||
public function stream()
|
||||
{
|
||||
return $this->disk->readStream($this->path);
|
||||
}
|
||||
|
||||
public function delete()
|
||||
{
|
||||
if (! $this->disk->delete($this->path)) {
|
||||
consoleOutput()->error("Failed to delete backup `{$this->path}`.");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$this->exists = false;
|
||||
|
||||
consoleOutput()->info("Deleted backup `{$this->path}`.");
|
||||
}
|
||||
}
|
||||
49
vendor/spatie/laravel-backup/src/BackupDestination/BackupCollection.php
vendored
Normal file
49
vendor/spatie/laravel-backup/src/BackupDestination/BackupCollection.php
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
namespace Spatie\Backup\BackupDestination;
|
||||
|
||||
use Illuminate\Contracts\Filesystem\Filesystem;
|
||||
use Illuminate\Support\Collection;
|
||||
use Spatie\Backup\Helpers\File;
|
||||
|
||||
class BackupCollection extends Collection
|
||||
{
|
||||
/** @var null|float */
|
||||
protected $sizeCache = null;
|
||||
|
||||
public static function createFromFiles(?FileSystem $disk, array $files): self
|
||||
{
|
||||
return (new static($files))
|
||||
->filter(function ($path) use ($disk) {
|
||||
return (new File)->isZipFile($disk, $path);
|
||||
})
|
||||
->map(function ($path) use ($disk) {
|
||||
return new Backup($disk, $path);
|
||||
})
|
||||
->sortByDesc(function (Backup $backup) {
|
||||
return $backup->date()->timestamp;
|
||||
})
|
||||
->values();
|
||||
}
|
||||
|
||||
public function newest(): ?Backup
|
||||
{
|
||||
return $this->first();
|
||||
}
|
||||
|
||||
public function oldest(): ?Backup
|
||||
{
|
||||
return $this
|
||||
->filter->exists()
|
||||
->last();
|
||||
}
|
||||
|
||||
public function size(): float
|
||||
{
|
||||
if ($this->sizeCache !== null) {
|
||||
return $this->sizeCache;
|
||||
}
|
||||
|
||||
return $this->sizeCache = $this->sum->size();
|
||||
}
|
||||
}
|
||||
191
vendor/spatie/laravel-backup/src/BackupDestination/BackupDestination.php
vendored
Normal file
191
vendor/spatie/laravel-backup/src/BackupDestination/BackupDestination.php
vendored
Normal file
@@ -0,0 +1,191 @@
|
||||
<?php
|
||||
|
||||
namespace Spatie\Backup\BackupDestination;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Exception;
|
||||
use Illuminate\Contracts\Filesystem\Factory;
|
||||
use Illuminate\Contracts\Filesystem\Filesystem;
|
||||
use Spatie\Backup\Exceptions\InvalidBackupDestination;
|
||||
|
||||
class BackupDestination
|
||||
{
|
||||
/** @var \Illuminate\Contracts\Filesystem\Filesystem */
|
||||
protected $disk;
|
||||
|
||||
/** @var string */
|
||||
protected $diskName;
|
||||
|
||||
/** @var string */
|
||||
protected $backupName;
|
||||
|
||||
/** @var Exception */
|
||||
public $connectionError;
|
||||
|
||||
/** @var null|\Spatie\Backup\BackupDestination\BackupCollection */
|
||||
protected $backupCollectionCache = null;
|
||||
|
||||
public function __construct(Filesystem $disk = null, string $backupName, string $diskName)
|
||||
{
|
||||
$this->disk = $disk;
|
||||
|
||||
$this->diskName = $diskName;
|
||||
|
||||
$this->backupName = preg_replace('/[^a-zA-Z0-9.]/', '-', $backupName);
|
||||
}
|
||||
|
||||
public function disk(): Filesystem
|
||||
{
|
||||
return $this->disk;
|
||||
}
|
||||
|
||||
public function diskName(): string
|
||||
{
|
||||
return $this->diskName;
|
||||
}
|
||||
|
||||
public function filesystemType(): string
|
||||
{
|
||||
if (is_null($this->disk)) {
|
||||
return 'unknown';
|
||||
}
|
||||
|
||||
$adapterClass = get_class($this->disk->getDriver()->getAdapter());
|
||||
|
||||
$filesystemType = last(explode('\\', $adapterClass));
|
||||
|
||||
return strtolower($filesystemType);
|
||||
}
|
||||
|
||||
public static function create(string $diskName, string $backupName): self
|
||||
{
|
||||
try {
|
||||
$disk = app(Factory::class)->disk($diskName);
|
||||
|
||||
return new static($disk, $backupName, $diskName);
|
||||
} catch (Exception $exception) {
|
||||
$backupDestination = new static(null, $backupName, $diskName);
|
||||
|
||||
$backupDestination->connectionError = $exception;
|
||||
|
||||
return $backupDestination;
|
||||
}
|
||||
}
|
||||
|
||||
public function write(string $file)
|
||||
{
|
||||
if (! is_null($this->connectionError)) {
|
||||
throw InvalidBackupDestination::connectionError($this->diskName);
|
||||
}
|
||||
|
||||
if (is_null($this->disk)) {
|
||||
throw InvalidBackupDestination::diskNotSet($this->backupName);
|
||||
}
|
||||
|
||||
$destination = $this->backupName.'/'.pathinfo($file, PATHINFO_BASENAME);
|
||||
|
||||
$handle = fopen($file, 'r+');
|
||||
|
||||
$result = $this->disk->getDriver()->writeStream(
|
||||
$destination,
|
||||
$handle,
|
||||
$this->getDiskOptions()
|
||||
);
|
||||
|
||||
if (is_resource($handle)) {
|
||||
fclose($handle);
|
||||
}
|
||||
|
||||
if ($result === false) {
|
||||
throw InvalidBackupDestination::writeError($this->diskName);
|
||||
}
|
||||
}
|
||||
|
||||
public function backupName(): string
|
||||
{
|
||||
return $this->backupName;
|
||||
}
|
||||
|
||||
public function backups(): BackupCollection
|
||||
{
|
||||
if ($this->backupCollectionCache) {
|
||||
return $this->backupCollectionCache;
|
||||
}
|
||||
|
||||
$files = [];
|
||||
|
||||
if (! is_null($this->disk)) {
|
||||
// $this->disk->allFiles() may fail when $this->disk is not reachable
|
||||
// in that case we still want to send the notification
|
||||
try {
|
||||
$files = $this->disk->allFiles($this->backupName);
|
||||
} catch (Exception $ex) {
|
||||
}
|
||||
}
|
||||
|
||||
return $this->backupCollectionCache = BackupCollection::createFromFiles(
|
||||
$this->disk,
|
||||
$files
|
||||
);
|
||||
}
|
||||
|
||||
public function connectionError(): Exception
|
||||
{
|
||||
return $this->connectionError;
|
||||
}
|
||||
|
||||
public function getDiskOptions(): array
|
||||
{
|
||||
return config("filesystems.disks.{$this->diskName()}.backup_options") ?? [];
|
||||
}
|
||||
|
||||
public function isReachable(): bool
|
||||
{
|
||||
if (is_null($this->disk)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
$this->disk->allFiles($this->backupName);
|
||||
|
||||
return true;
|
||||
} catch (Exception $exception) {
|
||||
$this->connectionError = $exception;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function usedStorage(): float
|
||||
{
|
||||
return $this->backups()->size();
|
||||
}
|
||||
|
||||
public function newestBackup(): ?Backup
|
||||
{
|
||||
return $this->backups()->newest();
|
||||
}
|
||||
|
||||
public function oldestBackup(): ?Backup
|
||||
{
|
||||
return $this->backups()->oldest();
|
||||
}
|
||||
|
||||
public function newestBackupIsOlderThan(Carbon $date): bool
|
||||
{
|
||||
$newestBackup = $this->newestBackup();
|
||||
|
||||
if (is_null($newestBackup)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return $newestBackup->date()->gt($date);
|
||||
}
|
||||
|
||||
public function fresh(): self
|
||||
{
|
||||
$this->backupCollectionCache = null;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
16
vendor/spatie/laravel-backup/src/BackupDestination/BackupDestinationFactory.php
vendored
Normal file
16
vendor/spatie/laravel-backup/src/BackupDestination/BackupDestinationFactory.php
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace Spatie\Backup\BackupDestination;
|
||||
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
class BackupDestinationFactory
|
||||
{
|
||||
public static function createFromArray(array $config): Collection
|
||||
{
|
||||
return collect($config['destination']['disks'])
|
||||
->map(function ($filesystemName) use ($config) {
|
||||
return BackupDestination::create($filesystemName, $config['name']);
|
||||
});
|
||||
}
|
||||
}
|
||||
58
vendor/spatie/laravel-backup/src/BackupServiceProvider.php
vendored
Normal file
58
vendor/spatie/laravel-backup/src/BackupServiceProvider.php
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
namespace Spatie\Backup;
|
||||
|
||||
use Illuminate\Support\Facades\Event;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use Spatie\Backup\Commands\BackupCommand;
|
||||
use Spatie\Backup\Commands\CleanupCommand;
|
||||
use Spatie\Backup\Commands\ListCommand;
|
||||
use Spatie\Backup\Commands\MonitorCommand;
|
||||
use Spatie\Backup\Events\BackupZipWasCreated;
|
||||
use Spatie\Backup\Helpers\ConsoleOutput;
|
||||
use Spatie\Backup\Listeners\EncryptBackupArchive;
|
||||
use Spatie\Backup\Notifications\EventHandler;
|
||||
use Spatie\Backup\Tasks\Cleanup\CleanupStrategy;
|
||||
|
||||
class BackupServiceProvider extends ServiceProvider
|
||||
{
|
||||
public function boot()
|
||||
{
|
||||
$this->publishes([
|
||||
__DIR__.'/../config/backup.php' => config_path('backup.php'),
|
||||
], 'config');
|
||||
|
||||
$this->publishes([
|
||||
__DIR__.'/../resources/lang' => "{$this->app['path.lang']}/vendor/backup",
|
||||
]);
|
||||
|
||||
$this->loadTranslationsFrom(__DIR__.'/../resources/lang/', 'backup');
|
||||
|
||||
if (EncryptBackupArchive::shouldEncrypt()) {
|
||||
Event::listen(BackupZipWasCreated::class, EncryptBackupArchive::class);
|
||||
}
|
||||
}
|
||||
|
||||
public function register()
|
||||
{
|
||||
$this->mergeConfigFrom(__DIR__.'/../config/backup.php', 'backup');
|
||||
|
||||
$this->app['events']->subscribe(EventHandler::class);
|
||||
|
||||
$this->app->bind('command.backup:run', BackupCommand::class);
|
||||
$this->app->bind('command.backup:clean', CleanupCommand::class);
|
||||
$this->app->bind('command.backup:list', ListCommand::class);
|
||||
$this->app->bind('command.backup:monitor', MonitorCommand::class);
|
||||
|
||||
$this->app->bind(CleanupStrategy::class, config('backup.cleanup.strategy'));
|
||||
|
||||
$this->commands([
|
||||
'command.backup:run',
|
||||
'command.backup:clean',
|
||||
'command.backup:list',
|
||||
'command.backup:monitor',
|
||||
]);
|
||||
|
||||
$this->app->singleton(ConsoleOutput::class);
|
||||
}
|
||||
}
|
||||
76
vendor/spatie/laravel-backup/src/Commands/BackupCommand.php
vendored
Normal file
76
vendor/spatie/laravel-backup/src/Commands/BackupCommand.php
vendored
Normal file
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
namespace Spatie\Backup\Commands;
|
||||
|
||||
use Exception;
|
||||
use Spatie\Backup\Events\BackupHasFailed;
|
||||
use Spatie\Backup\Exceptions\InvalidCommand;
|
||||
use Spatie\Backup\Tasks\Backup\BackupJobFactory;
|
||||
|
||||
class BackupCommand extends BaseCommand
|
||||
{
|
||||
/** @var string */
|
||||
protected $signature = 'backup:run {--filename=} {--only-db} {--db-name=*} {--only-files} {--only-to-disk=} {--disable-notifications} {--timeout=}';
|
||||
|
||||
/** @var string */
|
||||
protected $description = 'Run the backup.';
|
||||
|
||||
public function handle()
|
||||
{
|
||||
consoleOutput()->comment('Starting backup...');
|
||||
|
||||
$disableNotifications = $this->option('disable-notifications');
|
||||
|
||||
if ($this->option('timeout') && is_numeric($this->option('timeout'))) {
|
||||
set_time_limit((int) $this->option('timeout'));
|
||||
}
|
||||
|
||||
try {
|
||||
$this->guardAgainstInvalidOptions();
|
||||
|
||||
$backupJob = BackupJobFactory::createFromArray(config('backup'));
|
||||
|
||||
if ($this->option('only-db')) {
|
||||
$backupJob->dontBackupFilesystem();
|
||||
}
|
||||
if ($this->option('db-name')) {
|
||||
$backupJob->onlyDbName($this->option('db-name'));
|
||||
}
|
||||
|
||||
if ($this->option('only-files')) {
|
||||
$backupJob->dontBackupDatabases();
|
||||
}
|
||||
|
||||
if ($this->option('only-to-disk')) {
|
||||
$backupJob->onlyBackupTo($this->option('only-to-disk'));
|
||||
}
|
||||
|
||||
if ($this->option('filename')) {
|
||||
$backupJob->setFilename($this->option('filename'));
|
||||
}
|
||||
|
||||
if ($disableNotifications) {
|
||||
$backupJob->disableNotifications();
|
||||
}
|
||||
|
||||
$backupJob->run();
|
||||
|
||||
consoleOutput()->comment('Backup completed!');
|
||||
} catch (Exception $exception) {
|
||||
consoleOutput()->error("Backup failed because: {$exception->getMessage()}.");
|
||||
|
||||
if (! $disableNotifications) {
|
||||
event(new BackupHasFailed($exception));
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
protected function guardAgainstInvalidOptions()
|
||||
{
|
||||
if ($this->option('only-db') && $this->option('only-files')) {
|
||||
throw InvalidCommand::create('Cannot use `only-db` and `only-files` together');
|
||||
}
|
||||
}
|
||||
}
|
||||
18
vendor/spatie/laravel-backup/src/Commands/BaseCommand.php
vendored
Normal file
18
vendor/spatie/laravel-backup/src/Commands/BaseCommand.php
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace Spatie\Backup\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use Spatie\Backup\Helpers\ConsoleOutput;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
abstract class BaseCommand extends Command
|
||||
{
|
||||
public function run(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
app(ConsoleOutput::class)->setOutput($this);
|
||||
|
||||
return parent::run($input, $output);
|
||||
}
|
||||
}
|
||||
53
vendor/spatie/laravel-backup/src/Commands/CleanupCommand.php
vendored
Normal file
53
vendor/spatie/laravel-backup/src/Commands/CleanupCommand.php
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
namespace Spatie\Backup\Commands;
|
||||
|
||||
use Exception;
|
||||
use Spatie\Backup\BackupDestination\BackupDestinationFactory;
|
||||
use Spatie\Backup\Events\CleanupHasFailed;
|
||||
use Spatie\Backup\Tasks\Cleanup\CleanupJob;
|
||||
use Spatie\Backup\Tasks\Cleanup\CleanupStrategy;
|
||||
|
||||
class CleanupCommand extends BaseCommand
|
||||
{
|
||||
/** @var string */
|
||||
protected $signature = 'backup:clean {--disable-notifications}';
|
||||
|
||||
/** @var string */
|
||||
protected $description = 'Remove all backups older than specified number of days in config.';
|
||||
|
||||
/** @var \Spatie\Backup\Tasks\Cleanup\CleanupStrategy */
|
||||
protected $strategy;
|
||||
|
||||
public function __construct(CleanupStrategy $strategy)
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->strategy = $strategy;
|
||||
}
|
||||
|
||||
public function handle()
|
||||
{
|
||||
consoleOutput()->comment('Starting cleanup...');
|
||||
|
||||
$disableNotifications = $this->option('disable-notifications');
|
||||
|
||||
try {
|
||||
$config = config('backup');
|
||||
|
||||
$backupDestinations = BackupDestinationFactory::createFromArray($config['backup']);
|
||||
|
||||
$cleanupJob = new CleanupJob($backupDestinations, $this->strategy, $disableNotifications);
|
||||
|
||||
$cleanupJob->run();
|
||||
|
||||
consoleOutput()->comment('Cleanup completed!');
|
||||
} catch (Exception $exception) {
|
||||
if (! $disableNotifications) {
|
||||
event(new CleanupHasFailed($exception));
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
101
vendor/spatie/laravel-backup/src/Commands/ListCommand.php
vendored
Normal file
101
vendor/spatie/laravel-backup/src/Commands/ListCommand.php
vendored
Normal file
@@ -0,0 +1,101 @@
|
||||
<?php
|
||||
|
||||
namespace Spatie\Backup\Commands;
|
||||
|
||||
use Illuminate\Support\Collection;
|
||||
use Spatie\Backup\BackupDestination\Backup;
|
||||
use Spatie\Backup\Helpers\Format;
|
||||
use Spatie\Backup\Helpers\RightAlignedTableStyle;
|
||||
use Spatie\Backup\Tasks\Monitor\BackupDestinationStatus;
|
||||
use Spatie\Backup\Tasks\Monitor\BackupDestinationStatusFactory;
|
||||
|
||||
class ListCommand extends BaseCommand
|
||||
{
|
||||
/** @var string */
|
||||
protected $signature = 'backup:list';
|
||||
|
||||
/** @var string */
|
||||
protected $description = 'Display a list of all backups.';
|
||||
|
||||
public function handle()
|
||||
{
|
||||
$statuses = BackupDestinationStatusFactory::createForMonitorConfig(config('backup.monitor_backups'));
|
||||
|
||||
$this->displayOverview($statuses)->displayFailures($statuses);
|
||||
}
|
||||
|
||||
protected function displayOverview(Collection $backupDestinationStatuses)
|
||||
{
|
||||
$headers = ['Name', 'Disk', 'Reachable', 'Healthy', '# of backups', 'Newest backup', 'Used storage'];
|
||||
|
||||
$rows = $backupDestinationStatuses->map(function (BackupDestinationStatus $backupDestinationStatus) {
|
||||
return $this->convertToRow($backupDestinationStatus);
|
||||
});
|
||||
|
||||
$this->table($headers, $rows, 'default', [
|
||||
4 => new RightAlignedTableStyle(),
|
||||
6 => new RightAlignedTableStyle(),
|
||||
]);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function convertToRow(BackupDestinationStatus $backupDestinationStatus): array
|
||||
{
|
||||
$destination = $backupDestinationStatus->backupDestination();
|
||||
|
||||
$row = [
|
||||
$destination->backupName(),
|
||||
'disk' => $destination->diskName(),
|
||||
Format::emoji($destination->isReachable()),
|
||||
Format::emoji($backupDestinationStatus->isHealthy()),
|
||||
'amount' => $destination->backups()->count(),
|
||||
'newest' => $this->getFormattedBackupDate($destination->newestBackup()),
|
||||
'usedStorage' => Format::humanReadableSize($destination->usedStorage()),
|
||||
];
|
||||
|
||||
if (! $destination->isReachable()) {
|
||||
foreach (['amount', 'newest', 'usedStorage'] as $propertyName) {
|
||||
$row[$propertyName] = '/';
|
||||
}
|
||||
}
|
||||
|
||||
if ($backupDestinationStatus->getHealthCheckFailure() !== null) {
|
||||
$row['disk'] = '<error>'.$row['disk'].'</error>';
|
||||
}
|
||||
|
||||
return $row;
|
||||
}
|
||||
|
||||
protected function displayFailures(Collection $backupDestinationStatuses)
|
||||
{
|
||||
$failed = $backupDestinationStatuses
|
||||
->filter(function (BackupDestinationStatus $backupDestinationStatus) {
|
||||
return $backupDestinationStatus->getHealthCheckFailure() !== null;
|
||||
})
|
||||
->map(function (BackupDestinationStatus $backupDestinationStatus) {
|
||||
return [
|
||||
$backupDestinationStatus->backupDestination()->backupName(),
|
||||
$backupDestinationStatus->backupDestination()->diskName(),
|
||||
$backupDestinationStatus->getHealthCheckFailure()->healthCheck()->name(),
|
||||
$backupDestinationStatus->getHealthCheckFailure()->exception()->getMessage(),
|
||||
];
|
||||
});
|
||||
|
||||
if ($failed->isNotEmpty()) {
|
||||
$this->warn('');
|
||||
$this->warn('Unhealthy backup destinations');
|
||||
$this->warn('-----------------------------');
|
||||
$this->table(['Name', 'Disk', 'Failed check', 'Description'], $failed->all());
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function getFormattedBackupDate(Backup $backup = null)
|
||||
{
|
||||
return is_null($backup)
|
||||
? 'No backups present'
|
||||
: Format::ageInDays($backup->date());
|
||||
}
|
||||
}
|
||||
40
vendor/spatie/laravel-backup/src/Commands/MonitorCommand.php
vendored
Normal file
40
vendor/spatie/laravel-backup/src/Commands/MonitorCommand.php
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace Spatie\Backup\Commands;
|
||||
|
||||
use Spatie\Backup\Events\HealthyBackupWasFound;
|
||||
use Spatie\Backup\Events\UnhealthyBackupWasFound;
|
||||
use Spatie\Backup\Tasks\Monitor\BackupDestinationStatusFactory;
|
||||
|
||||
class MonitorCommand extends BaseCommand
|
||||
{
|
||||
/** @var string */
|
||||
protected $signature = 'backup:monitor';
|
||||
|
||||
/** @var string */
|
||||
protected $description = 'Monitor the health of all backups.';
|
||||
|
||||
public function handle()
|
||||
{
|
||||
$hasError = false;
|
||||
|
||||
$statuses = BackupDestinationStatusFactory::createForMonitorConfig(config('backup.monitor_backups'));
|
||||
|
||||
foreach ($statuses as $backupDestinationStatus) {
|
||||
$diskName = $backupDestinationStatus->backupDestination()->diskName();
|
||||
|
||||
if ($backupDestinationStatus->isHealthy()) {
|
||||
$this->info("The backups on {$diskName} are considered healthy.");
|
||||
event(new HealthyBackupWasFound($backupDestinationStatus));
|
||||
} else {
|
||||
$hasError = true;
|
||||
$this->error("The backups on {$diskName} are considered unhealthy!");
|
||||
event(new UnHealthyBackupWasFound($backupDestinationStatus));
|
||||
}
|
||||
}
|
||||
|
||||
if ($hasError) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
22
vendor/spatie/laravel-backup/src/Events/BackupHasFailed.php
vendored
Normal file
22
vendor/spatie/laravel-backup/src/Events/BackupHasFailed.php
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace Spatie\Backup\Events;
|
||||
|
||||
use Exception;
|
||||
use Spatie\Backup\BackupDestination\BackupDestination;
|
||||
|
||||
class BackupHasFailed
|
||||
{
|
||||
/** @var \Exception */
|
||||
public $exception;
|
||||
|
||||
/** @var \Spatie\Backup\BackupDestination\BackupDestination|null */
|
||||
public $backupDestination;
|
||||
|
||||
public function __construct(Exception $exception, BackupDestination $backupDestination = null)
|
||||
{
|
||||
$this->exception = $exception;
|
||||
|
||||
$this->backupDestination = $backupDestination;
|
||||
}
|
||||
}
|
||||
16
vendor/spatie/laravel-backup/src/Events/BackupManifestWasCreated.php
vendored
Normal file
16
vendor/spatie/laravel-backup/src/Events/BackupManifestWasCreated.php
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace Spatie\Backup\Events;
|
||||
|
||||
use Spatie\Backup\Tasks\Backup\Manifest;
|
||||
|
||||
class BackupManifestWasCreated
|
||||
{
|
||||
/** @var \Spatie\Backup\Tasks\Backup\Manifest */
|
||||
public $manifest;
|
||||
|
||||
public function __construct(Manifest $manifest)
|
||||
{
|
||||
$this->manifest = $manifest;
|
||||
}
|
||||
}
|
||||
16
vendor/spatie/laravel-backup/src/Events/BackupWasSuccessful.php
vendored
Normal file
16
vendor/spatie/laravel-backup/src/Events/BackupWasSuccessful.php
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace Spatie\Backup\Events;
|
||||
|
||||
use Spatie\Backup\BackupDestination\BackupDestination;
|
||||
|
||||
class BackupWasSuccessful
|
||||
{
|
||||
/** @var \Spatie\Backup\BackupDestination\BackupDestination */
|
||||
public $backupDestination;
|
||||
|
||||
public function __construct(BackupDestination $backupDestination)
|
||||
{
|
||||
$this->backupDestination = $backupDestination;
|
||||
}
|
||||
}
|
||||
14
vendor/spatie/laravel-backup/src/Events/BackupZipWasCreated.php
vendored
Normal file
14
vendor/spatie/laravel-backup/src/Events/BackupZipWasCreated.php
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace Spatie\Backup\Events;
|
||||
|
||||
class BackupZipWasCreated
|
||||
{
|
||||
/** @var string */
|
||||
public $pathToZip;
|
||||
|
||||
public function __construct(string $pathToZip)
|
||||
{
|
||||
$this->pathToZip = $pathToZip;
|
||||
}
|
||||
}
|
||||
22
vendor/spatie/laravel-backup/src/Events/CleanupHasFailed.php
vendored
Normal file
22
vendor/spatie/laravel-backup/src/Events/CleanupHasFailed.php
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace Spatie\Backup\Events;
|
||||
|
||||
use Exception;
|
||||
use Spatie\Backup\BackupDestination\BackupDestination;
|
||||
|
||||
class CleanupHasFailed
|
||||
{
|
||||
/** @var \Exception */
|
||||
public $exception;
|
||||
|
||||
/** @var \Spatie\Backup\BackupDestination\BackupDestination|null */
|
||||
public $backupDestination;
|
||||
|
||||
public function __construct(Exception $exception, BackupDestination $backupDestination = null)
|
||||
{
|
||||
$this->exception = $exception;
|
||||
|
||||
$this->backupDestination = $backupDestination;
|
||||
}
|
||||
}
|
||||
16
vendor/spatie/laravel-backup/src/Events/CleanupWasSuccessful.php
vendored
Normal file
16
vendor/spatie/laravel-backup/src/Events/CleanupWasSuccessful.php
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace Spatie\Backup\Events;
|
||||
|
||||
use Spatie\Backup\BackupDestination\BackupDestination;
|
||||
|
||||
class CleanupWasSuccessful
|
||||
{
|
||||
/** @var \Spatie\Backup\BackupDestination\BackupDestination */
|
||||
public $backupDestination;
|
||||
|
||||
public function __construct(BackupDestination $backupDestination)
|
||||
{
|
||||
$this->backupDestination = $backupDestination;
|
||||
}
|
||||
}
|
||||
16
vendor/spatie/laravel-backup/src/Events/DumpingDatabase.php
vendored
Normal file
16
vendor/spatie/laravel-backup/src/Events/DumpingDatabase.php
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace Spatie\Backup\Events;
|
||||
|
||||
use Spatie\DbDumper\DbDumper;
|
||||
|
||||
class DumpingDatabase
|
||||
{
|
||||
/** @var \Spatie\DbDumper\DbDumper */
|
||||
public $dbDumper;
|
||||
|
||||
public function __construct(DbDumper $dbDumper)
|
||||
{
|
||||
$this->dbDumper = $dbDumper;
|
||||
}
|
||||
}
|
||||
16
vendor/spatie/laravel-backup/src/Events/HealthyBackupWasFound.php
vendored
Normal file
16
vendor/spatie/laravel-backup/src/Events/HealthyBackupWasFound.php
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace Spatie\Backup\Events;
|
||||
|
||||
use Spatie\Backup\Tasks\Monitor\BackupDestinationStatus;
|
||||
|
||||
class HealthyBackupWasFound
|
||||
{
|
||||
/** @var \Spatie\Backup\Tasks\Monitor\BackupDestinationStatus */
|
||||
public $backupDestinationStatus;
|
||||
|
||||
public function __construct(BackupDestinationStatus $backupDestinationStatus)
|
||||
{
|
||||
$this->backupDestinationStatus = $backupDestinationStatus;
|
||||
}
|
||||
}
|
||||
16
vendor/spatie/laravel-backup/src/Events/UnhealthyBackupWasFound.php
vendored
Normal file
16
vendor/spatie/laravel-backup/src/Events/UnhealthyBackupWasFound.php
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace Spatie\Backup\Events;
|
||||
|
||||
use Spatie\Backup\Tasks\Monitor\BackupDestinationStatus;
|
||||
|
||||
class UnhealthyBackupWasFound
|
||||
{
|
||||
/** @var \Spatie\Backup\Tasks\Monitor\BackupDestinationStatus */
|
||||
public $backupDestinationStatus;
|
||||
|
||||
public function __construct(BackupDestinationStatus $backupDestinationStatus)
|
||||
{
|
||||
$this->backupDestinationStatus = $backupDestinationStatus;
|
||||
}
|
||||
}
|
||||
13
vendor/spatie/laravel-backup/src/Exceptions/CannotCreateDbDumper.php
vendored
Normal file
13
vendor/spatie/laravel-backup/src/Exceptions/CannotCreateDbDumper.php
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
namespace Spatie\Backup\Exceptions;
|
||||
|
||||
use Exception;
|
||||
|
||||
class CannotCreateDbDumper extends Exception
|
||||
{
|
||||
public static function unsupportedDriver(string $driver): self
|
||||
{
|
||||
return new static("Cannot create a dumper for db driver `{$driver}`. Use `mysql`, `pgsql`, `mongodb` or `sqlite`.");
|
||||
}
|
||||
}
|
||||
23
vendor/spatie/laravel-backup/src/Exceptions/InvalidBackupDestination.php
vendored
Normal file
23
vendor/spatie/laravel-backup/src/Exceptions/InvalidBackupDestination.php
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace Spatie\Backup\Exceptions;
|
||||
|
||||
use Exception;
|
||||
|
||||
class InvalidBackupDestination extends Exception
|
||||
{
|
||||
public static function diskNotSet(string $backupName): self
|
||||
{
|
||||
return new static("There is no disk set for the backup named `{$backupName}`.");
|
||||
}
|
||||
|
||||
public static function connectionError(string $diskName): self
|
||||
{
|
||||
return new static ("There is a connection error when trying to connect to disk named `{$diskName}`");
|
||||
}
|
||||
|
||||
public static function writeError(string $diskName): self
|
||||
{
|
||||
return new static ("There was an error trying to write to disk named `{$diskName}`");
|
||||
}
|
||||
}
|
||||
23
vendor/spatie/laravel-backup/src/Exceptions/InvalidBackupJob.php
vendored
Normal file
23
vendor/spatie/laravel-backup/src/Exceptions/InvalidBackupJob.php
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace Spatie\Backup\Exceptions;
|
||||
|
||||
use Exception;
|
||||
|
||||
class InvalidBackupJob extends Exception
|
||||
{
|
||||
public static function noDestinationsSpecified(): self
|
||||
{
|
||||
return new static('A backup job cannot run without a destination to backup to!');
|
||||
}
|
||||
|
||||
public static function destinationDoesNotExist(string $diskName): self
|
||||
{
|
||||
return new static("There is no backup destination with a disk named `{$diskName}`.");
|
||||
}
|
||||
|
||||
public static function noFilesToBeBackedUp(): self
|
||||
{
|
||||
return new static('There are no files to be backed up.');
|
||||
}
|
||||
}
|
||||
13
vendor/spatie/laravel-backup/src/Exceptions/InvalidCommand.php
vendored
Normal file
13
vendor/spatie/laravel-backup/src/Exceptions/InvalidCommand.php
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
namespace Spatie\Backup\Exceptions;
|
||||
|
||||
use Exception;
|
||||
|
||||
class InvalidCommand extends Exception
|
||||
{
|
||||
public static function create(string $reason): self
|
||||
{
|
||||
return new static($reason);
|
||||
}
|
||||
}
|
||||
13
vendor/spatie/laravel-backup/src/Exceptions/InvalidConfiguration.php
vendored
Normal file
13
vendor/spatie/laravel-backup/src/Exceptions/InvalidConfiguration.php
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
namespace Spatie\Backup\Exceptions;
|
||||
|
||||
use Exception;
|
||||
|
||||
class InvalidConfiguration extends Exception
|
||||
{
|
||||
public static function cannotUseUnsupportedDriver(string $connectionName, string $driverName): self
|
||||
{
|
||||
return new static("Db connection `{$connectionName}` uses an unsupported driver `{$driverName}`. Only `mysql` and `pgsql` are supported.");
|
||||
}
|
||||
}
|
||||
13
vendor/spatie/laravel-backup/src/Exceptions/InvalidHealthCheck.php
vendored
Normal file
13
vendor/spatie/laravel-backup/src/Exceptions/InvalidHealthCheck.php
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
namespace Spatie\Backup\Exceptions;
|
||||
|
||||
use Exception;
|
||||
|
||||
class InvalidHealthCheck extends Exception
|
||||
{
|
||||
public static function because(string $message): self
|
||||
{
|
||||
return new static($message);
|
||||
}
|
||||
}
|
||||
15
vendor/spatie/laravel-backup/src/Exceptions/NotificationCouldNotBeSent.php
vendored
Normal file
15
vendor/spatie/laravel-backup/src/Exceptions/NotificationCouldNotBeSent.php
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
namespace Spatie\Backup\Exceptions;
|
||||
|
||||
use Exception;
|
||||
|
||||
class NotificationCouldNotBeSent extends Exception
|
||||
{
|
||||
public static function noNotificationClassForEvent($event): self
|
||||
{
|
||||
$eventClass = get_class($event);
|
||||
|
||||
return new static("There is no notification class that can handle event `{$eventClass}`.");
|
||||
}
|
||||
}
|
||||
28
vendor/spatie/laravel-backup/src/Helpers/ConsoleOutput.php
vendored
Normal file
28
vendor/spatie/laravel-backup/src/Helpers/ConsoleOutput.php
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace Spatie\Backup\Helpers;
|
||||
|
||||
class ConsoleOutput
|
||||
{
|
||||
/** @var \Illuminate\Console\OutputStyle */
|
||||
protected $output;
|
||||
|
||||
/**
|
||||
* @param \Illuminate\Console\OutputStyle $output
|
||||
*/
|
||||
public function setOutput($output)
|
||||
{
|
||||
$this->output = $output;
|
||||
}
|
||||
|
||||
public function __call(string $method, array $arguments)
|
||||
{
|
||||
$consoleOutput = app(static::class);
|
||||
|
||||
if (! $consoleOutput->output) {
|
||||
return;
|
||||
}
|
||||
|
||||
$consoleOutput->output->$method($arguments[0]);
|
||||
}
|
||||
}
|
||||
49
vendor/spatie/laravel-backup/src/Helpers/File.php
vendored
Normal file
49
vendor/spatie/laravel-backup/src/Helpers/File.php
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
namespace Spatie\Backup\Helpers;
|
||||
|
||||
use Exception;
|
||||
use Illuminate\Contracts\Filesystem\Filesystem;
|
||||
|
||||
class File
|
||||
{
|
||||
/** @var array */
|
||||
protected static $allowedMimeTypes = [
|
||||
'application/zip',
|
||||
'application/x-zip',
|
||||
'application/x-gzip',
|
||||
];
|
||||
|
||||
public function isZipFile(?Filesystem $disk, string $path): bool
|
||||
{
|
||||
if ($this->hasZipExtension($path)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return $this->hasAllowedMimeType($disk, $path);
|
||||
}
|
||||
|
||||
protected function hasZipExtension(string $path): bool
|
||||
{
|
||||
return pathinfo($path, PATHINFO_EXTENSION) === 'zip';
|
||||
}
|
||||
|
||||
protected function hasAllowedMimeType(?Filesystem $disk, string $path)
|
||||
{
|
||||
return in_array($this->mimeType($disk, $path), self::$allowedMimeTypes);
|
||||
}
|
||||
|
||||
protected function mimeType(?Filesystem $disk, string $path)
|
||||
{
|
||||
try {
|
||||
if ($disk && method_exists($disk, 'mimeType')) {
|
||||
return $disk->mimeType($path) ?: false;
|
||||
}
|
||||
} catch (Exception $exception) {
|
||||
// Some drivers throw exceptions when checking mime types, we'll
|
||||
// just fallback to `false`.
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
36
vendor/spatie/laravel-backup/src/Helpers/Format.php
vendored
Normal file
36
vendor/spatie/laravel-backup/src/Helpers/Format.php
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace Spatie\Backup\Helpers;
|
||||
|
||||
use Carbon\Carbon;
|
||||
|
||||
class Format
|
||||
{
|
||||
public static function humanReadableSize(float $sizeInBytes): string
|
||||
{
|
||||
$units = ['B', 'KB', 'MB', 'GB', 'TB'];
|
||||
|
||||
if ($sizeInBytes === 0) {
|
||||
return '0 '.$units[1];
|
||||
}
|
||||
for ($i = 0; $sizeInBytes > 1024; $i++) {
|
||||
$sizeInBytes /= 1024;
|
||||
}
|
||||
|
||||
return round($sizeInBytes, 2).' '.$units[$i];
|
||||
}
|
||||
|
||||
public static function emoji(bool $bool): string
|
||||
{
|
||||
if ($bool) {
|
||||
return '✅';
|
||||
}
|
||||
|
||||
return '❌';
|
||||
}
|
||||
|
||||
public static function ageInDays(Carbon $date): string
|
||||
{
|
||||
return number_format(round($date->diffInMinutes() / (24 * 60), 2), 2).' ('.$date->diffForHumans().')';
|
||||
}
|
||||
}
|
||||
13
vendor/spatie/laravel-backup/src/Helpers/RightAlignedTableStyle.php
vendored
Normal file
13
vendor/spatie/laravel-backup/src/Helpers/RightAlignedTableStyle.php
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
namespace Spatie\Backup\Helpers;
|
||||
|
||||
use Symfony\Component\Console\Helper\TableStyle;
|
||||
|
||||
class RightAlignedTableStyle extends TableStyle
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
$this->setPadType(STR_PAD_LEFT);
|
||||
}
|
||||
}
|
||||
8
vendor/spatie/laravel-backup/src/Helpers/functions.php
vendored
Normal file
8
vendor/spatie/laravel-backup/src/Helpers/functions.php
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
use Spatie\Backup\Helpers\ConsoleOutput;
|
||||
|
||||
function consoleOutput(): ConsoleOutput
|
||||
{
|
||||
return app(ConsoleOutput::class);
|
||||
}
|
||||
71
vendor/spatie/laravel-backup/src/Listeners/EncryptBackupArchive.php
vendored
Normal file
71
vendor/spatie/laravel-backup/src/Listeners/EncryptBackupArchive.php
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
<?php
|
||||
|
||||
namespace Spatie\Backup\Listeners;
|
||||
|
||||
use Spatie\Backup\Events\BackupZipWasCreated;
|
||||
use ZipArchive;
|
||||
|
||||
class EncryptBackupArchive
|
||||
{
|
||||
public function handle(BackupZipWasCreated $event): void
|
||||
{
|
||||
if (! $this->shouldEncrypt()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$zip = new ZipArchive;
|
||||
|
||||
$zip->open($event->pathToZip);
|
||||
|
||||
$this->encrypt($zip);
|
||||
|
||||
$zip->close();
|
||||
}
|
||||
|
||||
protected function encrypt(ZipArchive $zip): void
|
||||
{
|
||||
$zip->setPassword(static::getPassword());
|
||||
|
||||
foreach (range(0, $zip->numFiles - 1) as $i) {
|
||||
$zip->setEncryptionIndex($i, static::getAlgorithm());
|
||||
}
|
||||
}
|
||||
|
||||
public static function shouldEncrypt(): bool
|
||||
{
|
||||
$password = static::getPassword();
|
||||
$algorithm = static::getAlgorithm();
|
||||
|
||||
if ($password === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($algorithm === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($algorithm === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected static function getPassword(): ?string
|
||||
{
|
||||
return config('backup.backup.password');
|
||||
}
|
||||
|
||||
protected static function getAlgorithm(): ?int
|
||||
{
|
||||
$encryption = config('backup.backup.encryption');
|
||||
|
||||
if ($encryption === 'default') {
|
||||
$encryption = defined("\ZipArchive::EM_AES_256")
|
||||
? ZipArchive::EM_AES_256
|
||||
: null;
|
||||
}
|
||||
|
||||
return $encryption;
|
||||
}
|
||||
}
|
||||
71
vendor/spatie/laravel-backup/src/Notifications/BaseNotification.php
vendored
Normal file
71
vendor/spatie/laravel-backup/src/Notifications/BaseNotification.php
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
<?php
|
||||
|
||||
namespace Spatie\Backup\Notifications;
|
||||
|
||||
use Illuminate\Notifications\Notification;
|
||||
use Illuminate\Support\Collection;
|
||||
use Spatie\Backup\BackupDestination\BackupDestination;
|
||||
use Spatie\Backup\Helpers\Format;
|
||||
|
||||
abstract class BaseNotification extends Notification
|
||||
{
|
||||
public function via(): array
|
||||
{
|
||||
$notificationChannels = config('backup.notifications.notifications.'.static::class);
|
||||
|
||||
return array_filter($notificationChannels);
|
||||
}
|
||||
|
||||
public function applicationName(): string
|
||||
{
|
||||
return config('app.name') ?? config('app.url') ?? 'Laravel application';
|
||||
}
|
||||
|
||||
public function backupName(): string
|
||||
{
|
||||
return $this->backupDestination()->backupName();
|
||||
}
|
||||
|
||||
public function diskName(): string
|
||||
{
|
||||
return $this->backupDestination()->diskName();
|
||||
}
|
||||
|
||||
protected function backupDestinationProperties(): Collection
|
||||
{
|
||||
$backupDestination = $this->backupDestination();
|
||||
|
||||
if (! $backupDestination) {
|
||||
return collect();
|
||||
}
|
||||
|
||||
$backupDestination->fresh();
|
||||
|
||||
$newestBackup = $backupDestination->newestBackup();
|
||||
$oldestBackup = $backupDestination->oldestBackup();
|
||||
|
||||
return collect([
|
||||
'Application name' => $this->applicationName(),
|
||||
'Backup name' => $this->backupName(),
|
||||
'Disk' => $backupDestination->diskName(),
|
||||
'Newest backup size' => $newestBackup ? Format::humanReadableSize($newestBackup->size()) : 'No backups were made yet',
|
||||
'Number of backups' => (string) $backupDestination->backups()->count(),
|
||||
'Total storage used' => Format::humanReadableSize($backupDestination->backups()->size()),
|
||||
'Newest backup date' => $newestBackup ? $newestBackup->date()->format('Y/m/d H:i:s') : 'No backups were made yet',
|
||||
'Oldest backup date' => $oldestBackup ? $oldestBackup->date()->format('Y/m/d H:i:s') : 'No backups were made yet',
|
||||
])->filter();
|
||||
}
|
||||
|
||||
public function backupDestination(): ?BackupDestination
|
||||
{
|
||||
if (isset($this->event->backupDestination)) {
|
||||
return $this->event->backupDestination;
|
||||
}
|
||||
|
||||
if (isset($this->event->backupDestinationStatus)) {
|
||||
return $this->event->backupDestinationStatus->backupDestination();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
74
vendor/spatie/laravel-backup/src/Notifications/EventHandler.php
vendored
Normal file
74
vendor/spatie/laravel-backup/src/Notifications/EventHandler.php
vendored
Normal file
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
|
||||
namespace Spatie\Backup\Notifications;
|
||||
|
||||
use Illuminate\Contracts\Config\Repository;
|
||||
use Illuminate\Contracts\Events\Dispatcher;
|
||||
use Illuminate\Notifications\Notification;
|
||||
use Spatie\Backup\Events\BackupHasFailed;
|
||||
use Spatie\Backup\Events\BackupWasSuccessful;
|
||||
use Spatie\Backup\Events\CleanupHasFailed;
|
||||
use Spatie\Backup\Events\CleanupWasSuccessful;
|
||||
use Spatie\Backup\Events\HealthyBackupWasFound;
|
||||
use Spatie\Backup\Events\UnhealthyBackupWasFound;
|
||||
use Spatie\Backup\Exceptions\NotificationCouldNotBeSent;
|
||||
|
||||
class EventHandler
|
||||
{
|
||||
/** @var \Illuminate\Contracts\Config\Repository */
|
||||
protected $config;
|
||||
|
||||
public function __construct(Repository $config)
|
||||
{
|
||||
$this->config = $config;
|
||||
}
|
||||
|
||||
public function subscribe(Dispatcher $events)
|
||||
{
|
||||
$events->listen($this->allBackupEventClasses(), function ($event) {
|
||||
$notifiable = $this->determineNotifiable();
|
||||
|
||||
$notification = $this->determineNotification($event);
|
||||
|
||||
$notifiable->notify($notification);
|
||||
});
|
||||
}
|
||||
|
||||
protected function determineNotifiable()
|
||||
{
|
||||
$notifiableClass = $this->config->get('backup.notifications.notifiable');
|
||||
|
||||
return app($notifiableClass);
|
||||
}
|
||||
|
||||
protected function determineNotification($event): Notification
|
||||
{
|
||||
$eventName = class_basename($event);
|
||||
|
||||
$notificationClass = collect($this->config->get('backup.notifications.notifications'))
|
||||
->keys()
|
||||
->first(function ($notificationClass) use ($eventName) {
|
||||
$notificationName = class_basename($notificationClass);
|
||||
|
||||
return $notificationName === $eventName;
|
||||
});
|
||||
|
||||
if (! $notificationClass) {
|
||||
throw NotificationCouldNotBeSent::noNotificationClassForEvent($event);
|
||||
}
|
||||
|
||||
return new $notificationClass($event);
|
||||
}
|
||||
|
||||
protected function allBackupEventClasses(): array
|
||||
{
|
||||
return [
|
||||
BackupHasFailed::class,
|
||||
BackupWasSuccessful::class,
|
||||
CleanupHasFailed::class,
|
||||
CleanupWasSuccessful::class,
|
||||
HealthyBackupWasFound::class,
|
||||
UnhealthyBackupWasFound::class,
|
||||
];
|
||||
}
|
||||
}
|
||||
25
vendor/spatie/laravel-backup/src/Notifications/Notifiable.php
vendored
Normal file
25
vendor/spatie/laravel-backup/src/Notifications/Notifiable.php
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace Spatie\Backup\Notifications;
|
||||
|
||||
use Illuminate\Notifications\Notifiable as NotifiableTrait;
|
||||
|
||||
class Notifiable
|
||||
{
|
||||
use NotifiableTrait;
|
||||
|
||||
public function routeNotificationForMail()
|
||||
{
|
||||
return config('backup.notifications.mail.to');
|
||||
}
|
||||
|
||||
public function routeNotificationForSlack()
|
||||
{
|
||||
return config('backup.notifications.slack.webhook_url');
|
||||
}
|
||||
|
||||
public function getKey()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
59
vendor/spatie/laravel-backup/src/Notifications/Notifications/BackupHasFailed.php
vendored
Normal file
59
vendor/spatie/laravel-backup/src/Notifications/Notifications/BackupHasFailed.php
vendored
Normal file
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
namespace Spatie\Backup\Notifications\Notifications;
|
||||
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
use Illuminate\Notifications\Messages\SlackAttachment;
|
||||
use Illuminate\Notifications\Messages\SlackMessage;
|
||||
use Spatie\Backup\Events\BackupHasFailed as BackupHasFailedEvent;
|
||||
use Spatie\Backup\Notifications\BaseNotification;
|
||||
|
||||
class BackupHasFailed extends BaseNotification
|
||||
{
|
||||
/** @var \Spatie\Backup\Events\BackupHasFailed */
|
||||
protected $event;
|
||||
|
||||
public function __construct(BackupHasFailedEvent $event)
|
||||
{
|
||||
$this->event = $event;
|
||||
}
|
||||
|
||||
public function toMail(): MailMessage
|
||||
{
|
||||
$mailMessage = (new MailMessage)
|
||||
->error()
|
||||
->from(config('backup.notifications.mail.from.address', config('mail.from.address')), config('backup.notifications.mail.from.name', config('mail.from.name')))
|
||||
->subject(trans('backup::notifications.backup_failed_subject', ['application_name' => $this->applicationName()]))
|
||||
->line(trans('backup::notifications.backup_failed_body', ['application_name' => $this->applicationName()]))
|
||||
->line(trans('backup::notifications.exception_message', ['message' => $this->event->exception->getMessage()]))
|
||||
->line(trans('backup::notifications.exception_trace', ['trace' => $this->event->exception->getTraceAsString()]));
|
||||
|
||||
$this->backupDestinationProperties()->each(function ($value, $name) use ($mailMessage) {
|
||||
$mailMessage->line("{$name}: $value");
|
||||
});
|
||||
|
||||
return $mailMessage;
|
||||
}
|
||||
|
||||
public function toSlack(): SlackMessage
|
||||
{
|
||||
return (new SlackMessage)
|
||||
->error()
|
||||
->from(config('backup.notifications.slack.username'), config('backup.notifications.slack.icon'))
|
||||
->to(config('backup.notifications.slack.channel'))
|
||||
->content(trans('backup::notifications.backup_failed_subject', ['application_name' => $this->applicationName()]))
|
||||
->attachment(function (SlackAttachment $attachment) {
|
||||
$attachment
|
||||
->title(trans('backup::notifications.exception_message_title'))
|
||||
->content($this->event->exception->getMessage());
|
||||
})
|
||||
->attachment(function (SlackAttachment $attachment) {
|
||||
$attachment
|
||||
->title(trans('backup::notifications.exception_trace_title'))
|
||||
->content($this->event->exception->getTraceAsString());
|
||||
})
|
||||
->attachment(function (SlackAttachment $attachment) {
|
||||
$attachment->fields($this->backupDestinationProperties()->toArray());
|
||||
});
|
||||
}
|
||||
}
|
||||
46
vendor/spatie/laravel-backup/src/Notifications/Notifications/BackupWasSuccessful.php
vendored
Normal file
46
vendor/spatie/laravel-backup/src/Notifications/Notifications/BackupWasSuccessful.php
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
namespace Spatie\Backup\Notifications\Notifications;
|
||||
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
use Illuminate\Notifications\Messages\SlackAttachment;
|
||||
use Illuminate\Notifications\Messages\SlackMessage;
|
||||
use Spatie\Backup\Events\BackupWasSuccessful as BackupWasSuccessfulEvent;
|
||||
use Spatie\Backup\Notifications\BaseNotification;
|
||||
|
||||
class BackupWasSuccessful extends BaseNotification
|
||||
{
|
||||
/** @var \Spatie\Backup\Events\BackupWasSuccessful */
|
||||
protected $event;
|
||||
|
||||
public function __construct(BackupWasSuccessfulEvent $event)
|
||||
{
|
||||
$this->event = $event;
|
||||
}
|
||||
|
||||
public function toMail(): MailMessage
|
||||
{
|
||||
$mailMessage = (new MailMessage)
|
||||
->from(config('backup.notifications.mail.from.address', config('mail.from.address')), config('backup.notifications.mail.from.name', config('mail.from.name')))
|
||||
->subject(trans('backup::notifications.backup_successful_subject', ['application_name' => $this->applicationName()]))
|
||||
->line(trans('backup::notifications.backup_successful_body', ['application_name' => $this->applicationName(), 'disk_name' => $this->diskName()]));
|
||||
|
||||
$this->backupDestinationProperties()->each(function ($value, $name) use ($mailMessage) {
|
||||
$mailMessage->line("{$name}: $value");
|
||||
});
|
||||
|
||||
return $mailMessage;
|
||||
}
|
||||
|
||||
public function toSlack(): SlackMessage
|
||||
{
|
||||
return (new SlackMessage)
|
||||
->success()
|
||||
->from(config('backup.notifications.slack.username'), config('backup.notifications.slack.icon'))
|
||||
->to(config('backup.notifications.slack.channel'))
|
||||
->content(trans('backup::notifications.backup_successful_subject_title'))
|
||||
->attachment(function (SlackAttachment $attachment) {
|
||||
$attachment->fields($this->backupDestinationProperties()->toArray());
|
||||
});
|
||||
}
|
||||
}
|
||||
59
vendor/spatie/laravel-backup/src/Notifications/Notifications/CleanupHasFailed.php
vendored
Normal file
59
vendor/spatie/laravel-backup/src/Notifications/Notifications/CleanupHasFailed.php
vendored
Normal file
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
namespace Spatie\Backup\Notifications\Notifications;
|
||||
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
use Illuminate\Notifications\Messages\SlackAttachment;
|
||||
use Illuminate\Notifications\Messages\SlackMessage;
|
||||
use Spatie\Backup\Events\CleanupHasFailed as CleanupHasFailedEvent;
|
||||
use Spatie\Backup\Notifications\BaseNotification;
|
||||
|
||||
class CleanupHasFailed extends BaseNotification
|
||||
{
|
||||
/** @var \Spatie\Backup\Events\CleanupHasFailed */
|
||||
protected $event;
|
||||
|
||||
public function __construct(CleanupHasFailedEvent $event)
|
||||
{
|
||||
$this->event = $event;
|
||||
}
|
||||
|
||||
public function toMail(): MailMessage
|
||||
{
|
||||
$mailMessage = (new MailMessage)
|
||||
->error()
|
||||
->from(config('backup.notifications.mail.from.address', config('mail.from.address')), config('backup.notifications.mail.from.name', config('mail.from.name')))
|
||||
->subject(trans('backup::notifications.cleanup_failed_subject', ['application_name' => $this->applicationName()]))
|
||||
->line(trans('backup::notifications.cleanup_failed_body', ['application_name' => $this->applicationName()]))
|
||||
->line(trans('backup::notifications.exception_message', ['message' => $this->event->exception->getMessage()]))
|
||||
->line(trans('backup::notifications.exception_trace', ['trace' => $this->event->exception->getTraceAsString()]));
|
||||
|
||||
$this->backupDestinationProperties()->each(function ($value, $name) use ($mailMessage) {
|
||||
$mailMessage->line("{$name}: $value");
|
||||
});
|
||||
|
||||
return $mailMessage;
|
||||
}
|
||||
|
||||
public function toSlack(): SlackMessage
|
||||
{
|
||||
return (new SlackMessage)
|
||||
->error()
|
||||
->from(config('backup.notifications.slack.username'), config('backup.notifications.slack.icon'))
|
||||
->to(config('backup.notifications.slack.channel'))
|
||||
->content(trans('backup::notifications.cleanup_failed_subject', ['application_name' => $this->applicationName()]))
|
||||
->attachment(function (SlackAttachment $attachment) {
|
||||
$attachment
|
||||
->title(trans('backup::notifications.exception_message_title'))
|
||||
->content($this->event->exception->getMessage());
|
||||
})
|
||||
->attachment(function (SlackAttachment $attachment) {
|
||||
$attachment
|
||||
->title(trans('backup::notifications.exception_message_trace'))
|
||||
->content($this->event->exception->getTraceAsString());
|
||||
})
|
||||
->attachment(function (SlackAttachment $attachment) {
|
||||
$attachment->fields($this->backupDestinationProperties()->toArray());
|
||||
});
|
||||
}
|
||||
}
|
||||
46
vendor/spatie/laravel-backup/src/Notifications/Notifications/CleanupWasSuccessful.php
vendored
Normal file
46
vendor/spatie/laravel-backup/src/Notifications/Notifications/CleanupWasSuccessful.php
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
namespace Spatie\Backup\Notifications\Notifications;
|
||||
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
use Illuminate\Notifications\Messages\SlackAttachment;
|
||||
use Illuminate\Notifications\Messages\SlackMessage;
|
||||
use Spatie\Backup\Events\CleanupWasSuccessful as CleanupWasSuccessfulEvent;
|
||||
use Spatie\Backup\Notifications\BaseNotification;
|
||||
|
||||
class CleanupWasSuccessful extends BaseNotification
|
||||
{
|
||||
/** @var \Spatie\Backup\Events\CleanupWasSuccessful */
|
||||
protected $event;
|
||||
|
||||
public function __construct(CleanupWasSuccessfulEvent $event)
|
||||
{
|
||||
$this->event = $event;
|
||||
}
|
||||
|
||||
public function toMail(): MailMessage
|
||||
{
|
||||
$mailMessage = (new MailMessage)
|
||||
->from(config('backup.notifications.mail.from.address', config('mail.from.address')), config('backup.notifications.mail.from.name', config('mail.from.name')))
|
||||
->subject(trans('backup::notifications.cleanup_successful_subject', ['application_name' => $this->applicationName()]))
|
||||
->line(trans('backup::notifications.cleanup_successful_body', ['application_name' => $this->applicationName(), 'disk_name' => $this->diskName()]));
|
||||
|
||||
$this->backupDestinationProperties()->each(function ($value, $name) use ($mailMessage) {
|
||||
$mailMessage->line("{$name}: $value");
|
||||
});
|
||||
|
||||
return $mailMessage;
|
||||
}
|
||||
|
||||
public function toSlack(): SlackMessage
|
||||
{
|
||||
return (new SlackMessage)
|
||||
->success()
|
||||
->from(config('backup.notifications.slack.username'), config('backup.notifications.slack.icon'))
|
||||
->to(config('backup.notifications.slack.channel'))
|
||||
->content(trans('backup::notifications.cleanup_successful_subject_title'))
|
||||
->attachment(function (SlackAttachment $attachment) {
|
||||
$attachment->fields($this->backupDestinationProperties()->toArray());
|
||||
});
|
||||
}
|
||||
}
|
||||
46
vendor/spatie/laravel-backup/src/Notifications/Notifications/HealthyBackupWasFound.php
vendored
Normal file
46
vendor/spatie/laravel-backup/src/Notifications/Notifications/HealthyBackupWasFound.php
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
namespace Spatie\Backup\Notifications\Notifications;
|
||||
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
use Illuminate\Notifications\Messages\SlackAttachment;
|
||||
use Illuminate\Notifications\Messages\SlackMessage;
|
||||
use Spatie\Backup\Events\HealthyBackupWasFound as HealthyBackupWasFoundEvent;
|
||||
use Spatie\Backup\Notifications\BaseNotification;
|
||||
|
||||
class HealthyBackupWasFound extends BaseNotification
|
||||
{
|
||||
/** @var \Spatie\Backup\Events\HealthyBackupWasFound */
|
||||
protected $event;
|
||||
|
||||
public function __construct(HealthyBackupWasFoundEvent $event)
|
||||
{
|
||||
$this->event = $event;
|
||||
}
|
||||
|
||||
public function toMail(): MailMessage
|
||||
{
|
||||
$mailMessage = (new MailMessage)
|
||||
->from(config('backup.notifications.mail.from.address', config('mail.from.address')), config('backup.notifications.mail.from.name', config('mail.from.name')))
|
||||
->subject(trans('backup::notifications.healthy_backup_found_subject', ['application_name' => $this->applicationName(), 'disk_name' => $this->diskName()]))
|
||||
->line(trans('backup::notifications.healthy_backup_found_body', ['application_name' => $this->applicationName()]));
|
||||
|
||||
$this->backupDestinationProperties()->each(function ($value, $name) use ($mailMessage) {
|
||||
$mailMessage->line("{$name}: $value");
|
||||
});
|
||||
|
||||
return $mailMessage;
|
||||
}
|
||||
|
||||
public function toSlack(): SlackMessage
|
||||
{
|
||||
return (new SlackMessage)
|
||||
->success()
|
||||
->from(config('backup.notifications.slack.username'), config('backup.notifications.slack.icon'))
|
||||
->to(config('backup.notifications.slack.channel'))
|
||||
->content(trans('backup::notifications.healthy_backup_found_subject_title', ['application_name' => $this->applicationName()]))
|
||||
->attachment(function (SlackAttachment $attachment) {
|
||||
$attachment->fields($this->backupDestinationProperties()->toArray());
|
||||
});
|
||||
}
|
||||
}
|
||||
91
vendor/spatie/laravel-backup/src/Notifications/Notifications/UnhealthyBackupWasFound.php
vendored
Normal file
91
vendor/spatie/laravel-backup/src/Notifications/Notifications/UnhealthyBackupWasFound.php
vendored
Normal file
@@ -0,0 +1,91 @@
|
||||
<?php
|
||||
|
||||
namespace Spatie\Backup\Notifications\Notifications;
|
||||
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
use Illuminate\Notifications\Messages\SlackAttachment;
|
||||
use Illuminate\Notifications\Messages\SlackMessage;
|
||||
use Spatie\Backup\Events\UnhealthyBackupWasFound as UnhealthyBackupWasFoundEvent;
|
||||
use Spatie\Backup\Notifications\BaseNotification;
|
||||
use Spatie\Backup\Tasks\Monitor\HealthCheckFailure;
|
||||
|
||||
class UnhealthyBackupWasFound extends BaseNotification
|
||||
{
|
||||
/** @var \Spatie\Backup\Events\UnhealthyBackupWasFound */
|
||||
protected $event;
|
||||
|
||||
public function __construct(UnhealthyBackupWasFoundEvent $event)
|
||||
{
|
||||
$this->event = $event;
|
||||
}
|
||||
|
||||
public function toMail(): MailMessage
|
||||
{
|
||||
$mailMessage = (new MailMessage)
|
||||
->error()
|
||||
->from(config('backup.notifications.mail.from.address', config('mail.from.address')), config('backup.notifications.mail.from.name', config('mail.from.name')))
|
||||
->subject(trans('backup::notifications.unhealthy_backup_found_subject', ['application_name' => $this->applicationName()]))
|
||||
->line(trans('backup::notifications.unhealthy_backup_found_body', ['application_name' => $this->applicationName(), 'disk_name' => $this->diskName()]))
|
||||
->line($this->problemDescription());
|
||||
|
||||
$this->backupDestinationProperties()->each(function ($value, $name) use ($mailMessage) {
|
||||
$mailMessage->line("{$name}: $value");
|
||||
});
|
||||
|
||||
if ($this->failure()->wasUnexpected()) {
|
||||
$mailMessage
|
||||
->line('Health check: '.$this->failure()->healthCheck()->name())
|
||||
->line(trans('backup::notifications.exception_message', ['message' => $this->failure()->exception()->getMessage()]))
|
||||
->line(trans('backup::notifications.exception_trace', ['trace' => $this->failure()->exception()->getTraceAsString()]));
|
||||
}
|
||||
|
||||
return $mailMessage;
|
||||
}
|
||||
|
||||
public function toSlack(): SlackMessage
|
||||
{
|
||||
$slackMessage = (new SlackMessage)
|
||||
->error()
|
||||
->from(config('backup.notifications.slack.username'), config('backup.notifications.slack.icon'))
|
||||
->to(config('backup.notifications.slack.channel'))
|
||||
->content(trans('backup::notifications.unhealthy_backup_found_subject_title', ['application_name' => $this->applicationName(), 'problem' => $this->problemDescription()]))
|
||||
->attachment(function (SlackAttachment $attachment) {
|
||||
$attachment->fields($this->backupDestinationProperties()->toArray());
|
||||
});
|
||||
|
||||
if ($this->failure()->wasUnexpected()) {
|
||||
$slackMessage
|
||||
->attachment(function (SlackAttachment $attachment) {
|
||||
$attachment
|
||||
->title('Health check')
|
||||
->content($this->failure()->healthCheck()->name());
|
||||
})
|
||||
->attachment(function (SlackAttachment $attachment) {
|
||||
$attachment
|
||||
->title(trans('backup::notifications.exception_message_title'))
|
||||
->content($this->failure()->exception()->getMessage());
|
||||
})
|
||||
->attachment(function (SlackAttachment $attachment) {
|
||||
$attachment
|
||||
->title(trans('backup::notifications.exception_trace_title'))
|
||||
->content($this->failure()->exception()->getTraceAsString());
|
||||
});
|
||||
}
|
||||
|
||||
return $slackMessage;
|
||||
}
|
||||
|
||||
protected function problemDescription(): string
|
||||
{
|
||||
if ($this->failure()->wasUnexpected()) {
|
||||
return trans('backup::notifications.unhealthy_backup_found_unknown');
|
||||
}
|
||||
|
||||
return $this->failure()->exception()->getMessage();
|
||||
}
|
||||
|
||||
protected function failure(): HealthCheckFailure
|
||||
{
|
||||
return $this->event->backupDestinationStatus->getHealthCheckFailure();
|
||||
}
|
||||
}
|
||||
306
vendor/spatie/laravel-backup/src/Tasks/Backup/BackupJob.php
vendored
Normal file
306
vendor/spatie/laravel-backup/src/Tasks/Backup/BackupJob.php
vendored
Normal file
@@ -0,0 +1,306 @@
|
||||
<?php
|
||||
|
||||
namespace Spatie\Backup\Tasks\Backup;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Exception;
|
||||
use Illuminate\Support\Collection;
|
||||
use Spatie\Backup\BackupDestination\BackupDestination;
|
||||
use Spatie\Backup\Events\BackupHasFailed;
|
||||
use Spatie\Backup\Events\BackupManifestWasCreated;
|
||||
use Spatie\Backup\Events\BackupWasSuccessful;
|
||||
use Spatie\Backup\Events\BackupZipWasCreated;
|
||||
use Spatie\Backup\Events\DumpingDatabase;
|
||||
use Spatie\Backup\Exceptions\InvalidBackupJob;
|
||||
use Spatie\DbDumper\Compressors\GzipCompressor;
|
||||
use Spatie\DbDumper\Databases\MongoDb;
|
||||
use Spatie\DbDumper\Databases\Sqlite;
|
||||
use Spatie\DbDumper\DbDumper;
|
||||
use Spatie\TemporaryDirectory\TemporaryDirectory;
|
||||
|
||||
class BackupJob
|
||||
{
|
||||
public const FILENAME_FORMAT = 'Y-m-d-H-i-s.\z\i\p';
|
||||
|
||||
/** @var \Spatie\Backup\Tasks\Backup\FileSelection */
|
||||
protected $fileSelection;
|
||||
|
||||
/** @var \Illuminate\Support\Collection */
|
||||
protected $dbDumpers;
|
||||
|
||||
/** @var \Illuminate\Support\Collection */
|
||||
protected $backupDestinations;
|
||||
|
||||
/** @var string */
|
||||
protected $filename;
|
||||
|
||||
/** @var \Spatie\TemporaryDirectory\TemporaryDirectory */
|
||||
protected $temporaryDirectory;
|
||||
|
||||
/** @var bool */
|
||||
protected $sendNotifications = true;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->dontBackupFilesystem();
|
||||
$this->dontBackupDatabases();
|
||||
$this->setDefaultFilename();
|
||||
|
||||
$this->backupDestinations = new Collection();
|
||||
}
|
||||
|
||||
public function dontBackupFilesystem(): self
|
||||
{
|
||||
$this->fileSelection = FileSelection::create();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function onlyDbName(array $allowedDbNames): self
|
||||
{
|
||||
$this->dbDumpers = $this->dbDumpers->filter(
|
||||
function (DbDumper $dbDumper, string $connectionName) use ($allowedDbNames) {
|
||||
return in_array($connectionName, $allowedDbNames);
|
||||
}
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function dontBackupDatabases(): self
|
||||
{
|
||||
$this->dbDumpers = new Collection();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function disableNotifications(): self
|
||||
{
|
||||
$this->sendNotifications = false;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setDefaultFilename(): self
|
||||
{
|
||||
$this->filename = Carbon::now()->format(static::FILENAME_FORMAT);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setFileSelection(FileSelection $fileSelection): self
|
||||
{
|
||||
$this->fileSelection = $fileSelection;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setDbDumpers(Collection $dbDumpers): self
|
||||
{
|
||||
$this->dbDumpers = $dbDumpers;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setFilename(string $filename): self
|
||||
{
|
||||
$this->filename = $filename;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function onlyBackupTo(string $diskName): self
|
||||
{
|
||||
$this->backupDestinations = $this->backupDestinations->filter(function (BackupDestination $backupDestination) use ($diskName) {
|
||||
return $backupDestination->diskName() === $diskName;
|
||||
});
|
||||
|
||||
if (! count($this->backupDestinations)) {
|
||||
throw InvalidBackupJob::destinationDoesNotExist($diskName);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setBackupDestinations(Collection $backupDestinations): self
|
||||
{
|
||||
$this->backupDestinations = $backupDestinations;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function run()
|
||||
{
|
||||
$temporaryDirectoryPath = config('backup.backup.temporary_directory') ?? storage_path('app/backup-temp');
|
||||
|
||||
$this->temporaryDirectory = (new TemporaryDirectory($temporaryDirectoryPath))
|
||||
->name('temp')
|
||||
->force()
|
||||
->create()
|
||||
->empty();
|
||||
|
||||
try {
|
||||
if (! count($this->backupDestinations)) {
|
||||
throw InvalidBackupJob::noDestinationsSpecified();
|
||||
}
|
||||
|
||||
$manifest = $this->createBackupManifest();
|
||||
|
||||
if (! $manifest->count()) {
|
||||
throw InvalidBackupJob::noFilesToBeBackedUp();
|
||||
}
|
||||
|
||||
$zipFile = $this->createZipContainingEveryFileInManifest($manifest);
|
||||
|
||||
$this->copyToBackupDestinations($zipFile);
|
||||
} catch (Exception $exception) {
|
||||
consoleOutput()->error("Backup failed because {$exception->getMessage()}.".PHP_EOL.$exception->getTraceAsString());
|
||||
|
||||
$this->sendNotification(new BackupHasFailed($exception));
|
||||
|
||||
$this->temporaryDirectory->delete();
|
||||
|
||||
throw $exception;
|
||||
}
|
||||
|
||||
$this->temporaryDirectory->delete();
|
||||
}
|
||||
|
||||
protected function createBackupManifest(): Manifest
|
||||
{
|
||||
$databaseDumps = $this->dumpDatabases();
|
||||
|
||||
consoleOutput()->info('Determining files to backup...');
|
||||
|
||||
$manifest = Manifest::create($this->temporaryDirectory->path('manifest.txt'))
|
||||
->addFiles($databaseDumps)
|
||||
->addFiles($this->filesToBeBackedUp());
|
||||
|
||||
$this->sendNotification(new BackupManifestWasCreated($manifest));
|
||||
|
||||
return $manifest;
|
||||
}
|
||||
|
||||
public function filesToBeBackedUp()
|
||||
{
|
||||
$this->fileSelection->excludeFilesFrom($this->directoriesUsedByBackupJob());
|
||||
|
||||
return $this->fileSelection->selectedFiles();
|
||||
}
|
||||
|
||||
protected function directoriesUsedByBackupJob(): array
|
||||
{
|
||||
return $this->backupDestinations
|
||||
->filter(function (BackupDestination $backupDestination) {
|
||||
return $backupDestination->filesystemType() === 'local';
|
||||
})
|
||||
->map(function (BackupDestination $backupDestination) {
|
||||
return $backupDestination->disk()->getDriver()->getAdapter()->applyPathPrefix('').$backupDestination->backupName();
|
||||
})
|
||||
->each(function (string $backupDestinationDirectory) {
|
||||
$this->fileSelection->excludeFilesFrom($backupDestinationDirectory);
|
||||
})
|
||||
->push($this->temporaryDirectory->path())
|
||||
->toArray();
|
||||
}
|
||||
|
||||
protected function createZipContainingEveryFileInManifest(Manifest $manifest)
|
||||
{
|
||||
consoleOutput()->info("Zipping {$manifest->count()} files and directories...");
|
||||
|
||||
$pathToZip = $this->temporaryDirectory->path(config('backup.backup.destination.filename_prefix').$this->filename);
|
||||
|
||||
$zip = Zip::createForManifest($manifest, $pathToZip);
|
||||
|
||||
consoleOutput()->info("Created zip containing {$zip->count()} files and directories. Size is {$zip->humanReadableSize()}");
|
||||
|
||||
if ($this->sendNotifications) {
|
||||
$this->sendNotification(new BackupZipWasCreated($pathToZip));
|
||||
} else {
|
||||
app()->call('\Spatie\Backup\Listeners\EncryptBackupArchive@handle', ['event' => new BackupZipWasCreated($pathToZip)]);
|
||||
}
|
||||
|
||||
return $pathToZip;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dumps the databases to the given directory.
|
||||
* Returns an array with paths to the dump files.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function dumpDatabases(): array
|
||||
{
|
||||
return $this->dbDumpers->map(function (DbDumper $dbDumper, $key) {
|
||||
consoleOutput()->info("Dumping database {$dbDumper->getDbName()}...");
|
||||
|
||||
$dbType = mb_strtolower(basename(str_replace('\\', '/', get_class($dbDumper))));
|
||||
|
||||
$dbName = $dbDumper->getDbName();
|
||||
if ($dbDumper instanceof Sqlite) {
|
||||
$dbName = $key.'-database';
|
||||
}
|
||||
|
||||
$fileName = "{$dbType}-{$dbName}.{$this->getExtension($dbDumper)}";
|
||||
|
||||
if (config('backup.backup.gzip_database_dump')) {
|
||||
$dbDumper->useCompressor(new GzipCompressor());
|
||||
$fileName .= '.'.$dbDumper->getCompressorExtension();
|
||||
}
|
||||
|
||||
if ($compressor = config('backup.backup.database_dump_compressor')) {
|
||||
$dbDumper->useCompressor(new $compressor());
|
||||
$fileName .= '.'.$dbDumper->getCompressorExtension();
|
||||
}
|
||||
|
||||
$temporaryFilePath = $this->temporaryDirectory->path('db-dumps'.DIRECTORY_SEPARATOR.$fileName);
|
||||
|
||||
event(new DumpingDatabase($dbDumper));
|
||||
|
||||
$dbDumper->dumpToFile($temporaryFilePath);
|
||||
|
||||
return $temporaryFilePath;
|
||||
})->toArray();
|
||||
}
|
||||
|
||||
protected function copyToBackupDestinations(string $path)
|
||||
{
|
||||
$this->backupDestinations->each(function (BackupDestination $backupDestination) use ($path) {
|
||||
try {
|
||||
consoleOutput()->info("Copying zip to disk named {$backupDestination->diskName()}...");
|
||||
|
||||
$backupDestination->write($path);
|
||||
|
||||
consoleOutput()->info("Successfully copied zip to disk named {$backupDestination->diskName()}.");
|
||||
|
||||
$this->sendNotification(new BackupWasSuccessful($backupDestination));
|
||||
} catch (Exception $exception) {
|
||||
consoleOutput()->error("Copying zip failed because: {$exception->getMessage()}.");
|
||||
|
||||
$this->sendNotification(new BackupHasFailed($exception, $backupDestination ?? null));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected function sendNotification($notification)
|
||||
{
|
||||
if ($this->sendNotifications) {
|
||||
rescue(function () use ($notification) {
|
||||
event($notification);
|
||||
}, function () {
|
||||
consoleOutput()->error('Sending notification failed');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
protected function getExtension(DbDumper $dbDumper): string
|
||||
{
|
||||
if ($extension = config('backup.backup.database_dump_file_extension')) {
|
||||
return $extension;
|
||||
}
|
||||
|
||||
return $dbDumper instanceof MongoDb
|
||||
? 'archive'
|
||||
: 'sql';
|
||||
}
|
||||
}
|
||||
33
vendor/spatie/laravel-backup/src/Tasks/Backup/BackupJobFactory.php
vendored
Normal file
33
vendor/spatie/laravel-backup/src/Tasks/Backup/BackupJobFactory.php
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace Spatie\Backup\Tasks\Backup;
|
||||
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Collection;
|
||||
use Spatie\Backup\BackupDestination\BackupDestinationFactory;
|
||||
|
||||
class BackupJobFactory
|
||||
{
|
||||
public static function createFromArray(array $config): BackupJob
|
||||
{
|
||||
return (new BackupJob())
|
||||
->setFileSelection(static::createFileSelection($config['backup']['source']['files']))
|
||||
->setDbDumpers(static::createDbDumpers($config['backup']['source']['databases']))
|
||||
->setBackupDestinations(BackupDestinationFactory::createFromArray($config['backup']));
|
||||
}
|
||||
|
||||
protected static function createFileSelection(array $sourceFiles): FileSelection
|
||||
{
|
||||
return FileSelection::create($sourceFiles['include'])
|
||||
->excludeFilesFrom($sourceFiles['exclude'])
|
||||
->shouldFollowLinks(isset($sourceFiles['follow_links']) && $sourceFiles['follow_links'])
|
||||
->shouldIgnoreUnreadableDirs(Arr::get($sourceFiles, 'ignore_unreadable_directories', false));
|
||||
}
|
||||
|
||||
protected static function createDbDumpers(array $dbConnectionNames): Collection
|
||||
{
|
||||
return collect($dbConnectionNames)->mapWithKeys(function (string $dbConnectionName) {
|
||||
return [$dbConnectionName => DbDumperFactory::createFromConnection($dbConnectionName)];
|
||||
});
|
||||
}
|
||||
}
|
||||
138
vendor/spatie/laravel-backup/src/Tasks/Backup/DbDumperFactory.php
vendored
Normal file
138
vendor/spatie/laravel-backup/src/Tasks/Backup/DbDumperFactory.php
vendored
Normal file
@@ -0,0 +1,138 @@
|
||||
<?php
|
||||
|
||||
namespace Spatie\Backup\Tasks\Backup;
|
||||
|
||||
use Exception;
|
||||
use Illuminate\Database\ConfigurationUrlParser;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Str;
|
||||
use Spatie\Backup\Exceptions\CannotCreateDbDumper;
|
||||
use Spatie\DbDumper\Databases\MongoDb;
|
||||
use Spatie\DbDumper\Databases\MySql;
|
||||
use Spatie\DbDumper\Databases\PostgreSql;
|
||||
use Spatie\DbDumper\Databases\Sqlite;
|
||||
use Spatie\DbDumper\DbDumper;
|
||||
|
||||
class DbDumperFactory
|
||||
{
|
||||
protected static $custom = [];
|
||||
|
||||
public static function createFromConnection(string $dbConnectionName): DbDumper
|
||||
{
|
||||
$parser = new ConfigurationUrlParser();
|
||||
|
||||
if (config("database.connections.{$dbConnectionName}") === null) {
|
||||
throw CannotCreateDbDumper::unsupportedDriver($dbConnectionName);
|
||||
}
|
||||
|
||||
try {
|
||||
$dbConfig = $parser->parseConfiguration(config("database.connections.{$dbConnectionName}"));
|
||||
} catch (Exception $e) {
|
||||
throw CannotCreateDbDumper::unsupportedDriver($dbConnectionName);
|
||||
}
|
||||
|
||||
if (isset($dbConfig['read'])) {
|
||||
$dbConfig = Arr::except(
|
||||
array_merge($dbConfig, $dbConfig['read']),
|
||||
['read', 'write']
|
||||
);
|
||||
}
|
||||
|
||||
$dbDumper = static::forDriver($dbConfig['driver'] ?? '')
|
||||
->setHost(Arr::first(Arr::wrap($dbConfig['host'] ?? '')))
|
||||
->setDbName($dbConfig['database'])
|
||||
->setUserName($dbConfig['username'] ?? '')
|
||||
->setPassword($dbConfig['password'] ?? '');
|
||||
|
||||
if ($dbDumper instanceof MySql) {
|
||||
$dbDumper->setDefaultCharacterSet($dbConfig['charset'] ?? '');
|
||||
}
|
||||
|
||||
if ($dbDumper instanceof MongoDb) {
|
||||
$dbDumper->setAuthenticationDatabase($dbConfig['dump']['mongodb_user_auth'] ?? '');
|
||||
}
|
||||
|
||||
if (isset($dbConfig['port'])) {
|
||||
$dbDumper = $dbDumper->setPort($dbConfig['port']);
|
||||
}
|
||||
|
||||
if (isset($dbConfig['dump'])) {
|
||||
$dbDumper = static::processExtraDumpParameters($dbConfig['dump'], $dbDumper);
|
||||
}
|
||||
|
||||
if (isset($dbConfig['unix_socket'])) {
|
||||
$dbDumper = $dbDumper->setSocket($dbConfig['unix_socket']);
|
||||
}
|
||||
|
||||
return $dbDumper;
|
||||
}
|
||||
|
||||
public static function extend(string $driver, callable $callback)
|
||||
{
|
||||
static::$custom[$driver] = $callback;
|
||||
}
|
||||
|
||||
protected static function forDriver($dbDriver): DbDumper
|
||||
{
|
||||
$driver = strtolower($dbDriver);
|
||||
|
||||
if (isset(static::$custom[$driver])) {
|
||||
return (static::$custom[$driver])();
|
||||
}
|
||||
|
||||
if ($driver === 'mysql' || $driver === 'mariadb') {
|
||||
return new MySql();
|
||||
}
|
||||
|
||||
if ($driver === 'pgsql') {
|
||||
return new PostgreSql();
|
||||
}
|
||||
|
||||
if ($driver === 'sqlite') {
|
||||
return new Sqlite();
|
||||
}
|
||||
|
||||
if ($driver === 'mongodb') {
|
||||
return new MongoDb();
|
||||
}
|
||||
|
||||
throw CannotCreateDbDumper::unsupportedDriver($driver);
|
||||
}
|
||||
|
||||
protected static function processExtraDumpParameters(array $dumpConfiguration, DbDumper $dbDumper): DbDumper
|
||||
{
|
||||
collect($dumpConfiguration)->each(function ($configValue, $configName) use ($dbDumper) {
|
||||
$methodName = lcfirst(Str::studly(is_numeric($configName) ? $configValue : $configName));
|
||||
$methodValue = is_numeric($configName) ? null : $configValue;
|
||||
|
||||
$methodName = static::determineValidMethodName($dbDumper, $methodName);
|
||||
|
||||
if (method_exists($dbDumper, $methodName)) {
|
||||
static::callMethodOnDumper($dbDumper, $methodName, $methodValue);
|
||||
}
|
||||
});
|
||||
|
||||
return $dbDumper;
|
||||
}
|
||||
|
||||
protected static function callMethodOnDumper(DbDumper $dbDumper, string $methodName, $methodValue): DbDumper
|
||||
{
|
||||
if (! $methodValue) {
|
||||
$dbDumper->$methodName();
|
||||
|
||||
return $dbDumper;
|
||||
}
|
||||
|
||||
$dbDumper->$methodName($methodValue);
|
||||
|
||||
return $dbDumper;
|
||||
}
|
||||
|
||||
protected static function determineValidMethodName(DbDumper $dbDumper, string $methodName): string
|
||||
{
|
||||
return collect([$methodName, 'set'.ucfirst($methodName)])
|
||||
->first(function (string $methodName) use ($dbDumper) {
|
||||
return method_exists($dbDumper, $methodName);
|
||||
}, '');
|
||||
}
|
||||
}
|
||||
186
vendor/spatie/laravel-backup/src/Tasks/Backup/FileSelection.php
vendored
Normal file
186
vendor/spatie/laravel-backup/src/Tasks/Backup/FileSelection.php
vendored
Normal file
@@ -0,0 +1,186 @@
|
||||
<?php
|
||||
|
||||
namespace Spatie\Backup\Tasks\Backup;
|
||||
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Str;
|
||||
use Symfony\Component\Finder\Finder;
|
||||
|
||||
class FileSelection
|
||||
{
|
||||
/** @var \Illuminate\Support\Collection */
|
||||
protected $includeFilesAndDirectories;
|
||||
|
||||
/** @var \Illuminate\Support\Collection */
|
||||
protected $excludeFilesAndDirectories;
|
||||
|
||||
/** @var bool */
|
||||
protected $shouldFollowLinks = false;
|
||||
|
||||
/** @var bool */
|
||||
protected $shouldIgnoreUnreadableDirs = false;
|
||||
|
||||
/**
|
||||
* @param array|string $includeFilesAndDirectories
|
||||
*
|
||||
* @return \Spatie\Backup\Tasks\Backup\FileSelection
|
||||
*/
|
||||
public static function create($includeFilesAndDirectories = []): self
|
||||
{
|
||||
return new static($includeFilesAndDirectories);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array|string $includeFilesAndDirectories
|
||||
*/
|
||||
public function __construct($includeFilesAndDirectories = [])
|
||||
{
|
||||
$this->includeFilesAndDirectories = collect($includeFilesAndDirectories);
|
||||
|
||||
$this->excludeFilesAndDirectories = collect();
|
||||
}
|
||||
|
||||
/**
|
||||
* Do not included the given files and directories.
|
||||
*
|
||||
* @param array|string $excludeFilesAndDirectories
|
||||
*
|
||||
* @return \Spatie\Backup\Tasks\Backup\FileSelection
|
||||
*/
|
||||
public function excludeFilesFrom($excludeFilesAndDirectories): self
|
||||
{
|
||||
$this->excludeFilesAndDirectories = $this->excludeFilesAndDirectories->merge($this->sanitize($excludeFilesAndDirectories));
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function shouldFollowLinks(bool $shouldFollowLinks): self
|
||||
{
|
||||
$this->shouldFollowLinks = $shouldFollowLinks;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set if it should ignore the unreadable directories.
|
||||
*
|
||||
* @param bool $ignoreUnreadableDirs
|
||||
*
|
||||
* @return \Spatie\Backup\Tasks\Backup\FileSelection
|
||||
*/
|
||||
public function shouldIgnoreUnreadableDirs(bool $ignoreUnreadableDirs): self
|
||||
{
|
||||
$this->shouldIgnoreUnreadableDirs = $ignoreUnreadableDirs;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Generator|string[]
|
||||
*/
|
||||
public function selectedFiles()
|
||||
{
|
||||
if ($this->includeFilesAndDirectories->isEmpty()) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$finder = (new Finder())
|
||||
->ignoreDotFiles(false)
|
||||
->ignoreVCS(false);
|
||||
|
||||
if ($this->shouldFollowLinks) {
|
||||
$finder->followLinks();
|
||||
}
|
||||
|
||||
if ($this->shouldIgnoreUnreadableDirs) {
|
||||
$finder->ignoreUnreadableDirs();
|
||||
}
|
||||
|
||||
foreach ($this->includedFiles() as $includedFile) {
|
||||
yield $includedFile;
|
||||
}
|
||||
|
||||
if (! count($this->includedDirectories())) {
|
||||
return;
|
||||
}
|
||||
|
||||
$finder->in($this->includedDirectories());
|
||||
|
||||
foreach ($finder->getIterator() as $file) {
|
||||
if ($this->shouldExclude($file)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
yield $file->getPathname();
|
||||
}
|
||||
}
|
||||
|
||||
protected function includedFiles(): array
|
||||
{
|
||||
return $this->includeFilesAndDirectories->filter(function ($path) {
|
||||
return is_file($path);
|
||||
})->toArray();
|
||||
}
|
||||
|
||||
protected function includedDirectories(): array
|
||||
{
|
||||
return $this->includeFilesAndDirectories->reject(function ($path) {
|
||||
return is_file($path);
|
||||
})->toArray();
|
||||
}
|
||||
|
||||
protected function shouldExclude(string $path): bool
|
||||
{
|
||||
$path = realpath($path);
|
||||
if (is_dir($path)) {
|
||||
$path .= DIRECTORY_SEPARATOR ;
|
||||
}
|
||||
foreach ($this->excludeFilesAndDirectories as $excludedPath) {
|
||||
if (Str::startsWith($path, $excludedPath.(is_dir($excludedPath) ? DIRECTORY_SEPARATOR : ''))) {
|
||||
if ($path != $excludedPath && is_file($excludedPath)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|array $paths
|
||||
*
|
||||
* @return \Illuminate\Support\Collection
|
||||
*/
|
||||
protected function sanitize($paths): Collection
|
||||
{
|
||||
return collect($paths)
|
||||
->reject(function ($path) {
|
||||
return $path === '';
|
||||
})
|
||||
->flatMap(function ($path) {
|
||||
return $this->getMatchingPaths($path);
|
||||
})
|
||||
->map(function ($path) {
|
||||
return realpath($path);
|
||||
})
|
||||
->reject(function ($path) {
|
||||
return $path === false;
|
||||
});
|
||||
}
|
||||
|
||||
protected function getMatchingPaths(string $path): array
|
||||
{
|
||||
if ($this->canUseGlobBrace($path)) {
|
||||
return glob(str_replace('*', '{.[!.],}*', $path), GLOB_BRACE);
|
||||
}
|
||||
|
||||
return glob($path);
|
||||
}
|
||||
|
||||
protected function canUseGlobBrace(string $path): bool
|
||||
{
|
||||
return strpos($path, '*') !== false && defined('GLOB_BRACE');
|
||||
}
|
||||
}
|
||||
74
vendor/spatie/laravel-backup/src/Tasks/Backup/Manifest.php
vendored
Normal file
74
vendor/spatie/laravel-backup/src/Tasks/Backup/Manifest.php
vendored
Normal file
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
|
||||
namespace Spatie\Backup\Tasks\Backup;
|
||||
|
||||
use Countable;
|
||||
use SplFileObject;
|
||||
|
||||
class Manifest implements Countable
|
||||
{
|
||||
/** @var string */
|
||||
protected $manifestPath;
|
||||
|
||||
public static function create(string $manifestPath): self
|
||||
{
|
||||
return new static($manifestPath);
|
||||
}
|
||||
|
||||
public function __construct(string $manifestPath)
|
||||
{
|
||||
$this->manifestPath = $manifestPath;
|
||||
|
||||
touch($manifestPath);
|
||||
}
|
||||
|
||||
public function path(): string
|
||||
{
|
||||
return $this->manifestPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array|string $filePaths
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function addFiles($filePaths): self
|
||||
{
|
||||
if (is_string($filePaths)) {
|
||||
$filePaths = [$filePaths];
|
||||
}
|
||||
|
||||
foreach ($filePaths as $filePath) {
|
||||
if (! empty($filePath)) {
|
||||
file_put_contents($this->manifestPath, $filePath.PHP_EOL, FILE_APPEND);
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Generator|string[]
|
||||
*/
|
||||
public function files()
|
||||
{
|
||||
$file = new SplFileObject($this->path());
|
||||
|
||||
while (! $file->eof()) {
|
||||
$filePath = $file->fgets();
|
||||
|
||||
if (! empty($filePath)) {
|
||||
yield trim($filePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function count(): int
|
||||
{
|
||||
$file = new SplFileObject($this->manifestPath, 'r');
|
||||
|
||||
$file->seek(PHP_INT_MAX);
|
||||
|
||||
return $file->key();
|
||||
}
|
||||
}
|
||||
127
vendor/spatie/laravel-backup/src/Tasks/Backup/Zip.php
vendored
Normal file
127
vendor/spatie/laravel-backup/src/Tasks/Backup/Zip.php
vendored
Normal file
@@ -0,0 +1,127 @@
|
||||
<?php
|
||||
|
||||
namespace Spatie\Backup\Tasks\Backup;
|
||||
|
||||
use Illuminate\Support\Str;
|
||||
use Spatie\Backup\Helpers\Format;
|
||||
use ZipArchive;
|
||||
|
||||
class Zip
|
||||
{
|
||||
/** @var \ZipArchive */
|
||||
protected $zipFile;
|
||||
|
||||
/** @var int */
|
||||
protected $fileCount = 0;
|
||||
|
||||
/** @var string */
|
||||
protected $pathToZip;
|
||||
|
||||
public static function createForManifest(Manifest $manifest, string $pathToZip): self
|
||||
{
|
||||
$relativePath = config('backup.backup.source.files.relative_path') ?
|
||||
rtrim(config('backup.backup.source.files.relative_path'), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR : false;
|
||||
|
||||
$zip = new static($pathToZip);
|
||||
|
||||
$zip->open();
|
||||
|
||||
foreach ($manifest->files() as $file) {
|
||||
$zip->add($file, self::determineNameOfFileInZip($file, $pathToZip, $relativePath));
|
||||
}
|
||||
|
||||
$zip->close();
|
||||
|
||||
return $zip;
|
||||
}
|
||||
|
||||
protected static function determineNameOfFileInZip(string $pathToFile, string $pathToZip, string $relativePath)
|
||||
{
|
||||
$fileDirectory = pathinfo($pathToFile, PATHINFO_DIRNAME) . DIRECTORY_SEPARATOR;
|
||||
|
||||
$zipDirectory = pathinfo($pathToZip, PATHINFO_DIRNAME) . DIRECTORY_SEPARATOR;
|
||||
|
||||
if (Str::startsWith($fileDirectory, $zipDirectory)) {
|
||||
return str_replace($zipDirectory, '', $pathToFile);
|
||||
}
|
||||
|
||||
if ($relativePath && $relativePath != DIRECTORY_SEPARATOR && Str::startsWith($fileDirectory, $relativePath)) {
|
||||
return str_replace($relativePath, '', $pathToFile);
|
||||
}
|
||||
|
||||
return $pathToFile;
|
||||
}
|
||||
|
||||
public function __construct(string $pathToZip)
|
||||
{
|
||||
$this->zipFile = new ZipArchive();
|
||||
|
||||
$this->pathToZip = $pathToZip;
|
||||
|
||||
$this->open();
|
||||
}
|
||||
|
||||
public function path(): string
|
||||
{
|
||||
return $this->pathToZip;
|
||||
}
|
||||
|
||||
public function size(): float
|
||||
{
|
||||
if ($this->fileCount === 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return filesize($this->pathToZip);
|
||||
}
|
||||
|
||||
public function humanReadableSize(): string
|
||||
{
|
||||
return Format::humanReadableSize($this->size());
|
||||
}
|
||||
|
||||
public function open()
|
||||
{
|
||||
$this->zipFile->open($this->pathToZip, ZipArchive::CREATE);
|
||||
}
|
||||
|
||||
public function close()
|
||||
{
|
||||
$this->zipFile->close();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|array $files
|
||||
* @param string $nameInZip
|
||||
*
|
||||
* @return \Spatie\Backup\Tasks\Backup\Zip
|
||||
*/
|
||||
public function add($files, string $nameInZip = null): self
|
||||
{
|
||||
if (is_array($files)) {
|
||||
$nameInZip = null;
|
||||
}
|
||||
|
||||
if (is_string($files)) {
|
||||
$files = [$files];
|
||||
}
|
||||
|
||||
foreach ($files as $file) {
|
||||
if (is_dir($file)) {
|
||||
$this->zipFile->addEmptyDir(ltrim($nameInZip ?: $file, DIRECTORY_SEPARATOR));
|
||||
}
|
||||
|
||||
if (is_file($file)) {
|
||||
$this->zipFile->addFile($file, ltrim($nameInZip, DIRECTORY_SEPARATOR)).PHP_EOL;
|
||||
}
|
||||
$this->fileCount++;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function count(): int
|
||||
{
|
||||
return $this->fileCount;
|
||||
}
|
||||
}
|
||||
66
vendor/spatie/laravel-backup/src/Tasks/Cleanup/CleanupJob.php
vendored
Normal file
66
vendor/spatie/laravel-backup/src/Tasks/Cleanup/CleanupJob.php
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
namespace Spatie\Backup\Tasks\Cleanup;
|
||||
|
||||
use Exception;
|
||||
use Illuminate\Support\Collection;
|
||||
use Spatie\Backup\BackupDestination\BackupDestination;
|
||||
use Spatie\Backup\Events\CleanupHasFailed;
|
||||
use Spatie\Backup\Events\CleanupWasSuccessful;
|
||||
use Spatie\Backup\Helpers\Format;
|
||||
|
||||
class CleanupJob
|
||||
{
|
||||
/** @var \Illuminate\Support\Collection */
|
||||
protected $backupDestinations;
|
||||
|
||||
/** @var \Spatie\Backup\Tasks\Cleanup\CleanupStrategy */
|
||||
protected $strategy;
|
||||
|
||||
/** @var bool */
|
||||
protected $sendNotifications = true;
|
||||
|
||||
public function __construct(Collection $backupDestinations, CleanupStrategy $strategy, bool $disableNotifications = false)
|
||||
{
|
||||
$this->backupDestinations = $backupDestinations;
|
||||
|
||||
$this->strategy = $strategy;
|
||||
|
||||
$this->sendNotifications = ! $disableNotifications;
|
||||
}
|
||||
|
||||
public function run()
|
||||
{
|
||||
$this->backupDestinations->each(function (BackupDestination $backupDestination) {
|
||||
try {
|
||||
if (! $backupDestination->isReachable()) {
|
||||
throw new Exception("Could not connect to disk {$backupDestination->diskName()} because: {$backupDestination->connectionError()}");
|
||||
}
|
||||
|
||||
consoleOutput()->info("Cleaning backups of {$backupDestination->backupName()} on disk {$backupDestination->diskName()}...");
|
||||
|
||||
$this->strategy
|
||||
->setBackupDestination($backupDestination)
|
||||
->deleteOldBackups($backupDestination->backups());
|
||||
|
||||
$this->sendNotification(new CleanupWasSuccessful($backupDestination));
|
||||
|
||||
$usedStorage = Format::humanReadableSize($backupDestination->fresh()->usedStorage());
|
||||
consoleOutput()->info("Used storage after cleanup: {$usedStorage}.");
|
||||
} catch (Exception $exception) {
|
||||
consoleOutput()->error("Cleanup failed because: {$exception->getMessage()}.");
|
||||
|
||||
$this->sendNotification(new CleanupHasFailed($exception));
|
||||
|
||||
throw $exception;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected function sendNotification($notification)
|
||||
{
|
||||
if ($this->sendNotifications) {
|
||||
event($notification);
|
||||
}
|
||||
}
|
||||
}
|
||||
43
vendor/spatie/laravel-backup/src/Tasks/Cleanup/CleanupStrategy.php
vendored
Normal file
43
vendor/spatie/laravel-backup/src/Tasks/Cleanup/CleanupStrategy.php
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
namespace Spatie\Backup\Tasks\Cleanup;
|
||||
|
||||
use Illuminate\Contracts\Config\Repository;
|
||||
use Spatie\Backup\BackupDestination\BackupCollection;
|
||||
use Spatie\Backup\BackupDestination\BackupDestination;
|
||||
|
||||
abstract class CleanupStrategy
|
||||
{
|
||||
/** @var \Illuminate\Contracts\Config\Repository */
|
||||
protected $config;
|
||||
|
||||
/** @var \Spatie\Backup\BackupDestination\BackupDestination */
|
||||
protected $backupDestination;
|
||||
|
||||
public function __construct(Repository $config)
|
||||
{
|
||||
$this->config = $config;
|
||||
}
|
||||
|
||||
abstract public function deleteOldBackups(BackupCollection $backups);
|
||||
|
||||
/**
|
||||
* @param \Spatie\Backup\BackupDestination\BackupDestination $backupDestination
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setBackupDestination(BackupDestination $backupDestination)
|
||||
{
|
||||
$this->backupDestination = $backupDestination;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Spatie\Backup\BackupDestination\BackupDestination
|
||||
*/
|
||||
public function backupDestination(): BackupDestination
|
||||
{
|
||||
return $this->backupDestination;
|
||||
}
|
||||
}
|
||||
31
vendor/spatie/laravel-backup/src/Tasks/Cleanup/Period.php
vendored
Normal file
31
vendor/spatie/laravel-backup/src/Tasks/Cleanup/Period.php
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace Spatie\Backup\Tasks\Cleanup;
|
||||
|
||||
use Carbon\Carbon;
|
||||
|
||||
class Period
|
||||
{
|
||||
/** @var \Carbon\Carbon */
|
||||
protected $startDate;
|
||||
|
||||
/** @var \Carbon\Carbon */
|
||||
protected $endDate;
|
||||
|
||||
public function __construct(Carbon $startDate, Carbon $endDate)
|
||||
{
|
||||
$this->startDate = $startDate;
|
||||
|
||||
$this->endDate = $endDate;
|
||||
}
|
||||
|
||||
public function startDate(): Carbon
|
||||
{
|
||||
return $this->startDate->copy();
|
||||
}
|
||||
|
||||
public function endDate(): Carbon
|
||||
{
|
||||
return $this->endDate->copy();
|
||||
}
|
||||
}
|
||||
117
vendor/spatie/laravel-backup/src/Tasks/Cleanup/Strategies/DefaultStrategy.php
vendored
Normal file
117
vendor/spatie/laravel-backup/src/Tasks/Cleanup/Strategies/DefaultStrategy.php
vendored
Normal file
@@ -0,0 +1,117 @@
|
||||
<?php
|
||||
|
||||
namespace Spatie\Backup\Tasks\Cleanup\Strategies;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Support\Collection;
|
||||
use Spatie\Backup\BackupDestination\Backup;
|
||||
use Spatie\Backup\BackupDestination\BackupCollection;
|
||||
use Spatie\Backup\Tasks\Cleanup\CleanupStrategy;
|
||||
use Spatie\Backup\Tasks\Cleanup\Period;
|
||||
|
||||
class DefaultStrategy extends CleanupStrategy
|
||||
{
|
||||
/** @var \Spatie\Backup\BackupDestination\Backup */
|
||||
protected $newestBackup;
|
||||
|
||||
public function deleteOldBackups(BackupCollection $backups)
|
||||
{
|
||||
// Don't ever delete the newest backup.
|
||||
$this->newestBackup = $backups->shift();
|
||||
|
||||
$dateRanges = $this->calculateDateRanges();
|
||||
|
||||
$backupsPerPeriod = $dateRanges->map(function (Period $period) use ($backups) {
|
||||
return $backups->filter(function (Backup $backup) use ($period) {
|
||||
return $backup->date()->between($period->startDate(), $period->endDate());
|
||||
});
|
||||
});
|
||||
|
||||
$backupsPerPeriod['daily'] = $this->groupByDateFormat($backupsPerPeriod['daily'], 'Ymd');
|
||||
$backupsPerPeriod['weekly'] = $this->groupByDateFormat($backupsPerPeriod['weekly'], 'YW');
|
||||
$backupsPerPeriod['monthly'] = $this->groupByDateFormat($backupsPerPeriod['monthly'], 'Ym');
|
||||
$backupsPerPeriod['yearly'] = $this->groupByDateFormat($backupsPerPeriod['yearly'], 'Y');
|
||||
|
||||
$this->removeBackupsForAllPeriodsExceptOne($backupsPerPeriod);
|
||||
|
||||
$this->removeBackupsOlderThan($dateRanges['yearly']->endDate(), $backups);
|
||||
|
||||
$this->removeOldBackupsUntilUsingLessThanMaximumStorage($backups);
|
||||
}
|
||||
|
||||
protected function calculateDateRanges(): Collection
|
||||
{
|
||||
$config = $this->config->get('backup.cleanup.default_strategy');
|
||||
|
||||
$daily = new Period(
|
||||
Carbon::now()->subDays($config['keep_all_backups_for_days']),
|
||||
Carbon::now()
|
||||
->subDays($config['keep_all_backups_for_days'])
|
||||
->subDays($config['keep_daily_backups_for_days'])
|
||||
);
|
||||
|
||||
$weekly = new Period(
|
||||
$daily->endDate(),
|
||||
$daily->endDate()
|
||||
->subWeeks($config['keep_weekly_backups_for_weeks'])
|
||||
);
|
||||
|
||||
$monthly = new Period(
|
||||
$weekly->endDate(),
|
||||
$weekly->endDate()
|
||||
->subMonths($config['keep_monthly_backups_for_months'])
|
||||
);
|
||||
|
||||
$yearly = new Period(
|
||||
$monthly->endDate(),
|
||||
$monthly->endDate()
|
||||
->subYears($config['keep_yearly_backups_for_years'])
|
||||
);
|
||||
|
||||
return collect(compact('daily', 'weekly', 'monthly', 'yearly'));
|
||||
}
|
||||
|
||||
protected function groupByDateFormat(Collection $backups, string $dateFormat): Collection
|
||||
{
|
||||
return $backups->groupBy(function (Backup $backup) use ($dateFormat) {
|
||||
return $backup->date()->format($dateFormat);
|
||||
});
|
||||
}
|
||||
|
||||
protected function removeBackupsForAllPeriodsExceptOne(Collection $backupsPerPeriod)
|
||||
{
|
||||
$backupsPerPeriod->each(function (Collection $groupedBackupsByDateProperty, string $periodName) {
|
||||
$groupedBackupsByDateProperty->each(function (Collection $group) {
|
||||
$group->shift();
|
||||
|
||||
$group->each->delete();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
protected function removeBackupsOlderThan(Carbon $endDate, BackupCollection $backups)
|
||||
{
|
||||
$backups->filter(function (Backup $backup) use ($endDate) {
|
||||
return $backup->exists() && $backup->date()->lt($endDate);
|
||||
})->each->delete();
|
||||
}
|
||||
|
||||
protected function removeOldBackupsUntilUsingLessThanMaximumStorage(BackupCollection $backups)
|
||||
{
|
||||
if (! $oldest = $backups->oldest()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$maximumSize = $this->config->get('backup.cleanup.default_strategy.delete_oldest_backups_when_using_more_megabytes_than')
|
||||
* 1024 * 1024;
|
||||
|
||||
if (($backups->size() + $this->newestBackup->size()) <= $maximumSize) {
|
||||
return;
|
||||
}
|
||||
$oldest->delete();
|
||||
|
||||
$backups = $backups->filter->exists();
|
||||
|
||||
$this->removeOldBackupsUntilUsingLessThanMaximumStorage($backups);
|
||||
}
|
||||
}
|
||||
70
vendor/spatie/laravel-backup/src/Tasks/Monitor/BackupDestinationStatus.php
vendored
Normal file
70
vendor/spatie/laravel-backup/src/Tasks/Monitor/BackupDestinationStatus.php
vendored
Normal file
@@ -0,0 +1,70 @@
|
||||
<?php
|
||||
|
||||
namespace Spatie\Backup\Tasks\Monitor;
|
||||
|
||||
use Exception;
|
||||
use Illuminate\Support\Collection;
|
||||
use Spatie\Backup\BackupDestination\BackupDestination;
|
||||
use Spatie\Backup\Tasks\Monitor\HealthChecks\IsReachable;
|
||||
|
||||
class BackupDestinationStatus
|
||||
{
|
||||
/** @var \Spatie\Backup\BackupDestination\BackupDestination */
|
||||
protected $backupDestination;
|
||||
|
||||
/** @var array */
|
||||
protected $healthChecks;
|
||||
|
||||
/** @var HealthCheckFailure|null */
|
||||
protected $healthCheckFailure;
|
||||
|
||||
public function __construct(BackupDestination $backupDestination, array $healthChecks = [])
|
||||
{
|
||||
$this->backupDestination = $backupDestination;
|
||||
|
||||
$this->healthChecks = $healthChecks;
|
||||
}
|
||||
|
||||
public function backupDestination(): BackupDestination
|
||||
{
|
||||
return $this->backupDestination;
|
||||
}
|
||||
|
||||
public function check(HealthCheck $check)
|
||||
{
|
||||
try {
|
||||
$check->checkHealth($this->backupDestination());
|
||||
} catch (Exception $exception) {
|
||||
return new HealthCheckFailure($check, $exception);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getHealthChecks(): Collection
|
||||
{
|
||||
return collect($this->healthChecks)->prepend(new IsReachable());
|
||||
}
|
||||
|
||||
public function getHealthCheckFailure(): ?HealthCheckFailure
|
||||
{
|
||||
return $this->healthCheckFailure;
|
||||
}
|
||||
|
||||
public function isHealthy(): bool
|
||||
{
|
||||
$healthChecks = $this->getHealthChecks();
|
||||
|
||||
foreach ($healthChecks as $healthCheck) {
|
||||
$checkResult = $this->check($healthCheck);
|
||||
|
||||
if ($checkResult instanceof HealthCheckFailure) {
|
||||
$this->healthCheckFailure = $checkResult;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
52
vendor/spatie/laravel-backup/src/Tasks/Monitor/BackupDestinationStatusFactory.php
vendored
Normal file
52
vendor/spatie/laravel-backup/src/Tasks/Monitor/BackupDestinationStatusFactory.php
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
namespace Spatie\Backup\Tasks\Monitor;
|
||||
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Collection;
|
||||
use Spatie\Backup\BackupDestination\BackupDestination;
|
||||
|
||||
class BackupDestinationStatusFactory
|
||||
{
|
||||
public static function createForMonitorConfig(array $monitorConfiguration): Collection
|
||||
{
|
||||
return collect($monitorConfiguration)->flatMap(function (array $monitorProperties) {
|
||||
return self::createForSingleMonitor($monitorProperties);
|
||||
})->sortBy(function (BackupDestinationStatus $backupDestinationStatus) {
|
||||
return $backupDestinationStatus->backupDestination()->backupName().'-'.
|
||||
$backupDestinationStatus->backupDestination()->diskName();
|
||||
});
|
||||
}
|
||||
|
||||
public static function createForSingleMonitor(array $monitorConfig): Collection
|
||||
{
|
||||
return collect($monitorConfig['disks'])->map(function ($diskName) use ($monitorConfig) {
|
||||
$backupDestination = BackupDestination::create($diskName, $monitorConfig['name']);
|
||||
|
||||
return new BackupDestinationStatus($backupDestination, static::buildHealthChecks($monitorConfig));
|
||||
});
|
||||
}
|
||||
|
||||
protected static function buildHealthChecks($monitorConfig)
|
||||
{
|
||||
return collect(Arr::get($monitorConfig, 'health_checks'))->map(function ($options, $class) {
|
||||
if (is_int($class)) {
|
||||
$class = $options;
|
||||
$options = [];
|
||||
}
|
||||
|
||||
return static::buildHealthCheck($class, $options);
|
||||
})->toArray();
|
||||
}
|
||||
|
||||
protected static function buildHealthCheck($class, $options)
|
||||
{
|
||||
// A single value was passed - we'll instantiate it manually assuming it's the first argument
|
||||
if (! is_array($options)) {
|
||||
return new $class($options);
|
||||
}
|
||||
|
||||
// A config array was given. Use reflection to match arguments
|
||||
return app()->makeWith($class, $options);
|
||||
}
|
||||
}
|
||||
36
vendor/spatie/laravel-backup/src/Tasks/Monitor/HealthCheck.php
vendored
Normal file
36
vendor/spatie/laravel-backup/src/Tasks/Monitor/HealthCheck.php
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace Spatie\Backup\Tasks\Monitor;
|
||||
|
||||
use Illuminate\Support\Str;
|
||||
use Spatie\Backup\BackupDestination\BackupDestination;
|
||||
use Spatie\Backup\Exceptions\InvalidHealthCheck;
|
||||
|
||||
abstract class HealthCheck
|
||||
{
|
||||
abstract public function checkHealth(BackupDestination $backupDestination);
|
||||
|
||||
public function name()
|
||||
{
|
||||
return Str::title(class_basename($this));
|
||||
}
|
||||
|
||||
protected function fail(string $message)
|
||||
{
|
||||
throw InvalidHealthCheck::because($message);
|
||||
}
|
||||
|
||||
protected function failIf(bool $condition, string $message)
|
||||
{
|
||||
if ($condition) {
|
||||
$this->fail($message);
|
||||
}
|
||||
}
|
||||
|
||||
protected function failUnless(bool $condition, string $message)
|
||||
{
|
||||
if (! $condition) {
|
||||
$this->fail($message);
|
||||
}
|
||||
}
|
||||
}
|
||||
37
vendor/spatie/laravel-backup/src/Tasks/Monitor/HealthCheckFailure.php
vendored
Normal file
37
vendor/spatie/laravel-backup/src/Tasks/Monitor/HealthCheckFailure.php
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
namespace Spatie\Backup\Tasks\Monitor;
|
||||
|
||||
use Exception;
|
||||
use Spatie\Backup\Exceptions\InvalidHealthCheck;
|
||||
|
||||
class HealthCheckFailure
|
||||
{
|
||||
/** @var \Spatie\Backup\Tasks\Monitor */
|
||||
protected $healthCheck;
|
||||
|
||||
/** @var \Exception */
|
||||
protected $exception;
|
||||
|
||||
public function __construct(HealthCheck $healthCheck, Exception $exception)
|
||||
{
|
||||
$this->healthCheck = $healthCheck;
|
||||
|
||||
$this->exception = $exception;
|
||||
}
|
||||
|
||||
public function healthCheck(): HealthCheck
|
||||
{
|
||||
return $this->healthCheck;
|
||||
}
|
||||
|
||||
public function exception(): Exception
|
||||
{
|
||||
return $this->exception;
|
||||
}
|
||||
|
||||
public function wasUnexpected(): bool
|
||||
{
|
||||
return ! $this->exception instanceof InvalidHealthCheck;
|
||||
}
|
||||
}
|
||||
19
vendor/spatie/laravel-backup/src/Tasks/Monitor/HealthChecks/IsReachable.php
vendored
Normal file
19
vendor/spatie/laravel-backup/src/Tasks/Monitor/HealthChecks/IsReachable.php
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace Spatie\Backup\Tasks\Monitor\HealthChecks;
|
||||
|
||||
use Spatie\Backup\BackupDestination\BackupDestination;
|
||||
use Spatie\Backup\Tasks\Monitor\HealthCheck;
|
||||
|
||||
class IsReachable extends HealthCheck
|
||||
{
|
||||
public function checkHealth(BackupDestination $backupDestination)
|
||||
{
|
||||
$this->failUnless(
|
||||
$backupDestination->isReachable(),
|
||||
trans('backup::notification.unhealthy_backup_found_not_reachable', [
|
||||
'error' => $backupDestination->connectionError,
|
||||
])
|
||||
);
|
||||
}
|
||||
}
|
||||
51
vendor/spatie/laravel-backup/src/Tasks/Monitor/HealthChecks/MaximumAgeInDays.php
vendored
Normal file
51
vendor/spatie/laravel-backup/src/Tasks/Monitor/HealthChecks/MaximumAgeInDays.php
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
namespace Spatie\Backup\Tasks\Monitor\HealthChecks;
|
||||
|
||||
use Spatie\Backup\BackupDestination\Backup;
|
||||
use Spatie\Backup\BackupDestination\BackupDestination;
|
||||
use Spatie\Backup\Tasks\Monitor\HealthCheck;
|
||||
|
||||
class MaximumAgeInDays extends HealthCheck
|
||||
{
|
||||
/** @var int */
|
||||
protected $days;
|
||||
|
||||
public function __construct($days = 1)
|
||||
{
|
||||
$this->days = $days;
|
||||
}
|
||||
|
||||
public function checkHealth(BackupDestination $backupDestination)
|
||||
{
|
||||
$this->failIf(
|
||||
$this->hasNoBackups($backupDestination),
|
||||
trans('backup::notifications.unhealthy_backup_found_empty')
|
||||
);
|
||||
|
||||
$newestBackup = $backupDestination->backups()->newest();
|
||||
|
||||
$this->failIf(
|
||||
$this->isTooOld($newestBackup),
|
||||
trans('backup::notifications.unhealthy_backup_found_old', ['date' => $newestBackup->date()->format('Y/m/d h:i:s')])
|
||||
);
|
||||
}
|
||||
|
||||
protected function hasNoBackups(BackupDestination $backupDestination)
|
||||
{
|
||||
return $backupDestination->backups()->isEmpty();
|
||||
}
|
||||
|
||||
protected function isTooOld(Backup $backup)
|
||||
{
|
||||
if (is_null($this->days)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($backup->date()->gt(now()->subDays($this->days))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
46
vendor/spatie/laravel-backup/src/Tasks/Monitor/HealthChecks/MaximumStorageInMegabytes.php
vendored
Normal file
46
vendor/spatie/laravel-backup/src/Tasks/Monitor/HealthChecks/MaximumStorageInMegabytes.php
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
namespace Spatie\Backup\Tasks\Monitor\HealthChecks;
|
||||
|
||||
use Spatie\Backup\BackupDestination\BackupDestination;
|
||||
use Spatie\Backup\Helpers\Format;
|
||||
use Spatie\Backup\Tasks\Monitor\HealthCheck;
|
||||
|
||||
class MaximumStorageInMegabytes extends HealthCheck
|
||||
{
|
||||
/** @var int */
|
||||
protected $maximumSizeInMegaBytes;
|
||||
|
||||
public function __construct(int $maximumSizeInMegaBytes = 5000)
|
||||
{
|
||||
$this->maximumSizeInMegaBytes = $maximumSizeInMegaBytes;
|
||||
}
|
||||
|
||||
public function checkHealth(BackupDestination $backupDestination)
|
||||
{
|
||||
$usageInBytes = $backupDestination->usedStorage();
|
||||
|
||||
$this->failIf(
|
||||
$this->exceedsAllowance($usageInBytes),
|
||||
trans('backup::notifications.unhealthy_backup_found_full', [
|
||||
'disk_usage' => $this->humanReadableSize($usageInBytes),
|
||||
'disk_limit' => $this->humanReadableSize($this->bytes($this->maximumSizeInMegaBytes)),
|
||||
])
|
||||
);
|
||||
}
|
||||
|
||||
protected function exceedsAllowance(float $usageInBytes): bool
|
||||
{
|
||||
return $usageInBytes > $this->bytes($this->maximumSizeInMegaBytes);
|
||||
}
|
||||
|
||||
protected function bytes(int $megaBytes): int
|
||||
{
|
||||
return $megaBytes * 1024 * 1024;
|
||||
}
|
||||
|
||||
protected function humanReadableSize(float $sizeInBytes): string
|
||||
{
|
||||
return Format::humanReadableSize($sizeInBytes);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user