Wednesday, October 20, 2010

Weird SVN State

Today when I got to work and tried to sync a pile of my projects, I was met with the following exception (and a cute dialog telling me the same thing, but without as many red X's):

org.eclipse.team.svn.core.connector.SVNConnectorException: svn: '/home/mrennie/workspaces/workspace/CommandLineDebugger' is not a working copy
svn: Cannot read from '/home/mrennie/workspaces/workspace/CommandLineDebugger/.svn/format': /home/mrennie/workspaces/workspace/CommandLineDebugger/.svn/format (No such file or directory)
at org.polarion.team.svn.connector.svnkit.SVNKitConnector.handleClientException(SVNKitConnector.java:1400)
at org.polarion.team.svn.connector.svnkit.SVNKitConnector.status(SVNKitConnector.java:337)
at org.eclipse.team.svn.core.extension.factory.ThreadNameModifier.status(ThreadNameModifier.java:608)
at org.eclipse.team.svn.core.operation.local.RemoteStatusOperation$2.run(RemoteStatusOperation.java:147)
at org.eclipse.team.svn.core.utility.ProgressMonitorUtility.doSubTask(ProgressMonitorUtility.java:118)
at org.eclipse.team.svn.core.operation.AbstractActionOperation.protectStep(AbstractActionOperation.java:154)
at org.eclipse.team.svn.core.operation.AbstractActionOperation.protectStep(AbstractActionOperation.java:149)
at org.eclipse.team.svn.core.operation.local.RemoteStatusOperation.runImpl(RemoteStatusOperation.java:145)
at org.eclipse.team.svn.core.operation.AbstractActionOperation.run(AbstractActionOperation.java:81)
at org.eclipse.team.svn.core.utility.ProgressMonitorUtility.doTask(ProgressMonitorUtility.java:104)
at org.eclipse.team.svn.core.operation.CompositeOperation.runImpl(CompositeOperation.java:95)
at org.eclipse.team.svn.core.operation.AbstractActionOperation.run(AbstractActionOperation.java:81)
at org.eclipse.team.svn.core.operation.LoggedOperation.run(LoggedOperation.java:39)
at org.eclipse.team.svn.core.utility.ProgressMonitorUtility.doTask(ProgressMonitorUtility.java:104)
at org.eclipse.team.svn.core.utility.ProgressMonitorUtility.doTaskExternal(ProgressMonitorUtility.java:90)
at org.eclipse.team.svn.core.synchronize.AbstractSVNSubscriber.findChanges(AbstractSVNSubscriber.java:314)
at org.eclipse.team.svn.core.synchronize.AbstractSVNSubscriber$UpdateStatusOperation$2.run(AbstractSVNSubscriber.java:349)
at org.eclipse.team.svn.core.utility.ProgressMonitorUtility.doSubTask(ProgressMonitorUtility.java:118)
at org.eclipse.team.svn.core.operation.AbstractActionOperation.protectStep(AbstractActionOperation.java:154)
at org.eclipse.team.svn.core.operation.AbstractActionOperation.protectStep(AbstractActionOperation.java:149)
at org.eclipse.team.svn.core.synchronize.AbstractSVNSubscriber$UpdateStatusOperation.runImpl(AbstractSVNSubscriber.java:347)
at org.eclipse.team.svn.core.operation.AbstractActionOperation.run(AbstractActionOperation.java:81)
at org.eclipse.team.svn.core.operation.LoggedOperation.run(LoggedOperation.java:39)
at org.eclipse.team.svn.core.utility.ProgressMonitorUtility.doTask(ProgressMonitorUtility.java:104)
at org.eclipse.team.svn.core.utility.ProgressMonitorUtility.doTaskExternal(ProgressMonitorUtility.java:90)
at org.eclipse.team.svn.core.utility.ProgressMonitorUtility.doTaskExternal(ProgressMonitorUtility.java:81)
at org.eclipse.team.svn.core.synchronize.AbstractSVNSubscriber.refresh(AbstractSVNSubscriber.java:186)
at org.eclipse.team.svn.core.synchronize.UpdateSubscriber.refresh(UpdateSubscriber.java:73)
at org.eclipse.team.core.subscribers.Subscriber.refresh(Subscriber.java:466)
at org.eclipse.team.core.subscribers.SubscriberMergeContext.refresh(SubscriberMergeContext.java:85)
at org.eclipse.team.core.mapping.provider.SynchronizationContext.refresh(SynchronizationContext.java:109)
at org.eclipse.team.internal.ui.synchronize.RefreshModelParticipantJob.doRefresh(RefreshModelParticipantJob.java:69)
at org.eclipse.team.internal.ui.synchronize.RefreshParticipantJob.run(RefreshParticipantJob.java:309)
at org.eclipse.team.internal.ui.synchronize.RefreshModelParticipantJob.run(RefreshModelParticipantJob.java:117)
at org.eclipse.core.internal.jobs.Worker.run(Worker.java:54)
Caused by: org.tigris.subversion.javahl.ClientException: svn: '/home/mrennie/workspaces/workspace/CommandLineDebugger' is not a working copy
svn: Cannot read from '/home/mrennie/workspaces/workspace/CommandLineDebugger/.svn/format': /home/mrennie/workspaces/workspace/CommandLineDebugger/.svn/format (No such file or directory)
at org.tigris.subversion.javahl.JavaHLObjectFactory.throwException(JavaHLObjectFactory.java:724)
at org.tmatesoft.svn.core.javahl.SVNClientImpl.throwException(SVNClientImpl.java:1929)
at org.tmatesoft.svn.core.javahl.SVNClientImpl.status(SVNClientImpl.java:304)
at org.tmatesoft.svn.core.javahl.SVNClientImpl.status(SVNClientImpl.java:282)
at org.polarion.team.svn.connector.svnkit.SVNKitConnector.status(SVNKitConnector.java:334)
... 33 more
Caused by: org.tmatesoft.svn.core.SVNException: svn: '/home/mrennie/workspaces/workspace/CommandLineDebugger' is not a working copy
svn: Cannot read from '/home/mrennie/workspaces/workspace/CommandLineDebugger/.svn/format': /home/mrennie/workspaces/workspace/CommandLineDebugger/.svn/format (No such file or directory)
at org.tmatesoft.svn.core.internal.wc.SVNErrorManager.error(SVNErrorManager.java:64)
at org.tmatesoft.svn.core.internal.wc.admin.SVNAdminAreaFactory.open(SVNAdminAreaFactory.java:149)
at org.tmatesoft.svn.core.internal.wc.admin.SVNWCAccess.doOpen(SVNWCAccess.java:355)
at org.tmatesoft.svn.core.internal.wc.admin.SVNWCAccess.open(SVNWCAccess.java:263)
at org.tmatesoft.svn.core.internal.wc.admin.SVNWCAccess.open(SVNWCAccess.java:256)
at org.tmatesoft.svn.core.internal.wc.admin.SVNWCAccess.openAnchor(SVNWCAccess.java:151)
at org.tmatesoft.svn.core.wc.SVNStatusClient.doStatus(SVNStatusClient.java:320)
at org.tmatesoft.svn.core.javahl.SVNClientImpl.status(SVNClientImpl.java:300)
... 35 more

After swearing for a bit and asking Google what I should do (and having no luck) I tried deleting suspicious looking files from the /.svn folder located in each affected project. The winner - at least for me - was to delete the /.svn/tmp folder and all of its contents and then restart Eclipse. After that all is well and I can sync to my hearts content.

I filed a bug for this state problem here:
https://bugs.eclipse.org/bugs/show_bug.cgi?id=328258

Wednesday, September 15, 2010

How p2 based targets work

Software Site locations in Target Definitions, typically described as "p2 based targets" are targets that get their bundles from an update site or p2 repository. This article will go over some of the implementation details of these targets. Knowing how the bundles are downloaded and added to the target can help to reproduce bugs and find workarounds.

For more general information on Target Platforms, see my previous article. The Eclipse help doc also explains a lot about how to create p2 based targets and add content to them.

The Basics:

Target definitions are created using the preference page or the editor. To create a p2 based target, at least one 'software site' location must be added to the target. The actual site location is abstracted from PDE. A local zipped repo, a remote site or a local profile will all be treated the same. A software site location specifies a site (or a category such as "all available sites") as well as one or more Root IUs. The root IUs describe what is being downloaded from the site, they are often high level features that effectively group a collection of bundles.

Target definitions must be resolved to modify the bundle list on the content tab or to set one as the active target platform. The resolve operation runs for each location independently. For most locations the resolve simply scans the location to get a list of file locations for bundles. In the case of a software site location, a more complex operation must be run.

Resolving Software Sites:

For each software site location, the following steps are taken:

  1. Load the repositories. This will create a queryable repository object. p2 will often request a repo's contents.xml file.
  2. Get the root IUs. If the location didn't already have actual installable units for the root units, the root IUs will be obtained from the site.
  3. Setup the planner or slicer. More on this later.
  4. Create a profile.
  5. Run the operation. Downloads and installs the units into the profile.
  6. Collect bundle locations for the target platform.
Note: In 3.7 a new performance enhancement was added that will skip the above steps and instead attempt to get a list of bundles from the stored profile. If the profile doesn't contain all the expected bundles or a problem occurs, the operation reverts to following the above steps.

Important Locations:

The following directories describe where PDE/p2 stores information related to the target resolution. Those familiar with p2 can modify the contents of the directories to force things to be recreated or to use the contents for a special purpose.

Target Definition Files:
/.metadata/.plugins/org.eclipse.pde.core/.local_targets
Where PDE stores the targets it creates from the preference page.

Profile Location:
/p2/org.eclipse.equinox.p2.engine/profileRegistry
Where profiles are created and persisted

Bundle Pool:
/.metadata/.plugins/org.eclipse.pde.core/.bundle_pool
Where p2 will download the bundles to during the operation

Planning vs Slicing

Once we have one or more sites and root IUs, we run a provisioning operation to download the required bundles and install them into a profile. The operation can be done using a slicer, which is typically used for mirroring a site or a planner, which is used by Eclipse to safely install and update itself.

Which one to use is determined by the options at the bottom of the wizard when editing a software site location. If "Include required software" is checked the planner is used. If unchecked the slicer is used. The include all environments setting determines if environment properties are set on the slicer.

The planner behaves the same as though we were installing the root IUs into an application. Therefore it checks that the complete set of required IUs are available to be downloaded and installed. If any IU is missing, the planner will report an error saying that a requirement is missing. This can be convenient as you may not realize some important piece is missing from your target. However, the target does not need to be a complete, runnable install, so forcibly requiring everything may be optimal.

The slicer uses an operation that copies IUs from a remote site to a local location. The slicer does create a list of required IUs, however it does not fail if the requirements are missing. Instead it will download all requirements it can from the site or sites that have been provided. This is a lot more flexible than the planner as all available IUs (even IUs that don't apply to the current environment settings) will be downloaded.

Conclusion:

After the resolve operation is complete, a list of bundles will be returned (pointing to the local copies in the bundle pool). PDE will use the local bundles as the target.

What is a Target Platform

The current Target Platform in PDE is very important to anyone developing bundles in Eclipse. Whether you are developing SDK Plug-ins, an RCP product or a OSGi application, managing the contents of your target platform is important.

So what is a target platform?

At its core, a target platform is a collection of plug-ins (aka bundles) that PDE can use to compile against, launch with, lookup in
formation in and more. When developing a bundle it is almost guaranteed that you will depend on other bundles. While you can have the complete required set of bundles in your workspace, it clutters the navigator views and degrades performance. The target platform provides an easy way to manage the bundles you build against.

The target platform is used for the following in PDE:
  1. Compile - Plug-ins in the workspace are built against the target platform so you do not have to have everything in your workspace
  2. Launch - When using PDE's launchers you can choose the set of plug-ins you want to launch. By default the Eclipse Application Launcher will start with all plug-ins in the target, but will use workspace plug-ins instead when available
  3. Calculate Dependencies - PDE assists you in finding the plug-ins your plug-ins was include/require to compile correctly by looking at what is available in the target platform

Where do I edit the target platform?

The target platform is managed on the PDE > Target Platform preference page. When you go to that page (3.5 and later) you will see a list of all the target definitions you have available with the current target platform bolded. PDE only has a single active target platform that all bundles in the workspace use (this might change someday).



However, you can have multiple target definitions. A target definition describes the contents of a target. You can select any target definition as the target platform and that is what PDE will build against. For users who only build one product, you only need to create and modify a single definition, but users who develop different applications (or different versions of the same application) in the same workspace will find that having multiple target definitions makes it easy to switch modes.

How do I create a target?

To get started, go to the preference page and hit add to create a new target. There are some options to create targets from existing templates, but for now select Nothing and hit next.

There are many options when setting up a target, but only a few are needed for basic setups. The first step is to give the target definition a name so we can recognize it later.



The important parts of a target definition is its locations and its content. The locations define where the target should find bundles, the content defines which bundles from the location to take.

On the locations tab you can add 4 types of locations. A directory will just collect any bundles found in the directory you point it to. An installation will treat the location as an Eclipse application. Rather than just looking in a directory, the installation location will consider link folders, a platform.xml if the app uses update manager, or a bundles.info file if the app uses p2 (simple configurator). A feature location will add a single feature and its included bundles to the target. Finally, a software site location will allow bundles to be retrieved from a local or remote update site or p2 repository.

The content tab is only important if you need to limit the bundles in the target. For plug-in developers this step is unecessary, but for RCP developers it can be more important. This article explains the reasoning. The content tab will list all the bundles in the target, along with check boxes to remove them. The tab also provides a number of ways to filter the list so you can quickly remove certain types.



One internal detail that target platform users may want to know is that when bundles are unchecked, the remaining list of bundles is stored as an include list, independant of the locations. This was a change from the <3.5 style="font-style: italic;">share
button on the preference page. You can also create a new target definition file in the workspace using File > New. The target files can be added to a version control system and shared among team members.

What other features use targets?

The Target Platform State View can be used to see what is in your target.
Add new content to your target on the fly.
You can export the contents of your target platform.
Manage your target contents using features.
Add the target platform to the java search path.

What is in the future for targets?

In 3.7 there have been multiple improvements around software site (p2) based targets, including improved resolution performance and better offline support. PDE's API Tooling features already leverage some of the target code, but hopefully in the near future there will be even better integration.

Expect another blog post soon explaining more about how p2 targets work.

Thursday, May 13, 2010

"Add new expression" inline in Expressions View


The debugger expressions view has a new feature: the ability to add a new expression without opening a dialog. When user clicks on "Add new expression" entry, a cell editor is activated to enter the new expression.

I hope most people will appreciate this little convenience but since introducing it few months ago I got one complaint and a request to make it optional. What do you think? Is it worth adding yet another preference to try to make everyone happy?