# Friday, October 31, 2008

I had a situation where I needed to temporarily modify some read-only files on disk that were under source control (TFS).  Basically what I wanted to do was:

  1. If the file is read-only, make it writable.
  2. Modify the file.
  3. Set it back to read-only if it was originally read-only.

You could just put an if then for steps 1 and 3, but that's ugly IMO.  Here's what the originally looked like before I refactored it:

bool isReadOnly = IsFileReadonly(webConfigPath);
FileAttributes originalFileAttributes = File.GetAttributes(webConfigPath);

if (isReadOnly)
{
	File.SetAttributes(file, FileAttributes.Normal);
}

File.Copy(backupWebConfigPath, webConfigPath, true);

if (isReadOnly)
{
	File.SetAttributes(webConfigPath, originalFileAttributes);
}

So here's my refactored solution using a DisposableAction which wraps a delegate that is invoked on dispose.  Inside the using statement the file is ensured to be writable, but at the end of the using statement its original attributes are set back on the file.  All the if statements in the code above get replaced with the following concise using statement:

using (FileAsWritable(webConfigPath))
{
	File.Copy(backupWebConfigPath, webConfigPath, true);
}

I think that's much cleaner, what do you think?  The rest of the supporting code if you're interested:

private static DisposableAction FileAsWritable(string file)
{
	if (!IsFileReadOnly(file))
	{
		return new DisposableAction(/* no-op */);
	}

	FileAttributes originalFileAttributes = File.GetAttributes(file);
	File.SetAttributes(file, FileAttributes.Normal);
	return new DisposableAction(() => File.SetAttributes(file, originalFileAttributes));
}
namespace Sneal.JsUnitUtils.Utils
{
    /// <summary>
    /// Wraps a delegate all that is called on Dispose, used for wrapping
    /// an action from a method call.
    /// </summary>
    public class DisposableAction : IDisposable
    {
        private Action action;

        public DisposableAction() {}

        public DisposableAction(Action action)
        {
            this.action = action;
        }

        public void Dispose()
        {
            if (action != null)
            {
                action();
            }
        }
    }

    public delegate void Action();
}
Friday, October 31, 2008 5:39:47 PM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [0]  | 
# Tuesday, October 21, 2008

Before I left on vacation a couple of weeks ago I was working with another developer on a story that made use of some 3rd party services on a VM.  Before leaving I gave him my VM to use so we could avoid the unnecessary PITA of configuring  a new environment. 

Unfortunately now that I've come back I would like to run my VM again, but I can't since he is still running it and we can't share instances (isolated development environment). 

What I ended up doing was taking the VM image as I had it before I left and essentially cloned it.  By renaming the PC and changing the SIDs on the box I essentially have a cloned VM that will peacefully coexist on the same Windows network.

Here are the steps to take an existing VM joined to the domain and essentially clone it as a different machine.

1.       Unjoin the machine from the domain.  Reboot.

2.       Download NewSid utility from Microsoft (sysinternals).

3.       Run NewSid from the command line: newsid /a mynewpcname

4.       After reboot, login and rejoin the PC to the domain.

5.       Done

From then on the two VMs can coexist with one another on the same network and domain.

Tuesday, October 21, 2008 8:34:00 PM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [0]  |