/[drupal]/contributions/modules/versioncontrol_cvs/versioncontrol_cvs.log.inc
ViewVC logotype

Contents of /contributions/modules/versioncontrol_cvs/versioncontrol_cvs.log.inc

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


Revision 1.12 - (show annotations) (download) (as text)
Sun Jan 11 02:27:30 2009 UTC (10 months, 2 weeks ago) by jpetso
Branch: MAIN
CVS Tags: DRUPAL-6--1-0-RC1, DRUPAL-6--1-0-ALPHA1, DRUPAL-6--1-0-BETA2, DRUPAL-6--1-0-BETA1, HEAD
Changes since 1.11: +2 -2 lines
File MIME type: text/x-php
Show log fetching errors as red errors rather than as green info boxes.
1 <?php
2 // $Id: versioncontrol_cvs.log.inc,v 1.11 2009/01/02 21:28:40 jpetso Exp $
3 /**
4 * @file
5 * CVS backend for Version Control API - Provides CVS commit information and
6 * account management as a pluggable backend.
7 *
8 * This file provides functionality to parse the output of 'cvs rlog'
9 * and transform it into Version Control API commits.
10 *
11 * Copyright 2005 by Kjartan Mannes ("Kjartan", http://drupal.org/user/2)
12 * Copyright 2006, 2007 by Derek Wright ("dww", http://drupal.org/user/46549)
13 * Copyright 2007, 2008, 2009 by Jakob Petsovits ("jpetso", http://drupal.org/user/56020)
14 */
15
16 /**
17 * Actually update the repository by fetching commits and other stuff
18 * directly from the repository, invoking the cvs executable.
19 *
20 * @return
21 * TRUE if the logs were updated, or FALSE if fetching and updating the logs
22 * failed for whatever reason.
23 */
24 function _versioncontrol_cvs_log_update_repository(&$repository) {
25 _versioncontrol_cvs_init_cvslib();
26
27 // Remember the current time for the "updated" value that is stored later on.
28 $date_updated = time();
29
30 $file_revisions = cvslib_log(
31 $repository['root'], $repository['cvs_specific']['modules'],
32 array('date_lower' => $repository['cvs_specific']['updated'])
33 );
34 if ($file_revisions === FALSE) {
35 drupal_set_message(cvslib_last_error_message(), 'error');
36 return FALSE;
37 }
38
39 // Having retrieved the file revisions, insert those into the database
40 // as Version Control API commits.
41 _versioncontrol_cvs_log_process($repository, $file_revisions);
42 $repository['cvs_specific']['updated'] = $date_updated;
43
44 // Everything's done, remember the time when we updated the log (= now).
45 db_query('UPDATE {versioncontrol_cvs_repositories}
46 SET updated = %d WHERE repo_id = %d',
47 $repository['cvs_specific']['updated'], $repository['repo_id']);
48
49 return TRUE;
50 }
51
52 /**
53 * Update the database by processing and inserting the previously retrieved
54 * file revision objects.
55 *
56 * @param $repository
57 * The repository array, as given by the Version Control API.
58 * @param $file_revisions
59 * A simple, flat list of file revision objects, as returned by cvslib_log().
60 */
61 function _versioncontrol_cvs_log_process($repository, $file_revisions) {
62 $operation_items_by_commitid = array();
63 $operation_items_by_user = array();
64
65 foreach ($file_revisions as $file_revision) {
66 // Don't insert the same revision twice.
67 $count = db_result(db_query(
68 "SELECT COUNT(*)
69 FROM {versioncontrol_item_revisions} ir
70 INNER JOIN {versioncontrol_operation_items} opitem
71 ON ir.item_revision_id = opitem.item_revision_id
72 INNER JOIN {versioncontrol_operations} op
73 ON opitem.vc_op_id = op.vc_op_id
74 WHERE op.repo_id = %d AND op.type = %d
75 AND ir.path = '%s' AND ir.revision = '%s'",
76 $repository['repo_id'], VERSIONCONTROL_OPERATION_COMMIT,
77 $file_revision->path, $file_revision->revision
78 ));
79 if ($count > 0) { // Item revision has been recorded already.
80 continue;
81 }
82
83 // We might only pick one of those (depending if the file
84 // has been added, modified or deleted) but let's add both
85 // current and source items for now.
86 $operation_item = array(
87 'type' => VERSIONCONTROL_ITEM_FILE,
88 'path' => $file_revision->path,
89 'revision' => $file_revision->revision,
90 'action' => VERSIONCONTROL_ACTION_MODIFIED, // default, might be changed
91 'source_items' => array(
92 array(
93 'type' => VERSIONCONTROL_ITEM_FILE,
94 'path' => $file_revision->path,
95 'revision' => versioncontrol_cvs_get_previous_revision_number($file_revision->revision),
96 ),
97 ),
98 'line_changes' => array(
99 'added' => $file_revision->lines_added,
100 'removed' => $file_revision->lines_removed,
101 ),
102 'cvs_specific' => array(
103 'file_revision' => $file_revision, // temporary
104 ),
105 );
106
107 if ($file_revision->dead) {
108 $operation_item['action'] = VERSIONCONTROL_ACTION_DELETED;
109 $operation_item['type'] = VERSIONCONTROL_ITEM_FILE_DELETED;
110 }
111 else {
112 if ($file_revision->revision === '1.1') {
113 $operation_item['action'] = VERSIONCONTROL_ACTION_ADDED;
114 $operation_item['source_items'] = array();
115 unset($operation_item['line_changes']);
116 }
117 }
118
119 if (isset($file_revision->commitid)) {
120 $operation_items_by_commitid[$file_revision->commitid][$file_revision->path] = $operation_item;
121 }
122 else {
123 $operation_items_by_user[$file_revision->username]
124 [$file_revision->date][$file_revision->path] = $operation_item;
125 }
126 }
127
128 $commit_infos_by_date = array();
129
130 // Part one: revisions with commitid - these are cool & easy.
131 foreach ($operation_items_by_commitid as $commitid => $operation_items) {
132 _versioncontrol_cvs_log_construct_commit_operation(
133 $repository, $operation_items, $commit_infos_by_date
134 );
135 }
136
137 // Part two: revisions without commitid - need to apply heuristics
138 // in order to get whole commits instead of separate file-by-file stuff.
139 foreach ($operation_items_by_user as $username => $operation_items_by_date) {
140 // Iterating through the date sorted array is a bit complicated
141 // as we need to delete file revision elements that are determined to be
142 // in the same commit as the reference item.
143 while ($date = key($operation_items_by_date)) {
144 while ($path = key($operation_items_by_date[$date])) {
145 $reference_item = array_shift($operation_items_by_date[$date]);
146
147 $operation_items = _versioncontrol_cvs_log_group_items(
148 $operation_items_by_date, $reference_item
149 );
150 _versioncontrol_cvs_log_construct_commit_operation(
151 $repository, $operation_items, $commit_infos_by_date
152 );
153 }
154 unset($operation_items_by_date[$date]); // Done with this date, next one.
155 reset($operation_items_by_date); // Set the array pointer to the start.
156 }
157 }
158
159 // Ok, we've got all commit operations gathered and in a nice array with
160 // the commit date as key. So the only thing that's left is to sort them
161 // and then send each commit to the API function for inserting into the db.
162 ksort($commit_infos_by_date);
163 foreach ($commit_infos_by_date as $date => $date_commit_infos) {
164 foreach ($date_commit_infos as $commit_info) {
165 _versioncontrol_cvs_fix_commit_operation_items(
166 $commit_info->operation, $commit_info->operation_items
167 );
168 versioncontrol_insert_operation(
169 $commit_info->operation, $commit_info->operation_items
170 );
171 }
172 }
173 }
174
175 /**
176 * Extract (and delete) items from the given $operation_items_by_date array
177 * that belong to the same commit as the $reference_action.
178 * This function is what provides heuristics for grouping file revisions
179 * (that lack a commitid) together into one commit operation.
180 *
181 * @return
182 * One or more items grouped into an $operation_items array,
183 * complete with file paths as keys as required by the Version Control API.
184 */
185 function _versioncontrol_cvs_log_group_items(&$operation_items_by_date, $reference_item) {
186 $file_revision = $reference_action['cvs_specific']['file_revision'];
187
188 $operation_items = array();
189 $operation_items[$file_revision->path] = $reference_item;
190
191 // Try all file revisions in the near future (next 30 seconds) to see if
192 // they belong to the same commit or not. If they do, extract and delete.
193 // Commits that take longer than half a minute are unlikely enough to be
194 // disregarded here.
195 for ($date = $file_revision->date; $date < ($file_revision->date + 30); $date++) {
196 if (!isset($operation_items_by_date[$date])) {
197 continue;
198 }
199
200 foreach ($operation_items_by_date[$date] as $path => $current_item) {
201 $current_file_revision = $current_item['cvs_specific']['file_revision'];
202
203 // Check for message and branch to be similar. We know that the username
204 // is similar because we sorted by that one, and the date is near enough
205 // to be regarded as roughly the same time.
206 if ($current_file_revision->message == $file_revision->message
207 && $current_file_revision->branch == $file_revision->branch) {
208 // So, sure enough, we have a file from the same commit here.
209 $operation_items[$path] = $current_item;
210 unset($operation_items_by_date[$date][$path]); // Don't process this revision twice.
211 }
212 }
213 }
214 return $operation_items;
215 }
216
217 /**
218 * Use the additional file revision information that has been stored in each
219 * operation item array in order to assemble the associated commit operation.
220 * That commit information is then stored as a list item in the given
221 * $commit_operations array as an object with 'operation' and 'operation_items'
222 * properties.
223 */
224 function _versioncontrol_cvs_log_construct_commit_operation($repository, $operation_items, &$commit_infos_by_date) {
225 $date = 0;
226
227 // Get any of those commit properties, they should all be the same anyways
228 // (apart from the date which may vary in large commits).
229 foreach ($operation_items as $path => $item) {
230 $file_revision = $item['cvs_specific']['file_revision'];
231 unset($operation_items[$path]['cvs_specific']['file_revision']);
232
233 if ($file_revision->date > $date) {
234 $date = $file_revision->date;
235 }
236 $username = $file_revision->username;
237 $message = $file_revision->message;
238 $branch_name = $file_revision->branch;
239 }
240
241 // Yay, we have all operation items and all information. Ready to go!
242 $operation = array(
243 'type' => VERSIONCONTROL_OPERATION_COMMIT,
244 'repo_id' => $repository['repo_id'],
245 'date' => $date,
246 'username' => $username,
247 'message' => $message,
248 'revision' => '',
249 'labels' => array(
250 array(
251 'name' => $branch_name,
252 'type' => VERSIONCONTROL_OPERATION_BRANCH,
253 'action' => VERSIONCONTROL_ACTION_MODIFIED,
254 ),
255 ),
256 );
257
258 $commit_info = new stdClass();
259 $commit_info->operation = $operation;
260 $commit_info->operation_items = $operation_items;
261 $commit_infos_by_date[$date][] = $commit_info;
262 }

  ViewVC Help
Powered by ViewVC 1.1.2