From 664e3eea912bb160e058695ba91ddc334705f7c4 Mon Sep 17 00:00:00 2001 From: Cam Findlay Date: Thu, 18 Dec 2014 09:41:13 +1300 Subject: [PATCH] ENHANCEMENT optional branch property to allow version aliases of development branches inside docsviewer. --- code/DocumentationManifest.php | 78 ++++++++++--------- code/controllers/DocumentationViewer.php | 99 +++++++++++++----------- code/models/DocumentationEntity.php | 60 +++++++++----- docs/en/configuration.md | 17 +++- 4 files changed, 151 insertions(+), 103 deletions(-) diff --git a/code/DocumentationManifest.php b/code/DocumentationManifest.php index 86c7177..fd53195 100644 --- a/code/DocumentationManifest.php +++ b/code/DocumentationManifest.php @@ -3,7 +3,7 @@ /** * A class which builds a manifest of all documentation present in a project. * - * The manifest is required to map the provided documentation URL rules to a + * The manifest is required to map the provided documentation URL rules to a * file path on the server. The stored cache looks similar to the following: * * @@ -92,7 +92,7 @@ class DocumentationManifest { /** * Sets up the top level entities. * - * Either manually registered through the YAML syntax or automatically + * Either manually registered through the YAML syntax or automatically * loaded through investigating the file system for `docs` folder. */ public function setupEntities() { @@ -128,11 +128,13 @@ class DocumentationManifest { $version = (isset($details['Version'])) ? $details['Version'] : ''; + $branch = (isset($details['Branch'])) ? $details['Branch'] : ''; + $langs = scandir($path); - + if($langs) { $possible = i18n::get_common_languages(true); - + foreach($langs as $k => $lang) { if(isset($possible[$lang])) { $entity = Injector::inst()->create( @@ -143,6 +145,7 @@ class DocumentationManifest { $entity->setTitle($details['Title']); $entity->setLanguage($lang); $entity->setVersion($version); + $entity->setBranch($branch); if(isset($details['Stable'])) { $entity->setIsStable($details['Stable']); @@ -192,7 +195,7 @@ class DocumentationManifest { } $dir = Controller::join_links(BASE_PATH, $entity); - + if(is_dir($dir)) { // check to see if it has docs $docs = Controller::join_links($dir, 'docs'); @@ -202,6 +205,7 @@ class DocumentationManifest { 'Path' => $docs, 'Title' => DocumentationHelper::clean_page_name($entity), 'Version' => 'master', + 'Branch' => 'master', 'Stable' => true ); } @@ -242,7 +246,7 @@ class DocumentationManifest { } /** - * Returns a particular page for the requested URL. + * Returns a particular page for the requested URL. * * @return DocumentationPage */ @@ -260,7 +264,7 @@ class DocumentationManifest { foreach($this->getEntities() as $entity) { if(strpos($record['filepath'], $entity->getPath()) !== false) { $page = Injector::inst()->create( - $record['type'], + $record['type'], $entity, $record['basename'], $record['filepath'] @@ -285,11 +289,11 @@ class DocumentationManifest { foreach($this->getEntities() as $entity) { $this->entity = $entity; - + $this->handleFolder('', $this->entity->getPath(), 0); $finder->find($this->entity->getPath()); } - + // groupds $grouped = array(); @@ -316,7 +320,7 @@ class DocumentationManifest { if ($a['filepath'] == $b['filepath']) { return 0; } - + return ($a['filepath'] < $b['filepath']) ? -1 : 1; }); @@ -339,8 +343,8 @@ class DocumentationManifest { ); $link = ltrim(str_replace( - Config::inst()->get('DocumentationViewer', 'link_base'), - '', + Config::inst()->get('DocumentationViewer', 'link_base'), + '', $folder->Link() ), '/'); @@ -355,9 +359,9 @@ class DocumentationManifest { } /** - * Individual files can optionally provide a nice title and a better URL - * through the use of markdown meta data. This creates a new - * {@link DocumentationPage} instance for the file. + * Individual files can optionally provide a nice title and a better URL + * through the use of markdown meta data. This creates a new + * {@link DocumentationPage} instance for the file. * * If the markdown does not specify the title in the meta data it falls back * to using the file name. @@ -368,7 +372,7 @@ class DocumentationManifest { */ public function handleFile($basename, $path, $depth) { $page = Injector::inst()->create( - 'DocumentationPage', + 'DocumentationPage', $this->entity, $basename, $path ); @@ -376,11 +380,11 @@ class DocumentationManifest { $page->getMarkdown(); $link = ltrim(str_replace( - Config::inst()->get('DocumentationViewer', 'link_base'), - '', + Config::inst()->get('DocumentationViewer', 'link_base'), + '', $page->Link() ), '/'); - + $this->pages[$link] = array( 'title' => $page->getTitle(), 'filepath' => $path, @@ -403,7 +407,7 @@ class DocumentationManifest { $output = new ArrayList(); $parts = explode('/', trim($record->getRelativeLink(), '/')); - + // Add the base link. $output->push(new ArrayData(array( 'Link' => $base->Link(), @@ -429,7 +433,7 @@ class DocumentationManifest { /** * Determine the next page from the given page. * - * Relies on the fact when the manifest was built, it was generated in + * Relies on the fact when the manifest was built, it was generated in * order. * * @param string $filepath @@ -470,7 +474,7 @@ class DocumentationManifest { /** * Determine the previous page from the given page. * - * Relies on the fact when the manifest was built, it was generated in + * Relies on the fact when the manifest was built, it was generated in * order. * * @param string $filepath @@ -508,7 +512,7 @@ class DocumentationManifest { public function normalizeUrl($url) { $url = trim($url, '/') .'/'; - // if the page is the index page then hide it from the menu + // if the page is the index page then hide it from the menu if(strpos(strtolower($url), '/index.md/')) { $url = substr($url, 0, strpos($url, "index.md/")); } @@ -529,12 +533,12 @@ class DocumentationManifest { if(!$recordPath) { $recordPath = $entityPath; } - + $output = new ArrayList(); $base = Config::inst()->get('DocumentationViewer', 'link_base'); $entityPath = $this->normalizeUrl($entityPath); $recordPath = $this->normalizeUrl($recordPath); - $recordParts = explode(DIRECTORY_SEPARATOR, trim($recordPath,'/')); + $recordParts = explode(DIRECTORY_SEPARATOR, trim($recordPath,'/')); $currentRecordPath = end($recordParts); $depth = substr_count($entityPath, '/'); @@ -548,18 +552,18 @@ class DocumentationManifest { // only pull it up if it's one more level depth if(substr_count($pagePath, DIRECTORY_SEPARATOR) == ($depth + 1)) { - $pagePathParts = explode(DIRECTORY_SEPARATOR, trim($pagePath,'/')); + $pagePathParts = explode(DIRECTORY_SEPARATOR, trim($pagePath,'/')); $currentPagePath = end($pagePathParts); - if($currentPagePath == $currentRecordPath) { + if($currentPagePath == $currentRecordPath) { $mode = 'current'; } - else if(strpos($recordPath, $pagePath) !== false) { + else if(strpos($recordPath, $pagePath) !== false) { $mode = 'section'; } else { $mode = 'link'; } - + $children = new ArrayList(); if($mode == 'section' || $mode == 'current') { @@ -583,7 +587,7 @@ class DocumentationManifest { * @param DocumentationEntity * * @return ArrayList - */ + */ public function getAllVersionsOfEntity(DocumentationEntity $entity) { $all = new ArrayList(); @@ -602,7 +606,7 @@ class DocumentationManifest { * @param DocumentationEntity * * @return DocumentationEntity - */ + */ public function getStableVersion(DocumentationEntity $entity) { foreach($this->getEntities() as $check) { if($check->getKey() == $entity->getKey()) { @@ -621,19 +625,19 @@ class DocumentationManifest { * @param DocumentationEntity * * @return ArrayList - */ + */ public function getVersions($entity) { if(!$entity) { return null; } - + $output = new ArrayList(); foreach($this->getEntities() as $check) { if($check->getKey() == $entity->getKey()) { if($check->getLanguage() == $entity->getLanguage()) { $same = ($check->getVersion() == $entity->getVersion()); - + $output->push(new ArrayData(array( 'Title' => $check->getVersion(), 'Link' => $check->Link(), @@ -652,7 +656,7 @@ class DocumentationManifest { */ public function getAllVersions() { $versions = array(); - + foreach($this->getEntities() as $entity) { if($entity->getVersion()) { $versions[$entity->getVersion()] = $entity->getVersion(); @@ -660,9 +664,9 @@ class DocumentationManifest { $versions['0.0'] = _t('DocumentationManifest.MASTER', 'Master'); } } - + asort($versions); - + return $versions; } } diff --git a/code/controllers/DocumentationViewer.php b/code/controllers/DocumentationViewer.php index 6465987..91a156b 100755 --- a/code/controllers/DocumentationViewer.php +++ b/code/controllers/DocumentationViewer.php @@ -3,7 +3,7 @@ /** * Documentation Viewer. * - * Reads the bundled markdown files from documentation folders and displays the + * Reads the bundled markdown files from documentation folders and displays the * output (either via markdown or plain text). * * For more documentation on how to use this class see the documentation in the @@ -31,7 +31,7 @@ class DocumentationViewer extends Controller { * @var string */ private static $documentation_title = 'SilverStripe Documentation'; - + /** * @var array */ @@ -65,7 +65,7 @@ class DocumentationViewer extends Controller { * @var string same as the routing pattern set through Director::addRules(). */ private static $link_base = 'dev/docs/'; - + /** * @config * @@ -91,9 +91,9 @@ class DocumentationViewer extends Controller { Requirements::javascript('//use.typekit.net/emt4dhq.js'); Requirements::customScript('try{Typekit.load();}catch(e){}'); - Requirements::javascript(THIRDPARTY_DIR .'/jquery/jquery.js'); + Requirements::javascript(THIRDPARTY_DIR .'/jquery/jquery.js'); Requirements::javascript('https://google-code-prettify.googlecode.com/svn/loader/run_prettify.js'); - + Requirements::javascript(DOCSVIEWER_DIR .'/javascript/DocumentationViewer.js'); Requirements::combine_files('docs.css', array( DOCSVIEWER_DIR .'/css/normalize.css', @@ -104,16 +104,16 @@ class DocumentationViewer extends Controller { DOCSVIEWER_DIR .'/css/small.css' )); } - + /** - * Can the user view this documentation. Hides all functionality for private + * Can the user view this documentation. Hides all functionality for private * wikis. * * @return bool */ public function canView() { - return (Director::isDev() || Director::is_cli() || - !$this->config()->get('check_permission') || + return (Director::isDev() || Director::is_cli() || + !$this->config()->get('check_permission') || Permission::check($this->config()->get('check_permission')) ); } @@ -127,8 +127,8 @@ class DocumentationViewer extends Controller { } /** - * Overloaded to avoid "action doesn't exist" errors - all URL parts in - * this controller are virtual and handled through handleRequest(), not + * Overloaded to avoid "action doesn't exist" errors - all URL parts in + * this controller are virtual and handled through handleRequest(), not * controller methods. * * @param $request @@ -145,20 +145,20 @@ class DocumentationViewer extends Controller { $url = $request->getURL(); // - // If the current request has an extension attached to it, strip that + // If the current request has an extension attached to it, strip that // off and redirect the user to the page without an extension. // if(DocumentationHelper::get_extension($url)) { $this->response = new SS_HTTPResponse(); $this->response->redirect( - DocumentationHelper::trim_extension_off($url) .'/', + DocumentationHelper::trim_extension_off($url) .'/', 301 ); $request->shift(); $request->shift(); - return $this->response; + return $this->response; } // @@ -170,22 +170,22 @@ class DocumentationViewer extends Controller { if($base && strpos($url, $base) !== false) { $url = substr( - ltrim($url, '/'), + ltrim($url, '/'), strlen($base) ); } else { } - + // // Handle any permanent redirections that the developer has defined. - // + // if($link = DocumentationPermalinks::map($url)) { // the first param is a shortcode for a page so redirect the user to // the short code. $this->response = new SS_HTTPResponse(); $this->response->redirect($link, 301); - + $request->shift(); $request->shift(); @@ -194,7 +194,7 @@ class DocumentationViewer extends Controller { // // Validate the language provided. Language is a required URL parameter. - // as we use it for generic interfaces and language selection. If + // as we use it for generic interfaces and language selection. If // language is not set, redirects to 'en' // $languages = i18n::get_common_languages(); @@ -245,7 +245,7 @@ class DocumentationViewer extends Controller { "DocumentationViewer_{$type}", "DocumentationViewer" )); - + return new SS_HTTPResponse($body, 200); } else if(!$url || $url == $lang) { $body = $this->renderWith(array( @@ -268,7 +268,7 @@ class DocumentationViewer extends Controller { */ public function httpError($status, $message = null) { $this->init(); - + $class = get_class($this); $body = $this->customise(new ArrayData(array( 'Message' => $message @@ -283,7 +283,7 @@ class DocumentationViewer extends Controller { public function getManifest() { if(!$this->manifest) { $flush = SapphireTest::is_running_test() || (isset($_GET['flush'])); - + $this->manifest = new DocumentationManifest($flush); } @@ -304,11 +304,11 @@ class DocumentationViewer extends Controller { /** - * Generate a list of {@link Documentation } which have been registered and which can - * be documented. + * Generate a list of {@link Documentation } which have been registered and which can + * be documented. * * @return DataObject - */ + */ public function getMenu() { $entities = $this->getManifest()->getEntities(); $output = new ArrayList(); @@ -319,25 +319,25 @@ class DocumentationViewer extends Controller { $checkLang = $entity->getLanguage(); $checkVers = $entity->getVersion(); - // only show entities with the same language or any entity that + // only show entities with the same language or any entity that // isn't registered under any particular language (auto detected) if($checkLang && $checkLang !== $this->getLanguage()) { continue; } - + if($current && $checkVers) { if($entity->getVersion() !== $current->getVersion()) { continue; } } - $mode = 'link'; + $mode = 'link'; $children = new ArrayList(); if($entity->hasRecord($record) || $entity->getIsDefaultEntity()) { $mode = 'current'; - // add children + // add children $children = $this->getManifest()->getChildrenFor( $entity->getPath(), ($record) ? $record->getPath() : $entity->getPath() ); @@ -360,7 +360,7 @@ class DocumentationViewer extends Controller { return $output; } - + /** * Return the content for the page. If its an actual documentation page then * display the content from the page, otherwise display the contents from @@ -430,7 +430,7 @@ class DocumentationViewer extends Controller { return new ArrayList(); } - + /** * Generate a list of breadcrumbs for the user. * @@ -474,7 +474,7 @@ class DocumentationViewer extends Controller { public function getTitle() { return ($this->record) ? $this->record->getTitle() : null; } - + /** * @return string */ @@ -502,7 +502,7 @@ class DocumentationViewer extends Controller { } /** - * Generate a list of all the pages in the documentation grouped by the + * Generate a list of all the pages in the documentation grouped by the * first letter of the page. * * @return GroupedList @@ -525,7 +525,7 @@ class DocumentationViewer extends Controller { return GroupedList::create($output->sort('Title', 'ASC')); } - + /** * Documentation Search Form. Allows filtering of the results by many entities * and multiple versions. @@ -536,13 +536,13 @@ class DocumentationViewer extends Controller { if(!Config::inst()->get('DocumentationSearch','enabled')) { return false; } - + return new DocumentationSearchForm($this); } /** * Sets the mapping between a entity name and the link for the end user - * to jump into editing the documentation. + * to jump into editing the documentation. * * Some variables are replaced: * - %version% @@ -554,7 +554,7 @@ class DocumentationViewer extends Controller { * * * DocumentationViewer::set_edit_link( - * 'framework', + * 'framework', * 'https://github.com/silverstripe/%entity%/edit/%version%/docs/%lang%/%path%', * $opts * )); @@ -592,6 +592,11 @@ class DocumentationViewer extends Controller { $url = self::$edit_links[strtolower($entity->title)]; $version = $entity->getVersion(); + if($entity->getBranch()){ + $version = $entity->getBranch(); + } + + if($version == "trunk" && (isset($url['options']['rewritetrunktomaster']))) { if($url['options']['rewritetrunktomaster']) { $version = "master"; @@ -601,9 +606,9 @@ class DocumentationViewer extends Controller { return str_replace( array('%entity%', '%lang%', '%version%', '%path%'), array( - $entity->title, - $this->getLanguage(), - $version, + $entity->title, + $this->getLanguage(), + $version, ltrim($page->getRelativePath(), '/') ), @@ -624,25 +629,25 @@ class DocumentationViewer extends Controller { * @return DocumentationPage */ public function getNextPage() { - return ($this->record) + return ($this->record) ? $this->getManifest()->getNextPage( - $this->record->getPath(), $this->getEntity()->getPath()) + $this->record->getPath(), $this->getEntity()->getPath()) : null; - } + } /** - * Returns the previous page. Either returns the previous sibling or the + * Returns the previous page. Either returns the previous sibling or the * parent of this page * * @return DocumentationPage */ public function getPreviousPage() { - return ($this->record) + return ($this->record) ? $this->getManifest()->getPreviousPage( - $this->record->getPath(), $this->getEntity()->getPath()) + $this->record->getPath(), $this->getEntity()->getPath()) : null; } - + /** * @return string */ diff --git a/code/models/DocumentationEntity.php b/code/models/DocumentationEntity.php index a511f3a..d905e04 100755 --- a/code/models/DocumentationEntity.php +++ b/code/models/DocumentationEntity.php @@ -2,25 +2,25 @@ /** * A {@link DocumentationEntity} represents a module or folder with stored - * documentation files. An entity not an individual page but a `section` of + * documentation files. An entity not an individual page but a `section` of * documentation arranged by version and language. * - * Each entity has a version assigned to it (i.e master) and folders can be + * Each entity has a version assigned to it (i.e master) and folders can be * labeled with a specific version. For instance, doc.silverstripe.org has three * DocumentEntities for Framework - versions 2.4, 3.0 and 3.1. In addition an * entity can have a language attached to it. So for an instance with en, de and * fr documentation you may have three {@link DocumentationEntities} registered. - * - * + * + * * @package docsviewer * @subpackage models */ class DocumentationEntity extends ViewableData { - + /** * The key to match entities with that is not localized. For instance, you - * may have three entities (en, de, fr) that you want to display a nice + * may have three entities (en, de, fr) that you want to display a nice * title for, but matching needs to occur on a specific key. * * @var string $key @@ -28,7 +28,7 @@ class DocumentationEntity extends ViewableData { protected $key; /** - * The human readable title of this entity. Set when the module is + * The human readable title of this entity. Set when the module is * registered. * * @var string $title @@ -36,7 +36,7 @@ class DocumentationEntity extends ViewableData { protected $title; /** - * If the system is setup to only document one entity then you may only + * If the system is setup to only document one entity then you may only * want to show a single entity in the URL and the sidebar. Set this when * you register the entity with the key `DefaultEntity` and the URL will * not include any version or language information. @@ -57,7 +57,14 @@ class DocumentationEntity extends ViewableData { protected $version; /** - * If this entity is a stable release or not. If it is not stable (i.e it + * The repository branch name (allows for $version to be an alias on development branches). + * + * @var string $branch + */ + protected $branch; + + /** + * If this entity is a stable release or not. If it is not stable (i.e it * could be a past or future release) then a warning message will be shown. * * @var boolean $stable @@ -70,12 +77,12 @@ class DocumentationEntity extends ViewableData { protected $language; /** - * + * */ public function __construct($key) { $this->key = DocumentationHelper::clean_page_url($key); } - + /** * Get the title of this module. @@ -103,7 +110,7 @@ class DocumentationEntity extends ViewableData { /** * Returns the web accessible link to this entity. * - * Includes the version information + * Includes the version information * * @return string */ @@ -116,7 +123,7 @@ class DocumentationEntity extends ViewableData { ); } else { $base = Controller::join_links( - Config::inst()->get('DocumentationViewer', 'link_base'), + Config::inst()->get('DocumentationViewer', 'link_base'), $this->getLanguage(), $this->getKey(), '/' @@ -130,12 +137,12 @@ class DocumentationEntity extends ViewableData { } return Controller::join_links( - $base, + $base, $this->getVersion(), '/' ); } - + /** * @return string */ @@ -213,6 +220,22 @@ class DocumentationEntity extends ViewableData { return $this->version; } + /** + * @param string + */ + public function setBranch($branch) { + $this->branch = $branch; + + return $this; + } + + /** + * @return float + */ + public function getBranch() { + return $this->branch; + } + /** * @return string */ @@ -250,8 +273,8 @@ class DocumentationEntity extends ViewableData { /** - * Returns an integer value based on if a given version is the latest - * version. Will return -1 for if the version is older, 0 if versions are + * Returns an integer value based on if a given version is the latest + * version. Will return -1 for if the version is older, 0 if versions are * the same and 1 if the version is greater than. * * @param string $version @@ -269,8 +292,9 @@ class DocumentationEntity extends ViewableData { 'Key' => $this->key, 'Path' => $this->getPath(), 'Version' => $this->getVersion(), + 'Branch' => $this->getBranch(), 'IsStable' => $this->getIsStable(), 'Language' => $this->getLanguage() ); } -} \ No newline at end of file +} diff --git a/docs/en/configuration.md b/docs/en/configuration.md index 5bc9a66..4ecee2f 100755 --- a/docs/en/configuration.md +++ b/docs/en/configuration.md @@ -25,6 +25,21 @@ In YAML this looks like: Path: "framework/docs/" Title: "Framework Documentation" +###Branch aliases for the edit link (optional) +When using entities with multiple versions, one of the branches of documentation may be a development version. For example the 'master' branch. You may have an internally assigned version number for this registered in your .yml configuration. + +If this version number is not the same as the branch name on the git repository the `getEditLinks` method will return an incorrect link to go and edit the documentation. In this case you can simply set an optional `branch` property on the entity which will be used in the edit link instead. + +Example: + + :::yml + DocumentationManifest: + register_entities: + - + Path: "framework/docs/" + Title: "Framework Documentation" + Version: "1.0" + Branch: "master" ## Permalinks @@ -92,4 +107,4 @@ headers you use. ## Images and Files If you want to attach images and other assets to a page you need to bundle those -in a directory called _images at the same level as your documentation. \ No newline at end of file +in a directory called _images at the same level as your documentation.