Write errors and warnings to an XML log file Merge the XML log files when M2 repos are merged
diff --git a/src/main/groovy/m4e/AbstractCommand.groovy b/src/main/groovy/m4e/AbstractCommand.groovy index d85ef12..21c53a4 100644 --- a/src/main/groovy/m4e/AbstractCommand.groovy +++ b/src/main/groovy/m4e/AbstractCommand.groovy
@@ -12,14 +12,16 @@ package m4e import java.io.File; +import m4e.maven.ErrorLog import org.slf4j.Logger; import org.slf4j.LoggerFactory; -abstract class AbstractCommand { +abstract class AbstractCommand implements CommonConstants { Logger log = LoggerFactory.getLogger( getClass() ) File workDir + ErrorLog errorLog void run( List<String> args ) { run( args as String[] ) @@ -38,7 +40,17 @@ } void destroy() { + if( errorLog ) { + errorLog.close() + } + } + + void prepareErrorLog( File repo, String command ) { + if( errorLog ) { + errorLog.close() + } + errorLog = new ErrorLog( repo: repo, command: command ) } abstract void doRun( String... args ); @@ -46,14 +58,32 @@ int errorCount = 0 int warningCount = 0 - void warn( Warning warning, String msg ) { + void warn( Warning warning, String msg, Map xml = null ) { warningCount ++ log.warn( msg + '\nFor details, see ' + warning.url() ) + + if( errorLog && xml ) { + Map map = new LinkedHashMap() + + map['code'] = warning.code() + map.putAll( xml ) + + errorLog.write().invokeMethod( 'warning', [ map, msg ] ) + } } - void error( Error error, String msg ) { + void error( Error error, String msg, Map xml = null ) { errorCount ++ log.error( msg + '\nFor details, see ' + error.url() ) + + if( errorLog && xml ) { + Map map = new LinkedHashMap() + + map['code'] = error.code() + map.putAll( xml ) + + errorLog.write().invokeMethod( 'error', [ map, msg ] ) + } } void mergeCounters( AbstractCommand other ) {
diff --git a/src/main/groovy/m4e/CommonConstants.java b/src/main/groovy/m4e/CommonConstants.java new file mode 100644 index 0000000..bc175d9 --- /dev/null +++ b/src/main/groovy/m4e/CommonConstants.java
@@ -0,0 +1,13 @@ +package m4e; + +public interface CommonConstants { + + /** Folder name inside of a Maven 2 repository where MT4E will put its files */ + static final String MT4E_FOLDER = ".mt4e"; + + /** File name of the import/export DB in the MT4E folder */ + static final String IMPORT_EXPORT_DB_FILE = "importExportDB"; + + /** UTF-8 encoding/charset */ + static final String UTF_8 = "UTF-8"; +}
diff --git a/src/main/groovy/m4e/Error.java b/src/main/groovy/m4e/Error.java index e7e0c6b..60865f0 100644 --- a/src/main/groovy/m4e/Error.java +++ b/src/main/groovy/m4e/Error.java
@@ -22,7 +22,11 @@ this.id = id; } + public String code() { + return String.format( "E%04d", id ); + } + public String url() { - return Warning.BASE_URL + String.format( "E%04d", id ); + return Warning.BASE_URL + code(); } }
diff --git a/src/main/groovy/m4e/InstallCmd.groovy b/src/main/groovy/m4e/InstallCmd.groovy index 20934c9..5c0f07c 100644 --- a/src/main/groovy/m4e/InstallCmd.groovy +++ b/src/main/groovy/m4e/InstallCmd.groovy
@@ -35,6 +35,15 @@ } log.info( "Import complete. Imported ${statistics.bundleCount} Eclipse bundles into ${statistics.pomCount} POMs. There are ${statistics.jarCount} new JARs of which ${statistics.sourceCount} have sources" ) + + if( m2repos.size() == 1 ) { + log.info( "The new Maven 2 repository is here: ${m2repos[0].absolutePath}" ) + } else { + log.info( "${m2repos.size()} Maven 2 repositories were created:" ) + m2repos.each { + log.info( " ${it.absolutePath}" ) + } + } } List<File> m2repos = [] @@ -188,6 +197,8 @@ m2repo = new File( tmpHome, 'm2repo' ) failure = new File( tmpHome, FAILURE_FILE_NAME ) + installCmd.prepareErrorLog( m2repo, 'install' ) + log.debug( "Importing plug-ins from ${eclipseFolder} into repo ${m2repo}" ) clean() @@ -339,7 +350,9 @@ void unpackNestedJar( String nestedJarPath, File jarFile ) { if( nestedJarPath.contains( ',' ) ) { - installCmd.warn( Warning.MULTIPLE_NESTED_JARS, "Multiple nested JARs are not supported; just copying the original bundle" ) + String msg = "Multiple nested JARs are not supported; just copying the original bundle" + Map xml = [ jar: jarFile.absolutePath, nestedJarPath: nestedJarPath ] + installCmd.warn( Warning.MULTIPLE_NESTED_JARS, msg, xml ) bundle.copy( jarFile ) return } @@ -621,7 +634,8 @@ def entry = archive[ 'META-INF/MANIFEST.MF' ] if( !entry ) { - installCmd.error( Error.MISSING_MANIFEST, "Can't find manifest in ${file.absolutePath}" ) + String msg = "Can't find manifest in ${file.absolutePath}" + installCmd.error( Error.MISSING_MANIFEST, msg, [ jar: file.absolutePath ] ) return null } @@ -696,7 +710,8 @@ Manifest loadManifestFromFile( File file ) { if( !file.exists() ) { - installCmd.error( Error.MISSING_MANIFEST, "Can't find manifest ${file.absolutePath}" ) + String msg = "Can't find manifest ${file.absolutePath}" + installCmd.error( Error.MISSING_MANIFEST, msg, [ jar: file.absolutePath ] ) return null }
diff --git a/src/main/groovy/m4e/MergeCmd.groovy b/src/main/groovy/m4e/MergeCmd.groovy index b33ce4d..2992b9c 100644 --- a/src/main/groovy/m4e/MergeCmd.groovy +++ b/src/main/groovy/m4e/MergeCmd.groovy
@@ -12,6 +12,7 @@ package m4e import java.io.File; +import de.pdark.decentxml.XMLUtils; class MergeCmd extends AbstractCommand { @@ -32,15 +33,44 @@ throw new UserError( "Target repository ${target} already exists. Cowardly refusing to continue." ) } + prepareErrorLog( target, 'merge' ) + + mt4eFolder = new File( target, '.mt4e' ) + log.debug( "Sources: ${sources}" ) log.debug( "Target: ${target}" ) for( source in sources ) { log.info( 'Merging {}', source ) - merge( new File( source ).absoluteFile, target ) + File file = new File( source ).absoluteFile + + merge( file, target ) + } + + closeXmlFiles() + } + + void closeXmlFiles() { + def exc = null + + xmlFiles.values().each { + try { + it << '</merged>\n' + it.close() + } catch( Exception e ) { + if( !exc ) { + exc = e + } + } + } + + if( exc ) { + throw e } } + File mt4eFolder + void merge( File source, File target ) { target.makedirs() @@ -48,6 +78,11 @@ source.eachFile { File srcPath -> File targetPath = new File( target, srcPath.name ) + if( targetPath.equals( mt4eFolder ) ) { + mergeMt4eFiles( srcPath, mt4eFolder ) + return + } + if( srcPath.isDirectory() ) { if( targetPath.exists() && !targetPath.isDirectory() ) { throw new RuntimeException( "${srcPath} is a directory but ${targetPath} is a file" ) @@ -70,6 +105,54 @@ } } + void mergeMt4eFiles( File source, File target ) { + source.eachFile { File srcPath -> + String name = srcPath.name + if( IMPORT_EXPORT_DB_FILE == name ) { + return + } + + File targetPath = new File( target, name ) + + if( srcPath.isDirectory() ) { + mergeMt4eFiles( srcPath, targetPath ) + return + } + + if( name.endsWith( '.xml' ) ) { + mergeXml( srcPath, targetPath ) + } else { + warn( Warning.UNABLE_TO_MERGE_MT4E_FILE, "Unable to merge ${srcPath.absolutePath}", [ file: srcPath.absolutePath ] ) + } + } + } + + Map<String, Writer> xmlFiles = [:] + + void mergeXml( File source, File target ) { + def writer = xmlFiles[ target.name ] + if( !writer ) { + if( target.exists() ) { + warn( Warning.UNABLE_TO_MERGE_MT4E_FILE, "Unable to merge ${source.absolutePath}", [ file: source.absolutePath ] ) + } + + target.parentFile?.makedirs() + + writer = target.newWriter( UTF_8 ) + xmlFiles[ target.name ] = writer + + writer << '<merged>\n' + } + + writer << '<source file="' << XMLUtils.escapeXMLText( source.absolutePath ).replace( '"', '"' ) << '">\n' + + source.withReader( UTF_8 ) { + writer << it + } + + writer << '\n</source>\n' + } + boolean filesAreEqual( File source, File target ) { if( source.size() != target.size() ) { return false
diff --git a/src/main/groovy/m4e/UpdateImportExportDatabaseCmd.groovy b/src/main/groovy/m4e/UpdateImportExportDatabaseCmd.groovy index 6047258..b03633d 100644 --- a/src/main/groovy/m4e/UpdateImportExportDatabaseCmd.groovy +++ b/src/main/groovy/m4e/UpdateImportExportDatabaseCmd.groovy
@@ -24,7 +24,7 @@ public void doRun( String... args ) { File repo = repoOption( args, 1 ) - File dbPath = new File( repo, '.mt4e/importExportDB' ) + File dbPath = new File( repo, MT4E_FOLDER + '/' + IMPORT_EXPORT_DB_FILE ) def db = new ImportExportDB( file: dbPath )
diff --git a/src/main/groovy/m4e/Warning.java b/src/main/groovy/m4e/Warning.java index e63345e..80009d5 100644 --- a/src/main/groovy/m4e/Warning.java +++ b/src/main/groovy/m4e/Warning.java
@@ -15,7 +15,8 @@ MISSING_BINARY_BUNDLE_FOR_SOURCES( 1 ), UNEXPECTED_FILE_IN_SOURCE_BUNDLE( 2 ), BINARY_DIFFERENCE( 3 ), - MULTIPLE_NESTED_JARS( 4 ); + MULTIPLE_NESTED_JARS( 4 ), + UNABLE_TO_MERGE_MT4E_FILE( 5 ); public final static String BASE_URL = "http://wiki.eclipse.org/MT4E_"; @@ -25,7 +26,11 @@ this.id = id; } + public String code() { + return String.format( "W%04d", id ); + } + public String url() { - return BASE_URL + String.format( "W%04d", id ); + return BASE_URL + code(); } }
diff --git a/src/main/groovy/m4e/maven/ErrorLog.groovy b/src/main/groovy/m4e/maven/ErrorLog.groovy new file mode 100644 index 0000000..8a8b985 --- /dev/null +++ b/src/main/groovy/m4e/maven/ErrorLog.groovy
@@ -0,0 +1,36 @@ +package m4e.maven; + +import groovy.xml.MarkupBuilder + +public class ErrorLog { + + File repo + String command + + Writer writer + MarkupBuilder builder + + MarkupBuilder write() { + if( ! builder ) { + File file = new File( repo, ".mt4e/logs/${command}.xml" ) + + file.parentFile?.makedirs() + + writer = file.newWriter( 'UTF-8' ) + builder = new MarkupBuilder( writer ) + + writer.write( "<mt4e-log command='${command}'>\n" ) + } + + return builder + } + + void close() { + if( writer ) { + builder.yield( "\n</mt4e-log>", false ) + + writer.close() + writer = null + } + } +}