1<?php
2
3/*
4	Phoronix Test Suite
5	URLs: http://www.phoronix.com, http://www.phoronix-test-suite.com/
6	Copyright (C) 2018, Phoronix Media
7	Copyright (C) 2018, Michael Larabel
8
9	This program is free software; you can redistribute it and/or modify
10	it under the terms of the GNU General Public License as published by
11	the Free Software Foundation; either version 3 of the License, or
12	(at your option) any later version.
13
14	This program is distributed in the hope that it will be useful,
15	but WITHOUT ANY WARRANTY; without even the implied warranty of
16	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17	GNU General Public License for more details.
18
19	You should have received a copy of the GNU General Public License
20	along with this program. If not, see <http://www.gnu.org/licenses/>.
21*/
22
23class backup extends pts_module_interface
24{
25	const module_name = 'Backup Creation + Restore';
26	const module_version = '1.0.0';
27	const module_description = 'This is a module for creating backups of the Phoronix Test Suite / Phoromatic and allows for restoring of created backups. The backup will be in ZIP or TAR format. If only a path is specified, the file-name will be auto-generated with a current time-stamp.';
28	const module_author = 'Phoronix Media';
29
30	public static function user_commands()
31	{
32		return array('create' => 'create_backup', 'restore' => 'restore_backup');
33	}
34	public static function create_backup($r)
35	{
36		if(!isset($r[0]) || empty($r[0]))
37		{
38			echo PHP_EOL . pts_client::cli_just_bold('ERROR: ') . 'You must pass the name of the backup file to create and/or any absolute path for the said file you would like to create.' . PHP_EOL . PHP_EOL;
39			return false;
40		}
41		$backup_location = $r[0];
42		if(strpos($backup_location, DIRECTORY_SEPARATOR) === false)
43		{
44			$backup_location = getcwd() . DIRECTORY_SEPARATOR . $backup_location;
45		}
46		if(is_dir($backup_location))
47		{
48			$backup_location .= 'pts-backup-' . date('Y-m-d-H-i-s');
49		}
50		$file_extension = phodevi::is_windows() ? 'zip' : 'tar';
51		if(substr($backup_location, -4) != '.' . $file_extension)
52		{
53			$backup_location .= '.' . $file_extension;
54		}
55		echo PHP_EOL . pts_client::cli_just_bold('Proposed Backup File:') . ' ' . $backup_location . PHP_EOL . PHP_EOL;
56
57		if(!is_writable(($dir = dirname($backup_location))))
58		{
59			echo pts_client::cli_just_bold('ERROR:') . ' This location does not appear writable: ' . $dir . PHP_EOL . PHP_EOL;
60			return false;
61		}
62
63		echo PHP_EOL . 'Making download-cache to cache downloaded test files...' . PHP_EOL;
64		pts_client::execute_command('make_download_cache');
65
66		$root_backup_temp_dir = pts_client::create_temporary_directory(null, true);
67		pts_file_io::mkdir(($backup_temp_dir = $root_backup_temp_dir . 'pts-backup' . DIRECTORY_SEPARATOR));
68		$backup_manifest = array();
69
70		$to_backup = self::backup_map();
71
72		echo PHP_EOL;
73		foreach($to_backup as $source => $dest)
74		{
75			echo pts_client::cli_just_bold('Backing Up:') . ' ' . $source . PHP_EOL;
76			$success = pts_file_io::copy($source, $backup_temp_dir . $dest);
77			if(!$success)
78			{
79				echo PHP_EOL . 'There may have been problems backing up: ' . $source . PHP_EOL;
80			}
81		}
82
83
84		$manifest = self::dir_checks($backup_temp_dir, $backup_temp_dir);
85		file_put_contents($backup_temp_dir . 'pts-backup-manifest.txt', $manifest);
86		if($file_extension == 'zip')
87		{
88			pts_compression::zip_archive_create($backup_location, $backup_temp_dir);
89		}
90		else
91		{
92			pts_compression::compress_to_archive($backup_temp_dir, $backup_location);
93		}
94		echo pts_client::cli_just_bold('Backup File Written To: ') . $backup_location . PHP_EOL;
95		echo pts_client::cli_just_bold('SHA1: ') . sha1_file($backup_location) . PHP_EOL;
96		echo pts_client::cli_just_bold('File Size: ') . round(filesize($backup_location) / 1000000, 1) . ' MB' . PHP_EOL;
97		pts_file_io::delete($root_backup_temp_dir, null, true);
98	}
99	protected static function backup_map()
100	{
101		return array(
102			// User configuration
103			pts_config::get_config_file_location() => 'phoronix-test-suite.xml',
104			// test results
105			PTS_SAVE_RESULTS_PATH => 'test-results',
106			// test profiles
107			PTS_TEST_PROFILE_PATH => 'test-profiles',
108			// test suites
109			PTS_TEST_SUITE_PATH => 'test-suites',
110			// modules data
111			pts_module::module_data_path() => 'modules-data',
112			// Phoromatic
113			phoromatic_server::phoromatic_path() => 'phoromatic-storage',
114			// Download Cache
115			pts_client::download_cache_path() => 'download-cache',
116			);
117	}
118	public static function restore_backup($r)
119	{
120		if(!isset($r[0]) || !is_file($r[0]))
121		{
122			echo PHP_EOL . pts_client::cli_just_bold('You must pass the name/path of the backup file to restore.') . PHP_EOL . PHP_EOL;
123			return false;
124		}
125		$backup_archive = $r[0];
126		echo pts_client::cli_just_bold('Backup File: ') . $backup_archive . PHP_EOL;
127		echo pts_client::cli_just_bold('SHA1: ') . sha1_file($backup_archive) . PHP_EOL;
128		if(substr($backup_archive, -4) == '.zip')
129		{
130			$root_restore_temp_dir = pts_client::create_temporary_directory(null, true);
131			$s = pts_compression::zip_archive_extract($backup_archive, $root_restore_temp_dir);
132		}
133		else if(substr($backup_archive, -4) == '.tar')
134		{
135			$root_restore_temp_dir = dirname($backup_archive);
136			$s = pts_compression::archive_extract($backup_archive);
137		}
138		else
139		{
140			echo PHP_EOL . 'Unknown file type.' . PHP_EOL;
141			return false;
142		}
143		if(!$s)
144		{
145			echo PHP_EOL . 'There was a problem extracting the archive.' . PHP_EOL;
146			return false;
147		}
148		$restore_dir = $root_restore_temp_dir . DIRECTORY_SEPARATOR . 'pts-backup' . DIRECTORY_SEPARATOR;
149		if(!is_dir($restore_dir) || !is_file($restore_dir . 'pts-backup-manifest.txt'))
150		{
151			echo PHP_EOL . 'This does not appear to be a valid PTS backup as no pts-backup found.' . PHP_EOL;
152			return false;
153		}
154
155		$manifest_files = array();
156		foreach(explode(PHP_EOL, pts_file_io::file_get_contents($restore_dir . 'pts-backup-manifest.txt')) as $line)
157		{
158			$r = explode(': ', $line);
159			$manifest_files[$r[0]] = $r[1];
160		}
161		// XXX decide how exactly we want to do with manifest_files
162
163		if(is_file($restore_dir . 'phoronix-test-suite.xml'))
164		{
165			$restore_conf = pts_user_io::prompt_bool_input('Do you want to restore the user configuration file specifying paths, etc?', false);
166			if($restore_conf)
167			{
168				pts_file_io::copy($restore_dir . 'phoronix-test-suite.xml', pts_config::get_config_file_location());
169			}
170		}
171
172		$backup_map = self::backup_map();
173		foreach($backup_map as $dest => $source)
174		{
175			if($source == 'phoronix-test-suite.xml')
176				continue;
177
178			if(is_dir($restore_dir . $source) || is_file($restore_dir . $source))
179			{
180				$s = pts_file_io::copy($restore_dir . $source, $dest);
181				if($s)
182					echo PHP_EOL . pts_client::cli_just_bold('Restored: ') . $source . ' to ' . $dest . PHP_EOL;
183				else
184					echo PHP_EOL . 'Failed to restore ' . $source . PHP_EOL;
185			}
186		}
187
188		pts_file_io::delete($root_restore_temp_dir . DIRECTORY_SEPARATOR . 'pts-backup', null, true);
189	}
190	protected static function dir_checks($dir, $remove_base_dir, &$checksums = array())
191	{
192		$files = scandir($dir);
193
194		foreach($files as $key => $value)
195		{
196			$p = realpath($dir . '/' . $value);
197			if(!is_dir($p))
198			{
199				$checksums[] = str_replace($remove_base_dir, '', $p) . ': ' . sha1_file($p) . PHP_EOL;
200			}
201			else if($value != '.' && $value != '..')
202			{
203				self::dir_checks($p, $remove_base_dir, $checksums);
204			}
205		}
206
207		return $checksums;
208	}
209
210}
211
212?>
213