Interim patcher support (no actual patches installing in this version...)

main
Inga 🏳‍🌈 12 years ago
parent 21e63d7d92
commit 5fa9ff5f4c
  1. 2
      Builder/IISMainHandler/build.txt
  2. 84
      Builder/IISMainHandler/product.wxs
  3. 5
      FLocal.Common/Config.cs
  4. 8
      FLocal.IISHandler/FLocal.IISHandler.csproj
  5. 2
      FLocal.IISHandler/Initializer.cs
  6. 9
      FLocal.IISHandler/MainHandler.cs
  7. 8
      FLocal.Migration.Console/Program.cs
  8. 76
      FLocal.Patcher.Common/FLocal.Patcher.Common.csproj
  9. 54
      FLocal.Patcher.Common/PatcherConfiguration.cs
  10. 15
      FLocal.Patcher.Common/PatcherInfo.cs
  11. 29
      FLocal.Patcher.Common/PatchesLoader.cs
  12. 36
      FLocal.Patcher.Common/Properties/AssemblyInfo.cs
  13. 43
      FLocal.Patcher.Common/Resources/ResourcesManager.cs
  14. 75
      FLocal.Patcher.IISHandler/FLocal.Patcher.IISHandler.csproj
  15. 22
      FLocal.Patcher.IISHandler/MainHandler.cs
  16. 36
      FLocal.Patcher.IISHandler/Properties/AssemblyInfo.cs
  17. 56
      FLocal.sln
  18. 39
      Patcher.Web/CheckParams.cs
  19. 32
      Patcher.Web/IPatcherConfiguration.cs
  20. 42
      Patcher.Web/MainHandler.cs
  21. 73
      Patcher.Web/Patcher.Web.csproj
  22. 30
      Patcher.Web/PatcherInfo.cs
  23. 36
      Patcher.Web/Properties/AssemblyInfo.cs
  24. 55
      Patcher/Checker.cs
  25. 46
      Patcher/Context.cs
  26. 21
      Patcher/DB/DBTraitsFactory.cs
  27. 9
      Patcher/DB/TransactionFactory.cs
  28. 7
      Patcher/Data/Patch/AbstractPatch.cs
  29. 12
      Patcher/Data/Patch/PatchId.cs
  30. 9
      Patcher/ICheckParams.cs
  31. 18
      Patcher/IUpdateParams.cs
  32. 35
      Patcher/Patcher.csproj
  33. 199
      Patcher/Updater.cs
  34. 34
      Patcher/Util/Cache.cs
  35. 15
      Web.Core/Config.cs
  36. 22
      Web.Core/IInteractiveConsole.cs
  37. 1
      Web.Core/Web.Core.csproj

@ -87,6 +87,30 @@
<Component Id="TexCompiler.pdb" Guid="707304A1-9774-446F-B672-FA25EAD8E4F{targetId}">
<File Id="TexCompiler.pdb" Source="..\..\TexCompiler\bin\Release\TexCompiler.pdb" KeyPath="yes" Checksum="yes"/>
</Component>
<Component Id="FLocal.Patcher.IISHandler.dll" Guid="FD81CC31-D95B-437C-83A9-AE4C05B1A5D{targetId}">
<File Id="FLocal.Patcher.IISHandler.dll" Source="..\..\FLocal.Patcher.IISHandler\bin\Release\FLocal.Patcher.IISHandler.dll" KeyPath="yes" Checksum="yes"/>
</Component>
<Component Id="FLocal.Patcher.IISHandler.pdb" Guid="DE40CE70-21D8-4C5B-95F6-C861FC185EB{targetId}">
<File Id="FLocal.Patcher.IISHandler.pdb" Source="..\..\FLocal.Patcher.IISHandler\bin\Release\FLocal.Patcher.IISHandler.pdb" KeyPath="yes" Checksum="yes"/>
</Component>
<Component Id="FLocal.Patcher.Common.dll" Guid="9ADCE502-78D1-44F9-9267-0FD1E02E7AE{targetId}">
<File Id="FLocal.Patcher.Common.dll" Source="..\..\FLocal.Patcher.Common\bin\Release\FLocal.Patcher.Common.dll" KeyPath="yes" Checksum="yes"/>
</Component>
<Component Id="FLocal.Patcher.Common.pdb" Guid="2A5EA0F4-D43C-4277-A2B2-F4EFA778943{targetId}">
<File Id="FLocal.Patcher.Common.pdb" Source="..\..\FLocal.Patcher.Common\bin\Release\FLocal.Patcher.Common.pdb" KeyPath="yes" Checksum="yes"/>
</Component>
<Component Id="Patcher.dll" Guid="B8F10219-2D29-49EC-8FE0-0834586C6B4{targetId}">
<File Id="Patcher.dll" Source="..\..\Patcher\bin\Release\Patcher.dll" KeyPath="yes" Checksum="yes"/>
</Component>
<Component Id="Patcher.pdb" Guid="A8EFE5CE-51B5-432E-974F-7056CEF4D40{targetId}">
<File Id="Patcher.pdb" Source="..\..\Patcher\bin\Release\Patcher.pdb" KeyPath="yes" Checksum="yes"/>
</Component>
<Component Id="Patcher.Web.dll" Guid="F5FEC45F-A24D-4C8F-85A2-B6AC8F3BCDE{targetId}">
<File Id="Patcher.Web.dll" Source="..\..\Patcher.Web\bin\Release\Patcher.Web.dll" KeyPath="yes" Checksum="yes"/>
</Component>
<Component Id="Patcher.Web.pdb" Guid="038ADB30-4F4A-419E-A8E3-949D3F04D39{targetId}">
<File Id="Patcher.Web.pdb" Source="..\..\Patcher.Web\bin\Release\Patcher.Web.pdb" KeyPath="yes" Checksum="yes"/>
</Component>
</DirectoryRef>
<DirectoryRef Id="ARCHIVEDIRECTORY">
<Component Id="Resources.FLocal.Templates.7z" Guid="B41F4142-A39C-43BE-8D20-F31BFFA9B48{targetId}">
@ -99,28 +123,22 @@
<File Id="_7z.exe" Name="7z.exe" Source="7z.exe" KeyPath="yes" Checksum="yes"/>
</Component>
</DirectoryRef>
<Feature Id='FLocal.IISHandler' Title='IISMainHandler' Level='1'>
<ComponentRef Id='FLocal.IISHandler.dll' />
<ComponentRef Id='FLocal.IISHandler.pdb' />
<Feature Id='Web' Title='Web' Level='1'>
<Feature Id='Web.Core' Title='Core library' Level='1'>
<ComponentRef Id='Web.Core.dll' />
<ComponentRef Id='Web.Core.pdb' />
</Feature>
</Feature>
<Feature Id='FLocal.Migration.Gateway' Title='Import utilities' Level='1'>
<Feature Id='Importer' Title='Importer library' Level='1'>
<ComponentRef Id='FLocal.Migration.Gateway.dll' />
<ComponentRef Id='FLocal.Migration.Gateway.pdb' />
<Feature Id='Patcher' Title='Patcher' Level='1'>
<Feature Id='Patcher.Patcher' Title='patcher core libraries' Level='1'>
<ComponentRef Id='Patcher.dll' />
<ComponentRef Id='Patcher.pdb' />
</Feature>
<Feature Id='FLocal.Migration.Console' Title='Import console' Level='1'>
<ComponentRef Id='FLocal.Migration.Console.exe' />
<ComponentRef Id='FLocal.Migration.Console.pdb' />
<Feature Id='Patcher.Web' Title='patcher web interop' Level='1'>
<ComponentRef Id='Patcher.Web.dll' />
<ComponentRef Id='Patcher.Web.pdb' />
</Feature>
</Feature>
<Feature Id='Web.Core' Title='Core library' Level='1'>
<ComponentRef Id='Web.Core.dll' />
<ComponentRef Id='Web.Core.pdb' />
</Feature>
<Feature Id='FLocal.Common' Title='Common FLocal libraries' Level='1'>
<ComponentRef Id='FLocal.Common.dll' />
<ComponentRef Id='FLocal.Common.pdb' />
</Feature>
<Feature Id='MySQLConnector' Title='Adapter to DbConnection' Level='1'>
<ComponentRef Id='MySQLConnector.dll' />
<ComponentRef Id='MySQLConnector.pdb' />
@ -129,6 +147,36 @@
<ComponentRef Id='TexCompiler.dll' />
<ComponentRef Id='TexCompiler.pdb' />
</Feature>
<Feature Id='FLocal' Title='FLocal' Level='1'>
<Feature Id='FLocal.Migration' Title='Import utilities' Level='1'>
<Feature Id='FLocal.Migration.Gateway' Title='Importer library' Level='1'>
<ComponentRef Id='FLocal.Migration.Gateway.dll' />
<ComponentRef Id='FLocal.Migration.Gateway.pdb' />
</Feature>
<Feature Id='FLocal.Migration.Console' Title='Import console' Level='1'>
<ComponentRef Id='FLocal.Migration.Console.exe' />
<ComponentRef Id='FLocal.Migration.Console.pdb' />
</Feature>
</Feature>
<Feature Id='FLocal.Common' Title='Common FLocal libraries' Level='1'>
<ComponentRef Id='FLocal.Common.dll' />
<ComponentRef Id='FLocal.Common.pdb' />
</Feature>
<Feature Id='FLocal.Patcher' Title='FLocal patcher' Level='1'>
<Feature Id='FLocal.Patcher.Common' Title='flocal patches/settings' Level='1'>
<ComponentRef Id='FLocal.Patcher.Common.dll' />
<ComponentRef Id='FLocal.Patcher.Common.pdb' />
</Feature>
<Feature Id='FLocal.Patcher.IISHandler' Title='flocal patcher handler' Level='1'>
<ComponentRef Id='FLocal.Patcher.IISHandler.dll' />
<ComponentRef Id='FLocal.Patcher.IISHandler.pdb' />
</Feature>
</Feature>
<Feature Id='FLocal.IISHandler' Title='IISMainHandler' Level='1'>
<ComponentRef Id='FLocal.IISHandler.dll' />
<ComponentRef Id='FLocal.IISHandler.pdb' />
</Feature>
</Feature>
<Feature Id='ThirdParty' Title='ThirdParty libraries/tools' Level='1'>
<Feature Id='NConsoler' Title='NConsoler' Level='1'>
<ComponentRef Id='NConsoler.dll' />

@ -10,6 +10,8 @@ namespace FLocal.Common {
public class Config : Config<Config> {
public readonly string AppInfo;
public readonly string InitTime;
public readonly Web.Core.DB.IDBConnection mainConnection;
@ -52,8 +54,9 @@ namespace FLocal.Common {
public readonly ILogger Logger;
protected Config(NameValueCollection data) : base(data) {
protected Config(NameValueCollection data) : base() {
this.InitTime = DateTime.Now.ToLongTimeString();
this.AppInfo = data["AppInfo"];
this.dataDir = data["DataDir"];
this.DirSeparator = System.IO.Path.DirectorySeparatorChar.ToString();
this.SaltMigration = data["SaltMigration"];

@ -132,6 +132,14 @@
<Project>{CE888859-9E46-41F7-91CE-8EC106F3A625}</Project>
<Name>Common</Name>
</ProjectReference>
<ProjectReference Include="..\FLocal.Patcher.Common\FLocal.Patcher.Common.csproj">
<Project>{AD931A4B-F62A-4095-B185-BAA9C991FBFF}</Project>
<Name>FLocal.Patcher.Common</Name>
</ProjectReference>
<ProjectReference Include="..\Patcher.Web\Patcher.Web.csproj">
<Project>{FB3DDF5A-E31D-4763-9633-5EEC6462DAED}</Project>
<Name>Patcher.Web</Name>
</ProjectReference>
<ProjectReference Include="..\Web.Core\Web.Core.csproj">
<Project>{6F532626-E9F8-498E-9683-1538E7CD62CB}</Project>
<Name>Core</Name>

@ -9,6 +9,7 @@ using FLocal.Common;
using FLocal.Common.dataobjects;
using System.IO;
using System.Threading;
using FLocal.Patcher.Common;
namespace FLocal.IISHandler {
class Initializer {
@ -39,6 +40,7 @@ namespace FLocal.IISHandler {
private void DoInitialize() {
Config.Init(ConfigurationManager.AppSettings);
PatcherConfiguration.Init(ConfigurationManager.AppSettings);
string dir = FLocal.Common.Config.instance.dataDir + "Logs\\";
using(StreamWriter writer = new StreamWriter(dir + DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss") + ".INITIALIZE.txt")) {

@ -6,6 +6,7 @@ using System.Web;
using System.Configuration;
using Web.Core;
using FLocal.Common;
using FLocal.Patcher.Common;
namespace FLocal.IISHandler {
public class MainHandler : IHttpHandler {
@ -18,12 +19,16 @@ namespace FLocal.IISHandler {
private void doProcessRequest(HttpContext httpcontext) {
if(PatcherInfo.instance.IsNeedsPatching) {
throw new FLocalException("DB is outdated");
}
Uri current = httpcontext.Request.Url;
if(!current.Host.EndsWith(Config.instance.BaseHost)) {
throw new Web.Core.FLocalException("Wrong host: " + current.Host + " (expected *" + Config.instance.BaseHost + ")");
throw new FLocalException("Wrong host: " + current.Host + " (expected *" + Config.instance.BaseHost + ")");
}
if(Config.instance.forceHttps && !httpcontext.Request.IsSecureConnection) {
throw new Web.Core.FLocalException("Only HTTPS connections are allowed");
throw new FLocalException("Only HTTPS connections are allowed");
}
Uri referer = httpcontext.Request.UrlReferrer;

@ -12,10 +12,12 @@ namespace FLocal.Migration.Console {
Consolery.Run(typeof(Program), args);
}
private static bool isConfigInitialized = false;
private static object initializeConfig_locker = new object();
private static void initializeConfig() {
if(!Config.isInitialized) {
lock(typeof(Config)) {
if(!Config.isInitialized) {
if(!isConfigInitialized) {
lock(initializeConfig_locker) {
if(!isConfigInitialized) {
Config.Init(ConfigurationManager.AppSettings);
}
}

@ -0,0 +1,76 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>9.0.30729</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{AD931A4B-F62A-4095-B185-BAA9C991FBFF}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>FLocal.Patcher.Common</RootNamespace>
<AssemblyName>FLocal.Patcher.Common</AssemblyName>
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Xml.Linq">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Data.DataSetExtensions">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="PatcherConfiguration.cs" />
<Compile Include="PatcherInfo.cs" />
<Compile Include="PatchesLoader.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Resources\ResourcesManager.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Patcher.Web\Patcher.Web.csproj">
<Project>{FB3DDF5A-E31D-4763-9633-5EEC6462DAED}</Project>
<Name>Patcher.Web</Name>
</ProjectReference>
<ProjectReference Include="..\Patcher\Patcher.csproj">
<Project>{78F407CF-416D-4D1F-971C-9A51FEA69B3A}</Project>
<Name>Patcher</Name>
</ProjectReference>
<ProjectReference Include="..\Web.Core\Web.Core.csproj">
<Project>{6F532626-E9F8-498E-9683-1538E7CD62CB}</Project>
<Name>Web.Core</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

@ -0,0 +1,54 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.Specialized;
using System.IO;
using Patcher.Data.Patch;
using Web.Core;
using Patcher.Web;
namespace FLocal.Patcher.Common {
public class PatcherConfiguration : Config<PatcherConfiguration>, IPatcherConfiguration {
private readonly string _DbDriverName;
public string DbDriverName {
get { throw new NotImplementedException(); }
}
private readonly string _GuestConnectionString;
public string GuestConnectionString {
get { throw new NotImplementedException(); }
}
private readonly string _PatchesTable;
public string PatchesTable {
get { throw new NotImplementedException(); }
}
private readonly string _EnvironmentName;
public string EnvironmentName {
get { throw new NotImplementedException(); }
}
public IEnumerable<PatchId> getPatchesList() {
return PatchesLoader.getPatchesList();
}
public Stream loadPatch(PatchId patchId) {
return PatchesLoader.loadPatch(patchId);
}
protected PatcherConfiguration(NameValueCollection data) : base() {
this._DbDriverName = data["Patcher.DbDriver"];
this._EnvironmentName = data["Patcher.EnvironmentName"];
this._GuestConnectionString = data["ConnectionString"];
this._PatchesTable = data["Patcher.PatchesTable"];
}
public static void Init(NameValueCollection data) {
doInit(() => new PatcherConfiguration(data));
}
}
}

@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace FLocal.Patcher.Common {
public class PatcherInfo : Patcher.Web.PatcherInfo {
public static readonly PatcherInfo instance = new PatcherInfo();
private PatcherInfo() : base(PatcherConfiguration.instance) {
}
}
}

@ -0,0 +1,29 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.IO;
using Patcher.Data.Patch;
namespace FLocal.Patcher.Common {
static class PatchesLoader {
private static readonly Regex PatchName = new Regex("^Patch_(?<version>[01-9]+)_(?<name>[a-z]+)\\.xml$", RegexOptions.Compiled | RegexOptions.ExplicitCapture);
public static IEnumerable<PatchId> getPatchesList() {
return
from resourceName in Resources.ResourcesManager.GetResourcesList()
where PatchName.IsMatch(resourceName)
let match = PatchName.Match(resourceName)
select new PatchId(int.Parse(match.Groups["version"].Value), match.Groups["name"].Value);
}
public static Stream loadPatch(PatchId patchId) {
return Resources.ResourcesManager.GetResource(String.Format("Patch_{0:D5}_{1}.xml", patchId.version, patchId.name));
}
//public static
}
}

@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("FLocal.Patcher.Common")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("FLocal.Patcher.Common")]
[assembly: AssemblyCopyright("Copyright © 2012")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("ecdf2812-7787-443b-bbf1-00be83dbc3ca")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

@ -0,0 +1,43 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using Patcher;
namespace FLocal.Patcher.Common.Resources {
static class ResourcesManager {
public class XmlUrlResolver : System.Xml.XmlUrlResolver {
public override object GetEntity(Uri absoluteUri, string role, Type ofObjectToReturn) {
//Assembly assembly = Assembly.GetExecutingAssembly();
//return assembly.GetManifestResourceStream(this.GetType(),Path.GetFileName(absoluteUri.AbsolutePath));
// throw new ApplicationException(Path.GetFileName(absoluteUri.AbsolutePath));
try {
return GetResource(Path.GetFileName(absoluteUri.AbsolutePath)); //note that we ignore all folders structure
} catch(ResourceNotFoundException) {
throw new XmlResourceNotFoundException(absoluteUri);
}
}
}
public static Stream GetResource(string name) {
var result = Assembly.GetExecutingAssembly().GetManifestResourceStream(typeof(ResourcesManager), name);
if(result == null) {
throw new ResourceNotFoundException(name);
}
return result;
}
private static readonly string Namespace = typeof(ResourcesManager).Namespace + ".";
public static IEnumerable<string> GetResourcesList() {
return
from rawName in Assembly.GetExecutingAssembly().GetManifestResourceNames()
where rawName.StartsWith(Namespace)
select rawName.Substring(Namespace.Length);
}
}
}

@ -0,0 +1,75 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>9.0.30729</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{5CCEDD35-6D7A-4F0F-87B8-290EFCF8EF2D}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>FLocal.Patcher.IISHandler</RootNamespace>
<AssemblyName>FLocal.Patcher.IISHandler</AssemblyName>
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.configuration" />
<Reference Include="System.Core">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Web" />
<Reference Include="System.Xml.Linq">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Data.DataSetExtensions">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="MainHandler.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\FLocal.Patcher.Common\FLocal.Patcher.Common.csproj">
<Project>{AD931A4B-F62A-4095-B185-BAA9C991FBFF}</Project>
<Name>FLocal.Patcher.Common</Name>
</ProjectReference>
<ProjectReference Include="..\Patcher.Web\Patcher.Web.csproj">
<Project>{FB3DDF5A-E31D-4763-9633-5EEC6462DAED}</Project>
<Name>Patcher.Web</Name>
</ProjectReference>
<ProjectReference Include="..\Web.Core\Web.Core.csproj">
<Project>{6F532626-E9F8-498E-9683-1538E7CD62CB}</Project>
<Name>Web.Core</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using FLocal.Patcher.Common;
namespace FLocal.Patcher.IISHandler {
public class MainHandler : Patcher.Web.MainHandler {
protected override Patcher.Web.PatcherInfo patcherInfo {
get {
return PatcherInfo.instance;
}
}
protected override string GetAdminConnectionString(HttpContext context) {
throw new NotImplementedException();
}
}
}

@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("FLocal.Patcher.IISHandler")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("FLocal.Patcher.IISHandler")]
[assembly: AssemblyCopyright("Copyright © 2012")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("7a43a64d-9908-4ffa-ae00-29343eecf31e")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

@ -23,6 +23,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TexCompiler", "TexCompiler\
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Patcher", "Patcher\Patcher.csproj", "{78F407CF-416D-4D1F-971C-9A51FEA69B3A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FLocal.Patcher.IISHandler", "FLocal.Patcher.IISHandler\FLocal.Patcher.IISHandler.csproj", "{5CCEDD35-6D7A-4F0F-87B8-290EFCF8EF2D}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Patcher.Web", "Patcher.Web\Patcher.Web.csproj", "{FB3DDF5A-E31D-4763-9633-5EEC6462DAED}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FLocal.Patcher.Common", "FLocal.Patcher.Common\FLocal.Patcher.Common.csproj", "{AD931A4B-F62A-4095-B185-BAA9C991FBFF}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -133,16 +139,46 @@ Global
{7D2A38F8-C42D-4F9F-AF64-1DDD5842C7EC}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{7D2A38F8-C42D-4F9F-AF64-1DDD5842C7EC}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{7D2A38F8-C42D-4F9F-AF64-1DDD5842C7EC}.Release|x86.ActiveCfg = Release|Any CPU
{78F407CF-416D-4D1F-971C-9A51FEA69B3A}.Debug|Any CPU.ActiveCfg = Debug|x86
{78F407CF-416D-4D1F-971C-9A51FEA69B3A}.Debug|Mixed Platforms.ActiveCfg = Debug|x86
{78F407CF-416D-4D1F-971C-9A51FEA69B3A}.Debug|Mixed Platforms.Build.0 = Debug|x86
{78F407CF-416D-4D1F-971C-9A51FEA69B3A}.Debug|x86.ActiveCfg = Debug|x86
{78F407CF-416D-4D1F-971C-9A51FEA69B3A}.Debug|x86.Build.0 = Debug|x86
{78F407CF-416D-4D1F-971C-9A51FEA69B3A}.Release|Any CPU.ActiveCfg = Release|x86
{78F407CF-416D-4D1F-971C-9A51FEA69B3A}.Release|Mixed Platforms.ActiveCfg = Release|x86
{78F407CF-416D-4D1F-971C-9A51FEA69B3A}.Release|Mixed Platforms.Build.0 = Release|x86
{78F407CF-416D-4D1F-971C-9A51FEA69B3A}.Release|x86.ActiveCfg = Release|x86
{78F407CF-416D-4D1F-971C-9A51FEA69B3A}.Release|x86.Build.0 = Release|x86
{78F407CF-416D-4D1F-971C-9A51FEA69B3A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{78F407CF-416D-4D1F-971C-9A51FEA69B3A}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{78F407CF-416D-4D1F-971C-9A51FEA69B3A}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{78F407CF-416D-4D1F-971C-9A51FEA69B3A}.Debug|x86.ActiveCfg = Debug|Any CPU
{78F407CF-416D-4D1F-971C-9A51FEA69B3A}.Debug|x86.Build.0 = Debug|Any CPU
{78F407CF-416D-4D1F-971C-9A51FEA69B3A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{78F407CF-416D-4D1F-971C-9A51FEA69B3A}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{78F407CF-416D-4D1F-971C-9A51FEA69B3A}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{78F407CF-416D-4D1F-971C-9A51FEA69B3A}.Release|x86.ActiveCfg = Release|Any CPU
{78F407CF-416D-4D1F-971C-9A51FEA69B3A}.Release|x86.Build.0 = Release|Any CPU
{5CCEDD35-6D7A-4F0F-87B8-290EFCF8EF2D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5CCEDD35-6D7A-4F0F-87B8-290EFCF8EF2D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5CCEDD35-6D7A-4F0F-87B8-290EFCF8EF2D}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{5CCEDD35-6D7A-4F0F-87B8-290EFCF8EF2D}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{5CCEDD35-6D7A-4F0F-87B8-290EFCF8EF2D}.Debug|x86.ActiveCfg = Debug|Any CPU
{5CCEDD35-6D7A-4F0F-87B8-290EFCF8EF2D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5CCEDD35-6D7A-4F0F-87B8-290EFCF8EF2D}.Release|Any CPU.Build.0 = Release|Any CPU
{5CCEDD35-6D7A-4F0F-87B8-290EFCF8EF2D}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{5CCEDD35-6D7A-4F0F-87B8-290EFCF8EF2D}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{5CCEDD35-6D7A-4F0F-87B8-290EFCF8EF2D}.Release|x86.ActiveCfg = Release|Any CPU
{FB3DDF5A-E31D-4763-9633-5EEC6462DAED}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FB3DDF5A-E31D-4763-9633-5EEC6462DAED}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FB3DDF5A-E31D-4763-9633-5EEC6462DAED}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{FB3DDF5A-E31D-4763-9633-5EEC6462DAED}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{FB3DDF5A-E31D-4763-9633-5EEC6462DAED}.Debug|x86.ActiveCfg = Debug|Any CPU
{FB3DDF5A-E31D-4763-9633-5EEC6462DAED}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FB3DDF5A-E31D-4763-9633-5EEC6462DAED}.Release|Any CPU.Build.0 = Release|Any CPU
{FB3DDF5A-E31D-4763-9633-5EEC6462DAED}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{FB3DDF5A-E31D-4763-9633-5EEC6462DAED}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{FB3DDF5A-E31D-4763-9633-5EEC6462DAED}.Release|x86.ActiveCfg = Release|Any CPU
{AD931A4B-F62A-4095-B185-BAA9C991FBFF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{AD931A4B-F62A-4095-B185-BAA9C991FBFF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AD931A4B-F62A-4095-B185-BAA9C991FBFF}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{AD931A4B-F62A-4095-B185-BAA9C991FBFF}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{AD931A4B-F62A-4095-B185-BAA9C991FBFF}.Debug|x86.ActiveCfg = Debug|Any CPU
{AD931A4B-F62A-4095-B185-BAA9C991FBFF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AD931A4B-F62A-4095-B185-BAA9C991FBFF}.Release|Any CPU.Build.0 = Release|Any CPU
{AD931A4B-F62A-4095-B185-BAA9C991FBFF}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{AD931A4B-F62A-4095-B185-BAA9C991FBFF}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{AD931A4B-F62A-4095-B185-BAA9C991FBFF}.Release|x86.ActiveCfg = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

@ -0,0 +1,39 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Patcher.Data.Patch;
namespace Patcher.Web {
class CheckParams : ICheckParams {
private readonly IPatcherConfiguration configuration;
public CheckParams(IPatcherConfiguration configuration) {
this.configuration = configuration;
}
public string DbDriverName {
get {
return this.configuration.DbDriverName;
}
}
public string ConnectionString {
get {
return this.configuration.GuestConnectionString;
}
}
public string PatchesTable {
get {
return this.configuration.PatchesTable;
}
}
public IEnumerable<PatchId> getPatchesList() {
return this.configuration.getPatchesList();
}
}
}

@ -0,0 +1,32 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Patcher.Data.Patch;
using System.IO;
namespace Patcher.Web {
public interface IPatcherConfiguration {
string DbDriverName {
get;
}
string GuestConnectionString {
get;
}
string PatchesTable {
get;
}
string EnvironmentName {
get;
}
IEnumerable<PatchId> getPatchesList();
Stream loadPatch(PatchId patchId);
}
}

@ -0,0 +1,42 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
namespace Patcher.Web {
abstract public class MainHandler : IHttpHandler {
abstract protected PatcherInfo patcherInfo {
get;
}
abstract protected string GetAdminConnectionString(HttpContext context);
public bool IsReusable {
get { return true; }
}
private void Install(HttpContext context) {
var writer = context.Response.Output;
writer.WriteLine("<p>Installing...</p>");
System.Threading.Thread.Sleep(TimeSpan.FromSeconds(2));
this.patcherInfo.AreNewPatchesInstalled = true;
writer.WriteLine("<p>Installed</p>");
}
private void ShowInfo(HttpContext context) {
var writer = context.Response.Output;
writer.WriteLine("<form method=\"POST\"><input type=\"hidden\" name=\"install\" value=\"install\"/><input type=\"submit\" value=\"Install!\"/></form>");
}
public void ProcessRequest(HttpContext context) {
if(context.Request.Form["install"] == "install") {
this.Install(context);
} else {
this.ShowInfo(context);
}
}
}
}

@ -0,0 +1,73 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>9.0.30729</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{FB3DDF5A-E31D-4763-9633-5EEC6462DAED}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Patcher.Web</RootNamespace>
<AssemblyName>Patcher.Web</AssemblyName>
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Web" />
<Reference Include="System.Xml.Linq">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Data.DataSetExtensions">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="CheckParams.cs" />
<Compile Include="MainHandler.cs" />
<Compile Include="IPatcherConfiguration.cs" />
<Compile Include="PatcherInfo.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Patcher\Patcher.csproj">
<Project>{78F407CF-416D-4D1F-971C-9A51FEA69B3A}</Project>
<Name>Patcher</Name>
</ProjectReference>
<ProjectReference Include="..\Web.Core\Web.Core.csproj">
<Project>{6F532626-E9F8-498E-9683-1538E7CD62CB}</Project>
<Name>Web.Core</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

@ -0,0 +1,30 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Patcher.Web {
abstract public class PatcherInfo {
internal readonly IPatcherConfiguration configuration;
public readonly bool IsContainsNewPatches;
public bool AreNewPatchesInstalled {
get;
internal set;
}
public bool IsNeedsPatching {
get {
return this.IsContainsNewPatches && !this.AreNewPatchesInstalled;
}
}
protected PatcherInfo(IPatcherConfiguration configuration) {
this.configuration = configuration;
this.IsContainsNewPatches = (new Checker(new CheckParams(configuration))).IsNeedsPatching();
}
}
}

@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("Patcher.Web")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Patcher.Web")]
[assembly: AssemblyCopyright("Copyright © 2012")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("ef9cd949-c853-4a5c-b4f6-8195fb785378")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

@ -0,0 +1,55 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Web.Core;
using Patcher.Data.Patch;
using Patcher.DB;
namespace Patcher {
public class Checker {
private const string STATUS_INSTALLING = "installing";
private const string STATUS_INSTALLED = "installed";
private readonly ICheckParams checkParams;
public Checker(ICheckParams checkParams) {
this.checkParams = checkParams;
}
public IEnumerable<PatchId> GetPatchesToInstall() {
List<PatchId> inputPatches = this.checkParams.getPatchesList().OrderBy(patchId => patchId).ToList();
using(Transaction transaction = TransactionFactory.Create(this.checkParams.DbDriverName, this.checkParams.ConnectionString)) {
return Util.RemoveExtra(
from patchId in this.checkParams.getPatchesList()
orderby patchId ascending
select patchId,
from row in transaction.ExecuteReader(
string.Format(
"select {1}, {2} from {0} where {3} = {4}",
transaction.EscapeName(this.checkParams.PatchesTable),
transaction.EscapeName("VERSION"),
transaction.EscapeName("NAME"),
transaction.EscapeName("STATUS"),
transaction.MarkParam("pstatus")
),
new Dictionary<string, object> {
{ "pstatus", STATUS_INSTALLED },
}
)
let patch = new PatchId(int.Parse(row["VERSION"]), row["NAME"])
orderby patch ascending
select patch
);
}
}
public bool IsNeedsPatching() {
System.Threading.Thread.Sleep(TimeSpan.FromSeconds(2));
return true;
//return this.GetPatchesToInstall().Any();
}
}
}

@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Web.Core;
using Patcher.Data.Patch;
using Patcher.DB;
using System.IO;
@ -11,25 +12,40 @@ namespace Patcher
class Context
{
public readonly IConfig config;
private readonly IUpdateParams updateParams;
public readonly Func<List<PatchId>> getPatchesList;
public readonly Func<PatchId, Stream> loadPatch;
public List<PatchId> getPatchesList() {
return (from patchId in this.updateParams.getPatchesList() orderby patchId ascending select patchId).ToList();
}
public readonly IDBTraits DbDriver;
private static readonly Dictionary<string, IDBTraits> DB_DRIVERS = new Dictionary<string, IDBTraits>
{
{ "oracle", OracleDBTraits.instance },
{ "oracle-faketransactional", OracleFakeTransactionalDBTraits.instance },
};
public Context(IConfig config, Func<IEnumerable<PatchId>> getPatchesListUnsorted, Func<PatchId, Stream> loadPatch) {
this.config = config;
this.getPatchesList = () => (from patchId in getPatchesListUnsorted() orderby patchId ascending select patchId).ToList();
this.loadPatch = loadPatch;
this.DbDriver = DB_DRIVERS[config.DbDriverName];
public readonly IInteractiveConsole console;
public string EnvironmentName {
get {
return this.updateParams.EnvironmentName;
}
}
public string PatchesTable {
get {
return this.updateParams.PatchesTable;
}
}
public Stream loadPatch(PatchId patchId) {
return this.updateParams.loadPatch(patchId);
}
public Transaction CreateTransaction() {
return TransactionFactory.Create(this.updateParams.DbDriverName, this.updateParams.ConnectionString);
}
public Context(IUpdateParams updateParams, IInteractiveConsole console) {
this.updateParams = updateParams;
this.DbDriver = DBTraitsFactory.GetTraits(updateParams.DbDriverName);
this.console = console;
}
}

@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Patcher.DB {
static class DBTraitsFactory {
public static IDBTraits GetTraits(string DbDriverName) {
switch(DbDriverName.ToLower()) {
case "oracle":
return OracleDBTraits.instance;
case "oracle-faketransactional":
return OracleFakeTransactionalDBTraits.instance;
default:
throw new NotImplementedException();
}
}
}
}

@ -9,15 +9,10 @@ namespace Patcher.DB
{
private static Transaction Create(IDBTraits DbDriver, string ConnectionString)
public static Transaction Create(string DbDriverName, string ConnectionString)
{
return new Transaction(DbDriver, ConnectionString);
return new Transaction(DBTraitsFactory.GetTraits(DbDriverName), ConnectionString);
}
public static Transaction Create(Context context)
{
return Create(context.DbDriver, context.config.ConnectionString);
}
}
}

@ -6,6 +6,7 @@ using System.Text;
using System.Xml;
using System.Xml.Linq;
using System.Xml.Schema;
using Web.Core;
using Patcher.Data.Command;
using Patcher.DB;
@ -41,7 +42,7 @@ namespace Patcher.Data.Patch
public static AbstractPatch LoadById(PatchId id, Context context)
{
return Cache<KeyValuePair<PatchId, Context>, AbstractPatch>.instance.GetValue(new KeyValuePair<PatchId, Context>(id, context), () => _LoadById(id, context));
return Cache<AbstractPatch>.instance.get(new KeyValuePair<PatchId, Context>(id, context), () => _LoadById(id, context));
}
private static AbstractPatch _LoadById(PatchId id, Context context)
@ -58,9 +59,9 @@ namespace Patcher.Data.Patch
XElement version = data.Root.Element("version");
string number = version.Element("number").Value;
string author = version.Element("author").Value;
if((number != id.version.ToString()) || (author != id.author))
if((number != id.version.ToString()) || (author != id.name))
{
throw new ApplicationException(string.Format("Versions mismatch on patch #{0} from {1} (got #{2} from {3})", id.version, id.author, number, author));
throw new ApplicationException(string.Format("Versions mismatch on patch #{0} from {1} (got #{2} from {3})", id.version, id.name, number, author));
}
HashSet<string> restrictToEnvironments;

@ -9,12 +9,12 @@ namespace Patcher.Data.Patch
{
public readonly int version;
public readonly string author;
public readonly string name;
public PatchId(int version, string author)
public PatchId(int version, string name)
{
this.version = version;
this.author = author;
this.name = name;
}
private int _CompareTo(PatchId other)
@ -22,7 +22,7 @@ namespace Patcher.Data.Patch
int result = this.version.CompareTo(other.version);
if(result == 0)
{
result = this.author.CompareTo(other.author);
result = this.name.CompareTo(other.name);
}
return result;
}
@ -50,8 +50,8 @@ namespace Patcher.Data.Patch
{
case "version":
return this.version.ToString(formatProvider);
case "author":
return this.author.ToString(formatProvider);
case "name":
return this.name.ToString(formatProvider);
default:
throw new ApplicationException(String.Format("Unknown format {0}", format));
}

@ -6,14 +6,9 @@ using Patcher.Data.Patch;
namespace Patcher
{
public interface IConfig
public interface ICheckParams
{
string EnvironmentName
{
get;
}
string DbDriverName
{
get;
@ -29,5 +24,7 @@ namespace Patcher
get;
}
IEnumerable<PatchId> getPatchesList();
}
}

@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using Patcher.Data.Patch;
namespace Patcher {
public interface IUpdateParams : ICheckParams {
string EnvironmentName {
get;
}
Stream loadPatch(PatchId patchId);
}
}

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>9.0.30729</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{78F407CF-416D-4D1F-971C-9A51FEA69B3A}</ProjectGuid>
@ -13,8 +13,7 @@
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
<PlatformTarget>x86</PlatformTarget>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
@ -23,8 +22,7 @@
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
<PlatformTarget>x86</PlatformTarget>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
@ -32,19 +30,21 @@
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup>
<StartupObject />
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Core">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Data.OracleClient" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Xml.Linq">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Checker.cs" />
<Compile Include="Context.cs" />
<Compile Include="Data\Command\AbstractColumnCommand.cs" />
<Compile Include="Data\Command\AbstractColumnCommandWithOptions.cs" />
@ -75,6 +75,7 @@
<Compile Include="DB\ColumnDescription.cs" />
<Compile Include="DB\ColumnOptions.cs" />
<Compile Include="DB\ColumnReference.cs" />
<Compile Include="DB\DBTraitsFactory.cs" />
<Compile Include="DB\ForeignKeyConstraint.cs" />
<Compile Include="DB\IDBTraits.cs" />
<Compile Include="DB\OracleDBTraits.cs" />
@ -89,12 +90,12 @@
<Compile Include="Exceptions\FormattableException.cs" />
<Compile Include="Exceptions\ResourceNotFoundException.cs" />
<Compile Include="Exceptions\XmlResourceNotFoundException.cs" />
<Compile Include="ConsoleProcessor.cs" />
<Compile Include="IConfig.cs" />
<Compile Include="IUpdateParams.cs" />
<Compile Include="Updater.cs" />
<Compile Include="ICheckParams.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Resources\ResourcesManager.cs" />
<Compile Include="ThirdParty\NConsoler.cs" />
<Compile Include="Util\Cache.cs" />
<Compile Include="Util\CultureReplacementWrapper.cs" />
<Compile Include="Util\Util.cs" />
</ItemGroup>
@ -150,6 +151,12 @@
<ItemGroup>
<None Include="Resources\Patch_00000_changeprocedure.xml" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Web.Core\Web.Core.csproj">
<Project>{6F532626-E9F8-498E-9683-1538E7CD62CB}</Project>
<Name>Web.Core</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.

@ -5,6 +5,7 @@ using System.Text;
using System.Text.RegularExpressions;
using System.Xml.Linq;
using NConsoler;
using Web.Core;
using Patcher.Data;
using Patcher.Data.Patch;
using Patcher.DB;
@ -12,61 +13,45 @@ using System.IO;
namespace Patcher
{
public sealed class ConsoleProcessor
public sealed class Updater
{
private const string STATUS_INSTALLING = "installing";
private const string STATUS_INSTALLED = "installed";
private static readonly Regex PatchName = new Regex("^Patch_(?<version>[01-9]+)_(?<author>[a-z]+)\\.xml$", RegexOptions.Compiled | RegexOptions.ExplicitCapture);
private readonly Context context;
private ConsoleProcessor(Context context)
{
this.context = context;
}
public static int Process(IConfig config, Func<IEnumerable<PatchId>> getPatchesList, Func<PatchId, Stream> loadPatch, string[] args)
{
using(new CultureReplacementWrapper(System.Globalization.CultureInfo.InvariantCulture))
{
return Consolery.RunInstance(new ConsoleProcessor(new Context(config, getPatchesList, loadPatch)), args);
}
public Updater(IUpdateParams updateParams, IInteractiveConsole console) {
this.context = new Context(updateParams, console);
}
private static int Wrap(bool interactive, Action action)
{
private int Wrap(Action action) {
bool success = false;
try
{
try {
action();
success = true;
} catch(Exception e)
{
Console.WriteLine();
Console.WriteLine(e);
} catch(Exception e) {
this.context.console.Report(e.ToString());
}
if(interactive)
{
Console.WriteLine("Press any key to exit...");
Console.ReadKey(true);
if(this.context.console.IsInteractive) {
this.context.console.Report("Press any key to exit...");
this.context.console.WaitForUserAction();
}
return success ? 0 : 1;
}
private void InstallPatch(PatchId patchId)
{
AbstractPatch patch = AbstractPatch.LoadById(patchId, this.context);
if(!patch.DoesSupportEnvironment(context.config.EnvironmentName))
if(!patch.DoesSupportEnvironment(this.context.EnvironmentName))
{
Console.Write(" (skipping because of unsupported environment) ");
this.context.console.Report(" (skipping because of unsupported environment) ");
return;
}
using(var transaction = TransactionFactory.Create(context))
using(var transaction = this.context.CreateTransaction())
{
bool patchExistsInDB;
@ -75,17 +60,17 @@ namespace Patcher
var patchDBData = transaction.ExecuteReader(
string.Format(
"select {1} from {0} where {2} = {3} and {4} = {5}",
transaction.EscapeName(context.config.PatchesTable),
transaction.EscapeName(this.context.PatchesTable),
transaction.EscapeName("STATUS"),
transaction.EscapeName("VERSION"),
transaction.MarkParam("pversion"),
transaction.EscapeName("AUTHOR"),
transaction.MarkParam("pauthor")
transaction.EscapeName("NAME"),
transaction.MarkParam("pname")
),
new Dictionary<string, object>
{
{ "pversion", patchId.version },
{ "pauthor", patchId.author },
{ "pname", patchId.name },
}
).ToList();
@ -135,11 +120,11 @@ namespace Patcher
? "update {0} set {5} = {6}, {7} = {8} where {1} = {2} and {3} = {4}"
: "insert into {0}({1}, {3}, {5}, {7}) values({2}, {4}, {6}, {8})"
,
transaction.EscapeName(context.config.PatchesTable),
transaction.EscapeName(this.context.PatchesTable),
transaction.EscapeName("VERSION"),
transaction.MarkParam("pversion"),
transaction.EscapeName("AUTHOR"),
transaction.MarkParam("pauthor"),
transaction.EscapeName("NAME"),
transaction.MarkParam("pname"),
transaction.EscapeName("ROLLBACK_DATA"),
transaction.MarkParam("prollbackdata"),
transaction.EscapeName("STATUS"),
@ -148,7 +133,7 @@ namespace Patcher
new Dictionary<string, object>
{
{ "pversion", patchId.version },
{ "pauthor", patchId.author },
{ "pname", patchId.name },
{ "prollbackdata", rollbackData.ToString() },
{ "pstatus", STATUS_INSTALLED },
}
@ -163,23 +148,23 @@ namespace Patcher
private void UninstallPatch(PatchId patchId)
{
using(var transaction = TransactionFactory.Create(context))
using(var transaction = this.context.CreateTransaction())
{
AbstractPatch patch = AbstractPatch.LoadById(patchId, context);
var patchInstallInfo = transaction.ExecuteReader(
String.Format(
"select {1} from {0} where {2} = {4} and {3} = {5} for update",
context.config.PatchesTable,
this.context.PatchesTable,
"ROLLBACK_DATA",
"VERSION",
"AUTHOR",
"NAME",
transaction.MarkParam("pversion"),
transaction.MarkParam("pauthor")
transaction.MarkParam("pname")
),
new Dictionary<string, object>
{
{ "pversion", patchId.version },
{ "pauthor", patchId.author },
{ "pname", patchId.name },
}
).Single();
patch.Rollback(transaction, XDocument.Parse(patchInstallInfo["ROLLBACK_DATA"]));
@ -187,16 +172,16 @@ namespace Patcher
int affectedRows = transaction.ExecuteNonQuery(
String.Format(
"delete from {0} where {1} = {3} and {2} = {4}",
transaction.EscapeName(context.config.PatchesTable),
transaction.EscapeName(this.context.PatchesTable),
transaction.EscapeName("VERSION"),
transaction.EscapeName("AUTHOR"),
transaction.EscapeName("NAME"),
transaction.MarkParam("pversion"),
transaction.MarkParam("pauthor")
transaction.MarkParam("pname")
),
new Dictionary<string, object>
{
{ "pversion", patchId.version },
{ "pauthor", patchId.author },
{ "pname", patchId.name },
}
);
if(affectedRows != 1)
@ -207,27 +192,26 @@ namespace Patcher
}
}
[Action]
public int Apply([Optional(false)] bool firstPatchOnly, [Optional(true)] bool interactive)
private int _Apply(bool firstPatchOnly)
{
return Wrap(interactive, () => {
Console.WriteLine("begin");
return Wrap(() => {
this.context.console.Report("begin");
List<PatchId> patchesToInstall;
List<PatchId> inputPatches = context.getPatchesList();
foreach (var patch in inputPatches)
{
Console.WriteLine("Found patch number {0:version}; author is {0:author}", patch);
this.context.console.Report("Found patch number {0:version}; name is {0:name}", patch);
}
using (Transaction transaction = TransactionFactory.Create(context))
using (Transaction transaction = this.context.CreateTransaction())
{
patchesToInstall = (
//We should install patches that didn't finished installing in the first place
from row in transaction.ExecuteReader(
string.Format(
"select {1}, {2} from {0} where {3} = {4} for update",
transaction.EscapeName(context.config.PatchesTable),
transaction.EscapeName(this.context.PatchesTable),
transaction.EscapeName("VERSION"),
transaction.EscapeName("AUTHOR"),
transaction.EscapeName("NAME"),
transaction.EscapeName("STATUS"),
transaction.MarkParam("pstatus")
),
@ -236,7 +220,7 @@ namespace Patcher
{ "pstatus", STATUS_INSTALLING },
}
)
let patch = new PatchId(int.Parse(row["VERSION"]), row["AUTHOR"])
let patch = new PatchId(int.Parse(row["VERSION"]), row["NAME"])
orderby patch ascending
select patch
)
@ -247,12 +231,12 @@ namespace Patcher
from row in transaction.ExecuteReader(
string.Format(
"select {1}, {2} from {0} for update",
transaction.EscapeName(context.config.PatchesTable),
transaction.EscapeName(this.context.PatchesTable),
transaction.EscapeName("VERSION"),
transaction.EscapeName("AUTHOR")
transaction.EscapeName("NAME")
)
)
let patch = new PatchId(int.Parse(row["VERSION"]), row["AUTHOR"])
let patch = new PatchId(int.Parse(row["VERSION"]), row["NAME"])
orderby patch ascending
select patch
)
@ -265,54 +249,48 @@ namespace Patcher
}
foreach (var patch in patchesToInstall)
{
Console.WriteLine("Going to install patch number {0:version}; author is {0:author}", patch);
this.context.console.Report("Going to install patch number {0:version}; name is {0:name}", patch);
}
if (patchesToInstall.Count == 0)
{
Console.WriteLine("No patches to install");
this.context.console.Report("No patches to install");
} else
{
bool shouldInstall = true;
if (interactive)
this.context.console.Report("Installing {0} patches...", patchesToInstall.Count);
foreach (var patch in patchesToInstall)
{
Console.WriteLine("Press Enter to install {0} patches or any key to exit", patchesToInstall.Count);
var info = Console.ReadKey(true);
if (info.Key != ConsoleKey.Enter) shouldInstall = false;
}
if (shouldInstall)
{
Console.WriteLine("Installing {0} patches...", patchesToInstall.Count);
foreach (var patch in patchesToInstall)
{
Console.Write("Installing patch #{0:version} from {0:author}...", patch);
InstallPatch(patch);
Console.WriteLine("done!");
}
Console.WriteLine("Finished installing patches");
} else
{
Console.WriteLine("Installation cancelled");
this.context.console.Report("Installing patch #{0:version} from {0:name}...", patch);
InstallPatch(patch);
this.context.console.Report("done!");
}
this.context.console.Report("Finished installing patches");
}
});
}
public int ApplyAll() {
return this._Apply(false);
}
public int ApplyFirstPatch() {
return this._Apply(true);
}
[Action]
public int Rollback([Optional(false)] bool lastPatchOnly, [Optional(true)] bool interactive)
private int _Rollback(bool lastPatchOnly)
{
return Wrap(interactive, () => {
Console.WriteLine("begin");
return Wrap(() => {
this.context.console.Report("begin");
List<PatchId> patchesToRemove;
using (Transaction transaction = TransactionFactory.Create(context))
using (Transaction transaction = this.context.CreateTransaction())
{
var patchesInstalling = (
from row in transaction.ExecuteReader(
string.Format(
"select {1}, {2} from {0} where {3} = {4} for update",
transaction.EscapeName(context.config.PatchesTable),
transaction.EscapeName(this.context.PatchesTable),
transaction.EscapeName("VERSION"),
transaction.EscapeName("AUTHOR"),
transaction.EscapeName("NAME"),
transaction.EscapeName("STATUS"),
transaction.MarkParam("pstatus")
),
@ -321,7 +299,7 @@ namespace Patcher
{ "pstatus", STATUS_INSTALLING },
}
)
let patch = new PatchId(int.Parse(row["VERSION"]), row["AUTHOR"])
let patch = new PatchId(int.Parse(row["VERSION"]), row["NAME"])
orderby patch ascending
select patch
).ToList();
@ -329,7 +307,7 @@ namespace Patcher
{
foreach(var patchInstalling in patchesInstalling)
{
Console.WriteLine("Patch #{0:version} from {0:author} is already installing", patchInstalling);
this.context.console.Report("Patch #{0:version} from {0:name} is already installing", patchInstalling);
}
throw new ApplicationException("Cannot uninstall patches while there are not installed ones");
}
@ -338,13 +316,13 @@ namespace Patcher
from row in transaction.ExecuteReader(
string.Format(
"select {1}, {2} from {0} for update order by {3} desc",
transaction.EscapeName(context.config.PatchesTable),
transaction.EscapeName(this.context.PatchesTable),
transaction.EscapeName("VERSION"),
transaction.EscapeName("AUTHOR"),
transaction.EscapeName("NAME"),
transaction.EscapeName("INSTALL_DATE")
)
)
let patch = new PatchId(int.Parse(row["VERSION"]), row["AUTHOR"])
let patch = new PatchId(int.Parse(row["VERSION"]), row["NAME"])
select patch
).ToList();
}
@ -354,37 +332,32 @@ namespace Patcher
}
foreach (var patch in patchesToRemove)
{
Console.WriteLine("Going to uninstall patch number {0:version}; author is {0:author}", patch);
this.context.console.Report("Going to uninstall patch number {0:version}; name is {0:name}", patch);
}
if (patchesToRemove.Count == 0)
{
Console.WriteLine("No patches to uninstall");
this.context.console.Report("No patches to uninstall");
} else
{
bool shouldInstall = true;
if (interactive)
{
Console.WriteLine("Press Enter to uninstall {0} patches or any key to exit", patchesToRemove.Count);
var info = Console.ReadKey(true);
if (info.Key != ConsoleKey.Enter) shouldInstall = false;
}
if (shouldInstall)
this.context.console.Report("Uninstalling {0} patches...", patchesToRemove.Count);
foreach (var patch in patchesToRemove)
{
Console.WriteLine("Uninstalling {0} patches...", patchesToRemove.Count);
foreach (var patch in patchesToRemove)
{
Console.Write("Uninstalling patch #{0:version} from {0:author}...", patch);
UninstallPatch(patch);
Console.WriteLine("done!");
}
Console.WriteLine("Finished uninstalling patches");
} else
{
Console.WriteLine("Uninstallation cancelled");
this.context.console.Report("Uninstalling patch #{0:version} from {0:name}...", patch);
UninstallPatch(patch);
this.context.console.Report("done!");
}
this.context.console.Report("Finished uninstalling patches");
}
});
}
public int RollbackAll() {
return this._Rollback(false);
}
public int RollbackLastPatch() {
return this._Rollback(true);
}
}
}

@ -1,34 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Patcher
{
class Cache<TKey, TValue>
{
public static readonly Cache<TKey, TValue> instance = new Cache<TKey, TValue>();
private readonly Dictionary<TKey, TValue> storage = new Dictionary<TKey, TValue>();
private Cache()
{
}
public TValue GetValue(TKey key, Func<TValue> creator)
{
if(!this.storage.ContainsKey(key))
{
lock(this.storage)
{
if(!this.storage.ContainsKey(key))
{
this.storage[key] = creator();
}
}
}
return this.storage[key];
}
}
}

@ -17,16 +17,7 @@ namespace Web.Core {
}
}
private NameValueCollection data;
public string AppInfo {
get {
return data["AppInfo"];
}
}
protected Config(NameValueCollection data) {
this.data = data;
protected Config() {
}
protected static void doInit(Func<T> configCreator) {
@ -37,7 +28,7 @@ namespace Web.Core {
}
}
protected static void doReInit(Func<T> configCreator) {
/*protected static void doReInit(Func<T> configCreator) {
lock(typeof(Config<T>)) {
_instance = configCreator();
}
@ -47,7 +38,7 @@ namespace Web.Core {
get {
return _instance != null;
}
}
}*/
public virtual void Dispose() {
}

@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Web.Core {
public interface IInteractiveConsole {
void Report(string message);
void Report(string format, params object[] data);
bool IsInteractive {
get;
}
bool Ask(string question);
void WaitForUserAction();
}
}

@ -81,6 +81,7 @@
<Compile Include="extensions\Extensions.cs" />
<Compile Include="extensions\String.cs" />
<Compile Include="IDataObject.cs" />
<Compile Include="IInteractiveConsole.cs" />
<Compile Include="ILogger.cs" />
<Compile Include="Network\IPv4.cs" />
<Compile Include="Network\IPv4Subnet.cs" />

Loading…
Cancel
Save