Resvolution - Components, Runtime & Booting

This commit is contained in:
Stephan
2016-09-01 19:06:08 +02:00
parent 18f3a7fbab
commit 0597eea72b
405 changed files with 5114 additions and 6261 deletions

View File

@@ -3,12 +3,9 @@ using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Web.Http;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Umbraco.Core;
using Umbraco.Core.Configuration;
using Umbraco.Core.Logging;
using Umbraco.Core.Persistence;
using Umbraco.Web.Install.Models;
using Umbraco.Web.WebApi;
@@ -18,48 +15,40 @@ namespace Umbraco.Web.Install.Controllers
[HttpInstallAuthorize]
public class InstallApiController : ApiController
{
public InstallApiController()
: this(UmbracoContext.Current)
{
private readonly DatabaseContext _databaseContext;
private readonly ProfilingLogger _proflog;
private readonly ILogger _logger;
private InstallHelper _helper;
}
public InstallApiController(UmbracoContext umbracoContext)
public InstallApiController(UmbracoContext umbracoContext, DatabaseContext databaseContext, ILogger logger, ProfilingLogger proflog)
{
if (umbracoContext == null) throw new ArgumentNullException("umbracoContext");
if (umbracoContext == null) throw new ArgumentNullException(nameof(umbracoContext));
if (databaseContext == null) throw new ArgumentNullException(nameof(databaseContext));
if (proflog == null) throw new ArgumentNullException(nameof(proflog));
if (logger == null) throw new ArgumentNullException(nameof(logger));
UmbracoContext = umbracoContext;
_databaseContext = databaseContext;
_logger = logger;
_proflog = proflog;
}
/// <summary>
/// Returns the current UmbracoContext
/// Gets the Umbraco context.
/// </summary>
public UmbracoContext UmbracoContext { get; private set; }
public UmbracoContext UmbracoContext { get; }
public ApplicationContext ApplicationContext
{
get { return UmbracoContext.Application; }
}
private InstallHelper _helper;
internal InstallHelper InstallHelper
{
get
{
return _helper ?? (_helper = new InstallHelper(UmbracoContext));
}
}
internal InstallHelper InstallHelper => _helper ?? (_helper = new InstallHelper(UmbracoContext, _databaseContext, _logger));
public bool PostValidateDatabaseConnection(DatabaseModel model)
{
var dbHelper = new DatabaseHelper();
var canConnect = dbHelper.CheckConnection(ApplicationContext.DatabaseContext, model);
var canConnect = dbHelper.CheckConnection(model);
return canConnect;
}
/// <summary>
/// Gets the install setup
/// Gets the install setup.
/// </summary>
/// <returns></returns>
public InstallSetup GetSetup()
{
var setup = new InstallSetup();
@@ -78,21 +67,20 @@ namespace Umbraco.Web.Install.Controllers
return setup;
}
public IEnumerable<Package> GetPackages()
{
var installHelper = new InstallHelper(UmbracoContext);
var installHelper = new InstallHelper(UmbracoContext, _databaseContext, _logger);
var starterKits = installHelper.GetStarterKits();
return starterKits;
}
/// <summary>
/// Does the install
/// Installs.
/// </summary>
/// <returns></returns>
public InstallProgressResultModel PostPerformInstall(InstallInstructions installModel)
{
if (installModel == null) throw new ArgumentNullException("installModel");
if (installModel == null) throw new ArgumentNullException(nameof(installModel));
var status = InstallStatusTracker.GetStatus().ToArray();
//there won't be any statuses returned if the app pool has restarted so we need to re-read from file.
@@ -105,22 +93,18 @@ namespace Umbraco.Web.Install.Controllers
var queue = new Queue<InstallTrackingItem>(status.Where(x => x.IsComplete == false));
while (queue.Count > 0)
{
var stepStatus = queue.Dequeue();
var step = InstallHelper.GetAllSteps().Single(x => x.Name == stepStatus.Name);
var item = queue.Dequeue();
var step = InstallHelper.GetAllSteps().Single(x => x.Name == item.Name);
JToken instruction = null;
//If this step has any instructions then extract them
if (installModel.Instructions.Any(x => x.Key == step.Name))
{
instruction = installModel.Instructions[step.Name];
}
//If this step doesn't require execution then continue to the next one, this is just a fail-safe check.
// if this step has any instructions then extract them
JToken instruction;
installModel.Instructions.TryGetValue(item.Name, out instruction); // else null
// if this step doesn't require execution then continue to the next one, this is just a fail-safe check.
if (StepRequiresExecution(step, instruction) == false)
{
//set this as complete and continue
InstallStatusTracker.SetComplete(installModel.InstallId, stepStatus.Name, null);
// set this as complete and continue
InstallStatusTracker.SetComplete(installModel.InstallId, item.Name);
continue;
}
@@ -128,13 +112,13 @@ namespace Umbraco.Web.Install.Controllers
{
var setupData = ExecuteStep(step, instruction);
//update the status
InstallStatusTracker.SetComplete(installModel.InstallId, step.Name, setupData != null ? setupData.SavedStepData : null);
// update the status
InstallStatusTracker.SetComplete(installModel.InstallId, step.Name, setupData?.SavedStepData);
//Determine's the next step in the queue and dequeue's any items that don't need to execute
var nextStep = IterateNextRequiredStep(step, queue, installModel.InstallId, installModel);
//check if there's a custom view to return for this step
// determine's the next step in the queue and dequeue's any items that don't need to execute
var nextStep = IterateSteps(step, queue, installModel.InstallId, installModel);
// check if there's a custom view to return for this step
if (setupData != null && setupData.View.IsNullOrWhiteSpace() == false)
{
return new InstallProgressResultModel(false, step.Name, nextStep, setupData.View, setupData.ViewModel);
@@ -185,65 +169,53 @@ namespace Umbraco.Web.Install.Controllers
/// <param name="installId"></param>
/// <param name="installModel"></param>
/// <returns></returns>
private string IterateNextRequiredStep(InstallSetupStep current, Queue<InstallTrackingItem> queue, Guid installId, InstallInstructions installModel)
private string IterateSteps(InstallSetupStep current, Queue<InstallTrackingItem> queue, Guid installId, InstallInstructions installModel)
{
if (queue.Count > 0)
while (queue.Count > 0)
{
var next = queue.Peek();
var step = InstallHelper.GetAllSteps().Single(x => x.Name == next.Name);
var item = queue.Peek();
//If the current step restarts the app pool then we must simply return the next one in the queue,
// we cannot peek ahead as the next step might rely on the app restart and therefore RequiresExecution
// will rely on that too.
// if the current step restarts the app pool then we must simply return the next one in the queue,
// we cannot peek ahead as the next step might rely on the app restart and therefore RequiresExecution
// will rely on that too.
if (current.PerformsAppRestart)
{
return step.Name;
}
return item.Name;
JToken instruction = null;
//If this step has any instructions then extract them
if (installModel.Instructions.Any(x => x.Key == step.Name))
{
instruction = installModel.Instructions[step.Name];
}
var step = InstallHelper.GetAllSteps().Single(x => x.Name == item.Name);
//if the step requires execution then return it's name
// if this step has any instructions then extract them
JToken instruction;
installModel.Instructions.TryGetValue(item.Name, out instruction); // else null
// if the step requires execution then return its name
if (StepRequiresExecution(step, instruction))
{
return step.Name;
}
//this step no longer requires execution, this could be due to a new config change during installation,
// so we'll dequeue this one from the queue and recurse
// no longer requires execution, could be due to a new config change during installation
// dequeue
queue.Dequeue();
//set this as complete
InstallStatusTracker.SetComplete(installId, step.Name, null);
// complete
InstallStatusTracker.SetComplete(installId, step.Name);
//recurse
return IterateNextRequiredStep(step, queue, installId, installModel);
// and continue
current = step;
}
//there is no more steps
return string.Empty;
}
/// <summary>
/// Check if the step requires execution
/// </summary>
/// <param name="step"></param>
/// <param name="instruction"></param>
/// <returns></returns>
// determines whether the step requires execution
internal bool StepRequiresExecution(InstallSetupStep step, JToken instruction)
{
var model = instruction == null ? null : instruction.ToObject(step.StepType);
var model = instruction?.ToObject(step.StepType);
var genericStepType = typeof(InstallSetupStep<>);
Type[] typeArgs = { step.StepType };
var typedStepType = genericStepType.MakeGenericType(typeArgs);
try
{
var method = typedStepType.GetMethods().Single(x => x.Name == "RequiresExecution");
return (bool)method.Invoke(step, new object[] { model });
return (bool) method.Invoke(step, new[] { model });
}
catch (Exception ex)
{
@@ -252,18 +224,19 @@ namespace Umbraco.Web.Install.Controllers
}
}
// executes the step
internal InstallSetupResult ExecuteStep(InstallSetupStep step, JToken instruction)
{
using (ApplicationContext.ProfilingLogger.TraceDuration<InstallApiController>("Executing installation step: " + step.Name, "Step completed"))
using (_proflog.TraceDuration<InstallApiController>("Executing installation step: " + step.Name, "Step completed"))
{
var model = instruction == null ? null : instruction.ToObject(step.StepType);
var model = instruction?.ToObject(step.StepType);
var genericStepType = typeof(InstallSetupStep<>);
Type[] typeArgs = { step.StepType };
var typedStepType = genericStepType.MakeGenericType(typeArgs);
try
{
var method = typedStepType.GetMethods().Single(x => x.Name == "Execute");
return (InstallSetupResult)method.Invoke(step, new object[] { model });
return (InstallSetupResult) method.Invoke(step, new[] { model });
}
catch (Exception ex)
{