]>
Commit | Line | Data |
---|---|---|
5cedb389 AD |
1 | <?php |
2 | class Updater extends Plugin { | |
3 | ||
4 | private $link; | |
5 | private $host; | |
6 | ||
d2a421e3 | 7 | function about() { |
7a866114 AD |
8 | return array(1.0, |
9 | "Updates tt-rss installation to latest version.", | |
de612e7a AD |
10 | "fox", |
11 | true); | |
7a866114 AD |
12 | } |
13 | ||
d2a421e3 | 14 | function init($host) { |
5cedb389 AD |
15 | $this->link = $host->get_link(); |
16 | $this->host = $host; | |
17 | ||
18 | $host->add_hook($host::HOOK_PREFS_TAB, $this); | |
73f28fe9 AD |
19 | |
20 | $host->add_command("update-self", | |
21 | "update tt-rss installation to latest version", | |
22 | $this); | |
23 | } | |
24 | ||
25 | function update_self_step($link, $step, $params, $force = false) { | |
26 | // __FILE__ is in plugins/updater so we need to go one level up | |
27 | $work_dir = dirname(dirname(dirname(__FILE__))); | |
28 | $parent_dir = dirname($work_dir); | |
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 | |
08da1c6a AD |
45 | if (!is_writable($work_dir) && !is_writable("$parent_dir")) { |
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 | |
08da1c6a | 62 | array_push($log, "Checking for tar..."); |
73f28fe9 | 63 | |
08da1c6a AD |
64 | $system_rc = 0; |
65 | system("which tar >/dev/null", $system_rc); | |
73f28fe9 | 66 | |
08da1c6a AD |
67 | if ($system_rc != 0) { |
68 | array_push($log, "Could not run tar executable (RC=$system_rc)."); | |
69 | $stop = true; break; | |
70 | } | |
73f28fe9 | 71 | |
08da1c6a | 72 | array_push($log, "Checking for gunzip..."); |
04486904 | 73 | |
08da1c6a AD |
74 | $system_rc = 0; |
75 | system("which gunzip >/dev/null", $system_rc); | |
04486904 | 76 | |
08da1c6a AD |
77 | if ($system_rc != 0) { |
78 | array_push($log, "Could not run gunzip executable (RC=$system_rc)."); | |
79 | $stop = true; break; | |
80 | } | |
04486904 AD |
81 | |
82 | ||
08da1c6a | 83 | array_push($log, "Checking for latest version..."); |
73f28fe9 | 84 | |
08da1c6a AD |
85 | $version_info = json_decode(fetch_file_contents("http://tt-rss.org/version.php"), |
86 | true); | |
73f28fe9 | 87 | |
08da1c6a AD |
88 | if (!is_array($version_info)) { |
89 | array_push($log, "Unable to fetch version information."); | |
90 | $stop = true; break; | |
91 | } | |
73f28fe9 | 92 | |
08da1c6a AD |
93 | $target_version = $version_info["version"]; |
94 | $target_dir = "$parent_dir/tt-rss-$target_version"; | |
73f28fe9 | 95 | |
08da1c6a AD |
96 | array_push($log, "Target version: $target_version"); |
97 | $params["target_version"] = $target_version; | |
73f28fe9 | 98 | |
08da1c6a AD |
99 | if (version_compare(VERSION, $target_version) != -1 && !$force) { |
100 | array_push($log, "Your Tiny Tiny RSS installation is up to date."); | |
101 | $stop = true; break; | |
102 | } | |
73f28fe9 | 103 | |
08da1c6a AD |
104 | if (file_exists($target_dir)) { |
105 | array_push($log, "Target directory $target_dir already exists."); | |
106 | $stop = true; break; | |
107 | } | |
73f28fe9 | 108 | |
08da1c6a AD |
109 | break; |
110 | case 1: | |
111 | $target_version = $params["target_version"]; | |
73f28fe9 | 112 | |
08da1c6a AD |
113 | array_push($log, "Downloading checksums..."); |
114 | $md5sum_data = fetch_file_contents("http://tt-rss.org/download/md5sum.txt"); | |
73f28fe9 | 115 | |
08da1c6a AD |
116 | if (!$md5sum_data) { |
117 | array_push($log, "Could not download checksums."); | |
118 | $stop = true; break; | |
119 | } | |
73f28fe9 | 120 | |
08da1c6a | 121 | $md5sum_data = explode("\n", $md5sum_data); |
73f28fe9 | 122 | |
08da1c6a AD |
123 | foreach ($md5sum_data as $line) { |
124 | $pair = explode(" ", $line); | |
73f28fe9 | 125 | |
08da1c6a AD |
126 | if ($pair[1] == "tt-rss-$target_version.tar.gz") { |
127 | $target_md5sum = $pair[0]; | |
128 | break; | |
129 | } | |
73f28fe9 | 130 | } |
73f28fe9 | 131 | |
08da1c6a AD |
132 | if (!$target_md5sum) { |
133 | array_push($log, "Unable to locate checksum for target version."); | |
134 | $stop = true; break; | |
135 | } | |
73f28fe9 | 136 | |
08da1c6a | 137 | $params["target_md5sum"] = $target_md5sum; |
73f28fe9 | 138 | |
08da1c6a AD |
139 | break; |
140 | case 2: | |
141 | $target_version = $params["target_version"]; | |
142 | $target_md5sum = $params["target_md5sum"]; | |
73f28fe9 | 143 | |
08da1c6a | 144 | array_push($log, "Downloading distribution tarball..."); |
73f28fe9 | 145 | |
08da1c6a AD |
146 | $tarball_url = "http://tt-rss.org/download/tt-rss-$target_version.tar.gz"; |
147 | $data = fetch_file_contents($tarball_url); | |
73f28fe9 | 148 | |
08da1c6a AD |
149 | if (!$data) { |
150 | array_push($log, "Could not download distribution tarball ($tarball_url)."); | |
151 | $stop = true; break; | |
152 | } | |
73f28fe9 | 153 | |
08da1c6a | 154 | array_push($log, "Verifying tarball checksum..."); |
73f28fe9 | 155 | |
08da1c6a | 156 | $test_md5sum = md5($data); |
73f28fe9 | 157 | |
08da1c6a AD |
158 | if ($test_md5sum != $target_md5sum) { |
159 | array_push($log, "Downloaded checksum doesn't match (got $test_md5sum, expected $target_md5sum)."); | |
160 | $stop = true; break; | |
161 | } | |
73f28fe9 | 162 | |
08da1c6a AD |
163 | $tmp_file = tempnam(sys_get_temp_dir(), 'tt-rss'); |
164 | array_push($log, "Saving download to $tmp_file"); | |
73f28fe9 | 165 | |
08da1c6a AD |
166 | if (!file_put_contents($tmp_file, $data)) { |
167 | array_push($log, "Unable to save download."); | |
168 | $stop = true; break; | |
169 | } | |
73f28fe9 | 170 | |
08da1c6a | 171 | $params["tmp_file"] = $tmp_file; |
73f28fe9 | 172 | |
08da1c6a AD |
173 | break; |
174 | case 3: | |
175 | $tmp_file = $params["tmp_file"]; | |
176 | $target_version = $params["target_version"]; | |
73f28fe9 | 177 | |
08da1c6a AD |
178 | if (!chdir($parent_dir)) { |
179 | array_push($log, "Unable to change into parent directory."); | |
180 | $stop = true; break; | |
181 | } | |
73f28fe9 | 182 | |
08da1c6a | 183 | $old_dir = tmpdirname($parent_dir, "tt-rss-old"); |
73f28fe9 | 184 | |
08da1c6a AD |
185 | array_push($log, "Renaming tt-rss directory to ".basename($old_dir)); |
186 | if (!rename($work_dir, $old_dir)) { | |
187 | array_push($log, "Unable to rename tt-rss directory."); | |
188 | $stop = true; break; | |
189 | } | |
73f28fe9 | 190 | |
08da1c6a AD |
191 | array_push($log, "Extracting tarball..."); |
192 | system("tar zxf $tmp_file", $system_rc); | |
73f28fe9 | 193 | |
08da1c6a AD |
194 | if ($system_rc != 0) { |
195 | array_push($log, "Error while extracting tarball (RC=$system_rc)."); | |
196 | $stop = true; break; | |
197 | } | |
73f28fe9 | 198 | |
08da1c6a | 199 | $target_dir = "$parent_dir/tt-rss-$target_version"; |
73f28fe9 | 200 | |
08da1c6a AD |
201 | array_push($log, "Renaming target directory..."); |
202 | if (!rename($target_dir, $work_dir)) { | |
203 | array_push($log, "Unable to rename target directory."); | |
204 | $stop = true; break; | |
205 | } | |
73f28fe9 | 206 | |
08da1c6a AD |
207 | if (!chdir($work_dir)) { |
208 | array_push($log, "Unable to change to work directory: $work_dir"); | |
209 | $stop = true; break; | |
210 | } | |
73f28fe9 | 211 | |
08da1c6a AD |
212 | array_push($log, "Copying config.php..."); |
213 | if (!copy("$old_dir/config.php", "$work_dir/config.php")) { | |
214 | array_push($log, "Unable to copy config.php to $work_dir."); | |
215 | $stop = true; break; | |
216 | } | |
73f28fe9 | 217 | |
08da1c6a AD |
218 | array_push($log, "Cleaning up..."); |
219 | unlink($tmp_file); | |
73f28fe9 | 220 | |
08da1c6a | 221 | array_push($log, "Fixing permissions..."); |
73f28fe9 | 222 | |
08da1c6a AD |
223 | $directories = array( |
224 | CACHE_DIR, | |
225 | CACHE_DIR . "/export", | |
226 | CACHE_DIR . "/images", | |
227 | CACHE_DIR . "/simplepie", | |
228 | ICONS_DIR, | |
229 | LOCK_DIRECTORY); | |
73f28fe9 | 230 | |
08da1c6a AD |
231 | foreach ($directories as $dir) { |
232 | array_push($log, "-> $dir"); | |
233 | chmod($dir, 0777); | |
234 | } | |
73f28fe9 | 235 | |
08da1c6a AD |
236 | array_push($log, "Upgrade completed."); |
237 | array_push($log, "Your old tt-rss directory is saved at $old_dir. ". | |
238 | "Please migrate locally modified files (if any) and remove it."); | |
239 | array_push($log, "You might need to re-enter current directory in shell to see new files."); | |
73f28fe9 | 240 | |
08da1c6a AD |
241 | $stop = true; |
242 | break; | |
243 | default: | |
244 | $stop = true; | |
245 | } | |
73f28fe9 AD |
246 | } |
247 | ||
248 | return array("step" => $step, "stop" => $stop, "params" => $params, "log" => $log); | |
249 | } | |
250 | ||
251 | function update_self_cli($link, $force = false) { | |
252 | $step = 0; | |
253 | $stop = false; | |
254 | $params = array(); | |
255 | ||
256 | while (!$stop) { | |
257 | $rc = $this->update_self_step($link, $step, $params, $force); | |
258 | ||
259 | $params = $rc['params']; | |
260 | $stop = $rc['stop']; | |
261 | ||
262 | foreach ($rc['log'] as $line) { | |
263 | _debug($line); | |
264 | } | |
265 | ++$step; | |
266 | } | |
267 | } | |
268 | ||
269 | function update_self($args) { | |
270 | _debug("Warning: self-updating is experimental. Use at your own risk."); | |
271 | _debug("Please backup your tt-rss directory before continuing. Your database will not be modified."); | |
272 | _debug("Type 'yes' to continue."); | |
273 | ||
274 | if (read_stdin() != 'yes') | |
275 | exit; | |
276 | ||
277 | $this->update_self_cli($link, in_array("-force", $args)); | |
5cedb389 AD |
278 | } |
279 | ||
280 | function get_prefs_js() { | |
281 | return file_get_contents(dirname(__FILE__) . "/updater.js"); | |
282 | } | |
283 | ||
284 | function hook_prefs_tab($args) { | |
285 | if ($args != "prefPrefs") return; | |
286 | ||
287 | if (($_SESSION["access_level"] >= 10 || SINGLE_USER_MODE) && CHECK_FOR_NEW_VERSION) { | |
288 | print "<div dojoType=\"dijit.layout.AccordionPane\" title=\"".__('Update Tiny Tiny RSS')."\">"; | |
289 | ||
290 | if ($_SESSION["pref_last_version_check"] + 86400 + rand(-1000, 1000) < time()) { | |
291 | $_SESSION["version_data"] = @check_for_update($this->link); | |
292 | $_SESSION["pref_last_version_check"] = time(); | |
293 | } | |
294 | ||
295 | if (is_array($_SESSION["version_data"])) { | |
296 | $version = $_SESSION["version_data"]["version"]; | |
297 | print_notice(T_sprintf("New version of Tiny Tiny RSS is available (%s).", "<b>$version</b>")); | |
298 | ||
299 | print "<p><button dojoType=\"dijit.form.Button\" onclick=\"return updateSelf()\">". | |
300 | __('Update Tiny Tiny RSS')."</button></p>"; | |
301 | ||
302 | } else { | |
303 | print_notice(__("Your Tiny Tiny RSS installation is up to date.")); | |
304 | } | |
305 | ||
306 | print "</div>"; #pane | |
307 | } | |
a439ac8a | 308 | } |
5cedb389 AD |
309 | |
310 | function updateSelf() { | |
311 | print "<form style='display : block' name='self_update_form' id='self_update_form'>"; | |
312 | ||
313 | print "<div class='error'>".__("Do not close this dialog until updating is finished. Backup your tt-rss directory before continuing.")."</div>"; | |
314 | ||
315 | print "<ul class='selfUpdateList' id='self_update_log'>"; | |
316 | print "<li>" . __("Ready to update.") . "</li>"; | |
317 | print "</ul>"; | |
318 | ||
319 | print "<div class='dlgButtons'>"; | |
320 | print "<button id=\"self_update_start_btn\" dojoType=\"dijit.form.Button\" onclick=\"return dijit.byId('updateSelfDlg').start()\" >". | |
321 | __("Start update")."</button>"; | |
322 | print "<button id=\"self_update_stop_btn\" onclick=\"return dijit.byId('updateSelfDlg').close()\" dojoType=\"dijit.form.Button\">". | |
323 | __("Close this window")."</button>"; | |
324 | print "</div>"; | |
325 | print "</form>"; | |
326 | } | |
327 | ||
328 | function performUpdate() { | |
329 | $step = (int) $_REQUEST["step"]; | |
330 | $params = json_decode($_REQUEST["params"], true); | |
331 | $force = (bool) $_REQUEST["force"]; | |
332 | ||
333 | if (($_SESSION["access_level"] >= 10 || SINGLE_USER_MODE) && CHECK_FOR_NEW_VERSION) { | |
73f28fe9 | 334 | print json_encode($this->update_self_step($this->link, $step, $params, $force)); |
5cedb389 AD |
335 | } |
336 | } | |
337 | ||
5cedb389 AD |
338 | } |
339 | ?> |