Monday, August 12, 2013

Getting your stuff - using the RTC SDK to zip a repository workspace

Have you ever wanted to create a zip archive of a repository workspace? This post describes how to use the RTC SDK (and some undocumented internals) to copy the contents of a repository workspaces into a zip file.

Let's start with some background. A repository workspace contains components, each of which has a configuration - which is a ten dollar word for "file tree." The configuration provides access to the structure of the tree and has pointers to the file content.

A program that zips up a remote workspace needs to:
  1. log into the repository,
  2. find the workspace to zip,
  3. get the components in the workspace,
  4. get the configuration of each component, and finally
  5. walk the file tree to write each directory/file to our zip.
This post uses unsupported API. It is likely that the APIs will change without warning in future iterations of RTC - you should use the Source Control command line tool instead. You are using these APIs at your own risk.
Each step is addressed in its own section. The code samples are available on JazzHub or can be downloaded as a zip. You are expected to have a working development environment with the RTC SDK and RTC server configured properly.

Logging in to the repository

All of the information we're interested in is stored on the RTC repository. In order to access it, our programs needs to log in:
ITeamRepository repo = TeamPlatform.getTeamRepositoryService().getTeamRepository(uri);
  
repo.registerLoginHandler(new MyLoginHandler(username, pw));

repo.login(null);
The MyLoginHandler class included in the sample project. The username and
pw are configured beforehand.

Finding the workspace

For our example, we find the workspace by searching for one with a specific name using the IWorkspaceManager#findWorkspaces() method.

The interesting classes here are the SCMPlatform singleton that allows us to get a IWorkspaceManager, and the IWorkspaceSearchCriteria. The workspace manager answers simple queries about workspaces, as well as providing access to IWorkspaceConnections, that we will learn more about below.

IWorkspaceManager mgr = SCMPlatform.getWorkspaceManager(repo);


// Find the named workspace
IWorkspaceSearchCriteria cri = IWorkspaceSearchCriteria.FACTORY.newInstance();
cri.getFilterByOwnerOptional().add(repo.loggedInContributor());
cri.setExactName(wsName);
List<IWorkspaceHandle> findWorkspaces = mgr.findWorkspaces(cri, 2, null);

if (findWorkspaces.size() == 0) {
 System.err.println("Couldn't find any workspaces named \"" + wsName + "\"");
 return false;
}

if (findWorkspaces.size() > 1) {
 System.err.println("Multiple workspaces named \"" + wsName + "\"");
 return false;
}
The IWorkspaceSearchCriteria allows us to build a query that matches a number of workspaces. The query fields are implicitly and'ed together to limit the workspaces returned. In an ideal world, we'll find exactly one workspace that matches our criteria.

Searching by workspace name is useful for our example, but it isn't the safest thing to do in a production environment, since there could be multiple workspaces with the same name. In production UI code, we would present the user with a choice of workspaces. If the code were headless, we would use the ID of the workspace we care about.

Because we want a modicum of correctness, our example ensures that there is exactly one visible workspace with the given name (lines 68-76).

The findWorkspaces() method returns a list of handles to the workspaces matching the criteria. A handle is a lightweight object that identifies an item in the repository. We'll use the handle later on to query the workspaces.

Getting the components in the workspace


Once we've found the IWorkspaceHandle, we need a richer representation to query the file tree. We do that by converting the handle into an IWorkspaceConnection (see line 78, below). The IWorkspaceConnection provides operations on a repository workspace, and caches information about the workspace.

Now we have the connection, we start digging into the structure of the workspace. The topmost layer in the logical tree consists of components. Components split remote workspaces into logical groupings of files and folders. They aren't normally represented in the local filesystem when loaded, so our zip creator won't record them in the zip.

IWorkspaceConnection wsConn = mgr.getWorkspaceConnection(findWorkspaces.get(0), null);

// Start walking the workspace contents
IFileContentManager contentManager = FileSystemCore.getContentManager(repo);

File base = new File(System.getProperty("user.dir"));

FileOutputStream out = new FileOutputStream(new File(base, wsName + ".zip"));
try {
 ZipOutputStream zos = new ZipOutputStream(out);
 
 for (IComponentHandle compHandle : (List<IComponentHandle>)wsConn.getComponents()) {
  IConfiguration compConfig = wsConn.configuration(compHandle);

  // Fetch the items at the root of each component. We do this to initialize our 
  // queue of stuff to download.
  Map<String, IVersionableHandle> handles = compConfig.childEntriesForRoot(null);
  List<IVersionable> items = compConfig.fetchCompleteItems(new ArrayList<IVersionableHandle>(handles.values()), null);

  loadDirectory(contentManager, compConfig, zos, "", items);
 }
 
 zos.close();

} finally {
 out.close();
}
On line 89 we loop over each of the components, getting an IConfiguration. The configuration encapsulates the file/folder structure in the repository workspace, so we use that to walk the remote filesystem. The first part of the walk is on line 94 where we get the handles of the component's root items. (Note that we're dealing with root items: there could be files and symlinks at the top of the component hierarchy, as well as directories)

Walking the file tree to fetch content


We're finally here! The fun part that involves getting file content from the repository. Unfortunately, this is also where we diverge from the supported API. In our last code snippet, you'll notice that we got an IFileContentManager on line 81. Sadly, that isn't part of the API anyone outside of the SCM Core is supposed to use. If you do use it, be aware that the class could change in future releases. You use it at your own risk.

With the legalese/honesty out of the way, let's look at how we use the forbidden API. Our loadDirectory method is called recursively to write the content of each directory into the zip file. It takes a list of IVersionable items as an argument. An IVersionable is the superclass of the things that live in a filesystem: files, folders, or symlinks. It is possible that other types of items could exist in the configuration - but let's pretend they don't, because, for the most part, they won't.

loadDirectory() loops over each versionable and either creates a directory in the zip or writes the file content into the zip. In the case of folders, it gets the children from the configuration (line 135), and then recursively calls itself:

if (v instanceof IFolder) {
 // Write the directory
 String dirPath = path + v.getName() + "/";
 zos.putNextEntry(new ZipEntry(dirPath));
 
 @SuppressWarnings("unchecked")
 Map<String, IVersionableHandle> children = compConfig.childEntries((IFolderHandle)v, null);
 @SuppressWarnings("unchecked")
 List<IVersionable> completeChildren = compConfig.fetchCompleteItems(new ArrayList<IVersionableHandle>(children.values()), null);

 loadDirectory(contentManager, compConfig, zos, dirPath, completeChildren);
}

More interesting things happen in the IFileItem block:

else if (v instanceof IFileItem) {
 // Get the file contents and write them into the directory
 IFileItem file = (IFileItem) v;
 zos.putNextEntry(new ZipEntry(path + v.getName()));
 
 InputStream in = contentManager.retrieveContentStream(file, file.getContent(), null);
 byte[] arr = new byte[1024];
 int w;
 while (-1 != (w = in.read(arr))) {
  zos.write(arr, 0, w);
 }
 
 zos.closeEntry();
}

The fun part is on line 146 where we ask the (forbidden) IFileContentManager for the content of the file. We pass in the IFileItem as well as its IContent, which is a pointer to the blob of bytes stored in the RTC repository. The remainder of the block is anticlimactic: copying the content with a regular Java stream idiom.

Even though the file content portion of this example is forbidden API, the example helps to show how to use our APIs. The pattern of logging in, finding a workspace, and then using the IWorkspaceConnection to perform some operation may be useful in other contexts. The example doesn't begin to get into the practical complexities of getting content (normalizing line endings, storing file properties, handling symlinks), or the problems faced when merging into an existing filesystem.

You can download the full Eclipse project or poke at the project on JazzHub

Thursday, July 4, 2013

Configuring Eclipse to use the RTC SDK

Last night I was poking around trying to figure out how to write a demo with the Rational Team Concert SDK. My first attempt failed. It wasn't until I found Ralph Schoon's excellent blog post on using the SDK that I finally figured out how to do it.

Since Ralph's post is long and it refers to an even longer PDF, I thought I'd present an abridged explanation:

  1. Download the RTC SDK and server. At the time of writing, 4.0.3 is the most recent release, so  you might as well grab that
  2. Extract the SDK to ~/rtc-sdk.
  3. Start Eclipse on a fresh workspace. 
  4. Set your target platform by:
    1. Open the Eclipse preferences and search for the Target Platform page.

    2. Click "Add" to create a new target platform. Initialize it with "Nothing."

    3. Edit the target platform.

    4. Add an Installation. Point it to ~/rtc-sdk.

    5. Set your target platform as default.
You're done! You can now write programs that use the RTC SDK.

To verify that your Eclipse is properly configured, download the attached project, and copy it into Eclipse. Get your server configured and started, then edit Start.java to use the URI of your server and credentials of the user you created.

You can run the test application with the "api demo" Eclipse launcher. It logs into the server, creates a repository workspace named "meow", and then lists all of the repository workspaces owned by the current user. At the very least, you should see "meow" in the Eclipse Console:
Expected output in a properly configured Eclipse

Sunday, January 27, 2013

When should you start using a source control?

My eyes were immediately drawn to this thread on Ars Technica: "When should I make the first commit to source control?", with answers from Stack Exchange users.

I'm from a team at IBM that is building a source control. So getting my opinion is a bit like asking your stock broker what he or she thinks about the merits of investing on the stock market. Of course I'm convinced the source control should be a transparent part of your development - you should not even have to think about it while you design and edit your code. It should just be there when you're in a bad state and you want to return to a know good one. Aka, you should not even ask yourself when to make the first commit...

A source control doesn't have to be in the way of your dev work. It knows when you save files, and in many IDEs and products out there, it even knows what task or defect you are working on. It can work in the background, safely pushing your changes from your local drive to a remote machine, so you can crash your hard drive or pursue your work from a separate machine in the evening.

A source control is now a basic feature like syntax highlighting, code assist or refactoring. It's a given that whatever you've done, you can review and roll back in time, fork and try something else. Suspend your current work, resume some other on-going work. Work with a buddie, with a team. And when you can do all that without thinking about having to use a source control, then we've succeeded.

The first tip I give about using a source control is to check-in frequently. By that I mean storing your changes frequently in the source control, which isn't the same as giving every one of your changes to your team. Many source controls have a staged approach - you can version control your own changes in a private way then control when you find them useful and good enough to be shared with others.

In the 8 years of RTC Source Control, we tested different source control workflows. In the early days, we were really keen on something called auto check-in. In 1.0, that feature was on by default. You save a file. Bing. That change is safely backed up on the RTC server, in your private workspace. Some of us were wondering - why bother asking the user when to manually check-in? Why not doing it automatically for every file that is modified? It turned out to be a very divisive matter. 
  • Some really thought that was the way of the future - just have every change you do automatically be replicated in your backup on the server. 
  • And others really wanted to stay in control as to when their changes leave their local drive and become part of the source control's memory.
I was initially a strong proponent of the auto check-in workflow. I always thought the ones opposing it were a bit like the mathematician Gauss as described by Abel: "he is like the fox, who effaces his tracks in the sand with his tail". Like you don't want others to know all the wrong paths you've explored before you actually perfected the fix for a defect... That's too bad, because e.g. RTC Source Control has a way to highlight the initial and final versions in a change set and make the intermediate versions mostly hidden in regular operations. 

So why did we turn off auto check-in by default? Because many users were hit by some of its drawbacks.
  • Network latency when you work over a poor wifi connection at the airport
  • Big mess when a mistake you do in your IDE refactors 1000 files.
  • Your history is filled with meaningless changes (if you use auto-complete of change sets) or with huge change sets if you forget to help the tool and complete your change sets from time to time
I did experience all these annoyances myself and was convinced that it wasn't appropriate for a majority of users in its current form. It's fantastic for those users who like the convenience and remember to complete their change sets at appropriate stable moments. I don't use auto check-in anymore. But I frequently check-in my changes so that I can easily go back to a previous good state, and in RTC we make it easy with a simple "Check-in all" button. I only deliver my changes to the stream used by my team when it's ready - after a green personal build for example.

If the source control you use makes a commit sound like a complicated, slow and cumbersome task to perform, you're likely missing the greatest strength of a source control. It's invisible to you when things work, and it's there when you need it. So, in conclusion, next time you create a project, put it under version control right away... Version control is good for you even if you don't intend to share with other peers right away.

Friday, December 21, 2012

Latest videos and articles about RTC SCM

For some of us working in RTC SCM, it's a big snow day, we're not just dreaming about a white Xmas :-) For our developers in locations where snow is a rarity, you cannot imaging the joy of clearing up your drive way... This said, time to reflect on what we've done and published for our RTC users.

Since the articles and videos we listed last July and August, much more has happened in the last  five months.

For CLI users, check out these three videos from Shashik and Sridevi.
If your source code base is large - or should I say, huge - and you have to deal with many variants, you want to carefully think about how to organize it in your SCM. Here are tips illustrated with the popular Android OS code base, from John.
How you use your source with your local tools and how you version it in RTC can be straightforward or very sophisticated. These two articles go to great depth in load workflows.
Yes, process is built-in with every component of RTC - Work Item, planning, build and of course source control. If you're a scrum master, component lead or project manager, this article from Evan is a must read.
And if you want to upgrade to the latest version of your VS IDE, we got it covered... Vandana gives an overview there.
For tips on how we review changes when fixing defects and how we set process conditions to ensure appropriate reviews are in place, have a peek at this blog post from myself, and its two videos.
See you in 2013! We've got more in the pipeline...

Tuesday, November 27, 2012

Try out the latest 4.0.1 RTC SCM in the jazz.net sandbox

It's really easy to get a feel for the latest RTC SCM 4.0.1. The jazz.net sandbox gets you up and running in seconds. All you need is a jazz.net login account. You'll have your own project area hosted on jazz.net, ready for your trial of RTC and SCM.

Create your jazz.net sandbox


  1. Go to www.jazz.net/sandbox . You may have to create a free jazz.net user account if you've never been there before. That will also allow you to open work items and ask questions on the forum.
  2. Pick the option /sandbox2 - you'll get your project hosted on the very latest RTC 4.0.1 server
  3. Give a name to your project area - e.g. mine is called chrisx's 4.0.1 project.

Upload content into your jazz.net sandbox


Click on Source Control / Welcome to Source Control. You're ready to try our latest SCM!


Your project area is mostly empty to start with. It does come with a default stream, into which you can add folders and files. From the Welcome to Source Control page, click on Show Streams and navigate into the one stream listed there. It has one component which contains no files or folders. Adding new files and folders is very easily done through the Web UI. Click on the Add folder icon as indicated below, give it a name and hit save.


Once that folder is created, you can upload new files, etc. Here below we created a new text file named 'readme.txt'.


Invite others to your sandbox on jazz.net


Being alone isn't the greatest way to try a collaborative tool. So go back to www.jazz.net/sandbox, click on sandbox02/ again. This lists all your project areas, including the one you have just created. Click on the Invitations button and bring your teammates to your trial party. Once they accept your invitation, they will be added to your project area. They will be able to see the files you have added earlier to that default stream and start collaborating with you through RTC Source Control.


Try out the other (non Web UI) RTC Source Control clients


At that point you and your co-workers may want to try out other RTC clients such as the Eclipse RTC Client, RTC Client for Microsoft Visual Studio, RTC Shell (which integrates into the Windows Explorer) or the Command Line Interface tool. You can download the desired client (and your own server if you want to go beyond what the jazz.net hosted sandbox provides) at https://jazz.net/downloads/rational-team-concert/.

As an example, I downloaded and installed the RTC Shell client. This client integrates into the Microsoft Windows Explorer, so I can easily sync up files and folders loaded on my local drive and collaborate with my team members. After the installation, you just accept the team invitation (see below) which is available from the jazz.net sandbox (see above).


I followed the recommendations of the 'Accept Team Invitation' wizard. I created a repository workspace from the stream I had been using earlier and loaded its content under my local drive. It created the expected Documents folder and readme.txt file I had added through the Web UI.


This is showing the RTC Shell client integrated into Windows Explorer. This content was loaded from the RTC server hosted on the jazz.net sandbox. I can make changes to these files and folders with my local editors (Notepad etc.), check-in and deliver them so that others in my team can access them.

Summary


It's really easy to get a quick feel for our latest RTC SCM, with the jazz.net sandbox. And if all you want is to play with our Web UI, you have nothing to download!

Friday, November 23, 2012

Icons used in Rational Team Concert Source Control

The Eclipse client for RTC, RTC Client for Microsoft Visual Studio and the Web UI use specific icons to represent SCM artifacts. These base icons are enhanced with extra visuals relative to their status in certain views (e.g. the Team Artifacts view, Pending Changes view, Repository workspace editor, etc.). Here's a list of the basic icons and their variants used in the SCM. If you are not familiar with any of the terms used below, please try out Good practices and key workflows for Rational Team Concert Source Control users for appropriate references.




Stream


 Repository Workspace


Snapshot


 Baseline




Component


  1. Component (if shown within a repository workspace, also indicate it is loaded or partially loaded in my sandbox)
  2. Component owned by a project area
  3. Component owned by me
  4. Component owned by a contributor who isn't me
  5. Component (if shown within a repository workspace, also indicate it is not loaded in my sandbox)
 



Change Set


  1. Change set (active i.e. not completed, not linked to any work item)
  2. Current change set (active i.e. not completed, auto check-in will default to this change set)
  3. Completed change set (not linked to any work item)
  4. Completed change set linked to one work item
  5. Completed change set linked to two or more work items
If you are puzzled by other SCM icons, please drop a comment below with a link to a screen capture (e.g. attach it to the work item 40464). Hope this reference will be helpful to you.

Note. For icons inside the Pending Changes view, explanations are also provided here.

Friday, September 28, 2012

working with different currencies

One of the things that I like the most about Rational Team Concert is how we solve problems which cross-cut across the developer's perspective.  What this means is that the change sets that a developer produces are linked to work items, which often have a particular process workflow to them.  The change sets are also captured in snapshots via builds, so we have traceability from builds right through to the work item or plan.  We almost take this traceability for granted, having used the product now for > 5 years and counting.  This traceability provides another benefit that may be subtle to some people.

The linking of work items to change sets allows for users of different backgrounds to talk about the same problem in language that they are most familiar with.  We have found that many people indicate that they "deliver work items" to the stream when they are done.   The work item tends to be where the discussion happens, and where consensus is reached.  The code artifacts are derived from that understanding.  So when talking to a development manager, they are interested in knowing that the work item is closed (and the fix delivered) rather than the specifics as to how the fix was done.

So while developers may talk change sets, their bosses may talk work items, or change requests.  Which is why we try and write features which deal in both currencies, like Locate Change Set.


As you see in the above screenshot, Locate Change Set allows users to work with either change sets or work items in order to ensure that people can answer questions using the terms and currencies they are most comfortable with.

Similarly, when someone compares builds, the comparisons come back in the forms of change sets or work items.  We have numerous features in Rational Team Concert that work like this.  When you allow for users to answer questions using the concepts they are most comfortable with, you create an ease of use that really helps to allow different roles to enjoy using the product.