Subiendo proyecto completo sin restricciones de git ignore

This commit is contained in:
Jose Sanchez
2023-08-17 11:44:02 -04:00
parent a0d4f5ba3b
commit 20f1c60600
19921 changed files with 2509159 additions and 45 deletions

View File

@@ -0,0 +1,16 @@
<?php
namespace Spatie\DbDumper\Compressors;
class Bzip2Compressor implements Compressor
{
public function useCommand(): string
{
return 'bzip2';
}
public function useExtension(): string
{
return 'bz2';
}
}

View File

@@ -0,0 +1,10 @@
<?php
namespace Spatie\DbDumper\Compressors;
interface Compressor
{
public function useCommand(): string;
public function useExtension(): string;
}

View File

@@ -0,0 +1,16 @@
<?php
namespace Spatie\DbDumper\Compressors;
class GzipCompressor implements Compressor
{
public function useCommand(): string
{
return 'gzip';
}
public function useExtension(): string
{
return 'gz';
}
}

View File

@@ -0,0 +1,101 @@
<?php
namespace Spatie\DbDumper\Databases;
use Spatie\DbDumper\DbDumper;
use Spatie\DbDumper\Exceptions\CannotStartDump;
use Symfony\Component\Process\Process;
class MongoDb extends DbDumper
{
protected int $port = 27017;
protected ?string $collection = null;
protected ?string $authenticationDatabase = null;
public function dumpToFile(string $dumpFile): void
{
$this->guardAgainstIncompleteCredentials();
$process = $this->getProcess($dumpFile);
$process->run();
$this->checkIfDumpWasSuccessFul($process, $dumpFile);
}
/**
* Verifies if the dbname and host options are set.
*
* @throws \Spatie\DbDumper\Exceptions\CannotStartDump
*
* @return void
*/
public function guardAgainstIncompleteCredentials(): void
{
foreach (['dbName', 'host'] as $requiredProperty) {
if (strlen($this->$requiredProperty) === 0) {
throw CannotStartDump::emptyParameter($requiredProperty);
}
}
}
public function setCollection(string $collection): self
{
$this->collection = $collection;
return $this;
}
public function setAuthenticationDatabase(string $authenticationDatabase): self
{
$this->authenticationDatabase = $authenticationDatabase;
return $this;
}
public function getDumpCommand(string $filename): string
{
$quote = $this->determineQuote();
$command = [
"{$quote}{$this->dumpBinaryPath}mongodump{$quote}",
"--db {$this->dbName}",
'--archive',
];
if ($this->userName) {
$command[] = "--username {$quote}{$this->userName}{$quote}";
}
if ($this->password) {
$command[] = "--password {$quote}{$this->password}{$quote}";
}
if (isset($this->host)) {
$command[] = "--host {$this->host}";
}
if (isset($this->port)) {
$command[] = "--port {$this->port}";
}
if (isset($this->collection)) {
$command[] = "--collection {$this->collection}";
}
if ($this->authenticationDatabase) {
$command[] = "--authenticationDatabase {$this->authenticationDatabase}";
}
return $this->echoToFile(implode(' ', $command), $filename);
}
public function getProcess(string $dumpFile): Process
{
$command = $this->getDumpCommand($dumpFile);
return Process::fromShellCommandline($command, null, null, null, $this->timeout);
}
}

View File

@@ -0,0 +1,297 @@
<?php
namespace Spatie\DbDumper\Databases;
use Spatie\DbDumper\DbDumper;
use Spatie\DbDumper\Exceptions\CannotStartDump;
use Symfony\Component\Process\Process;
class MySql extends DbDumper
{
protected bool $skipComments = true;
protected bool $useExtendedInserts = true;
protected bool $useSingleTransaction = false;
protected bool $skipLockTables = false;
protected bool $doNotUseColumnStatistics = false;
protected bool $useQuick = false;
protected string $defaultCharacterSet = '';
protected bool $dbNameWasSetAsExtraOption = false;
protected bool $allDatabasesWasSetAsExtraOption = false;
protected string $setGtidPurged = 'AUTO';
protected bool $createTables = true;
/** @var false|resource */
private $tempFileHandle;
public function __construct()
{
$this->port = 3306;
}
public function skipComments(): self
{
$this->skipComments = true;
return $this;
}
public function dontSkipComments(): self
{
$this->skipComments = false;
return $this;
}
public function useExtendedInserts(): self
{
$this->useExtendedInserts = true;
return $this;
}
public function dontUseExtendedInserts(): self
{
$this->useExtendedInserts = false;
return $this;
}
public function useSingleTransaction(): self
{
$this->useSingleTransaction = true;
return $this;
}
public function dontUseSingleTransaction(): self
{
$this->useSingleTransaction = false;
return $this;
}
public function skipLockTables(): self
{
$this->skipLockTables = true;
return $this;
}
public function doNotUseColumnStatistics(): self
{
$this->doNotUseColumnStatistics = true;
return $this;
}
public function dontSkipLockTables(): self
{
$this->skipLockTables = false;
return $this;
}
public function useQuick(): self
{
$this->useQuick = true;
return $this;
}
public function dontUseQuick(): self
{
$this->useQuick = false;
return $this;
}
public function setDefaultCharacterSet(string $characterSet): self
{
$this->defaultCharacterSet = $characterSet;
return $this;
}
public function setGtidPurged(string $setGtidPurged): self
{
$this->setGtidPurged = $setGtidPurged;
return $this;
}
public function dumpToFile(string $dumpFile): void
{
$this->guardAgainstIncompleteCredentials();
$tempFileHandle = tmpfile();
$this->setTempFileHandle($tempFileHandle);
$process = $this->getProcess($dumpFile);
$process->run();
$this->checkIfDumpWasSuccessFul($process, $dumpFile);
}
public function addExtraOption(string $extraOption): self
{
if (str_contains($extraOption, '--all-databases')) {
$this->dbNameWasSetAsExtraOption = true;
$this->allDatabasesWasSetAsExtraOption = true;
}
if (preg_match('/^--databases (\S+)/', $extraOption, $matches) === 1) {
$this->setDbName($matches[1]);
$this->dbNameWasSetAsExtraOption = true;
}
return parent::addExtraOption($extraOption);
}
public function doNotCreateTables(): self
{
$this->createTables = false;
return $this;
}
public function getDumpCommand(string $dumpFile, string $temporaryCredentialsFile): string
{
$quote = $this->determineQuote();
$command = [
"{$quote}{$this->dumpBinaryPath}mysqldump{$quote}",
"--defaults-extra-file=\"{$temporaryCredentialsFile}\"",
];
if (! $this->createTables) {
$command[] = '--no-create-info';
}
if ($this->skipComments) {
$command[] = '--skip-comments';
}
$command[] = $this->useExtendedInserts ? '--extended-insert' : '--skip-extended-insert';
if ($this->useSingleTransaction) {
$command[] = '--single-transaction';
}
if ($this->skipLockTables) {
$command[] = '--skip-lock-tables';
}
if ($this->doNotUseColumnStatistics) {
$command[] = '--column-statistics=0';
}
if ($this->useQuick) {
$command[] = '--quick';
}
if ($this->socket !== '') {
$command[] = "--socket={$this->socket}";
}
foreach ($this->excludeTables as $tableName) {
$command[] = "--ignore-table={$this->dbName}.{$tableName}";
}
if (! empty($this->defaultCharacterSet)) {
$command[] = '--default-character-set='.$this->defaultCharacterSet;
}
foreach ($this->extraOptions as $extraOption) {
$command[] = $extraOption;
}
if ($this->setGtidPurged !== 'AUTO') {
$command[] = '--set-gtid-purged='.$this->setGtidPurged;
}
if (! $this->dbNameWasSetAsExtraOption) {
$command[] = $this->dbName;
}
if (! empty($this->includeTables)) {
$includeTables = implode(' ', $this->includeTables);
$command[] = "--tables {$includeTables}";
}
foreach ($this->extraOptionsAfterDbName as $extraOptionAfterDbName) {
$command[] = $extraOptionAfterDbName;
}
return $this->echoToFile(implode(' ', $command), $dumpFile);
}
public function getContentsOfCredentialsFile(): string
{
$contents = [
'[client]',
"user = '{$this->userName}'",
"password = '{$this->password}'",
"port = '{$this->port}'",
];
if ($this->socket === '') {
$contents[] = "host = '{$this->host}'";
}
return implode(PHP_EOL, $contents);
}
public function guardAgainstIncompleteCredentials(): void
{
foreach (['userName', 'host'] as $requiredProperty) {
if (strlen($this->$requiredProperty) === 0) {
throw CannotStartDump::emptyParameter($requiredProperty);
}
}
if (strlen($this->dbName) === 0 && ! $this->allDatabasesWasSetAsExtraOption) {
throw CannotStartDump::emptyParameter('dbName');
}
}
/**
* @param string $dumpFile
* @return Process
*/
public function getProcess(string $dumpFile): Process
{
fwrite($this->getTempFileHandle(), $this->getContentsOfCredentialsFile());
$temporaryCredentialsFile = stream_get_meta_data($this->getTempFileHandle())['uri'];
$command = $this->getDumpCommand($dumpFile, $temporaryCredentialsFile);
return Process::fromShellCommandline($command, null, null, null, $this->timeout);
}
/**
* @return false|resource
*/
public function getTempFileHandle(): mixed
{
return $this->tempFileHandle;
}
/**
* @param false|resource $tempFileHandle
*/
public function setTempFileHandle($tempFileHandle)
{
$this->tempFileHandle = $tempFileHandle;
}
}

View File

@@ -0,0 +1,150 @@
<?php
namespace Spatie\DbDumper\Databases;
use Spatie\DbDumper\DbDumper;
use Spatie\DbDumper\Exceptions\CannotStartDump;
use Symfony\Component\Process\Process;
class PostgreSql extends DbDumper
{
protected bool $useInserts = false;
protected bool $createTables = true;
/** @var false|resource */
private $tempFileHandle;
public function __construct()
{
$this->port = 5432;
}
public function useInserts(): self
{
$this->useInserts = true;
return $this;
}
public function dumpToFile(string $dumpFile): void
{
$this->guardAgainstIncompleteCredentials();
$tempFileHandle = tmpfile();
$this->setTempFileHandle($tempFileHandle);
$process = $this->getProcess($dumpFile);
$process->run();
$this->checkIfDumpWasSuccessFul($process, $dumpFile);
}
public function getDumpCommand(string $dumpFile): string
{
$quote = $this->determineQuote();
$command = [
"{$quote}{$this->dumpBinaryPath}pg_dump{$quote}",
"-U \"{$this->userName}\"",
'-h '.($this->socket === '' ? $this->host : $this->socket),
"-p {$this->port}",
];
if ($this->useInserts) {
$command[] = '--inserts';
}
if (! $this->createTables) {
$command[] = '--data-only';
}
foreach ($this->extraOptions as $extraOption) {
$command[] = $extraOption;
}
if (! empty($this->includeTables)) {
$command[] = '-t '.implode(' -t ', $this->includeTables);
}
if (! empty($this->excludeTables)) {
$command[] = '-T '.implode(' -T ', $this->excludeTables);
}
return $this->echoToFile(implode(' ', $command), $dumpFile);
}
public function getContentsOfCredentialsFile(): string
{
$contents = [
$this->escapeCredentialEntry($this->host),
$this->escapeCredentialEntry($this->port),
$this->escapeCredentialEntry($this->dbName),
$this->escapeCredentialEntry($this->userName),
$this->escapeCredentialEntry($this->password),
];
return implode(':', $contents);
}
protected function escapeCredentialEntry($entry): string
{
$entry = str_replace('\\', '\\\\', $entry);
$entry = str_replace(':', '\\:', $entry);
return $entry;
}
public function guardAgainstIncompleteCredentials()
{
foreach (['userName', 'dbName', 'host'] as $requiredProperty) {
if (empty($this->$requiredProperty)) {
throw CannotStartDump::emptyParameter($requiredProperty);
}
}
}
protected function getEnvironmentVariablesForDumpCommand(string $temporaryCredentialsFile): array
{
return [
'PGPASSFILE' => $temporaryCredentialsFile,
'PGDATABASE' => $this->dbName,
];
}
public function doNotCreateTables(): self
{
$this->createTables = false;
return $this;
}
public function getProcess(string $dumpFile): Process
{
$command = $this->getDumpCommand($dumpFile);
fwrite($this->getTempFileHandle(), $this->getContentsOfCredentialsFile());
$temporaryCredentialsFile = stream_get_meta_data($this->getTempFileHandle())['uri'];
$envVars = $this->getEnvironmentVariablesForDumpCommand($temporaryCredentialsFile);
return Process::fromShellCommandline($command, null, $envVars, null, $this->timeout);
}
/**
* @return false|resource
*/
public function getTempFileHandle()
{
return $this->tempFileHandle;
}
/**
* @param false|resource $tempFileHandle
*/
public function setTempFileHandle($tempFileHandle): void
{
$this->tempFileHandle = $tempFileHandle;
}
}

View File

@@ -0,0 +1,61 @@
<?php
namespace Spatie\DbDumper\Databases;
use Spatie\DbDumper\DbDumper;
use SQLite3;
use Symfony\Component\Process\Process;
class Sqlite extends DbDumper
{
public function dumpToFile(string $dumpFile): void
{
$process = $this->getProcess($dumpFile);
$process->run();
$this->checkIfDumpWasSuccessFul($process, $dumpFile);
}
public function getDbTables(): array
{
$db = new SQLite3($this->dbName);
$query = $db->query("SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%';");
$tables = [];
while ($table = $query->fetchArray(SQLITE3_ASSOC)) {
$tables[] = $table['name'];
}
$db->close();
return $tables;
}
public function getDumpCommand(string $dumpFile): string
{
$includeTables = rtrim(' ' . implode(' ', $this->includeTables));
if (empty($includeTables) && ! empty($this->excludeTables)) {
$tables = $this->getDbTables();
$includeTables = rtrim(' ' . implode(' ', array_diff($tables, $this->excludeTables)));
}
$dumpInSqlite = "echo 'BEGIN IMMEDIATE;\n.dump{$includeTables}'";
if ($this->isWindows()) {
$dumpInSqlite = "(echo BEGIN IMMEDIATE; & echo .dump{$includeTables})";
}
$quote = $this->determineQuote();
$command = sprintf(
"{$dumpInSqlite} | {$quote}%ssqlite3{$quote} --bail {$quote}%s{$quote}",
$this->dumpBinaryPath,
$this->dbName
);
return $this->echoToFile($command, $dumpFile);
}
public function getProcess(string $dumpFile): Process
{
$command = $this->getDumpCommand($dumpFile);
return Process::fromShellCommandline($command, null, null, null, $this->timeout);
}
}

262
vendor/spatie/db-dumper/src/DbDumper.php vendored Normal file
View File

@@ -0,0 +1,262 @@
<?php
namespace Spatie\DbDumper;
use Spatie\DbDumper\Compressors\Compressor;
use Spatie\DbDumper\Exceptions\CannotSetParameter;
use Spatie\DbDumper\Exceptions\DumpFailed;
use Symfony\Component\Process\Process;
abstract class DbDumper
{
protected string $databaseUrl = '';
protected string $dbName = '';
protected string $userName = '';
protected string $password = '';
protected string $host = 'localhost';
protected int $port = 5432;
protected string $socket = '';
protected int $timeout = 0;
protected string $dumpBinaryPath = '';
protected array $includeTables = [];
protected array $excludeTables = [];
protected array $extraOptions = [];
protected array $extraOptionsAfterDbName = [];
protected ?object $compressor = null;
public static function create(): static
{
return new static();
}
public function getDbName(): string
{
return $this->dbName;
}
public function setDbName(string $dbName): self
{
$this->dbName = $dbName;
return $this;
}
public function getDatabaseUrl(): string
{
return $this->databaseUrl;
}
public function setDatabaseUrl(string $databaseUrl): self
{
$this->databaseUrl = $databaseUrl;
$this->configureFromDatabaseUrl();
return $this;
}
public function setUserName(string $userName): self
{
$this->userName = $userName;
return $this;
}
public function setPassword(string $password): self
{
$this->password = $password;
return $this;
}
public function setHost(string $host): self
{
$this->host = $host;
return $this;
}
public function getHost(): string
{
return $this->host;
}
public function setPort(int $port): self
{
$this->port = $port;
return $this;
}
public function setSocket(string $socket): self
{
$this->socket = $socket;
return $this;
}
public function setTimeout(int $timeout): self
{
$this->timeout = $timeout;
return $this;
}
public function setDumpBinaryPath(string $dumpBinaryPath): self
{
if ($dumpBinaryPath !== '' && ! str_ends_with($dumpBinaryPath, '/')) {
$dumpBinaryPath .= '/';
}
$this->dumpBinaryPath = $dumpBinaryPath;
return $this;
}
public function getCompressorExtension(): string
{
return $this->compressor->useExtension();
}
public function useCompressor(Compressor $compressor): self
{
$this->compressor = $compressor;
return $this;
}
public function includeTables(string | array $includeTables): self
{
if (! empty($this->excludeTables)) {
throw CannotSetParameter::conflictingParameters('includeTables', 'excludeTables');
}
if (! is_array($includeTables)) {
$includeTables = explode(', ', $includeTables);
}
$this->includeTables = $includeTables;
return $this;
}
public function excludeTables(string | array $excludeTables): self
{
if (! empty($this->includeTables)) {
throw CannotSetParameter::conflictingParameters('excludeTables', 'includeTables');
}
if (! is_array($excludeTables)) {
$excludeTables = explode(', ', $excludeTables);
}
$this->excludeTables = $excludeTables;
return $this;
}
public function addExtraOption(string $extraOption): self
{
if (! empty($extraOption)) {
$this->extraOptions[] = $extraOption;
}
return $this;
}
public function addExtraOptionAfterDbName(string $extraOptionAfterDbName): self
{
if (! empty($extraOptionAfterDbName)) {
$this->extraOptionsAfterDbName[] = $extraOptionAfterDbName;
}
return $this;
}
abstract public function dumpToFile(string $dumpFile): void;
public function checkIfDumpWasSuccessFul(Process $process, string $outputFile): void
{
if (! $process->isSuccessful()) {
throw DumpFailed::processDidNotEndSuccessfully($process);
}
if (! file_exists($outputFile)) {
throw DumpFailed::dumpfileWasNotCreated($process);
}
if (filesize($outputFile) === 0) {
throw DumpFailed::dumpfileWasEmpty($process);
}
}
protected function configureFromDatabaseUrl(): void
{
$parsed = (new DsnParser($this->databaseUrl))->parse();
$componentMap = [
'host' => 'setHost',
'port' => 'setPort',
'database' => 'setDbName',
'username' => 'setUserName',
'password' => 'setPassword',
];
foreach ($parsed as $component => $value) {
if (isset($componentMap[$component])) {
$setterMethod = $componentMap[$component];
if (! $value || in_array($value, ['', 'null'])) {
continue;
}
$this->$setterMethod($value);
}
}
}
protected function getCompressCommand(string $command, string $dumpFile): string
{
$compressCommand = $this->compressor->useCommand();
if ($this->isWindows()) {
return "{$command} | {$compressCommand} > {$dumpFile}";
}
return "(((({$command}; echo \$? >&3) | {$compressCommand} > {$dumpFile}) 3>&1) | (read x; exit \$x))";
}
protected function echoToFile(string $command, string $dumpFile): string
{
$dumpFile = '"' . addcslashes($dumpFile, '\\"') . '"';
if ($this->compressor) {
return $this->getCompressCommand($command, $dumpFile);
}
return $command . ' > ' . $dumpFile;
}
protected function determineQuote(): string
{
return $this->isWindows() ? '"' : "'";
}
protected function isWindows(): bool
{
return str_starts_with(strtoupper(PHP_OS), 'WIN');
}
}

View File

@@ -0,0 +1,106 @@
<?php
namespace Spatie\DbDumper;
use Spatie\DbDumper\Exceptions\InvalidDatabaseUrl;
class DsnParser
{
protected string $dsn;
public function __construct(string $dsn)
{
$this->dsn = $dsn;
}
public function parse(): array
{
$rawComponents = $this->parseUrl($this->dsn);
$decodedComponents = $this->parseNativeTypes(
array_map('rawurldecode', $rawComponents)
);
return array_merge(
$this->getPrimaryOptions($decodedComponents),
$this->getQueryOptions($rawComponents)
);
}
protected function getPrimaryOptions($url): array
{
return array_filter([
'database' => $this->getDatabase($url),
'host' => $url['host'] ?? null,
'port' => $url['port'] ?? null,
'username' => $url['user'] ?? null,
'password' => $url['pass'] ?? null,
], static fn ($value) => ! is_null($value));
}
protected function getDatabase($url): ?string
{
$path = $url['path'] ?? null;
if (! $path) {
return null;
}
if ($path === '/') {
return null;
}
if (isset($url['scheme']) && str_contains($url['scheme'], 'sqlite')) {
return $path;
}
return trim($path, '/');
}
protected function getQueryOptions($url)
{
$queryString = $url['query'] ?? null;
if (! $queryString) {
return [];
}
$query = [];
parse_str($queryString, $query);
return $this->parseNativeTypes($query);
}
protected function parseUrl($url): array
{
$url = preg_replace('#^(sqlite3?):///#', '$1://null/', $url);
$parsedUrl = parse_url($url);
if ($parsedUrl === false) {
throw InvalidDatabaseUrl::invalidUrl($url);
}
return $parsedUrl;
}
protected function parseNativeTypes($value)
{
if (is_array($value)) {
return array_map([$this, 'parseNativeTypes'], $value);
}
if (! is_string($value)) {
return $value;
}
$parsedValue = json_decode($value, true);
if (json_last_error() === JSON_ERROR_NONE) {
return $parsedValue;
}
return $value;
}
}

View File

@@ -0,0 +1,13 @@
<?php
namespace Spatie\DbDumper\Exceptions;
use Exception;
class CannotSetParameter extends Exception
{
public static function conflictingParameters(string $name, string $conflictName): static
{
return new static("Cannot set `{$name}` because it conflicts with parameter `{$conflictName}`.");
}
}

View File

@@ -0,0 +1,13 @@
<?php
namespace Spatie\DbDumper\Exceptions;
use Exception;
class CannotStartDump extends Exception
{
public static function emptyParameter(string $name): static
{
return new static("Parameter `{$name}` cannot be empty.");
}
}

View File

@@ -0,0 +1,52 @@
<?php
namespace Spatie\DbDumper\Exceptions;
use Exception;
use Symfony\Component\Process\Process;
class DumpFailed extends Exception
{
public static function processDidNotEndSuccessfully(Process $process): static
{
$processOutput = static::formatProcessOutput($process);
return new static("The dump process failed with a none successful exitcode.{$processOutput}");
}
public static function dumpfileWasNotCreated(Process $process): static
{
$processOutput = static::formatProcessOutput($process);
return new static("The dumpfile could not be created.{$processOutput}");
}
public static function dumpfileWasEmpty(Process $process): static
{
$processOutput = static::formatProcessOutput($process);
return new static("The created dumpfile is empty.{$processOutput}");
}
protected static function formatProcessOutput(Process $process): string
{
$output = $process->getOutput() ?: '<no output>';
$errorOutput = $process->getErrorOutput() ?: '<no output>';
$exitCodeText = $process->getExitCodeText() ?: '<no exit text>';
return <<<CONSOLE
Exitcode
========
{$process->getExitCode()}: {$exitCodeText}
Output
======
{$output}
Error Output
============
{$errorOutput}
CONSOLE;
}
}

View File

@@ -0,0 +1,13 @@
<?php
namespace Spatie\DbDumper\Exceptions;
use Exception;
class InvalidDatabaseUrl extends Exception
{
public static function invalidUrl(string $databaseUrl): static
{
return new static("Database URL `{$databaseUrl}` is invalid and cannot be parsed.");
}
}