Skip to content

Commit

Permalink
First approach towards a packaging tool.
Browse files Browse the repository at this point in the history
  • Loading branch information
beberlei committed Jan 23, 2012
1 parent 1e423b4 commit 98024fb
Show file tree
Hide file tree
Showing 13 changed files with 415 additions and 9 deletions.
2 changes: 2 additions & 0 deletions .gitignore
@@ -0,0 +1,2 @@
vendor
composer.lock
10 changes: 10 additions & 0 deletions .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

40 changes: 32 additions & 8 deletions Command/PackageCommand.php
Expand Up @@ -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()
Expand All @@ -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.");
}
}

64 changes: 64 additions & 0 deletions 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);
}
}

71 changes: 71 additions & 0 deletions 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;
}
}

18 changes: 18 additions & 0 deletions 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>
32 changes: 32 additions & 0 deletions 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);
}
}

32 changes: 32 additions & 0 deletions 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());
}
}

61 changes: 61 additions & 0 deletions 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>

0 comments on commit 98024fb

Please sign in to comment.