Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Automate the PEAR packaging and PEAR channel management

  • Loading branch information...
commit 41f804c8130e08a8a317f94c5e1bba7b0afbb361 1 parent 1cbba61
@ogail ogail authored
Showing with 460 additions and 4 deletions.
  1. +2 −3 .gitignore
  2. +1 −1  build.xml
  3. +457 −0 tools/ChannelManager.php
View
5 .gitignore
@@ -4,10 +4,9 @@ build/coverage
build/logs
build/pdepend
build/phpdox
-channel
+tools/channel
phpunit.xml
-ChannelManager.php
cache.properties
vendor
nbproject
-*.tgz
+tools/*.tgz
View
2  build.xml
@@ -191,7 +191,7 @@
<target name="new-pear-release" description="Adds new release to PEAR channel">
<exec executable="php.exe">
- <arg path="${basedir}/ChannelManager.php" />
+ <arg path="${basedir}/tools/ChannelManager.php" />
<arg value="release" />
</exec>
</target>
View
457 tools/ChannelManager.php
@@ -0,0 +1,457 @@
+<?php
+/**
+ * LICENSE: Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * PHP version 5
+ *
+ * @category Microsoft
+ * @package WindowsAzure
+ * @author Azure PHP SDK <azurephpsdk@microsoft.com>
+ * @copyright 2012 Microsoft Corporation
+ * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0
+ * @link http://pear.php.net/package/azure-sdk-for-php
+ */
+
+namespace WindowsAzure;
+
+require_once '../WindowsAzure/WindowsAzure.php';
+require_once '../defaults.php';
+use WindowsAzure\Common\Internal\Utilities;
+use WindowsAzure\Common\Internal\Serialization\XmlSerializer;
+use WindowsAzure\Common\Configuration;
+use WindowsAzure\Blob\BlobSettings;
+use WindowsAzure\Blob\BlobService;
+use WindowsAzure\Blob\Models\CreateContainerOptions;
+use WindowsAzure\Blob\Models\PublicAccessType;
+use WindowsAzure\Common\ServiceException;
+use WindowsAzure\Blob\Models\CreateBlobOptions;
+
+/**
+ * Manages a PEAR channel.
+ *
+ * @category Microsoft
+ * @package WindowsAzure
+ * @author Azure PHP SDK <azurephpsdk@microsoft.com>
+ * @copyright 2012 Microsoft Corporation
+ * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0
+ * @version Release: @package_version@
+ * @link http://pear.php.net/package/azure-sdk-for-php
+ */
+class ChannelManager
+{
+ /**
+ * @var BlobRestProxy
+ */
+ private static $_blobRestProxy;
+
+ /**
+ * Creates new blob REST proxy.
+ *
+ * @return BlobRestProxy
+ */
+ private static function _createBlobRestProxy()
+ {
+ $config = new Configuration();
+ $config->setProperty(BlobSettings::ACCOUNT_KEY, getenv('CHANNEL_STORAGE_SERVICE_KEY'));
+ $config->setProperty(BlobSettings::ACCOUNT_NAME, CHANNEL_STORAGE_SERVICE_NAME);
+ $config->setProperty(BlobSettings::URI, CHANNEL_URL);
+
+ return BlobService::create($config);
+ }
+
+ /**
+ * Channel manager main entry.
+ *
+ * @return none
+ */
+ public static function main()
+ {
+ self::$_blobRestProxy = self::_createBlobRestProxy();
+
+ if ( isset($_GET['release'])
+ || (isset($_SERVER['argv'])
+ && @$_SERVER['argv'][1] == 'release')
+ ) {
+ // Ship a new release
+ self::_downloadChannel();
+ self::_addPackage();
+ self::_uploadChannel();
+ self::_verifyInstall();
+ } else {
+ // Prompt user to manage channel
+ self::_manageChannel();
+ }
+ }
+
+ /**
+ * Command line interaction with user to manage the channel by letting user to:
+ * 1) Get the channel (either by creation of new one or download existing one).
+ * 2) Prompt user to remove old package.
+ * 3) Prompt user to add current package.
+ * 4) Upload the channel back.
+ * 5) Verify that latest package is installable.
+ *
+ * @return none
+ */
+ private static function _manageChannel()
+ {
+ $answer = self::_promptMsg('Create new channel? [n]:', true);
+ switch ($answer) {
+ case 'y':
+ self::_createNewChannel();
+ self::_uploadChannel();
+ self::_executeCommand('pear channel-discover ' . CHANNEL_NAME);
+ break;
+ case 'n':
+ case '':
+ self::_downloadChannel();
+ break;
+ }
+
+ do {
+ $answer = self::_promptMsg('Want to remove exisitng package? [n]:', true);
+ switch ($answer) {
+ case 'y':
+ self::_removePackage();
+ break;
+ }
+ } while ($answer == 'y');
+
+ $answer = self::_promptMsg('Want to add current package? [y]:', true);
+ switch ($answer) {
+ case 'y':
+ case '':
+ self::_addPackage();
+ break;
+ }
+
+ self::_uploadChannel();
+
+ self::_verifyInstall();
+ }
+
+ /**
+ * Creates new channel and removes existing channel files by:
+ * 1) Removes existing channel files on the cloud.
+ * 2) Constructs pirum.xml contents.
+ * 3) Cleans previous files if any and create new channel directory.
+ * 4) Writes pirum.xml.
+ * 5) Generates the channel files.
+ *
+ * @return none
+ */
+ private static function _createNewChannel()
+ {
+ echo "Removing old channel files if any...\n";
+ self::_clearContainer(CHANNEL_MAIN_CONTAINER, self::$_blobRestProxy);
+ self::_clearContainer(CHANNEL_GET_CONTAINER, self::$_blobRestProxy);
+ self::_clearContainer(CHANNEL_REST_CONTAINER, self::$_blobRestProxy);
+
+ $xmlSerializer = new XmlSerializer();
+ $properties = array(XmlSerializer::ROOT_NAME => 'server');
+ $fileArray = array(
+ 'name' => CHANNEL_NAME,
+ 'summary' => CHANNEL_SUMMARY,
+ 'alias' => CHANNEL_ALIAS,
+ 'url' => CHANNEL_URL
+ );
+ $fileContents = $xmlSerializer->serialize($fileArray, $properties);
+ $dirName = CHANNEL_DIR_NAME;
+
+ self::_createDir(CHANNEL_DIR_NAME);
+
+ $filePath = dirname(__FILE__) . DIRECTORY_SEPARATOR . $dirName;
+ $filePath .= DIRECTORY_SEPARATOR . 'pirum.xml';
+ file_put_contents($filePath, $fileContents);
+
+ self::_executeCommand("pirum build $dirName/");
+ }
+
+ /**
+ * Tries to install the new released package.
+ *
+ * @return none
+ */
+ private static function _verifyInstall()
+ {
+ echo "Test installing the package...\n";
+ self::_executeCommand('pear uninstall WindowsAzure/WindowsAzure');
+ self::_executeCommand('pear channel-update WindowsAzure');
+ self::_executeCommand('pear clear-cache');
+ self::_executeCommand('pear install WindowsAzure/WindowsAzure');
+ }
+
+ /**
+ * Deletes all the Blobs in a specified container.
+ *
+ * @param string $container The container name.
+ *
+ * @return none
+ */
+ private static function _clearContainer($container)
+ {
+ $blobs = self::$_blobRestProxy->listBlobs($container);
+ $blobs = $blobs->getBlobs();
+ foreach ($blobs as $blob) {
+ self::$_blobRestProxy->deleteBlob($container, $blob->getName());
+ }
+ }
+
+ /**
+ * Downloads all the Blobs in a container to a specified directory.
+ *
+ * @param string $containerName The container name.
+ * @param string $dirName The directory name.
+ *
+ * @return none
+ */
+ private static function _downloadContainerInDir($containerName, $dirName)
+ {
+ self::_createDir($dirName);
+ $blobs = self::$_blobRestProxy->listBlobs($containerName);
+ $blobs = $blobs->getBlobs();
+ foreach ($blobs as $blob) {
+ $name = $blob->getName();
+ $blob = self::$_blobRestProxy->getBlob($containerName, $name);
+ $file = $dirName . '/' . $name;
+ $dir = dirname($file);
+ if (!is_dir($dir)) {
+ mkdir($dir, 0777, true);
+ }
+ file_put_contents($file, stream_get_contents($blob->getContentStream()));
+ }
+ }
+
+ /**
+ * Downloads the channel files.
+ *
+ * @return none
+ */
+ private static function _downloadChannel()
+ {
+ echo "Downloading the channel files...\n";
+ self::_downloadContainerInDir(CHANNEL_MAIN_CONTAINER, CHANNEL_DIR_NAME);
+ self::_downloadContainerInDir(CHANNEL_GET_CONTAINER, CHANNEL_DIR_NAME . '/get');
+ self::_downloadContainerInDir(CHANNEL_REST_CONTAINER, CHANNEL_DIR_NAME . '/rest');
+ }
+
+ /**
+ * Uploads the channel files to blob storage.
+ *
+ * @return none
+ *
+ * @throws \Exception
+ */
+ private static function _uploadChannel()
+ {
+ $names = array();
+ self::_rscandir('channel', $names);
+ $contents = array_map('file_get_contents', $names);
+
+ echo "Uploading channel files to the cloud...\n";
+ self::_tryCreateContainer(CHANNEL_MAIN_CONTAINER);
+ self::_tryCreateContainer(CHANNEL_GET_CONTAINER);
+ self::_tryCreateContainer(CHANNEL_REST_CONTAINER);
+
+ $channelDir = 'channel/';
+ $getDir = $channelDir . 'get/';
+ $restDir = $channelDir . 'rest/';
+
+ for ($i = 0; $i < count($names); $i++) {
+ $options = new CreateBlobOptions();
+ $finfo = finfo_open(FILEINFO_MIME_TYPE);
+ $options->setContentType(finfo_file($finfo, $names[$i]));
+
+ if (strpos($names[$i], $getDir) !== false) {
+ $names[$i] = str_replace($getDir, '', $names[$i]);
+ $container = CHANNEL_GET_CONTAINER;
+ } else if (strpos($names[$i], $restDir) !== false) {
+ $names[$i] = str_replace($restDir, '', $names[$i]);
+ $container = CHANNEL_REST_CONTAINER;
+ } else if (strpos($names[$i], $channelDir) !== false) {
+ $names[$i] = str_replace($channelDir, '', $names[$i]);
+ $container = CHANNEL_MAIN_CONTAINER;
+ } else {
+ throw new \Exception('incorrect file path.');
+ }
+
+ self::$_blobRestProxy->createBlockBlob(
+ $container,
+ $names[$i],
+ $contents[$i],
+ $options
+ );
+ }
+ }
+ /**
+ * Scans a directory and returns all files under it recursively.
+ *
+ * @param string $dir The directory path.
+ * @param array &$files The directory files.
+ *
+ * @return none
+ */
+ private static function _rscandir($dir, &$files) {
+ foreach(glob($dir . '/*') as $file) {
+ if(is_dir($file))
+ self::_rscandir($file, $files);
+ else
+ $files[] = $file;
+ }
+ }
+
+ /**
+ * Tries to create new container if it does not exist.
+ *
+ * @param string $container The container name.
+ *
+ * @return none
+ */
+ private static function _tryCreateContainer($container)
+ {
+ try {
+ $options = new CreateContainerOptions();
+ $options->setPublicAccess(PublicAccessType::BLOBS_ONLY);
+ self::$_blobRestProxy->createContainer($container, $options);
+ } catch (ServiceException $e) {
+ if ($e->getCode() != 409) {
+ print_r($e);
+ exit();
+ }
+ }
+ }
+
+ /**
+ * Adds new package.
+ *
+ * @return none
+ */
+ private static function _addPackage()
+ {
+ self::_executeCommand('php ..\package.php make');
+ self::_executeCommand('pear package ..\package.xml');
+ $files = glob('*.tgz');
+ $name = $files[count($files) - 1];
+ self::_executeCommand("pirum add channel $name");
+ }
+
+ /**
+ * Removes existing package.
+ *
+ * @return none
+ */
+ private static function _removePackage()
+ {
+ $files = glob('channel/get/*.tgz');
+ if (empty($files)) {
+ echo "No packages to remove.\n";
+ } else {
+ $files = array_map('basename', $files);
+ $msg = '';
+ for ($i = 0; $i < count($files); $i++) {
+ $msg .= ($i + 1) . '. ' . $files[$i] . "\n";
+ }
+ $answer = self::_promptMsg($msg . 'Choose package to remove:');
+ $name = $files[$answer - 1];
+ self::_executeCommand("pirum remove channel $name");
+ }
+ }
+
+ /**
+ * Creates new directory and removes existing one.
+ *
+ * @param string $dirName The directory name.
+ *
+ * @return none
+ */
+ private static function _createDir($dirName)
+ {
+ // Clear previous files if any
+ self::_rrmdir($dirName);
+
+ // Create new directory
+ mkdir($dirName);
+ }
+
+ /**
+ * Executes cmdline command.
+ *
+ * @param string $command The command to execute.
+ *
+ * @return none
+ */
+ private static function _executeCommand($command)
+ {
+ exec($command, $output, $failed);
+ echo implode("\n", $output) . "\n";
+ if ($failed) {
+ echo "Something went wrong. Exit\n";
+ exit();
+ }
+ }
+
+ /**
+ * Removes a whole directory with all files inside it.
+ *
+ * @param string $dir The directory path.
+ *
+ * @return none
+ */
+ private static function _rrmdir($dir)
+ {
+ foreach(glob($dir . '/*') as $file) {
+ if(is_dir($file)) {
+ self::_rrmdir($file);
+ } else {
+ unlink($file);
+ }
+ }
+
+ if (is_dir($dir)) {
+ rmdir($dir);
+ }
+ }
+
+ /**
+ * Prompts message to the uers and return back the input.
+ *
+ * @param string $msg The message to display.
+ * @param boolean $isYesNoMsg Flag to indicate if this is Y/N question.
+ *
+ * @return string
+ */
+ private static function _promptMsg($msg, $isYesNoMsg = false)
+ {
+ if ($isYesNoMsg) {
+ do {
+ echo $msg;
+ $line = trim(fgets(STDIN));
+ $line = strtolower($line);
+ $line = empty($line) ? $line : $line[0];
+ if ($line == '' || $line == 'y' || $line == 'n') {
+ break;
+ }
+ } while (true);
+ } else {
+ echo $msg;
+ $line = trim(fgets(STDIN));
+ }
+
+ return $line;
+ }
+}
+
+
+// Start the script
+ChannelManager::main();
+
+?>
Please sign in to comment.
Something went wrong with that request. Please try again.