TweetFollow Us on Twitter

September 95 - MPW Tips and Tricks: Customizing Source Control With SourceServer

MPW Tips and Tricks: Customizing Source Control With SourceServer

Tim Maroney

When two engineers on a team edit the same source file at the same time, the resulting chaos can be terrible to behold. Source control was invented to mitigate the problem. Most Macintosh programmers are familiar with the MPW Shell's Check In and Check Out dialogs, and with its Projector commands. The next frontier of custom source control involves SourceServer, a nearly faceless application that implements most of the Projector commands. MPW scripts are easy to write, but they're no match for the power, speed, and friendliness of compiled software. SourceServer exports Projector commands as Apple events, allowing source control from compiled software without launching the MPW Shell in all its pomp and splendor.

Popular third-party development environments often send Apple events to SourceServer for integrated source control. You can also use SourceServer to customize Projector beyond what you might have thought possible. For instance, you can drag source control, kicking and screaming, into the modern world of user experience with drop-on applications. In this column, I'll show you how to check a file in or out with a simple drag and drop, and how to use SourceServer for other things as well. The sample code is provided on this issue's CD; SourceServer is distributed, with documentation, on the MPW Pro and E.T.O. CDs (available from Apple Developer Catalog) and with third-party development systems.

APPLE EVENTS FOR SOURCESERVER

Apple events have many faces, but they're primarily a way of communicating between different applications.

Each Apple event encapsulates a message as a command with any number of input parameters; the receiver of the message may return any number of result parameters to the sender. The most basic unit of data is the Apple event descriptor, which consists of a type code and a data handle. Apple events are built out of descriptors and are themselves special kinds of complex descriptors.

    For an excellent introduction to Apple events, see "Scripting the Finder From Your Application" by Greg Anderson in develop Issue 20.*

SourceServer's commands are represented as descriptor lists. Its Apple events are exact duplicates of the MPW Shell's Projector commands, but to avoid the overhead of a full command parser, both the command name and each argument are descriptors in the descriptor list. This saves you the trouble of putting quotes and escapes into arguments that might contain spaces or other special characters. The downside is that you have to expand arguments yourself: you can't pass in MPW wildcard characters, backquoted commands for expansion, or other special constructs.

Creating descriptor lists may sound harder than writing MPW scripts, but that's only because it is. I've provided some utility routines to ease the way, though. Listing 1 shows the utilities and illustrates how to make a command to check out a file for modification. As illustrated in the CheckOut routine in this listing, you call the CreateCommand routine first and then use the AddXArg routines to add arguments.

Listing 1. Creating SourceServer commands

OSErr CreateCommand(AEDesc *command, CString commandText)
// Begin a new SourceServer command; name of command is in
// commandText.
{
   OSErr err = AECreateList(NULL, 0, false, command);
   if (err != noErr) return err;
   err = AddCStringArg(command, commandText);
   if (err != noErr) (void) AEDisposeDesc(command);
   return err;
}

OSErr AddCommentArg(AEDesc *command, StringPtr comment)
/* Add a "-cs comment" argument to a SourceServer command. */
{
   OSErr err;
   if (comment[0] == 0) return noErr;
   err = AddCStringArg(command, "-cs");
   if (err != noErr) return err;
   err = AddPStringArg(command, comment);
   return err;
}

/* Other SourceServer argument utilities */
OSErr AddDirArg(AEDesc *command, short vRefNum, long folderID);
OSErr AddProjectArg(AEDesc *command, StringPtr projectName);
OSErr AddUserArg(AEDesc *command, StringPtr userName);
OSErr AddFullNameArg(AEDesc *command, FSSpec *file);
OSErr AddPStringArg(AEDesc *command, StringPtr string);
OSErr AddCStringArg(AEDesc *command, CString string);

OSErr CheckOut(FSSpec *file, StringPtr userName,
               StringPtr projectName, StringPtr comment)
/* Create a "Check Out Modifiable" command for SourceServer: */
/* CheckOut -m -cs <comment> -d <dir> -project < */
/*           project> -u <user> <file> */
{
   OSErr             err;
   AEDesc          command;
   CStringHandle    output = NULL, diagnostic = NULL;

   err = CreateCommand(&command, "CheckOut");
   if (err != noErr) return err;
   err = AddCStringArg(&command, "-m");
   if (err == noErr) err = AddCommentArg(&command, comment);
   if (err == noErr)
     err = AddDirArg(&command, file->vRefNum, file->parID);
   if (err == noErr) err = AddProjectArg(&command, projectName);
   if (err == noErr) err = AddUserArg(&command, userName);
   if (err == noErr) err = AddPStringArg(&command, file->name);
   if (err == noErr)
     err = SourceServerCommand(&command, &output, &diagnostic);
   (void) AEDisposeDesc(&command);
   /* Display output or diagnostic text as desired. */
   if (output != NULL) DisposeHandle((Handle) output);
   if (diagnostic != NULL) DisposeHandle((Handle) diagnostic);
   return err;
}

Some of the utilities take Pascal strings, while others take C strings, which could well be considered bad programming practice. I chose this dubious method not because I'm on drugs, but because Pascal strings and C strings are used in different ways. SourceServer's text descriptors are C strings; when passed to these utilities as string constants, they shouldn't be converted from Pascal format in place, since some compilers put constants in read-only areas. If you're internationally savvy, you may have another objection: string constants themselves are bad practice. However, for better or worse, MPW scripts and tools are not internationalized. Just like aliens in Star Trek, all MPW programmers are assumed to speak English.

While on the subject of programming practice, I must gently reprimand SourceServer for its approach to Apple events, in which script commands are simulated through a single 'cmnd' event. SourceServer's idiosyncratic convention dates from the earliest days of Apple events, and modern guidelines discourage this type of design. An application implementing its own Apple events should designate a different command code for each operation, treating arguments as keyword parameters.

Listing 2 shows how to send an Apple event to SourceServer. It's first necessary to find and perhaps launch the SourceServer application. The snippet called SignatureToApp (by Jens Alfke) on this issue's CD accomplishes this with a single function call. Simply pass in the creator code of SourceServer, which is 'MPSP'.

Listing 2. Sending commands to SourceServer

OSErr SourceServerCommand(AEDesc *command, CStringHandle *output,
                          CStringHandle *diagnostic)
{
   AppleEvent            aeEvent;
   AERecord              aeReply;
   AEDesc                sourceServerAddress, paramDesc;
   ProcessSerialNumber   sourceServerProcess;
   /* SignatureToApp requires this due to a minor bug */
   FSSpec                appSpec;
   long                  theLong, theSize;
   DescType              theType;
   OSErr                 err;

   *output = *diagnostic = NULL;   /* default replies */
   
   /* Find the SourceServer process and make a descriptor for its */
   /* process ID. */
   err = SignatureToApp('MPSP', NULL, &sourceServerProcess,
                         &appSpec, NULL, Sig2App_LaunchApplication,
                         launchContinue + launchDontSwitch);
   if (err != noErr) return err;
   err = AECreateDesc(typeProcessSerialNumber,
                      (Ptr) &sourceServerProcess,
                     sizeof(ProcessSerialNumber),
                     &sourceServerAddress);
   if (err != noErr) return err;

   /* Create and send the SourceServer Apple event. */
   err = AECreateAppleEvent('MPSP', 'cmnd', &sourceServerAddress,
                           kAutoGenerateReturnID, kAnyTransactionID,
                           &aeEvent);
   /* done with the address descriptor */
   (void) AEDisposeDesc(&sourceServerAddress);
   if (err != noErr) return err;
   /* add the command */
   err = AEPutParamDesc(&aeEvent, keyDirectObject, command);
   if (err != noErr) { (void) AEDisposeDesc(&aeEvent); return err; }
   err = AESend(&aeEvent, &aeReply,
                kAEWaitReply + kAENeverInteract, kAENormalPriority,
                kNoTimeOut, NULL, NULL);
   (void) AEDisposeDesc(&aeEvent);   /* done with the Apple event */
   if (err != noErr) return err;

   /* Check for an error return in the keyErrorNumber parameter. */
   err = AEGetParamPtr(&aeReply, keyErrorNumber, typeInteger,
                      &theType, &theLong, sizeof(long),
                      &theSize);
   if (err == noErr && (err = theLong) == noErr) {
      /* Get the standard output from the keyDirectObject parameter. */
      err = AEGetParamDesc(&aeReply, keyDirectObject, typeChar,
                           &paramDesc);
      if (err == noErr)
          *output = (CStringHandle) paramDesc.dataHandle;
      /* Get the diagnostic output from the 'diag' parameter. */
      err = AEGetParamDesc (&aeReply, 'diag', typeChar,
          &paramDesc);
      if (err == noErr)
          *diagnostic = (CStringHandle) paramDesc.dataHandle;
      /* Get the MPW status from the 'stat' parameter -- it */
      /* becomes our error return. */
      err = AEGetParamPtr(&aeReply, 'stat', typeInteger,
                         &theType, &theLong,
                         sizeof(long), &theSize);
      if (err == noErr) err = theLong;
   }

   /* done with the reply descriptor */
   (void) AEDisposeDesc(&aeReply);
   return err;
}

The event must be created before it can be sent. For SourceServer, there's a single parameter, named keyDirectObject, which is the descriptor list containing the command. After sending the event, you must extract the results. The results of an Apple event are returned as keyword parameters in a reply descriptor. First there's the standard keyErrorNumber parameter, which returns an error code if delivery failed. SourceServer returns three other parameters: The 'stat' parameter contains a second error code; if it's nonzero, SourceServer tried to execute the command and failed. When there's an error, there will be diagnostic output in the 'diag' parameter, a handle containing text from the MPW diagnostic (error) channel. Finally, there's standard output -- a handle specified by keyDirectObject -- which contains explanatory text.

PROJECTDRAG -- DRAG AND DROP SOURCE CONTROL

The Macintosh has always had a drag and drop user experience, but the true power and generality of dragging has been widely recognized only recently. The drag paradigm can even be used for source control. To turn Projector into a drag-savvy system, I've written a set of utilities called ProjectDrag (source code and documentation are provided on this issue's CD). You simply drag and drop icons onto the following miniapplications that make up ProjectDrag, and the corresponding function is performed:
  • Check In and Check Out, for checking files in and out

  • ModifyReadOnly, for editing a file without checking it out

  • Update, for bringing a file or folder up to date, as well as canceling checkouts and modify-read-only changes

  • ProjectDrag Setup, for configuring the system
These utilities are based on a drop-on application framework called DropShell (written by Leonard Rosenthol and Stephan Somogyi), also on the CD. When a file is dropped onto an application, the application receives an Open Documents ('odoc') event. DropShell takes care of the rigmarole of receiving this and other required Apple events. The ProjectDrag miniapplications pull the file specifications out of 'odoc' events and create SourceServer commands that operate on the files and folders that were dropped on their icons.
    DropShell is also available on the Internet at ftp://ftp.hawaii.edu/pub/mac/info-mac/Development/src/ and at other Info-Mac mirror sites.*
Some setup is required. ProjectDrag needs to know the locations of Projector databases. It maps between project names and Projector database files by keeping aliases to database folders in its Preferences folder. To start using a project, simply drag its ProjectorDB file or the enclosing folder onto ProjectDrag Setup. Projector also needs to know your user name, and your initials or a nickname are used in change comments at the start of files. These are stored in a text file in the Preferences folder. ProjectDrag asks you for this information if it can't find it, or you can launch ProjectDrag Setup and give the Set User Name command.

ProjectDrag is scriptable, unlike SourceServer and the MPW Shell. The miniapplications have an Apple event terminology resource ('aete') to advertise their events to scripting systems. This allows you to add source control commands to any application that lets you add AppleScript scripts to its menus.

ProjectDrag is able to run remotely over a network. This circumvents a limitation of SourceServer, which can only be driven locally. ProjectDrag can receive remote Apple events and then drive a copy of SourceServer that's local to it. Among other uses, this could support an accelerator for Apple Remote Access. Checking a file in or out over ARA takes a few minutes, which is fine, especially for those who find tedium particularly enjoyable. Copying files is faster. With local AppleScript front ends for remote ProjectDrag miniapplications, you could copy files to and from a remote "shadow folder" and initiate SourceServer commands at the remote location, where they would execute over a fast network such as Ethernet.

I like to think that I can solve user interface problems in my sleep. When I was writing ProjectDrag, I had a dream of a better user experience. Instead of miniapplications, ProjectDrag would be a magical system extension that would put a single small icon at some convenient place on the screen. When you dragged a file onto this icon, it would pop open into a temporary window and show you icons for the various options. Dreams are great for creativity, but it's easier to weigh alternatives when you're awake. After I woke up, I realized that miniapplications will be able to do the same thing.

Here's how: In Copland, the next generation of the Mac OS, the Finder will spring-load folders so that they open automatically when you drag onto them. It will also let you stash commonly used folders at the bottom of the screen, where they appear as short title bars. Drag the ProjectDrag folder to the bottom of the screen and you're set! Since the Finder will be providing my dream interface, there's no point in a lot of trap patching and extensibility infrastructure to accomplish the same thing.

Copland will bring another user experience benefit to ProjectDrag: it's planned that document windows will have a draggable file icon in their title bar, so you'll be able to use ProjectDrag on an open document by dragging the icon from its window.

YOU TAKE IT FROM HERE

You can create programs that use SourceServer for many other tasks. On cross-platform projects, Projector is sometimes used to control both platforms' source folders. This can lead to baroque and error-prone processes. With SourceServer, you can create front ends that do the right thing. They could copy to remote folders over a network, or lock read-only files since the other platform doesn't see Projector's 'ckid' resources.

Quality is an interesting area for source control applications. A quality tool could query Projector databases for the frequency and scope of changes at various stages of the project, correlating them with bug tracking to develop project metrics. Along similar lines, a tool could measure the change rate of various files to assist in what the quality gods refer to as root-cause analysis.

SourceServer is much more than a way for development systems to provide integrated source control. It's great for structuring your internal development process as well!

TIM MARONEY wrote TOPS Terminal and BackDrop, and has been a major contributor to TOPS for Macintosh, FaxPro, and Cachet. He has also contributed to Fiery, the Disney Screen Saver, Ofoto, Colortron, and the Usenet Mac Programmer's Guide. Tim learned computer networking while working on the Andrew and MacIP projects at Carnegie Mellon and studied compiler design in graduate school at Chapel Hill. He has written for all three major operating systems and a few minor ones. On the Macintosh, Tim's code has included applications, INITs, control panels, HyperCard stacks, XCMDs, shared libraries, trap patches, plug-ins, scripts, and things more difficult to characterize. Tim is currently doing contract work at Apple, and is available for parties and special events at a nominal cost.*

Thanks to Greg Anderson, Arno Gourdol, and B. Winston Hendrickson for reviewing this column.*

Special thanks to Jens Alfke, Jon Pugh, Leonard Rosenthol, and Stephan Somogyi.*

 

Community Search:
MacTech Search:

Software Updates via MacUpdate

Check out the new Pirate Attack update i...
Love pirates and board games? Well, you'll love the new Pirate Attack themed update that just launched in Game of Dice. It adds a bunch of new content themed around pirates, like an all new event map based on a pirate ship which revamps the toll... | Read more »
Splash Cars guide - How to paint the tow...
Splash Cars is an arcade driving game that feels like a hybrid between Dawn of the Plow and Splatoon. In it, you'll need to drive a car around to repaint areas of a town that have lost all of their color. Check out these tips to help you perform... | Read more »
The best video player on mobile
We all know the stock video player on iOS is not particularly convenient, primarily because it asks us to hook a device up to iTunes to sync video in a world that has things like Netflix. [Read more] | Read more »
Four apps to help improve your Super Bow...
Super Bowl Sunday is upon us, and whether you’re a Panthers or a Broncos fan you’re no doubt gearing up for it. [Read more] | Read more »
LooperSonic (Music)
LooperSonic 1.0 Device: iOS Universal Category: Music Price: $4.99, Version: 1.0 (iTunes) Description: LooperSonic is a multi-track audio looper and recorder that will take your loops to the next level. Use it like a loop pedal to... | Read more »
Space Grunts guide - How to survive
Space Grunts is a fast-paced roguelike from popular iOS developer, Orange Pixel. While it taps into many of the typical roguelike sensibilities, you might still find yourself caught out by a few things. We delved further to find you some helpful... | Read more »
Dreii guide - How to play well with othe...
Dreii is a rather stylish and wonderful puzzle game that’s reminiscent of cooperative games like Journey. If that sounds immensely appealing, then you should immediately get cracking and give it a whirl. We can offer you some tips and tricks on... | Read more »
Kill the Plumber World guide - How to ou...
You already know how to hop around like Mario, but do you know how to defeat him? Those are your marching orders in Kill the Plumber, and it's not always as easy as it looks. Here are some tips to get you started. This is not a seasoned platform... | Read more »
Planar Conquest (Games)
Planar Conquest 1.0 Device: iOS Universal Category: Games Price: $12.99, Version: 1.0 (iTunes) Description: IMPORTANT: Planar Conquest is compatible only with iPad 3 & newer devices, iPhone 5 & newer. It’s NOT compatible with... | Read more »
We talk to Cheetah Mobile about its plan...
Piano Tiles 2 is a fast-paced rhythm action high score chaser out now on iOS and Android. You have to tap a series of black tiles that appear on the screen in time to the music, being careful not to accidentally hit anywhere else. Do that and it's... | Read more »

Price Scanner via MacPrices.net

BookBook For iPad Pro Coming Soon
The iPad Pro is a device unlike any other, and with Apple Pencil, it’s the ideal portable sketchpad: all that’s missing is the modern easel and portfolio to go. TwelveSouth’s BookBook for iPad Pro... Read more
12-inch 1.2GHz Silver Retina MacBook on sale...
B&H Photo has the 12″ 1.2GHz Silver Retina MacBook on sale for $1399 including free shipping plus NY sales tax only. Their price is $200 off MSRP, and it’s the lowest price for this model from... Read more
iPads on sale at Target: $100 off iPad Air 2,...
Target has WiFi iPad Air 2s and iPad mini 4s on sale for up to $100 off MSRP on their online store for a limited time. Choose free shipping or free local store pickup (if available). Sale prices for... Read more
Target offers Apple Watch for $100 off MSRP
Target has Apple Watches on sale for $100 for a limited time. Choose free shipping or free local store pickup (if available). Sale prices for online orders only, in-store prices may vary: - Apple... Read more
Apple refurbished 2014 13-inch Retina MacBook...
Apple has Certified Refurbished 2014 13″ Retina MacBook Pros available for up to $400 off original MSRP, starting at $979. An Apple one-year warranty is included with each model, and shipping is free... Read more
Macs available for up to $300 off MSRP, $20 o...
Purchase a new Mac or iPad using Apple’s Education Store and take up to $300 off MSRP. All teachers, students, and staff of any educational institution qualify for the discount. Shipping is free, and... Read more
Watch Super Bowl 50 Live On Your iPad For Fre...
Watch Super Bowl 50 LIVE on the CBS Sports app for iPad and Apple TV. Get the app and then tune in Sunday, February 7, 2016 at 6:30 PM ET to catch every moment of the big game. The CBS Sports app is... Read more
Two-thirds Of All Smart Watches Shipped In 20...
Apple dominated the smart watch market in 2015, accounting for over 12 million units and two-thirds of all shipments according to Canalys market research analysts’ estimates. Samsung returned to... Read more
12-inch 1.2GHz Retina MacBooks on sale for up...
B&H Photo has 12″ 1.2GHz Retina MacBooks on sale for $180 off MSRP. Shipping is free, and B&H charges NY tax only: - 12″ 1.2GHz Gray Retina MacBook: $1499 $100 off MSRP - 12″ 1.2GHz Silver... Read more
12-inch 1.1GHz Gray Retina MacBook on sale fo...
B&H Photo has the 12″ 1.1GHz Gray Retina MacBook on sale for $1199 including free shipping plus NY sales tax only. Their price is $100 off MSRP, and it’s the lowest price available for this model... Read more

Jobs Board

*Apple* Retail - Multiple Positions (US) - A...
Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, you're also the Read more
*Apple* Retail - Multiple Positions (US) - A...
Job Description: Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, Read more
*Apple* Subject Matter Expert - Experis (Uni...
This position is for an Apple Subject Matter Expert to assist in developing the architecture, support and services for integration of Apple devices into the domain. Read more
*Apple* Macintosh OSX - Net2Source Inc. (Uni...
…: * Work Authorization : * Contact Number(Best time to reach you) : Skills : Apple Macintosh OSX Location : New York, New York. Duartion : 6+ Months The associate would Read more
Computer Operations Technician ll - *Apple*...
# Web Announcement** Apple Technical Liaison**The George Mason University, Information Technology Services (ITS), Technology Support Services, Desktop Support Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.