├── .gitattributes ├── .gitignore ├── .gitmodules ├── .nuget ├── NuGet.Config ├── NuGet.exe └── NuGet.targets ├── Builder.Tests ├── Builder.Tests.csproj ├── DebuggerShim.cs ├── Features │ └── StagerCanRunBuilderSpec.cs ├── Fixtures │ ├── apps │ │ ├── no-app │ │ │ └── TextFile.txt │ │ ├── run-procfile │ │ │ ├── Procfile │ │ │ └── custom.bat │ │ └── run │ │ │ └── run.bat │ └── buildpacks │ │ ├── nop-buildpack │ │ └── bin │ │ │ ├── compile.bat │ │ │ ├── detect.bat │ │ │ └── release.bat │ │ └── run-buildpack │ │ └── bin │ │ ├── compile.bat │ │ ├── detect.bat │ │ └── release.bat ├── Properties │ ├── AssemblyInfo.cs │ ├── Resources.Designer.cs │ └── Resources.resx ├── Resources │ └── bsdtar.exe ├── Specs │ └── TarGZFileTest.cs ├── app.config ├── app │ ├── Controllers │ │ └── InstancesController.cs │ ├── Global.asax │ ├── Global.asax.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── README.md │ ├── Web.Debug.config │ ├── Web.Release.config │ ├── Web.config │ ├── favicon.ico │ ├── nora.csproj │ └── packages.config └── packages.config ├── Builder ├── App.config ├── Builder.csproj ├── Options.cs ├── OutputMetadata.cs ├── Program.cs ├── Properties │ ├── AssemblyInfo.cs │ ├── Resources.Designer.cs │ └── Resources.resx ├── Resources │ └── bsdtar.exe ├── TarGZFile.cs └── packages.config ├── LICENSE ├── Launcher.Tests ├── ArgumentEscaper.cs ├── DebuggerShim.cs ├── Features │ └── LauncherCanRunStartCommandSpec.cs ├── Fixtures │ ├── CivetCat.bat │ └── Exit.bat ├── Launcher.Tests.csproj ├── Properties │ └── AssemblyInfo.cs ├── Specs │ └── IntegrationSpec.cs └── packages.config ├── Launcher ├── App.config ├── Launcher.csproj ├── Program.cs ├── Properties │ └── AssemblyInfo.cs └── packages.config ├── NOTICE ├── README.md ├── Web.config ├── WebAppServer.Tests ├── DebuggerShim.cs ├── Features │ └── WebAppServerHostsNetAppSpec.cs ├── Fixtures │ ├── ASP-classic │ │ ├── Web.config │ │ └── default.asp │ └── Nora │ │ ├── Global.asax │ │ ├── Web.config │ │ ├── bin │ │ ├── Newtonsoft.Json.dll │ │ ├── Nora.dll │ │ ├── System.Net.Http.Formatting.dll │ │ ├── System.Web.Http.WebHost.dll │ │ └── System.Web.Http.dll │ │ └── packages.config ├── Properties │ └── AssemblyInfo.cs ├── Specs │ ├── OptionsTest.cs │ ├── ProgramTest.cs │ └── WebConfigTest.cs ├── Test.nunit ├── WebAppServer.Tests.csproj ├── app.config └── packages.config ├── WebAppServer ├── ConfigGenerator.cs ├── Constants.cs ├── Logger.cs ├── Options.cs ├── Program.cs ├── Properties │ ├── AssemblyInfo.cs │ ├── Resources.Designer.cs │ └── Resources.resx ├── Readme.txt ├── Resources │ ├── applicationhost.config │ ├── aspnet.config │ └── v2.0AppHost.config ├── WebAppServer.csproj ├── WebConfig.cs ├── WebCoreActivationException.cs ├── WebServer.cs └── XmlExtensions.cs ├── WindowsAppLifecycle.sln ├── appveyor.yml ├── bin ├── bsdtar.exe └── nuget.exe ├── scripts └── make.bat └── vendor ├── CommandLineParser.1.9.71.nupkg ├── Newtonsoft.Json.8.0.3.nupkg ├── YamlDotNet.3.8.0.nupkg └── nspec.0.9.68.nupkg /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | windows_app_lifecycle*.tgz 5 | diego-sshd.exe 6 | 7 | # User-specific files 8 | *.suo 9 | *.user 10 | *.sln.docstates 11 | 12 | # Build results 13 | 14 | [Dd]ebug/ 15 | [Rr]elease/ 16 | x64/ 17 | build/ 18 | [Bb]in/ 19 | [Oo]bj/ 20 | 21 | # Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets 22 | !packages/*/build/ 23 | 24 | # MSTest test Results 25 | [Tt]est[Rr]esult*/ 26 | [Bb]uild[Ll]og.* 27 | 28 | *_i.c 29 | *_p.c 30 | *.ilk 31 | *.meta 32 | *.obj 33 | *.pch 34 | *.pdb 35 | *.pgc 36 | *.pgd 37 | *.rsp 38 | *.sbr 39 | *.tlb 40 | *.tli 41 | *.tlh 42 | *.tmp 43 | *.tmp_proj 44 | *.log 45 | *.vspscc 46 | *.vssscc 47 | .builds 48 | *.pidb 49 | *.log 50 | *.scc 51 | 52 | # Visual C++ cache files 53 | ipch/ 54 | *.aps 55 | *.ncb 56 | *.opensdf 57 | *.sdf 58 | *.cachefile 59 | 60 | # Visual Studio profiler 61 | *.psess 62 | *.vsp 63 | *.vspx 64 | 65 | # Guidance Automation Toolkit 66 | *.gpState 67 | 68 | # ReSharper is a .NET coding add-in 69 | _ReSharper*/ 70 | *.[Rr]e[Ss]harper 71 | 72 | # TeamCity is a build add-in 73 | _TeamCity* 74 | 75 | # DotCover is a Code Coverage Tool 76 | *.dotCover 77 | 78 | # NCrunch 79 | *.ncrunch* 80 | .*crunch*.local.xml 81 | 82 | # Installshield output folder 83 | [Ee]xpress/ 84 | 85 | # DocProject is a documentation generator add-in 86 | DocProject/buildhelp/ 87 | DocProject/Help/*.HxT 88 | DocProject/Help/*.HxC 89 | DocProject/Help/*.hhc 90 | DocProject/Help/*.hhk 91 | DocProject/Help/*.hhp 92 | DocProject/Help/Html2 93 | DocProject/Help/html 94 | 95 | # Click-Once directory 96 | publish/ 97 | 98 | # Publish Web Output 99 | *.Publish.xml 100 | 101 | # NuGet Packages Directory 102 | ## TODO: If you have NuGet Package Restore enabled, uncomment the next line 103 | packages/ 104 | 105 | # Windows Azure Build Output 106 | csx 107 | *.build.csdef 108 | 109 | # Windows Store app package directory 110 | AppPackages/ 111 | 112 | # Others 113 | sql/ 114 | *.Cache 115 | ClientBin/ 116 | [Ss]tyle[Cc]op.* 117 | ~$* 118 | *~ 119 | *.dbmdl 120 | *.[Pp]ublish.xml 121 | *.pfx 122 | *.publishsettings 123 | 124 | # RIA/Silverlight projects 125 | Generated_Code/ 126 | 127 | # Backup & report files from converting an old project file to a newer 128 | # Visual Studio version. Backup files are not needed, because we have git ;-) 129 | _UpgradeReport_Files/ 130 | Backup*/ 131 | UpgradeLog*.XML 132 | UpgradeLog*.htm 133 | 134 | # SQL Server files 135 | App_Data/*.mdf 136 | App_Data/*.ldf 137 | 138 | 139 | #LightSwitch generated files 140 | GeneratedArtifacts/ 141 | _Pvt_Extensions/ 142 | ModelManifest.xml 143 | 144 | # ========================= 145 | # Windows detritus 146 | # ========================= 147 | 148 | # Windows image file caches 149 | Thumbs.db 150 | ehthumbs.db 151 | 152 | # Folder config file 153 | Desktop.ini 154 | 155 | # Recycle Bin used on file shares 156 | $RECYCLE.BIN/ 157 | 158 | # Mac desktop service store files 159 | .DS_Store 160 | 161 | 162 | # Exception to fixtures 163 | !/Builder.Tests/Fixtures/**/* -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudfoundry-attic/windows_app_lifecycle/686f5c2e682410b23c29163bd02765ace79a60a6/.gitmodules -------------------------------------------------------------------------------- /.nuget/NuGet.Config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /.nuget/NuGet.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudfoundry-attic/windows_app_lifecycle/686f5c2e682410b23c29163bd02765ace79a60a6/.nuget/NuGet.exe -------------------------------------------------------------------------------- /.nuget/NuGet.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | $(MSBuildProjectDirectory)\..\ 5 | 6 | 7 | false 8 | 9 | 10 | false 11 | 12 | 13 | true 14 | 15 | 16 | false 17 | 18 | 19 | 20 | 21 | 22 | 26 | 27 | 28 | 29 | 30 | $([System.IO.Path]::Combine($(SolutionDir), ".nuget")) 31 | 32 | 33 | 34 | 35 | $(SolutionDir).nuget 36 | 37 | 38 | 39 | $(MSBuildProjectDirectory)\packages.$(MSBuildProjectName.Replace(' ', '_')).config 40 | $(MSBuildProjectDirectory)\packages.$(MSBuildProjectName).config 41 | 42 | 43 | 44 | $(MSBuildProjectDirectory)\packages.config 45 | $(PackagesProjectConfig) 46 | 47 | 48 | 49 | 50 | $(NuGetToolsPath)\NuGet.exe 51 | @(PackageSource) 52 | 53 | "$(NuGetExePath)" 54 | mono --runtime=v4.0.30319 "$(NuGetExePath)" 55 | 56 | $(TargetDir.Trim('\\')) 57 | 58 | -RequireConsent 59 | -NonInteractive 60 | 61 | "$(SolutionDir) " 62 | "$(SolutionDir)" 63 | 64 | 65 | $(NuGetCommand) install "$(PackagesConfig)" -source "$(PackageSources)" $(NonInteractiveSwitch) $(RequireConsentSwitch) -solutionDir $(PaddedSolutionDir) 66 | $(NuGetCommand) pack "$(ProjectPath)" -Properties "Configuration=$(Configuration);Platform=$(Platform)" $(NonInteractiveSwitch) -OutputDirectory "$(PackageOutputDir)" -symbols 67 | 68 | 69 | 70 | RestorePackages; 71 | $(BuildDependsOn); 72 | 73 | 74 | 75 | 76 | $(BuildDependsOn); 77 | BuildPackage; 78 | 79 | 80 | 81 | 82 | 83 | 84 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 99 | 100 | 103 | 104 | 105 | 106 | 108 | 109 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 141 | 142 | 143 | 144 | 145 | -------------------------------------------------------------------------------- /Builder.Tests/Builder.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | AnyCPU 6 | {2FE7925C-AC3E-4103-BF03-2D22F3D88610} 7 | Library 8 | Properties 9 | Builder.Tests 10 | BuilderTests 11 | v4.5 12 | 512 13 | {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 14 | 10.0 15 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) 16 | $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages 17 | False 18 | UnitTest 19 | 20 | ..\ 21 | true 22 | 23 | 24 | true 25 | full 26 | false 27 | bin\Debug\ 28 | DEBUG;TRACE 29 | prompt 30 | 4 31 | 32 | 33 | pdbonly 34 | true 35 | bin\Release\ 36 | TRACE 37 | prompt 38 | 4 39 | 40 | 41 | 42 | ..\packages\Newtonsoft.Json.8.0.3\lib\net45\Newtonsoft.Json.dll 43 | True 44 | 45 | 46 | ..\packages\nspec.0.9.68\lib\NSpec.dll 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | True 66 | True 67 | Resources.resx 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | PreserveNewest 76 | 77 | 78 | PreserveNewest 79 | 80 | 81 | PreserveNewest 82 | 83 | 84 | PreserveNewest 85 | 86 | 87 | PreserveNewest 88 | 89 | 90 | PreserveNewest 91 | 92 | 93 | PreserveNewest 94 | 95 | 96 | PreserveNewest 97 | 98 | 99 | 100 | 101 | 102 | {68f6a408-b0f2-4bb4-a0a4-278694fab63d} 103 | Builder 104 | 105 | 106 | 107 | 108 | ResXFileCodeGenerator 109 | Resources.Designer.cs 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | PreserveNewest 119 | 120 | 121 | 122 | 123 | PreserveNewest 124 | 125 | 126 | 127 | 128 | 129 | 130 | False 131 | 132 | 133 | False 134 | 135 | 136 | False 137 | 138 | 139 | False 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. 150 | 151 | 152 | 153 | 160 | -------------------------------------------------------------------------------- /Builder.Tests/DebuggerShim.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using System.Reflection; 3 | using NSpec; 4 | using NSpec.Domain; 5 | using NSpec.Domain.Formatters; 6 | 7 | /* 8 | * Howdy, 9 | * 10 | * This is NSpec's DebuggerShim. It will allow you to use TestDriven.Net or Resharper's test runner to run 11 | * NSpec tests that are in the same Assembly as this class. 12 | * 13 | * It's DEFINITELY worth trying specwatchr (http://nspec.org/continuoustesting). Specwatchr automatically 14 | * runs tests for you. 15 | * 16 | * If you ever want to debug a test when using Specwatchr, simply put the following line in your test: 17 | * 18 | * System.Diagnostics.Debugger.Launch() 19 | * 20 | * Visual Studio will detect this and will give you a window which you can use to attach a debugger. 21 | */ 22 | 23 | //[TestFixture] 24 | public class DebuggerShim 25 | { 26 | //[Test] 27 | public void debug() 28 | { 29 | var tagOrClassName = "class_or_tag_you_want_to_debug"; 30 | 31 | var types = GetType().Assembly.GetTypes(); 32 | // OR 33 | // var types = new Type[]{typeof(Some_Type_Containg_some_Specs)}; 34 | var finder = new SpecFinder(types, ""); 35 | var builder = new ContextBuilder(finder, new Tags().Parse(tagOrClassName), new DefaultConventions()); 36 | var runner = new ContextRunner(builder, new ConsoleFormatter(), false); 37 | var results = runner.Run(builder.Contexts().Build()); 38 | 39 | //assert that there aren't any failures 40 | results.Failures().Count().should_be(0); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Builder.Tests/Fixtures/apps/no-app/TextFile.txt: -------------------------------------------------------------------------------- 1 | dummy text -------------------------------------------------------------------------------- /Builder.Tests/Fixtures/apps/run-procfile/Procfile: -------------------------------------------------------------------------------- 1 | web: custom.bat -------------------------------------------------------------------------------- /Builder.Tests/Fixtures/apps/run-procfile/custom.bat: -------------------------------------------------------------------------------- 1 | echo App ran successfully. Exiting. -------------------------------------------------------------------------------- /Builder.Tests/Fixtures/apps/run/run.bat: -------------------------------------------------------------------------------- 1 | echo App ran successfully. Exiting. -------------------------------------------------------------------------------- /Builder.Tests/Fixtures/buildpacks/nop-buildpack/bin/compile.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | set build_path=%1 3 | set cache_path=%2 4 | :: do whatever is needed for the application to run 5 | 6 | echo Nothing to do ... 7 | echo Done. 8 | 9 | exit /b 0 10 | -------------------------------------------------------------------------------- /Builder.Tests/Fixtures/buildpacks/nop-buildpack/bin/detect.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | set app_dir=%1 3 | :: detect if buildpack supports this application 4 | 5 | echo Nop Buildpack 6 | exit /b 0 -------------------------------------------------------------------------------- /Builder.Tests/Fixtures/buildpacks/nop-buildpack/bin/release.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | :: output valid yaml containing the start command 3 | 4 | echo --- 5 | echo default_process_types: [] 6 | -------------------------------------------------------------------------------- /Builder.Tests/Fixtures/buildpacks/run-buildpack/bin/compile.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | set build_path=%1 3 | set cache_path=%2 4 | :: do whatever is needed for the application to run 5 | 6 | echo Nothing to do ... 7 | echo No error 1>&2 8 | echo touch > %build_path%\compite-touch.txt 9 | echo touch > %cache_path%\compite-touch.txt 10 | echo Done. 11 | 12 | exit /b 0 13 | -------------------------------------------------------------------------------- /Builder.Tests/Fixtures/buildpacks/run-buildpack/bin/detect.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | set app_dir=%1 3 | :: detect if buildpack supports this application 4 | 5 | if exist "%app_dir%\run.bat" ( 6 | echo Run Buildpack 7 | exit /b 0 8 | ) else ( 9 | exit /b 1 10 | ) 11 | -------------------------------------------------------------------------------- /Builder.Tests/Fixtures/buildpacks/run-buildpack/bin/release.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | :: output valid yaml containing the start command 3 | 4 | echo --- 5 | echo default_process_types: 6 | echo web: run.bat 7 | -------------------------------------------------------------------------------- /Builder.Tests/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("Builder.Tests")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("Builder.Tests")] 13 | [assembly: AssemblyCopyright("Copyright © 2014")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("fa81399a-4b34-452b-8df4-e06a9f981cce")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /Builder.Tests/Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace Builder.Tests.Properties { 12 | using System; 13 | 14 | 15 | /// 16 | /// A strongly-typed resource class, for looking up localized strings, etc. 17 | /// 18 | // This class was auto-generated by the StronglyTypedResourceBuilder 19 | // class via a tool like ResGen or Visual Studio. 20 | // To add or remove a member, edit your .ResX file then rerun ResGen 21 | // with the /str option, or rebuild your VS project. 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class Resources { 26 | 27 | private static global::System.Resources.ResourceManager resourceMan; 28 | 29 | private static global::System.Globalization.CultureInfo resourceCulture; 30 | 31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 32 | internal Resources() { 33 | } 34 | 35 | /// 36 | /// Returns the cached ResourceManager instance used by this class. 37 | /// 38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 39 | internal static global::System.Resources.ResourceManager ResourceManager { 40 | get { 41 | if (object.ReferenceEquals(resourceMan, null)) { 42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Builder.Tests.Properties.Resources", typeof(Resources).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// Overrides the current thread's CurrentUICulture property for all 51 | /// resource lookups using this strongly typed resource class. 52 | /// 53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 54 | internal static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | 63 | /// 64 | /// Looks up a localized resource of type System.Byte[]. 65 | /// 66 | internal static byte[] bsdtar { 67 | get { 68 | object obj = ResourceManager.GetObject("bsdtar", resourceCulture); 69 | return ((byte[])(obj)); 70 | } 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /Builder.Tests/Properties/Resources.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | 122 | ..\Resources\bsdtar.exe;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 123 | 124 | -------------------------------------------------------------------------------- /Builder.Tests/Resources/bsdtar.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudfoundry-attic/windows_app_lifecycle/686f5c2e682410b23c29163bd02765ace79a60a6/Builder.Tests/Resources/bsdtar.exe -------------------------------------------------------------------------------- /Builder.Tests/Specs/TarGZFileTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.Linq; 4 | using System.Reflection; 5 | using Builder.Tests.Properties; 6 | using NSpec; 7 | using System.IO; 8 | 9 | namespace Builder.Tests 10 | { 11 | class TarGZFileTest : nspec 12 | { 13 | string tgzPath, tmpDir, extractDir; 14 | private static string TarArchiverPath(string filename) 15 | { 16 | var uri = new Uri(Assembly.GetExecutingAssembly().CodeBase); 17 | return Path.Combine(Path.GetDirectoryName(uri.LocalPath), filename); 18 | } 19 | 20 | void before_all() 21 | { 22 | File.WriteAllBytes(TarArchiverPath("tar.exe"), Resources.bsdtar); 23 | } 24 | 25 | void before_each() { 26 | tgzPath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); 27 | tmpDir = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); 28 | Directory.CreateDirectory(tmpDir); 29 | File.WriteAllText(Path.Combine(tmpDir, "a_file.txt"), "Some exciting text"); 30 | Directory.CreateDirectory(Path.Combine(tmpDir, "a dir")); 31 | File.WriteAllText(Path.Combine(tmpDir, "a dir", "another_file.txt"), "Some spacey text"); 32 | } 33 | 34 | void after_each() 35 | { 36 | Directory.Delete(tmpDir, true); 37 | if (Directory.Exists(extractDir)) 38 | { 39 | Directory.Delete(extractDir, true); 40 | } 41 | if (File.Exists(tgzPath)) 42 | { 43 | File.Delete(tgzPath); 44 | } 45 | } 46 | 47 | private void describe_CreateFromDirectory() 48 | { 49 | it["creates the tgz file"] = () => 50 | { 51 | TarGZFile.CreateFromDirectory(tmpDir, tgzPath); 52 | File.Exists(tgzPath).should_be_true(); 53 | }; 54 | 55 | it["puts the files inside the file"] = () => 56 | { 57 | TarGZFile.CreateFromDirectory(tmpDir, tgzPath); 58 | 59 | var process = new Process(); 60 | var processStartInfo = process.StartInfo; 61 | processStartInfo.FileName = TarArchiverPath("tar.exe"); 62 | processStartInfo.Arguments = "tf " + tgzPath; 63 | processStartInfo.RedirectStandardOutput = true; 64 | processStartInfo.UseShellExecute = false; 65 | process.Start(); 66 | process.WaitForExit(); 67 | var fileNames = process.StandardOutput.ReadToEnd(); 68 | fileNames.should_contain(Path.GetFileName(tmpDir) + "/a_file.txt"); 69 | fileNames.should_contain(Path.GetFileName(tmpDir) + "/a dir/another_file.txt"); 70 | }; 71 | 72 | it["can deal with Unicode in filenames"] = () => 73 | { 74 | File.WriteAllText(Path.Combine(tmpDir, "新闻.txt"), "Chinese news"); 75 | extractDir = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); 76 | Directory.CreateDirectory(extractDir); 77 | 78 | TarGZFile.CreateFromDirectory(tmpDir, tgzPath); 79 | 80 | var process = new Process(); 81 | var processStartInfo = process.StartInfo; 82 | processStartInfo.FileName = TarArchiverPath("tar.exe"); 83 | processStartInfo.Arguments = "xf " + tgzPath + " -C " + extractDir; 84 | processStartInfo.UseShellExecute = false; 85 | process.Start(); 86 | process.WaitForExit(); 87 | var fileNames = Directory.EnumerateFiles(extractDir, "*", SearchOption.AllDirectories).ToList(); 88 | fileNames.should_contain(Path.Combine(extractDir, Path.GetFileName(tmpDir)) + @"\新闻.txt"); 89 | }; 90 | } 91 | } 92 | } 93 | 94 | 95 | 96 | -------------------------------------------------------------------------------- /Builder.Tests/app.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /Builder.Tests/app/Controllers/InstancesController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Web.Http; 3 | 4 | namespace nora.Controllers 5 | { 6 | public class InstancesController : ApiController 7 | { 8 | [Route("~/")] 9 | [HttpGet] 10 | public IHttpActionResult Root() 11 | { 12 | return Ok("hello i am nora"); 13 | } 14 | 15 | [Route("~/id")] 16 | [HttpGet] 17 | public IHttpActionResult Id() 18 | { 19 | const string uuid = "A123F285-26B4-45F1-8C31-816DC5F53ECF"; 20 | return Ok(uuid); 21 | } 22 | 23 | [Route("~/env")] 24 | [HttpGet] 25 | public IHttpActionResult Env() 26 | { 27 | return Ok(Environment.GetEnvironmentVariables()); 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /Builder.Tests/app/Global.asax: -------------------------------------------------------------------------------- 1 | <%@ Application Codebehind="Global.asax.cs" Inherits="nora.WebApiApplication" Language="C#" %> -------------------------------------------------------------------------------- /Builder.Tests/app/Global.asax.cs: -------------------------------------------------------------------------------- 1 | using System.Web; 2 | using System.Web.Http; 3 | using System.Web.Mvc; 4 | using System.Web.Optimization; 5 | using System.Web.Routing; 6 | 7 | namespace nora 8 | { 9 | public class WebApiApplication : HttpApplication 10 | { 11 | protected void Application_Start() 12 | { 13 | GlobalConfiguration.Configure((config) => 14 | { 15 | // Web API configuration and services 16 | 17 | // Web API routes 18 | config.MapHttpAttributeRoutes(); 19 | 20 | config.Routes.MapHttpRoute("DefaultApi", "api/{controller}/{id}", new { id = RouteParameter.Optional }); 21 | }); 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /Builder.Tests/app/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | // General Information about an assembly is controlled through the following 5 | // set of attributes. Change these attribute values to modify the information 6 | // associated with an assembly. 7 | 8 | [assembly: AssemblyTitle("nora")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("nora")] 13 | [assembly: AssemblyCopyright("Copyright © 2014")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | 21 | [assembly: ComVisible(false)] 22 | 23 | // The following GUID is for the ID of the typelib if this project is exposed to COM 24 | 25 | [assembly: Guid("12bf6eaf-ae7e-43cb-8363-b686f0afa644")] 26 | 27 | // Version information for an assembly consists of the following four values: 28 | // 29 | // Major Version 30 | // Minor Version 31 | // Build Number 32 | // Revision 33 | // 34 | // You can specify all the values or you can default the Revision and Build Numbers 35 | // by using the '*' as shown below: 36 | 37 | [assembly: AssemblyVersion("1.0.0.0")] 38 | [assembly: AssemblyFileVersion("1.0.0.0")] -------------------------------------------------------------------------------- /Builder.Tests/app/README.md: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /Builder.Tests/app/Web.Debug.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 17 | 18 | 29 | 30 | -------------------------------------------------------------------------------- /Builder.Tests/app/Web.Release.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 17 | 18 | 19 | 30 | 31 | -------------------------------------------------------------------------------- /Builder.Tests/app/Web.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 7 | 8 | 9 | 10 |
13 | 14 | 15 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /Builder.Tests/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudfoundry-attic/windows_app_lifecycle/686f5c2e682410b23c29163bd02765ace79a60a6/Builder.Tests/app/favicon.ico -------------------------------------------------------------------------------- /Builder.Tests/app/nora.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | 8 | 9 | 2.0 10 | {5FC9E271-52AB-4707-A3C1-23C7AB909ACA} 11 | {349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} 12 | Library 13 | Properties 14 | nora 15 | nora 16 | v4.5 17 | false 18 | true 19 | 20 | 21 | 22 | 23 | 24 | 25 | true 26 | full 27 | false 28 | bin\ 29 | DEBUG;TRACE 30 | prompt 31 | 4 32 | 33 | 34 | pdbonly 35 | true 36 | bin\ 37 | TRACE 38 | prompt 39 | 4 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | ..\packages\Microsoft.AspNet.WebApi.Client.5.2.2\lib\net45\System.Net.Http.Formatting.dll 52 | 53 | 54 | ..\packages\Microsoft.AspNet.WebApi.Core.5.2.2\lib\net45\System.Web.Http.dll 55 | 56 | 57 | ..\packages\Microsoft.AspNet.WebApi.WebHost.5.2.2\lib\net45\System.Web.Http.WebHost.dll 58 | 59 | 60 | True 61 | ..\packages\Microsoft.AspNet.Mvc.5.2.2\lib\net45\System.Web.Mvc.dll 62 | 63 | 64 | ..\packages\Microsoft.AspNet.Web.Optimization.1.1.3\lib\net40\System.Web.Optimization.dll 65 | 66 | 67 | 68 | 69 | ..\packages\EntityFramework.6.1.1\lib\net45\EntityFramework.dll 70 | 71 | 72 | ..\packages\EntityFramework.6.1.1\lib\net45\EntityFramework.SqlServer.dll 73 | 74 | 75 | ..\packages\Microsoft.Owin.Security.OAuth.3.0.0\lib\net45\Microsoft.Owin.Security.OAuth.dll 76 | 77 | 78 | ..\packages\Microsoft.AspNet.WebApi.Owin.5.2.2\lib\net45\System.Web.Http.Owin.dll 79 | 80 | 81 | 82 | 83 | 84 | Global.asax 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | Web.config 94 | 95 | 96 | Web.config 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 10.0 108 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | True 121 | True 122 | 57239 123 | / 124 | http://localhost:55408/ 125 | False 126 | False 127 | 128 | 129 | False 130 | 131 | 132 | 133 | 134 | 140 | -------------------------------------------------------------------------------- /Builder.Tests/app/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /Builder.Tests/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /Builder/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /Builder/Builder.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {68F6A408-B0F2-4BB4-A0A4-278694FAB63D} 8 | Exe 9 | Properties 10 | Builder 11 | builder 12 | v4.5 13 | 512 14 | 15 | ..\ 16 | true 17 | d326f9dd 18 | 19 | 20 | AnyCPU 21 | true 22 | full 23 | false 24 | bin\ 25 | DEBUG;TRACE 26 | prompt 27 | 4 28 | false 29 | 30 | 31 | AnyCPU 32 | pdbonly 33 | true 34 | bin\ 35 | TRACE 36 | prompt 37 | 4 38 | false 39 | false 40 | 41 | 42 | 43 | ..\packages\CommandLineParser.1.9.71\lib\net45\CommandLine.dll 44 | 45 | 46 | ..\packages\Newtonsoft.Json.8.0.3\lib\net45\Newtonsoft.Json.dll 47 | True 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | ..\packages\YamlDotNet.3.8.0\lib\net35\YamlDotNet.dll 56 | True 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | True 66 | True 67 | Resources.resx 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | ResXFileCodeGenerator 78 | Resources.Designer.cs 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. 89 | 90 | 91 | 92 | 99 | -------------------------------------------------------------------------------- /Builder/Options.cs: -------------------------------------------------------------------------------- 1 | using CommandLine; 2 | using CommandLine.Text; 3 | 4 | namespace Builder 5 | { 6 | public enum OptionBool 7 | { 8 | False, 9 | True 10 | } 11 | 12 | public class Options 13 | { 14 | [Option("buildDir", Required = true)] 15 | public string BuildDir { get; set; } 16 | 17 | [Option("buildArtifactsCacheDir", Required = false)] 18 | public string BuildArtifactsCacheDir { get; set; } 19 | 20 | [Option("buildpackOrder", Required = false)] 21 | public string BuildpackOrder { get; set; } 22 | 23 | [Option("buildpacksDir", Required = false)] 24 | public string BuildpacksDir { get; set; } 25 | 26 | [Option("outputBuildArtifactsCache", Required = false)] 27 | public string OutputBuildArtifactsCache { get; set; } 28 | 29 | [Option("outputDroplet", Required = true)] 30 | public string OutputDroplet { get; set; } 31 | 32 | [Option("outputMetadata", Required = true)] 33 | public string OutputMetadata { get; set; } 34 | 35 | [Option("skipDetect", Required = false, DefaultValue = OptionBool.False)] 36 | public OptionBool SkipDetect { get; set; } 37 | 38 | [Option("skipCertVerify", Required = false)] 39 | public OptionBool SkipCertVerify { get; set; } 40 | 41 | 42 | [HelpOption] 43 | public string GetUsage() 44 | { 45 | return HelpText.AutoBuild(this, 46 | (HelpText current) => HelpText.DefaultParsingErrorsHandler(this, current)); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /Builder/OutputMetadata.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Newtonsoft.Json; 3 | using YamlDotNet.Serialization; 4 | using System.Collections.Generic; 5 | 6 | namespace Builder 7 | { 8 | // Structure validation here: 9 | // https://github.com/cloudfoundry/cloud_controller_ng/blob/f418b7cc273a410b39938fc9a46d9d94f591d887/lib/cloud_controller/diego/buildpack/staging_completion_handler.rb#L11-L25 10 | public class OutputMetadata 11 | { 12 | [JsonProperty("lifecycle_type")] 13 | public string LifecycleType { get; set; } 14 | 15 | [JsonProperty("lifecycle_metadata")] 16 | public LifecycleMetadata LifecycleMetadata { get; set; } 17 | 18 | [JsonProperty("process_types")] 19 | public Dictionary ProcessTypes { get; set; } 20 | 21 | [JsonProperty("execution_metadata")] 22 | public string ExecutionMetadata { get; set; } 23 | } 24 | 25 | public class LifecycleMetadata 26 | { 27 | [JsonProperty("buildpack_key")] 28 | public string BuildpackKey { get; set; } 29 | 30 | [JsonProperty("detected_buildpack")] 31 | public string DetectedBuildpack { get; set; } 32 | } 33 | 34 | public class ReleaseInfo 35 | { 36 | [YamlMember(Alias = "default_process_types")] 37 | public Dictionary defaultProcessTypes { get; set; } 38 | } 39 | } -------------------------------------------------------------------------------- /Builder/Program.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Diagnostics; 5 | using System.Globalization; 6 | using System.IO; 7 | using System.IO.Compression; 8 | using System.Linq; 9 | using System.Net; 10 | using System.Net.Security; 11 | using System.Security.Cryptography; 12 | using System.Text; 13 | using YamlDotNet.Serialization; 14 | 15 | namespace Builder 16 | { 17 | public class Program 18 | { 19 | private static string[] buildpackBinaries = new string[] { "detect", "compile", "release" }; 20 | 21 | private static string[] binariesExtensions = new string[] { ".EXE", ".BAT", ".CMD" }; 22 | 23 | private static bool IsWindowsBuildpack(string buildpackDir) 24 | { 25 | foreach (var app in buildpackBinaries) 26 | { 27 | bool found = false; 28 | foreach (string ext in binariesExtensions) 29 | { 30 | if (File.Exists(Path.Combine(buildpackDir, "bin", app + ext))) 31 | { 32 | found = true; 33 | } 34 | } 35 | if (!found) 36 | { 37 | return false; 38 | } 39 | } 40 | return true; 41 | } 42 | 43 | private static string GetExecutable(string path, string file) 44 | { 45 | foreach (string ext in binariesExtensions) 46 | { 47 | if (File.Exists(Path.Combine(path, file + ext))) 48 | { 49 | return Path.Combine(path, file + ext); 50 | } 51 | } 52 | 53 | throw new Exception(String.Format("No executable found for '{0}' in '{1}'", file, path)); 54 | } 55 | 56 | private static int RunBuildpackProcess(string path, string args, TextWriter outputStream, TextWriter errorStream) 57 | { 58 | var p = new Process(); 59 | p.StartInfo.FileName = path; 60 | p.StartInfo.Arguments = args; 61 | p.StartInfo.UseShellExecute = false; 62 | p.StartInfo.CreateNoWindow = true; 63 | p.StartInfo.RedirectStandardOutput = true; 64 | p.StartInfo.RedirectStandardError = true; 65 | 66 | p.OutputDataReceived += (object sender, DataReceivedEventArgs e) => 67 | { 68 | outputStream.WriteLine(e.Data); 69 | }; 70 | p.ErrorDataReceived += (object sender, DataReceivedEventArgs e) => 71 | { 72 | errorStream.WriteLine(e.Data); 73 | }; 74 | p.Start(); 75 | p.BeginOutputReadLine(); 76 | p.BeginErrorReadLine(); 77 | p.WaitForExit(); 78 | 79 | return p.ExitCode; 80 | } 81 | 82 | private static string GetBuildpackDirName(string buildpackName) 83 | { 84 | using (MD5 md5Hash = MD5.Create()) 85 | { 86 | byte[] data = md5Hash.ComputeHash(Encoding.UTF8.GetBytes(buildpackName)); 87 | return BitConverter.ToString(data).Replace("-", ""); 88 | } 89 | } 90 | 91 | private static void SanitizeArgs(string[] args) 92 | { 93 | for (int i = 0; i < args.Length; i++) 94 | { 95 | if (args[i].StartsWith("-") && !args[i].StartsWith("--")) 96 | { 97 | args[i] = "-" + args[i]; 98 | } 99 | } 100 | } 101 | 102 | private static Dictionary GetProcfileProcessTypes(List files) 103 | { 104 | var procfiles = files.Where(x => Path.GetFileName(x).ToLower() == "procfile").ToList(); 105 | 106 | if (procfiles.Any()) 107 | { 108 | using (var procfileStream = new StreamReader(procfiles.First())) 109 | { 110 | return new Deserializer().Deserialize>(procfileStream); 111 | } 112 | } 113 | else 114 | { 115 | return null; 116 | } 117 | } 118 | 119 | private static void DownloadAndExtractZip(Uri source, string destination) 120 | { 121 | var tlsIgnoreFailureCallback = new RemoteCertificateValidationCallback(delegate { return true; }); 122 | string tempFile = null; 123 | 124 | try 125 | { 126 | tempFile = Path.GetTempFileName(); 127 | 128 | using (var webClient = new WebClient()) 129 | { 130 | webClient.DownloadFile(source, tempFile); 131 | } 132 | 133 | ZipFile.ExtractToDirectory(tempFile, destination); 134 | } 135 | finally 136 | { 137 | if (tempFile != null) 138 | { 139 | File.Delete(tempFile); 140 | } 141 | } 142 | } 143 | 144 | private static bool IsZipBuildpack(string filename) 145 | { 146 | return filename.EndsWith(".zip", false, CultureInfo.InvariantCulture); 147 | } 148 | 149 | private static void DownloadBuildpacks(string[] buildpacks, string buildpacksDir) 150 | { 151 | foreach (var buildpackName in buildpacks) 152 | { 153 | Uri downloadUri = null; 154 | var downloadableBuildoack = Uri.TryCreate(buildpackName, UriKind.Absolute, out downloadUri); 155 | if (downloadableBuildoack) 156 | { 157 | var buildpackDir = Path.Combine(buildpacksDir, GetBuildpackDirName(buildpackName)); 158 | if (IsZipBuildpack(buildpackName)) 159 | { 160 | DownloadAndExtractZip(downloadUri, buildpackDir); 161 | } 162 | } 163 | } 164 | } 165 | 166 | static void Main(string[] args) 167 | { 168 | SanitizeArgs(args); 169 | var options = new Options(); 170 | if (!CommandLine.Parser.Default.ParseArguments(args, options)) 171 | { 172 | Environment.Exit(1); 173 | } 174 | 175 | Run(options); 176 | } 177 | 178 | private static void Run(Options options) 179 | { 180 | var rootDir = Directory.GetCurrentDirectory(); 181 | 182 | var appPath = rootDir + options.BuildDir; 183 | var buildpacksDir = rootDir + options.BuildpacksDir; 184 | 185 | var buildCacheDir = rootDir + options.BuildArtifactsCacheDir; 186 | Directory.CreateDirectory(buildCacheDir); 187 | 188 | var outputCache = rootDir + options.OutputBuildArtifactsCache; 189 | var outputDropletPath = rootDir + options.OutputDroplet; 190 | 191 | string detectedBuildpack = ""; 192 | string detectedBuildpackDir = ""; 193 | string detectOutput = ""; 194 | bool buildpackDetected = false; 195 | 196 | var buildpacks = new string[0]; 197 | if (options.BuildpackOrder != null) 198 | { 199 | buildpacks = options.BuildpackOrder.Split(new char[] { ',' }); 200 | } 201 | 202 | DownloadBuildpacks(buildpacks, buildpacksDir); 203 | 204 | foreach (var buildpackName in buildpacks) 205 | { 206 | var buildpackDir = Path.Combine(buildpacksDir, GetBuildpackDirName(buildpackName)); 207 | 208 | if (!IsWindowsBuildpack(buildpackDir)) 209 | { 210 | continue; 211 | } 212 | 213 | if (options.SkipDetect == OptionBool.False) 214 | { 215 | var detectPath = GetExecutable(Path.Combine(buildpackDir, "bin"), "detect"); 216 | 217 | var outputStream = new StringWriter(); 218 | var exitCode = RunBuildpackProcess(detectPath, appPath, outputStream, Console.Error); 219 | detectOutput = outputStream.ToString(); 220 | 221 | detectOutput = detectOutput.TrimEnd(new char[] { '\n', '\r' }); 222 | 223 | if (exitCode == 0) 224 | { 225 | detectedBuildpack = buildpackName; 226 | detectedBuildpackDir = buildpackDir; 227 | buildpackDetected = true; 228 | break; 229 | } 230 | } 231 | else 232 | { 233 | detectedBuildpack = buildpackName; 234 | detectedBuildpackDir = buildpackDir; 235 | buildpackDetected = true; 236 | break; 237 | } 238 | } 239 | 240 | if (!buildpackDetected) 241 | { 242 | Console.WriteLine("None of the buildpacks detected a compatible application"); 243 | Environment.Exit(222); 244 | } 245 | 246 | var compilePath = GetExecutable(Path.Combine(detectedBuildpackDir, "bin"), "compile"); 247 | 248 | var compoileExitCode = RunBuildpackProcess(compilePath, appPath + " " + buildCacheDir, Console.Out, Console.Error); 249 | if (compoileExitCode != 0) 250 | { 251 | Console.WriteLine("Failed to compile droplet"); 252 | Environment.Exit(223); 253 | } 254 | 255 | Dictionary procfileProcessTypes = GetProcfileProcessTypes(Directory.EnumerateFiles(appPath).ToList()); 256 | 257 | var releaseBinPath = GetExecutable(Path.Combine(detectedBuildpackDir, "bin"), "release"); 258 | 259 | var releaseStream = new StringWriter(); 260 | var releaseExitCode = RunBuildpackProcess(releaseBinPath, appPath, releaseStream, Console.Error); 261 | if (releaseExitCode != 0) 262 | { 263 | Console.WriteLine("Failed to build droplet release"); 264 | Environment.Exit(224); 265 | } 266 | 267 | var releaseOutput = releaseStream.ToString(); 268 | ReleaseInfo releaseInfo = new Deserializer(ignoreUnmatched: true).Deserialize(new StringReader(releaseOutput)); 269 | 270 | var outputMetadata = new OutputMetadata() 271 | { 272 | LifecycleType = "buildpack", 273 | LifecycleMetadata = new LifecycleMetadata() 274 | { 275 | BuildpackKey = detectedBuildpack, 276 | DetectedBuildpack = detectOutput 277 | }, 278 | ProcessTypes = procfileProcessTypes ?? releaseInfo.defaultProcessTypes, 279 | ExecutionMetadata = "" 280 | }; 281 | 282 | File.WriteAllText(rootDir + options.OutputMetadata, JsonConvert.SerializeObject(outputMetadata)); 283 | 284 | TarGZFile.CreateFromDirectory(buildCacheDir + "\\", outputCache); 285 | TarGZFile.CreateFromDirectory(appPath, outputDropletPath); 286 | } 287 | } 288 | } 289 | -------------------------------------------------------------------------------- /Builder/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("Builder")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("Builder")] 13 | [assembly: AssemblyCopyright("Copyright © 2014")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("a99915a0-03f9-4346-86fb-5164fe025038")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /Builder/Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace Builder.Properties { 12 | using System; 13 | 14 | 15 | /// 16 | /// A strongly-typed resource class, for looking up localized strings, etc. 17 | /// 18 | // This class was auto-generated by the StronglyTypedResourceBuilder 19 | // class via a tool like ResGen or Visual Studio. 20 | // To add or remove a member, edit your .ResX file then rerun ResGen 21 | // with the /str option, or rebuild your VS project. 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class Resources { 26 | 27 | private static global::System.Resources.ResourceManager resourceMan; 28 | 29 | private static global::System.Globalization.CultureInfo resourceCulture; 30 | 31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 32 | internal Resources() { 33 | } 34 | 35 | /// 36 | /// Returns the cached ResourceManager instance used by this class. 37 | /// 38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 39 | internal static global::System.Resources.ResourceManager ResourceManager { 40 | get { 41 | if (object.ReferenceEquals(resourceMan, null)) { 42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Builder.Properties.Resources", typeof(Resources).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// Overrides the current thread's CurrentUICulture property for all 51 | /// resource lookups using this strongly typed resource class. 52 | /// 53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 54 | internal static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | 63 | /// 64 | /// Looks up a localized resource of type System.Byte[]. 65 | /// 66 | internal static byte[] bsdtar { 67 | get { 68 | object obj = ResourceManager.GetObject("bsdtar", resourceCulture); 69 | return ((byte[])(obj)); 70 | } 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /Builder/Properties/Resources.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | 122 | ..\Resources\bsdtar.exe;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 123 | 124 | -------------------------------------------------------------------------------- /Builder/Resources/bsdtar.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudfoundry-attic/windows_app_lifecycle/686f5c2e682410b23c29163bd02765ace79a60a6/Builder/Resources/bsdtar.exe -------------------------------------------------------------------------------- /Builder/TarGZFile.cs: -------------------------------------------------------------------------------- 1 |  2 | using System; 3 | using System.Diagnostics; 4 | using System.IO; 5 | using System.Reflection; 6 | using Builder.Properties; 7 | 8 | namespace Builder 9 | { 10 | public class TarGZFile 11 | { 12 | private static string TarArchiverPath(string filename) 13 | { 14 | var uri = new Uri(Assembly.GetExecutingAssembly().CodeBase); 15 | return Path.Combine(Path.GetDirectoryName(uri.LocalPath), filename); 16 | } 17 | 18 | static TarGZFile() 19 | { 20 | File.WriteAllBytes(TarArchiverPath("tar.exe"), Resources.bsdtar); 21 | } 22 | 23 | public static void CreateFromDirectory(string fullSourcePath, string destinationArchiveFileName) 24 | { 25 | var parentPath = Path.GetDirectoryName(fullSourcePath); 26 | var baseName = Path.GetFileName(fullSourcePath); 27 | if (string.IsNullOrEmpty(baseName)) 28 | { 29 | baseName = "."; 30 | } 31 | 32 | var process = new Process(); 33 | var processStartInfo = process.StartInfo; 34 | processStartInfo.FileName = TarArchiverPath("tar.exe"); 35 | processStartInfo.Arguments = "czf " + destinationArchiveFileName + " -C " + parentPath + " " + baseName; 36 | processStartInfo.UseShellExecute = false; 37 | process.Start(); 38 | process.WaitForExit(); 39 | var exitCode = process.ExitCode; 40 | if (exitCode != 0) 41 | { 42 | throw new Exception("Failed to create archive"); 43 | } 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /Builder/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /Launcher.Tests/ArgumentEscaper.cs: -------------------------------------------------------------------------------- 1 | using System.Text; 2 | 3 | namespace Launcher 4 | { 5 | public static class ArgumentEscaper 6 | { 7 | public static string Escape(string[] args) 8 | { 9 | var builder = new StringBuilder(); 10 | foreach (string arg in args) 11 | { 12 | if (builder.Length > 0) 13 | builder.Append(" "); 14 | 15 | builder.Append("\"") 16 | .Append(arg.Replace("\\", "\\\\").Replace("\"", "\\\"")) 17 | .Append("\""); 18 | } 19 | return builder.ToString(); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Launcher.Tests/DebuggerShim.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using System.Reflection; 3 | using NSpec; 4 | using NSpec.Domain; 5 | using NSpec.Domain.Formatters; 6 | 7 | /* 8 | * Howdy, 9 | * 10 | * This is NSpec's DebuggerShim. It will allow you to use TestDriven.Net or Resharper's test runner to run 11 | * NSpec tests that are in the same Assembly as this class. 12 | * 13 | * It's DEFINITELY worth trying specwatchr (http://nspec.org/continuoustesting). Specwatchr automatically 14 | * runs tests for you. 15 | * 16 | * If you ever want to debug a test when using Specwatchr, simply put the following line in your test: 17 | * 18 | * System.Diagnostics.Debugger.Launch() 19 | * 20 | * Visual Studio will detect this and will give you a window which you can use to attach a debugger. 21 | */ 22 | 23 | //[TestFixture] 24 | public class DebuggerShim 25 | { 26 | //[Test] 27 | public void debug() 28 | { 29 | var tagOrClassName = "class_or_tag_you_want_to_debug"; 30 | 31 | var types = GetType().Assembly.GetTypes(); 32 | // OR 33 | // var types = new Type[]{typeof(Some_Type_Containg_some_Specs)}; 34 | var finder = new SpecFinder(types, ""); 35 | var builder = new ContextBuilder(finder, new Tags().Parse(tagOrClassName), new DefaultConventions()); 36 | var runner = new ContextRunner(builder, new ConsoleFormatter(), false); 37 | var results = runner.Run(builder.Contexts().Build()); 38 | 39 | //assert that there aren't any failures 40 | results.Failures().Count().should_be(0); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Launcher.Tests/Features/LauncherCanRunStartCommandSpec.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | using System.IO; 3 | using NSpec; 4 | using System; 5 | 6 | namespace Launcher.Tests.Features 7 | { 8 | internal class LauncherCanRunStartCommandSpec : nspec 9 | { 10 | private Process StartLauncher(params string[] args) 11 | { 12 | var startInfo = new ProcessStartInfo 13 | { 14 | Arguments = ArgumentEscaper.Escape(args), 15 | FileName = "Launcher.exe", 16 | RedirectStandardError = true, 17 | RedirectStandardOutput = true, 18 | UseShellExecute = false 19 | }; 20 | var proc = Process.Start(startInfo); 21 | proc.should_not_be_null(); 22 | proc.WaitForExit(); 23 | return proc; 24 | } 25 | 26 | private void describe_() 27 | { 28 | before = () => 29 | { 30 | var workingDirectory = Path.GetFullPath(Path.Combine(System.Reflection.Assembly.GetExecutingAssembly().CodeBase, "..").Replace("file:///", "")); 31 | Directory.SetCurrentDirectory(workingDirectory); 32 | }; 33 | 34 | after = () => File.Delete(@"Fixtures\Bean.txt"); 35 | 36 | describe["when started with insufficient arguments"] = () => 37 | { 38 | 39 | it["outputs a message onto STDERR"] = () => 40 | { 41 | var launcher = StartLauncher(); 42 | launcher.StandardError.ReadToEnd().should_contain("Launcher was run with insufficient arguments"); 43 | }; 44 | 45 | it["returns an exit code of 1"] = () => 46 | { 47 | var launcher = StartLauncher(); 48 | launcher.ExitCode.should_be(1); 49 | }; 50 | }; 51 | 52 | 53 | describe["when a start command is provided to the Launcher"] = () => 54 | { 55 | it["runs it"] = () => 56 | { 57 | StartLauncher("Fixtures", "CivetCat.bat bean1 bean2"); 58 | 59 | var beans = File.ReadAllText(@"Fixtures\Bean.txt").Split('\n'); 60 | beans[0].should_contain("bean1"); 61 | beans[1].should_contain("bean2"); 62 | }; 63 | 64 | it["returns the exit code from it"] = () => 65 | { 66 | var launcher = StartLauncher("Fixtures", @"CivetCat.bat"); 67 | launcher.ExitCode.should_be(0); 68 | 69 | launcher = StartLauncher("Fixtures", "Exit.bat 5678"); 70 | launcher.ExitCode.should_be(5678); 71 | }; 72 | 73 | it["propagates stdout from it"] = () => 74 | { 75 | var launcher = StartLauncher("Fixtures", "CivetCat.bat"); 76 | var stdout = launcher.StandardOutput.ReadToEnd(); 77 | stdout.should_contain("This is STDOUT"); 78 | }; 79 | 80 | it["propagates stderr from it"] = () => 81 | { 82 | var launcher = StartLauncher("Fixtures", "CivetCat.bat"); 83 | var stderr = launcher.StandardError.ReadToEnd(); 84 | stderr.should_contain("This is STDERR"); 85 | }; 86 | 87 | it["properly splits up arguments"] = () => 88 | { 89 | StartLauncher("Fixtures", "CivetCat.bat bean1 bean2"); 90 | 91 | var beans = File.ReadAllText(@"Fixtures\Bean.txt").Split('\n'); 92 | beans[0].should_contain("bean1"); 93 | beans[1].should_contain("bean2"); 94 | 95 | StartLauncher("Fixtures", "CivetCat.bat \"bean1 bean2\""); 96 | 97 | var beans2 = File.ReadAllText(@"Fixtures\Bean.txt").Split('\n'); 98 | beans2[0].should_contain("bean1 bean2"); 99 | }; 100 | 101 | it["works with absolute paths with quoted arguments"] = () => 102 | { 103 | StartLauncher("Fixtures", "/Fixtures/CivetCat.bat \"bean1\" \"bean2\""); 104 | 105 | var beans = File.ReadAllText(@"Fixtures\Bean.txt").Split('\n'); 106 | beans[0].should_contain("bean1"); 107 | beans[1].should_contain("bean2"); 108 | }; 109 | }; 110 | } 111 | } 112 | } -------------------------------------------------------------------------------- /Launcher.Tests/Fixtures/CivetCat.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | setlocal enabledelayedexpansion 3 | 4 | del Bean.txt 5 | 6 | set argCount=0 7 | for %%x in (%*) do ( 8 | set /A argCount+=1 9 | set "argVec[!argCount!]=%%~x" 10 | ) 11 | 12 | for /L %%i in (1,1,%argCount%) do ( 13 | echo "!argVec[%%i]!" >> Bean.txt 14 | ) 15 | 16 | echo This is STDOUT 17 | echo This is STDERR >&2 18 | -------------------------------------------------------------------------------- /Launcher.Tests/Fixtures/Exit.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | exit /b %* -------------------------------------------------------------------------------- /Launcher.Tests/Launcher.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {273733E4-6283-4E52-9CED-10EFA609EB38} 8 | Library 9 | Properties 10 | Launcher.Tests 11 | LauncherTests 12 | v4.5 13 | 512 14 | 15 | ..\ 16 | true 17 | 18 | 19 | true 20 | full 21 | false 22 | bin\Debug\ 23 | DEBUG;TRACE 24 | prompt 25 | 4 26 | 27 | 28 | pdbonly 29 | true 30 | bin\Release\ 31 | TRACE 32 | prompt 33 | 4 34 | 35 | 36 | 37 | ..\packages\Newtonsoft.Json.8.0.3\lib\net45\Newtonsoft.Json.dll 38 | True 39 | 40 | 41 | ..\packages\nspec.0.9.68\lib\NSpec.dll 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | PreserveNewest 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | {956F7FAD-B936-4ED7-9685-4D963E4CBDD6} 65 | Launcher 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. 74 | 75 | 76 | 77 | 84 | -------------------------------------------------------------------------------- /Launcher.Tests/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("Launcher.Tests")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("Launcher.Tests")] 13 | [assembly: AssemblyCopyright("Copyright © 2014")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("87cd9680-2817-4908-ab37-09b02e4b6f1f")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /Launcher.Tests/Specs/IntegrationSpec.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.IO; 5 | using System.Reflection; 6 | using Newtonsoft.Json; 7 | using NSpec; 8 | 9 | namespace Launcher.Tests.Specs 10 | { 11 | class IntegrationSpec : nspec 12 | { 13 | public static string AssemblyDirectory 14 | { 15 | get 16 | { 17 | string codeBase = Assembly.GetExecutingAssembly().CodeBase; 18 | UriBuilder uri = new UriBuilder(codeBase); 19 | string path = Uri.UnescapeDataString(uri.Path); 20 | return Path.GetDirectoryName(path); 21 | } 22 | } 23 | 24 | public void describe_() 25 | { 26 | describe["an app started with no start command"] = () => 27 | { 28 | it["prints an error message"] = () => 29 | { 30 | var startInfo = new ProcessStartInfo(AssemblyDirectory + @"\..\..\..\Launcher\bin\Launcher.exe") 31 | { 32 | Arguments = "\"\" \"\"", 33 | UseShellExecute = false, 34 | RedirectStandardError = true, 35 | RedirectStandardOutput = true, 36 | 37 | }; 38 | 39 | var process = Process.Start(startInfo); 40 | process.WaitForExit(1000); 41 | var stderr = process.StandardError.ReadToEnd(); 42 | stderr.should_contain("Could not determine a start command"); 43 | process.ExitCode.should_be(1); 44 | }; 45 | }; 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Launcher.Tests/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /Launcher/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /Launcher/Launcher.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {956F7FAD-B936-4ED7-9685-4D963E4CBDD6} 8 | Exe 9 | Properties 10 | Launcher 11 | launcher 12 | v4.5 13 | 512 14 | 15 | ..\ 16 | true 17 | publish\ 18 | true 19 | Disk 20 | false 21 | Foreground 22 | 7 23 | Days 24 | false 25 | false 26 | true 27 | 0 28 | 1.0.0.%2a 29 | false 30 | false 31 | true 32 | 33 | 34 | AnyCPU 35 | true 36 | full 37 | false 38 | bin\ 39 | DEBUG;TRACE 40 | prompt 41 | 4 42 | false 43 | 44 | 45 | AnyCPU 46 | pdbonly 47 | true 48 | bin\ 49 | TRACE 50 | prompt 51 | 4 52 | false 53 | false 54 | 55 | 56 | 57 | ..\packages\Newtonsoft.Json.8.0.3\lib\net45\Newtonsoft.Json.dll 58 | True 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | False 74 | .NET Framework 3.5 SP1 Client Profile 75 | false 76 | 77 | 78 | False 79 | .NET Framework 3.5 SP1 80 | false 81 | 82 | 83 | 84 | 85 | 86 | 87 | This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. 88 | 89 | 90 | 91 | 98 | -------------------------------------------------------------------------------- /Launcher/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.IO; 4 | using System.Runtime.InteropServices; 5 | using System.Threading; 6 | using Newtonsoft.Json; 7 | 8 | namespace Launcher 9 | { 10 | public class ExecutionMetadata 11 | { 12 | [JsonProperty("start_command")] 13 | public string StartCommand { get; set; } 14 | 15 | [JsonProperty("start_command_args")] 16 | public string[] StartCommandArgs { get; set; } 17 | } 18 | 19 | internal class Program 20 | { 21 | private static int Main(string[] args) 22 | { 23 | if (args.Length < 2) 24 | { 25 | Console.Error.WriteLine("Launcher was run with insufficient arguments. Usage: launcher.exe "); 26 | return 1; 27 | } 28 | 29 | var containerRoot = Directory.GetCurrentDirectory(); 30 | var workingDirectory = Path.Combine(containerRoot, args[0]); 31 | var executablePathAndArgs = args[1]; 32 | 33 | if (String.IsNullOrWhiteSpace(executablePathAndArgs)) 34 | { 35 | Console.Error.WriteLine("Could not determine a start command. Use the -c flag to 'cf push' to specify a custom start command."); 36 | return 1; 37 | } 38 | if (executablePathAndArgs[0] == '/') 39 | { 40 | executablePathAndArgs = containerRoot + executablePathAndArgs; 41 | } 42 | Console.Out.WriteLine("Running {0}", executablePathAndArgs); 43 | 44 | Directory.SetCurrentDirectory(workingDirectory); 45 | return StartProcess(executablePathAndArgs); 46 | } 47 | 48 | private static int StartProcess(string executablePathAndArgs) 49 | { 50 | STARTUPINFO startupInformation = new STARTUPINFO(); 51 | PROCESS_INFORMATION processInformation; 52 | var result = CreateProcess(null, executablePathAndArgs, IntPtr.Zero, IntPtr.Zero, false, 0, IntPtr.Zero, null, ref startupInformation, out processInformation); 53 | if (!result) 54 | { 55 | var errorCode = Marshal.GetLastWin32Error(); 56 | Console.Error.WriteLine(new System.ComponentModel.Win32Exception(errorCode).Message); 57 | return errorCode; 58 | } 59 | WaitForSingleObject(processInformation.hProcess, INFINITE); 60 | UInt32 exitCode = 0; 61 | GetExitCodeProcess(processInformation.hProcess, ref exitCode); 62 | return (int) exitCode; 63 | } 64 | 65 | [DllImport("kernel32.dll", SetLastError = true)] 66 | static extern bool CreateProcess(string lpApplicationName, string lpCommandLine, IntPtr lpProcessAttributes, 67 | IntPtr lpThreadAttributes, bool bInheritHandles, uint dwCreationFlags, 68 | IntPtr lpEnvironment, string lpCurrentDirectory, ref STARTUPINFO lpStartupInfo, 69 | out PROCESS_INFORMATION lpProcessInformation); 70 | 71 | [DllImport("kernel32.dll", SetLastError = true)] 72 | static extern UInt32 WaitForSingleObject(IntPtr hHandle, UInt32 dwMilliseconds); 73 | 74 | [DllImport("kernel32.dll", SetLastError = true)] 75 | public static extern bool GetExitCodeProcess(IntPtr process, ref UInt32 exitCode); 76 | 77 | const UInt32 INFINITE = 0xFFFFFFFF; 78 | } 79 | 80 | public struct PROCESS_INFORMATION 81 | { 82 | public IntPtr hProcess; 83 | public IntPtr hThread; 84 | public uint dwProcessId; 85 | public uint dwThreadId; 86 | } 87 | 88 | public struct STARTUPINFO 89 | { 90 | public uint cb; 91 | public string lpReserved; 92 | public string lpDesktop; 93 | public string lpTitle; 94 | public uint dwX; 95 | public uint dwY; 96 | public uint dwXSize; 97 | public uint dwYSize; 98 | public uint dwXCountChars; 99 | public uint dwYCountChars; 100 | public uint dwFillAttribute; 101 | public uint dwFlags; 102 | public short wShowWindow; 103 | public short cbReserved2; 104 | public IntPtr lpReserved2; 105 | public IntPtr hStdInput; 106 | public IntPtr hStdOutput; 107 | public IntPtr hStdError; 108 | } 109 | 110 | public struct SECURITY_ATTRIBUTES 111 | { 112 | public int length; 113 | public IntPtr lpSecurityDescriptor; 114 | public bool bInheritHandle; 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /Launcher/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("Launcher")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("Launcher")] 13 | [assembly: AssemblyCopyright("Copyright © 2014")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("20debaf7-4659-4d06-82d4-0222d04b930d")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /Launcher/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014-2015 Pivotal Software, Inc. All Rights Reserved. 2 | 3 | This product is licensed to you under the Apache License, Version 2.0 (the "License"). 4 | You may not use this product except in compliance with the License. 5 | 6 | This product may include a number of subcomponents with separate copyright notices 7 | and license terms. Your use of these subcomponents is subject to the terms and 8 | conditions of the subcomponent's license, as noted in the LICENSE file. 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | windows app lifecycle 2 | ===================== 3 | 4 | The windows application lifecycle implements the traditional Cloud Foundry deployment 5 | strategy. 6 | 7 | The **Builder** downloads buildpacks and app bits, and produces a droplet. 8 | 9 | The **Launcher** runs the start command using a standard rootfs and 10 | environment. 11 | 12 | The **WebAppServer** runs a HostableWebCore server to host the user's app. 13 | 14 | Read about the app lifecycle spec here: https://github.com/cloudfoundry-incubator/diego-design-notes#app-lifecycles 15 | 16 | ## Dependencies 17 | - 64 bit version of Windows (tested with Windows Server 2012 R2 Standard) 18 | - msbuild in PATH 19 | - Administrator access 20 | 21 | building on the command line 22 | ============================ 23 | 24 | 1. Run make.bat in cmd. 25 | 26 | building in Visual Studio 27 | ======================== 28 | 29 | 1. Install https://visualstudiogallery.msdn.microsoft.com/7a52473f-9e1a-40f3-8bd8-6c00ab163609 (nspec test runner) 30 | 31 | 1. Open Visual Studio as Administrator. 32 | ![opening as admin](https://github.com/pivotal-cf-experimental/containerizer/blob/master/README_images/open_as_admin.png) 33 | ![visual studio running as admin](https://github.com/pivotal-cf-experimental/containerizer/blob/master/README_images/showing_vs_running_as_admin.png) 34 | -------------------------------------------------------------------------------- /Web.config: -------------------------------------------------------------------------------- 1 |  2 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /WebAppServer.Tests/DebuggerShim.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using System.Reflection; 3 | using NSpec; 4 | using NSpec.Domain; 5 | using NSpec.Domain.Formatters; 6 | 7 | /* 8 | * Howdy, 9 | * 10 | * This is NSpec's DebuggerShim. It will allow you to use TestDriven.Net or Resharper's test runner to run 11 | * NSpec tests that are in the same Assembly as this class. 12 | * 13 | * It's DEFINITELY worth trying specwatchr (http://nspec.org/continuoustesting). Specwatchr automatically 14 | * runs tests for you. 15 | * 16 | * If you ever want to debug a test when using Specwatchr, simply put the following line in your test: 17 | * 18 | * System.Diagnostics.Debugger.Launch() 19 | * 20 | * Visual Studio will detect this and will give you a window which you can use to attach a debugger. 21 | */ 22 | 23 | //[TestFixture] 24 | public class DebuggerShim 25 | { 26 | //[Test] 27 | public void debug() 28 | { 29 | var tagOrClassName = "class_or_tag_you_want_to_debug"; 30 | 31 | var types = GetType().Assembly.GetTypes(); 32 | // OR 33 | // var types = new Type[]{typeof(Some_Type_Containg_some_Specs)}; 34 | var finder = new SpecFinder(types, ""); 35 | var builder = new ContextBuilder(finder, new Tags().Parse(tagOrClassName), new DefaultConventions()); 36 | var runner = new ContextRunner(builder, new ConsoleFormatter(), false); 37 | var results = runner.Run(builder.Contexts().Build()); 38 | 39 | //assert that there aren't any failures 40 | results.Failures().Count().should_be(0); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /WebAppServer.Tests/Features/WebAppServerHostsNetAppSpec.cs: -------------------------------------------------------------------------------- 1 | using NSpec; 2 | using System; 3 | using System.Diagnostics; 4 | using System.IO; 5 | using System.Net; 6 | using System.Net.Http; 7 | using System.Security.Principal; 8 | using System.Threading; 9 | using System.Linq; 10 | 11 | namespace WebAppServer.Tests 12 | { 13 | class WebAppServerHostsNetAppSpec : nspec 14 | { 15 | const string processName = "WebAppServer.exe"; 16 | const int port = 43311; 17 | private void describe_() 18 | { 19 | Process process = null; 20 | 21 | before = () => 22 | { 23 | KillOrphanWebAppServer(); 24 | }; 25 | 26 | after = () => 27 | { 28 | if (!process.HasExited) 29 | { 30 | process.Kill(); 31 | process.WaitForExit(); 32 | } 33 | 34 | if (process.ExitCode == 1) 35 | { 36 | throw new Exception( 37 | String.Format( 38 | "WebAppServer failed to start. Check that the current user has access to the port (eg. run 'netsh http add urlacl url=http://*:{0}/ user={1}' as an Administrator).", 39 | port, 40 | WindowsIdentity.GetCurrent().Name)); 41 | } 42 | }; 43 | 44 | describe["Given that I have a ASP.NET MVC application"] = () => 45 | { 46 | describe["When I pass it to WebAppServer"] = () => 47 | { 48 | 49 | act = () => 50 | { 51 | process = StartApp("Nora"); 52 | }; 53 | 54 | it["runs it on the specified port"] = () => 55 | { 56 | var client = new HttpClient(); 57 | var response = client.GetAsync("http://localhost:" + port).GetAwaiter().GetResult(); 58 | response.StatusCode.should_be(HttpStatusCode.OK); 59 | response.Content.ReadAsStringAsync().Result.should_be("\"hello i am nora\""); 60 | }; 61 | 62 | it["does not add unexpected custom headers"] = () => 63 | { 64 | var client = new HttpClient(); 65 | var response = client.GetAsync("http://localhost:" + port).GetAwaiter().GetResult(); 66 | response.StatusCode.should_be(HttpStatusCode.OK); 67 | 68 | var CustomHeaders = response.Headers.Where((x) => x.Key.StartsWith("X-")).Select((x) => x.Key).ToList(); 69 | CustomHeaders.should_be(new string[] { "X-AspNet-Version" }); 70 | }; 71 | 72 | }; 73 | }; 74 | 75 | describe["Given that I have a ASP classic application"] = () => 76 | { 77 | it["runs it on the specified port"] = () => 78 | { 79 | var client = new HttpClient(); 80 | var response = client.GetAsync("http://localhost:" + port).GetAwaiter().GetResult(); 81 | response.StatusCode.should_be(HttpStatusCode.OK); 82 | response.Content.ReadAsStringAsync().Result.should_be("Hello World!"); 83 | }; 84 | 85 | act = () => 86 | { 87 | process = StartApp("ASP-classic"); 88 | }; 89 | }; 90 | } 91 | 92 | private Process StartApp(string fixtureName) 93 | { 94 | Process process; 95 | var workingDir = 96 | Path.GetFullPath( 97 | Path.Combine(System.Reflection.Assembly.GetExecutingAssembly().CodeBase, "..", "..", "..") 98 | .Replace("file:///", "")); 99 | var webRoot = Path.Combine(workingDir, "Fixtures", fixtureName); 100 | 101 | process = new Process 102 | { 103 | StartInfo = 104 | { 105 | FileName = Path.Combine(workingDir, "..", "WebAppServer", "bin", processName), 106 | Arguments = ".", 107 | WorkingDirectory = webRoot, 108 | RedirectStandardInput = true, 109 | RedirectStandardError = true, 110 | RedirectStandardOutput = true, 111 | UseShellExecute = false 112 | } 113 | }; 114 | process.StartInfo.EnvironmentVariables["PORT"] = port.ToString(); 115 | 116 | process.Start(); 117 | 118 | // wait for the web app server to start to avoid race conditions 119 | while (!process.HasExited) 120 | { 121 | var readLine = process.StandardOutput.ReadLine(); 122 | readLine.should_not_be_null(); 123 | if (readLine.Contains("Server Started")) 124 | { 125 | break; 126 | } 127 | } 128 | return process; 129 | } 130 | 131 | private void KillOrphanWebAppServer() 132 | { 133 | const string force = "/f"; 134 | const string alsoKillChildProcesses = "/t"; 135 | const string useProcessName = "/im"; 136 | var killOrphanProcess = new Process 137 | { 138 | StartInfo = 139 | { 140 | FileName = "taskkill.exe", 141 | Arguments = 142 | String.Format("{0} {1} {2} {3}", force, alsoKillChildProcesses, useProcessName, 143 | processName), 144 | UseShellExecute = false, 145 | RedirectStandardError = true 146 | } 147 | }; 148 | 149 | killOrphanProcess.Start(); 150 | var stderr = killOrphanProcess.StandardError.ReadToEnd(); 151 | if (stderr.Contains("Access is denied")) 152 | { 153 | throw new Exception(String.Format("Could not remove orphan {0}." + 154 | "This is likely because WinowsAppLifecycle was previously run as Administrator," + 155 | " and is currently running under a non privleged user. To fix:" + 156 | " run \"taskkill.exe /f /t /im {0}\" in admin command prompt", processName)); 157 | 158 | } 159 | killOrphanProcess.WaitForExit(); 160 | } 161 | } 162 | } 163 | 164 | -------------------------------------------------------------------------------- /WebAppServer.Tests/Fixtures/ASP-classic/Web.config: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /WebAppServer.Tests/Fixtures/ASP-classic/default.asp: -------------------------------------------------------------------------------- 1 | <% 2 | response.write("Hello World!") 3 | %> 4 | -------------------------------------------------------------------------------- /WebAppServer.Tests/Fixtures/Nora/Global.asax: -------------------------------------------------------------------------------- 1 | <%@ Application Codebehind="Global.asax.cs" Inherits="Nora.WebApiApplication" Language="C#" %> 2 | -------------------------------------------------------------------------------- /WebAppServer.Tests/Fixtures/Nora/Web.config: -------------------------------------------------------------------------------- 1 |  2 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /WebAppServer.Tests/Fixtures/Nora/bin/Newtonsoft.Json.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudfoundry-attic/windows_app_lifecycle/686f5c2e682410b23c29163bd02765ace79a60a6/WebAppServer.Tests/Fixtures/Nora/bin/Newtonsoft.Json.dll -------------------------------------------------------------------------------- /WebAppServer.Tests/Fixtures/Nora/bin/Nora.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudfoundry-attic/windows_app_lifecycle/686f5c2e682410b23c29163bd02765ace79a60a6/WebAppServer.Tests/Fixtures/Nora/bin/Nora.dll -------------------------------------------------------------------------------- /WebAppServer.Tests/Fixtures/Nora/bin/System.Net.Http.Formatting.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudfoundry-attic/windows_app_lifecycle/686f5c2e682410b23c29163bd02765ace79a60a6/WebAppServer.Tests/Fixtures/Nora/bin/System.Net.Http.Formatting.dll -------------------------------------------------------------------------------- /WebAppServer.Tests/Fixtures/Nora/bin/System.Web.Http.WebHost.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudfoundry-attic/windows_app_lifecycle/686f5c2e682410b23c29163bd02765ace79a60a6/WebAppServer.Tests/Fixtures/Nora/bin/System.Web.Http.WebHost.dll -------------------------------------------------------------------------------- /WebAppServer.Tests/Fixtures/Nora/bin/System.Web.Http.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudfoundry-attic/windows_app_lifecycle/686f5c2e682410b23c29163bd02765ace79a60a6/WebAppServer.Tests/Fixtures/Nora/bin/System.Web.Http.dll -------------------------------------------------------------------------------- /WebAppServer.Tests/Fixtures/Nora/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /WebAppServer.Tests/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("WebAppServer.Tests")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("WebAppServer.Tests")] 13 | [assembly: AssemblyCopyright("Copyright © 2015")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("cfb9c5fb-5ba7-4daf-a511-d784a88148a1")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /WebAppServer.Tests/Specs/OptionsTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using NSpec; 8 | 9 | namespace WebAppServer.Tests.Specs 10 | { 11 | class OptionsTest : nspec 12 | { 13 | private void describe_() 14 | { 15 | describe["Parse"] = () => 16 | { 17 | Options options = null; 18 | string path = null; 19 | string port = null; 20 | 21 | before = () => 22 | { 23 | port = "9999"; 24 | Environment.SetEnvironmentVariable("PORT", port); 25 | options = new Options(); 26 | }; 27 | 28 | act = () => 29 | { 30 | options.Parse(new string[] { }); 31 | }; 32 | 33 | it["parses port as an int"] = () => 34 | { 35 | options.Port.should_be(9999U); 36 | }; 37 | 38 | 39 | it["returns the full path to the current directory"] = () => 40 | { 41 | options.WebRoot.should_be(Directory.GetCurrentDirectory()); 42 | }; 43 | }; 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /WebAppServer.Tests/Specs/ProgramTest.cs: -------------------------------------------------------------------------------- 1 | using Moq; 2 | using NSpec; 3 | using System.Threading; 4 | 5 | namespace WebAppServer.Tests.Specs 6 | { 7 | class ProgramTest : nspec 8 | { 9 | void describe_() 10 | { 11 | describe["RunWebServer"] = () => 12 | { 13 | Mock webServer = null; 14 | Mock log = null; 15 | 16 | before = () => 17 | { 18 | log = new Mock(); 19 | }; 20 | 21 | context["When WebServer does not have access to the port"] = () => 22 | { 23 | before = () => 24 | { 25 | webServer = new Mock(); 26 | webServer.Setup(x => x.Start()) 27 | .Throws(new WebCorePortException()); 28 | }; 29 | 30 | it["Gives the user a helpful error message"] = () => 31 | { 32 | Program.RunWebServer(webServer.Object, log.Object, new ManualResetEvent(true)); 33 | log.Verify( 34 | x => x.Error( 35 | It.Is(message => message.StartsWith("Please allow the user to access the port. eg. 'netsh http add urlacl url=http://*:9999/ user=")), 36 | It.IsAny() 37 | ) 38 | ); 39 | }; 40 | }; 41 | }; 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /WebAppServer.Tests/Specs/WebConfigTest.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using System.Xml; 3 | using NSpec; 4 | 5 | namespace WebAppServer.Tests.Specs 6 | { 7 | class WebConfigTest : nspec 8 | { 9 | public string GetTemporaryDirectory() 10 | { 11 | string tempDirectory = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); 12 | Directory.CreateDirectory(tempDirectory); 13 | return tempDirectory; 14 | } 15 | 16 | public const string DefaultRootWebConfig = @" 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | "; 26 | 27 | public string RootWebConfigPath() 28 | { 29 | var file = Path.Combine(GetTemporaryDirectory(), "web.config"); 30 | File.WriteAllText(file, DefaultRootWebConfig); 31 | return file; 32 | } 33 | 34 | void describe_() 35 | { 36 | describe["WebConfig"] = () => 37 | { 38 | string baseDir = ""; 39 | string rootWebConfigPath = ""; 40 | 41 | before = () => 42 | { 43 | baseDir = GetTemporaryDirectory(); 44 | Directory.CreateDirectory(Path.Combine(baseDir, "config")); 45 | rootWebConfigPath = RootWebConfigPath(); 46 | }; 47 | 48 | after = () => 49 | { 50 | Directory.Delete(baseDir, true); 51 | File.Delete(rootWebConfigPath); 52 | }; 53 | 54 | it["Creates a new configuration file"] = () => 55 | { 56 | var webConfigPath = WebConfig.Create(rootWebConfigPath, baseDir); 57 | webConfigPath.should_contain(baseDir); 58 | var doc = new XmlDocument(); 59 | doc.Load(webConfigPath); 60 | XmlAttribute[] attributes = new XmlAttribute[1]; 61 | doc.SelectSingleNode("//configuration/system.web/compilation").Attributes.CopyTo(attributes, 0); 62 | attributes.Length.should_be(1); 63 | attributes[0].Value.should_be(Path.Combine(baseDir, "tmp")); 64 | attributes[0].Name.should_be("tempDirectory"); 65 | }; 66 | }; 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /WebAppServer.Tests/Test.nunit: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /WebAppServer.Tests/WebAppServer.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {74217BBF-73AF-4F95-9116-FA86C9830718} 8 | Library 9 | Properties 10 | WebAppServer.Tests 11 | WebAppServer.Tests 12 | v4.5 13 | 512 14 | ..\ 15 | true 16 | 17 | 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | 26 | 27 | pdbonly 28 | true 29 | bin\Release\ 30 | TRACE 31 | prompt 32 | 4 33 | 34 | 35 | 36 | ..\packages\Moq.4.2.1409.1722\lib\net40\Moq.dll 37 | 38 | 39 | ..\packages\nspec.0.9.68\lib\NSpec.dll 40 | 41 | 42 | 43 | 44 | 45 | False 46 | ..\packages\Microsoft.AspNet.WebApi.Client.5.2.2\lib\net45\System.Net.Http.Formatting.dll 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | PreserveNewest 77 | 78 | 79 | 80 | 81 | {dc9f6edc-5779-481c-9424-7c4cd63620b3} 82 | WebAppServer 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. 91 | 92 | 93 | 94 | 101 | -------------------------------------------------------------------------------- /WebAppServer.Tests/app.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /WebAppServer.Tests/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /WebAppServer/ConfigGenerator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Security.Cryptography; 4 | using System.Text; 5 | using System.Xml.Linq; 6 | using System.Xml.XPath; 7 | using WebAppServer.Properties; 8 | 9 | namespace WebAppServer 10 | { 11 | public class ConfigSettings 12 | { 13 | public string RootWebConfigPath { get; set; } 14 | public string AppConfigPath { get; set; } 15 | public uint Port { get; set; } 16 | 17 | } 18 | 19 | public class ConfigGenerator : IDisposable 20 | { 21 | private readonly string configPath; 22 | private readonly string webRootPath; 23 | private readonly string logsRootPath; 24 | private readonly string tempPath; 25 | 26 | public ConfigGenerator(string webRoot) 27 | { 28 | if (string.IsNullOrWhiteSpace(webRoot)) 29 | { 30 | throw new ArgumentNullException("webRoot"); 31 | } 32 | this.webRootPath = webRoot; 33 | 34 | var baseDirectory = AppDomain.CurrentDomain.BaseDirectory; 35 | configPath = Path.Combine(baseDirectory, "config"); 36 | logsRootPath = Path.Combine(baseDirectory, "log"); 37 | tempPath = Path.Combine(baseDirectory, "tmp"); 38 | 39 | EnsureDirectory(configPath); 40 | EnsureDirectory(logsRootPath); 41 | EnsureDirectory(tempPath); 42 | } 43 | 44 | /// 45 | /// 46 | /// 47 | /// The application port 48 | /// The to the framework's root web.config based on runtime version 49 | /// One of the Constants.RuntimeVersion values. 50 | /// One of the Constants.PipelineMode values. 51 | /// 52 | public ConfigSettings Create(uint port, string rootWebConfigPath, string runtimeVersion, string pipelineMode, string userName, string password) 53 | { 54 | 55 | var settings = new ConfigSettings 56 | { 57 | Port = port, 58 | RootWebConfigPath = Environment.ExpandEnvironmentVariables(rootWebConfigPath), 59 | AppConfigPath = Path.Combine(configPath, "applicationHost.config") 60 | }; 61 | 62 | var clrConfigPath = Path.Combine(configPath, "aspnet.config"); // TODO: might need to just -> runtime version aspnet.config file 63 | 64 | File.WriteAllText(clrConfigPath, Resources.aspnet); 65 | File.WriteAllText(settings.AppConfigPath, runtimeVersion == Constants.RuntimeVersion.VersionFourDotZero ? Resources.applicationhost : Resources.v2_0AppHost); 66 | 67 | // TODO: Randomize AES Session Keys?? 68 | // TODO: Generage new machine key - use BuildMachineKeyElement() 69 | // TODO: /configuration/system.webServer/security/authentication/anonymousAuthentication[username] = sandbox username or just IUSR? 70 | 71 | var appHostConfig = XDocument.Load(settings.AppConfigPath); 72 | 73 | // set the application pools config files 74 | var appPoolName = "AppPool" + port; 75 | appHostConfig.XPathSelectElement(Constants.ConfigXPath.AppPools).RemoveNodes(); 76 | appHostConfig.AddToElement(Constants.ConfigXPath.AppPools, 77 | BuildApplicationPool(appPoolName, runtimeVersion, pipelineMode, clrConfigPath, userName, password)); 78 | 79 | // disable http logging 80 | appHostConfig.SetValue(Constants.ConfigXPath.WebServer + "/httpLogging", "dontLog", true); 81 | 82 | // add the site and settings to the app host config 83 | appHostConfig.AddToElement(Constants.ConfigXPath.Sites, BuildSiteElement("IronFoundrySite", webRootPath, appPoolName, port)); 84 | 85 | appHostConfig.SetValue(Constants.ConfigXPath.Sites + "/applicationDefaults", "applicationPool", appPoolName); 86 | appHostConfig.SetValue(Constants.ConfigXPath.Sites + "/virtualDirectoryDefaults", "allowSubDirConfig", true); 87 | 88 | appHostConfig.Save(settings.AppConfigPath); 89 | return settings; 90 | } 91 | 92 | private void EnsureDirectory(string directory) 93 | { 94 | if (!Directory.Exists(directory)) 95 | { 96 | Directory.CreateDirectory(directory); 97 | } 98 | } 99 | 100 | protected virtual XElement BuildApplicationPool( 101 | string name, string runtimeVersion, 102 | string pipelineMode, string configFile, 103 | string userName, string password) 104 | { 105 | var pool = new XElement("add"); 106 | pool.Add(new XAttribute("name", name)); 107 | pool.Add(new XAttribute("managedRuntimeVersion", runtimeVersion)); 108 | pool.Add(new XAttribute("managedPipelineMode", pipelineMode)); 109 | pool.Add(new XAttribute("CLRConfigFile", configFile)); 110 | pool.Add(new XAttribute("autoStart", true)); 111 | pool.Add(new XAttribute("startMode", "AlwaysRunning")); 112 | 113 | if (!(string.IsNullOrWhiteSpace(userName) || string.IsNullOrWhiteSpace(password))) 114 | { 115 | var processModel = new XElement("processModel"); 116 | processModel.Add(new XAttribute("identityType", "SpecificUser")); 117 | processModel.Add(new XAttribute("userName", userName)); 118 | processModel.Add(new XAttribute("password", password)); 119 | processModel.Add(new XAttribute("manualGroupMembership", "true")); 120 | pool.Add(processModel); 121 | } 122 | 123 | return pool; 124 | } 125 | 126 | protected virtual XElement BuildMachineKeyElement() 127 | { 128 | Func keyGen = length => 129 | { 130 | var buff = new Byte[length]; 131 | new RNGCryptoServiceProvider().GetBytes(buff); 132 | var sb = new StringBuilder(length * 2); 133 | foreach (byte t in buff) 134 | { 135 | sb.AppendFormat("{0:X2}", t); 136 | } 137 | return sb.ToString(); 138 | }; 139 | 140 | var node = new XElement("machineKey"); 141 | node.Add(new XAttribute("validationKey", keyGen(64))); 142 | node.Add(new XAttribute("decryptionKey", keyGen(32))); 143 | node.Add(new XAttribute("validation", "SHA1")); 144 | node.Add(new XAttribute("decryption", "AES")); 145 | return node; 146 | } 147 | 148 | protected virtual XElement BuildSiteElement(string name, string physicalPath, string appPoolName, uint port) 149 | { 150 | var site = new XElement("site"); 151 | site.Add(new XAttribute("name", name)); 152 | site.Add(new XAttribute("id", 1)); 153 | site.Add(new XAttribute("serverAutoStart", true)); 154 | site.Add(BuildApplicationElement("/", physicalPath, appPoolName)); 155 | site.Add(new XElement("bindings", BuildBindingElement("http", port, String.Empty))); // "localhost" vs String.Empty for local ONLY binding 156 | return site; 157 | } 158 | 159 | protected virtual XElement BuildApplicationElement(string path, string physicalPath, string applicationPool) 160 | { 161 | var app = new XElement("application"); 162 | app.Add(new XAttribute("path", path)); 163 | app.Add(new XAttribute("applicationPool", applicationPool)); 164 | app.Add(BuildVirtualDirectoryElement("/", physicalPath)); 165 | return app; 166 | } 167 | 168 | protected virtual XElement BuildVirtualDirectoryElement(string path, string physicalPath) 169 | { 170 | var vDir = new XElement("virtualDirectory"); 171 | vDir.Add(new XAttribute("path", path)); 172 | vDir.Add(new XAttribute("physicalPath", physicalPath)); 173 | return vDir; 174 | } 175 | 176 | protected virtual XElement BuildBindingElement(string protocol, uint port, string host) 177 | { 178 | var binding = new XElement("binding"); 179 | binding.Add(new XAttribute("protocol", protocol)); 180 | binding.Add(new XAttribute("bindingInformation", String.Format("*:{0}:{1}", port, host))); 181 | return binding; 182 | } 183 | 184 | public void Dispose() 185 | { 186 | if (Directory.Exists(configPath)) 187 | { 188 | Directory.Delete(configPath, true); 189 | } 190 | } 191 | } 192 | } 193 | -------------------------------------------------------------------------------- /WebAppServer/Constants.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace WebAppServer 6 | { 7 | public class Constants 8 | { 9 | public class ConfigXPath 10 | { 11 | public static string ApplicationHost = "/configuration/system.applicationHost"; 12 | public static string AppPools = ApplicationHost + "/applicationPools"; 13 | public static string Sites = ApplicationHost + "/sites"; 14 | public static string SiteDefaults = Sites + "/siteDefaults"; 15 | 16 | public static string WebServer = "/configuration/system.webServer"; 17 | } 18 | 19 | public class FrameworkPaths 20 | { 21 | public static string TwoDotZero = @"%windir%\Microsoft.NET\Framework\v2.0.50727"; 22 | public static string FourDotZero = @"%windir%\Microsoft.NET\Framework\v4.0.30319"; 23 | 24 | public static string TwoDotZeroWebConfig = TwoDotZero + @"\Config\web.config"; 25 | public static string FourDotZeroWebConfig = FourDotZero + @"\Config\web.config"; 26 | } 27 | 28 | public class RuntimeVersion 29 | { 30 | public static string VersionFourDotZero = "v4.0"; 31 | public static string VersionTwoDotZero = "v2.0"; 32 | } 33 | 34 | public class PipelineMode 35 | { 36 | public static string Integrated = "Integrated"; 37 | public static string Classic = "Classic"; 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /WebAppServer/Logger.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using System.Threading.Tasks; 5 | 6 | namespace WebAppServer 7 | { 8 | public class Logger 9 | { 10 | public virtual void Info(string messageFormat, params object[] args) 11 | { 12 | Console.Out.WriteLine(DateTimeOffset.UtcNow.ToString("u") + "|INFO|" + messageFormat, args); 13 | } 14 | 15 | public virtual void Error(string messageFormat, params object[] args) 16 | { 17 | Console.Error.WriteLine(DateTimeOffset.UtcNow.ToString("u") + "|ERROR|" + messageFormat, args); 18 | } 19 | 20 | public virtual void ErrorException(string message, Exception exception) 21 | { 22 | Error(message); 23 | Error(exception.ToString()); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /WebAppServer/Options.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace WebAppServer 8 | { 9 | public class Options 10 | { 11 | public uint Port { get; set; } 12 | public string WebRoot { get; set; } 13 | 14 | public void Parse(string[] args) 15 | { 16 | Console.Out.WriteLine("PORT == {0}", Environment.GetEnvironmentVariable("PORT")); 17 | 18 | Port = uint.Parse(Environment.GetEnvironmentVariable("PORT")); 19 | WebRoot = Path.GetFullPath("."); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /WebAppServer/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Net; 4 | using System.Security.Principal; 5 | using System.Threading; 6 | 7 | namespace WebAppServer 8 | { 9 | public static class Program 10 | { 11 | private static readonly Logger log = new Logger(); 12 | private static readonly ManualResetEvent exitLatch = new ManualResetEvent(false); 13 | 14 | public static int RunWebServer(IWebServer webServer, Logger log, ManualResetEvent exitLatch) 15 | { 16 | try 17 | { 18 | log.Info("Starting web server instance..."); 19 | webServer.Start(); 20 | Console.WriteLine("Server Started.... press CTRL + C to stop"); 21 | Warmup(webServer); 22 | exitLatch.WaitOne(); 23 | Console.WriteLine("Server shutting down, please wait..."); 24 | webServer.Stop(); 25 | 26 | return 0; 27 | } 28 | catch (WebCorePortException) 29 | { 30 | log.Error("Please allow the user to access the port. eg. 'netsh http add urlacl url=http://*:9999/ user={0}'", WindowsIdentity.GetCurrent().Name); 31 | return 1; 32 | } 33 | } 34 | 35 | private static void Warmup(IWebServer server) 36 | { 37 | var req = WebRequest.Create("http://localhost:" + server.Port); 38 | req.Timeout = 1000; 39 | try 40 | { 41 | req.GetResponse(); 42 | } 43 | catch (WebException ex) 44 | { 45 | // ignore exceptions. An exception can be thrown if a 404 was returned 46 | // which is a possibility if the application doesn't have `~/' endpoint 47 | } 48 | } 49 | 50 | private static int Main(string[] args) 51 | { 52 | Console.CancelKeyPress += (s, e) => 53 | { 54 | e.Cancel = true; 55 | exitLatch.Set(); 56 | }; 57 | 58 | Console.Error.WriteLine("The use of WebAppServer.exe is deprecated. Please use the hwc-buildpack instead."); 59 | 60 | var exitCode = 0; 61 | try 62 | { 63 | var options = new Options(); 64 | options.Parse(args); 65 | 66 | log.Info("Port:{0}", options.Port); 67 | log.Info("Webroot:{0}", options.WebRoot); 68 | 69 | var configGenerator = new ConfigGenerator(options.WebRoot); 70 | var webConfig = WebConfig.Create(Environment.ExpandEnvironmentVariables(Constants.FrameworkPaths.FourDotZeroWebConfig), 71 | AppDomain.CurrentDomain.BaseDirectory); 72 | var settings = configGenerator.Create( 73 | options.Port, 74 | webConfig, 75 | Constants.RuntimeVersion.VersionFourDotZero, 76 | Constants.PipelineMode.Integrated, 77 | null, 78 | null); 79 | 80 | using (var webServer = new WebServer(settings)) 81 | { 82 | exitCode = RunWebServer(webServer, log, exitLatch); 83 | } 84 | } 85 | catch (Exception ex) 86 | { 87 | log.ErrorException("Error on startup.", ex); 88 | exitCode = 1; 89 | } 90 | 91 | return exitCode; 92 | } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /WebAppServer/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("WebAppServer")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("WebAppServer")] 13 | [assembly: AssemblyCopyright("Copyright © 2015")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("2c27e47c-20f3-489d-8378-fbb026faba8f")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /WebAppServer/Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.34014 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace WebAppServer.Properties { 12 | using System; 13 | 14 | 15 | /// 16 | /// A strongly-typed resource class, for looking up localized strings, etc. 17 | /// 18 | // This class was auto-generated by the StronglyTypedResourceBuilder 19 | // class via a tool like ResGen or Visual Studio. 20 | // To add or remove a member, edit your .ResX file then rerun ResGen 21 | // with the /str option, or rebuild your VS project. 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class Resources { 26 | 27 | private static global::System.Resources.ResourceManager resourceMan; 28 | 29 | private static global::System.Globalization.CultureInfo resourceCulture; 30 | 31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 32 | internal Resources() { 33 | } 34 | 35 | /// 36 | /// Returns the cached ResourceManager instance used by this class. 37 | /// 38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 39 | internal static global::System.Resources.ResourceManager ResourceManager { 40 | get { 41 | if (object.ReferenceEquals(resourceMan, null)) { 42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("WebAppServer.Properties.Resources", typeof(Resources).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// Overrides the current thread's CurrentUICulture property for all 51 | /// resource lookups using this strongly typed resource class. 52 | /// 53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 54 | internal static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | 63 | /// 64 | /// Looks up a localized string similar to <?xml version="1.0" encoding="UTF-8"?> 65 | ///<configuration> 66 | /// 67 | /// <configSections> 68 | /// <sectionGroup name="system.applicationHost"> 69 | /// <section name="applicationPools" allowDefinition="AppHostOnly" overrideModeDefault="Deny" /> 70 | /// <section name="configHistory" allowDefinition="AppHostOnly" overrideModeDefault="Deny" /> 71 | /// <section name="customMetadata" allowDefinition="AppHostOnly" overrideModeDefault="Deny" /> 72 | /// <section name="listenerAdapters" allowDefinition="AppHostOnly" overrideModeDefault [rest of string was truncated]";. 73 | /// 74 | internal static string applicationhost { 75 | get { 76 | return ResourceManager.GetString("applicationhost", resourceCulture); 77 | } 78 | } 79 | 80 | /// 81 | /// Looks up a localized string similar to <?xml version="1.0" encoding="UTF-8" ?> 82 | ///<configuration> 83 | /// <runtime> 84 | /// <legacyUnhandledExceptionPolicy enabled="false" /> 85 | /// <legacyImpersonationPolicy enabled="true"/> 86 | /// <alwaysFlowImpersonationPolicy enabled="false"/> 87 | /// <SymbolReadingPolicy enabled="1" /> 88 | /// </runtime> 89 | /// <startup useLegacyV2RuntimeActivationPolicy="true" /> 90 | ///</configuration> 91 | ///. 92 | /// 93 | internal static string aspnet { 94 | get { 95 | return ResourceManager.GetString("aspnet", resourceCulture); 96 | } 97 | } 98 | 99 | /// 100 | /// Looks up a localized string similar to <?xml version="1.0" encoding="UTF-8"?> 101 | /// 102 | ///<configuration> 103 | /// 104 | /// <configSections> 105 | /// <sectionGroup name="system.applicationHost"> 106 | /// <section name="applicationPools" allowDefinition="AppHostOnly" overrideModeDefault="Deny" /> 107 | /// <section name="configHistory" allowDefinition="AppHostOnly" overrideModeDefault="Deny" /> 108 | /// <section name="customMetadata" allowDefinition="AppHostOnly" overrideModeDefault="Deny" /> 109 | /// <section name="listenerAdapters" allowDefinition="AppHostOnly" overrideModeDefau [rest of string was truncated]";. 110 | /// 111 | internal static string v2_0AppHost { 112 | get { 113 | return ResourceManager.GetString("v2_0AppHost", resourceCulture); 114 | } 115 | } 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /WebAppServer/Properties/Resources.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | 122 | ..\Resources\applicationhost.config;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252 123 | 124 | 125 | ..\resources\aspnet.config;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252 126 | 127 | 128 | ..\Resources\v2.0AppHost.config;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252 129 | 130 | -------------------------------------------------------------------------------- /WebAppServer/Readme.txt: -------------------------------------------------------------------------------- 1 | Configuring HTTP.SYS 2 | ------------------------------------------------------ 3 | http://msdn.microsoft.com/en-us/library/ms733768.aspx 4 | netsh http add urlacl url=http://foobar:port/ user=containerUser 5 | netsh http delete urlacl url=http://foobar:port/ user=containerUser 6 | 7 | Hostable Web Core 8 | ------------------------------------------------------ 9 | API Ref: http://msdn.microsoft.com/en-us/library/ms693832(v=vs.90).aspx 10 | Walkthrough: http://msdn.microsoft.com/en-us/library/ms689327(v=vs.90).aspx 11 | Runtime errors show up in windows application event log, source = HostableWebCore 12 | 13 | Note that WebcoreActivate and WebcoreShutdown can be called only once in process lifetime. 14 | Also HWC always uses .Net 2.0 schema and there is no way to make it pick .Net 4.0 schema. 15 | So root web.config passed to WebcoreActivate cannot have properties which are only supported 16 | in .Net 4.0. This problem will be fixed in Win8. 17 | 18 | Notes: 19 | ----------------------------------------------------- 20 | - On Windows 7, you can only use .net 2.0 runtime version 21 | (read above for explanation, this is hostable web core limitation). 22 | 23 | given the following args: 24 | -p 8869 -r d:\container -v 2.0 -b true 25 | 26 | It expects your web app to live in: d:\container\www 27 | It will create log in d:\container\log 28 | It will create config in d:\container\config 29 | It will create temp in d:\container\tmp -------------------------------------------------------------------------------- /WebAppServer/Resources/aspnet.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /WebAppServer/WebAppServer.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {DC9F6EDC-5779-481C-9424-7C4CD63620B3} 8 | Exe 9 | Properties 10 | WebAppServer 11 | WebAppServer 12 | v4.5 13 | 512 14 | 15 | 16 | AnyCPU 17 | true 18 | full 19 | false 20 | bin\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | false 25 | 26 | 27 | AnyCPU 28 | pdbonly 29 | true 30 | bin\ 31 | TRACE 32 | prompt 33 | 4 34 | false 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | True 51 | True 52 | Resources.resx 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | Designer 62 | ResXFileCodeGenerator 63 | Resources.Designer.cs 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 80 | -------------------------------------------------------------------------------- /WebAppServer/WebConfig.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using System.Xml; 3 | 4 | namespace WebAppServer 5 | { 6 | public class WebConfig 7 | { 8 | public static string Create(string rootWebConfigPath, string baseDir) 9 | { 10 | var webConfig = Path.Combine(baseDir, "config", "web.config"); 11 | File.Copy(rootWebConfigPath, webConfig, true); 12 | 13 | var doc = new XmlDocument(); 14 | doc.Load(webConfig); 15 | var tempDirAttr = doc.CreateAttribute("tempDirectory"); 16 | tempDirAttr.Value = Path.Combine(baseDir, "tmp"); 17 | doc.SelectSingleNode("//configuration/system.web/compilation").Attributes.Append(tempDirAttr); 18 | doc.Save(webConfig); 19 | 20 | return webConfig; 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /WebAppServer/WebCoreActivationException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace WebAppServer 6 | { 7 | using System.ComponentModel; 8 | 9 | public class WebCoreActivationException : Exception 10 | { 11 | // ref: http://blogs.iis.net/ksingla/archive/2007/12/20/ins-amp-outs-of-hostable-web-core.aspx 12 | public static readonly Dictionary HResults = new Dictionary 13 | { 14 | {"80070032", "HWC Activation failed - the request is not supported, check application event log for further details."}, 15 | {"80070038", "HWC Activation failed - appHostConfig has multiple app pools defined in it"}, 16 | {"800700B7", "HWC Activation failed - invalid binding: port/IP in use already or app pool name in use"}, 17 | {"80070015", "HWC Activation failed - no websites defined in appHostConfig"}, 18 | {"80070044", "HWC Activation failed - app pool defined but site pointing to nonexistend app pool"}, 19 | {"8007000D", "HWC Activation failed - All configuration system checks are still valid. So invalid xml in configuration or duplicate site ids in appHostConfig."}, 20 | {"80070057", "HWC Activation failed - bad parameter"}, 21 | {"80070490", "HWC Activation failed - appHostConfig path is not valid"}, 22 | {"80070420", "HWC Activation failed - service already running"} 23 | }; 24 | 25 | public WebCoreActivationException(int result) : this(result.ToString("X"), result) { } 26 | 27 | private WebCoreActivationException(string hResult, int result) : base( 28 | HResults.ContainsKey(hResult) 29 | ? new Win32Exception(result).Message + ": " + HResults[hResult] 30 | : new Win32Exception(result).Message) 31 | { 32 | HResult = result; 33 | } 34 | } 35 | 36 | public class WebCorePortException : WebCoreActivationException 37 | { 38 | public WebCorePortException() : base(unchecked((int)WebServer.HostableWebCore.ERROR_ACCESS_DENIED)) 39 | { 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /WebAppServer/WebServer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Runtime.InteropServices; 4 | 5 | namespace WebAppServer 6 | { 7 | public interface IWebServer : IDisposable 8 | { 9 | void Start(); 10 | void Stop(); 11 | uint Port { get; } 12 | } 13 | 14 | // Ref: http://msdn.microsoft.com/en-us/library/ms689327%28v=vs.90%29.aspx 15 | // May require: // netsh http add urlacl url=http://*:PORT/ user=DOMAIN\user 16 | public class WebServer : IWebServer 17 | { 18 | private readonly ConfigSettings configSettings; 19 | 20 | public WebServer(ConfigSettings configSettings) 21 | { 22 | this.configSettings = configSettings; 23 | } 24 | 25 | public void Dispose() 26 | { 27 | Stop(); 28 | } 29 | 30 | public void Start() 31 | { 32 | if (!HostableWebCore.IsActivated) 33 | { 34 | HostableWebCore.Activate(configSettings.AppConfigPath, configSettings.RootWebConfigPath, Guid.NewGuid().ToString()); 35 | } 36 | } 37 | 38 | public void Stop() 39 | { 40 | if (HostableWebCore.IsActivated) 41 | { 42 | HostableWebCore.Shutdown(false); 43 | } 44 | } 45 | 46 | public uint Port 47 | { 48 | get { return configSettings.Port; } 49 | } 50 | 51 | #region Hostable WebCore 52 | public static class HostableWebCore 53 | { 54 | public const uint ERROR_ACCESS_DENIED = 0x80070005; 55 | 56 | const string HWCPath = @"%windir%\system32\inetsrv\hwebcore.dll"; 57 | 58 | private static bool _isActivated; 59 | 60 | private delegate uint FnWebCoreShutdown(bool immediate); 61 | private delegate uint FnWebCoreActivate( 62 | [In, MarshalAs(UnmanagedType.LPWStr)]string appHostConfig, 63 | [In, MarshalAs(UnmanagedType.LPWStr)]string rootWebConfig, 64 | [In, MarshalAs(UnmanagedType.LPWStr)]string instanceName); 65 | 66 | private static readonly FnWebCoreActivate WebCoreActivate; 67 | private static readonly FnWebCoreShutdown WebCoreShutdown; 68 | 69 | static HostableWebCore() 70 | { 71 | var hostableWebCorePath = Environment.ExpandEnvironmentVariables(HWCPath); 72 | if (!File.Exists(hostableWebCorePath)) 73 | { 74 | throw new FileNotFoundException("Unable to locate hostable web core library, ensure IIS 7+ is installed", hostableWebCorePath); 75 | } 76 | 77 | // Load the library and get the function pointers for the WebCore entry points 78 | IntPtr hwc = HWCInterop.LoadLibrary(hostableWebCorePath); 79 | 80 | IntPtr procaddr = HWCInterop.GetProcAddress(hwc, "WebCoreActivate"); 81 | WebCoreActivate = (FnWebCoreActivate) Marshal.GetDelegateForFunctionPointer(procaddr, typeof(FnWebCoreActivate)); 82 | 83 | procaddr = HWCInterop.GetProcAddress(hwc, "WebCoreShutdown"); 84 | WebCoreShutdown = (FnWebCoreShutdown) Marshal.GetDelegateForFunctionPointer(procaddr, typeof(FnWebCoreShutdown)); 85 | } 86 | 87 | /// 88 | /// Specifies if Hostable WebCore has been activated 89 | /// 90 | public static bool IsActivated 91 | { 92 | get { return _isActivated; } 93 | } 94 | 95 | /// 96 | /// Activate the HWC 97 | /// 98 | /// Path to ApplicationHost.config to use 99 | /// Path to the Root Web.config to use 100 | /// Name for this instance 101 | public static void Activate(string appHostConfig, string rootWebConfig, string instanceName) 102 | { 103 | uint result = WebCoreActivate(appHostConfig, rootWebConfig, instanceName); 104 | if (result != 0) 105 | { 106 | if (result == ERROR_ACCESS_DENIED) 107 | throw new WebCorePortException(); 108 | 109 | throw new WebCoreActivationException((int)result); 110 | } 111 | 112 | _isActivated = true; 113 | } 114 | 115 | /// 116 | /// Shutdown HWC 117 | /// 118 | public static void Shutdown(bool immediate) 119 | { 120 | if (_isActivated) 121 | { 122 | WebCoreShutdown(immediate); 123 | _isActivated = false; 124 | } 125 | } 126 | 127 | private static class HWCInterop 128 | { 129 | [DllImport("kernel32.dll", SetLastError = true)] 130 | internal static extern IntPtr LoadLibrary(String dllname); 131 | 132 | [DllImport("kernel32.dll", SetLastError = true)] 133 | internal static extern IntPtr GetProcAddress(IntPtr hModule, String procname); 134 | } 135 | } 136 | #endregion 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /WebAppServer/XmlExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Xml.Linq; 2 | using System.Xml.XPath; 3 | 4 | namespace WebAppServer 5 | { 6 | public static class XmlExtensions 7 | { 8 | public static void SetValue(this XDocument root, string elementSelector, string attributeName, object attributeValue) 9 | { 10 | root.XPathSelectElement(elementSelector).SetAttributeValue(attributeName, attributeValue); 11 | } 12 | 13 | public static void AddToElement(this XDocument root, string elementSelector, object value) 14 | { 15 | root.XPathSelectElement(elementSelector).Add(value); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /WindowsAppLifecycle.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.25420.1 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Builder", "Builder\Builder.csproj", "{68F6A408-B0F2-4BB4-A0A4-278694FAB63D}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{08426B53-B9F2-420A-9147-641DFBFE04BE}" 9 | ProjectSection(SolutionItems) = preProject 10 | .nuget\NuGet.Config = .nuget\NuGet.Config 11 | .nuget\NuGet.exe = .nuget\NuGet.exe 12 | .nuget\NuGet.targets = .nuget\NuGet.targets 13 | EndProjectSection 14 | EndProject 15 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Launcher.Tests", "Launcher.Tests\Launcher.Tests.csproj", "{273733E4-6283-4E52-9CED-10EFA609EB38}" 16 | ProjectSection(ProjectDependencies) = postProject 17 | {956F7FAD-B936-4ED7-9685-4D963E4CBDD6} = {956F7FAD-B936-4ED7-9685-4D963E4CBDD6} 18 | EndProjectSection 19 | EndProject 20 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebAppServer", "WebAppServer\WebAppServer.csproj", "{DC9F6EDC-5779-481C-9424-7C4CD63620B3}" 21 | EndProject 22 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebAppServer.Tests", "WebAppServer.Tests\WebAppServer.Tests.csproj", "{74217BBF-73AF-4F95-9116-FA86C9830718}" 23 | EndProject 24 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Launcher", "Launcher\Launcher.csproj", "{956F7FAD-B936-4ED7-9685-4D963E4CBDD6}" 25 | EndProject 26 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Builder.Tests", "Builder.Tests\Builder.Tests.csproj", "{2FE7925C-AC3E-4103-BF03-2D22F3D88610}" 27 | EndProject 28 | Global 29 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 30 | Debug|Any CPU = Debug|Any CPU 31 | Release|Any CPU = Release|Any CPU 32 | EndGlobalSection 33 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 34 | {68F6A408-B0F2-4BB4-A0A4-278694FAB63D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 35 | {68F6A408-B0F2-4BB4-A0A4-278694FAB63D}.Debug|Any CPU.Build.0 = Debug|Any CPU 36 | {68F6A408-B0F2-4BB4-A0A4-278694FAB63D}.Release|Any CPU.ActiveCfg = Release|Any CPU 37 | {68F6A408-B0F2-4BB4-A0A4-278694FAB63D}.Release|Any CPU.Build.0 = Release|Any CPU 38 | {273733E4-6283-4E52-9CED-10EFA609EB38}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 39 | {273733E4-6283-4E52-9CED-10EFA609EB38}.Debug|Any CPU.Build.0 = Debug|Any CPU 40 | {273733E4-6283-4E52-9CED-10EFA609EB38}.Release|Any CPU.ActiveCfg = Release|Any CPU 41 | {273733E4-6283-4E52-9CED-10EFA609EB38}.Release|Any CPU.Build.0 = Release|Any CPU 42 | {DC9F6EDC-5779-481C-9424-7C4CD63620B3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 43 | {DC9F6EDC-5779-481C-9424-7C4CD63620B3}.Debug|Any CPU.Build.0 = Debug|Any CPU 44 | {DC9F6EDC-5779-481C-9424-7C4CD63620B3}.Release|Any CPU.ActiveCfg = Release|Any CPU 45 | {DC9F6EDC-5779-481C-9424-7C4CD63620B3}.Release|Any CPU.Build.0 = Release|Any CPU 46 | {74217BBF-73AF-4F95-9116-FA86C9830718}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 47 | {74217BBF-73AF-4F95-9116-FA86C9830718}.Debug|Any CPU.Build.0 = Debug|Any CPU 48 | {74217BBF-73AF-4F95-9116-FA86C9830718}.Release|Any CPU.ActiveCfg = Release|Any CPU 49 | {74217BBF-73AF-4F95-9116-FA86C9830718}.Release|Any CPU.Build.0 = Release|Any CPU 50 | {956F7FAD-B936-4ED7-9685-4D963E4CBDD6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 51 | {956F7FAD-B936-4ED7-9685-4D963E4CBDD6}.Debug|Any CPU.Build.0 = Debug|Any CPU 52 | {956F7FAD-B936-4ED7-9685-4D963E4CBDD6}.Release|Any CPU.ActiveCfg = Release|Any CPU 53 | {956F7FAD-B936-4ED7-9685-4D963E4CBDD6}.Release|Any CPU.Build.0 = Release|Any CPU 54 | {2FE7925C-AC3E-4103-BF03-2D22F3D88610}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 55 | {2FE7925C-AC3E-4103-BF03-2D22F3D88610}.Debug|Any CPU.Build.0 = Debug|Any CPU 56 | {2FE7925C-AC3E-4103-BF03-2D22F3D88610}.Release|Any CPU.ActiveCfg = Release|Any CPU 57 | {2FE7925C-AC3E-4103-BF03-2D22F3D88610}.Release|Any CPU.Build.0 = Release|Any CPU 58 | EndGlobalSection 59 | GlobalSection(SolutionProperties) = preSolution 60 | HideSolutionNode = FALSE 61 | EndGlobalSection 62 | EndGlobal 63 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | version: 0.{build} 2 | skip_tags: true 3 | cache: C:\Users\appveyor\AppData\Local\NuGet\Cache 4 | build_script: 5 | - git submodule update --init --recursive 6 | - scripts\make.bat 7 | test: off 8 | artifacts: 9 | - path: output/* 10 | name: lifecycle 11 | deploy: 12 | - provider: S3 13 | access_key_id: AKIAI2AAY3LUVTHYDTDA 14 | secret_access_key: 15 | secure: zNBMp5HGSOJLlSY+lBKwgWH5eE71tYCWST8QQjXO+IwIE2pDeI/uv5Nm0iBwob4K 16 | region: us-east-1 17 | bucket: build-windows-app-lifecycle 18 | artifact: lifecycle 19 | set_public: true 20 | on: 21 | branch: master 22 | branches: 23 | only: 24 | - master 25 | - /appveyor/ 26 | -------------------------------------------------------------------------------- /bin/bsdtar.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudfoundry-attic/windows_app_lifecycle/686f5c2e682410b23c29163bd02765ace79a60a6/bin/bsdtar.exe -------------------------------------------------------------------------------- /bin/nuget.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudfoundry-attic/windows_app_lifecycle/686f5c2e682410b23c29163bd02765ace79a60a6/bin/nuget.exe -------------------------------------------------------------------------------- /scripts/make.bat: -------------------------------------------------------------------------------- 1 | :: msbuild must be in path 2 | SET PATH=%PATH%;%WINDIR%\Microsoft.NET\Framework64\v4.0.30319;%WINDIR%\SysNative 3 | where msbuild 4 | if errorLevel 1 ( echo "msbuild was not found on PATH" && exit /b 1 ) 5 | 6 | :: enable some features 7 | dism /online /Enable-Feature /FeatureName:IIS-WebServer /All /NoRestart 8 | dism /online /Enable-Feature /FeatureName:IIS-WebSockets /All /NoRestart 9 | dism /online /Enable-Feature /FeatureName:Application-Server-WebServer-Support /FeatureName:AS-NET-Framework /All /NoRestart 10 | dism /online /Enable-Feature /FeatureName:IIS-HostableWebCore /All /NoRestart 11 | 12 | rmdir /S /Q output 13 | rmdir /S /Q packages 14 | bin\nuget restore || exit /b 1 15 | 16 | MSBuild WindowsAppLifecycle.sln /t:Rebuild /p:Configuration=Release || exit /b 1 17 | packages\nspec.0.9.68\tools\NSpecRunner.exe Builder.Tests\bin\Release\BuilderTests.dll || exit /b 1 18 | packages\nspec.0.9.68\tools\NSpecRunner.exe Launcher.Tests\bin\Release\LauncherTests.dll || exit /b 1 19 | packages\nspec.0.9.68\tools\NSpecRunner.exe WebAppServer.Tests\bin\Release\WebAppServer.Tests.dll || exit /b 1 20 | bin\bsdtar -czvf windows_app_lifecycle.tgz --exclude log -C Builder\bin . -C ..\..\Launcher\bin . -C ..\..\WebAppServer\bin . || exit /b 1 21 | for /f "tokens=*" %%a in ('git rev-parse --short HEAD') do ( 22 | set VAR=%%a 23 | ) 24 | 25 | mkdir output 26 | move /Y windows_app_lifecycle.tgz output\windows_app_lifecycle-%VAR%.tgz || exit /b 1 27 | -------------------------------------------------------------------------------- /vendor/CommandLineParser.1.9.71.nupkg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudfoundry-attic/windows_app_lifecycle/686f5c2e682410b23c29163bd02765ace79a60a6/vendor/CommandLineParser.1.9.71.nupkg -------------------------------------------------------------------------------- /vendor/Newtonsoft.Json.8.0.3.nupkg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudfoundry-attic/windows_app_lifecycle/686f5c2e682410b23c29163bd02765ace79a60a6/vendor/Newtonsoft.Json.8.0.3.nupkg -------------------------------------------------------------------------------- /vendor/YamlDotNet.3.8.0.nupkg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudfoundry-attic/windows_app_lifecycle/686f5c2e682410b23c29163bd02765ace79a60a6/vendor/YamlDotNet.3.8.0.nupkg -------------------------------------------------------------------------------- /vendor/nspec.0.9.68.nupkg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudfoundry-attic/windows_app_lifecycle/686f5c2e682410b23c29163bd02765ace79a60a6/vendor/nspec.0.9.68.nupkg --------------------------------------------------------------------------------