Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

First approach towards a packaging tool.

  • Loading branch information...
commit 98024fb786bf67185394d3c9424008b98cd5ba8a 1 parent 1e423b4
@beberlei authored
View
2  .gitignore
@@ -0,0 +1,2 @@
+vendor
+composer.lock
View
10 .travis.yml
@@ -0,0 +1,10 @@
+language: php
+
+php:
+ - 5.3
+ - 5.4
+
+before_script:
+ - wget http://getcomposer.org/composer.phar
+ - php composer.phar install
+
View
40 Command/PackageCommand.php
@@ -18,7 +18,13 @@
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Filesystem\Filesystem;
+use Symfony\Component\Process\Process;
+/**
+ * Package a Symfony application for deployment.
+ *
+ * @author Benjamin Eberlei <kontakt@beberlei.de>
+ */
class PackageCommand extends ContainerAwareCommand
{
protected function configure()
@@ -32,15 +38,33 @@ protected function configure()
protected function execute(InputInterface $input, OutputInterface $output)
{
- $kernel = $this->getContainer()->get('kernel');
- $rootDir = $kernel->getRootDir();
- $azureDir = $rootDir . '/azure';
- $filesystem = new Filesystem();
-
- if ( ! file_exists($azureDir) ) {
- $output->writeln('No WindowsAzure directory found. Creating in <info>%s</info>', $azureDir));
- $filesystem->mirror($kernel->locateResource("@WindowsAzureDistributionBundle/Resources/azure_scaffold"), $azureDir, null, array('copy_on_windows' => true));
+ $serviceDefinition = $this->getContainer()->get('windows_azure_distribution.config.service_definition');
+ $azureCmdBuilder = $this->getContainer()->get('windows_azure_distribution.deployment.azure_sdk_command_builder');
+ $cmd = $azureCmdBuilder->buildPackageCmd($serviceDefinition, $input->getOption('dev-fabric'));
+
+ $process = new Process($this->getAzureSdkBinaryFolder() . '\\' . $cmd);
+ $process->run();
+
+ if ( ! $process->isSuccessful()) {
+ throw new \RuntimeException($process->getErrorOutput());
}
+
+ print $process->getOutput();
+ }
+
+ private function getAzureSdkBinaryFolder()
+ {
+ $programDirectories = array('ProgramFiles', 'ProgramFiles(x86)', 'ProgramW6432');
+ $binDirectories = array('Windows Azure SDK\*\bin', 'Windows Azure Emulator\emulator');
+ foreach ($programDirectories as $programDirectory) {
+ foreach ($binDirectories as $binDirectory) {
+ if ($dirs = glob($programDirectory . '\\' . $binDirectoy, GLOB_NOSORT)) {
+ return $dirs;
+ }
+ }
+ }
+
+ throw new \RuntimeException("Cannot find Windows Azure SDK. You can download the SDK from http://www.windowsazure.com.");
}
}
View
64 Deployment/AzureSDKCommandBuilder.php
@@ -0,0 +1,64 @@
+<?php
+/**
+ * WindowsAzure DistributionBundle
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to kontakt@beberlei.de so I can send you a copy immediately.
+ */
+
+namespace WindowsAzure\DistributionBundle\Deployment;
+
+/**
+ * Abstraction layer to build commands from input parameters.
+ *
+ * @author Benjamin Eberlei <kontakt@beberlei.de>
+ */
+class AzureSDKCommandBuilder
+{
+ /**
+ * @var string
+ */
+ private $rootDir;
+
+ /**
+ * @var string
+ */
+ private $outputDir;
+
+ public function __construct($rootDir, $outputDir)
+ {
+ $this->rootDir = $rootDir;
+ $this->outputDir = $outputDir;
+ }
+
+ /**
+ * Build Packaging command
+ *
+ * @param ServiceDefinition $serviceDefinition
+ * @param bool $isDevFabric
+ * @return string
+ */
+ public function buildPackageCmd(ServiceDefinition $serviceDefinition, $isDevFabric)
+ {
+ $args = array($serviceDefinition->getPath());
+ foreach ($serviceDefinition->getWebRoleNames() as $roleName) {
+ $args[] = sprintf('/role:%s;%s', $roleName, $this->rootDir); // TODO: Only standard layout
+ }
+ foreach ($serviceDefinition->getWorkerRoleNames() as $roleName) {
+ $args[] = sprintf('/role:%s;%s', $roleName, $this->rootDir); // TODO: Only standard layout
+ }
+ $args[] = sprintf('/out:%s', $this->outputDir);
+
+ if ($isDevFabric) {
+ $args[] = '/copyOnly';
+ }
+
+ return 'cspack.exe ' . implode(" ", $args);
+ }
+}
+
View
71 Deployment/ServiceDefinition.php
@@ -0,0 +1,71 @@
+<?php
+/**
+ * WindowsAzure DistributionBundle
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to kontakt@beberlei.de so I can send you a copy immediately.
+ */
+
+namespace WindowsAzure\DistributionBundle\Deployment;
+
+/**
+ * Wraps the ServiceDefinition.csdef file and allows convenient access.
+ *
+ * @author Benjamin Eberlei <kontakt@beberlei.de>
+ */
+class ServiceDefinition
+{
+ /**
+ * @var string
+ */
+ private $serviceDefinitionFile;
+ /**
+ * @var DOMDocument
+ */
+ private $dom;
+
+ /**
+ * @param string $serviceDefinitionFile
+ */
+ public function __construct($serviceDefinitionFile)
+ {
+ if (!file_exists($serviceDefinitionFile)) {
+ throw new \InvalidArgumentException("No valid file-path given.");
+ }
+
+ $this->serviceDefinitionFile = $serviceDefinitionFile;
+ $this->dom = new \DOMDocument('1.0', 'UTF-8');
+ $this->dom->load($this->serviceDefinitionFile);
+ }
+
+ public function getPath()
+ {
+ return $this->serviceDefinitionFile;
+ }
+
+ public function getWebRoleNames()
+ {
+ return $this->getRoleNames("WebRole");
+ }
+
+ public function getWorkerRoleNames()
+ {
+ return $this->getRoleNames("WorkerRole");
+ }
+
+ private function getRoleNames($tagName)
+ {
+ $nodes = $this->dom->getElementsByTagName($tagName);
+ $roleNames = array();
+ foreach ($nodes as $node) {
+ $roleNames[] = $node->getAttribute('name');
+ }
+ return $roleNames;
+ }
+}
+
View
18 Resources/config/services.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" ?>
+<container>
+ <parameters>
+ <parameter name="windows_azure_distribution.config.service_definition_file">%kernel.root_dir%/azure/ServiceDefinition.csdef</parameter>
+ <parameter name="windows_azure_distribution.config.application_root">%kernel.root_dir%/../<parameter>
+ <parameter name="windows_azure_distribution.deployment.azure_sdk_command_builder.class">WindowsAzure\DistributionBundle\Deployment\AzureSDKCommandBuilder</parameter>
+ </parameters>
+ <services>
+ <service id="windows_azure_distribution.config.service_definition" class="WindowsAzure\DistributionBundle\Deployment\ServiceConfiguration">
+ <argument>%windows_azure_distribution.config.service_definition_file%</argument>
+ </service>
+
+ <service id="windows_azure_distribution.deployment.azure_sdk_command_builder" class="%windows_azure_distribution.deployment.azure_sdk_command_builder.class%">
+ <argument>%windows_azure_distribution.config.application_root%</argument>
+ <argument>%kernel.cache_dir%</argument>
+ </service>
+ </services>
+</container>
View
32 Tests/Deployment/AzureSDKCommandBuilderTest.php
@@ -0,0 +1,32 @@
+<?php
+/**
+ * WindowsAzure DistributionBundle
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to kontakt@beberlei.de so I can send you a copy immediately.
+ */
+
+namespace WindowsAzure\DistributionBundle\Tests\Deployment;
+
+use WindowsAzure\DistributionBundle\Deployment\ServiceDefinition;
+use WindowsAzure\DistributionBundle\Deployment\AzureSDKCommandBuilder;
+
+class AzureSDKCommandBuilderTest extends \PHPUnit_Framework_TestCase
+{
+ public function testGetPackageCommand()
+ {
+ $rootPath = "C:\symfony\app";
+ $outputPath = "C:\output";
+ $def = new ServiceDefinition(__DIR__ . '/_files/webrole_def.xml');
+ $builder = new AzureSDKCommandBuilder($rootPath, $outputPath);
+
+ $cmd = $builder->buildPackageCmd($def, true);
+ $this->assertEquals('cspack.exe /role:TestRole;C:\symfony\app /out:C:\output /copyOnly', $cmd);
+ }
+}
+
View
32 Tests/Deployment/ServiceDefinitionTest.php
@@ -0,0 +1,32 @@
+<?php
+/**
+ * WindowsAzure DistributionBundle
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to kontakt@beberlei.de so I can send you a copy immediately.
+ */
+
+namespace WindowsAzure\DistributionBundle\Tests\Deployment;
+
+use WindowsAzure\DistributionBundle\Deployment\ServiceDefinition;
+
+class ServiceDefinitionTest extends \PHPUnit_Framework_TestCase
+{
+ public function testGetWebRoleNames()
+ {
+ $def = new ServiceDefinition(__DIR__ . "/_files/webrole_def.xml");
+ $this->assertEquals(array("TestRole"), $def->getWebRoleNames());
+ }
+
+ public function testGetWorkerRoleNames()
+ {
+ $def = new ServiceDefinition(__DIR__ . "/_files/workerrole_def.xml");
+ $this->assertEquals(array("WorkerRoleTest"), $def->getWorkerRoleNames());
+ }
+}
+
View
61 Tests/Deployment/_files/webrole_def.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" ?>
+<ServiceDefinition name="service-name" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition" upgradeDomainCount="number-of-upgrade-domains">
+ <WebRole name="TestRole" vmsize="[ExtraSmall|Small|Medium|Large|ExtraLarge]" enableNativeCodeExecution="[true|false]">
+ <Certificates>
+ <Certificate name="certificate-name" storeLocation="certificate-store" storeName="store-name" />
+ </Certificates>
+ <ConfigurationSettings>
+ <Setting name="setting-name" />
+ </ConfigurationSettings>
+ <Imports>
+ <Import moduleName="import-module"/>
+ </Imports>
+ <InputEndpoints >
+ <InputEndpoint certificate="certificate-name" ignoreRoleInstanceStatus="[true|false]" name="input-endpoint-name" protocol="[http|https]" localPort="port-number" port="port-number" />
+ </InputEndpoints>
+ <Endpoints>
+ <InputEndpoint certificate="certificate-name" ignoreRoleInstanceStatus="[true|false]" name="input-endpoint-name" protocol="[http|https|tcp]" localPort="port-number" port="port-number" />
+ <InternalEndpoint name="internal-endpoint-name" protocol="[http|tcp]" port="port-number">
+ <FixedPort port="port-number"/>
+ <FixedPortRange min="minium-port-number" max="maximum-port-number"/>
+ </InternalEndpoint>
+ </Endpoints>
+ <LocalResources>
+ <LocalStorage name="local-store-name" cleanOnRoleRecycle="[true|false]" sizeInMB="size-in-megabytes" />
+ </LocalResources>
+ <LocalStorage name="local-store-name" cleanOnRoleRecycle="[true|false]" sizeInMB="size-in-megabytes" />
+ <Runtime executionContext="[limited|elevated]">
+ <Environment>
+ <Variable name="variable-name" value="variable-value">
+ <RoleInstanceValue xpath="xpath-to-role-environment-settings"/>
+ </Variable>
+ </Environment>
+ <EntryPoint>
+ <NetFxEntryPoint assemblyName="name-of-assembly-containing-entrypoint" targetFrameworkVersion=".net-framework-version"/>
+ </EntryPoint>
+ </Runtime>
+ <Sites>
+ <Site name="web-site-name">
+ <VirtualApplication name="application-name" physicalDirectory="directory-path"/>
+ <VirtualDirectory name="directory-path" physicalDirectory="directory-path"/>
+ <Bindings>
+ <Binding name="binding-name" endpointName="endpoint-name-bound-to" hostHeader="url-of-the-site"/>
+ </Bindings>
+ </Site>
+ </Sites>
+ <Startup priority="for-internal-use-only>">
+ <Task commandLine="command-to=execute" executionContext="[limited|elevated]" taskType="[simple|foreground|background]">
+ <Environment>
+ <Variable name="variable-name" value="variable-value">
+ <RoleInstanceValue xpath="xpath-to-role-environment-settings"/>
+ </Variable>
+ </Environment>
+ </Task>
+ </Startup>
+ <Contents>
+ <Content destination="destination-folder-name" >
+ <SourceDirectory path="local-source-directory" />
+ </Content>
+ </Contents>
+ </WebRole>
+</ServiceDefinition>
View
49 Tests/Deployment/_files/workerrole_def.xml
@@ -0,0 +1,49 @@
+<ServiceDefinition name="service-name" upgradeDomainCount="number-of-upgrade-domains">
+ <WorkerRole name="WorkerRoleTest" vmsize="[ExtraSmall|Small|Medium|Large|ExtraLarge]" enableNativeCodeExecution="[true|false]">
+ <Certificates>
+ <Certificate name="certificate-name" storeLocation="[CurrentUser|LocalMachine]" storeName="[My|Root|CA|Trust|Disallow|TrustedPeople|TrustedPublisher|AuthRoot|AddressBook|custom-store]" />
+ </Certificates>
+ <ConfigurationSettings>
+ <Setting name="setting-name" />
+ </ConfigurationSettings>
+ <Endpoints>
+ <InputEndpoint name="input-endpoint-name" protocol="[http|https|tcp]" localPort="local-port-number" port="port-number" certificate="certificate-name" />
+ <InternalEndpoint name="internal-endpoint-name" protocol="[http|tcp]" port="port-number">
+ <FixedPort port="port-number"/>
+ <FixedPortRange min="minium-port-number" max="maximum-port-number"/>
+ </InternalEndpoint>
+ </Endpoints>
+ <Imports>
+ <Import moduleName="[RemoteAccess|RemoteForwarder|Diagnostics|Connect]"/>
+ </Imports>
+ <LocalResources>
+ <LocalStorage name="local-store-name" cleanOnRoleRecycle="[true|false]" sizeInMB="size-in-megabytes" />
+ </LocalResources>
+ <LocalStorage name="local-store-name" cleanOnRoleRecycle="[true|false]" sizeInMB="size-in-megabytes" />
+ <Runtime executionContext="[limited|elevated]">
+ <Environment>
+ <Variable name="variable-name" value="variable-value">
+ <RoleInstanceValue xpath="xpath-to-role-environment-settings"/>
+ </Variable>
+ </Environment>
+ <EntryPoint>
+ <NetFxEntryPoint assemblyName="name-of-assembly-containing-entrypoint" targetFrameworkVersion=".net-framework-version"/>
+ <ProgramEntryPoint commandLine="application" setReadyOnProcessStart="[true|false]" />
+ </EntryPoint>
+ </Runtime>
+ <Startup priority="for-internal-use-only">
+ <Task commandLine="" executionContext="[limited|elevated]" taskType="[simple|foreground|background]">
+ <Environment>
+ <Variable name="variable-name" value="variable-value">
+ <RoleInstanceValue xpath="xpath-to-role-environment-settings"/>
+ </Variable>
+ </Environment>
+ </Task>
+ </Startup>
+ <Contents>
+ <Content destination="destination-folder-name" >
+ <SourceDirectory path="local-source-directory" />
+ </Content>
+ </Contents>
+ </WorkerRole>
+</ServiceDefinition>
View
21 Tests/bootstrap.php
@@ -0,0 +1,21 @@
+<?php
+
+if (!@include __DIR__ . '/../vendor/.composer/autoload.php') {
+ die(<<<'EOT'
+You must set up the project dependencies, run the following commands:
+wget http://getcomposer.org/composer.phar
+php composer.phar install
+EOT
+ );
+}
+
+spl_autoload_register(function($class) {
+ if (0 === strpos($class, 'WindowsAzure\\DistributionBundle')) {
+ $path = __DIR__.'/../'.implode('/', array_slice(explode('\\', $class), 2)).'.php';
+ if (!stream_resolve_include_path($path)) {
+ return false;
+ }
+ require_once $path;
+ return true;
+ }
+});
View
6 composer.json
@@ -6,6 +6,10 @@
],
"require": {
"symfony/symfony": ">=2.0.0"
- }
+ },
+ "autoload": {
+ "psr-0": { "WindowsAzure\\DistributionBundle":"" }
+ },
+ "target-dir": "WindowsAzure/DistributionBundle"
}
View
18 phpunit.xml.dist
@@ -0,0 +1,18 @@
+<?xml version="1.0" ?>
+<phpunit bootstrap="Tests/bootstrap.php">
+ <testsuites>
+ <testsuite name="WindowsAzure Distribution Bundle">
+ <directory suffix="Test.php">./Tests</directory>
+ </testsuite>
+ </testsuites>
+
+ <filter>
+ <whitelist>
+ <directory>./</directory>
+ <exclude>
+ <directory>./Resources</directory>
+ <directory>./Tests</directory>
+ </exclude>
+ </whitelist>
+ </filter>
+</phpunit>
Please sign in to comment.
Something went wrong with that request. Please try again.