Index: trunk/extensions/Deployment/specials/SpecialExtensions.php |
— | — | @@ -21,12 +21,233 @@ |
22 | 22 | */ |
23 | 23 | class SpecialExtensions extends SpecialPage { |
24 | 24 | |
| 25 | + protected $firstExtOpened = true; |
| 26 | + |
| 27 | + protected static $viewvcUrls = array( |
| 28 | + 'svn+ssh://svn.wikimedia.org/svnroot/mediawiki' => 'http://svn.wikimedia.org/viewvc/mediawiki', |
| 29 | + 'http://svn.wikimedia.org/svnroot/mediawiki' => 'http://svn.wikimedia.org/viewvc/mediawiki', |
| 30 | + # Doesn't work at the time of writing but maybe some day: |
| 31 | + 'https://svn.wikimedia.org/viewvc/mediawiki' => 'http://svn.wikimedia.org/viewvc/mediawiki', |
| 32 | + ); |
| 33 | + |
25 | 34 | public function __construct() { |
26 | 35 | parent::__construct( 'Extensions' ); |
27 | 36 | } |
28 | 37 | |
29 | 38 | public function execute( $arg ) { |
| 39 | + global $wgOut; |
| 40 | + $wgOut->addWikiText( $this->getExtensionList() ); |
| 41 | + } |
| 42 | + |
| 43 | + protected function getExtensionList() { |
| 44 | + global $wgExtensionCredits; |
30 | 45 | |
| 46 | + $out = Xml::element( 'h2', array( 'id' => 'mw-version-ext' ), wfMsg( 'version-extensions' ) ) . |
| 47 | + Xml::openElement( 'table', array( 'class' => 'wikitable', 'id' => 'sv-ext' ) ); |
| 48 | + |
| 49 | + foreach ( $wgExtensionCredits as $type => $extensions ) { |
| 50 | + if ( count( $wgExtensionCredits[$type] ) > 0 ) { |
| 51 | + $out .= $this->getExtensionTypeHeader( $type, 'credits-' . $type ); |
| 52 | + |
| 53 | + usort( $wgExtensionCredits[$type], array( $this, 'compare' ) ); |
| 54 | + |
| 55 | + foreach ( $wgExtensionCredits[$type] as $extension ) { |
| 56 | + $out .= $this->getExtensionForList( $extension ); |
| 57 | + } |
| 58 | + } |
| 59 | + } |
| 60 | + |
| 61 | + return $out; |
31 | 62 | } |
32 | 63 | |
| 64 | + protected function getExtensionTypeHeader( $text, $name ) { |
| 65 | + $opt = array( 'colspan' => 4 ); |
| 66 | + $out = ''; |
| 67 | + |
| 68 | + if( !$this->firstExtOpened ) { |
| 69 | + // Insert a spacing line |
| 70 | + $out .= '<tr class="sv-space">' . Html::element( 'td', $opt ) . "</tr>\n"; |
| 71 | + $this->firstExtOpened = true; |
| 72 | + } |
| 73 | + |
| 74 | + if( $name ) { |
| 75 | + $opt['id'] = "sv-$name"; |
| 76 | + } |
| 77 | + |
| 78 | + $out .= "<tr>" . Xml::element( 'th', $opt, $text ) . "</tr>\n"; |
| 79 | + return $out; |
| 80 | + } |
| 81 | + |
| 82 | + protected function getExtensionForList( array $extension ) { |
| 83 | + global $wgLang; |
| 84 | + |
| 85 | + $name = isset( $extension['name'] ) ? $extension['name'] : '[no name]'; |
| 86 | + |
| 87 | + if ( isset( $extension['path'] ) ) { |
| 88 | + $svnInfo = self::getSvnInfo( dirname($extension['path']) ); |
| 89 | + $directoryRev = isset( $svnInfo['directory-rev'] ) ? $svnInfo['directory-rev'] : null; |
| 90 | + $checkoutRev = isset( $svnInfo['checkout-rev'] ) ? $svnInfo['checkout-rev'] : null; |
| 91 | + $viewvcUrl = isset( $svnInfo['viewvc-url'] ) ? $svnInfo['viewvc-url'] : null; |
| 92 | + } else { |
| 93 | + $directoryRev = null; |
| 94 | + $checkoutRev = null; |
| 95 | + $viewvcUrl = null; |
| 96 | + } |
| 97 | + |
| 98 | + # Make main link (or just the name if there is no URL). |
| 99 | + if ( isset( $extension['url'] ) ) { |
| 100 | + $mainLink = "[{$extension['url']} $name]"; |
| 101 | + } else { |
| 102 | + $mainLink = $name; |
| 103 | + } |
| 104 | + |
| 105 | + if ( isset( $extension['version'] ) ) { |
| 106 | + $versionText = '<span class="mw-version-ext-version">' . |
| 107 | + wfMsg( 'version-version', $extension['version'] ) . |
| 108 | + '</span>'; |
| 109 | + } else { |
| 110 | + $versionText = ''; |
| 111 | + } |
| 112 | + |
| 113 | + # Make subversion text/link. |
| 114 | + if ( $checkoutRev ) { |
| 115 | + $svnText = wfMsg( 'version-svn-revision', $directoryRev, $checkoutRev ); |
| 116 | + $svnText = isset( $viewvcUrl ) ? "[$viewvcUrl $svnText]" : $svnText; |
| 117 | + } else { |
| 118 | + $svnText = false; |
| 119 | + } |
| 120 | + |
| 121 | + # Make description text. |
| 122 | + $description = isset ( $extension['description'] ) ? $extension['description'] : ''; |
| 123 | + |
| 124 | + if( isset ( $extension['descriptionmsg'] ) ) { |
| 125 | + # Look for a localized description. |
| 126 | + $descriptionMsg = $extension['descriptionmsg']; |
| 127 | + |
| 128 | + if( is_array( $descriptionMsg ) ) { |
| 129 | + $descriptionMsgKey = $descriptionMsg[0]; // Get the message key |
| 130 | + array_shift( $descriptionMsg ); // Shift out the message key to get the parameters only |
| 131 | + array_map( "htmlspecialchars", $descriptionMsg ); // For sanity |
| 132 | + $msg = wfMsg( $descriptionMsgKey, $descriptionMsg ); |
| 133 | + } else { |
| 134 | + $msg = wfMsg( $descriptionMsg ); |
| 135 | + } |
| 136 | + if ( !wfEmptyMsg( $descriptionMsg, $msg ) && $msg != '' ) { |
| 137 | + $description = $msg; |
| 138 | + } |
| 139 | + } |
| 140 | + |
| 141 | + if ( $svnText !== false ) { |
| 142 | + $extNameVer = "<tr> |
| 143 | + <td><em>$mainLink $versionText</em></td> |
| 144 | + <td><em>$svnText</em></td>"; |
| 145 | + } else { |
| 146 | + $extNameVer = "<tr> |
| 147 | + <td colspan=\"2\"><em>$mainLink $versionText</em></td>"; |
| 148 | + } |
| 149 | + |
| 150 | + $author = isset ( $extension['author'] ) ? $extension['author'] : array(); |
| 151 | + $extDescAuthor = "<td>$description</td> |
| 152 | + <td>" . $wgLang->listToText( (array)$author ) . "</td> |
| 153 | + </tr>\n"; |
| 154 | + |
| 155 | + return $extNameVer . $extDescAuthor; |
| 156 | + } |
| 157 | + |
| 158 | + /** |
| 159 | + * Callback to sort extensions by type. |
| 160 | + */ |
| 161 | + public function compare( $a, $b ) { |
| 162 | + global $wgLang; |
| 163 | + if( $a['name'] === $b['name'] ) { |
| 164 | + return 0; |
| 165 | + } else { |
| 166 | + return $wgLang->lc( $a['name'] ) > $wgLang->lc( $b['name'] ) |
| 167 | + ? 1 |
| 168 | + : -1; |
| 169 | + } |
| 170 | + } |
| 171 | + |
| 172 | + /** |
| 173 | + * Get an associative array of information about a given path, from its .svn |
| 174 | + * subdirectory. Returns false on error, such as if the directory was not |
| 175 | + * checked out with subversion. |
| 176 | + * |
| 177 | + * Returned keys are: |
| 178 | + * Required: |
| 179 | + * checkout-rev The revision which was checked out |
| 180 | + * Optional: |
| 181 | + * directory-rev The revision when the directory was last modified |
| 182 | + * url The subversion URL of the directory |
| 183 | + * repo-url The base URL of the repository |
| 184 | + * viewvc-url A ViewVC URL pointing to the checked-out revision |
| 185 | + */ |
| 186 | + public static function getSvnInfo( $dir ) { |
| 187 | + // http://svnbook.red-bean.com/nightly/en/svn.developer.insidewc.html |
| 188 | + $entries = $dir . '/.svn/entries'; |
| 189 | + |
| 190 | + if( !file_exists( $entries ) ) { |
| 191 | + return false; |
| 192 | + } |
| 193 | + |
| 194 | + $lines = file( $entries ); |
| 195 | + if ( !count( $lines ) ) { |
| 196 | + return false; |
| 197 | + } |
| 198 | + |
| 199 | + // check if file is xml (subversion release <= 1.3) or not (subversion release = 1.4) |
| 200 | + if( preg_match( '/^<\?xml/', $lines[0] ) ) { |
| 201 | + // subversion is release <= 1.3 |
| 202 | + if( !function_exists( 'simplexml_load_file' ) ) { |
| 203 | + // We could fall back to expat... YUCK |
| 204 | + return false; |
| 205 | + } |
| 206 | + |
| 207 | + // SimpleXml whines about the xmlns... |
| 208 | + wfSuppressWarnings(); |
| 209 | + $xml = simplexml_load_file( $entries ); |
| 210 | + wfRestoreWarnings(); |
| 211 | + |
| 212 | + if( $xml ) { |
| 213 | + foreach( $xml->entry as $entry ) { |
| 214 | + if( $xml->entry[0]['name'] == '' ) { |
| 215 | + // The directory entry should always have a revision marker. |
| 216 | + if( $entry['revision'] ) { |
| 217 | + return array( 'checkout-rev' => intval( $entry['revision'] ) ); |
| 218 | + } |
| 219 | + } |
| 220 | + } |
| 221 | + } |
| 222 | + |
| 223 | + return false; |
| 224 | + } |
| 225 | + |
| 226 | + // Subversion is release 1.4 or above. |
| 227 | + if ( count( $lines ) < 11 ) { |
| 228 | + return false; |
| 229 | + } |
| 230 | + |
| 231 | + $info = array( |
| 232 | + 'checkout-rev' => intval( trim( $lines[3] ) ), |
| 233 | + 'url' => trim( $lines[4] ), |
| 234 | + 'repo-url' => trim( $lines[5] ), |
| 235 | + 'directory-rev' => intval( trim( $lines[10] ) ) |
| 236 | + ); |
| 237 | + |
| 238 | + if ( isset( self::$viewvcUrls[$info['repo-url']] ) ) { |
| 239 | + $viewvc = str_replace( |
| 240 | + $info['repo-url'], |
| 241 | + self::$viewvcUrls[$info['repo-url']], |
| 242 | + $info['url'] |
| 243 | + ); |
| 244 | + |
| 245 | + $pathRelativeToRepo = substr( $info['url'], strlen( $info['repo-url'] ) ); |
| 246 | + $viewvc .= '/?pathrev='; |
| 247 | + $viewvc .= urlencode( $info['checkout-rev'] ); |
| 248 | + $info['viewvc-url'] = $viewvc; |
| 249 | + } |
| 250 | + |
| 251 | + return $info; |
| 252 | + } |
| 253 | + |
33 | 254 | } |
\ No newline at end of file |
Index: trunk/extensions/Deployment/Deployment.i18n.php |
— | — | @@ -18,7 +18,12 @@ |
19 | 19 | // General |
20 | 20 | 'deployment-desc' => 'Provides a way to install extensions via GUI and update them and the wiki itself via another GUI', |
21 | 21 | |
22 | | - // Filesystem: Direct |
| 22 | + // Special pages |
| 23 | + 'specialpages-group-administration' => 'Wiki administration', |
| 24 | + 'dashboard' => 'Administration dashboard', |
| 25 | + 'extensions' => 'Manage extensions', |
| 26 | + 'update' => 'Update wiki and extensions', |
| 27 | + 'install' => 'Install extensions', |
23 | 28 | |
24 | 29 | // Filesystem: FTP |
25 | 30 | 'deploy-ftp-not-loaded' => 'The FTP PHP extension is not available', |
— | — | @@ -38,5 +43,4 @@ |
39 | 44 | 'deploy-ssh2-key-authentication-failed' => 'Public and private keys are incorrect for username $1', |
40 | 45 | 'deploy-ssh2-password-authentication-failed' => 'Username or password incorrect for username $1', |
41 | 46 | 'deploy-ssh2-command-failed' => 'Unable to perform command: $1', |
42 | | - |
43 | 47 | ); |
Index: trunk/extensions/Deployment/Deployment.php |
— | — | @@ -14,7 +14,7 @@ |
15 | 15 | die( 'Not an entry point.' ); |
16 | 16 | } |
17 | 17 | |
18 | | -define( 'Deployment_VERSION', '0.0.0' ); |
| 18 | +define( 'Deployment_VERSION', '0.1 alpha' ); |
19 | 19 | |
20 | 20 | // Register the initialization function. |
21 | 21 | $wgExtensionFunctions[] = 'efDeploymentSetup'; |
— | — | @@ -22,6 +22,27 @@ |
23 | 23 | // Register the internationalization file. |
24 | 24 | $wgExtensionMessagesFiles['Deployment'] = dirname( __FILE__ ) . '/Deployment.i18n.php'; |
25 | 25 | |
| 26 | +// Load and register Special:Dashboard. |
| 27 | +$wgAutoloadClasses['SpecialDashboard'] = dirname( __FILE__ ) . '/specials/SpecialDashboard.php'; |
| 28 | +$wgSpecialPages['Dashboard'] = 'SpecialDashboard'; |
| 29 | +$wgSpecialPageGroups['Dashboard'] = 'administration'; |
| 30 | + |
| 31 | +// Load and register Special:Extensions. |
| 32 | +$wgAutoloadClasses['SpecialExtensions'] = dirname( __FILE__ ) . '/specials/SpecialExtensions.php'; |
| 33 | +$wgSpecialPages['Extensions'] = 'SpecialExtensions'; |
| 34 | +$wgSpecialPageGroups['Extensions'] = 'administration'; |
| 35 | + |
| 36 | +// Load and register Special:Install. |
| 37 | +$wgAutoloadClasses['SpecialInstall'] = dirname( __FILE__ ) . '/specials/SpecialInstall.php'; |
| 38 | +$wgSpecialPages['Install'] = 'SpecialInstall'; |
| 39 | +$wgSpecialPageGroups['Install'] = 'administration'; |
| 40 | + |
| 41 | +// Load and register Special:Update. |
| 42 | +$wgAutoloadClasses['SpecialUpdate'] = dirname( __FILE__ ) . '/specials/SpecialUpdate.php'; |
| 43 | +$wgSpecialPages['Update'] = 'SpecialUpdate'; |
| 44 | +$wgSpecialPageGroups['Update'] = 'administration'; |
| 45 | + |
| 46 | + |
26 | 47 | /** |
27 | 48 | * Initialization function for the Deployment extension. |
28 | 49 | */ |
Index: trunk/extensions/Deployment/INSTALL |
— | — | @@ -0,0 +1,5 @@ |
| 2 | +Once you have downloaded the code, place the 'Deployment' directory within your MediaWiki 'extensions' directory. |
| 3 | +Then add the following code to your LocalSettings.php file: |
| 4 | + |
| 5 | +# Distribution |
| 6 | +require_once( "$IP/extensions/Deployment/Deployment.php" ); |
\ No newline at end of file |
Index: trunk/extensions/Deployment/api/ApiExtensions.php |
— | — | @@ -1 +0,0 @@ |
2 | | -<?php |
Index: trunk/extensions/Deployment/api/ApiQueryExtensions.php |
— | — | @@ -1 +0,0 @@ |
2 | | -<?php |