Checkpoint   A
last analyzed

Complexity

Total Complexity 22

Size/Duplication

Total Lines 182
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 3

Test Coverage

Coverage 31.65%

Importance

Changes 0
Metric Value
wmc 22
lcom 1
cbo 3
dl 0
loc 182
ccs 25
cts 79
cp 0.3165
rs 10
c 0
b 0
f 0

11 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
A remove() 0 5 1
A getAll() 0 15 2
A getLastCheckpointId() 0 4 2
A getCheckpointPath() 0 3 1
A assertCheckpointExists() 0 6 3
B create() 0 40 6
A restore() 0 7 1
A checkpointExists() 0 3 1
A createCheckpointId() 0 4 1
A getAllCheckpointIds() 0 12 3
1
<?php
2
/**
3
 * @author Victor Dubiniuk <[email protected]>
4
 *
5
 * @copyright Copyright (c) 2015, ownCloud, Inc.
6
 * @license AGPL-3.0
7
 *
8
 * This code is free software: you can redistribute it and/or modify
9
 * it under the terms of the GNU Affero General Public License, version 3,
10
 * as published by the Free Software Foundation.
11
 *
12
 * This program is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
 * GNU Affero General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU Affero General Public License, version 3,
18
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
19
 *
20
 */
21
22
namespace Owncloud\Updater\Utils;
23
24
use Owncloud\Updater\Console\Application;
25
26
/**
27
 * Class Checkpoint
28
 *
29
 * @package Owncloud\Updater\Utils
30
 */
31
class Checkpoint {
32
33
	const CORE_DIR = 'core';
34
	const APP_DIR = 'apps';
35
36
	/**
37
	 * @var Locator $locator
38
	 */
39
	protected $locator;
40
41
	/**
42
	 * @var Filesystemhelper $fsHelper
43
	 */
44
	protected $fsHelper;
45
46
	/**
47
	 *
48
	 * @param Locator $locator
49
	 * @param FilesystemHelper $fsHelper
50
	 */
51 2
	public function __construct(Locator $locator, FilesystemHelper $fsHelper){
52 2
		$this->locator = $locator;
53 2
		$this->fsHelper = $fsHelper;
54 2
	}
55
56
	/**
57
	 * Creates a checkpoint
58
	 * @return string
59
	 * @throws \Exception if base checkpoint directory is not writable
60
	 */
61
	public function create(){
62
		$checkpointId = $this->createCheckpointId();
63
		$checkpointPath = $this->getCheckpointPath($checkpointId);
64
		try{
65
			if (!$this->fsHelper->isWritable($this->locator->getCheckpointDir())){
66
				throw new \Exception($this->locator->getCheckpointDir() . ' is not writable.');
67
			}
68
			$this->fsHelper->mkdir($checkpointPath);
69
70
			$checkpointCorePath = $checkpointPath . '/' . self::CORE_DIR;
71
			$this->fsHelper->mkdir($checkpointCorePath);
72
			$core = $this->locator->getRootDirItems();
73
			foreach ($core as $coreItem){
74
				$cpItemPath = $checkpointCorePath . '/' . basename($coreItem);
75
				$this->fsHelper->copyr($coreItem, $cpItemPath, true);
76
			}
77
			//copy config.php
78
			$configDirSrc = $this->locator->getOwnCloudRootPath() . '/config';
79
			$configDirDst = $checkpointCorePath . '/config';
80
			$this->fsHelper->copyr($configDirSrc, $configDirDst, true);
81
			
82
			$checkpointAppPath = $checkpointPath . '/' . self::APP_DIR;
83
			$this->fsHelper->mkdir($checkpointAppPath);
84
			$appManager = Application::$container['utils.appmanager'];
85
			$apps = $appManager->getAllApps();
86
			foreach ($apps as $appId){
87
				$appPath = $appManager->getAppPath($appId);
88
				if ($appPath){
89
					$this->fsHelper->copyr($appPath, $checkpointAppPath . '/' . $appId, true);
90
				}
91
			}
92
93
		} catch (\Exception $e){
94
			$application = Application::$container['application'];
95
			$application->getLogger()->error($e->getMessage());
96
			$this->fsHelper->removeIfExists($checkpointPath);
97
			throw $e;
98
		}
99
		return $checkpointId;
100
	}
101
102
	/**
103
	 * Restore a checkpoint by id
104
	 * @param string $checkpointId id of checkpoint
105
	 * @return array
106
	 * @throws \UnexpectedValueException if there is no checkpoint with this id
107
	 */
108
	public function restore($checkpointId){
109
		$this->assertCheckpointExists($checkpointId);
110
		$checkpointDir = $this->locator->getCheckpointDir() . '/' . $checkpointId;
111
		$ocRoot = $this->locator->getOwnCloudRootPath();
112
		$this->fsHelper->copyr($checkpointDir . '/' . self::CORE_DIR, $ocRoot, false);
113
		$this->fsHelper->copyr($checkpointDir . '/' . self::APP_DIR, $ocRoot . '/' . self::APP_DIR, false);
114
	}
115
116
	/**
117
	 * Remove a checkpoint by id
118
	 * @param string $checkpointId id of checkpoint
119
	 * @return array
120
	 * @throws \UnexpectedValueException if there is no checkpoint with this id
121
	 */
122
	public function remove($checkpointId){
123
		$this->assertCheckpointExists($checkpointId);
124
		$checkpointPath = $this->getCheckpointPath($checkpointId);
125
		$this->fsHelper->removeIfExists($checkpointPath);
126
	}
127
128
	/**
129
	 * Return all checkpoints as an array of items [ 'title', 'date' ]
130
	 * @return array
131
	 */
132 2
	public function getAll(){
133 2
		$checkpoints = [];
134 2
		foreach ($this->getAllCheckpointIds() as $dir){
135 1
			$checkpoints[] = [
136 1
				'title' => $dir,
137 1
				'date' => date(
138 1
					"F d Y H:i", 
139 1
					$this->fsHelper->filemtime(
140 1
						$this->locator->getCheckpointDir() . '/' . $dir
141
					)
142
				)
143
			];
144
		}
145 2
		return $checkpoints;
146
	}
147
148
	/**
149
	 * Check if there is a checkpoint with a given id
150
	 * @param string $checkpointId id of checkpoint
151
	 * @return bool
152
	 */
153
	public function checkpointExists($checkpointId){
154
		return in_array($checkpointId, $this->getAllCheckpointIds());
155
	}
156
157
	/**
158
	 * Get the most recent checkpoint Id
159
	 * @return string|bool
160
	 */
161
	public function getLastCheckpointId(){
162
		$allCheckpointIds = $this->getAllCheckpointIds();
163
		return count($allCheckpointIds) > 0 ? end($allCheckpointIds) : false;
164
	}
165
166
	/**
167
	 * Return array of all checkpoint ids
168
	 * @return array
169
	 */
170 2
	public function getAllCheckpointIds(){
171 2
		$checkpointDir = $this->locator->getCheckpointDir();
172 2
		$content = $this->fsHelper->isDir($checkpointDir) ? $this->fsHelper->scandir($checkpointDir) : [];
173 2
		$checkpoints = array_filter(
174 2
 			$content,
175
 			function($dir){
176 1
 				$checkpointPath = $this->getCheckpointPath($dir);
177 1
 				return !in_array($dir, ['.', '..']) && $this->fsHelper->isDir($checkpointPath);
178 2
 			}
179
 		);
180 2
 		return $checkpoints;
181
	}
182
183
	/**
184
	 * Create an unique checkpoint id
185
	 * @return string
186
	 */
187
	protected function createCheckpointId(){
188
		$versionString = implode('.', $this->locator->getInstalledVersion());
189
		return uniqid($versionString . '-');
190
	}
191
192
	/**
193
	 * Get an absolute path to the checkpoint directory by checkpoint Id
194
	 * @param string $checkpointId id of checkpoint
195
	 * @return string
196
	 */
197 1
	public function getCheckpointPath($checkpointId){
198 1
		return $this->locator->getCheckpointDir() . '/' . $checkpointId;
199
	}
200
201
	/**
202
	 * Produce an error on non-existing checkpoints
203
	 * @param string $checkpointId id of checkpoint
204
	 * @throws \UnexpectedValueException if there is no checkpoint with this id
205
	 */
206
	private function assertCheckpointExists($checkpointId){
207
		if (!$this->checkpointExists($checkpointId) || $checkpointId === ''){
208
			$message = sprintf('Checkpoint %s does not exist.', $checkpointId);
209
			throw new \UnexpectedValueException($message);
210
		}
211
	}
212
}
213