'Repositories', 'page callback' => 'drupal_get_form', 'page arguments' => array('repoview_selection_form'), 'access arguments' => array($browse_access), 'type' => MENU_SUGGESTED_ITEM, ); $items['repoview/%repoview_location'] = array( 'title callback' => 'repoview_location_title', 'title arguments' => array(1), 'page callback' => 'drupal_get_form', 'page arguments' => array('repoview_browser_form', 1), 'access arguments' => array($browse_access), 'load arguments' => array('%map', '%index'), 'type' => MENU_CALLBACK, ); return $items; } /** * Menu wildcard loader for a repository location ('%repoview_location') that * can be browsed with Repoview. Returns FALSE if the repository is not * browsable, but does not check if the item in the repository actually exists. * If the repository is browsable, this function returns an associative array * with keys 'repository' and 'path' filled in. Requires array('%map', '%index') * as load arguments so that the item path can be loaded correctly. */ function repoview_location_load($repo_id, $map_array, $index) { $repository = versioncontrol_repository_load($repo_id); if (!$repository || !_repoview_repository_supports_browsing($repository)) { return FALSE; } // Construct the path out of the trailing menu path arguments. $path = (count($map_array) > $index + 1) ? '/'. join('/', array_slice($map_array, $index + 1)) : '/'; return array('repository' => $repository, 'path' => $path); } /** * Title callback for a repository location loaded by repoview_location_load(). */ function repoview_location_title($location) { if ($location['path'] != '/') { return check_plain($location['repository']['name']); } return check_plain(basename($location['path'])); } /** * 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, 'export_file'); } /** * 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_state) { $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/%repoview_location[/...]' menu path. */ function repoview_browser_form($form_state, $location) { $repository = $location['repository']; $path = $location['path']; $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_add_css(drupal_get_path('module', 'repoview') .'/repoview.css'); if (versioncontrol_is_directory_item($item)) { return repoview_directory_contents_form($form_state, $repository, $item); } return repoview_file_contents_form($form_state, $repository, $item); } /** * Form callback for 'repoview/%repoview_location[/...]' * if the path is a directory item. */ function repoview_directory_contents_form($form_state, $repository, $dir_item) { $form = array(); $children = versioncontrol_get_directory_contents($repository, $dir_item); if (!isset($children)) { $form['empty'] = array( '#value' => ''. t('Unable to fetch directory contents.') .'
', ); return $form; } 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, $parent_item); // First column: image. $image = theme('image', drupal_get_path('module', 'repoview') .'/icons/folder-parent.png'); $image_link = l($image, $item_url, array('html' => TRUE)); $image = ' '; // Second column: directory name. $item_link = l(''. t('Parent directory') .'', $item_url, array('html' => TRUE)); // 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 = '