/[drupal]/contributions/modules/versioncontrol_svn/versioncontrol_svn.module
ViewVC logotype

Contents of /contributions/modules/versioncontrol_svn/versioncontrol_svn.module

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.18 - (show annotations) (download) (as text)
Sat Jun 20 10:26:36 2009 UTC (5 months ago) by jpetso
Branch: MAIN
CVS Tags: HEAD
Changes since 1.17: +2 -2 lines
File MIME type: text/x-php
Enable the "Commit restrictions" fieldset in the repository edit form
by specifying the COMMIT_RESTRICTIONS capability for the backend.

Use the resulting "Allow unauthorized commit access" option in the tests
to make sure that unauthorized accounts can't commit to the test repository.
1 <?php
2 // $Id: versioncontrol_svn.module,v 1.17 2009/06/20 10:16:51 jpetso Exp $
3 /**
4 * @file
5 * Subversion backend for Version Control API - Provides Subversion commit
6 * information and account management as a pluggable backend.
7 *
8 * Copyright 2007, 2008 by Jakob Petsovits ("jpetso", http://drupal.org/user/56020)
9 */
10
11 // Update methods.
12 define('VERSIONCONTROL_SVN_UPDATE_CRON', 1);
13 define('VERSIONCONTROL_SVN_UPDATE_XSVN', 2);
14
15 // The admin and user edit pages.
16 include_once(drupal_get_path('module', 'versioncontrol_svn') .'/versioncontrol_svn.forms.inc');
17
18 define('VERSIONCONTROL_SVN_ACTION_DELETE', 0x001);
19 define('VERSIONCONTROL_SVN_ACTION_CHANGE', 0x002);
20 define('VERSIONCONTROL_SVN_ACTION_MOVE', 0x004);
21 define('VERSIONCONTROL_SVN_ACTION_COPY', 0x008);
22 define('VERSIONCONTROL_SVN_ACTION_ADD', 0x010 | VERSIONCONTROL_SVN_ACTION_CHANGE);
23 define('VERSIONCONTROL_SVN_ACTION_MODIFY', 0x020 | VERSIONCONTROL_SVN_ACTION_CHANGE);
24 define('VERSIONCONTROL_SVN_ACTION_REPLACE', 0x040 | VERSIONCONTROL_SVN_ACTION_CHANGE | VERSIONCONTROL_SVN_ACTION_DELETE);
25 define('VERSIONCONTROL_SVN_ACTION_REPLACE_INPLACE', 0x080 | VERSIONCONTROL_SVN_ACTION_REPLACE);
26 define('VERSIONCONTROL_SVN_ACTION_DELETE_SIMPLE', 0x100 | VERSIONCONTROL_SVN_ACTION_DELETE);
27 define('VERSIONCONTROL_SVN_ACTION_DELETE_UGLY', 0x200 | VERSIONCONTROL_SVN_ACTION_DELETE);
28
29 /**
30 * Implementation of hook_versioncontrol_backends().
31 *
32 * @return
33 * A structured array containing information about this known backends.
34 * Array key is the unique string identifier of the version control system.
35 * The corresponding array values are again structured arrays and consist
36 * of elements with the following keys:
37 *
38 * 'name': The user-visible name of the VCS.
39 * 'description': A short description of the backend, if possible not longer
40 * than one or two sentences.
41 * 'capabilities': An array listing optional capabilities, in addition to the
42 * required functionality like retrieval of detailed
43 * commit information. Array values can be an arbitrary
44 * combination of VERSIONCONTROL_CAPABILITY_* values. If no
45 * additional capabilities are supported by the backend,
46 * this array will be empty.
47 * 'autoadd': An array listing which tables should be managed by
48 * Version Control API instead of doing it manually in
49 * the backend. Array values can be an arbitrary combination of
50 * VERSIONCONTROL_AUTOADD_* values. If no array additions
51 * should be automatically managed, this array will be empty.
52 */
53 function versioncontrol_svn_versioncontrol_backends() {
54 return array(
55 // The array key is up to 8 characters long, and used as unique identifier
56 // for this VCS, in functions, URLs and in the database.
57 'svn' => array(
58 // The user-visible name of the VCS.
59 'name' => 'Subversion',
60
61 // A short description of the VCS, if possible not longer than one or two sentences.
62 'description' => t('Subversion (SVN) is a code management system that supports file and directory revisions, atomic commits, serverless diffs and renaming items. Tags and branches are emulated by directory naming conventions, and merge functionality is still lacking.'),
63
64 // A list of optional capabilities, in addition to the required retrieval
65 // of detailed commit information.
66 'capabilities' => array(
67 // Able to cancel commits if the committer lacks permissions
68 // to commit to specific paths and/or branches.
69 // Not implemented yet.
70 VERSIONCONTROL_CAPABILITY_COMMIT_RESTRICTIONS,
71 // Able to cancel branch or tag assignments if the committer lacks
72 // permissions to create/update/delete those.
73 // Not implemented yet.
74 //VERSIONCONTROL_CAPABILITY_BRANCH_TAG_RESTRICTIONS,
75 // Able to retrieve a file or its revision number based on a global
76 // revision identifier.
77 VERSIONCONTROL_CAPABILITY_ATOMIC_COMMITS,
78 // The version control system assigns revisions not only to files
79 // but also to directories.
80 VERSIONCONTROL_CAPABILITY_DIRECTORY_REVISIONS,
81 ),
82
83 // An array listing which tables should be managed by Version Control API
84 // instead of doing it manually in the backend.
85 'flags' => array(
86 // versioncontrol_insert_repository() will automatically insert
87 // array elements from $repository['svn_specific'] into
88 // {versioncontrol_svn_repositories} and versioncontrol_get_repositories()
89 // will automatically fetch it from there.
90 VERSIONCONTROL_FLAG_AUTOADD_REPOSITORIES,
91 ),
92 ),
93 );
94 }
95
96 /**
97 * Implementation of hook_menu().
98 */
99 function versioncontrol_svn_menu() {
100 global $user;
101 $items = array();
102
103 $items['admin/project/versioncontrol-repositories/update/svn/%versioncontrol_repository'] = array(
104 'title' => 'Fetch log',
105 'page callback' => 'versioncontrol_svn_update_repository_callback',
106 'page arguments' => array(5),
107 'access callback' => 'versioncontrol_admin_access',
108 'type' => MENU_CALLBACK,
109 );
110 return $items;
111 }
112
113 /**
114 * Implementation of hook_cron():
115 * Update repositories that have log fetching enabled.
116 */
117 function versioncontrol_svn_cron() {
118 $result = db_query("SELECT repo_id FROM {versioncontrol_svn_repositories}
119 WHERE update_method = %d", VERSIONCONTROL_SVN_UPDATE_CRON);
120
121 // Set timeout limit to 3600 seconds as it can take a long time to process
122 // the log initially. (And hook_cron() might be called by poormanscron.)
123 if (!ini_get('safe_mode')) {
124 set_time_limit(3600);
125 }
126 while ($repo = db_fetch_object($result)) {
127 $repository = versioncontrol_get_repository($repo->repo_id);
128 if (isset($repository)) {
129 _versioncontrol_svn_update_repository($repository);
130 }
131 }
132 }
133
134
135 /**
136 * Implementation of [versioncontrol_backend]_format_revision_identifier():
137 * Get the user-visible version of a commit identifier a.k.a. 'revision',
138 * as plaintext.
139 */
140 function versioncontrol_svn_format_revision_identifier($repository, $revision, $format = 'full') {
141 switch ($format) {
142 case 'full':
143 case 'short':
144 default:
145 return 'r'. $revision;
146 }
147 }
148
149 /**
150 * Implementation of [versioncontrol_backend]_get_selected_operation_item_label():
151 * Retrieve the tag or branch that applied to that item during the given
152 * operation. The result of this function will be used for the 'selected_label'
153 * property of each item, which is necessary to provide a starting point for
154 * branch and tag navigation.
155 */
156 function versioncontrol_svn_get_selected_label_from_operation($operation, $target_item) {
157 // No branch/tag support yet, might be implemented in the future.
158 return NULL;
159 }
160
161 /**
162 * Implementation of [versioncontrol_backend]_get_selected_label_from_other_item():
163 * Retrieve a valid label (tag or branch) for a new @p $target_item that is
164 * (hopefully) similar or related to that of the given @p $other_item which
165 * already has a selected label assigned. If the backend cannot find a related
166 * label, return any valid label. The result of this function will be used for
167 * the selected label property of each item, which is necessary to preserve the
168 * item state throughout navigational API functions.
169 */
170 function versioncontrol_svn_get_selected_label_from_other_item($repository, $target_item, &$other_item, $other_item_tags = array()) {
171 // No branch/tag support yet, might be implemented in the future.
172 return NULL;
173 }
174
175
176 /**
177 * Include the svnlib.inc helper library and initialize persistent
178 * repository settings that will be reused in later svnlib function calls.
179 */
180 function _versioncontrol_svn_init_svnlib(&$repository) {
181 if (!empty($repository['repo']) && $repository['repo'] instanceof SvnInstance) {
182 // Cut out early if the repo object has already been built.
183 return;
184 }
185
186 if (!class_exists('SvnInstance')) {
187 require_once(drupal_get_path('module', 'versioncontrol_svn') .'/new_svnlib/svn.php');
188 }
189
190 $repository['repo'] = &svnlib_get_repository($repository['root']);
191 $repo = &$repository['repo'];
192
193 if (!empty($repository['svn_specific']['auth_username'])) {
194 $repo->username($repository['svn_specific']['auth_username'])
195 ->password(str_rot13($repository['svn_specific']['auth_password']));
196 }
197 }
198
199 /**
200 * Implementation of [versioncontrol_backend]_get_item():
201 * Try to retrieve a given item in a repository.
202 */
203 function versioncontrol_svn_get_item(&$repository, $path, $constraints = array()) {
204 _versioncontrol_svn_init_svnlib($repository);
205 $revision = empty($constraints['revision']) ? 'HEAD' : $constraints['revision'];
206 $info = reset($repository['repo']->svn('info')->target($path)->revision($revision)
207 ->execute()->seekPath($path));
208
209 if (empty($info)) {
210 return NULL;
211 }
212 $item = array(
213 'path' => $info['path'],
214 'revision' => $info['created_rev'],
215 'type' => ($info['type'] == 'dir')
216 ? VERSIONCONTROL_ITEM_DIRECTORY
217 : VERSIONCONTROL_ITEM_FILE,
218 );
219 return array('item' => $item, 'selected_label' => NULL);
220 }
221
222 /**
223 * Implementation of [versioncontrol_backend]_get_directory_contents():
224 * Retrieve the set of files and directories that exist at a specified revision
225 * in the given directory inside the repository.
226 */
227 function versioncontrol_svn_get_directory_contents(&$repository, $directory_item, $recursive = FALSE) {
228 _versioncontrol_svn_init_svnlib($repository);
229
230 $info = $repository['repo']->svn('info')->target($directory_item['path'])
231 ->revision($directory_item['revision'])
232 ->depth($recursive ? 'infinite' : 'immediates')
233 ->execute()->seekPath($path);
234
235 $items = array();
236
237 foreach ($info as $item_info) {
238 $items[$item_info['path']] = array(
239 'item' => array(
240 'path' => $item_info['path'],
241 'revision' => $item_info['created_rev'],
242 'type' => ($item_info['type'] == 'dir')
243 ? VERSIONCONTROL_ITEM_DIRECTORY
244 : VERSIONCONTROL_ITEM_FILE,
245 ),
246 'selected_label' => NULL,
247 );
248 }
249 return $items;
250 }
251
252 /**
253 * Implementation of [versioncontrol_backend]_export_file():
254 * Retrieve a copy of the contents of a given item in the repository.
255 * (You won't get the original because repositories can often be remote.)
256 */
257 function versioncontrol_svn_export_file(&$repository, $file_item, $destination) {
258 _versioncontrol_svn_init_svnlib($repository);
259
260 $success = svnlib_cat($destination,
261 $repository['root'] . $file_item['path'], $file_item['revision']
262 );
263 return $success;
264 }
265
266
267 /**
268 * Menu callback for
269 * 'admin/project/versioncontrol-repositories/update/svn/%versioncontrol_repository':
270 * Retrieve/validate the specified repository, fetch new commits by invoking
271 * the svn executable, output messages and redirect back to the repository page.
272 */
273 function versioncontrol_svn_update_repository_callback(&$repository) {
274 if ($repository['svn_specific']['update_method'] == VERSIONCONTROL_SVN_UPDATE_CRON) {
275 _versioncontrol_svn_init_svnlib($repository);
276 // Set timeout limit to 3600 seconds as it can take a long time
277 // to process the log initially.
278 if (!ini_get('safe_mode')) {
279 set_time_limit(3600);
280 }
281 $message = _versioncontrol_svn_update_repository($repository);
282 drupal_set_message($message);
283 }
284 else {
285 drupal_set_message(t('Repository update method does not allow manual updates, did not fetch anything.'));
286 }
287 drupal_goto('admin/project/versioncontrol-repositories');
288 }
289
290 /**
291 * Actually update the repository by fetching commits directly from
292 * the repository, invoking the svn executable.
293 *
294 * @return
295 * TRUE if the logs were updated, or FALSE if fetching and updating the logs
296 * failed for whatever reason.
297 */
298 function _versioncontrol_svn_update_repository(&$repository) {
299 include_once(drupal_get_path('module', 'versioncontrol_svn') .'/versioncontrol_svn.log.inc');
300 return _versioncontrol_svn_log_update_repository($repository);
301 }
302
303 /**
304 * Implementation of [versioncontrol_backend]_is_account_username_valid():
305 * Determine if the given repository allows a username to exist.
306 *
307 * It looks like Subversion can take any characters (any of the ascii printable
308 * characters, at least) as a username; the issue is just safely escaping the
309 * strings.
310 *
311 * At the very least [a-zA-Z0-9_-]+ should be fine, and would probably take care
312 * of most of the cases worth worrying about. Adding [.@+] would get most email
313 * addresses, and shouldn't be too much to worry about, security-wise.
314 *
315 * @param $repository
316 * The repository where the the VCS account exists or will be located.
317 * @param $username
318 * The username to check. It is passed by reference so if the username is
319 * valid but needs minor adaptions (such as cutting away unneeded parts) then
320 * it the backend can modify it before returning the result.
321 *
322 * @return
323 * TRUE if the username is valid, FALSE if not.
324 */
325 function versioncontrol_svn_is_account_username_valid($repository, &$username) {
326 return drupal_validate_utf8($username);
327 }

  ViewVC Help
Powered by ViewVC 1.1.2