]>
Commit | Line | Data |
---|---|---|
5cedb389 AD |
1 | <?php |
2 | class Updater extends Plugin { | |
3 | ||
5cedb389 AD |
4 | private $host; |
5 | ||
d2a421e3 | 6 | function about() { |
7a866114 AD |
7 | return array(1.0, |
8 | "Updates tt-rss installation to latest version.", | |
de612e7a AD |
9 | "fox", |
10 | true); | |
7a866114 AD |
11 | } |
12 | ||
d2a421e3 | 13 | function init($host) { |
5cedb389 AD |
14 | $this->host = $host; |
15 | ||
16 | $host->add_hook($host::HOOK_PREFS_TAB, $this); | |
73f28fe9 AD |
17 | |
18 | $host->add_command("update-self", | |
19 | "update tt-rss installation to latest version", | |
20 | $this); | |
21 | } | |
22 | ||
a42c55f0 | 23 | function update_self_step($step, $params, $force = false) { |
73f28fe9 AD |
24 | // __FILE__ is in plugins/updater so we need to go one level up |
25 | $work_dir = dirname(dirname(dirname(__FILE__))); | |
26 | $parent_dir = dirname($work_dir); | |
b509b059 | 27 | // Set PATH to run "which" |
28 | putenv('PATH="$PATH:/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin"'); | |
73f28fe9 | 29 | |
08da1c6a AD |
30 | $log = array(); |
31 | if (!is_array($params)) $params = array(); | |
32 | ||
33 | $stop = false; | |
34 | ||
73f28fe9 AD |
35 | if (!chdir($work_dir)) { |
36 | array_push($log, "Unable to change to work directory: $work_dir"); | |
08da1c6a | 37 | $stop = true; |
73f28fe9 AD |
38 | } |
39 | ||
08da1c6a AD |
40 | if (!$stop) { |
41 | switch ($step) { | |
42 | case 0: | |
43 | array_push($log, "Work directory: $work_dir"); | |
73f28fe9 | 44 | |
cd4d71b4 | 45 | if (!is_writable($work_dir) || !is_writable("$parent_dir")) { |
08da1c6a AD |
46 | $user = posix_getpwuid(posix_geteuid()); |
47 | $user = $user["name"]; | |
48 | array_push($log, "Both tt-rss and parent directories should be writable as current user ($user)."); | |
49 | $stop = true; break; | |
50 | } | |
73f28fe9 | 51 | |
08da1c6a AD |
52 | if (!file_exists("$work_dir/config.php") || !file_exists("$work_dir/include/sanity_check.php")) { |
53 | array_push($log, "Work directory $work_dir doesn't look like tt-rss installation."); | |
54 | $stop = true; break; | |
55 | } | |
73f28fe9 | 56 | |
08da1c6a AD |
57 | if (!is_writable(sys_get_temp_dir())) { |
58 | array_push($log, "System temporary directory should be writable as current user."); | |
59 | $stop = true; break; | |
60 | } | |
73f28fe9 | 61 | |
49dc0280 AD |
62 | // bah, also humbug |
63 | putenv("PATH=" . getenv("PATH") . PATH_SEPARATOR . "/bin" . | |
64 | PATH_SEPARATOR . "/usr/bin"); | |
65 | ||
96aba17f BS |
66 | array_push($log, "Checking for system() call..."); |
67 | ||
68 | $disabled = explode(',', ini_get('disable_functions')); | |
69 | foreach ($disabled as $function) { | |
70 | if ( trim($function) == 'system' ) { | |
71 | array_push($log, "Can not execute commands with PHP's system() function."); | |
72 | $stop = true; | |
73 | } | |
74 | } | |
75 | ||
76 | if ( $stop == true ) { | |
77 | break; | |
78 | } | |
79 | ||
08da1c6a | 80 | array_push($log, "Checking for tar..."); |
73f28fe9 | 81 | |
08da1c6a AD |
82 | $system_rc = 0; |
83 | system("which tar >/dev/null", $system_rc); | |
73f28fe9 | 84 | |
08da1c6a AD |
85 | if ($system_rc != 0) { |
86 | array_push($log, "Could not run tar executable (RC=$system_rc)."); | |
87 | $stop = true; break; | |
88 | } | |
73f28fe9 | 89 | |
08da1c6a | 90 | array_push($log, "Checking for gunzip..."); |
04486904 | 91 | |
08da1c6a AD |
92 | $system_rc = 0; |
93 | system("which gunzip >/dev/null", $system_rc); | |
04486904 | 94 | |
08da1c6a AD |
95 | if ($system_rc != 0) { |
96 | array_push($log, "Could not run gunzip executable (RC=$system_rc)."); | |
97 | $stop = true; break; | |
98 | } | |
04486904 | 99 | |
08da1c6a | 100 | array_push($log, "Checking for latest version..."); |
73f28fe9 | 101 | |
08da1c6a AD |
102 | $version_info = json_decode(fetch_file_contents("http://tt-rss.org/version.php"), |
103 | true); | |
73f28fe9 | 104 | |
08da1c6a AD |
105 | if (!is_array($version_info)) { |
106 | array_push($log, "Unable to fetch version information."); | |
107 | $stop = true; break; | |
108 | } | |
73f28fe9 | 109 | |
08da1c6a | 110 | $target_version = $version_info["version"]; |
0ac2f52e | 111 | $target_dir = "$parent_dir/Tiny-Tiny-RSS-$target_version"; |
73f28fe9 | 112 | |
08da1c6a AD |
113 | array_push($log, "Target version: $target_version"); |
114 | $params["target_version"] = $target_version; | |
73f28fe9 | 115 | |
08da1c6a AD |
116 | if (version_compare(VERSION, $target_version) != -1 && !$force) { |
117 | array_push($log, "Your Tiny Tiny RSS installation is up to date."); | |
118 | $stop = true; break; | |
119 | } | |
73f28fe9 | 120 | |
08da1c6a AD |
121 | if (file_exists($target_dir)) { |
122 | array_push($log, "Target directory $target_dir already exists."); | |
123 | $stop = true; break; | |
124 | } | |
73f28fe9 | 125 | |
08da1c6a AD |
126 | break; |
127 | case 1: | |
128 | $target_version = $params["target_version"]; | |
73f28fe9 | 129 | |
0ac2f52e | 130 | /* array_push($log, "Downloading checksums..."); |
08da1c6a | 131 | $md5sum_data = fetch_file_contents("http://tt-rss.org/download/md5sum.txt"); |
73f28fe9 | 132 | |
08da1c6a AD |
133 | if (!$md5sum_data) { |
134 | array_push($log, "Could not download checksums."); | |
135 | $stop = true; break; | |
136 | } | |
73f28fe9 | 137 | |
08da1c6a | 138 | $md5sum_data = explode("\n", $md5sum_data); |
73f28fe9 | 139 | |
08da1c6a AD |
140 | foreach ($md5sum_data as $line) { |
141 | $pair = explode(" ", $line); | |
73f28fe9 | 142 | |
08da1c6a AD |
143 | if ($pair[1] == "tt-rss-$target_version.tar.gz") { |
144 | $target_md5sum = $pair[0]; | |
145 | break; | |
146 | } | |
73f28fe9 | 147 | } |
73f28fe9 | 148 | |
08da1c6a AD |
149 | if (!$target_md5sum) { |
150 | array_push($log, "Unable to locate checksum for target version."); | |
151 | $stop = true; break; | |
152 | } | |
73f28fe9 | 153 | |
0ac2f52e AD |
154 | $params["target_md5sum"] = $target_md5sum; */ |
155 | ||
156 | array_push($log, "Proceeding to download..."); | |
73f28fe9 | 157 | |
08da1c6a AD |
158 | break; |
159 | case 2: | |
160 | $target_version = $params["target_version"]; | |
0ac2f52e | 161 | // $target_md5sum = $params["target_md5sum"]; |
73f28fe9 | 162 | |
08da1c6a | 163 | array_push($log, "Downloading distribution tarball..."); |
73f28fe9 | 164 | |
0ac2f52e | 165 | $tarball_url = "https://github.com/gothfox/Tiny-Tiny-RSS/archive/$target_version.tar.gz"; |
08da1c6a | 166 | $data = fetch_file_contents($tarball_url); |
73f28fe9 | 167 | |
08da1c6a AD |
168 | if (!$data) { |
169 | array_push($log, "Could not download distribution tarball ($tarball_url)."); | |
170 | $stop = true; break; | |
171 | } | |
73f28fe9 | 172 | |
0ac2f52e | 173 | /* array_push($log, "Verifying tarball checksum..."); |
73f28fe9 | 174 | |
08da1c6a | 175 | $test_md5sum = md5($data); |
73f28fe9 | 176 | |
08da1c6a AD |
177 | if ($test_md5sum != $target_md5sum) { |
178 | array_push($log, "Downloaded checksum doesn't match (got $test_md5sum, expected $target_md5sum)."); | |
179 | $stop = true; break; | |
0ac2f52e | 180 | } */ |
73f28fe9 | 181 | |
08da1c6a AD |
182 | $tmp_file = tempnam(sys_get_temp_dir(), 'tt-rss'); |
183 | array_push($log, "Saving download to $tmp_file"); | |
73f28fe9 | 184 | |
08da1c6a AD |
185 | if (!file_put_contents($tmp_file, $data)) { |
186 | array_push($log, "Unable to save download."); | |
187 | $stop = true; break; | |
188 | } | |
73f28fe9 | 189 | |
08da1c6a | 190 | $params["tmp_file"] = $tmp_file; |
73f28fe9 | 191 | |
08da1c6a AD |
192 | break; |
193 | case 3: | |
194 | $tmp_file = $params["tmp_file"]; | |
195 | $target_version = $params["target_version"]; | |
73f28fe9 | 196 | |
08da1c6a AD |
197 | if (!chdir($parent_dir)) { |
198 | array_push($log, "Unable to change into parent directory."); | |
199 | $stop = true; break; | |
200 | } | |
73f28fe9 | 201 | |
08da1c6a AD |
202 | array_push($log, "Extracting tarball..."); |
203 | system("tar zxf $tmp_file", $system_rc); | |
73f28fe9 | 204 | |
08da1c6a AD |
205 | if ($system_rc != 0) { |
206 | array_push($log, "Error while extracting tarball (RC=$system_rc)."); | |
207 | $stop = true; break; | |
208 | } | |
73f28fe9 | 209 | |
0ac2f52e AD |
210 | $target_dir = "$parent_dir/Tiny-Tiny-RSS-$target_version"; |
211 | ||
212 | if (!is_dir($target_dir)) { | |
213 | array_push($log, "Target directory ($target_dir) not found."); | |
214 | $stop = true; break; | |
215 | } | |
216 | ||
217 | $old_dir = tmpdirname($parent_dir, "tt-rss-old"); | |
218 | ||
219 | array_push($log, "Renaming tt-rss directory to ".basename($old_dir)); | |
220 | if (!rename($work_dir, $old_dir)) { | |
221 | array_push($log, "Unable to rename tt-rss directory."); | |
222 | $stop = true; break; | |
223 | } | |
73f28fe9 | 224 | |
08da1c6a AD |
225 | array_push($log, "Renaming target directory..."); |
226 | if (!rename($target_dir, $work_dir)) { | |
227 | array_push($log, "Unable to rename target directory."); | |
228 | $stop = true; break; | |
229 | } | |
73f28fe9 | 230 | |
08da1c6a AD |
231 | if (!chdir($work_dir)) { |
232 | array_push($log, "Unable to change to work directory: $work_dir"); | |
233 | $stop = true; break; | |
234 | } | |
73f28fe9 | 235 | |
08da1c6a AD |
236 | array_push($log, "Copying config.php..."); |
237 | if (!copy("$old_dir/config.php", "$work_dir/config.php")) { | |
238 | array_push($log, "Unable to copy config.php to $work_dir."); | |
239 | $stop = true; break; | |
240 | } | |
73f28fe9 | 241 | |
08da1c6a AD |
242 | array_push($log, "Cleaning up..."); |
243 | unlink($tmp_file); | |
73f28fe9 | 244 | |
08da1c6a | 245 | array_push($log, "Fixing permissions..."); |
73f28fe9 | 246 | |
08da1c6a AD |
247 | $directories = array( |
248 | CACHE_DIR, | |
249 | CACHE_DIR . "/export", | |
250 | CACHE_DIR . "/images", | |
897589a5 | 251 | CACHE_DIR . "/js", |
08da1c6a | 252 | CACHE_DIR . "/simplepie", |
b16e8ba8 | 253 | CACHE_DIR . "/upload", |
08da1c6a AD |
254 | ICONS_DIR, |
255 | LOCK_DIRECTORY); | |
73f28fe9 | 256 | |
08da1c6a AD |
257 | foreach ($directories as $dir) { |
258 | array_push($log, "-> $dir"); | |
259 | chmod($dir, 0777); | |
260 | } | |
73f28fe9 | 261 | |
aff02f89 AD |
262 | if (ICONS_DIR == "feed-icons") { |
263 | array_push($log, "Migrating feed icons..."); | |
264 | ||
265 | $icons = glob("$old_dir/feed-icons/*.ico"); | |
266 | $icons_copied = 0; | |
267 | ||
268 | foreach ($icons as $icon) { | |
269 | $icon = basename($icon); | |
270 | ||
271 | if (copy("$old_dir/feed-icons/$icon", "$work_dir/feed-icons/$icon")) { | |
272 | ++$icons_copied; | |
273 | } | |
274 | } | |
275 | ||
276 | array_push($log, "Done; $icons_copied files copied"); | |
277 | ||
278 | } else { | |
279 | array_push($log, "Not migrating feed icons, ICONS_DIR modified."); | |
280 | } | |
281 | ||
08da1c6a AD |
282 | array_push($log, "Upgrade completed."); |
283 | array_push($log, "Your old tt-rss directory is saved at $old_dir. ". | |
284 | "Please migrate locally modified files (if any) and remove it."); | |
285 | array_push($log, "You might need to re-enter current directory in shell to see new files."); | |
73f28fe9 | 286 | |
08da1c6a AD |
287 | $stop = true; |
288 | break; | |
289 | default: | |
290 | $stop = true; | |
291 | } | |
73f28fe9 AD |
292 | } |
293 | ||
294 | return array("step" => $step, "stop" => $stop, "params" => $params, "log" => $log); | |
295 | } | |
296 | ||
a42c55f0 | 297 | function update_self_cli($force = false) { |
73f28fe9 AD |
298 | $step = 0; |
299 | $stop = false; | |
300 | $params = array(); | |
301 | ||
302 | while (!$stop) { | |
a42c55f0 | 303 | $rc = $this->update_self_step($step, $params, $force); |
73f28fe9 AD |
304 | |
305 | $params = $rc['params']; | |
306 | $stop = $rc['stop']; | |
307 | ||
308 | foreach ($rc['log'] as $line) { | |
309 | _debug($line); | |
310 | } | |
311 | ++$step; | |
312 | } | |
313 | } | |
314 | ||
315 | function update_self($args) { | |
0bcf69e1 AD |
316 | _debug("READ THE FOLLOWING BEFORE CONTINUING!"); |
317 | _debug("* It is suggested to backup your tt-rss directory first."); | |
318 | _debug("* Your database will not be modified."); | |
319 | _debug("* Your current tt-rss installation directory will not be modified. It will be renamed and left in the parent directory. You will be able to migrate all your customized files after update finishes."); | |
73f28fe9 AD |
320 | _debug("Type 'yes' to continue."); |
321 | ||
aff02f89 AD |
322 | $input = read_stdin(); |
323 | ||
324 | if ($input != 'yes' && $input != 'force') | |
73f28fe9 AD |
325 | exit; |
326 | ||
a42c55f0 | 327 | $this->update_self_cli($input == 'force'); |
5cedb389 AD |
328 | } |
329 | ||
330 | function get_prefs_js() { | |
331 | return file_get_contents(dirname(__FILE__) . "/updater.js"); | |
332 | } | |
333 | ||
334 | function hook_prefs_tab($args) { | |
335 | if ($args != "prefPrefs") return; | |
336 | ||
337 | if (($_SESSION["access_level"] >= 10 || SINGLE_USER_MODE) && CHECK_FOR_NEW_VERSION) { | |
338 | print "<div dojoType=\"dijit.layout.AccordionPane\" title=\"".__('Update Tiny Tiny RSS')."\">"; | |
339 | ||
340 | if ($_SESSION["pref_last_version_check"] + 86400 + rand(-1000, 1000) < time()) { | |
6322ac79 | 341 | $_SESSION["version_data"] = @check_for_update(); |
5cedb389 AD |
342 | $_SESSION["pref_last_version_check"] = time(); |
343 | } | |
344 | ||
345 | if (is_array($_SESSION["version_data"])) { | |
346 | $version = $_SESSION["version_data"]["version"]; | |
2e828a4a | 347 | $version_id = $_SESSION["version_data"]["version_id"]; |
5cedb389 AD |
348 | print_notice(T_sprintf("New version of Tiny Tiny RSS is available (%s).", "<b>$version</b>")); |
349 | ||
2e828a4a AD |
350 | $details = "http://tt-rss.org/redmine/versions/$version_id"; |
351 | ||
352 | print "<p><button onclick=\"window.open('$details')\" dojoType=\"dijit.form.Button\">".__("See the release notes")."</button>"; | |
353 | ||
354 | print " <button dojoType=\"dijit.form.Button\" onclick=\"return updateSelf()\">". | |
5cedb389 AD |
355 | __('Update Tiny Tiny RSS')."</button></p>"; |
356 | ||
357 | } else { | |
358 | print_notice(__("Your Tiny Tiny RSS installation is up to date.")); | |
59962a6e AD |
359 | |
360 | print "<br/> <button dojoType=\"dijit.form.Button\" onclick=\"return updateSelf()\">". | |
361 | __('Force update')."</button></p>"; | |
362 | ||
5cedb389 AD |
363 | } |
364 | ||
365 | print "</div>"; #pane | |
366 | } | |
a439ac8a | 367 | } |
5cedb389 AD |
368 | |
369 | function updateSelf() { | |
0bcf69e1 AD |
370 | print_warning(__("Do not close this dialog until updating is finished.")); |
371 | ||
5cedb389 AD |
372 | print "<form style='display : block' name='self_update_form' id='self_update_form'>"; |
373 | ||
0bcf69e1 AD |
374 | print "<style type='text/css'> |
375 | li.notice { font-style : italic; color : red; } | |
376 | </style>"; | |
5cedb389 AD |
377 | |
378 | print "<ul class='selfUpdateList' id='self_update_log'>"; | |
0bcf69e1 AD |
379 | print "<li class='notice'>" .__("It is suggested to backup your tt-rss directory first.") . "</li>"; |
380 | print "<li class='notice'>" . __("Your database will not be modified.") . "</li>"; | |
381 | print "<li class='notice'>" . __("Your current tt-rss installation directory will not be modified. It will be renamed and left in the parent directory. You will be able to migrate all your customized files after update finishes.") . "</li>"; | |
5cedb389 AD |
382 | print "<li>" . __("Ready to update.") . "</li>"; |
383 | print "</ul>"; | |
384 | ||
385 | print "<div class='dlgButtons'>"; | |
386 | print "<button id=\"self_update_start_btn\" dojoType=\"dijit.form.Button\" onclick=\"return dijit.byId('updateSelfDlg').start()\" >". | |
387 | __("Start update")."</button>"; | |
388 | print "<button id=\"self_update_stop_btn\" onclick=\"return dijit.byId('updateSelfDlg').close()\" dojoType=\"dijit.form.Button\">". | |
389 | __("Close this window")."</button>"; | |
390 | print "</div>"; | |
391 | print "</form>"; | |
392 | } | |
393 | ||
394 | function performUpdate() { | |
395 | $step = (int) $_REQUEST["step"]; | |
396 | $params = json_decode($_REQUEST["params"], true); | |
397 | $force = (bool) $_REQUEST["force"]; | |
398 | ||
399 | if (($_SESSION["access_level"] >= 10 || SINGLE_USER_MODE) && CHECK_FOR_NEW_VERSION) { | |
a42c55f0 | 400 | print json_encode($this->update_self_step($step, $params, $force)); |
5cedb389 AD |
401 | } |
402 | } | |
403 | ||
106a3de9 AD |
404 | function api_version() { |
405 | return 2; | |
406 | } | |
407 | ||
5cedb389 AD |
408 | } |
409 | ?> |