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