#region Copyright 2009-2014 by Roger Knapp, Licensed under the Apache License, Version 2.0
/* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#endregion
using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Xml;
using System.Text.RegularExpressions;
using CSharpTest.Net.Utils;
using System.Diagnostics;
namespace CSharpTest.Net.AppConfig
{
partial class UserSettingsSection
{
#region Upgrade Version Properties
///
/// Describes the version of the application that originally wrote the configuration
///
[ConfigurationProperty("originalVersion", IsRequired = false)]
public string OriginalVersion
{
get { return (string)base["originalVersion"]; }
set { base["originalVersion"] = value; }
}
///
/// The version that the user settings were previously updagraded from
///
[ConfigurationProperty("upgradedVersion", IsRequired = false)]
public string UpgradedVersion
{
get { return (string)base["upgradedVersion"]; }
set { base["upgradedVersion"] = value; }
}
///
/// The last date/time the settings were upgraded from the upgradedVersion
///
[ConfigurationProperty("upgradedDate", IsRequired = false)]
public string UpgradedDate
{
get { return (string)base["upgradedDate"]; }
set { base["upgradedDate"] = value; }
}
#endregion
///
/// Searches for old user settings from previous versions and copies them into the
/// configuration provided.
///
/// The configuration to inspect for previous versions
/// The destination UserSettingsSection object
public static void UpgradeUserSettings(Configuration config, UserSettingsSection settings)
{
if (String.IsNullOrEmpty(config.FilePath))
return;
try
{
//pattern for version strings: "1.0.1000.325622", etc
Regex match = RegexPatterns.FullVersion;
List folders = new List();
string foundVersionFile = null;
Version foundVersion = null;
//breakdown the current configuration path to work from
string newVersionFile = config.FilePath;
string fileName = Path.GetFileName(newVersionFile);
string versionDir = Path.GetDirectoryName(newVersionFile);
string myVersion = Path.GetFileName(versionDir);
string allVersions = Path.GetDirectoryName(versionDir);
//The last directory in the path should be our current version, if not, get outta here
if (false == match.IsMatch(myVersion))
return;//not versioned?
//Get any directories that match a basic wildcard mask
folders.AddRange(Directory.GetDirectories(allVersions, "*.*.*.*"));
foreach (string folder in folders)
{
//directory must be a numeric version
if (false == match.IsMatch(Path.GetFileName(folder)))
continue;
//user.config file must be located in directory
if (!File.Exists(Path.Combine(folder, fileName)))
continue;//no data
//we are not looking for our own current configuration
if (StringComparer.OrdinalIgnoreCase.Equals(myVersion, Path.GetFileName(folder)))
continue;
//try to parse the version and see if it's the newest, if so hang on to it.
try
{
Version testVersion = new Version(Path.GetFileName(folder));
if (foundVersion == null || testVersion > foundVersion)
{
foundVersion = testVersion;
foundVersionFile = Path.Combine(folder, fileName);
}
}
catch { }
}
//Hopefully we now have a previous file and version, if not he'll just return.
UpgradeSettingsFromFile(config, settings, foundVersion == null ? null : foundVersion.ToString(), myVersion, foundVersionFile);
}
catch (Exception e) { Trace.TraceError("{1}\r\n{0}", e, "Failed to upgrade user settings."); }
}
///
/// Forces a read of the configuration file specified and copies the settings from
/// the old file
///
private static void UpgradeSettingsFromFile(Configuration config, UserSettingsSection settings, string oldVersionString, string newVersionString, string oldVersionConfig)
{
if (String.IsNullOrEmpty(oldVersionConfig) || !File.Exists(oldVersionConfig))
return;
//Log.Info("Upgrading settings from version {0} to {1}", oldVersionString, newVersionString);
//Copy the config file so that we can modify and read
string tempexename = Path.GetTempFileName();
string tempconfig = tempexename + ".config";
try
{
//Make a copy and modify to ensure that we have a section declaration
File.Copy(oldVersionConfig, tempconfig, true);
ReplaceConfigDeclaration(tempconfig);
//Read the new configuration
Configuration upgradeFrom = ConfigurationManager.OpenExeConfiguration(tempexename);
UserSettingsSection upgradeSettings = upgradeFrom.Sections[SECTION_NAME] as UserSettingsSection;
if (upgradeSettings != null)
{
//copy the settings
settings.CopyFrom(upgradeSettings);
//update version upgrade information
if (!String.IsNullOrEmpty(upgradeSettings.OriginalVersion))
settings.OriginalVersion = upgradeSettings.OriginalVersion;
else
settings.OriginalVersion = oldVersionString;
settings.UpgradedVersion = oldVersionString;
settings.UpgradedDate = XmlConvert.ToString(DateTime.Now, XmlDateTimeSerializationMode.RoundtripKind);
//I guess it worked ;)
Trace.WriteLine("Settings upgrade successful.");
}
}
finally
{
//done with our temp files
try { File.Delete(tempexename); File.Delete(tempconfig); }
catch { }
}
}
private static void ReplaceConfigDeclaration(string filename)
{
//Replace the declared sections with just our own
XmlDocument doc = new XmlDocument();
doc.Load(filename);
XmlElement sections = doc.SelectSingleNode("/configuration/configSections") as XmlElement;
if (sections == null)
{
sections = doc.CreateElement("configSections");
Check.NotNull(doc.SelectSingleNode("/configuration")).InsertAfter(sections, null);
}
//Just trash whatever is there
sections.RemoveAll();
//create our section declaration
XmlElement sectionDecl = doc.CreateElement("section");
sectionDecl.SetAttribute("name", "userSettings");
sectionDecl.SetAttribute("type", String.Format("{0}, {1}", typeof(UserSettingsSection).FullName, typeof(UserSettingsSection).Assembly.FullName));
//add it back and save
sections.AppendChild(sectionDecl);
doc.Save(filename);
}
}
}