PageRenderTime 42ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/build/ChannelManager.php

https://bitbucket.org/skudatech/azure-sdk-for-php
PHP | 453 lines | 259 code | 39 blank | 155 comment | 39 complexity | 2f8debf3adb068b4a4ef4416a3400ac2 MD5 | raw file
  1. <?php
  2. /**
  3. * LICENSE: Licensed under the Apache License, Version 2.0 (the "License");
  4. * you may not use this file except in compliance with the License.
  5. * You may obtain a copy of the License at
  6. * http://www.apache.org/licenses/LICENSE-2.0
  7. *
  8. * Unless required by applicable law or agreed to in writing, software
  9. * distributed under the License is distributed on an "AS IS" BASIS,
  10. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  11. * See the License for the specific language governing permissions and
  12. * limitations under the License.
  13. *
  14. * PHP version 5
  15. *
  16. * @category Microsoft
  17. * @package WindowsAzure
  18. * @author Azure PHP SDK <azurephpsdk@microsoft.com>
  19. * @copyright 2012 Microsoft Corporation
  20. * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0
  21. * @link https://github.com/windowsazure/azure-sdk-for-php
  22. */
  23. namespace WindowsAzure;
  24. require_once '../WindowsAzure/WindowsAzure.php';
  25. require_once '../defaults.php';
  26. use WindowsAzure\Common\Internal\Utilities;
  27. use WindowsAzure\Common\Internal\Serialization\XmlSerializer;
  28. use WindowsAzure\Blob\Models\CreateContainerOptions;
  29. use WindowsAzure\Blob\Models\PublicAccessType;
  30. use WindowsAzure\Common\ServiceException;
  31. use WindowsAzure\Blob\Models\CreateBlobOptions;
  32. use WindowsAzure\Common\ServicesBuilder;
  33. /**
  34. * Manages a PEAR channel.
  35. *
  36. * @category Microsoft
  37. * @package WindowsAzure
  38. * @author Azure PHP SDK <azurephpsdk@microsoft.com>
  39. * @copyright 2012 Microsoft Corporation
  40. * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0
  41. * @version Release: @package_version@
  42. * @link https://github.com/windowsazure/azure-sdk-for-php
  43. */
  44. class ChannelManager
  45. {
  46. /**
  47. * @var BlobRestProxy
  48. */
  49. private static $_blobRestProxy;
  50. /**
  51. * Creates new blob REST proxy.
  52. *
  53. * @return BlobRestProxy
  54. */
  55. private static function _createBlobRestProxy()
  56. {
  57. $accountKey = getenv('CHANNEL_STORAGE_SERVICE_KEY');
  58. $accountName = CHANNEL_STORAGE_SERVICE_NAME;
  59. $blobEndpointUri = CHANNEL_URL;
  60. $connectionString = "BlobEndpoint=$blobEndpointUri;AccountName=$accountName;AccountKey=$accountKey";
  61. return ServicesBuilder::getInstance()->createBlobService($connectionString);
  62. }
  63. /**
  64. * Channel manager main entry.
  65. *
  66. * @return none
  67. */
  68. public static function main()
  69. {
  70. self::$_blobRestProxy = self::_createBlobRestProxy();
  71. if ( isset($_GET['release'])
  72. || (isset($_SERVER['argv'])
  73. && @$_SERVER['argv'][1] == 'release')
  74. ) {
  75. // Ship a new release
  76. self::_downloadChannel();
  77. self::_addPackage();
  78. self::_uploadChannel();
  79. self::_verifyInstall();
  80. } else {
  81. // Prompt user to manage channel
  82. self::_manageChannel();
  83. }
  84. }
  85. /**
  86. * Command line interaction with user to manage the channel by letting user to:
  87. * 1) Get the channel (either by creation of new one or download existing one).
  88. * 2) Prompt user to remove old package.
  89. * 3) Prompt user to add current package.
  90. * 4) Upload the channel back.
  91. * 5) Verify that latest package is installable.
  92. *
  93. * @return none
  94. */
  95. private static function _manageChannel()
  96. {
  97. $answer = self::_promptMsg('Create new channel? [n]:', true);
  98. switch ($answer) {
  99. case 'y':
  100. self::_createNewChannel();
  101. self::_uploadChannel();
  102. self::_executeCommand('pear channel-discover ' . CHANNEL_NAME);
  103. break;
  104. case 'n':
  105. case '':
  106. self::_downloadChannel();
  107. break;
  108. }
  109. do {
  110. $answer = self::_promptMsg('Want to remove exisitng package? [n]:', true);
  111. switch ($answer) {
  112. case 'y':
  113. self::_removePackage();
  114. break;
  115. }
  116. } while ($answer == 'y');
  117. $answer = self::_promptMsg('Want to add current package? [y]:', true);
  118. switch ($answer) {
  119. case 'y':
  120. case '':
  121. self::_addPackage();
  122. break;
  123. }
  124. self::_uploadChannel();
  125. self::_verifyInstall();
  126. }
  127. /**
  128. * Creates new channel and removes existing channel files by:
  129. * 1) Removes existing channel files on the cloud.
  130. * 2) Constructs pirum.xml contents.
  131. * 3) Cleans previous files if any and create new channel directory.
  132. * 4) Writes pirum.xml.
  133. * 5) Generates the channel files.
  134. *
  135. * @return none
  136. */
  137. private static function _createNewChannel()
  138. {
  139. echo "Removing old channel files if any...\n";
  140. self::_clearContainer(CHANNEL_MAIN_CONTAINER, self::$_blobRestProxy);
  141. self::_clearContainer(CHANNEL_GET_CONTAINER, self::$_blobRestProxy);
  142. self::_clearContainer(CHANNEL_REST_CONTAINER, self::$_blobRestProxy);
  143. $xmlSerializer = new XmlSerializer();
  144. $properties = array(XmlSerializer::ROOT_NAME => 'server');
  145. $fileArray = array(
  146. 'name' => CHANNEL_NAME,
  147. 'summary' => CHANNEL_SUMMARY,
  148. 'alias' => CHANNEL_ALIAS,
  149. 'url' => CHANNEL_URL
  150. );
  151. $fileContents = $xmlSerializer->serialize($fileArray, $properties);
  152. $dirName = CHANNEL_DIR_NAME;
  153. self::_createDir(CHANNEL_DIR_NAME);
  154. $filePath = dirname(__FILE__) . DIRECTORY_SEPARATOR . $dirName;
  155. $filePath .= DIRECTORY_SEPARATOR . 'pirum.xml';
  156. file_put_contents($filePath, $fileContents);
  157. self::_executeCommand("pirum build $dirName/");
  158. }
  159. /**
  160. * Tries to install the new released package.
  161. *
  162. * @return none
  163. */
  164. private static function _verifyInstall()
  165. {
  166. echo "Test installing the package...\n";
  167. self::_executeCommand('pear uninstall WindowsAzure/WindowsAzure');
  168. self::_executeCommand('pear channel-update WindowsAzure');
  169. self::_executeCommand('pear clear-cache');
  170. self::_executeCommand('pear install WindowsAzure/WindowsAzure');
  171. }
  172. /**
  173. * Deletes all the Blobs in a specified container.
  174. *
  175. * @param string $container The container name.
  176. *
  177. * @return none
  178. */
  179. private static function _clearContainer($container)
  180. {
  181. $blobs = self::$_blobRestProxy->listBlobs($container);
  182. $blobs = $blobs->getBlobs();
  183. foreach ($blobs as $blob) {
  184. self::$_blobRestProxy->deleteBlob($container, $blob->getName());
  185. }
  186. }
  187. /**
  188. * Downloads all the Blobs in a container to a specified directory.
  189. *
  190. * @param string $containerName The container name.
  191. * @param string $dirName The directory name.
  192. *
  193. * @return none
  194. */
  195. private static function _downloadContainerInDir($containerName, $dirName)
  196. {
  197. self::_createDir($dirName);
  198. $blobs = self::$_blobRestProxy->listBlobs($containerName);
  199. $blobs = $blobs->getBlobs();
  200. foreach ($blobs as $blob) {
  201. $name = $blob->getName();
  202. $blob = self::$_blobRestProxy->getBlob($containerName, $name);
  203. $file = $dirName . '/' . $name;
  204. $dir = dirname($file);
  205. if (!is_dir($dir)) {
  206. mkdir($dir, 0777, true);
  207. }
  208. file_put_contents($file, stream_get_contents($blob->getContentStream()));
  209. }
  210. }
  211. /**
  212. * Downloads the channel files.
  213. *
  214. * @return none
  215. */
  216. private static function _downloadChannel()
  217. {
  218. echo "Downloading the channel files...\n";
  219. self::_downloadContainerInDir(CHANNEL_MAIN_CONTAINER, CHANNEL_DIR_NAME);
  220. self::_downloadContainerInDir(CHANNEL_GET_CONTAINER, CHANNEL_DIR_NAME . '/get');
  221. self::_downloadContainerInDir(CHANNEL_REST_CONTAINER, CHANNEL_DIR_NAME . '/rest');
  222. }
  223. /**
  224. * Uploads the channel files to blob storage.
  225. *
  226. * @return none
  227. *
  228. * @throws \Exception
  229. */
  230. private static function _uploadChannel()
  231. {
  232. $names = array();
  233. self::_rscandir('channel', $names);
  234. $contents = array_map('file_get_contents', $names);
  235. echo "Uploading channel files to the cloud...\n";
  236. self::_tryCreateContainer(CHANNEL_MAIN_CONTAINER);
  237. self::_tryCreateContainer(CHANNEL_GET_CONTAINER);
  238. self::_tryCreateContainer(CHANNEL_REST_CONTAINER);
  239. $channelDir = 'channel/';
  240. $getDir = $channelDir . 'get/';
  241. $restDir = $channelDir . 'rest/';
  242. for ($i = 0; $i < count($names); $i++) {
  243. $options = new CreateBlobOptions();
  244. $finfo = finfo_open(FILEINFO_MIME_TYPE);
  245. $options->setContentType(finfo_file($finfo, $names[$i]));
  246. if (strpos($names[$i], $getDir) !== false) {
  247. $names[$i] = str_replace($getDir, '', $names[$i]);
  248. $container = CHANNEL_GET_CONTAINER;
  249. } else if (strpos($names[$i], $restDir) !== false) {
  250. $names[$i] = str_replace($restDir, '', $names[$i]);
  251. $container = CHANNEL_REST_CONTAINER;
  252. } else if (strpos($names[$i], $channelDir) !== false) {
  253. $names[$i] = str_replace($channelDir, '', $names[$i]);
  254. $container = CHANNEL_MAIN_CONTAINER;
  255. } else {
  256. throw new \Exception('incorrect file path.');
  257. }
  258. self::$_blobRestProxy->createBlockBlob(
  259. $container,
  260. $names[$i],
  261. $contents[$i],
  262. $options
  263. );
  264. }
  265. }
  266. /**
  267. * Scans a directory and returns all files under it recursively.
  268. *
  269. * @param string $dir The directory path.
  270. * @param array &$files The directory files.
  271. *
  272. * @return none
  273. */
  274. private static function _rscandir($dir, &$files) {
  275. foreach(glob($dir . '/*') as $file) {
  276. if(is_dir($file)) {
  277. self::_rscandir($file, $files);
  278. } else {
  279. $files[] = $file;
  280. }
  281. }
  282. }
  283. /**
  284. * Tries to create new container if it does not exist.
  285. *
  286. * @param string $container The container name.
  287. *
  288. * @return none
  289. */
  290. private static function _tryCreateContainer($container)
  291. {
  292. try {
  293. $options = new CreateContainerOptions();
  294. $options->setPublicAccess(PublicAccessType::BLOBS_ONLY);
  295. self::$_blobRestProxy->createContainer($container, $options);
  296. } catch (ServiceException $e) {
  297. if ($e->getCode() != 409) {
  298. print_r($e);
  299. exit();
  300. }
  301. }
  302. }
  303. /**
  304. * Adds new package.
  305. *
  306. * @return none
  307. */
  308. private static function _addPackage()
  309. {
  310. self::_executeCommand('php ..\package.php make');
  311. self::_executeCommand('pear package ..\package.xml');
  312. $files = glob('*.tgz');
  313. $name = $files[count($files) - 1];
  314. self::_executeCommand("pirum add channel $name");
  315. }
  316. /**
  317. * Removes existing package.
  318. *
  319. * @return none
  320. */
  321. private static function _removePackage()
  322. {
  323. $files = glob('channel/get/*.tgz');
  324. if (empty($files)) {
  325. echo "No packages to remove.\n";
  326. } else {
  327. $files = array_map('basename', $files);
  328. $msg = '';
  329. for ($i = 0; $i < count($files); $i++) {
  330. $msg .= ($i + 1) . '. ' . $files[$i] . "\n";
  331. }
  332. $answer = self::_promptMsg($msg . 'Choose package to remove:');
  333. $name = $files[$answer - 1];
  334. self::_executeCommand("pirum remove channel $name");
  335. }
  336. }
  337. /**
  338. * Creates new directory and removes existing one.
  339. *
  340. * @param string $dirName The directory name.
  341. *
  342. * @return none
  343. */
  344. private static function _createDir($dirName)
  345. {
  346. // Clear previous files if any
  347. self::_rrmdir($dirName);
  348. // Create new directory
  349. mkdir($dirName);
  350. }
  351. /**
  352. * Executes cmdline command.
  353. *
  354. * @param string $command The command to execute.
  355. *
  356. * @return none
  357. */
  358. private static function _executeCommand($command)
  359. {
  360. exec($command, $output, $failed);
  361. echo implode("\n", $output) . "\n";
  362. if ($failed) {
  363. echo "Something went wrong. Exit\n";
  364. exit();
  365. }
  366. }
  367. /**
  368. * Removes a whole directory with all files inside it.
  369. *
  370. * @param string $dir The directory path.
  371. *
  372. * @return none
  373. */
  374. private static function _rrmdir($dir)
  375. {
  376. foreach(glob($dir . '/*') as $file) {
  377. if(is_dir($file)) {
  378. self::_rrmdir($file);
  379. } else {
  380. unlink($file);
  381. }
  382. }
  383. if (is_dir($dir)) {
  384. rmdir($dir);
  385. }
  386. }
  387. /**
  388. * Prompts message to the uers and return back the input.
  389. *
  390. * @param string $msg The message to display.
  391. * @param boolean $isYesNoMsg Flag to indicate if this is Y/N question.
  392. *
  393. * @return string
  394. */
  395. private static function _promptMsg($msg, $isYesNoMsg = false)
  396. {
  397. if ($isYesNoMsg) {
  398. do {
  399. echo $msg;
  400. $line = trim(fgets(STDIN));
  401. $line = strtolower($line);
  402. $line = empty($line) ? $line : $line[0];
  403. if ($line == '' || $line == 'y' || $line == 'n') {
  404. break;
  405. }
  406. } while (true);
  407. } else {
  408. echo $msg;
  409. $line = trim(fgets(STDIN));
  410. }
  411. return $line;
  412. }
  413. }
  414. ChannelManager::main();