Added bit.ly support for distiributives download; Updated year in copyright text;

This commit is contained in:
ptsurbeleu 2012-02-14 23:15:45 -08:00
parent 8b7b150da7
commit 2dc3ced5cf
12 changed files with 1210 additions and 955 deletions

View file

@ -63,6 +63,24 @@
} }
"Entry" "Entry"
{ {
"MsmKey" = "8:_5FD334A6C47943FA9A98232EA921C90B"
"OwnerKey" = "8:_05F59A142DD147798C90054A203C0EE9"
"MsmSig" = "8:_UNDEFINED"
}
"Entry"
{
"MsmKey" = "8:_5FD334A6C47943FA9A98232EA921C90B"
"OwnerKey" = "8:_1239E87E938248B1BAF9BF75C32D3EDC"
"MsmSig" = "8:_UNDEFINED"
}
"Entry"
{
"MsmKey" = "8:_5FD334A6C47943FA9A98232EA921C90B"
"OwnerKey" = "8:_CFB0AE8275767700870555C8CDA92C96"
"MsmSig" = "8:_UNDEFINED"
}
"Entry"
{
"MsmKey" = "8:_BD9DC4338DFD4472BE5D099C388608B6" "MsmKey" = "8:_BD9DC4338DFD4472BE5D099C388608B6"
"OwnerKey" = "8:_UNDEFINED" "OwnerKey" = "8:_UNDEFINED"
"MsmSig" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED"
@ -294,6 +312,37 @@
"IsDependency" = "11:FALSE" "IsDependency" = "11:FALSE"
"IsolateTo" = "8:" "IsolateTo" = "8:"
} }
"{9F6F8455-1EF1-4B85-886A-4223BCC8E7F7}:_5FD334A6C47943FA9A98232EA921C90B"
{
"AssemblyRegister" = "3:1"
"AssemblyIsInGAC" = "11:FALSE"
"AssemblyAsmDisplayName" = "8:Ionic.Zip.Reduced, Version=1.8.4.28, Culture=neutral, PublicKeyToken=edbe51ad942a3f5c, processorArchitecture=MSIL"
"ScatterAssemblies"
{
"_5FD334A6C47943FA9A98232EA921C90B"
{
"Name" = "8:Ionic.Zip.Reduced.dll"
"Attributes" = "3:512"
}
}
"SourcePath" = "8:Ionic.Zip.Reduced.dll"
"TargetName" = "8:"
"Tag" = "8:"
"Folder" = "8:_E742E59BFE4D43C59AA65A07792B89FB"
"Condition" = "8:"
"Transitive" = "11:FALSE"
"Vital" = "11:TRUE"
"ReadOnly" = "11:FALSE"
"Hidden" = "11:FALSE"
"System" = "11:FALSE"
"Permanent" = "11:FALSE"
"SharedLegacy" = "11:FALSE"
"PackageAs" = "3:1"
"Register" = "3:1"
"Exclude" = "11:FALSE"
"IsDependency" = "11:TRUE"
"IsolateTo" = "8:"
}
"{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_BD9DC4338DFD4472BE5D099C388608B6" "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_BD9DC4338DFD4472BE5D099C388608B6"
{ {
"SourcePath" = "8:Banner.bmp" "SourcePath" = "8:Banner.bmp"
@ -407,15 +456,15 @@
{ {
"Name" = "8:Microsoft Visual Studio" "Name" = "8:Microsoft Visual Studio"
"ProductName" = "8:WebsitePanel Installer" "ProductName" = "8:WebsitePanel Installer"
"ProductCode" = "8:{09BCDF68-1964-4FC6-9570-9AB3B8512CF6}" "ProductCode" = "8:{A22F374C-4AFC-4B5D-A509-7456A6107588}"
"PackageCode" = "8:{D94FF2E6-1D7D-4E33-8528-C7B6BFADEC99}" "PackageCode" = "8:{401F157D-6D55-4F66-A2C6-419F87BBF97D}"
"UpgradeCode" = "8:{2950A907-11E7-436C-86CE-049C414AFD08}" "UpgradeCode" = "8:{2950A907-11E7-436C-86CE-049C414AFD08}"
"AspNetVersion" = "8:4.0.30319.0" "AspNetVersion" = "8:4.0.30319.0"
"RestartWWWService" = "11:FALSE" "RestartWWWService" = "11:FALSE"
"RemovePreviousVersions" = "11:FALSE" "RemovePreviousVersions" = "11:FALSE"
"DetectNewerInstalledVersion" = "11:FALSE" "DetectNewerInstalledVersion" = "11:FALSE"
"InstallAllUsers" = "11:TRUE" "InstallAllUsers" = "11:TRUE"
"ProductVersion" = "8:1.2.0" "ProductVersion" = "8:1.2.1"
"Manufacturer" = "8:Outercurve Foundation" "Manufacturer" = "8:Outercurve Foundation"
"ARPHELPTELEPHONE" = "8:" "ARPHELPTELEPHONE" = "8:"
"ARPHELPLINK" = "8:" "ARPHELPLINK" = "8:"

View file

@ -1,4 +1,4 @@
// Copyright (c) 2011, Outercurve Foundation. // Copyright (c) 2012, Outercurve Foundation.
// All rights reserved. // All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without modification, // Redistribution and use in source and binary forms, with or without modification,
@ -35,7 +35,7 @@ using System.Reflection;
// Revision // Revision
// //
[assembly: AssemblyCompany("Outercurve Foundation")] [assembly: AssemblyCompany("Outercurve Foundation")]
[assembly: AssemblyCopyright("Copyright © 2011 Outercurve Foundation.")] [assembly: AssemblyCopyright("Copyright © 2012 Outercurve Foundation.")]
[assembly: AssemblyVersion("1.2.0.0")] [assembly: AssemblyVersion("1.2.1.0")]
[assembly: AssemblyFileVersion("1.2.0.38")] [assembly: AssemblyFileVersion("1.2.1.0")]
[assembly: AssemblyInformationalVersion("1.2.0")] [assembly: AssemblyInformationalVersion("1.2.1")]

View file

@ -1,4 +1,4 @@
// Copyright (c) 2011, Outercurve Foundation. // Copyright (c) 2012, Outercurve Foundation.
// All rights reserved. // All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without modification, // Redistribution and use in source and binary forms, with or without modification,
@ -34,43 +34,43 @@ using System.IO;
namespace WebsitePanel.Installer.Common namespace WebsitePanel.Installer.Common
{ {
/// <summary> /// <summary>
/// File utils. /// File utils.
/// </summary> /// </summary>
public sealed class FileUtils public sealed class FileUtils
{ {
/// <summary> /// <summary>
/// Initializes a new instance of the class. /// Initializes a new instance of the class.
/// </summary> /// </summary>
private FileUtils() private FileUtils()
{ {
} }
/// <summary> /// <summary>
/// Creates drectory with the specified directory. /// Creates drectory with the specified directory.
/// </summary> /// </summary>
/// <param name="path">The directory path to create.</param> /// <param name="path">The directory path to create.</param>
public static void CreateDirectory(string path) public static void CreateDirectory(string path)
{ {
string dir = Path.GetDirectoryName(path); string dir = Path.GetDirectoryName(path);
if(!Directory.Exists(dir)) if(!Directory.Exists(dir))
{ {
// create directory structure // create directory structure
Directory.CreateDirectory(dir); Directory.CreateDirectory(dir);
} }
} }
/// <summary> /// <summary>
/// Saves file content. /// Saves file content.
/// </summary> /// </summary>
/// <param name="fileName">File name.</param> /// <param name="fileName">File name.</param>
/// <param name="content">The array of bytes to write.</param> /// <param name="content">The array of bytes to write.</param>
public static void SaveFileContent(string fileName, byte[] content) public static void SaveFileContent(string fileName, byte[] content)
{ {
FileStream stream = new FileStream(fileName, FileMode.Create); FileStream stream = new FileStream(fileName, FileMode.Create);
stream.Write(content, 0, content.Length); stream.Write(content, 0, content.Length);
stream.Close(); stream.Close();
} }
/// <summary> /// <summary>
/// Saves file content. /// Saves file content.
@ -84,188 +84,203 @@ namespace WebsitePanel.Installer.Common
stream.Close(); stream.Close();
} }
/// <summary> /// <summary>
/// Deletes the specified file. /// Deletes the specified file.
/// </summary> /// </summary>
/// <param name="fileName">The name of the file to be deleted.</param> /// <param name="fileName">The name of the file to be deleted.</param>
public static void DeleteFile(string fileName) public static void DeleteFile(string fileName)
{ {
int attempts = 0; int attempts = 0;
while (true) while (true)
{ {
try try
{ {
DeleteFileInternal(fileName); DeleteFileInternal(fileName);
break; break;
} }
catch (Exception) catch (Exception)
{ {
if (attempts > 2) if (attempts > 2)
throw; throw;
attempts++; attempts++;
System.Threading.Thread.Sleep(1000); System.Threading.Thread.Sleep(1000);
} }
} }
} }
/// <summary> /// <summary>
/// Deletes the specified file. /// Deletes the specified file.
/// </summary> /// </summary>
/// <param name="fileName">The name of the file to be deleted.</param> /// <param name="fileName">The name of the file to be deleted.</param>
private static void DeleteReadOnlyFile(string fileName) private static void DeleteReadOnlyFile(string fileName)
{ {
FileInfo info = new FileInfo(fileName); FileInfo info = new FileInfo(fileName);
info.Attributes = FileAttributes.Normal; info.Attributes = FileAttributes.Normal;
info.Delete(); info.Delete();
} }
/// <summary> /// <summary>
/// Deletes the specified file. /// Deletes the specified file.
/// </summary> /// </summary>
/// <param name="fileName">The name of the file to be deleted.</param> /// <param name="fileName">The name of the file to be deleted.</param>
private static void DeleteFileInternal(string fileName) private static void DeleteFileInternal(string fileName)
{ {
try try
{ {
File.Delete(fileName); File.Delete(fileName);
} }
catch (UnauthorizedAccessException) catch (UnauthorizedAccessException)
{ {
DeleteReadOnlyFile(fileName); DeleteReadOnlyFile(fileName);
} }
} }
/// <summary> /// <summary>
/// Deletes the specified directory. /// Deletes the specified directory.
/// </summary> /// </summary>
/// <param name="directory">The name of the directory to be deleted.</param> /// <param name="directory">The name of the directory to be deleted.</param>
public static void DeleteDirectory(string directory) public static void DeleteDirectory(string directory)
{ {
if (!Directory.Exists(directory)) if (!Directory.Exists(directory))
return; return;
// iterate through child folders // iterate through child folders
string[] dirs = Directory.GetDirectories(directory); string[] dirs = Directory.GetDirectories(directory);
foreach (string dir in dirs) foreach (string dir in dirs)
{ {
DeleteDirectory(dir); DeleteDirectory(dir);
} }
// iterate through child files // iterate through child files
string[] files = Directory.GetFiles(directory); string[] files = Directory.GetFiles(directory);
foreach (string file in files) foreach (string file in files)
{ {
DeleteFile(file); DeleteFile(file);
} }
//try to delete dir for 3 times //try to delete dir for 3 times
int attempts = 0; int attempts = 0;
while (true) while (true)
{ {
try try
{ {
DeleteDirectoryInternal(directory); DeleteDirectoryInternal(directory);
break; break;
} }
catch (Exception) catch (Exception)
{ {
if (attempts > 2) if (attempts > 2)
throw; throw;
attempts++; attempts++;
System.Threading.Thread.Sleep(1000); System.Threading.Thread.Sleep(1000);
} }
} }
} }
/// <summary> /// <summary>
/// Deletes the specified directory. /// Deletes the specified directory.
/// </summary> /// </summary>
/// <param name="directory">The name of the directory to be deleted.</param> /// <param name="directory">The name of the directory to be deleted.</param>
private static void DeleteDirectoryInternal(string directory) private static void DeleteDirectoryInternal(string directory)
{ {
try try
{ {
Directory.Delete(directory); Directory.Delete(directory);
} }
catch (IOException) catch (IOException)
{ {
DeleteReadOnlyDirectory(directory); DeleteReadOnlyDirectory(directory);
} }
} }
/// <summary> /// <summary>
/// Deletes the specified directory. /// Deletes the specified directory.
/// </summary> /// </summary>
/// <param name="directory">The name of the directory to be deleted.</param> /// <param name="directory">The name of the directory to be deleted.</param>
private static void DeleteReadOnlyDirectory(string directory) private static void DeleteReadOnlyDirectory(string directory)
{ {
DirectoryInfo info = new DirectoryInfo(directory); DirectoryInfo info = new DirectoryInfo(directory);
info.Attributes = FileAttributes.Normal; info.Attributes = FileAttributes.Normal;
info.Delete(); info.Delete();
} }
/// <summary> /// <summary>
/// Determines whether the specified file exists. /// Determines whether the specified file exists.
/// </summary> /// </summary>
/// <param name="fileName">The path to check.</param> /// <param name="fileName">The path to check.</param>
/// <returns></returns> /// <returns></returns>
public static bool FileExists(string fileName) public static bool FileExists(string fileName)
{ {
return File.Exists(fileName); return File.Exists(fileName);
} }
/// <summary> /// <summary>
/// Determines whether the given path refers to an existing directory on disk. /// Determines whether the given path refers to an existing directory on disk.
/// </summary> /// </summary>
/// <param name="path">The path to test.</param> /// <param name="path">The path to test.</param>
/// <returns></returns> /// <returns></returns>
public static bool DirectoryExists(string path) public static bool DirectoryExists(string path)
{ {
return Directory.Exists(path); return Directory.Exists(path);
} }
/// <summary> /// <summary>
/// Returns current application path. /// Returns current application path.
/// </summary> /// </summary>
/// <returns>Curent application path.</returns> /// <returns>Curent application path.</returns>
public static string GetCurrentDirectory() public static string GetCurrentDirectory()
{ {
return AppDomain.CurrentDomain.BaseDirectory; return AppDomain.CurrentDomain.BaseDirectory;
} }
/// <summary> /// <summary>
/// Returns application temp directory. /// Returns application temp directory.
/// </summary> /// </summary>
/// <returns>Application temp directory.</returns> /// <returns>Application temp directory.</returns>
public static string GetTempDirectory() public static string GetTempDirectory()
{ {
return Path.Combine(GetCurrentDirectory(), "Tmp"); return Path.Combine(GetCurrentDirectory(), "Tmp");
} }
/// <summary> /// <summary>
/// Returns application data directory. /// Returns application data directory.
/// </summary> /// </summary>
/// <returns>Application data directory.</returns> /// <returns>Application data directory.</returns>
public static string GetDataDirectory() public static string GetDataDirectory()
{ {
return Path.Combine(GetCurrentDirectory(), "Data"); return Path.Combine(GetCurrentDirectory(), "Data");
} }
/// <summary> /// <summary>
/// Deletes application temp directory. /// Deletes application's Data folder.
/// </summary> /// </summary>
public static void DeleteTempDirectory() public static void DeleteDataDirectory()
{ {
try try
{ {
DeleteDirectory(GetTempDirectory()); DeleteDirectory(GetDataDirectory());
} }
catch (Exception ex) catch (Exception ex)
{ {
Log.WriteError("IO Error", ex); Log.WriteError("IO Error", ex);
} }
} }
}
/// <summary>
/// Deletes application Tmp directory.
/// </summary>
public static void DeleteTempDirectory()
{
try
{
DeleteDirectory(GetTempDirectory());
}
catch (Exception ex)
{
Log.WriteError("IO Error", ex);
}
}
}
} }

View file

@ -1,4 +1,4 @@
// Copyright (c) 2011, Outercurve Foundation. // Copyright (c) 2012, Outercurve Foundation.
// All rights reserved. // All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without modification, // Redistribution and use in source and binary forms, with or without modification,
@ -45,6 +45,7 @@ using System.Threading;
using WebsitePanel.Installer.Core; using WebsitePanel.Installer.Core;
using WebsitePanel.Installer.Configuration; using WebsitePanel.Installer.Configuration;
using System.Xml; using System.Xml;
using System.Data;
namespace WebsitePanel.Installer.Common namespace WebsitePanel.Installer.Common
{ {
@ -389,5 +390,23 @@ namespace WebsitePanel.Installer.Common
mutex = new Mutex(true, "WebsitePanel Installer", out createdNew); mutex = new Mutex(true, "WebsitePanel Installer", out createdNew);
return createdNew; return createdNew;
} }
public static string GetDistributiveLocationInfo(string ccode, string cversion)
{
var service = ServiceProviderProxy.GetInstallerWebService();
//
DataSet ds = service.GetReleaseFileInfo(ccode, cversion);
//
if (ds == null || ds.Tables.Count == 0 || ds.Tables[0].Rows.Count == 0)
{
Log.WriteInfo("Component code: {0}; Component version: {1};", ccode, cversion);
//
throw new ServiceComponentNotFoundException("Seems that the Service has no idea about the component requested.");
}
//
DataRow row = ds.Tables[0].Rows[0];
//
return row["FullFilePath"].ToString();
}
} }
} }

View file

@ -1,4 +1,4 @@
// Copyright (c) 2011, Outercurve Foundation. // Copyright (c) 2012, Outercurve Foundation.
// All rights reserved. // All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without modification, // Redistribution and use in source and binary forms, with or without modification,
@ -36,380 +36,495 @@ using System.Text;
using Ionic.Zip; using Ionic.Zip;
using WebsitePanel.Installer.Common; using WebsitePanel.Installer.Common;
using System.Net;
using System.Text.RegularExpressions;
using System.Collections;
using System.Threading.Tasks;
using System.Reflection;
using System.Diagnostics;
namespace WebsitePanel.Installer.Core namespace WebsitePanel.Installer.Core
{ {
public class LoaderEventArgs<T> : EventArgs public class LoaderEventArgs<T> : EventArgs
{ {
public string StatusMessage { get; set; } public string StatusMessage { get; set; }
public T EventData { get; set; } public T EventData { get; set; }
public bool Cancellable { get; set; } public bool Cancellable { get; set; }
} }
/// <summary> public static class LoaderFactory
/// Loader form. {
/// </summary> /// <summary>
public partial class Loader /// Instantiates either BitlyLoader or InstallerServiceLoader based on remote file format.
{ /// </summary>
public const string ConnectingRemotServiceMessage = "Connecting..."; /// <param name="remoteFile"></param>
public const string DownloadingSetupFilesMessage = "Downloading setup files..."; /// <returns></returns>
public const string CopyingSetupFilesMessage = "Copying setup files..."; public static Loader CreateFileLoader(string remoteFile)
public const string PreparingSetupFilesMessage = "Please wait while Setup prepares the necessary files..."; {
public const string DownloadProgressMessage = "{0} KB of {1} KB"; Debug.Assert(!String.IsNullOrEmpty(remoteFile), "Remote file is empty");
public const string PrepareSetupProgressMessage = "{0}%";
private const int ChunkSize = 262144; if (remoteFile.StartsWith("http://bit.ly/"))
private Thread thread; {
private string localFile; return new BitlyLoader(remoteFile);
private string remoteFile; }
private string componentCode; else
private string version; {
return new Loader(remoteFile);
}
}
}
public event EventHandler<LoaderEventArgs<String>> StatusChanged; public class BitlyLoader : Loader
public event EventHandler<LoaderEventArgs<Exception>> OperationFailed; {
public event EventHandler<LoaderEventArgs<Int32>> ProgressChanged; public const string WEB_PI_USER_AGENT_HEADER = "PI-Integrator/3.0.0.0({0})";
public event EventHandler<EventArgs> OperationCompleted;
public Loader(string remoteFile) private WebClient fileLoader;
{
this.remoteFile = remoteFile;
}
public Loader(string localFile, string componentCode, string version) public BitlyLoader(string remoteFile)
{ : base(remoteFile)
this.localFile = localFile; {
this.componentCode = componentCode; InitFileLoader();
this.version = version; }
}
public void LoadAppDistributive() private void InitFileLoader()
{ {
thread = new Thread(new ThreadStart(LoadAppDistributiveInternal)); fileLoader = new WebClient();
thread.Start(); // Set HTTP header for Codeplex to allow direct downloads
} fileLoader.Headers.Add("User-Agent", String.Format(WEB_PI_USER_AGENT_HEADER, Assembly.GetExecutingAssembly().FullName));
}
private void RaiseOnStatusChangedEvent(string statusMessage) protected override Task GetDownloadFileTask(string remoteFile, string tmpFile, CancellationToken ct)
{ {
RaiseOnStatusChangedEvent(statusMessage, String.Empty); var downloadFileTask = new Task(() =>
} {
if (!File.Exists(tmpFile))
{
// Mimic synchronous file download operation because we need to track the download progress
// and be able to cancel the operation in progress
AutoResetEvent autoEvent = new AutoResetEvent(false);
private void RaiseOnStatusChangedEvent(string statusMessage, string eventData) if (fileLoader.IsBusy.Equals(true))
{ {
RaiseOnStatusChangedEvent(statusMessage, eventData, true); return;
} }
private void RaiseOnStatusChangedEvent(string statusMessage, string eventData, bool cancellable) ct.Register(() =>
{ {
if (StatusChanged == null) fileLoader.CancelAsync();
{ });
return;
}
// No event data for status updates
StatusChanged(this, new LoaderEventArgs<String> {
StatusMessage = statusMessage,
EventData = eventData,
Cancellable = cancellable
});
}
private void RaiseOnProgressChangedEvent(int eventData) Log.WriteStart("Downloading file");
{ Log.WriteInfo("Downloading file \"{0}\" to \"{1}\"", remoteFile, tmpFile);
RaiseOnProgressChangedEvent(eventData, true);
}
private void RaiseOnProgressChangedEvent(int eventData, bool cancellable) // Attach event handlers to track status of the download process
{ fileLoader.DownloadProgressChanged += (obj, e) =>
if (ProgressChanged == null) {
{ if (ct.IsCancellationRequested)
return; return;
}
//
ProgressChanged(this, new LoaderEventArgs<int> {
EventData = eventData,
Cancellable = cancellable
});
}
private void RaiseOnOperationFailedEvent(Exception ex) RaiseOnProgressChangedEvent(e.ProgressPercentage);
{ RaiseOnStatusChangedEvent(DownloadingSetupFilesMessage,
if (OperationFailed == null) String.Format(DownloadProgressMessage, e.BytesReceived / 1024, e.TotalBytesToReceive / 1024));
{ };
return;
}
//
OperationFailed(this, new LoaderEventArgs<Exception> { EventData = ex });
}
private void RaiseOnOperationCompletedEvent() fileLoader.DownloadFileCompleted += (obj, e) =>
{ {
if (OperationCompleted == null) if (ct.IsCancellationRequested == false)
{ {
return; RaiseOnProgressChangedEvent(100);
} RaiseOnStatusChangedEvent(DownloadingSetupFilesMessage, "100%");
// }
OperationCompleted(this, EventArgs.Empty);
}
/// <summary> if (e.Cancelled)
/// Displays process progress. {
/// </summary> CancelDownload(tmpFile);
private void LoadAppDistributiveInternal() }
{
//
try
{
var service = ServiceProviderProxy.GetInstallerWebService();
//
string dataFolder = FileUtils.GetDataDirectory();
string tmpFolder = FileUtils.GetTempDirectory();
if (!Directory.Exists(dataFolder)) autoEvent.Set();
{ };
Directory.CreateDirectory(dataFolder);
Log.WriteInfo("Data directory created");
}
if (Directory.Exists(tmpFolder)) fileLoader.DownloadFileAsync(new Uri(remoteFile), tmpFile);
{ RaiseOnStatusChangedEvent(DownloadingSetupFilesMessage);
FileUtils.DeleteTempDirectory();
}
if (!Directory.Exists(tmpFolder)) autoEvent.WaitOne();
{ }
Directory.CreateDirectory(tmpFolder); }, ct);
Log.WriteInfo("Tmp directory created");
}
string fileToDownload = null; return downloadFileTask;
if (!string.IsNullOrEmpty(localFile)) }
{ }
fileToDownload = localFile;
}
else
{
fileToDownload = Path.GetFileName(remoteFile);
}
string destinationFile = Path.Combine(dataFolder, fileToDownload); /// <summary>
string tmpFile = Path.Combine(tmpFolder, fileToDownload); /// Loader form.
/// </summary>
public class Loader
{
public const string ConnectingRemotServiceMessage = "Connecting...";
public const string DownloadingSetupFilesMessage = "Downloading setup files...";
public const string CopyingSetupFilesMessage = "Copying setup files...";
public const string PreparingSetupFilesMessage = "Please wait while Setup prepares the necessary files...";
public const string DownloadProgressMessage = "{0} KB of {1} KB";
public const string PrepareSetupProgressMessage = "{0}%";
//check whether file already downloaded private const int ChunkSize = 262144;
if (!File.Exists(destinationFile)) private string remoteFile;
{ private CancellationTokenSource cts;
if (string.IsNullOrEmpty(remoteFile))
{
//need to get remote file name
RaiseOnStatusChangedEvent(ConnectingRemotServiceMessage);
//
RaiseOnProgressChangedEvent(0);
//
DataSet ds = service.GetReleaseFileInfo(componentCode, version);
//
RaiseOnProgressChangedEvent(100);
//
if (ds != null &&
ds.Tables.Count > 0 &&
ds.Tables[0].Rows.Count > 0)
{
DataRow row = ds.Tables[0].Rows[0];
remoteFile = row["FullFilePath"].ToString();
fileToDownload = Path.GetFileName(remoteFile);
destinationFile = Path.Combine(dataFolder, fileToDownload);
tmpFile = Path.Combine(tmpFolder, fileToDownload);
}
else
{
throw new Exception("Installer not found");
}
}
// download file to tmp folder public event EventHandler<LoaderEventArgs<String>> StatusChanged;
RaiseOnStatusChangedEvent(DownloadingSetupFilesMessage); public event EventHandler<LoaderEventArgs<Exception>> OperationFailed;
// public event EventHandler<LoaderEventArgs<Int32>> ProgressChanged;
RaiseOnProgressChangedEvent(0); public event EventHandler<EventArgs> OperationCompleted;
//
DownloadFile(remoteFile, tmpFile);
//
RaiseOnProgressChangedEvent(100);
// copy downloaded file to data folder public Loader(string remoteFile)
RaiseOnStatusChangedEvent(CopyingSetupFilesMessage); {
// this.remoteFile = remoteFile;
RaiseOnProgressChangedEvent(0); }
// Ensure that the target does not exist. public void LoadAppDistributive()
if (File.Exists(destinationFile)) {
FileUtils.DeleteFile(destinationFile); ThreadPool.QueueUserWorkItem(q => LoadAppDistributiveInternal());
File.Move(tmpFile, destinationFile); }
//
RaiseOnProgressChangedEvent(100);
}
// unzip file protected void RaiseOnStatusChangedEvent(string statusMessage)
RaiseOnStatusChangedEvent(PreparingSetupFilesMessage); {
// RaiseOnStatusChangedEvent(statusMessage, String.Empty);
RaiseOnProgressChangedEvent(0); }
//
UnzipFile(destinationFile, tmpFolder);
//
RaiseOnProgressChangedEvent(100);
//
RaiseOnOperationCompletedEvent();
}
catch (Exception ex)
{
if (Utils.IsThreadAbortException(ex))
return;
Log.WriteError("Loader module error", ex); protected void RaiseOnStatusChangedEvent(string statusMessage, string eventData)
// {
RaiseOnOperationFailedEvent(ex); RaiseOnStatusChangedEvent(statusMessage, eventData, true);
} }
}
private void DownloadFile(string sourceFile, string destinationFile) protected void RaiseOnStatusChangedEvent(string statusMessage, string eventData, bool cancellable)
{ {
try if (StatusChanged == null)
{ {
var service = ServiceProviderProxy.GetInstallerWebService(); return;
// }
Log.WriteStart("Downloading file"); // No event data for status updates
Log.WriteInfo(string.Format("Downloading file \"{0}\" to \"{1}\"", sourceFile, destinationFile)); StatusChanged(this, new LoaderEventArgs<String>
{
StatusMessage = statusMessage,
EventData = eventData,
Cancellable = cancellable
});
}
long downloaded = 0; protected void RaiseOnProgressChangedEvent(int eventData)
long fileSize = service.GetFileSize(sourceFile); {
if (fileSize == 0) RaiseOnProgressChangedEvent(eventData, true);
{ }
throw new FileNotFoundException("Service returned empty file.", sourceFile);
}
byte[] content; protected void RaiseOnProgressChangedEvent(int eventData, bool cancellable)
{
if (ProgressChanged == null)
{
return;
}
//
ProgressChanged(this, new LoaderEventArgs<int>
{
EventData = eventData,
Cancellable = cancellable
});
}
while (downloaded < fileSize) protected void RaiseOnOperationFailedEvent(Exception ex)
{ {
content = service.GetFileChunk(sourceFile, (int)downloaded, ChunkSize); if (OperationFailed == null)
if (content == null) {
{ return;
throw new FileNotFoundException("Service returned NULL file content.", sourceFile); }
} //
FileUtils.AppendFileContent(destinationFile, content); OperationFailed(this, new LoaderEventArgs<Exception> { EventData = ex });
downloaded += content.Length; }
//update progress bar
RaiseOnStatusChangedEvent(DownloadingSetupFilesMessage,
string.Format(DownloadProgressMessage, downloaded / 1024, fileSize / 1024));
//
RaiseOnProgressChangedEvent(Convert.ToInt32((downloaded * 100) / fileSize));
if (content.Length < ChunkSize) protected void RaiseOnOperationCompletedEvent()
break; {
} if (OperationCompleted == null)
// {
RaiseOnStatusChangedEvent(DownloadingSetupFilesMessage, "100%"); return;
// }
Log.WriteEnd(string.Format("Downloaded {0} bytes", downloaded)); //
} OperationCompleted(this, EventArgs.Empty);
catch (Exception ex) }
{
if (Utils.IsThreadAbortException(ex))
return;
throw; /// <summary>
} /// Executes a file download request asynchronously
} /// </summary>
private void LoadAppDistributiveInternal()
{
try
{
string dataFolder;
string tmpFolder;
// Retrieve local storage configuration
GetLocalStorageInfo(out dataFolder, out tmpFolder);
// Initialize storage
InitializeLocalStorage(dataFolder, tmpFolder);
private void UnzipFile(string zipFile, string destFolder) string fileToDownload = Path.GetFileName(remoteFile);
{
try
{
int val = 0;
// Negative value means no progress made yet
int progress = -1;
//
Log.WriteStart("Unzipping file");
Log.WriteInfo(string.Format("Unzipping file \"{0}\" to the folder \"{1}\"", zipFile, destFolder));
long zipSize = 0; string destinationFile = Path.Combine(dataFolder, fileToDownload);
var zipInfo = ZipFile.Read(zipFile); string tmpFile = Path.Combine(tmpFolder, fileToDownload);
try
{
foreach (ZipEntry entry in zipInfo)
{
if (!entry.IsDirectory)
zipSize += entry.UncompressedSize;
}
}
finally
{
if (zipInfo != null)
{
zipInfo.Dispose();
}
}
long unzipped = 0; cts = new CancellationTokenSource();
// CancellationToken token = cts.Token;
var zip = ZipFile.Read(zipFile);
//
try
{
foreach (ZipEntry entry in zip)
{
//
entry.Extract(destFolder, ExtractExistingFileAction.OverwriteSilently);
//
if (!entry.IsDirectory)
unzipped += entry.UncompressedSize;
if (zipSize != 0) try
{ {
val = Convert.ToInt32(unzipped * 100 / zipSize); // Download the file requested
// Skip to raise the progress event change when calculated progress Task downloadFileTask = GetDownloadFileTask(remoteFile, tmpFile, token);
// and the current progress value are even // Move the file downloaded from temporary location to Data folder
if (val == progress) var moveFileTask = downloadFileTask.ContinueWith((t) =>
{ {
continue; if (File.Exists(tmpFile))
} {
// // copy downloaded file to data folder
RaiseOnStatusChangedEvent( RaiseOnStatusChangedEvent(CopyingSetupFilesMessage);
PreparingSetupFilesMessage, //
String.Format(PrepareSetupProgressMessage, val), RaiseOnProgressChangedEvent(0);
false);
//
RaiseOnProgressChangedEvent(val, false);
}
}
// Notify client the operation can be cancelled at this time
RaiseOnProgressChangedEvent(100);
//
Log.WriteEnd("Unzipped file");
}
finally
{
if (zip != null)
{
zip.Dispose();
}
}
}
catch (Exception ex)
{
if (Utils.IsThreadAbortException(ex))
return;
//
RaiseOnOperationFailedEvent(ex);
}
}
public void AbortOperation() // Ensure that the target does not exist.
{ if (File.Exists(destinationFile))
if (thread != null) FileUtils.DeleteFile(destinationFile);
{ File.Move(tmpFile, destinationFile);
if (thread.IsAlive) //
{ RaiseOnProgressChangedEvent(100);
thread.Abort(); }
} }, TaskContinuationOptions.NotOnCanceled);
thread.Join(); // Unzip file downloaded
} var unzipFileTask = moveFileTask.ContinueWith((t) =>
} {
} if (File.Exists(destinationFile))
{
RaiseOnStatusChangedEvent(PreparingSetupFilesMessage);
//
RaiseOnProgressChangedEvent(0);
//
UnzipFile(destinationFile, tmpFolder);
//
RaiseOnProgressChangedEvent(100);
}
}, token);
//
var notifyCompletionTask = unzipFileTask.ContinueWith((t) =>
{
RaiseOnOperationCompletedEvent();
}, token);
downloadFileTask.Start();
downloadFileTask.Wait();
}
catch (AggregateException ae)
{
ae.Handle((e) =>
{
// We handle cancellation requests
if (e is OperationCanceledException)
{
CancelDownload(tmpFile);
Log.WriteInfo("Download has been cancelled by the user");
return true;
}
// But other issues just being logged
Log.WriteError("Could not download the file", e);
return false;
});
}
}
catch (Exception ex)
{
if (Utils.IsThreadAbortException(ex))
return;
Log.WriteError("Loader module error", ex);
//
RaiseOnOperationFailedEvent(ex);
}
}
protected virtual Task GetDownloadFileTask(string sourceFile, string tmpFile, CancellationToken ct)
{
var downloadFileTask = new Task(() =>
{
if (!File.Exists(tmpFile))
{
var service = ServiceProviderProxy.GetInstallerWebService();
RaiseOnProgressChangedEvent(0);
RaiseOnStatusChangedEvent(DownloadingSetupFilesMessage);
Log.WriteStart("Downloading file");
Log.WriteInfo(string.Format("Downloading file \"{0}\" to \"{1}\"", sourceFile, tmpFile));
long downloaded = 0;
long fileSize = service.GetFileSize(sourceFile);
if (fileSize == 0)
{
throw new FileNotFoundException("Service returned empty file.", sourceFile);
}
byte[] content;
while (downloaded < fileSize)
{
// Throw OperationCancelledException if there is an incoming cancel request
ct.ThrowIfCancellationRequested();
content = service.GetFileChunk(sourceFile, (int)downloaded, ChunkSize);
if (content == null)
{
throw new FileNotFoundException("Service returned NULL file content.", sourceFile);
}
FileUtils.AppendFileContent(tmpFile, content);
downloaded += content.Length;
// Update download progress
RaiseOnStatusChangedEvent(DownloadingSetupFilesMessage,
string.Format(DownloadProgressMessage, downloaded / 1024, fileSize / 1024));
RaiseOnProgressChangedEvent(Convert.ToInt32((downloaded * 100) / fileSize));
if (content.Length < ChunkSize)
break;
}
RaiseOnStatusChangedEvent(DownloadingSetupFilesMessage, "100%");
Log.WriteEnd(string.Format("Downloaded {0} bytes", downloaded));
}
}, ct);
return downloadFileTask;
}
private static void InitializeLocalStorage(string dataFolder, string tmpFolder)
{
if (!Directory.Exists(dataFolder))
{
Directory.CreateDirectory(dataFolder);
Log.WriteInfo("Data directory created");
}
if (Directory.Exists(tmpFolder))
{
Directory.Delete(tmpFolder, true);
}
if (!Directory.Exists(tmpFolder))
{
Directory.CreateDirectory(tmpFolder);
Log.WriteInfo("Tmp directory created");
}
}
private static void GetLocalStorageInfo(out string dataFolder, out string tmpFolder)
{
dataFolder = FileUtils.GetDataDirectory();
tmpFolder = FileUtils.GetTempDirectory();
}
private void UnzipFile(string zipFile, string destFolder)
{
try
{
int val = 0;
// Negative value means no progress made yet
int progress = -1;
//
Log.WriteStart("Unzipping file");
Log.WriteInfo(string.Format("Unzipping file \"{0}\" to the folder \"{1}\"", zipFile, destFolder));
long zipSize = 0;
var zipInfo = ZipFile.Read(zipFile);
try
{
foreach (ZipEntry entry in zipInfo)
{
if (!entry.IsDirectory)
zipSize += entry.UncompressedSize;
}
}
finally
{
if (zipInfo != null)
{
zipInfo.Dispose();
}
}
long unzipped = 0;
//
var zip = ZipFile.Read(zipFile);
//
try
{
foreach (ZipEntry entry in zip)
{
//
entry.Extract(destFolder, ExtractExistingFileAction.OverwriteSilently);
//
if (!entry.IsDirectory)
unzipped += entry.UncompressedSize;
if (zipSize != 0)
{
val = Convert.ToInt32(unzipped * 100 / zipSize);
// Skip to raise the progress event change when calculated progress
// and the current progress value are even
if (val == progress)
{
continue;
}
//
RaiseOnStatusChangedEvent(
PreparingSetupFilesMessage,
String.Format(PrepareSetupProgressMessage, val),
false);
//
RaiseOnProgressChangedEvent(val, false);
}
}
// Notify client the operation can be cancelled at this time
RaiseOnProgressChangedEvent(100);
//
Log.WriteEnd("Unzipped file");
}
finally
{
if (zip != null)
{
zip.Dispose();
}
}
}
catch (Exception ex)
{
if (Utils.IsThreadAbortException(ex))
return;
//
RaiseOnOperationFailedEvent(ex);
}
}
/// <summary>
/// Cleans up temporary file if the download process has been cancelled.
/// </summary>
/// <param name="tmpFile">Path to the temporary file to cleanup</param>
protected virtual void CancelDownload(string tmpFile)
{
if (File.Exists(tmpFile))
{
File.Delete(tmpFile);
}
}
public void AbortOperation()
{
// Make sure we are in business
if (cts != null)
{
cts.Cancel();
}
}
}
} }

View file

@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace WebsitePanel.Installer.Core
{
class ServiceComponentNotFoundException : Exception
{
private string p;
public ServiceComponentNotFoundException(string p)
: base(p)
{
}
}
}

View file

@ -35,6 +35,7 @@
<Reference Include="Ionic.Zip.Reduced"> <Reference Include="Ionic.Zip.Reduced">
<HintPath>..\..\Lib\Ionic.Zip.Reduced.dll</HintPath> <HintPath>..\..\Lib\Ionic.Zip.Reduced.dll</HintPath>
</Reference> </Reference>
<Reference Include="Microsoft.CSharp" />
<Reference Include="System" /> <Reference Include="System" />
<Reference Include="System.configuration" /> <Reference Include="System.configuration" />
<Reference Include="System.Data" /> <Reference Include="System.Data" />
@ -80,6 +81,7 @@
<DesignTimeSharedInput>True</DesignTimeSharedInput> <DesignTimeSharedInput>True</DesignTimeSharedInput>
<DependentUpon>Settings.settings</DependentUpon> <DependentUpon>Settings.settings</DependentUpon>
</Compile> </Compile>
<Compile Include="ServiceComponentNotFoundException.cs" />
<Compile Include="ServiceProviderProxy.cs"> <Compile Include="ServiceProviderProxy.cs">
<SubType>Code</SubType> <SubType>Code</SubType>
</Compile> </Compile>

View file

@ -1,4 +1,4 @@
// Copyright (c) 2011, Outercurve Foundation. // Copyright (c) 2012, Outercurve Foundation.
// All rights reserved. // All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without modification, // Redistribution and use in source and binary forms, with or without modification,
@ -211,7 +211,7 @@ namespace WebsitePanel.Installer.Controls
{ {
Log.WriteInfo(string.Format("Updating {0}", componentName)); Log.WriteInfo(string.Format("Updating {0}", componentName));
//download installer //download installer
Loader form = new Loader(this.AppContext, fileName); Loader form = new Loader(fileName, (e) => AppContext.AppForm.ShowError(e));
DialogResult result = form.ShowDialog(this); DialogResult result = form.ShowDialog(this);
if (result == DialogResult.OK) if (result == DialogResult.OK)
{ {
@ -273,7 +273,7 @@ namespace WebsitePanel.Installer.Controls
{ {
Log.WriteInfo(string.Format("Uninstalling {0}", componentName)); Log.WriteInfo(string.Format("Uninstalling {0}", componentName));
//download installer //download installer
Loader form = new Loader(this.AppContext, installer, componentCode, release); Loader form = new Loader(installer, componentCode, release, (e) => AppContext.AppForm.ShowError(e));
DialogResult result = form.ShowDialog(this); DialogResult result = form.ShowDialog(this);
if (result == DialogResult.OK) if (result == DialogResult.OK)
{ {
@ -326,15 +326,15 @@ namespace WebsitePanel.Installer.Controls
string path = element.GetStringSetting("InstallerPath"); string path = element.GetStringSetting("InstallerPath");
string type = element.GetStringSetting("InstallerType"); string type = element.GetStringSetting("InstallerType");
string componentId = element.ID; string componentId = element.ID;
string componentCode = element.GetStringSetting("ComponentCode"); string ccode = element.GetStringSetting("ComponentCode");
string componentName = element.GetStringSetting("ComponentName"); string componentName = element.GetStringSetting("ComponentName");
string release = element.GetStringSetting("Release"); string cversion = element.GetStringSetting("Release");
try try
{ {
Log.WriteInfo(string.Format("Setup {0} {1}", componentName, release)); Log.WriteInfo(string.Format("Setup {0} {1}", componentName, cversion));
//download installer //download installer
Loader form = new Loader(this.AppContext, installer, componentCode, release); Loader form = new Loader(installer, ccode, cversion, (e) => AppContext.AppForm.ShowError(e));
DialogResult result = form.ShowDialog(this); DialogResult result = form.ShowDialog(this);
if (result == DialogResult.OK) if (result == DialogResult.OK)
{ {

View file

@ -1,4 +1,4 @@
// Copyright (c) 2011, Outercurve Foundation. // Copyright (c) 2012, Outercurve Foundation.
// All rights reserved. // All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without modification, // Redistribution and use in source and binary forms, with or without modification,
@ -45,273 +45,273 @@ using WebsitePanel.Installer.Configuration;
namespace WebsitePanel.Installer.Controls namespace WebsitePanel.Installer.Controls
{ {
/// <summary> /// <summary>
/// Components control /// Components control
/// </summary> /// </summary>
internal partial class ComponentsControl : ResultViewControl internal partial class ComponentsControl : ResultViewControl
{ {
delegate void SetGridDataSourceCallback(object dataSource, string dataMember); delegate void SetGridDataSourceCallback(object dataSource, string dataMember);
private string componentCode = null; private string componentCode = null;
private string componentVersion = null; private string componentVersion = null;
private string componentSettingsXml = null; private string componentSettingsXml = null;
public ComponentsControl() public ComponentsControl()
{ {
InitializeComponent(); InitializeComponent();
grdComponents.AutoGenerateColumns = false; grdComponents.AutoGenerateColumns = false;
} }
/// <summary> /// <summary>
/// Action on click Install link /// Action on click Install link
/// </summary> /// </summary>
/// <param name="sender"></param> /// <param name="sender"></param>
/// <param name="e"></param> /// <param name="e"></param>
private void OnInstallLinkClick(object sender, DataGridViewCellEventArgs e) private void OnInstallLinkClick(object sender, DataGridViewCellEventArgs e)
{ {
if (e.ColumnIndex == grdComponents.Columns.IndexOf(colLink)) if (e.ColumnIndex == grdComponents.Columns.IndexOf(colLink))
{ {
DataRowView row = grdComponents.Rows[e.RowIndex].DataBoundItem as DataRowView; DataRowView row = grdComponents.Rows[e.RowIndex].DataBoundItem as DataRowView;
if (row != null) if (row != null)
{ {
StartInstaller(row); StartInstaller(row);
StartLoadingComponents(); StartLoadingComponents();
} }
} }
} else
{
private void StartInstaller(DataRowView row) }
{ }
string applicationName = Utils.GetDbString(row[Global.Parameters.ApplicationName]);
string componentName = Utils.GetDbString(row[Global.Parameters.ComponentName]);
string componentCode = Utils.GetDbString(row[Global.Parameters.ComponentCode]);
string componentDescription = Utils.GetDbString(row[Global.Parameters.ComponentDescription]);
string component = Utils.GetDbString(row[Global.Parameters.Component]);
string version = Utils.GetDbString(row[Global.Parameters.Version]);
string fileName = row[Global.Parameters.FullFilePath].ToString();
string installerPath = Utils.GetDbString(row[Global.Parameters.InstallerPath]);
string installerType = Utils.GetDbString(row[Global.Parameters.InstallerType]);
if (CheckForInstalledComponent(componentCode)) private void StartInstaller(DataRowView row)
{ {
AppContext.AppForm.ShowWarning(Global.Messages.ComponentIsAlreadyInstalled); string applicationName = Utils.GetDbString(row[Global.Parameters.ApplicationName]);
return; string componentName = Utils.GetDbString(row[Global.Parameters.ComponentName]);
} string componentCode = Utils.GetDbString(row[Global.Parameters.ComponentCode]);
try string componentDescription = Utils.GetDbString(row[Global.Parameters.ComponentDescription]);
{ string component = Utils.GetDbString(row[Global.Parameters.Component]);
// download installer string version = Utils.GetDbString(row[Global.Parameters.Version]);
Loader form = new Loader(this.AppContext, fileName); string fileName = row[Global.Parameters.FullFilePath].ToString();
DialogResult result = form.ShowDialog(this); string installerPath = Utils.GetDbString(row[Global.Parameters.InstallerPath]);
string installerType = Utils.GetDbString(row[Global.Parameters.InstallerType]);
if (result == DialogResult.OK) if (CheckForInstalledComponent(componentCode))
{ {
string tmpFolder = FileUtils.GetTempDirectory(); AppContext.AppForm.ShowWarning(Global.Messages.ComponentIsAlreadyInstalled);
string path = Path.Combine(tmpFolder, installerPath); return;
Update(); }
string method = "Install"; try
Log.WriteStart(string.Format("Running installer {0}.{1} from {2}", installerType, method, path)); {
// download installer
Loader form = new Loader(fileName, (e) => AppContext.AppForm.ShowError(e));
DialogResult result = form.ShowDialog(this);
//prepare installer args if (result == DialogResult.OK)
Hashtable args = new Hashtable(); {
string tmpFolder = FileUtils.GetTempDirectory();
string path = Path.Combine(tmpFolder, installerPath);
Update();
string method = "Install";
Log.WriteStart(string.Format("Running installer {0}.{1} from {2}", installerType, method, path));
args[Global.Parameters.ComponentName] = componentName; //prepare installer args
args[Global.Parameters.ApplicationName] = applicationName; Hashtable args = new Hashtable();
args[Global.Parameters.ComponentCode] = componentCode;
args[Global.Parameters.ComponentDescription] = componentDescription;
args[Global.Parameters.Version] = version;
args[Global.Parameters.InstallerFolder] = tmpFolder;
args[Global.Parameters.InstallerPath] = installerPath;
args[Global.Parameters.InstallerType] = installerType;
args[Global.Parameters.Installer] = Path.GetFileName(fileName);
args[Global.Parameters.ShellVersion] = AssemblyLoader.GetShellVersion();
args[Global.Parameters.BaseDirectory] = FileUtils.GetCurrentDirectory();
args[Global.Parameters.ShellMode] = Global.VisualInstallerShell;
args[Global.Parameters.IISVersion] = Global.IISVersion;
args[Global.Parameters.SetupXml] = this.componentSettingsXml;
args[Global.Parameters.ParentForm] = FindForm();
//run installer args[Global.Parameters.ComponentName] = componentName;
DialogResult res = (DialogResult)AssemblyLoader.Execute(path, installerType, method, new object[] { args }); args[Global.Parameters.ApplicationName] = applicationName;
Log.WriteInfo(string.Format("Installer returned {0}", res)); args[Global.Parameters.ComponentCode] = componentCode;
Log.WriteEnd("Installer finished"); args[Global.Parameters.ComponentDescription] = componentDescription;
Update(); args[Global.Parameters.Version] = version;
if (res == DialogResult.OK) args[Global.Parameters.InstallerFolder] = tmpFolder;
{ args[Global.Parameters.InstallerPath] = installerPath;
AppContext.AppForm.ReloadApplication(); args[Global.Parameters.InstallerType] = installerType;
} args[Global.Parameters.Installer] = Path.GetFileName(fileName);
FileUtils.DeleteTempDirectory(); args[Global.Parameters.ShellVersion] = AssemblyLoader.GetShellVersion();
} args[Global.Parameters.BaseDirectory] = FileUtils.GetCurrentDirectory();
} args[Global.Parameters.ShellMode] = Global.VisualInstallerShell;
catch (Exception ex) args[Global.Parameters.IISVersion] = Global.IISVersion;
{ args[Global.Parameters.SetupXml] = this.componentSettingsXml;
Log.WriteError("Installer error", ex); args[Global.Parameters.ParentForm] = FindForm();
AppContext.AppForm.ShowError(ex);
}
finally
{
this.componentSettingsXml = null;
this.componentCode = null;
}
} //run installer
DialogResult res = (DialogResult)AssemblyLoader.Execute(path, installerType, method, new object[] { args });
Log.WriteInfo(string.Format("Installer returned {0}", res));
Log.WriteEnd("Installer finished");
Update();
if (res == DialogResult.OK)
{
AppContext.AppForm.ReloadApplication();
}
FileUtils.DeleteTempDirectory();
}
}
catch (Exception ex)
{
Log.WriteError("Installer error", ex);
AppContext.AppForm.ShowError(ex);
}
finally
{
this.componentSettingsXml = null;
this.componentCode = null;
}
private bool CheckForInstalledComponent(string componentCode) }
{
bool ret = false;
List<string> installedComponents = new List<string>();
foreach (ComponentConfigElement componentConfig in AppConfigManager.AppConfiguration.Components)
{
string code = componentConfig.Settings["ComponentCode"].Value;
installedComponents.Add(code);
if (code == componentCode)
{
ret = true;
break;
}
}
if (componentCode == "standalone")
{
if (installedComponents.Contains("server") ||
installedComponents.Contains("enterprise server") ||
installedComponents.Contains("portal"))
ret = true;
}
return ret;
}
/// <summary> private bool CheckForInstalledComponent(string componentCode)
/// Displays component description when entering grid row {
/// </summary> bool ret = false;
/// <param name="sender"></param> List<string> installedComponents = new List<string>();
/// <param name="e"></param> foreach (ComponentConfigElement componentConfig in AppConfigManager.AppConfiguration.Components)
private void OnRowEnter(object sender, DataGridViewCellEventArgs e) {
{ string code = componentConfig.Settings["ComponentCode"].Value;
DataRowView row = grdComponents.Rows[e.RowIndex].DataBoundItem as DataRowView; installedComponents.Add(code);
if (row != null) if (code == componentCode)
{ {
lblDescription.Text = Utils.GetDbString(row["ComponentDescription"]); ret = true;
} break;
} }
}
if (componentCode == "standalone")
{
if (installedComponents.Contains("server") ||
installedComponents.Contains("enterprise server") ||
installedComponents.Contains("portal"))
ret = true;
}
return ret;
}
/// <summary> /// <summary>
/// Start new thread to load components /// Displays component description when entering grid row
/// </summary> /// </summary>
/// <param name="sender"></param> /// <param name="sender"></param>
/// <param name="e"></param> /// <param name="e"></param>
private void OnLoadComponentsClick(object sender, EventArgs e) private void OnRowEnter(object sender, DataGridViewCellEventArgs e)
{ {
StartLoadingComponents(); DataRowView row = grdComponents.Rows[e.RowIndex].DataBoundItem as DataRowView;
} if (row != null)
{
lblDescription.Text = Utils.GetDbString(row["ComponentDescription"]);
}
}
private void StartLoadingComponents() /// <summary>
{ /// Start new thread to load components
//load list of available components in the separate thread /// </summary>
AppContext.AppForm.StartAsyncProgress("Connecting...", true); /// <param name="sender"></param>
ThreadStart threadDelegate = new ThreadStart(LoadComponents); /// <param name="e"></param>
Thread newThread = new Thread(threadDelegate); private void OnLoadComponentsClick(object sender, EventArgs e)
newThread.Start(); {
} StartLoadingComponents();
}
/// <summary> private void StartLoadingComponents()
/// Loads list of available components via web service {
/// </summary> //load list of available components in the separate thread
private void LoadComponents() AppContext.AppForm.StartAsyncProgress("Connecting...", true);
{ ThreadPool.QueueUserWorkItem(o => LoadComponents());
try }
{
Log.WriteStart("Loading list of available components");
lblDescription.Text = string.Empty;
//load components via web service
var webService = ServiceProviderProxy.GetInstallerWebService();
DataSet dsComponents = webService.GetAvailableComponents();
//remove already installed components
foreach (DataRow row in dsComponents.Tables[0].Rows)
{
string componentCode = Utils.GetDbString(row["ComponentCode"]);
if (CheckForInstalledComponent(componentCode))
{
row.Delete();
}
}
dsComponents.AcceptChanges();
Log.WriteEnd("Available components loaded");
SetGridDataSource(dsComponents, dsComponents.Tables[0].TableName);
AppContext.AppForm.FinishProgress();
}
catch (Exception ex)
{
Log.WriteError("Web service error", ex);
AppContext.AppForm.FinishProgress();
AppContext.AppForm.ShowServerError();
}
}
/// <summary> /// <summary>
/// Thread safe grid binding. /// Loads list of available components via web service
/// </summary> /// </summary>
/// <param name="dataSource">Data source</param> private void LoadComponents()
/// <param name="dataMember">Data member</param> {
private void SetGridDataSource(object dataSource, string dataMember) try
{ {
// InvokeRequired required compares the thread ID of the Log.WriteStart("Loading list of available components");
// calling thread to the thread ID of the creating thread. lblDescription.Text = string.Empty;
// If these threads are different, it returns true. //load components via web service
if (this.grdComponents.InvokeRequired) var webService = ServiceProviderProxy.GetInstallerWebService();
{ DataSet dsComponents = webService.GetAvailableComponents();
SetGridDataSourceCallback callBack = new SetGridDataSourceCallback(SetGridDataSource); //remove already installed components
this.grdComponents.Invoke(callBack, new object[] { dataSource, dataMember }); foreach (DataRow row in dsComponents.Tables[0].Rows)
} {
else string componentCode = Utils.GetDbString(row["ComponentCode"]);
{ if (CheckForInstalledComponent(componentCode))
this.grdComponents.DataSource = dataSource; {
this.grdComponents.DataMember = dataMember; row.Delete();
} }
} }
dsComponents.AcceptChanges();
Log.WriteEnd("Available components loaded");
SetGridDataSource(dsComponents, dsComponents.Tables[0].TableName);
AppContext.AppForm.FinishProgress();
}
catch (Exception ex)
{
Log.WriteError("Web service error", ex);
AppContext.AppForm.FinishProgress();
AppContext.AppForm.ShowServerError();
}
}
/// <summary> /// <summary>
/// Installs component during unattended setup /// Thread safe grid binding.
/// </summary> /// </summary>
/// <param name="componentCode"></param> /// <param name="dataSource">Data source</param>
internal void InstallComponent(string componentCode, string componentVersion, string settingsXml) /// <param name="dataMember">Data member</param>
{ private void SetGridDataSource(object dataSource, string dataMember)
//load list of available components in the separate thread {
this.componentCode = componentCode; // InvokeRequired required compares the thread ID of the
this.componentVersion = componentVersion; // calling thread to the thread ID of the creating thread.
this.componentSettingsXml = settingsXml; // If these threads are different, it returns true.
AppContext.AppForm.StartAsyncProgress("Connecting...", true); if (this.grdComponents.InvokeRequired)
ThreadStart threadDelegate = new ThreadStart(Install); {
Thread newThread = new Thread(threadDelegate); SetGridDataSourceCallback callBack = new SetGridDataSourceCallback(SetGridDataSource);
newThread.Start(); this.grdComponents.Invoke(callBack, new object[] { dataSource, dataMember });
} }
else
{
this.grdComponents.DataSource = dataSource;
this.grdComponents.DataMember = dataMember;
}
}
/// <summary> /// <summary>
/// Loads list of available components via web service and install specified component /// Installs component during unattended setup
/// during unattended setup /// </summary>
/// </summary> /// <param name="componentCode"></param>
private void Install() internal void InstallComponent(string componentCode, string componentVersion, string settingsXml)
{ {
LoadComponents(); //load list of available components in the separate thread
foreach (DataGridViewRow gridRow in grdComponents.Rows) this.componentCode = componentCode;
{ this.componentVersion = componentVersion;
DataRowView row = gridRow.DataBoundItem as DataRowView; this.componentSettingsXml = settingsXml;
if (row != null) AppContext.AppForm.StartAsyncProgress("Connecting...", true);
{ ThreadPool.QueueUserWorkItem(o => Install());
string code = Utils.GetDbString(row["ComponentCode"]); }
string version = Utils.GetDbString(row["Version"]);
if (code == componentCode) /// <summary>
{ /// Loads list of available components via web service and install specified component
//check component version if specified /// during unattended setup
if (!string.IsNullOrEmpty(componentVersion)) /// </summary>
{ private void Install()
if (version != componentVersion) {
continue; LoadComponents();
} foreach (DataGridViewRow gridRow in grdComponents.Rows)
StartInstaller(row); {
AppContext.AppForm.ProceedUnattendedSetup(); DataRowView row = gridRow.DataBoundItem as DataRowView;
break; if (row != null)
} {
} string code = Utils.GetDbString(row["ComponentCode"]);
} string version = Utils.GetDbString(row["Version"]);
} if (code == componentCode)
} {
//check component version if specified
if (!string.IsNullOrEmpty(componentVersion))
{
if (version != componentVersion)
continue;
}
StartInstaller(row);
AppContext.AppForm.ProceedUnattendedSetup();
break;
}
}
}
}
}
} }

View file

@ -1,4 +1,4 @@
// Copyright (c) 2011, Outercurve Foundation. // Copyright (c) 2012, Outercurve Foundation.
// All rights reserved. // All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without modification, // Redistribution and use in source and binary forms, with or without modification,
@ -39,118 +39,156 @@ using Ionic.Zip;
using WebsitePanel.Installer.Services; using WebsitePanel.Installer.Services;
using WebsitePanel.Installer.Common; using WebsitePanel.Installer.Common;
using WebsitePanel.Installer.Core;
namespace WebsitePanel.Installer.Controls namespace WebsitePanel.Installer.Controls
{ {
public delegate void OperationProgressDelegate(int percentage); public delegate void OperationProgressDelegate(int percentage);
/// <summary> /// <summary>
/// Loader form. /// Loader form.
/// </summary> /// </summary>
internal partial class Loader : Form internal partial class Loader : Form
{ {
private AppContext appContext; private Core.Loader appLoader;
private Core.Loader appLoader;
public Loader() public Loader()
{ {
InitializeComponent(); InitializeComponent();
DialogResult = DialogResult.Cancel; DialogResult = DialogResult.Cancel;
} }
public Loader(AppContext context, string remoteFile) public Loader(string remoteFile, Action<Exception> callback)
: this() : this()
{ {
this.appContext = context; Start(remoteFile, callback);
// }
appLoader = new Core.Loader(remoteFile);
//
Start();
}
public Loader(AppContext context, string localFile, string componentCode, string version) public Loader(string localFile, string componentCode, string version, Action<Exception> callback)
: this() : this()
{ {
this.appContext = context; Start(componentCode, version, callback);
// }
appLoader = new Core.Loader(localFile, componentCode, version);
//
Start();
}
private void Start() /// <summary>
{ /// Resolves URL of the component's distributive and initiates download process.
// /// </summary>
appLoader.OperationFailed += new EventHandler<Core.LoaderEventArgs<Exception>>(appLoader_OperationFailed); /// <param name="componentCode">Component code to resolve</param>
appLoader.ProgressChanged += new EventHandler<Core.LoaderEventArgs<Int32>>(appLoader_ProgressChanged); /// <param name="version">Component version to resolve</param>
appLoader.StatusChanged += new EventHandler<Core.LoaderEventArgs<String>>(appLoader_StatusChanged); private void Start(string componentCode, string version, Action<Exception> callback)
appLoader.OperationCompleted += new EventHandler<EventArgs>(appLoader_OperationCompleted); {
// string remoteFile = Utils.GetDistributiveLocationInfo(componentCode, version);
appLoader.LoadAppDistributive();
}
void appLoader_OperationCompleted(object sender, EventArgs e) Start(remoteFile, callback);
{ }
DialogResult = DialogResult.OK;
Close();
}
void appLoader_StatusChanged(object sender, Core.LoaderEventArgs<String> e) /// <summary>
{ /// Initializes and starts the app distributive download process.
lblProcess.Text = e.StatusMessage; /// </summary>
lblValue.Text = e.EventData; /// <param name="remoteFile">URL of the file to be downloaded</param>
// Adjust Cancel button availability for an operation being performed private void Start(string remoteFile, Action<Exception> callback)
if (btnCancel.Enabled != e.Cancellable) {
{ appLoader = Core.LoaderFactory.CreateFileLoader(remoteFile);
btnCancel.Enabled = e.Cancellable;
}
// This check allows to avoid extra form redrawing operations
if (ControlBox != e.Cancellable)
{
ControlBox = e.Cancellable;
}
}
void appLoader_ProgressChanged(object sender, Core.LoaderEventArgs<Int32> e) appLoader.OperationFailed += new EventHandler<Core.LoaderEventArgs<Exception>>(appLoader_OperationFailed);
{ appLoader.OperationFailed += (object sender, Core.LoaderEventArgs<Exception> e) => {
progressBar.Value = e.EventData; if (callback != null)
// Adjust Cancel button availability for an operation being performed {
if (btnCancel.Enabled != e.Cancellable) try
{ {
btnCancel.Enabled = e.Cancellable; callback(e.EventData);
} }
// This check allows to avoid extra form redrawing operations catch
if (ControlBox != e.Cancellable) {
{ // Just swallow the exception as we have no interest in it.
ControlBox = e.Cancellable; }
} }
} };
appLoader.ProgressChanged += new EventHandler<Core.LoaderEventArgs<Int32>>(appLoader_ProgressChanged);
appLoader.StatusChanged += new EventHandler<Core.LoaderEventArgs<String>>(appLoader_StatusChanged);
appLoader.OperationCompleted += new EventHandler<EventArgs>(appLoader_OperationCompleted);
void appLoader_OperationFailed(object sender, Core.LoaderEventArgs<Exception> e) appLoader.LoadAppDistributive();
{ }
appContext.AppForm.ShowError(e.EventData);
//
DialogResult = DialogResult.Abort;
Close();
}
private void btnCancel_Click(object sender, EventArgs e) void appLoader_OperationCompleted(object sender, EventArgs e)
{ {
Log.WriteInfo("Execution was canceled by user"); DialogResult = DialogResult.OK;
Close(); Close();
} }
private void OnLoaderFormClosing(object sender, FormClosingEventArgs e) void appLoader_StatusChanged(object sender, Core.LoaderEventArgs<String> e)
{ {
if (this.DialogResult == DialogResult.Cancel) lblProcess.Text = e.StatusMessage;
{ lblValue.Text = e.EventData;
appLoader.AbortOperation(); // Adjust Cancel button availability for an operation being performed
} if (btnCancel.Enabled != e.Cancellable)
// Remove event handlers {
appLoader.OperationFailed -= new EventHandler<Core.LoaderEventArgs<Exception>>(appLoader_OperationFailed); btnCancel.Enabled = e.Cancellable;
appLoader.ProgressChanged -= new EventHandler<Core.LoaderEventArgs<Int32>>(appLoader_ProgressChanged); }
appLoader.StatusChanged -= new EventHandler<Core.LoaderEventArgs<String>>(appLoader_StatusChanged); // This check allows to avoid extra form redrawing operations
appLoader.OperationCompleted -= new EventHandler<EventArgs>(appLoader_OperationCompleted); if (ControlBox != e.Cancellable)
} {
} ControlBox = e.Cancellable;
}
}
void appLoader_ProgressChanged(object sender, Core.LoaderEventArgs<Int32> e)
{
bool updateControl = (progressBar.Value != e.EventData);
progressBar.Value = e.EventData;
// Adjust Cancel button availability for an operation being performed
if (btnCancel.Enabled != e.Cancellable)
{
btnCancel.Enabled = e.Cancellable;
}
// This check allows to avoid extra form redrawing operations
if (ControlBox != e.Cancellable)
{
ControlBox = e.Cancellable;
}
//
if (updateControl)
{
progressBar.Update();
}
}
void appLoader_OperationFailed(object sender, Core.LoaderEventArgs<Exception> e)
{
DialogResult = DialogResult.Abort;
Close();
}
private void btnCancel_Click(object sender, EventArgs e)
{
DetachEventHandlers();
Log.WriteInfo("Execution was canceled by user");
Close();
}
private void DetachEventHandlers()
{
// Detach event handlers
if (appLoader != null)
{
appLoader.OperationFailed -= new EventHandler<Core.LoaderEventArgs<Exception>>(appLoader_OperationFailed);
appLoader.ProgressChanged -= new EventHandler<Core.LoaderEventArgs<Int32>>(appLoader_ProgressChanged);
appLoader.StatusChanged -= new EventHandler<Core.LoaderEventArgs<String>>(appLoader_StatusChanged);
appLoader.OperationCompleted -= new EventHandler<EventArgs>(appLoader_OperationCompleted);
}
}
private void OnLoaderFormClosing(object sender, FormClosingEventArgs e)
{
if (this.DialogResult == DialogResult.Cancel)
{
if (appLoader != null)
{
appLoader.AbortOperation();
appLoader = null;
}
}
}
}
} }

View file

@ -1,4 +1,4 @@
// Copyright (c) 2011, Outercurve Foundation. // Copyright (c) 2012, Outercurve Foundation.
// All rights reserved. // All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without modification, // Redistribution and use in source and binary forms, with or without modification,
@ -1901,52 +1901,52 @@ namespace WebsitePanel.Setup
} }
} }
private void UpdateWebConfigNamespaces() private void UpdateWebConfigNamespaces()
{ {
try try
{ {
// find all .config files in the installation directory // find all .config files in the installation directory
string[] configFiles = Directory.GetFiles(Wizard.SetupVariables.InstallationFolder, string[] configFiles = Directory.GetFiles(Wizard.SetupVariables.InstallationFolder,
"*.config", SearchOption.TopDirectoryOnly); "*.config", SearchOption.TopDirectoryOnly);
if (configFiles != null && configFiles.Length > 0) if (configFiles != null && configFiles.Length > 0)
{ {
foreach (string path in configFiles) foreach (string path in configFiles)
{ {
try try
{ {
Log.WriteStart(String.Format("Updating '{0}' file", path)); Log.WriteStart(String.Format("Updating '{0}' file", path));
// load configuration file in memory // load configuration file in memory
string content = File.ReadAllText(path); string content = File.ReadAllText(path);
// replace DotNetPark. to empty strings // replace DotNetPark. to empty strings
content = Regex.Replace(content, "dotnetpark\\.", "", RegexOptions.IgnoreCase); content = Regex.Replace(content, "dotnetpark\\.", "", RegexOptions.IgnoreCase);
// save updated config // save updated config
File.WriteAllText(path, content); File.WriteAllText(path, content);
Log.WriteEnd(String.Format("Updated '{0}' file", path)); Log.WriteEnd(String.Format("Updated '{0}' file", path));
InstallLog.AppendLine(String.Format("- Updated {0} file", path)); InstallLog.AppendLine(String.Format("- Updated {0} file", path));
} }
catch (Exception ex) catch (Exception ex)
{ {
if (Utils.IsThreadAbortException(ex)) if (Utils.IsThreadAbortException(ex))
return; return;
Log.WriteError(String.Format("Error updating '{0}' file", path), ex); Log.WriteError(String.Format("Error updating '{0}' file", path), ex);
throw; throw;
} }
} }
} }
} }
catch (Exception ex) catch (Exception ex)
{ {
if (Utils.IsThreadAbortException(ex)) if (Utils.IsThreadAbortException(ex))
return; return;
Log.WriteError("Error listing *.config files", ex); Log.WriteError("Error listing *.config files", ex);
throw; throw;
} }
} }
private void UpdateEnterpriseServerUrl() private void UpdateEnterpriseServerUrl()
{ {