Scott Hanselman

The Weekly Source Code 42 - Tree Trim, Plugins, and MEF

May 20, 2009 Comment on this post [5] Posted in Open Source | Source Code
Sponsored By

image I really advocate folks reading as much source as they can because you become a better writer by reading as much as writing. That's the whole point of the Weekly Source Code - reading code to be a better developer.

Reading code in Open Source projects is a good way to learn, especially if the project has been around a while and been successful, or if you already respect the team of people working on it. Less reliably, you can find snippets of code by searching and sharing code.

Tree Trim == CleanSources++

Many years ago, Omar Shahine wrote a great little app called Clean Sources. It added a right-click menu to the Windows Explorer that would delete your bin, obj and setup folders.

Later, Jeff wrote Clean Sources Plus. It added a "Clean and Zip" option as well as support for removing source control bindings.

Now, Steve Dunn has extended these to create Tree Trim, a command-line tool to do all this and more. He's extended it to include a plugin model that creates a little pipeline of plugins. You can chain them together and extend the command-line with your own plugins, and MEF (Managed Extensibility Framework) is at its core.

Tree Trim is convenient for build servers where you want to, for example, make a working copy, delete source control bindings, zip stuff up, email it, etc.

Each command line argument is a "task" and each command line arg (moniker) maps to a object.

treetrim.console.exe c:\dev\myproject -workingCopy -deleteFromDisk -zip -email

It's significant that order of arguments matter, so the args cause the plugins to run in order, like "make working copy, delete bin/obj, zip up, email."

Make your own Plugin and be MEFy

He's got an IPlugin interface:

public interface IPlugin
{
string Moniker { get ; }
string WorkingPath { get ; }
void Cleanup( ) ;
void Run(IPluginRuntimeSettings settings, IPlugin lastPlugin);
}

When you make a plugin, you need to let MEF know that it's available by Exporting the type:

[Export(typeof(IPlugin))]
public class SomePlugin : IPlugin
{
...
public string Moniker
{
get { return @"newPluginArgument" ; }
}
...
}

Then any plugin in the same directory gets pulled into a list of plugins...

public DiscoverPluginsInAssemblyDirectory( )
{

var catalog = new DirectoryCatalog(disk.DirectoryOfExecutingAssembly);

var container = new CompositionContainer(catalog);

var batch = new CompositionBatch();
batch.AddPart(this);

container.Compose(batch);
}

[Import( typeof( IPlugin ) )]
public IList<IPlugin> Plugins
{
get;
set;
}

The app kicks off this little pipeline by passing the command line args in along with the plugins found:

Trimmer.TrimTree(
new TaskCollection( pluginDiscoverer.DiscoveredPlugins, commandLineArgs ),
path );

...then...

public static void TrimTree(ITaskCollection tasks, string sourceTreeRoot)
{
ITask lastTask = new Task { Plugin = new NullPlugin( sourceTreeRoot ) } ;

foreach ( ITask eachTask in tasks )
{
eachTask.Run( lastTask );

lastTask = eachTask ;
}

IEnumerable<ITask> reversedTasks = tasks.Reverse( ) ;

foreach (ITask eachTask in reversedTasks)
{
eachTask.Cleanup();
}
}

The code is actually very easy to read and is up at TreeTrim on Google Code and check out the FAQ. Plugins are super easy with MEF and Tree Trim has some good examples of a number of things. First, just plugins in general, but also a technique for passing settings to plugins.

Add Context Menus to Explorer

You can easily create context menus in Explorer for this tool (or any tool). Add a Key to the Registry like below.

HKEY_CLASSES_ROOT\Folder\shell\<WHATEVER TEXT YOU WANT>\command

Then in the (Default) string value, put it something like this (for example):

"C:\Program Files (x86)\Tree Trim\TreeTrim.Gui.exe" "%1"  -workingcopy -deletefromdisk -zip:writeTo:"c:\users\scott\desktop\justzipped.zip"+dontCleanUp

Here's how it looks in registry:

Registry Editor (2)

Steve is also starting to setup tests using XUnit. He's starting to use the ContextSpecification Pattern for his tests, so it'll be interesting to see if he completes the tests. That part is pretty basic so far. Check out the TaskCollectionSpecs.cs as an example.

All in all, fun to read, and an interesting tool I'll use to quickly clean and send code samples around. I may extend it with a plugin to upload to my blog, then put the link in the clipboard. That could make blogging samples easier.

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook bluesky subscribe
About   Newsletter
Hosting By
Hosted on Linux using .NET in an Azure App Service
May 20, 2009 16:18
I really like the simplicity of the plugin framework. It just reinforces my theory that a well thought out design will typically result in clean and elegant code. Good post.
May 20, 2009 19:16
You might also like:

http://msmvps.com/blogs/peterritchie/archive/2006/10/02/Add-Visual-Studio-2005-Intermediate-Files-to-Windows-Disk-Cleanup.aspx
May 21, 2009 1:53
Nice to see how simply the MEF functionality fits in.
May 22, 2009 13:16
You shouldn't add your registry key to Folder, but to Directory. Folder includes non-file system folders, such as control panel and the recycle bin, and the tool won't work on those. So, just register it under:

HKEY_CLASSES_ROOT\Directory\shell\<WHATEVER TEXT YOU WANT>\command

Cheers
Matt
May 25, 2009 5:11
I like plug-in (add-on) very much, it really save me lots of time!

If the plug-in occupy less resource, it will be better.

Comments are closed.

Disclaimer: The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.