Honey, I Shrank the Partition!

Luis de la Rosa asked in a comment to this post about my experience resizing partitions.

Before Monday, my experience was nil. The Mac traditionally hasn’t had utilities that can resize partitions, and OS X especially has had none.

That’s changed. Now, there’s VolumeWorks ($59.95) from SubRosaSoft and iPartition ($44.95) from Coriolis Systems.

iPartition is cheaper: is it better? VersionTracker says so, 4 stars versus 3 stars. I decided to buy it and try it.

First of all, it doesn’t come with a bootable CD. The Web site directs you to BootCD by CharlesSoft, but that is not compatible with Mac OS X 10.4.

I got around this problem by attaching my laptop to my tower via a firewire cable and booting the laptop into target mode, so the partitions showed up in the Finder on the tower. iPartition can resize the partitions of a drive connected via FireWire just fine.

First, I copied the entire contents of all the laptop’s partitions to my tower. I used cp from the command line: on 10.4, cp will also copy resource forks.

I also used Apple’s Disk Utility application to make sure all the laptop partitions were OK.

I used the bundled program iDefrag Lite to compact the used bytes of my data partition, then used iPartition to shave 15 Gb. off of it and distribute them to the three system partitions. The UI for this in iPartition is especially nice: you drag the sides of brightly-colored pie wedges representing the partitions on disk to make them bigger or smaller. A selected “slice” is half-removed from the pie, so it’s easier to see and manipulate.

All the steps together took maybe 8-9 hours.

I rebooted the laptop, and haven’t had any problems yet.

svnX: A Review

svnX looks like it’s the most full-featured GUI Subversion client on the Mac. Nate Silva asked me about it way back in this comment in my first Subversion post. So, how is it?

It’s got a good deal of the functionality I want.

• I can see the state of the files in my working copy: modified, added, removed.

• It supports visual diffs, and for extra points, it supports all the major external apps that provide this.

• For a repository, it can show me all the files affected by a particular check-in. It supports deleting, moving, and copying files in the repository.

All in all, it’s a workable replacement for Xcode’s Subversion support. That’s how I use it, as an occasional replacement, to deal with the Subversion work I need done for files that aren’t in my Xcode project.

Now, before I get to what I don’t like about it, let me acknowledge two things.

One, svnX has been released under the GPL. I could dive into the code myself and fix the problems I’m going to describe. Unfortunately, I’m already in the middle of a project – that’s what I’m keeping in my Subversion repository, and why I need a Subversion client! That said, I may take this up at some point.

Two, I want to keep my criticism of the application separate from the application authors. I treat the failings of a project like this, done for free and presumably in one’s spare time, far differently than I would treat even a shareware application.

I said svnX had most of the functionality I need. But in the realm of polish, it is disappointing, shocking even.

Have a look at the screenshot of the repository window. Notice anything strange in the uppermost table? What’s that first column of radio buttons doing there? To do a diff between two check-in versions, I shit you not, you need to select one of them via the radio button column, and the other by a more normal selection highlight, and then click the FileMerge button.

Why is the UI set up in this bizarre manner? I don’t know for sure, but my suspicion is because it was easier. In Cocoa nibs, tables can be set to allow only single-row selection, or multiple-row selection. Multiple-row selection, as you can imagine, involves a lot more work to handle all the different possibilities. But it’s what users expect.

Actually, I simplified things a bit. Hitting the FileMerge button doesn’t go directly to a file merge. It actually brings up a sheet with exactly the same two tables that are at the top of the window the sheet is attached to, from which you have to select the versions you want to compare. What does that sheet refer to? It turns out, it refers to the file selected in the third table on the main window, though the sheet gives you no indication of that. You can’t multiple-select in that file table, either, so you can’t do several file comparisons at once.

svnX has separate windows for Subversion repositories versus Subversion working copies. You can see a screenshot of the working copies window here. You’ll notice this window is much more simple. The repository history is completely unavailable. All you can know from this window is whether any files have had changes made to them since the last check-in.

Again, I’m assuming the reason this was done was to make things easier. It would be much harder to create an intuitive user interface where the information about a working copy is overlaid on the repository itself…but that’s what I want.

I want to be able to compare my working copy file’s condition against what was checked in 10 revisions ago. I want to be able to see what check-ins were made on the files that I have edited, in the same table – a column you can hide, perhaps, so it’s not always cluttering up the window?

I want to be able to perform file and folder moves in the working repository before checking them in: right now, you can only do that in svnX in the repository window, where changes are immediate.

I want to be able to go from the row representing the file to the file in the Finder. Contextual menus seem totally unsupported.

There’s probably more, but this will do. Some of this stuff is small potatoes, but if I were to work on this, I’d want to tackle the big stuff first, which would probably mean rewriting a lot of the UI code. Not something to be undertaken lightly.

Before I go, I’m going to have to take issue with the name. “svnX”? You name a GUI application after Subversion’s crypticly-named command-line tool plus an “X” to show it’s on Mac OS X? Is that the best you can do?

Here are a few suggestions, marked as (taken) if I found an app with that name in http://VersionTracker.com:

“Subversion” sounds like “Subversive”, right? So how about: Saboteur (probably not), Instigator, Agitator, Provocateur (I like that one).

You’re gaining access to an otherwise unreachable destination, like a castle, right? So how about: Drawbridge, Bridge, even Moat.

It’s a record of changes, so how about: History (taken), Historian (taken), or Archiver. You use it to find or figure things out, so maybe: (Code) Detective, Codehound, maybe even Code Thief.

Finally, I’ll end on a positive note: I like the swirly blue icon.

Subversion Immersion: Changing How I Write My Home Projects

One of the things that sank my MacTADS project was that I let my perfectionist tendencies take over. It wasn’t enough to have things work: the files had to be formatted exactly the same way, had to use the exact same techniques everywhere, had to have exactly the right behavior.

I didn’t use an SCM system then.

Now that I’m using Subversion, I’m finding something pretty cool: the rewriting tendency is more easily resisted.

Instead of letting one thing lead me to another, and then to another (“OK, I’ve fixed that bug, but I’ve noticed this other inconsistency, I’ll just do a big find-and-replace to regularize that….”), I now have to stop and think, what kind of comment would I check that in with? Does it really make sense to lump together this two, or three, or five different changes? When I started out only wanting the first? All right, then, undo the beginnings of the other changes, check in what I have, and call it a night.

Now, if I didn’t care about the organization of my Subversion repository, this wouldn’t be a problem. I might not even use comments for my checkins! (There’s a circle of Hell reserved for such people, btw.) But I’m a perfectionist, remember?

Now, I haven’t yet turned this into greater productivity. I’m not getting things done faster. But I do think I’m avoiding getting things done even slower….

Any Sufficiently Advanced…

Others have commented on how the style of the iTunes 5.0 interface is different than any other Mac OS X 10.4 “Tiger” application. What’s more interesting to me is the contents of the new interface.

They finally added groups! I mean, folders. But they kept most of the wacky, colorful smart groups, I mean, sources, from 4.9:

iTunes 5.0 Xcode 2.1
Xcode iTunes iTunes Xcode

All of this leads me to rule #1 (No, not that rule #1!):

Any sufficiently advanced Mac OS X application is indistinguishable from Xcode.

Obj-C++ Apps and Xcode 2.1 Obj-C Unit Tests: Don’t Forget Step 9!

1. Open Xcode 2.1

2. Make a Cocoa application project. I actually have the OCUnit stuff installed from a previous Xcode version, so my list of new projects included “Cocoa Application + Test”, which I chose (but which you shouldn’t, see below). I called my project “Testy”.

3. Add a C++ class with a member function that’s defined in the .cpp file. I called my class “Testy” as well, and the member function “test()”.

4. In the build settings for the application target, turn off ZeroLink for all configurations: choose “All Configurations” as your configuration in the target’s Info window, select the ZeroLink setting, and hit the delete key. This should turn it from bold to non-bold, and the checkbox to unchecked.

5. Build and run the application, be sure it runs OK, then quit it.

6. Add a Unit Test Bundle target. Add your app target as a direct dependency. Set the target’s Bundle Loader and Test Host settings as specified in Chris Hanson’s wonderful Unit Testing Cocoa Applications post.

7. Add a new Objective-C test case class file. Be sure it has an .mm suffix. In that file, instantiate your C++ class, and call the member function from that instance.

8. Build the Unit Test Bundle target.

It should work, right? You’re using a default project, default targets, following the instructions carefully. But it doesn’t work. The unit test bundle can’t find the C++ symbols from the application.

And the reason why is an additional little wrinkle I discovered today.

9. In your application target’s Info window build settings pane, search on “symbols hidden”. Turn it off. Rebuild your application and your unit test bundle.

Now it works.

Step 9 isn’t needed for applications with Objective-C classes and Objective-C unit test bundles. But it is needed for applications with C++ classes and Objective-C unit test bundles.

So if you have that combination, as I do, don’t forget step 9!

P.S. Second lesson: if you’ve got the old OCUnit stuff on your system, get rid of it before using Xcode 2.1-style unit tests. They don’t go well together. Because I didn’t, I had a lot of “scratch head, fiddle with it some more” sub-steps in the above that you should be spared.

Subversion Incursion: Three Questions

Question #1
In a particular directory in my Subversion repository, I had made maybe ten subdirectories whose names were version numbers, missing their decimal points. Version 2.5.8 was directory name "258", 2.5.9 was "259", etc.

This stopped sorting correctly with version 2.5.10. D’oh!

So I wanted to change all the directory names to their full decimal point equivalents, and then commit the lot of ’em.

Trouble was, I mistyped one of my svn rename changes. I set one directory’s new location to be inside another directory’s new location. Quick, how could I undo that!?

I undid it by using the svn revert command on both the new location and the old location. But what about the case where one was inside another? I had a bad feeling about it, and I was right.

I wound up with Subversion thinking that one of the new locations was (a) an existing, checked-in directory, and (b) being moved to another branch (?). Like so:

    S  3.0.0

Multiple subsequent uses of svn revert were unable to change Subversion’s mind.

Now, the easiest way to undo all this is probably to nuke the working directory and check it out again.

But I’m never one for easy, so I decided to try mucking with the contents of the local .svn directories.

The .svn/entries file has a list of all the files, with changes. Each file is represented by an <entry/> tag. The schedule attribute seems to describe the rename directives I’ve been making.

But hand-editing this file didn’t change the result of a svn status call.

I didn’t want to screw around with it, so I nuked the directory and started over. This time I set up the svn rename calls ahead of time in a text file and double-checked them, so I would get them right the first time.

Has anyone had success hand-edited these entries files?

Question #2
Inside those version number directories mentioned above are code archives. I needed to update my code directories with files from within those the archives. Replace both files and files within subdirectories and files with subdirectories of subdirectories.

In fact, under normal circumstances, I would have just taken the directory that each archive expanded to and dragged that over to replace its code directory twin, because my code directories have the same layout as the archives.

But now that my files are in a Subversion repository, I had to worry about all those little hidden .svn subdirectories. If I just replaced a top-level directory in the repository with a directory from elsewhere via the Finder, all the .svn instances would vanish.

So: is there a utility that will do such a nested copy without actually replacing the directories themselves (and thus deleting their hidden contents)?

Question #3
Once the new files had been copied over, I needed to add them all to the repository. Oops! svn add requires you to specify the exact file (or maybe the location of the files?) to be added. But I’ve got a hundred of new files in a score of different directories.

Text files to the rescue again. I copy the results of an svn status call into BBEdit and sort the lines, so all the lines that start with ? come first, then manipulate the text a little more to get a list of svn add commands.

Is there an easier way?

Omnipreferential: Rolling My Own Prefs Window, Instead of Using Omni Frameworks

After a long hiatus, I am once again looking at the project that first got me using both the Omni frameworks and unit tests.

Why now? An application already exists that does what my project’s app does, but that existing app is Classic-only. Classic seemed to be moseying along just fine until splat! it hit the brick wall of Macintel. No more Classic.

I was using the Omni frameworks primarily for how they made your application’s preferences window easier to implement. The trouble is, the Omni framework projects are sorely outdated. The version you’re supposed to use don’t have native targets, which is a requirement for building Universal binaries.

So it’s time to give them the heave-ho. Does that mean I have to make my own preferences implementation from scratch?

One alternative is to use the Preference Panes framework from Apple. It’s primarily for System Preferences panes, but the documentation makes it clear that it can be used for application preferences, too. The trouble? If you use it for your own application, you have to manage the window and the toolbar yourself. Since that’s most of the work, and since, if you use the Preferences Pane framework, you need to package each pane as a separate bundle, which is even more work, I give it a pass.

Uli Kusterer has UKPrefsPanel and UKToolbarFactory available in the source code portion of his Web site. They look promising. The prefs panel even uses an NSTabView as an easy way to deal with the prefs panes, which is how I was thinking of doing it. But it doesn’t support automatic resizing of a preferences window to the height of each individual preference pane, which is something I definitely want.

In fact, I want my preferences window to look and behave exactly like the preferences windows of standard Apple applications like Safari and Address Book.

So I decide to work directly with NSToolbar, and see what sort of progress I can make.

Apple’s ADC Web site has ToolbarSample source code that’s a good starting point.

Following that sample, I make the NSToolbar myself in code, and add it to the window by sending the window the message setToolbar:. That API actually expands the window by the height of the toolbar: I don’t have to leave room for it myself in the window’s nib. The window also fully takes care of the user hiding and reshowing the toolbar, and saving the selected toolbar item, as long as I send it a setAutosavesConfiguration:YES message. Neat.

There are a lot of things that need some tweaking, though:

• I want to use an NSWindowController to encapsulate the preferences window nib, a straightforward Cocoa technique. But the controller doesn’t seem to use NSWindow’s frameAutosaveName value, which is settable in the nib. In fact, it seems to set it to nil. Instead, if I want to go that route (which I don’t, see below) I need to set the controller’s windowFrameAutosaveName value, which can only be done in code. Annoying.

• The preferences windows of Safari et al erase themselves and then use a cool drawer-like animation to resize between preference panes. I can get the latter using setFrame:display:YES animate:YES, but not the former. I handle this by adding an extra, empty NSTabViewItem after all the other meaningful ones. I switch to that, do the resize, then switch to the NSTabViewItem I really want afterwards.

• I want the individual preference pane’s size info to be in the nib, not something I have recompile to alter. But every NSTabViewItem within an NSTabView is the same size. I work around this by putting my own custom NSView inside each NSTabViewItem, and then putting all my widgets in that subview.

In my code, I check for that subview’s size, and resize the window to match it, when switching to that NSTabViewItem.

• I need to be careful with resizing: it order to get the the effect I want — which is that the window title bar stays stationary, and the bottom of the window slides up or down — in the normal Quartz coordinate system, I need to change both the window size and its origin, because the origin is in the lower left-hand corner of the window. So, every time I select a toolbar item, as far as Cocoa is concerned, I’m both resizing and moving the window. But NSWindowController doesn’t catch this, leading to erroneous positioning when I close and reopen the application.

• If I handle user defaults manually instead of relying on NSWindowController, I can save the window’s frame to the user defaults (a) when I choose a new toolbar item (see the sample for how to associate toolbar items with actions), (b) when the window is moved around by the user (via the notification NSWindowDidMoveNotification), and (c) when the window is resized (via the notification NSWindowDidResizeNotification). Now, the window is not user-resizable, but this notification is still invoked when the user shows or hides the toolbar, because that automatically changes the size of the window.

But why do that much work? Instead, I listen for the notification NSApplicationWillTerminateNotification, and save off the window frame then. Since user defaults are generally only saved to disk upon application termination, this doesn’t lead to a mismatch even if you force-quit the application, because neither the toolbar user default changes that have already happened, nor my code’s user default changes that haven’t happened yet, are saved.