Category Archives: Programming

backup and deploy using MSDeploy and Phantom with configuration version control

Working on a project that spans several environments like development, testing, staging and production can prove difficult when it comes to managing their configuration files.

Because they are basically the same configuration files but with different settings, like pointing on different databases or enable/disable debug stuff.

Using my recent Github fork of Phantom I am now able to do this:

  1. Deploy a website/application using MSDeploy
  2. Backup an existing website/application before deploying, also using MSDeploy
  3. Version control configuration files and deploy the correct set to a given environment

The following build.boo show how to configure  backups,  configuration files and deploy targets for the same solution.

this script assumes that there is a directory named “.configurations” in the solution directory and that it contains two sub folders named “staging” and “production”

solution_file = "solution.sln"
configuration = "release"

output_path = "./.output"
published_web_path = output_path + "/_PublishedWebsites/website"
package_path = output_path+"/deploy_package"

remote_backup_folder = "{path on remote machine}/some_name_["+System.Environment.MachineName +"]_"+ date.Now.ToString("yyyy.MM.dd.hh.mm.ss")

msdeploy_authentication_staging = ",wmsvc=\"127.0.0.1\",authType=\"basic\",userName=\"admin\",password=\"god!secure\""
msdeploy_authentication_production = ",wmsvc=\"127.0.0.2\",authType=\"basic\",userName=\"admin\",password=\"god!more!secure\""

target default, (build, clean):
  pass

target build:
  msbuild(file: solution_file, configuration: configuration, properties: {"OutputPath": output_path })

target package:
  rm(package_path)
  with FileList(published_web_path):
    .Exclude("{*.config, *.txt}")
    .ForEach def(file):
      file.CopyToDirectory(package_path)

target deploy_to_staging, (clean, build, package, backup_staging, clean):

	with FileList("./.configurations/staging/"):
		.Include("**")
		.ForEach def(file):
			file.CopyToDirectory(package_path)

	msdeploy(skipfiles: (".*\\.bak",".*\\.txt"), verb: "sync", source: "iisApp="+package_path, dest: "iisApp=\"Default Website\""+msdeploy_authentication_staging)

target deploy_to_production, (clean, build, package, backup_production, clean):

	with FileList("./.configurations/production/"):
		.Include("**")
		.ForEach def(file):
			file.CopyToDirectory(package_path)

	msdeploy(skipfiles: (".*\\.bak",".*\\.txt"), verb: "sync", source: "iisApp="+package_path, dest: "iisApp=\"Default Website\""+msdeploy_authentication_production )

target backup_staging:
	msdeploy(verb: "sync", source: "iisApp=\"Default Website\""+msdeploy_authentication_staging, dest: "archivedir=\""+remote_backup_folder+"\"+msdeploy_authentication_staging)

target backup_production:
	msdeploy(verb: "sync", source: "iisApp=\"Default Website\""+msdeploy_authentication_production , dest: "archivedir=\""+remote_backup_folder+"\"+msdeploy_authentication_production )

target clean:
  rm(output_path)

Example usage:

  • “Phantom.exe deploy_to_staging” : builds, makes a backup, configures and deploys
  • “Phantom.exe deploy_to_production” : builds, makes a backup, configures and deploys

Displacement Field – more fun with javascript and canvas

Just another fun/play/experiment with javascript, canvas and some number crunching.

http://www.creamdog.se/DisplacementField/

JSCloth – fun with javascript and canvas

Just wanna post a link to my latest experiment, simulating cloth/fabric using javascript and canvas.

Obviously you need a browser that supports the <canvas> element, should work fine in Chrome, Firefox, Safari or Opera. I do not recall at the moment if IE9 supports it, but I think so.

Anyhow,

It is pretty slow in Firefox 3.6.10 (15 fps textured, 30 fps wireframe)

It is faster in Firefox 4 Beta, but just barely (18-20 fps textured, 35-40 fps wireframe)

Chrome 6.0.472.63 is the fastest browser (50 fps textured, 80 fps wireframe)

http://www.creamdog.se/JSCloth/

Visual Studio copy, paste & freeze

The problem

After I installed Visual Studio 2010 I started experiencing that the IDE would freeze for 20+ seconds after I pasted a code snipped in markup edit mode. I had the same issue on my home computer also running Visual Studio 2010.

As you may suspect this became a bit frustrating quite fast.

Fumbling in the dark

I found some MS post suggesting re-installing Visual Studio / Windows or whatever but really, who would do that, really?

Also some MS people suggested that the issue may be not enough RAM for the copy paste operation. Since I have 4GB on both computers and monitoring the memory usage during copy paste at ~2GB it did not really feel like the culprit in this case.

I did find some promising theories out there, like add an exception to your antivirus not to scan your project files – did not work.

Maybe uninstalling Microsoft Visual Studio Web Authoring Component? Seemed like a good idea in general since its just some Frontpage crap – but didn’t help much.

I did find a hotfix from Microsoft with the description (Patch Available for Cut or Copy displaying “insufficient memory” error in VS 2010) not quite my scenario but hey, they seemed related so I installed it, took a long time - did nothing.

The solution

By this time I was quite fed up with this shit, I could not get any real work done with Visual Studio behaving like this. So I started looking at warnings and stuff and did find that there was a typo in the web.config in a sectiongroup.

<configuration>
  <configSections>
    <sectionGroup name="system.web.extensions" type="System.Web.Configuration.SystemWebExtensionsSectionGroup, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
      <sectionGroup name="scripting" type="System.Web.Configuration.ScrpingSectionGroup, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
       ...
      </sectionGroup>
    </sectionGroup>
  </configSections>
</configuration>

The sectionGroup “scripting” had a typo in in its type attribute, “ScrpingSectionGroup” instead of “ScriptingSectionGroup”.

After I had corrected this everything worked fine.

I had no idea that a typo in web.config could screw up the IDE so bad. Keep in mind that even that web.config had this typo, the project compiled and ran just fine.

Sigh

PyBlocks

Some time ago I had the need to generate order confirmation emails using templates populated with order data such as ordered items, pricing and customer information.

One way is of course to serialize the order to XML and transform it via XSL but I had an urge to try something new.

So I decided to use IronPython and parse templates with {py py} blocks.

You can download the example PyBlocks solution here

Example PyBlocks template

Hello {py Console.Write(customer.Givenname+ ' ' + customer.Surname) py}!

The package will be sent to the following adress

  {py
  Console.WriteLine(customer.Street + ' ' + customer.StreetNumber)
  Console.WriteLine(customer.ZipCode + ' ' + customer.City)
  py}
Regards
//Some online store

Rendering the template

var engine = Python.CreateEngine(AppDomain.CurrentDomain);
var scope = new ScriptScope(engine, new Scope()).Engine.GetClrModule();

scope.SetVariable("customer", new Customer
                                  {
                                      City = "Stockholm",
                                      Givenname = "Steve",
                                      Street = "AppleRow",
                                      StreetNumber = "23",
                                      Surname = "Mobs",
                                      ZipCode = "14565"
                                  });

Console.WriteLine(PyBlocksRenderer.Render(engine, scope, template));

Output

Hello Steve Mobs!

The package will be sent to the following adress

  AppleRow 23
  14565 Stockholm

Regards
//Some online store

PyBlocksRenderer.cs

    public class PyBlocksRenderer
    {

        /// <summary>
        /// Renders the template using the specified engine and scope.
        /// </summary>
        /// <param name="pythonEngine">The python engine.</param>
        /// <param name="scriptScope">The script scope.</param>
        /// <param name="template">The template.</param>
        /// <returns></returns>
        public static string Render(ScriptEngine pythonEngine, ScriptScope scriptScope, string template)
        {
            //Replace tabs with 4 spaces using a string extension method
            template = template.ReplaceTabsWithSpaces();

            //Fetch a MatchCollection using a string extension method
            var pythonBlocksMatchCollection = template.GetPythonBlockMatches();

            //contains the matching {py..py} block as a key and the result as value
            var pyBlockMatchResults = new List<KeyValuePair<string, string>>();

            foreach (Match pythonBlockMatch in pythonBlocksMatchCollection)
            {
                //Fetch matching code block code and normalize indentation using a string extension method
                var pythonCode = pythonBlockMatch.Groups["code"].Value.NormalizeIndentations();

                //Add import to enable writing to the console from within the pythonCode
                pythonCode = string.Format("from System import Console{0}{1}", Environment.NewLine, pythonCode);

                //Execute script
                var pyResult = ExecuteScript(pythonEngine, scriptScope, pythonCode);

                //Fix result indentations
                var line = template.GetLineAt(pythonBlockMatch.Index);
                if (string.IsNullOrEmpty(line.Trim()))
                {
                    var indentation = line.GetIndentation();
                    var pyLines = pyResult.GetLines().ToList();
                    var lines = from l in pyLines select pyLines.IndexOf(l) > 0 ? l.Prepend(" ", indentation) : l;
                    pyResult = string.Join(Environment.NewLine, lines.ToArray());
                }

                //Add the result of this execution to the list
                pyBlockMatchResults.Add(new KeyValuePair<string, string>(pythonBlockMatch.Value, pyResult));
            }

            //find / replace template py blocks with results
            foreach (var replace in pyBlockMatchResults)
                template = template.Replace(replace.Key, replace.Value);

            return template;
        }

        /// <summary>
        /// Executes the script.
        /// </summary>
        /// <param name="engine">The engine.</param>
        /// <param name="scope">The scope.</param>
        /// <param name="code">The code.</param>
        /// <returns>code output</returns>
        public static string ExecuteScript(ScriptEngine engine, ScriptScope scope, string code)
        {
            //save reference to standard Console out
            var stdOut = Console.Out;

            //1: redirect the console to write to a stringwriter
            //2: execute the script
            //3: return the contents of the stringbuilder
            //4: reset Console out to the saved reference above
            //Exception: return the exception message
            try
            {
                var sb = new StringBuilder();
                Console.SetOut(new StringWriter(sb));
                engine.Execute<string>(code, scope);
                return sb.ToString();
            }
            catch (Exception ex)
            {
                return string.Format("#! {0}", ex.Message);
            }
            finally
            {
                Console.SetOut(stdOut);
            }
        }
    }

StringExtensions.cs

    public static class StringExtensions
    {
        /// <summary>
        /// Replaces the tabs with spaces.
        /// </summary>
        /// <param name="str">The STR.</param>
        /// <returns></returns>
        public static string ReplaceTabsWithSpaces(this string str)
        {
            return str.Replace("\t", "    ");
        }

        /// <summary>
        /// Gets the python blocks.
        /// </summary>
        /// <param name="template">The template.</param>
        /// <returns></returns>
        public static MatchCollection GetPythonBlockMatches(this string template)
        {
            return Regex.Matches(template, "{py(?<code>.*?)py}", RegexOptions.IgnoreCase | RegexOptions.Singleline);
        }

        /// <summary>
        /// Normalizes the indentations.
        /// </summary>
        /// <param name="str">The STR.</param>
        /// <returns></returns>
        public static string NormalizeIndentations(this string str)
        {
            str = str.ReplaceTabsWithSpaces();
            var lines = from line in str.GetLines() where !string.IsNullOrEmpty(line.Trim()) select line;
            var minimumIndent = lines.GetMinimumIndentation();
            return string.Join(Environment.NewLine, (from line in lines select line.Substring(minimumIndent)).ToArray());
        }

        /// <summary>
        /// Gets the lines.
        /// </summary>
        /// <param name="str">The STR.</param>
        /// <returns></returns>
        public static string[] GetLines(this string str)
        {
            return Regex.Split(str, "\\r?\\n");
        }

        /// <summary>
        /// Gets the minimum indentation.
        /// </summary>
        /// <param name="lines">The lines.</param>
        /// <returns></returns>
        private static int GetMinimumIndentation(this IEnumerable<string> lines)
        {
            var minimumIndent = int.MinValue;

            foreach (var line in lines)
            {
                var indent = line.GetIndentation();
                minimumIndent = minimumIndent > indent || minimumIndent == int.MinValue ? indent : minimumIndent;
            }

            return minimumIndent > int.MinValue ? minimumIndent : 0;
        }

        /// <summary>
        /// Gets the indentation.
        /// </summary>
        /// <param name="str">The STR.</param>
        /// <returns></returns>
        public static int GetIndentation(this string str)
        {
            return Regex.Match(str, "^\\s+").Value.Length;
        }

        /// <summary>
        /// Gets the line at.
        /// </summary>
        /// <param name="str">The STR.</param>
        /// <param name="index">The index.</param>
        /// <returns></returns>
        public static string GetLineAt(this string str, int index)
        {
            return str.Substring(0, index).GetLines().LastOrDefault() ?? string.Empty;
        }

        /// <summary>
        /// Prepends the specified STR with value n times.
        /// </summary>
        /// <param name="str">The STR.</param>
        /// <param name="value">The value.</param>
        /// <param name="times">The times.</param>
        /// <returns></returns>
        public static string Prepend(this string str, string value, int times)
        {
            for (var i = 0; i < times; i++)
                str = value + str;

            return str;
        }
    }