4 Plugin URI: http://octo.it/yourls-gitweb/
\r
5 Description: Automatically redirect to a Gitweb installation if an appropriate Git object exists.
\r
7 Author: Florian "octo" Forster
\r
8 Author URI: http://octo.it/
\r
12 * yourls -- Gitweb plugin
\r
13 * Copyright (C) 2011 Florian Forster
\r
15 * Permission is hereby granted, free of charge, to any person obtaining a
\r
16 * copy of this software and associated documentation files (the "Software"),
\r
17 * to deal in the Software without restriction, including without limitation
\r
18 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
\r
19 * and/or sell copies of the Software, and to permit persons to whom the
\r
20 * Software is furnished to do so, subject to the following conditions:
\r
22 * The above copyright notice and this permission notice shall be included in
\r
23 * all copies or substantial portions of the Software.
\r
25 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
\r
26 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
\r
27 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
\r
28 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
\r
29 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
\r
30 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
\r
31 * DEALINGS IN THE SOFTWARE.
\r
34 * Florian Forster <ff at octo.it>
\r
37 function gitweb_check_repository ($obj, $repo, $dir, $base_url) /* {{{ */
\r
42 $cmd = 'git --git-dir=' . escapeshellarg ($dir)
\r
43 . ' rev-parse --verify ' . escapeshellarg ($obj)
\r
45 $obj_name = trim (shell_exec ($cmd));
\r
49 if (!preg_match ('/^[0-9a-fA-F]{40}$/', $obj_name))
\r
51 error_log ("git-rev-parse(1) returned unexpected object name: $obj_name");
\r
55 $cmd = 'git --git-dir=' . escapeshellarg ($dir)
\r
56 . ' cat-file -t ' . escapeshellarg ($obj_name)
\r
58 $obj_type = trim (shell_exec ($cmd));
\r
61 error_log ("gitweb_check_repository: git-cat-file(1) failed.");
\r
65 if ($obj_type == 'commit')
\r
67 $to_url = "$base_url?p=" . urlencode ($repo) . ';a=commitdiff;h=' . urlencode ($obj_name);
\r
68 yourls_redirect ($to_url, /* status = */ 301);
\r
71 elseif ($obj_type == 'tag')
\r
73 $to_url = "$base_url?p=" . urlencode ($repo) . ';a=tag;h=' . urlencode ($obj_name);
\r
74 yourls_redirect ($to_url, /* status = */ 301);
\r
78 elseif ($obj_type == 'tree')
\r
80 $to_url = "$base_url?p=" . urlencode ($repo) . ";a=tree;h=" . urlencode ($obj_name);
\r
81 yourls_redirect ($to_url, /* status = */ 301);
\r
84 elseif ($obj_type == 'blob')
\r
86 $to_url = "$base_url?p=" . urlencode ($repo) . ";a=blob;h=" . urlencode ($obj_name);
\r
87 yourls_redirect ($to_url, /* status = */ 301);
\r
92 error_log ("Gitweb plugin: Object \"$obj_name\" in repository \"$repo\" has unknown type \"$obj_type\".");
\r
95 } /* }}} function gitweb_check_repository */
\r
97 /* This callback function is called when the given keyword was not found in the
\r
98 * database. I'll see if this looks like an object identifier in a Git
\r
99 * repository and, if so, try to locate the object using the local
\r
101 function gitweb_redirect_keyword_not_found ($args) /* {{{ */
\r
103 $keyword = $args[0];
\r
105 if (!preg_match ('/^[0-9a-fA-F]{6,40}$/', $keyword))
\r
108 $base_directory = yourls_get_option ('gitweb_base_directory');
\r
109 if (!$base_directory)
\r
112 $base_url = yourls_get_option ('gitweb_base_url');
\r
116 $dh = opendir ($base_directory);
\r
120 while (($subdir = readdir ($dh)) !== false)
\r
122 /* Ignore all files and directories starting with a dot, including the
\r
123 * special directories "." and "..". */
\r
124 if (substr ($subdir, 0, 1) == '.')
\r
127 $absdir = "$base_directory/$subdir";
\r
128 if (!is_dir ($absdir))
\r
131 /* Ignore repositories which are private (i.e. not exported by the
\r
132 * git-daemon(1). We might leak information if we don't. */
\r
133 if (!file_exists ("$absdir/git-daemon-export-ok"))
\r
136 if (gitweb_check_repository ($keyword, $subdir, $absdir, $base_url))
\r
141 } /* }}} function gitweb_redirect_keyword_not_found */
\r
143 function gitweb_set_base_directory ($dir) /* {{{ */
\r
145 /* Remove trailing slashes. */
\r
146 $dir = preg_replace ('/\/+$/', '', $dir);
\r
148 if (!preg_match ('/^\//', $dir))
\r
150 print ("<p class=\"error\">Not an absolute path: "
\r
151 . htmlspecialchars ($dir)
\r
156 if (!is_dir ($dir))
\r
158 print ("<p class=\"error\">Not a directory: "
\r
159 . htmlspecialchars ($dir)
\r
164 /* Open the directory only to check its permissions. */
\r
165 $dh = opendir ($dir);
\r
168 print ("<p class=\"error\">Unable to open directory.</p>\n");
\r
173 yourls_update_option ('gitweb_base_directory', $dir);
\r
175 } /* }}} function gitweb_set_base_directory */
\r
177 function gitweb_set_base_url ($url) /* {{{ */
\r
179 if (!preg_match ('/https?:\/\//i', $url))
\r
181 print ("<p class=\"error\">This does not look like a valid URL: "
\r
182 . htmlspecialchars ($url)
\r
187 $url = preg_replace ('/\?.*/', '', $url);
\r
189 yourls_update_option ('gitweb_base_url', $url);
\r
191 } /* }}} function gitweb_set_base_directory */
\r
193 function gitweb_show_plugin_page () /* {{{ */
\r
196 <h2>Gitweb Plugin Administration Page</h2>
\r
197 <p>This plugin redirects to a Gitweb installation if a keyword wasn't
\r
198 found in the database, looks like a Git object ID and is found in a
\r
199 local Git repository.</p>
\r
202 if (isset ($_POST['base_directory']))
\r
203 gitweb_set_base_directory ($_POST['base_directory']);
\r
205 if (isset ($_POST['base_url']))
\r
206 gitweb_set_base_url ($_POST['base_url']);
\r
208 $base_directory = yourls_get_option ('gitweb_base_directory');
\r
209 if ($base_directory)
\r
210 $base_directory = htmlspecialchars ($base_directory);
\r
212 $base_url = yourls_get_option ('gitweb_base_url');
\r
214 $base_url = htmlspecialchars ($base_url);
\r
217 <form method="post">
\r
218 <table style="background-color: #cdcdcd; border-spacing: 1px;">
\r
220 <th style="border: 1px solid white; background: #C7E7FF; padding: 4px;"><label for="base_directory">Base directory</label></th>
\r
221 <td style="background-color: white; padding: 4px;"><input type="text" id="base_directory" name="base_directory" value="$base_directory" /></td>
\r
224 <th style="border: 1px solid white; background: #C7E7FF; padding: 4px;"><label for="base_url">Gitweb URL</label></th>
\r
225 <td style="background-color: white; padding: 4px;"><input type="text" id="base_url" name="base_url" value="$base_url" /></td>
\r
228 <td colspan="2" style="border: 1px solid white; background-color: #E3F3FF; text-align: right; padding: 4px;"><input type="submit" value="Update" class="button primary" /></td>
\r
233 } /* }}} function gitweb_show_plugin_page */
\r
235 function gitweb_register_plugin_page () /* {{{ */
\r
237 yourls_register_plugin_page ('gitweb_page', 'Gitweb',
\r
238 'gitweb_show_plugin_page');
\r
239 } /* }}} function gitweb_register_plugin_page */
\r
241 yourls_add_action ('plugins_loaded', 'gitweb_register_plugin_page');
\r
242 yourls_add_action ('redirect_keyword_not_found', 'gitweb_redirect_keyword_not_found');
\r
244 /* vim: set sw=2 sts=2 et fdm=marker : */
\r