PageRenderTime 48ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 1ms

/Kudu.Core/Deployment/SiteBuilderFactory.cs

https://github.com/moacap/kudu
C# | 192 lines | 145 code | 27 blank | 20 comment | 24 complexity | 91719b7cca79a940671975551b879fc9 MD5 | raw file
Possible License(s): Apache-2.0
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Globalization;
  4. using System.IO;
  5. using System.Linq;
  6. using Kudu.Contracts.Tracing;
  7. using Kudu.Core.Infrastructure;
  8. namespace Kudu.Core.Deployment
  9. {
  10. public class SiteBuilderFactory : ISiteBuilderFactory
  11. {
  12. private readonly IEnvironment _environment;
  13. private readonly IBuildPropertyProvider _propertyProvider;
  14. public SiteBuilderFactory(IBuildPropertyProvider propertyProvider, IEnvironment environment)
  15. {
  16. _propertyProvider = propertyProvider;
  17. _environment = environment;
  18. }
  19. public ISiteBuilder CreateBuilder(ITracer tracer, ILogger logger)
  20. {
  21. string repositoryRoot = _environment.DeploymentRepositoryPath;
  22. var configuration = new DeploymentConfiguration(repositoryRoot);
  23. // If there's a custom deployment file then let that take over.
  24. if (!String.IsNullOrEmpty(configuration.Command))
  25. {
  26. return new CustomBuilder(repositoryRoot, _environment.TempPath, configuration.Command, _propertyProvider);
  27. }
  28. // If the repository has an explicit pointer to a project path to be deployed
  29. // then use it.
  30. string targetProjectPath = configuration.ProjectPath;
  31. if (!String.IsNullOrEmpty(targetProjectPath))
  32. {
  33. tracer.Trace("Found .deployment file in repository");
  34. // Try to resolve the project
  35. return ResolveProject(repositoryRoot,
  36. targetProjectPath,
  37. tryWebSiteProject: true,
  38. searchOption: SearchOption.TopDirectoryOnly);
  39. }
  40. // Get all solutions in the current repository path
  41. var solutions = VsHelper.GetSolutions(repositoryRoot).ToList();
  42. if (!solutions.Any())
  43. {
  44. return ResolveProject(repositoryRoot,
  45. searchOption: SearchOption.AllDirectories);
  46. }
  47. // More than one solution is ambiguous
  48. if (solutions.Count > 1)
  49. {
  50. // TODO: Show relative paths in error messages
  51. ThrowAmbiguousSolutionsError(solutions);
  52. }
  53. // We have a solution
  54. VsSolution solution = solutions[0];
  55. // We need to determine what project to deploy so get a list of all web projects and
  56. // figure out with some heuristic, which one to deploy.
  57. // TODO: Pick only 1 and throw if there's more than one
  58. VsSolutionProject project = solution.Projects.Where(p => p.IsWap || p.IsWebSite).FirstOrDefault();
  59. if (project == null)
  60. {
  61. logger.Log(Resources.Log_NoDeployableProjects, solution.Path);
  62. return new BasicBuilder(repositoryRoot, _environment.TempPath, _environment.ScriptPath);
  63. }
  64. if (project.IsWap)
  65. {
  66. return new WapBuilder(_propertyProvider,
  67. repositoryRoot,
  68. project.AbsolutePath,
  69. _environment.TempPath,
  70. _environment.NuGetCachePath,
  71. solution.Path);
  72. }
  73. return new WebSiteBuilder(_propertyProvider,
  74. repositoryRoot,
  75. project.AbsolutePath,
  76. _environment.TempPath,
  77. _environment.NuGetCachePath,
  78. solution.Path);
  79. }
  80. private ISiteBuilder ResolveProject(string repositoryRoot, bool tryWebSiteProject = false, SearchOption searchOption = SearchOption.AllDirectories)
  81. {
  82. return ResolveProject(repositoryRoot, repositoryRoot, tryWebSiteProject, searchOption, specificConfiguration: false);
  83. }
  84. private ISiteBuilder ResolveProject(string repositoryRoot, string targetPath, bool tryWebSiteProject, SearchOption searchOption = SearchOption.AllDirectories, bool specificConfiguration = true)
  85. {
  86. if (DeploymentHelper.IsProject(targetPath))
  87. {
  88. return DetermineProject(repositoryRoot, targetPath);
  89. }
  90. // Check for loose projects
  91. var projects = DeploymentHelper.GetProjects(targetPath, searchOption);
  92. if (projects.Count > 1)
  93. {
  94. // Can't determine which project to build
  95. throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture,
  96. Resources.Error_AmbiguousProjects,
  97. String.Join(", ", projects)));
  98. }
  99. else if (projects.Count == 1)
  100. {
  101. return DetermineProject(repositoryRoot, projects[0]);
  102. }
  103. if (tryWebSiteProject)
  104. {
  105. // Website projects need a solution to build so look for one in the repository path
  106. // that has this website in it.
  107. var solutions = VsHelper.FindContainingSolutions(repositoryRoot, targetPath);
  108. // More than one solution is ambiguous
  109. if (solutions.Count > 1)
  110. {
  111. ThrowAmbiguousSolutionsError(solutions);
  112. }
  113. else if (solutions.Count == 1)
  114. {
  115. // Unambiguously pick the root
  116. return new WebSiteBuilder(_propertyProvider,
  117. repositoryRoot,
  118. targetPath,
  119. _environment.TempPath,
  120. _environment.NuGetCachePath,
  121. solutions[0].Path);
  122. }
  123. }
  124. // This should only ever happen if the user specifies an invalid directory.
  125. // The other case where the method is called we always resolve the path so it's a non issue there.
  126. if (specificConfiguration && !Directory.Exists(targetPath))
  127. {
  128. throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture,
  129. Resources.Error_ProjectDoesNotExist,
  130. targetPath));
  131. }
  132. // If there's none then use the basic builder (the site is xcopy deployable)
  133. return new BasicBuilder(targetPath, _environment.TempPath, _environment.ScriptPath);
  134. }
  135. private ISiteBuilder DetermineProject(string repositoryRoot, string targetPath)
  136. {
  137. if (!DeploymentHelper.IsDeployableProject(targetPath))
  138. {
  139. throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture,
  140. Resources.Error_ProjectNotDeployable,
  141. targetPath));
  142. }
  143. else if (File.Exists(targetPath))
  144. {
  145. var solution = VsHelper.FindContainingSolution(repositoryRoot, targetPath);
  146. string solutionPath = solution != null ? solution.Path : null;
  147. return new WapBuilder(_propertyProvider,
  148. repositoryRoot,
  149. targetPath,
  150. _environment.TempPath,
  151. _environment.NuGetCachePath,
  152. solutionPath);
  153. }
  154. throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture,
  155. Resources.Error_ProjectDoesNotExist,
  156. targetPath));
  157. }
  158. private static void ThrowAmbiguousSolutionsError(IList<VsSolution> solutions)
  159. {
  160. throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture,
  161. Resources.Error_AmbiguousSolutions,
  162. String.Join(", ", solutions.Select(s => s.Path))));
  163. }
  164. }
  165. }