'repoview', 'title' => t('Repositories'), 'callback' => 'drupal_get_form', 'callback arguments' => array('repoview_selection_form'), 'access' => $browse_access, 'type' => MENU_SUGGESTED_ITEM, ); } else { $repositories = versioncontrol_get_repositories(); foreach ($repositories as $repo_id => $repository) { $supports_browsing = _repoview_repository_supports_browsing($repository); $items[] = array( 'path' => 'repoview/'. $repo_id, 'title' => t('@reponame', array('@reponame' => $repository['name'])), 'callback' => 'drupal_get_form', 'callback arguments' => array('repoview_browser_form', $repository), 'access' => $browse_access && $supports_browsing, 'type' => MENU_CALLBACK, ); } } return $items; } /** * Implementation of hook_perm(). */ function repoview_perm() { return array('browse version control repositories'); } /** * Function to determine if a VCS backend provides enough functionality * to support browsing. */ function _repoview_repository_supports_browsing($repository) { $vcs = $repository['vcs']; return versioncontrol_backend_implements($vcs, 'get_item') && versioncontrol_backend_implements($vcs, 'get_directory_contents') && versioncontrol_backend_implements($vcs, 'get_file_copy'); } /** * Return the URL for viewing a given item with repoview. */ function repoview_item_url($repository, $item) { return 'repoview/'. $repository['repo_id'] . drupal_urlencode($item['path']); } /** * Form callback for the "repoview" menu path. */ function repoview_selection_form() { $form = array(); $repositories = versioncontrol_get_repositories(); foreach ($repositories as $repo_id => $repository) { if (!_repoview_repository_supports_browsing($repository)) { unset($repositories[$repo_id]); } } if (empty($repositories)) { $form['empty'] = array( '#value' => '
'. t('No repositories available to browse.') .'
', ); return $form; } if (count($repositories) == 1) { $only_repo = reset($repositories); drupal_goto('repoview/'. $only_repo['repo_id']); } $header = array(''); $rows = array(); foreach ($repositories as $repo_id => $repository) { $rows[] = array(l($repository['name'], 'repoview/'. $repo_id)); } $form['table'] = array( '#value' => theme('table', $header, $rows), ); return $form; } /** * Form callback for the "repoview/$repo_id[/...]" menu path. */ function repoview_browser_form($repository) { $args = func_get_args(); array_shift($args); // shift away the repository, we're interested in the rest $path = '/'. join('/', $args); $item = versioncontrol_get_item($repository, $path); _repoview_breadcrumb($repository, $path); if (empty($item)) { drupal_set_title(check_plain(basename($path))); $form['empty'] = array( '#value' => ''. t('File or directory doesn\'t exist at this revision, or doesn\'t exist at all.') .'
', ); return $form; } drupal_set_title(_repoview_title($repository, $item)); drupal_add_css(drupal_get_path('module', 'repoview') .'/repoview.css'); if (versioncontrol_is_directory_item($item)) { return repoview_directory_contents_form($repository, $item); } return repoview_file_contents_form($repository, $item); } /** * Retrieve the title for the page showing the given item. The result of this * function is supposed to be passed to drupal_set_title() as is. */ function _repoview_title($repository, $item) { if ($item['path'] == '/') { return check_plain($repository['name']); } return check_plain(basename($item['path'])); } /** * Form callback for "repoview/$repo_id[/...]" if the path is a directory item. */ function repoview_directory_contents_form($repository, $dir_item) { $form = array(); $children = versioncontrol_get_directory_contents($repository, $dir_item); unset($children[$dir_item['path']]); $children = _repoview_item_listing_sort($children); $header = array(t('File'), t('Rev.'), t('Author'), t('Age'), t('Message')); $rows = array(); if ($dir_item['path'] != '/') { $parent_item = versioncontrol_get_parent_item($repository, $dir_item); $item_url = repoview_item_url($repository, $item); // First column: image. $image = theme('image', drupal_get_path('module', 'repoview') .'/icons/folder-parent.png'); $image_link = l($image, $item_url, array(), NULL, NULL, FALSE, TRUE /* $image is checked HTML */); $image = ' '; // Second column: directory name. $item_link = l(''. t('Parent directory') .'', $item_url, array(), NULL, NULL, FALSE, TRUE /* label is checked HTML */); // Rest of the columns (even easier). $rows[] = array( ''. t('Error accessing the file.') .'
', ); return $form; } // Retrieve the mimetype of the file - if possible, because that function is // deprecated and the fileinfo PECL extension seems not to be built into // PHP 5 at least. if (function_exists('mime_content_type')) { $mimetype = mime_content_type($filepath); } $is_text = $is_image = FALSE; if (isset($mimetype) && (strpos($mimetype, 'text/') !== FALSE)) { $is_text = TRUE; } if (isset($mimetype) && in_array($mimetype, array('image/png', 'image/jpeg', 'image/gif'))) { $is_image = TRUE; } // We don't want to show normal binary files, let's just transfer them as is. if ($force_download || (!$is_text /*&& !$is_image ...later */)) { // Also, make sure we delete the file even if file_transfer() exits. register_shutdown_function('_repoview_delete_file_copy', $filepath); // Transfer the file! $headers = array( 'Content-Type: '. mime_header_encode($mimetype), 'Content-Length: '. filesize($filepath), // Force file download and set the default target filename. 'Content-Disposition: attachment; filename="'. basename($file_item['path']) .'";', ); file_transfer($filepath, $headers); // exit(); -- called by file_transfer() } if ($is_text) { // Cool, it's a text file. Let's display it in a nice table with a row // for each line. (repoview.css makes sure it looks nice.) $lines = file($filepath); _repoview_delete_file_copy($filepath); $linecount = 1; $line_numbers = ''; $content = ''; $header = array(); $rows = array(); foreach ($lines as $line) { $rows[] = array( ''. $linecount .'', '
'. trim(check_plain($line), "\n\r") .'' ); ++$linecount; } $contents = theme('table', $header, $rows, $attributes); $contents = '