From b225c26fb81ce73f30d64082cc566f0b1572d47f Mon Sep 17 00:00:00 2001 From: markitosgv Date: Sun, 20 Jul 2014 13:10:11 +0200 Subject: [PATCH] #5 New Feature: Can remove older backups in relative PHP datetime format - Local filesystem supported - Dropbox supported --- config/config.ini.php | 4 +- src/Dimsav/Backup/Shell.php | 5 ++ src/Dimsav/Backup/Storage/Drivers/Dropbox.php | 66 ++++++++++++++++- src/Dimsav/Backup/Storage/Drivers/Local.php | 71 ++++++++++++++++++- src/Dimsav/Backup/Storage/StorageFactory.php | 2 +- 5 files changed, 141 insertions(+), 7 deletions(-) diff --git a/config/config.ini.php b/config/config.ini.php index 8c5e73f..026befb 100644 --- a/config/config.ini.php +++ b/config/config.ini.php @@ -47,12 +47,14 @@ "my_dropbox" => array( "driver" => "dropbox", "username" => "dropbox@example.com", - "destination" => "/Backups" + "destination" => "/Backups", + "clean" => "-7 days", //All relative formats. Ex "last monday" :: http://php.net/manual/en/datetime.formats.relative.php ), "my_system" => array( "driver" => "local", "destination" => "/backups", + "clean" => "-7 days", //All relative formats. Ex "last monday" :: http://php.net/manual/en/datetime.formats.relative.php ), ), diff --git a/src/Dimsav/Backup/Shell.php b/src/Dimsav/Backup/Shell.php index 4af984b..4ab69e8 100644 --- a/src/Dimsav/Backup/Shell.php +++ b/src/Dimsav/Backup/Shell.php @@ -48,4 +48,9 @@ public function getStatusCode() { return $this->statusCode; } + + public function cleanOutput() + { + $this->output = null; + } } diff --git a/src/Dimsav/Backup/Storage/Drivers/Dropbox.php b/src/Dimsav/Backup/Storage/Drivers/Dropbox.php index 6158be4..a5d943a 100644 --- a/src/Dimsav/Backup/Storage/Drivers/Dropbox.php +++ b/src/Dimsav/Backup/Storage/Drivers/Dropbox.php @@ -11,6 +11,7 @@ class Dropbox implements Storage private $destination; private $name; private $username; + private $clean; /** * @var Shell @@ -26,18 +27,48 @@ public function __construct(array $config, Shell $shell) public function store($file, $projectName = null) { + $file = new \SplFileInfo($file); + $prefix = ($file->getExtension() == "sql") ? "sql" : "files"; + $this->validate(); $this->validateFile($file); - $this->shell->exec($this->getCommand($file, $projectName)); + $this->shell->exec($this->getCommand($file, $projectName, $prefix)); + + $this->cleanOldBackups($projectName, $prefix); } - public function getCommand($file, $projectName) + private function cleanOldBackups($projectName, $prefix) { - $destination = $projectName ? $this->destination . "/$projectName" : $this->destination; + //clean shell output + $this->shell->cleanOutput(); + + //clean old backups + $this->shell->exec($this->getFileListCommand($projectName, $prefix)); + $deleteList = $this->parseFiles($this->shell->getOutput()); + + foreach ($deleteList as $file) { + $this->shell->exec($this->removeCommand($projectName, $file, $prefix)); + } + } + + public function getCommand($file, $projectName, $prefix) + { + + $destination = $projectName ? $this->destination . "/$projectName". "/". $prefix : $this->destination ."/". $prefix; $destination .= substr($destination, -1, 1) == '/' ? basename($file) : '/' . basename($file); return $this->getScript().' -f '.$this->getConfigFile()." upload $file " . $destination; } + public function getFileListCommand($projectName, $prefix) + { + return $this->getScript().' -f '.$this->getConfigFile()." list ". $this->destination . "/$projectName"."/".$prefix; + } + + private function removeCommand($projectName, $file, $prefix) + { + return $this->getScript().' -f '.$this->getConfigFile()." delete ". $this->destination . "/$projectName"."/".$prefix."/".$file; + } + /** * @return void * @throws \Dimsav\Backup\Storage\Exceptions\TokenNotSetException @@ -102,5 +133,34 @@ private function setProperties(array $config) $this->name = isset($config['name']) ? $config['name'] : null; $this->username = isset($this->config['username']) ? $this->config['username'] : null; $this->destination = isset($config['destination']) ? $config['destination'] : '/'; + $this->clean = isset($config['clean']) ? $config['clean'] : '365 days'; + } + + private function parseFiles($data) + { + $deleteList = array(); + $data = explode("[F]", $data); + $data = array_slice($data, 1); + + foreach ($data as $file) { + + preg_match('([\s-]\S{1,})', ltrim($file), $filename); + $filename = ltrim($filename[0]); + + preg_match('([\s-]\S{1,16})', ltrim($file), $result); + $date = explode("_", $result[0]); + $time = str_replace("-",":",$date[1]); + $date = $date[0]; + $datetime = new \DateTime($date.$time); + $today = new \DateTime(); + + $today->modify($this->clean); + if ($datetime < $today) { + $deleteList[] = $filename; + } + } + + return $deleteList; } + } diff --git a/src/Dimsav/Backup/Storage/Drivers/Local.php b/src/Dimsav/Backup/Storage/Drivers/Local.php index c5c0bc3..52c0915 100644 --- a/src/Dimsav/Backup/Storage/Drivers/Local.php +++ b/src/Dimsav/Backup/Storage/Drivers/Local.php @@ -1,5 +1,6 @@ shell = $shell; $this->setProperties($config); } @@ -17,6 +25,7 @@ private function setProperties(array $config) { $this->name = isset($config['name']) ? $config['name'] : null; $this->destination = $this->getDestination($config); + $this->clean = isset($config['clean']) ? $config['clean'] : '365 days'; } private function getDestination($config) @@ -42,7 +51,11 @@ public function store($file, $projectName = null) $this->validate(); $this->validateFile($file); - $exportDir = $this->destination . '/' . $projectName; + $file = new \SplFileInfo($file); + + $prefix = ($file->getExtension() == "sql") ? "sql" : "files"; + + $exportDir = $this->destination . '/' . $projectName. "/". $prefix; if ($projectName && ! is_dir($exportDir)) { mkdir($exportDir, 0777, true); @@ -51,6 +64,33 @@ public function store($file, $projectName = null) // we don't want to move the file for the case we have more storages copy($file, $exportDir . '/' . basename($file)); + + $this->cleanOldBackups($projectName, $prefix); + } + + private function cleanOldBackups($projectName, $prefix) + { + //clean shell output + $this->shell->cleanOutput(); + + //clean old backups + $this->shell->exec($this->getFileListCommand($projectName, $prefix)); + + $deleteList = $this->parseFiles($this->shell->getOutput()); + + foreach ($deleteList as $file) { + $this->shell->exec($this->removeCommand($projectName, $file, $prefix)); + } + } + + public function getFileListCommand($projectName, $prefix) + { + return "ls ". $this->destination . "/$projectName"."/".$prefix." | tr '\n' '\n' | sed 's/$/|||/g'"; + } + + private function removeCommand($projectName, $file, $prefix) + { + return " rm ". $this->destination . "/$projectName"."/".$prefix."/".$file; } /** @@ -79,4 +119,31 @@ private function validateFile($file) throw new \InvalidArgumentException("Local storage '{$this->name}' could not find the file '$file'."); } } + + private function parseFiles($data) + { + $deleteList = array(); + $data = explode("|||", $data); + array_pop($data); + + foreach ($data as $file) { + + $filename = $file; + + preg_match('(\S{1,16})', ltrim($file), $result); + $date = explode("_", $result[0]); + $time = str_replace("-",":",$date[1]); + $date = $date[0]; + + $datetime = new \DateTime($date.$time); + $today = new \DateTime(); + + $today->modify($this->clean); + if ($datetime < $today) { + $deleteList[] = $filename; + } + } + + return $deleteList; + } } \ No newline at end of file diff --git a/src/Dimsav/Backup/Storage/StorageFactory.php b/src/Dimsav/Backup/Storage/StorageFactory.php index 9a5010d..0fa1380 100644 --- a/src/Dimsav/Backup/Storage/StorageFactory.php +++ b/src/Dimsav/Backup/Storage/StorageFactory.php @@ -85,7 +85,7 @@ private function createStorage($storageName) case 'dropbox': return new Dropbox($this->getDriverConfig($storageName), new Shell()); case 'local': - return new Local($this->getDriverConfig($storageName)); + return new Local($this->getDriverConfig($storageName), new Shell()); } throw new StorageDriverNotSupportedException; }