Completed
Push — master ( f4a48e...a101ca )
by Sean
8s
created

SSPak::extract()   B

Complexity

Conditions 4
Paths 6

Size

Total Lines 42
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 42
rs 8.5806
c 0
b 0
f 0
cc 4
eloc 16
nc 6
nop 1
1
<?php
2
3
use SilverStripe\SsPak\DataExtractor\DatabaseConnector;
4
use SilverStripe\SsPak\DataExtractor\CsvTableWriter;
5
use SilverStripe\SsPak\DataExtractor\CsvTableReader;
6
7
/**
8
 * SSPak handler
9
 */
10
class SSPak {
11
	protected $executor;
12
13
	/**
14
	 * Create a new handler
15
	 * @param Executor $executor The Executor object to handle command execution
16
	 */
17
	function __construct($executor) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
18
		$this->executor = $executor;
19
	}
20
21
	function getActions() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
22
		return array(
23
			"help" => array(
24
				"description" => "Show this help message.",
25
				"method" => "help",
26
			),
27
			"save" => array(
28
				"description" => "Save an .sspak file from a SilverStripe site.",
29
				"unnamedArgs" => array("webroot", "sspak file"),
30
				"namedArgs" => array("identity"),
31
				"method" => "save",
32
			),
33
			"load" => array(
34
				"description" => "Load an .sspak file into a SilverStripe site. Does not backup - be careful!",
35
				"unnamedArgs" => array("sspak file", "[webroot]"),
36
				"namedArgs" => array("identity"),
37
				"namedFlags" => array("drop-db"),
38
				"method" => "load",
39
			),
40
			"saveexisting" => array(
41
				"description" => "Create an .sspak file from database SQL dump and/or assets. Does not require a SilverStripe site.",
42
				"unnamedArgs" => array("sspak file"),
43
				"namedArgs" => array("db", "assets"),
44
				"method" => "saveexisting"
45
			),
46
			"extract" => array(
47
				"description" => "Extract an .sspak file into the current working directory. Does not require a SilverStripe site.",
48
				"unnamedArgs" => array("sspak file", "destination path"),
49
				"method" => "extract"
50
			),
51
			"listtables" => array(
52
				"description" => "List tables in the database",
53
				"unnamedArgs" => array("webroot"),
54
				"method" => "listTables"
55
			),
56
57
			"savecsv" => array(
58
				"description" => "Save tables in the database to a collection of CSV files",
59
				"unnamedArgs" => array("webroot", "output-path"),
60
				"method" => "saveCsv"
61
			),
62
63
			"loadcsv" => array(
64
				"description" => "Load tables from collection of CSV files to a webroot",
65
				"unnamedArgs" => array("input-path", "webroot"),
66
				"method" => "loadCsv"
67
			),
68
			/*
0 ignored issues
show
Unused Code Comprehensibility introduced by
57% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
69
70
			"install" => array(
71
				"description" => "Install a .sspak file into a new environment.",
72
				"unnamedArgs" => array("sspak file", "new webroot"),
73
				"method" => "install",
74
			),
75
			"bundle" => array(
76
				"description" => "Bundle a .sspak file into a self-extracting executable .sspak.phar installer.",
77
				"unnamedArgs" => array("sspak file", "executable"),
78
				"method" => "bundle",
79
			),
80
			"transfer" => array(
81
				"description" => "Transfer db & assets from one site to another (not implemented yet).",
82
				"unnamedArgs" => array("src webroot", "dest webroot"),
83
				"method" => "transfer",
84
			),
85
			*/
86
		);
87
	}
88
89
	function help($args) {
0 ignored issues
show
Unused Code introduced by
The parameter $args is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
90
		echo "SSPak: manage SilverStripe .sspak archives.\n\nUsage:\n";
91
		foreach($this->getActions() as $action => $info) {
92
			echo "sspak $action";
93
			if(!empty($info['unnamedArgs'])) {
94
				foreach($info['unnamedArgs'] as $arg) echo " ($arg)";
0 ignored issues
show
Bug introduced by
The expression $info['unnamedArgs'] of type string|array<integer,string,{"0":"string"}> is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
95
			}
96
			if(!empty($info['namedFlags'])) {
97
				foreach($info['namedFlags'] as $arg) echo " (--$arg)";
0 ignored issues
show
Bug introduced by
The expression $info['namedFlags'] of type string|array<integer,string,{"0":"string"}> is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
98
			}
99
			if(!empty($info['namedArgs'])) {
100
				foreach($info['namedArgs'] as $arg) echo " --$arg=\"$arg value\"";
0 ignored issues
show
Bug introduced by
The expression $info['namedArgs'] of type string|array<integer,string,{"0":"string"}> is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
101
			}
102
			echo "\n  {$info['description']}\n\n";
103
		}
104
	}
105
106
	/**
107
	 * Save an existing database and/or assets into an .sspak.phar file.
108
	 * Does the same as {@link save()} but doesn't require an existing site.
109
	 */
110
	function saveexisting($args) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
111
		$executor = $this->executor;
112
113
		$args->requireUnnamed(array('sspak file'));
114
		$unnamedArgs = $args->getUnnamedArgs();
115
		$namedArgs = $args->getNamedArgs();
116
117
		$sspak = new SSPakFile($unnamedArgs[0], $executor);
118
119
		// Look up which parts of the sspak are going to be saved
120
		$pakParts = $args->pakParts();
121
122
		$filesystem = new FilesystemEntity(null, $executor);
123
124
		if($pakParts['db']) {
125
			$dbPath = escapeshellarg($namedArgs['db']);
126
			$process = $filesystem->createProcess("cat $dbPath | gzip -c");
127
			$sspak->writeFileFromProcess('database.sql.gz', $process);
128
		}
129
130
		if($pakParts['assets']) {
131
			$assetsParentArg = escapeshellarg(dirname($namedArgs['assets']));
132
			$assetsBaseArg = escapeshellarg(basename($namedArgs['assets']));
133
			$process = $filesystem->createProcess("cd $assetsParentArg && tar cfh - $assetsBaseArg | gzip -c");
134
			$sspak->writeFileFromProcess('assets.tar.gz', $process);
135
		}
136
	}
137
138
	/**
139
	 * Extracts an existing database and/or assets from a sspak into the given directory,
140
	 * defaulting the current working directory if the destination is not given.
141
	 */
142
	function extract($args) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
143
		$executor = $this->executor;
144
145
		$args->requireUnnamed(array('source sspak file'));
146
		$unnamedArgs = $args->getUnnamedArgs();
147
		$file = $unnamedArgs[0];
148
		$dest = !empty($unnamedArgs[1]) ? $unnamedArgs[1] : getcwd();
149
150
		// Phar and PharData use "ustar" format for tar archives (http://php.net/manual/pl/phar.fileformat.tar.php).
151
		// Ustar does not support files larger than 8 GB.
152
		// If the sspak has been created through tar and gz directly, it will probably be in POSIX, PAX or GNU formats,
153
		// which do support >8 GB files. Such archive cannot be accessed by Phar/PharData, and needs to be handled
154
		// manually - it will just spew checksum errors where PHP expects to see ustar headers, but finds garbage
155
		// from other formats.
156
		// There is no cross-platform way of checking the assets.tar.gz size without unpacking, so we assume the size
157
		// of database is negligible which lets us approximate the size of assets.
158
		if (filesize($file) > 8*1024*1024*1024) {
159
			$msg = <<<EOM
160
161
ERROR: SSPak is unable to extract archives over 8 GB.
162
163
Packed asset or database sizes over 8 GB are not supported due to PHP Phar library limitations.
164
You can still access your data directly by using the tar utility:
165
166
	tar xzf "%s"
167
168
This tool is sorry for the inconvenience and stands aside in disgrace.
169
See http://silverstripe.github.io/sspak/, "Manual access" for more information.
170
171
EOM;
172
			printf($msg, $file);
173
			die(1);
174
		}
175
176
		$sspak = new SSPakFile($file, $executor);
177
178
		// Validation
179
		if(!$sspak->exists()) throw new Exception("File '$file' doesn't exist.");
180
181
		$phar = $sspak->getPhar();
182
		$phar->extractTo($dest);
183
	}
184
185
	function listTables($args) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
186
		$args->requireUnnamed(array('webroot'));
187
		$unnamedArgs = $args->getUnnamedArgs();
188
		$webroot = $unnamedArgs[0];
189
190
		$db = new DatabaseConnector($webroot);
191
192
		print_r($db->getTables());
193
	}
194
195
	function saveCsv($args) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
196
		$args->requireUnnamed(array('webroot', 'path'));
197
		$unnamedArgs = $args->getUnnamedArgs();
198
		$webroot = $unnamedArgs[0];
199
		$destPath = $unnamedArgs[1];
200
201
		if (!file_exists($destPath)) {
202
			mkdir($destPath) || die("Can't create $destPath");
203
		}
204
		if (!is_dir($destPath)) {
205
			die("$destPath isn't a directory");
206
		}
207
208
		$db = new DatabaseConnector($webroot);
209
210
		foreach($db->getTables() as $table) {
211
			$filename = $destPath . '/' . $table . '.csv';
212
			echo $filename . "...\n";
213
			touch($filename);
214
			$writer = new CsvTableWriter($filename);
215
			$db->saveTable($table, $writer);
216
		}
217
		echo "Done!";
218
	}
219
220
	function loadCsv($args) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
221
		$args->requireUnnamed(array('input-path', 'webroot'));
222
		$unnamedArgs = $args->getUnnamedArgs();
223
224
		$srcPath = $unnamedArgs[0];
225
		$webroot = $unnamedArgs[1];
226
227
		if (!is_dir($srcPath)) {
228
			die("$srcPath isn't a directory");
229
		}
230
231
		$db = new DatabaseConnector($webroot);
232
233
		foreach($db->getTables() as $table) {
234
			$filename = $srcPath . '/' . $table . '.csv';
235
			if(file_exists($filename)) {
236
				echo $filename . "...\n";
237
				$reader = new CsvTableReader($filename);
238
				$db->loadTable($table, $reader);
239
			} else {
240
				echo "$filename doesn't exist; skipping.\n";
241
			}
242
		}
243
		echo "Done!";
244
	}
245
	/**
246
	 * Save a .sspak.phar file
247
	 */
248
	function save($args) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
249
		$executor = $this->executor;
250
251
		$args->requireUnnamed(array('source webroot', 'dest sspak file'));
252
253
		$unnamedArgs = $args->getUnnamedArgs();
254
		$namedArgs = $args->getNamedArgs();
255
256
		$webroot = new Webroot($unnamedArgs[0], $executor);
257
		$file = $unnamedArgs[1];
258
		if(file_exists($file)) throw new Exception( "File '$file' already exists.");
259
260
		$sspak = new SSPakFile($file, $executor);
261
262
		if(!empty($namedArgs['identity'])) {
263
			// SSH private key
264
			$webroot->setSSHItentityFile($namedArgs['identity']);
265
		}
266
		if(!empty($namedArgs['from-sudo'])) $webroot->setSudo($namedArgs['from-sudo']);
267
		else if(!empty($namedArgs['sudo'])) $webroot->setSudo($namedArgs['sudo']);
268
269
		// Look up which parts of the sspak are going to be saved
270
		$pakParts = $args->pakParts();
271
272
		// Get the environment details
273
		$details = $webroot->sniff();
274
275
		// Create a build folder for the sspak file
276
		$buildFolder = "/tmp/sspak-" . rand(100000,999999);
277
		$webroot->exec(array('mkdir', $buildFolder));
0 ignored issues
show
Documentation introduced by
array('mkdir', $buildFolder) is of type array<integer,string,{"0":"string","1":"string"}>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
278
279
		$dbFile = "$buildFolder/database.sql.gz";
280
		$assetsFile = "$buildFolder/assets.tar.gz";
281
		$gitRemoteFile = "$buildFolder/git-remote";
282
283
		// Files to include in the .sspak.phar file
284
		$fileList = array();
0 ignored issues
show
Unused Code introduced by
$fileList is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
285
286
		// Save DB
287
		if($pakParts['db']) {
288
			// Check the database type
289
			$dbFunction = 'getdb_'.$details['db_type'];
290 View Code Duplication
			if(!method_exists($this,$dbFunction)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
291
				throw new Exception("Can't process database type '" . $details['db_type'] . "'");
292
			}
293
			$this->$dbFunction($webroot, $details, $sspak, basename($dbFile));
294
		}
295
296
		// Save Assets
297
		if($pakParts['assets']) {
298
			$this->getassets($webroot, $details['assets_path'], $sspak, basename($assetsFile));
299
		}
300
301
		// Save git-remote
302
		if($pakParts['git-remote']) {
303
			$this->getgitremote($webroot, $sspak, basename($gitRemoteFile));
304
		}
305
306
		// Remove the build folder
307
		$webroot->unlink($buildFolder);
308
	}
309
310
	function getdb_MySQLPDODatabase($webroot, $conf, $sspak, $filename) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
311
		return $this->getdb_MySQLDatabase($webroot, $conf, $sspak, $filename);
312
	}
313
314
	function getdb_MySQLDatabase($webroot, $conf, $sspak, $filename) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
315
		$usernameArg = escapeshellarg("--user=".$conf['db_username']);
316
		$passwordArg = escapeshellarg("--password=".$conf['db_password']);
317
		$databaseArg = escapeshellarg($conf['db_database']);
318
319
		$hostArg = '';
320
		$portArg = '';
321 View Code Duplication
		if (!empty($conf['db_server']) && $conf['db_server'] != 'localhost') {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
322
			if (strpos($conf['db_server'], ':')!==false) {
323
				// Handle "server:port" format.
324
				$server = explode(':', $conf['db_server'], 2);
325
				$hostArg = escapeshellarg("--host=".$server[0]);
326
				$portArg = escapeshellarg("--port=".$server[1]);
327
			} else {
328
				$hostArg = escapeshellarg("--host=".$conf['db_server']);
329
			}
330
		}
331
332
		$filenameArg = escapeshellarg($filename);
0 ignored issues
show
Unused Code introduced by
$filenameArg is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
333
334
		$process = $webroot->createProcess("mysqldump --skip-opt --add-drop-table --extended-insert --create-options --quick  --set-charset --default-character-set=utf8 $usernameArg $passwordArg $hostArg $portArg $databaseArg | gzip -c");
335
		$sspak->writeFileFromProcess($filename, $process);
336
		return true;
337
	}
338
339
	function getdb_PostgreSQLDatabase($webroot, $conf, $sspak, $filename) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
340
		$usernameArg = escapeshellarg("--username=".$conf['db_username']);
341
		$passwordArg = "PGPASSWORD=".escapeshellarg($conf['db_password']);
342
		$databaseArg = escapeshellarg($conf['db_database']);
343
		$hostArg = escapeshellarg("--host=".$conf['db_server']);
344
		$filenameArg = escapeshellarg($filename);
0 ignored issues
show
Unused Code introduced by
$filenameArg is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
345
346
		$process = $webroot->createProcess("$passwordArg pg_dump --clean --no-owner --no-tablespaces $usernameArg $hostArg $databaseArg | gzip -c");
347
		$sspak->writeFileFromProcess($filename, $process);
348
		return true;
349
	}
350
351
	function getassets($webroot, $assetsPath, $sspak, $filename) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
352
		$assetsParentArg = escapeshellarg(dirname($assetsPath));
353
		$assetsBaseArg = escapeshellarg(basename($assetsPath));
354
355
		$process = $webroot->createProcess("cd $assetsParentArg && tar cfh - $assetsBaseArg | gzip -c");
356
		$sspak->writeFileFromProcess($filename, $process);
357
	}
358
359
	function getgitremote($webroot, $sspak, $gitRemoteFile) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
360
		// Only do anything if we're copying from a git checkout
361
		$gitRepo = $webroot->getPath() .'/.git';
362
		if($webroot->exists($gitRepo)) {
363
			// Identify current branch
364
			$output = $webroot->exec(array('git', '--git-dir='.$gitRepo, 'branch'));
365
			if(preg_match("/\* ([^ \n]*)/", $output['output'], $matches) && strpos("(no branch)", $matches[1])===false) {
366
				// If there is a current branch, use that branch's remove
367
				$currentBranch = trim($matches[1]);
368
				$output = $webroot->exec(array('git', '--git-dir='.$gitRepo, 'config','--get',"branch.$currentBranch.remote"));
369
				$remoteName = trim($output['output']);
370
				if(!$remoteName) $remoteName = 'origin';
371
372
			// Default to origin
373
			} else {
374
				$currentBranch = null;
375
				$remoteName = 'origin';
376
			}
377
378
			// Determine the URL of that remote
379
			$output = $webroot->exec(array('git', '--git-dir='.$gitRepo, 'config','--get',"remote.$remoteName.url"));
380
			$remoteURL = trim($output['output']);
381
382
			// Determine the current SHA
383
			$output = $webroot->exec(array('git', '--git-dir='.$gitRepo, 'log','-1','--format=%H'));
384
			$sha = trim($output['output']);
385
386
			$content = "remote = $remoteURL\nbranch = $currentBranch\nsha = $sha\n";
387
388
			$sspak->writeFile($gitRemoteFile, $content);
389
390
			return true;
391
		}
392
		return false;
393
	}
394
395
	/**
396
	 * Load an .sspak into an environment.
397
	 * Does not backup - be careful! */
398
	function load($args) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
399
		$executor = $this->executor;
400
401
		$args->requireUnnamed(array('source sspak file'));
402
403
		// Set-up
404
		$file = $args->unnamed(0);
405
		$sspak = new SSPakFile($file, $executor);
406
		$webroot = new Webroot(($args->unnamed(1) ?: '.'), $executor);
407
		$webroot->setSudo($args->sudo('to'));
408
		$pakParts = $args->pakParts();
409
410
		$namedArgs = $args->getNamedArgs();
411
		if(!empty($namedArgs['identity'])) {
412
			// SSH private key
413
			$webroot->setSSHItentityFile($namedArgs['identity']);
414
		}
415
416
		// Validation
417
		if(!$sspak->exists()) throw new Exception( "File '$file' doesn't exist.");
418
419
		// Push database, if necessary
420
		$namedArgs = $args->getNamedArgs();
421
		if($pakParts['db'] && $sspak->contains('database.sql.gz')) {
422
			$webroot->putdb($sspak, isset($namedArgs['drop-db']));
423
		}
424
425
		// Push assets, if neccessary
426
		if($pakParts['assets'] && $sspak->contains('assets.tar.gz')) {
427
			$webroot->putassets($sspak);
428
		}
429
	}
430
431
	/**
432
	 * Install an .sspak into a new environment.
433
	 */
434
	function install($args) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
435
		$executor = $this->executor;
436
437
		$args->requireUnnamed(array('source sspak file', 'dest new webroot'));
438
439
		// Set-up
440
		$file = $args->unnamed(0);
441
		$webrootDir = $args->unnamed(1);
442
		$sspak = new SSPakFile($file, $executor);
443
		$webroot = new Webroot($webrootDir, $executor);
444
		$webroot->setSudo($args->sudo('to'));
445
		$pakParts = $args->pakParts();
446
447
		// Validation
448
		if($webroot->exists($webroot->getPath())) throw new Exception( "Webroot '$webrootDir' already exists.");
449
		if(!$sspak->exists()) throw new Exception( "File '$file' doesn't exist.");
450
451
		// Create new dir
452
		$webroot->exec(array('mkdir', $webroot->getPath()));
0 ignored issues
show
Documentation introduced by
array('mkdir', $webroot->getPath()) is of type array<integer,?,{"0":"string","1":"?"}>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
453
454
		if($sspak->contains('git-remote')) {
455
			$details = $sspak->gitRemoteDetails();
456
			$webroot->putgit($details);
457
		}
458
459
		// TODO: composer install needed.
460
461
		// Push database, if necessary
462
		$namedArgs = $args->getNamedArgs();
463
		if($pakParts['db'] && $sspak->contains('database.sql.gz')) {
464
			$webroot->putdb($sspak, isset($namedArgs['drop-db']));
465
		}
466
467
		// Push assets, if neccessary
468
		if($pakParts['assets'] && $sspak->contains('assets.tar.gz')) {
469
			$webroot->putassets($sspak);
470
		}
471
	}
472
473
	/**
474
	 * Bundle a .sspak into a self-extracting executable installer.
475
	 */
476
	function bundle($args) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
477
		// TODO: throws require_once errors, fix before re-enabling.
478
479
		$executor = $this->executor;
480
481
		$args->requireUnnamed(array('source sspak file', 'dest executable file'));
482
483
		// Set-up
484
		$sourceFile = $args->unnamed(0);
485
		$destFile = $args->unnamed(1);
486
487
		$sspakScript = file_get_contents($_SERVER['argv'][0]);
488
		// Broken up to not get detected by our sed command
489
		$sspakScript .= "\n__halt_compiler();\n"."//"." TAR START?>\n";
490
491
		// Mark as self-extracting
492
		$sspakScript = str_replace('$isSelfExtracting = false;', '$isSelfExtracting = true;', $sspakScript);
493
494
		// Load the sniffer file
495
		$snifferFile = dirname(__FILE__) . '/sspak-sniffer.php';
496
		$sspakScript = str_replace("\$snifferFileContent = '';\n",
497
			"\$snifferFileContent = '"
498
			. str_replace(array("\\","'"),array("\\\\", "\\'"), file_get_contents($snifferFile)) . "';\n", $sspakScript);
499
500
		file_put_contents($destFile, $sspakScript);
501
		chmod($destFile, 0775);
502
503
		$executor->execLocal(array('cat', $sourceFile), array(
0 ignored issues
show
Documentation introduced by
array('cat', $sourceFile) is of type array<integer,?,{"0":"string","1":"?"}>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
504
			'outputFile' => $destFile,
505
			'outputFileAppend' => true
506
		));
507
	}
508
509
	/**
510
	 * Transfer between environments without creating an sspak file
511
	 */
512
	function transfer($args) {
0 ignored issues
show
Unused Code introduced by
The parameter $args is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
513
		echo "Not implemented yet.\n";
514
	}
515
}
516