'commitlog',
'title' => t('Commit Log'),
'callback' => 'commitlog_commits_page',
'access' => $access,
'type' => MENU_SUGGESTED_ITEM,
);
$items[] = array(
'path' => 'commitlog/feed',
'title' => t('Commit Log'),
'callback' => 'commitlog_commits_rss',
'access' => $access,
'type' => MENU_CALLBACK,
);
$items[] = array(
'path' => 'commitlog/tags',
'title' => t('Tag history'),
'callback' => 'commitlog_tags_page',
'access' => $access,
'type' => MENU_SUGGESTED_ITEM,
);
$items[] = array(
'path' => 'commitlog/branches',
'title' => t('Branch history'),
'callback' => 'commitlog_branches_page',
'access' => $access,
'type' => MENU_SUGGESTED_ITEM,
);
// Search pages:
/*
// until this works, no sense displaying this page
// see http://drupal.org/node/59659
$items[] = array(
'path' => 'search/commitlog',
'title' => t('Commit messages'),
'callback' => 'commitlog_commits_page_search',
'access' => $access,
'type' => MENU_LOCAL_TASK,
'weight' => 2,
);
*/
}
else {
if (arg(0) == 'user' && is_numeric(arg(1))) {
$uid = arg(1);
$accounts = versioncontrol_get_accounts(array('uids' => array($uid)));
if (!empty($accounts)) {
// If the user has a CVS account, add a 'track commit messages' tab to the tracker page.
$items[] = array(
'path' => 'user/'. $uid .'/track/code',
'title' => t('Track code'),
'callback' => 'commitlog_account_tracker',
'callback arguments' => array($uid),
'access' => user_access('access commit messages'),
'type' => MENU_LOCAL_TASK,
'weight' => 2,
);
}
}
}
return $items;
}
/**
* Implementation of hook_perm().
*/
function commitlog_perm() {
return array('access commit messages');
}
/**
* Implementation of hook_form_alter():
* Add a fieldset for to the general settings form so that the user can
* enable/disable admin notification mails and configure the pager limit.
*/
function commitlog_form_alter($form_id, &$form) {
if ($form['#id'] == 'versioncontrol-settings-form') {
$form['#validate']['commitlog_settings_validate'] = array();
$form['#submit']['commitlog_settings_submit'] = array();
$form['commitlog'] = array(
'#type' => 'fieldset',
'#title' => t('Commit Log'),
'#collapsible' => TRUE,
'#collapsed' => TRUE,
'#weight' => 3,
);
$form['commitlog']['commitlog_send_notification_mails'] = array(
'#type' => 'checkbox',
'#title' => 'Send commit notification mails to the VCS administrator',
'#description' => 'If this is enabled, each commit that is recorded on this site causes a notification mail to be sent to the VCS administrator\'s e-mail address. This mail includes all relevant commit data like the commit message and the files and directories that were changed. Note that disabling the Commit Log module also disables notification mails.',
'#default_value' => variable_get('commitlog_send_notification_mails', 0),
);
$form['commitlog']['commitlog_pager'] = array(
'#type' => 'textfield',
'#title' => t('Number of commits per page'),
'#description' => t('Controls how many commits can be shown on a single page of the !commitlog. Paging is used when there are more commits to show than specified by this value.', array('!commitlog' => l(t('Commit Log'), 'commitlog'))),
'#default_value' => variable_get('commitlog_pager', 10),
);
}
}
/**
* Validation handler for the settings form:
* Make sure that the pager limit is a positive number.
*/
function commitlog_settings_validate($form_id, $form_values) {
if (!is_numeric($form_values['commitlog_pager']) || $form_values['commitlog_pager'] <= 0) {
form_set_error('commitlog_pager', t('The number of commits per page needs to be a positive number.'));
}
}
/**
* Submit handler for the settings form.
*/
function commitlog_settings_submit($form_id, $form_values) {
variable_set('commitlog_pager', $form_values['commitlog_pager']);
variable_set('commitlog_send_notification_mails', $form_values['commitlog_send_notification_mails']);
}
/**
* Implementation of hook_versioncontrol_commit():
* If enabled, send out a notification mail to the VCS admin.
*/
function commitlog_versioncontrol_commit($op, $commit, $commit_actions) {
if ($op == 'insert') {
if (variable_get('commitlog_send_notification_mails', 0)) {
$to = variable_get('versioncontrol_email_address', 'versioncontrol@example.com');
commitlog_send_commit_mail($to, $commit, $commit_actions);
}
}
}
/**
* Implementation of hook_versioncontrol_branch_operation():
* If enabled, send out a notification mail to the VCS admin.
*/
function commitlog_versioncontrol_branch_operation($op, $branch, $branched_items) {
if ($op == 'insert') {
if (variable_get('commitlog_send_notification_mails', 0)) {
$to = variable_get('versioncontrol_email_address', 'versioncontrol@example.com');
commitlog_send_branch_or_tag_mail('branch', $to, $branch, $branched_items);
}
}
}
/**
* Implementation of hook_versioncontrol_tag_operation():
* If enabled, send out a notification mail to the VCS admin.
*/
function commitlog_versioncontrol_tag_operation($op, $tag, $tagged_items) {
if ($op == 'insert') {
if (variable_get('commitlog_send_notification_mails', 0)) {
$to = variable_get('versioncontrol_email_address', 'versioncontrol@example.com');
commitlog_send_branch_or_tag_mail('tag', $to, $tag, $tagged_items);
}
}
}
/**
* Send out a commit notification mail to the given mail address.
*/
function commitlog_send_commit_mail($to, $commit, $commit_actions) {
$admin_mail = variable_get('versioncontrol_email_address', 'versioncontrol@example.com');
$location = theme('commitlog_commit_location', $commit, NULL, 'plaintext');
$username = commitlog_account_username(
$commit['uid'], $commit['username'], $commit['repository'], TRUE, 'plaintext'
);
$from = "$username <$admin_mail>";
$subject = $location;
$message = commitlog_commit($commit, $commit_actions, $username, 'plaintext');
drupal_mail(
'commitlog_notification_email', $to,
$subject, $message, $from, array('X-Mailer' => 'Drupal')
);
}
/**
* Send out a branch or tag notification mail to the given mail address.
*
* @param $type
* Either 'branch' or 'tag'.
*/
function commitlog_send_branch_or_tag_mail($type, $to, $op, $items) {
$admin_mail = variable_get('versioncontrol_email_address', 'versioncontrol@example.com');
$username = commitlog_account_username(
$op['uid'], $op['username'], $op['repository'], TRUE, 'plaintext'
);
$from = "$username <$admin_mail>";
$subject = theme('commitlog_branch_or_tag_email_subject',
$type, $op, $items, $username
);
$message = commitlog_branch_or_tag_operation(
$type, $op, $items, $username, 'plaintext'
);
drupal_mail(
'commitlog_notification_email', $to,
$subject, $message, $from, array('X-Mailer' => 'Drupal')
);
}
/**
* Page callback for the 'commitlog' menu path.
*/
function commitlog_commits_page() {
if ($error_message = _commitlog_check_request()) {
return $error_message;
}
list($constraints, $attributes) = _commitlog_get_commit_constraints();
$commits = commitlog_get_paged_commits($constraints);
drupal_add_css(drupal_get_path('module', 'commitlog') .'/commitlog.css');
return theme('commitlog_commits_page', $commits, $attributes);
}
/**
* Page callback for the 'track code' tab on the user page.
*/
function commitlog_account_tracker($uid) {
$user = user_load(array('uid' => $uid));
if (!$user) {
drupal_not_found();
exit();
}
$_REQUEST['uids'] = (string) $uid;
drupal_set_title($user->name);
list($constraints, $attributes) = _commitlog_get_commit_constraints();
$commits = commitlog_get_paged_commits($constraints);
unset($_REQUEST['uids']);
drupal_add_css(drupal_get_path('module', 'commitlog') .'/commitlog.css');
return theme('commitlog_commits_page', $commits, $attributes);
}
/**
* Page callback for the 'commitlog/feed' menu path.
*/
function commitlog_commits_rss() {
if ($error_message = _commitlog_check_request()) {
exit();
}
list($constraints, $attributes) = _commitlog_get_commit_constraints();
$commits = commitlog_get_paged_commits($constraints);
drupal_set_header('Content-Type: text/xml; charset=utf-8');
print theme('commitlog_rss', $commits);
exit();
}
/**
* Retrieve the commit constraints for the page display by dissecting
* the $_REQUEST variable.
*
* @return
* An array($constraints, $attributes) where $constraints is an array of
* commit constraints supposed to be passed to versioncontrol_get_commits(),
* and $attributes is an associative array of the processed arguments
* from $_REQUEST.
*/
function _commitlog_get_commit_constraints() {
$constraints = array();
$attributes = array();
// Transform query string into query string. We use $_REQUEST because we
// need to support both GET and POST requests.
if (isset($_REQUEST['commits'])) {
$constraints['commit_ids'] = explode(',', $_REQUEST['commits']);
$attributes['commits'] = $_REQUEST['commits'];
}
if (isset($_REQUEST['usernames'])) {
$constraints['usernames'] = explode(',', $_REQUEST['usernames']);
$attributes['usernames'] = $_REQUEST['usernames'];
}
if (isset($_REQUEST['uids'])) {
$constraints['uids'] = explode(',', $_REQUEST['uids']);
$attributes['uids'] = $_REQUEST['uids'];
}
if (isset($_REQUEST['vcs'])) {
$constraints['vcs'] = explode(',', $_REQUEST['vcs']);
$attributes['vcs'] = $_REQUEST['vcs'];
}
if (isset($_REQUEST['branches'])) {
$constraints['branches'] = explode(',', $_REQUEST['branches']);
$attributes['branches'] = $_REQUEST['branches'];
}
if (isset($_REQUEST['paths'])) {
$constraints['paths'] = explode(',', $_REQUEST['paths']);
$attributes['paths'] = $_REQUEST['paths'];
}
if (isset($_REQUEST['repos'])) {
$constraints['repo_ids'] = explode(',', $_REQUEST['repos']);
$attributes['repos'] = $_REQUEST['repos'];
}
// filter by commit message search? ...use cases?
if (module_exists('versioncontrol_project')) {
$project_constraints = array();
if (isset($_REQUEST['nids'])) {
$project_constraints['nids'] = explode(',', $_REQUEST['nids']);
$attributes['nids'] = $_REQUEST['nids'];
}
if (isset($_REQUEST['maintainer_uids'])) {
$project_constraints['maintainer_uids'] = explode(',', $_REQUEST['maintainers']);
$attributes['maintainers'] = $_REQUEST['maintainers'];
}
if (!empty($project_constraints)) {
$constraints = versioncontrol_project_get_commit_constraints(
$constraints, $project_constraints
);
}
}
return array($constraints, $attributes);
}
/**
* Return an array of commits, resulting from a versioncontrol_get_commits()
* call. Paging is also used by emulating pager_query().
*/
function commitlog_get_paged_commits($constraints, $element = 0) {
global $pager_page_array, $pager_total, $pager_total_items;
$page = isset($_GET['page']) ? $_GET['page'] : '';
$pager_page_array = explode(',', $page);
$page = empty($pager_page_array[$element]) ? 0 : $pager_page_array[$element];
$limit = variable_get('commitlog_pager', 10);
$commits = versioncontrol_get_commits($constraints, $result_count, $page, $limit);
// Emulate pager_query() in order to get a proper theme('pager').
$pager_total_items[$element] = $result_count;
$pager_total[$element] = ceil($pager_total_items[$element] / $limit);
$pager_page_array[$element] = max(0, min((int)$pager_page_array[$element], ((int)$pager_total[$element]) - 1));
return $commits;
}
/**
* Check the $_REQUEST variable if it contains elements that can't be processed
* in the current Drupal configuration.
*
* @return
* A string containing the appropriate error message, or NULL if everything
* can proceed as planned.
*/
function _commitlog_check_request() {
if (isset($_REQUEST['nids']) || isset($_REQUEST['maintainers'])) {
if (!module_exists('versioncontrol_project')) {
return '
'. t('The given commit constraints can\'t be applied as the Version Control / Project Node Integration module is not enabled. In order to use the "nids" or "maintainer_uids" constraints, please enable this module.') .'
';
}
}
return NULL;
}
/**
* Return a formatted date string if the given timestamp is on a different day
* than the one that was passed previous call to this function, or NULL if the
* previous call's timestamp argument is on the same day as this one.
*/
function _commitlog_date($timestamp) {
static $last;
$date = format_date($timestamp, 'custom', 'F j, Y');
if ($date != $last) {
$last = $date;
return $date;
}
return NULL;
}
/**
* Return formatted output for displaying the given commits on an HTML page.
*/
function theme_commitlog_commits_page($commits, $attributes) {
if (empty($commits)) {
return ''. t('No commit messages found.') .'
';
}
$output = '';
$initial = TRUE;
foreach ($commits as $commit) {
$commit_actions = versioncontrol_get_commit_actions($commit);
$date = _commitlog_date($commit['date']);
if (isset($date)) { // begin a new list for each day
if (!$initial) {
$output .= '';
}
$initial = FALSE;
$output .= "
$date
";
$output .= '
';
}
$output .= '- '. commitlog_commit($commit, $commit_actions, NULL, 'html') .'
';
}
$output .= '
';
if ($pager = theme('pager', NULL, variable_get('commitlog_pager', 10), 0, $attributes)) {
$output .= $pager;
}
$output .= '
';
$query_items = array();
foreach ($attributes as $key => $value) {
$query_items[] = $key .'='. $value;
}
$query = empty($query_items) ? NULL : implode('&', $query_items);
$output .= theme('feed_icon', url('commitlog/feed', $query));
return $output;
}
function theme_commitlog_rss($commits) {
global $languages, $base_url;
$language = empty($languages) ? 'en' : reset(array_keys($languages));
$items = '';
foreach ($commits as $commit) {
$commit_actions = versioncontrol_get_commit_actions($commit);
$location = theme('commitlog_commit_location', $commit);
$username = commitlog_account_username(
$commit['uid'], $commit['username'], $commit['repository']
);
$title = t('!location by @username', array('!location' => $location, '@username' => $username));
$link = url('commitlog', 'commits='. $commit['commit_id'], NULL, TRUE);
$extra = array(
array('key' => 'pubDate', 'value' => gmdate('r', $commit['date'])),
array('key' => 'guid',
'value' => 'Commit '. $commit['commit_id'] .' at '. $base_url,
'attributes' => array('isPermaLink' => 'false'),
),
);
$text = commitlog_commit($commit, $commit_actions, $username, 'html');
$items .= format_rss_item($title, $link, $text, $extra);
}
$title = t('Commit messages for @site', array('@site' => variable_get('site_name', 'Drupal')));
$link = url('commitlog', NULL, NULL, TRUE);
$output = "\n";
$output .= "\n";
$output .= format_rss_channel($title, $link, $title, $items, $language);
$output .= "\n";
return $output;
}
function commitlog_commit($commit, $commit_actions, $username = NULL, $format = 'html') {
if (isset($username)) {
$variables['username'] = $username;
}
else {
$variables['username'] = commitlog_account_username(
$commit['uid'], $commit['username'], $commit['repository'], TRUE, $format
);
}
$variables['id'] = theme('commitlog_commit_identifier', $commit, $format);
$variables['repository_name'] = theme('commitlog_repository', $commit['repository'], $format);
$variables['time'] = format_date($commit['date'], 'custom', 'H:i');
$variables['actions'] = theme('commitlog_commit_actions', $commit, $commit_actions, $format);
$variables['message'] = theme('commitlog_commit_message', $commit, $format);
$variables['branches'] = theme('commitlog_commit_branches', $commit, $format);
if ($format == 'html') {
return theme('commitlog_commit_html', $variables);
}
return theme('commitlog_commit_plaintext', $variables);
}
function theme_commitlog_commit_html($variables) {
$output = '';
$output .= '
';
$output .= t('Commit !id by !name at !time in !repo:', array(
'!id' => $variables['id'],
'!repo' => $variables['repository_name'],
'!name' => $variables['username'],
'!time' => $variables['time'],
));
$output .= "
\n"; // class "title"
$output .= '
'. $variables['actions'] .'
'."\n";
$output .= '
'. $variables['message'] .'
'."\n";
$output .= "
\n"; // class "commit"
return $output;
}
function theme_commitlog_commit_plaintext($variables) {
$output = t('Commit !id by !name at !time in !repo:', array(
'!id' => $variables['id'],
'!repo' => $variables['repository_name'],
'!name' => $variables['username'],
'!time' => $variables['time'],
)) ."\n\n";
$output .= $variables['message'] ."\n\n";
$output .= $variables['actions'] ."\n";
return $output;
}
/**
* Return a the username of a VCS account.
*
* @param $uid
* The Drupal user id of the user. If this is 0, the corresponding
* Drupal user naturally can't be retrieved, with all implications for
* displaying the username.
* @param $username
* The VCS username for the account.
* @param $repository
* The repository where this account is registered.
* @param $replace_with_drupal_username
* If TRUE (which is the default), this function tries to get the
* corresponding Drupal user for the supplied uid and returns the "real"
* username rather than the given one.
* If FALSE, the given VCS username is always returned.
* @param $format
* If 'html', the username will be linked to the user page (if possible)
* or to the commit log page containing the user's commits.
* If 'plaintext', the username will be returned without markup.
*/
function commitlog_account_username($uid, $username, $repository, $replace_with_drupal_username = TRUE, $format = 'html') {
if ($uid && $replace_with_drupal_username) {
$user = user_load(array('uid' => $uid));
if ($user) {
return ($format == 'html') ? theme('username', $user) : $user->name;
}
}
if ($format == 'html') {
return l(check_plain($username), 'commitlog', NULL,
'usernames='. drupal_urlencode($username) .'&repos='. $repository['repo_id']);
}
return $username;
}
function theme_commitlog_repository($repository, $format = 'html') {
if ($format == 'html') {
return l(check_plain($repository['name']), 'commitlog', NULL, 'repos='. $repository['repo_id']);
}
return check_plain($repository['name']);
}
function theme_commitlog_commit_location($commit, $directory_item = NULL, $format = 'html') {
$item = isset($directory_item)
? $directory_item
: versioncontrol_get_directory_item($commit);
$location = theme('commitlog_item', $commit['repository'], $item, $directory_item['path'], $format);
$branches = theme('commitlog_commit_branches', $commit, $format);
if (!empty($branches)) {
$location = t('!branches: !directory', array(
'!directory' => $location,
'!branches' => $branches,
));
}
return $location;
}
function theme_commitlog_commit_identifier($commit, $format = 'html') {
$id = empty($commit['revision']) ? $commit['commit_id'] : $commit['revision'];
if ($format == 'html') {
$commit_url = versioncontrol_get_url_commit_view($commit);
$id = empty($commit_url)
? theme('commitlog_commit_id', $commit['commit_id'], $id, $format)
: ''. $id .'';
}
return $id;
}
function theme_commitlog_commit_id($commit_id, $text = NULL, $format = 'html') {
if (!isset($text)) {
$text = $commit_id;
}
if ($format == 'html') {
return l($text, 'commitlog', NULL, 'commits='. $commit_id);
}
return $text;
}
function theme_commitlog_commit_message($commit, $format = 'html') {
if ($format != 'html') {
return $commit['message'];
}
// Link to issues whose numbers are given in the commit message.
$message = htmlspecialchars($commit['message']);
$matches = array();
if (preg_match('/(?:(?:fix|add|patch)(?:ed)?\s+#?|#)(\d+)/i', $message, $matches)) {
foreach ($matches as $match) {
$link = strtr('!text', array(
'!text' => $match[0],
'!url' => versioncontrol_get_url_tracker($commit['repository'], $match[1]),
));
$message = strtr($message, array($match[0] => $link));
}
}
return $message;
}
function theme_commitlog_commit_branches($commit, $format = 'html') {
$branches = versioncontrol_get_commit_branches($commit);
if (empty($branches)) {
return '';
}
if ($format == 'html') {
$branch_links = array();
foreach ($branches as $branch) {
$branch_links[] = l($branch, 'commitlog', NULL, 'branches='. $branch);
}
return implode(', ', $branch_links);
}
return implode(', ', $branches);
}
function theme_commitlog_commit_actions($commit, $commit_actions, $format = 'html') {
if (empty($commit_actions)) {
return '';
}
$commit_directory_item = versioncontrol_get_directory_item($commit);
if (module_exists('versioncontrol_project')) {
$project = versioncontrol_project_get_project_for_item($commit['repository'], $commit['directory']);
if (isset($project)) {
$project_item = versioncontrol_get_parent_item(
$commit['repository'], $commit_directory_item, $project['directory']
);
$project_string = theme('commitlog_project', $commit['repository'], $project, $format);
}
}
$directory_item = isset($project_item) ? $project_item : $commit_directory_item;
$lines = array();
foreach ($commit_actions as $path => $action) {
$item = versioncontrol_get_affected_item($action);
if (module_exists('versioncontrol_project')) {
if (isset($project)) {
$item_project = $project;
}
else {
$item_project = versioncontrol_project_get_project_for_item(
$commit['repository'], $item['path']
);
}
}
$offset = ($directory_item['path'] == '/') ? 0 : 1;
$item_path = substr($item['path'], strlen($directory_item['path']) + $offset);
if ($item['type'] == VERSIONCONTROL_ITEM_DIRECTORY) {
$item_path = t('!path [directory]', array('!path' => $item_path));
}
$item_string = theme('commitlog_item', $commit['repository'], $item, $item_path, $format);
if (isset($action['source items'])) {
$oldrev_string = theme('commitlog_item_revision',
$commit['repository'], $action['source items'][0], $format
);
}
if (isset($action['source items'])) {
$olditems = array();
foreach ($action['source items'] as $source_item) {
$item_path = substr($source_item['path'], strlen($directory_item['path']) + 1);
$olditems[] = theme('commitlog_item', $commit['repository'], $source_item, $item_path, $format);
}
$olditems_string = implode(', ', $olditems);
}
$show_diff = FALSE;
if ($format == 'html') {
$diff_string = theme('commitlog_diff_link', $commit, $action);
if (!empty($diff_string)) {
$show_diff = TRUE;
}
}
switch ($action['action']) {
case VERSIONCONTROL_ACTION_ADDED:
$action_string = t('!item (added)');
break;
case VERSIONCONTROL_ACTION_MODIFIED:
$action_string = $show_diff
? t('!item (modified, previous: !oldrev, !diff)')
: t('!item (modified, previous: !oldrev)');
break;
case VERSIONCONTROL_ACTION_MOVED:
$action_string = $show_diff
? t('!item (moved from !olditems, !diff)')
: t('!item (moved from !olditems)');
break;
case VERSIONCONTROL_ACTION_COPIED:
$action_string = $show_diff
? t('!item (copied from !olditems, !diff)')
: t('!item (copied from !olditems)');
break;
case VERSIONCONTROL_ACTION_MERGED:
$action_string = $show_diff
? t('!item (merged from !olditems, !diff)')
: t('!item (merged from !olditems)');
break;
case VERSIONCONTROL_ACTION_DELETED:
$action_string = t('!path (deleted: !oldrev)');
break;
default:
return 'Error: action type enum value not known: '. $action['action'];
}
if ($format == 'html' && isset($item_project)) {
$project_string = isset($project_string)
? $project_string
: theme('commitlog_project', $commit['repository'], $item_project, $format);
$action_string = t('!project: !action', array('!action' => $action_string));
}
$lines[] = strtr($action_string, array(
'!project' => $project_string,
'!item' => $item_string,
'!path' => $item_path,
'!oldrev' => $oldrev_string,
'!olditems' => $olditems_string,
'!diff' => $diff_string,
));
}
$location = theme('commitlog_commit_location', $commit, $directory_item, $format);
if ($format == 'html') {
$output = ''. $location .'
'."\n";
$output .= ''. theme('item_list', $lines) ."
\n";
return $output;
}
// else: plaintext
$output = $location ."\n";
foreach ($lines as $key => $line) {
$lines[$key] = '- '. $line;
}
$output .= implode("\n", $lines);
return $output;
}
function theme_commitlog_item($repository, $item, $path = NULL, $format = 'html') {
$backends = versioncontrol_get_backends();
if (!isset($backends[$repository['vcs']])) {
return '';
}
$has_atomic_commits = FALSE;
$backend = $backends[$repository['vcs']];
if (in_array(VERSIONCONTROL_CAPABILITY_ATOMIC_COMMITS, $backend['capabilities'])) {
$has_atomic_commits = TRUE;
}
if (!isset($path)) {
$path = $item['path'];
}
// For version control systems without atomic commits, display the revision
// next to the path. For all other ones this doesn't make sense, as there is
// only one global revision for all items, and that one is already displayed
// in the commit title.
if (empty($item['revision']) || $has_atomic_commits) {
$output = $path;
if ($format == 'html') {
$view_url = versioncontrol_get_url_item_view($repository, $item);
if (!empty($view_url)) {
$output = ''. $path .'';
}
}
return $output;
}
else {
if ($format == 'html') {
$log_url = versioncontrol_get_url_item_log_view($repository, $item);
if (!empty($log_url)) {
$path = ''. $path .'';
}
}
return $path .' '. theme('commitlog_item_revision', $repository, $item, $format);
}
}
function theme_commitlog_item_revision($repository, $item, $format = 'html') {
if (empty($item['revision'])) {
return '';
}
$revision = $item['revision'];
if ($format == 'html') {
$view_url = versioncontrol_get_url_item_view($repository, $item);
if (!empty($view_url)) {
$revision = ''. $item['revision'] .'';
}
}
return $revision;
}
function theme_commitlog_diff_link($commit, $commit_action) {
// If the item was modified, link to the diff URL.
if (in_array($commit_action['action'], array(VERSIONCONTROL_ACTION_MODIFIED, VERSIONCONTROL_ACTION_MERGED))
|| $action['modified'])
{
$diff_url = versioncontrol_get_url_diff(
$commit['repository'], $commit_action['current item'], $commit_action['source items'][0]
);
if (!empty($diff_url)) {
return ''. t('diff') .'';
}
}
return '';
}
function theme_commitlog_project($repository, $project, $format = 'html') {
$project_node = node_load($project['nid']);
if ($project_node) {
if ($format == 'html') {
return l(check_plain($project_node->title), 'node/'. $project_node->nid);
}
return check_plain($project_node->title);
}
return '';
}
/**
* Page callback for the 'commitlog/branches' menu path.
*/
function commitlog_branches_page() {
if ($error_message = _commitlog_check_request()) {
return $error_message;
}
list($constraints, $attributes) = _commitlog_get_branch_tag_constraints();
$branches = commitlog_get_paged_branch_operations($constraints);
drupal_add_css(drupal_get_path('module', 'commitlog') .'/commitlog.css');
return theme('commitlog_branches_tags_page', 'branch', $branches, $attributes);
}
/**
* Page callback for the 'commitlog/tags' menu path.
*/
function commitlog_tags_page() {
if ($error_message = _commitlog_check_request()) {
return $error_message;
}
list($constraints, $attributes) = _commitlog_get_branch_tag_constraints();
$tags = commitlog_get_paged_tag_operations($constraints);
drupal_add_css(drupal_get_path('module', 'commitlog') .'/commitlog.css');
return theme('commitlog_branches_tags_page', 'tag', $tags, $attributes);
}
/**
* Retrieve the branch or tag constraints for the page display by dissecting
* the $_REQUEST variable.
*
* @return
* An array($constraints, $attributes) where $constraints is
* an array of commit constraints supposed to be passed to
* versioncontrol_get_branch_operations() or
* versioncontrol_get_tag_operations(), and $attributes is
* an associative array of the processed arguments from $_REQUEST.
*/
function _commitlog_get_branch_tag_constraints() {
$constraints = array();
$attributes = array();
// Transform query string into query string. We use $_REQUEST because we
// need to support both GET and POST requests.
if (isset($_REQUEST['branches'])) {
$constraints['branch_names'] = explode(',', $_REQUEST['branches']);
$attributes['branches'] = $_REQUEST['branches'];
}
if (isset($_REQUEST['branch_op_ids'])) {
$constraints['branch_op_ids'] = explode(',', $_REQUEST['branch_op_ids']);
$attributes['branch_op_ids'] = $_REQUEST['branch_op_ids'];
}
if (isset($_REQUEST['tags'])) {
$constraints['tag_names'] = explode(',', $_REQUEST['tags']);
$attributes['tags'] = $_REQUEST['tags'];
}
if (isset($_REQUEST['tag_op_ids'])) {
$constraints['tag_op_ids'] = explode(',', $_REQUEST['tag_op_ids']);
$attributes['tag_op_ids'] = $_REQUEST['tag_op_ids'];
}
if (isset($_REQUEST['usernames'])) {
$constraints['usernames'] = explode(',', $_REQUEST['usernames']);
$attributes['usernames'] = $_REQUEST['usernames'];
}
if (isset($_REQUEST['uids'])) {
$constraints['uids'] = explode(',', $_REQUEST['uids']);
$attributes['uids'] = $_REQUEST['uids'];
}
if (isset($_REQUEST['vcs'])) {
$constraints['vcs'] = explode(',', $_REQUEST['vcs']);
$attributes['vcs'] = $_REQUEST['vcs'];
}
if (isset($_REQUEST['repos'])) {
$constraints['repo_ids'] = explode(',', $_REQUEST['repos']);
$attributes['repos'] = $_REQUEST['repos'];
}
return array($constraints, $attributes);
}
/**
* Return an array of tag operations, resulting from a
* versioncontrol_get_tag_operations() call.
* Paging is also used by emulating pager_query().
*/
function commitlog_get_paged_tag_operations($constraints, $element = 0) {
global $pager_page_array, $pager_total, $pager_total_items;
$page = isset($_GET['page']) ? $_GET['page'] : '';
$pager_page_array = explode(',', $page);
$page = empty($pager_page_array[$element]) ? 0 : $pager_page_array[$element];
$limit = variable_get('commitlog_pager', 10);
$tags = versioncontrol_get_tag_operations($constraints, $result_count, $page, $limit);
// Emulate pager_query() in order to get a proper theme('pager').
$pager_total_items[$element] = $result_count;
$pager_total[$element] = ceil($pager_total_items[$element] / $limit);
$pager_page_array[$element] = max(0, min((int)$pager_page_array[$element], ((int)$pager_total[$element]) - 1));
return $tags;
}
/**
* Return an array of branch operations, resulting from a
* versioncontrol_get_branch_operations() call.
* Paging is also used by emulating pager_query().
*/
function commitlog_get_paged_branch_operations($constraints, $element = 0) {
global $pager_page_array, $pager_total, $pager_total_items;
$page = isset($_GET['page']) ? $_GET['page'] : '';
$pager_page_array = explode(',', $page);
$page = empty($pager_page_array[$element]) ? 0 : $pager_page_array[$element];
$limit = variable_get('commitlog_pager', 10);
$branches = versioncontrol_get_branch_operations($constraints, $result_count, $page, $limit);
// Emulate pager_query() in order to get a proper theme('pager').
$pager_total_items[$element] = $result_count;
$pager_total[$element] = ceil($pager_total_items[$element] / $limit);
$pager_page_array[$element] = max(0, min((int)$pager_page_array[$element], ((int)$pager_total[$element]) - 1));
return $branches;
}
/**
* Return formatted output for displaying the given commits on an HTML page.
*
* @param $type
* Either 'branch' or 'tag'.
* @param $operations
* The branch or tag operations array that was retrieved by calling
* versioncontrol_get_{branch,tag}_operations().
* @param $attributes
* The request attributes, so that they can be incorporated
* into links on this page.
*/
function theme_commitlog_branches_tags_page($type, $branch_or_tag_ops, $attributes) {
if (empty($branch_or_tag_ops)) {
return ''.
(($type == 'branch')
? t('No branch messages found.') : t('No tag messages found.'))
.'
';
}
$output = '';
$initial = TRUE;
foreach ($branch_or_tag_ops as $branch_or_tag_op) {
$items = ($type == 'branch')
? versioncontrol_get_branched_items($branch_or_tag_op)
: versioncontrol_get_tagged_items($branch_or_tag_op);
$date = _commitlog_date($branch_or_tag_op['date']);
if (isset($date)) { // begin a new list for each day
if (!$initial) {
$output .= '';
}
$initial = FALSE;
$output .= "
$date
";
$output .= '
';
}
$output .= '- ';
$output .= commitlog_branch_or_tag_operation($type, $branch_or_tag_op, $items, NULL, 'html');
$output .= '
';
}
$output .= '
';
if ($pager = theme('pager', NULL, variable_get('commitlog_pager', 10), 0, $attributes)) {
$output .= $pager;
}
$output .= '
';
/*
$query_items = array();
foreach ($attributes as $key => $value) {
$query_items[] = $key .'='. $value;
}
$query = empty($query_items) ? NULL : implode('&', $query_items);
$output .= theme('feed_icon', url('commitlog/[branches-or-tags]/feed', $query));
*/
return $output;
}
function commitlog_branch_or_tag_operation($type, $op, $items, $username = NULL, $format = 'html') {
if (isset($username)) {
$variables['username'] = $username;
}
else {
$variables['username'] = commitlog_account_username(
$op['uid'], $op['username'], $op['repository'], TRUE, $format
);
}
if ($type == 'branch') {
$variables['name'] = l($op['branch_name'], 'commitlog', NULL, 'branches='. $op['branch_name']);
}
else {
$variables['name'] = $op['tag_name'];
}
$variables['repository_name'] = theme('commitlog_repository', $op['repository'], $format);
$variables['time'] = format_date($op['date'], 'custom', 'H:i');
$variables['action'] = $op['action'];
$variables['message'] = $op['message'];
$variables['items'] = $items;
$directory_item = versioncontrol_get_directory_item($op);
$variables['directory'] = theme('commitlog_item',
$op['repository'], $directory_item, $directory_item['path'], $format
);
if ($format == 'html') {
return theme('commitlog_branch_or_tag_html', $type, $variables);
}
return theme('commitlog_branch_or_tag_plaintext', $type, $variables);
}
function theme_commitlog_branch_or_tag_email_subject($type, $op, $items, $username) {
$params = array(
'!type' => ($type == 'branch') ? t('Branch') : t('Tag'),
'!name' => ($type == 'branch') ? $op['branch_name'] : $op['tag_name'],
'!directory' => $op['directory'],
);
// If the branch or tag has been assigned for the whole repository,
// it doesn't make sense to mention the directory.
if (empty($items)) {
return t('!type !name', $params);
}
return t('!type !name in !directory', $params);
}
function theme_commitlog_branch_or_tag_html($type, $variables) {
$action_text = theme('commitlog_branch_or_tag_action_message', $type, $variables, 'html');
$output = '';
$output .= '
';
$output .= t('In !repo, at !time:', array(
'!time' => $variables['time'],
'!repo' => $variables['repository_name'],
));
$output .= '
'. $action_text;
$output .= "
\n"; // class "title"
if (!empty($variables['message'])) { // only for tags and non-CVS version control systems
$output .= '
'. $variables['message'] .'
'."\n";
}
$output .= "
\n"; // class "commit"
return $output;
}
function theme_commitlog_branch_or_tag_plaintext($type, $variables) {
$action_text = theme('commitlog_branch_or_tag_action_message', $type, $variables, 'plaintext');
$output = t('In !repo, at !time:', array(
'!time' => $variables['time'],
'!repo' => $variables['repository_name'],
));
$output .= "\n". $action_text ."\n";
if (!empty($variables['message'])) { // only for tags and non-CVS version control systems
$output .= "\n". $variables['message'] ."\n";
}
return $output;
}
function theme_commitlog_branch_or_tag_action_message($type, $variables, $format) {
$params = array(
'!username' => $variables['username'],
'!name' => $variables['name'],
'!directory' => $variables['directory'],
'!type' => ($type == 'branch') ? t('Branch') : t('Tag'),
);
// If the branch or tag has been assigned for the whole repository,
// it doesn't make sense to mention the directory.
if (empty($variables['items'])) {
switch ($variables['action']) {
case VERSIONCONTROL_ACTION_ADDED:
return t('!type !name created by !username.', $params);
case VERSIONCONTROL_ACTION_MOVED:
return t('!type renamed to !name by !username.', $params);
case VERSIONCONTROL_ACTION_DELETED:
return t('!type !name by !username.', $params);
}
}
switch ($variables['action']) {
case VERSIONCONTROL_ACTION_ADDED:
return t('!type !name created by !username in !directory.', $params);
case VERSIONCONTROL_ACTION_MOVED:
return t('!type renamed to !name by !username in !directory.', $params);
case VERSIONCONTROL_ACTION_DELETED:
return t('!type !name by !username in !directory.', $params);
}
}