Monday, August 07, 2006

Groovy Monkey: Eclipse Icons Script in Groovy Monkey Pt 2/4

In my previous post I began work on writing a script to checkout all the available icon files from the Eclipse Platform project as a test and demonstration of Groovy Monkey. I would like to continue on and begin demonstrating how you can rewrite some of that code to be reused as a Groovy Monkey library script or as a DOM plugin prototype. I would like to but after reading the original article that inspired me again, I realized I have a little more work to do. I need to remove all the CVS cruft from the workspace and then package the whole thing up as a zip file that could be published to a website.

Now before I dive into the subject, I would like to take a moment to point out a feature of Groovy Monkey that was inherited from Eclipse Monkey. In my previous posting I have a number of versions of the "Get Eclipse Icons" script and I have been working on this script from more than one location. It is easy in Groovy Monkey to grab scripts and to dump them into your workspace. Select the text of the script beginning with:


--- Came wiffling through the eclipsey wood ---


And ending with:


--- And burbled as it ran! ---


Copy into the clipboard and then go over to your Eclipse workbench and select "Groovy Monkey > Paste New Script". The script should be dumped into your workspace into the GroovyMonkeyExamples or Groovy Monkey Scripts project under the monkey folder. You can directly invoke it from the Groovy Monkey menu or can proceed to edit it.

Now back to the job at hand. We could just delete the CVS folders and files and then have Eclipse update the workspace, but there is a command in Eclipse that will disconnect a project from CVS and so why not try and use it?

I know there is a Disconnect popup menu command from the Package Explorer view and so I know to begin looking through the plugin.xml files of Eclipse plugins I suspect. From the previous work on this script I suspect the org.eclipse.team.cvs plugins, so lets start there. Since the command I would like to automate has a graphical component, I start with the org.eclipse.team.cvs.ui plugin. Since I know that Eclipse likes to use plugin/bundle.properties to put the names of UI commands in, I start there. Sure enough "UnmanageFolder.label=&Disconnect..." seems to be what I am looking for. In the plugin.xml this maps to the class org.eclipse.team.internal.ccvs.ui.actions.UnmanageAction. Lets start there.

In the UnmanageAction class, it seems as though all it does is do some configuration , then query the user to see if they are sure they wish to disconnect the project and then use the DisconnectOperation class to actually do the work. So it looks as though all we must do is to instanciate the DisconnectOperation and then invoke run, lets go for it.

One note, if you have already run the script and checked out the icons, it would probably be better to split this off into another script so as to avoid having to recheckout everything.


--- Came wiffling through the eclipsey wood ---
/*
* Menu: Get Eclipse Icons
* Kudos: ervinja
* License: EPL 1.0
* DOM: http://groovy-monkey.sourceforge.net/update/plugins/net.sf.groovyMonkey.dom
* Include-Bundle: org.eclipse.team.cvs.core
* Include-Bundle: org.eclipse.team.cvs.ui
*/
import org.eclipse.core.resources.IProject
import org.eclipse.core.runtime.SubProgressMonitor
import org.eclipse.team.internal.ccvs.core.CVSProviderPlugin
import org.eclipse.team.internal.ccvs.core.ICVSRemoteFolder
import org.eclipse.team.internal.ccvs.ui.operations.CheckoutIntoOperation
import org.eclipse.team.internal.ccvs.ui.operations.DisconnectOperation

def plugin = CVSProviderPlugin.getPlugin()
def repositoryLoc
for( location in plugin.getKnownRepositories() )
{
if( monitor.isCanceled() )
return
if( location.getRootDirectory() == '/home/eclipse' )
repositoryLoc = location
}

def targetProject = workspace.getRoot().getProject( 'GroovyMonkeyExamples' )
def members = repositoryLoc.members( null, false, null )
monitor.beginTask( '', 2 * members.size() )
def iconFolders = []
for( member in members )
{
member.fetchChildren()
if( monitor.isCanceled() )
return
if( !member.childExists( 'icons' ) )
{
monitor.worked( 1 )
continue
}
def icons = member.getFolder( 'icons' )
iconFolders.add( icons )
monitor.worked( 1 )
}
iconFolders.each
{ folder ->
if( monitor.isCanceled() )
return
def targetFolder = targetProject.getFolder( 'icons' ).getFolder( folder.getRemoteParent().getRepositoryRelativePath() )
new CheckoutIntoOperation( null, folder, targetFolder, true ).execute( new SubProgressMonitor( monitor, 1 ) )
monitor.worked( 1 )
}
jface.syncExec
{
new DisconnectOperation( null, [ targetProject ].toArray( new IProject[0] ), true ).run()
}
monitor.done()
--- And burbled as it ran! ---


Now we have a script that checks out icons and then removes CVS cruft. So that just leaves us with the need to package it up as a zip. I don't know of any Eclipse code in particular to support this so I am going to use the Groovy Ant scripting support to do this quickly. Afterwords I am going to have the script tell the workspace to refresh itself.


--- Came wiffling through the eclipsey wood ---
/*
* Menu: Get Eclipse Icons
* Kudos: ervinja
* License: EPL 1.0
* DOM: http://groovy-monkey.sourceforge.net/update/plugins/net.sf.groovyMonkey.dom
* Include-Bundle: org.eclipse.team.cvs.core
* Include-Bundle: org.eclipse.team.cvs.ui
*/
import org.eclipse.core.resources.IProject
import org.eclipse.core.resources.IResource
import org.eclipse.core.runtime.SubProgressMonitor
import org.eclipse.team.internal.ccvs.core.CVSProviderPlugin
import org.eclipse.team.internal.ccvs.core.ICVSRemoteFolder
import org.eclipse.team.internal.ccvs.ui.operations.CheckoutIntoOperation
import org.eclipse.team.internal.ccvs.ui.operations.DisconnectOperation

def plugin = CVSProviderPlugin.getPlugin()
def repositoryLoc
for( location in plugin.getKnownRepositories() )
{
if( monitor.isCanceled() )
return
if( location.getRootDirectory() == '/home/eclipse' )
repositoryLoc = location
}

def targetProject = workspace.getRoot().getProject( 'GroovyMonkeyExamples' )
def members = repositoryLoc.members( null, false, null )
monitor.beginTask( '', 2 * members.size() )
def iconFolders = []
for( member in members )
{
member.fetchChildren()
if( monitor.isCanceled() )
return
if( !member.childExists( 'icons' ) )
{
monitor.worked( 1 )
continue
}
def icons = member.getFolder( 'icons' )
iconFolders.add( icons )
monitor.worked( 1 )
}
iconFolders.each
{ folder ->
if( monitor.isCanceled() )
return
def targetFolder = targetProject.getFolder( 'icons' ).getFolder( folder.getRemoteParent().getRepositoryRelativePath() )
new CheckoutIntoOperation( null, folder, targetFolder, true ).execute( new SubProgressMonitor( monitor, 1 ) )
monitor.worked( 1 )
}
jface.syncExec
{
new DisconnectOperation( null, [ targetProject ].toArray( new IProject[0] ), true ).run()
}

def baseDir = targetProject.getFolder( 'icons' )
def destFile = targetProject.getFile( 'eclipse-icons.zip' )
if( destFile.exists() )
destFile.delete( true, null )

def ant = new AntBuilder()
ant.zip( basedir:"${baseDir.getRawLocation()}", destfile:"${destFile.getRawLocation()}" )

targetProject.refreshLocal( IResource.DEPTH_INFINITE, null )

monitor.done()
--- And burbled as it ran! ---


Now we have a script that accomplishes the entirety of the original script. Now to some of you this script is probably pretty good and you would use it as written. Now me, with my ADD and lazy mind, does not like it. I would like to be able to reuse some of this code in other scripts and quite frankly it is too complex and ugly. So my next couple of blog entries are going to deal with this issue. First we are going to rewrite the script so that it can invoke other Groovy Monkey scripts and create reuse that way and second we are going to start work on doing a DOM plugin prototype that I think you will find more dynamic and fun that doing straight Eclipse plugin work. So hopefully you will stick around for them.

No comments: