Extending Xamarin Studio's mdtool For Fun and Profit

In Xamarin Studio, if you look in the About dialog you'll find all sorts of information about the versions for all the various tools involved in building your apps. There's so much more to compiling an app than the version of Xamarin you have installed. There's the version of OS X, Android tools, Xcode, etc. Any one of these things is a significant data point in any app release you have.

Every time we do a release at Olo I've been copying the output of that dialog and pasting it into a release in GitHub so we don't lose track of exactly what was in that release. We manage a ton of releases, so every data point matters. It's no secret that I'm big on automating this sort of thing, so I set out to see if I could do so for this task. Spoiler alert: I could.

Before I get into the details, I want to extend a big thank you to Michael Hutchinson, the guru of all things Xamarin Studio, for pointing me in the right direction which definitely saved me many hours of digging through the MonoDevelop source. After maybe five years of using MonoDevelop/Xamarin Studio, this was the first time I'd ever tried writing any sort of add-in and I am definitely impressed by how approachable the add-in system is.

To prove that, let's take a look at how little code it took to achieve what I wanted to do. If you're just getting started building add-ins for Xamarin Studio, I'd recommend starting with the guide on their site which is a great primer.

The first step was defining my add-ins manifest:

<?xml version="1.0" encoding="UTF-8"?>  
<ExtensionModel>  
    <Extension path="/MonoDevelop/Core/Applications">
        <Application id="systeminfo" class="Olo.BuildTools.SystemInfo" description="Gather info on tool and add-in versions"/>
    </Extension>
</ExtensionModel>  

There are many different options for extension paths, depending on what you want to achieve with your add-in. For this one, there's no actual UI to expose, so I used the /MonoDevelop/Core/Applications extension point to simply add a command to mdtool. If you're unfamiliar with mdtool, it's a command line tool included with Xamarin Studio that can be used to do various tasks from the command line, such as building iOS apps. I had no idea before writing this that it was so easy to extend this core tool.

With the manifest defined, all that's left is defining the class that it points to. The code there wasn't much more complicated:

using System;  
using System.IO;  
using System.Linq;  
using MonoDevelop.Core;

namespace Olo.BuildTools  
{
    class SystemInfo : IApplication
    {
        public int Run(string[] arguments)
        {
            var systemInformationSummary = SystemInformation.GetTextDescription();

            if (!arguments.Any())
                printHelp();

            foreach (var argument in arguments)
            {
                if (argument == "-c")
                    Console.WriteLine(systemInformationSummary);
                else if (argument == "-h")
                    printHelp();
                else if (argument.StartsWith("-f:"))
                    File.WriteAllText(argument.Substring(3), systemInformationSummary);
            }

            return 0;
        }

        private void printHelp()
        {
            Console.WriteLine();
            Console.WriteLine("System Info Tool");
            Console.WriteLine("Usage: mdtool systeminfo [-c] [-f:file-path]");
            Console.WriteLine();

            Console.WriteLine("Options");
            Console.WriteLine("  -h                Print this message");
            Console.WriteLine("  -c                Output system information to the console");
            Console.WriteLine("  -f:file-path      Output system information into the specifed file");
            Console.WriteLine();
        }
    }
}

To be honest, the "hard" work here was mostly just spending some time getting to know the source to MonoDevelop a little better, and coming across the SystemInformation class, which is what gets used in the dialog in Xamarin Studio. The code above essentially just reproduces what happens there, and redirects it to either a file or the console.

That's it! Once that add-in is loaded into Xamarin Studio, you can go to the command line and do:

mdtool systeminfo -c  

and you'll get the same output you see in the About dialog. If you want to pipe the output to a file, as we do in our build process, you can do:

mdtool systeminfo -f:versions.txt  

We then take that file and publish it as a build artifact in TeamCity, alongside the actual app package.

In addition to this post, we've created an open source repository on our GitHub account where we intend to put more add-ins as we come up with them. You can also find this add-in from any Xamarin Studio install by searching for Olo.BuildTools.

Xamarin Studio Add-In

comments powered by Disqus
Navigation