/** * Copyright (C) 2008-2010, Squale Project - http://www.squale.org * * This file is part of Squale. * * Squale is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation, either version 3 of the * License, or any later version. * * Squale is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with Squale. If not, see <http://www.gnu.org/licenses/>. */ package org.squale.squalix.tools.mccabe; import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; import java.util.Collection; import java.util.HashSet; import java.util.Iterator; import java.util.List; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.squale.squalecommon.enterpriselayer.businessobject.component.parameters.ListParameterBO; import org.squale.squalecommon.enterpriselayer.businessobject.component.parameters.MapParameterBO; import org.squale.squalecommon.enterpriselayer.businessobject.component.parameters.ParametersConstants; import org.squale.squalecommon.enterpriselayer.businessobject.component.parameters.StringParameterBO; import org.squale.squalix.core.TaskData; import org.squale.squalix.core.TaskException; import org.squale.squalix.core.exception.ConfigurationException; import org.squale.squalix.util.buildpath.BuildProjectPath; import org.squale.squalix.util.csv.CSVParser; import org.squale.squalix.util.file.FileUtility; import org.squale.squalix.util.parser.CppParser; import org.squale.squalix.util.process.ProcessManager; /** * T�che McCabe pour les projets C++ Cette t�che n�cessite des ajustements pour l'analyse du code C++. Les fichiers * source doivent �tre pr�process�s pour g�n�rer des fichiers .i. Un fichier myheader.dat doit �tre cr�� pour y * r�f�rencer l'ensemble des fichiers d'include � prendre en compte */ public class CppMcCabeTask extends OOMcCabeTask implements CSVParser.CSVHandler { /** * Logger */ private static final Log LOGGER = LogFactory.getLog( AbstractMcCabeTask.class ); /** * Constructeur */ public CppMcCabeTask() { mName = "CppMcCabeTask"; } /** * {@inheritDoc} On doit utiliser un parser C++ * * @see org.squale.squalix.tools.mccabe.AbstractMcCabeTask#setParser() */ public void setParser() { mParser = new CppParser( mProject ); } /** * {@inheritDoc} * * @see org.squale.squalix.tools.mccabe.AbstractMcCabeTask#setClassTemplate() */ public void setClassTemplate() { mClassTemplate = "csv.template.class"; } /** * {@inheritDoc} * * @see org.squale.squalix.core.Task#execute() */ public void execute() throws TaskException { // On passe la phase de compilation avant de lancer // McCabe doCompilation(); super.execute(); } /** * Cette m�thode r�alise la compilation d'un projet C++. * * @throws TaskException exception lors de la compilation. */ protected void doCompilation() throws TaskException { try { /* si le fichier de script est conforme */ File scriptFile = getCompilationScriptFile(); if ( !scriptFile.exists() ) { /* on lance une exception */ throw new Exception( McCabeMessages.getString( "cpp.exception.task.scriptfile_not_found", scriptFile.toString() ) ); } LOGGER.info( McCabeMessages.getString( "logs.cpp.compile", scriptFile.getAbsolutePath() ) ); String viewPath = (String) getData().getData( TaskData.VIEW_PATH ); /* Lancement du process */ ProcessManager mgr = new ProcessManager( new String[] { scriptFile.getAbsolutePath(), viewPath }, null, scriptFile.getParentFile() ); mgr.setOutputHandler( this ); int result = mgr.startProcess( this ); /* si le process se termine correctement */ if ( 0 != result ) { throw new TaskException( McCabeMessages.getString( "cpp.logs.task.not_compiled" ) ); } } catch ( Exception e ) { throw new TaskException( e ); } } /** * Obtention du nom du script de compilation * * @return script de compilation * @throws ConfigurationException si erreur */ private File getCompilationScriptFile() throws ConfigurationException { File result; // On prend la valeur stock�e dans le projet MapParameterBO cppParams = (MapParameterBO) mProject.getParameter( ParametersConstants.CPP ); if ( cppParams == null ) { // Renvoi d'une exception de configuration throw new ConfigurationException( McCabeMessages.getString( "cpp.exception.variable.not_found", ParametersConstants.CPP ) ); } else { StringParameterBO cppScript = (StringParameterBO) cppParams.getParameters().get( ParametersConstants.CPP_SCRIPTFILE ); // Renvoi d'une exception de configuration if ( cppScript == null ) { // Renvoi d'une exception de configuration throw new ConfigurationException( McCabeMessages.getString( "cpp.exception.variable.not_found", ParametersConstants.CPP_SCRIPTFILE ) ); } else { File scriptFile = new File( cppScript.getValue() ); // Si le script a un nom absolue et existe, on prend celui-ci if ( scriptFile.isAbsolute() && scriptFile.exists() ) { result = scriptFile; } else { // Le script est suppos� �tre relatif � la vue String viewPath = (String) getData().getData( TaskData.VIEW_PATH ); if ( viewPath == null ) { // Renvoi d'une exception de configuration throw new ConfigurationException( McCabeMessages.getString( "cpp.exception.variable.not_found", TaskData.VIEW_PATH ) ); } result = new File( viewPath, scriptFile.getPath() ); } } } return result; } /** * {@inheritDoc} * * @see org.squale.squalix.tools.mccabe.AbstractMcCabeTask#createProjectConfigurationFile(org.squale.squalix.tools.mccabe.McCabePCFFile) */ protected void createProjectConfigurationFile( McCabePCFFile pFile ) throws Exception { // Cr�ation du fichier super.createProjectConfigurationFile( pFile ); // Cr�ation du fichier avec les headers � prendre en compte File headerFile = new File( pFile.getPcfFile().getParentFile(), "myheader.dat" ); LOGGER.info( McCabeMessages.getString( "logs.cpp.header", headerFile ) ); Collection headerFiles = getHeaderFiles(); BufferedWriter buf = new BufferedWriter( new FileWriter( headerFile ) ); Iterator it = headerFiles.iterator(); while ( it.hasNext() ) { buf.write( (String) it.next() ); buf.newLine(); } buf.close(); } /** * Obtention des fichiers headers * * @return liste des fichiers header */ protected Collection getHeaderFiles() { // Construction de la liste des fichiers .h non exclus // On parcourt chaque r�pertoire source sous la vue avec // l'extension requise File root = new File( (String) getData().getData( TaskData.VIEW_PATH ) ); List srcs = ( (ListParameterBO) getProject().getParameters().getParameters().get( ParametersConstants.SOURCES ) ).getParameters(); List paths = BuildProjectPath.buildProjectPath( (String) getData().getData( TaskData.VIEW_PATH ), srcs ); HashSet filesList = new HashSet(); // Parcours de chaque r�pertoire source for ( int i = 0; i < paths.size(); i++ ) { McCabeFileFilter filter = new McCabeFileFilter( root.getAbsolutePath(), mConfiguration.getEntetes() ); HashSet fileList = new HashSet(); File pDirectory = new File( (String) paths.get( i ) ); FileUtility.createRecursiveListOfFiles( pDirectory, filter, fileList ); Iterator it = fileList.iterator(); String filename = null; int rootLength = root.getAbsolutePath().length() + File.separator.length(); // On ne retient que le nom du fichier while ( it.hasNext() ) { filename = new File( (String) it.next() ).getName(); filesList.add( filename ); } } return filesList; } /** * {@inheritDoc} * * @see org.squale.squalix.tools.mccabe.AbstractMcCabeTask#createReport(java.lang.String) */ protected void createReport( String pReport ) throws Exception { // G�n�ration du rapport super.createReport( pReport ); // Dans le cas d'un rapport de type classe // on va lire ce rapport pour extraire les noms de classe if ( pReport.startsWith( McCabeMessages.getString( "reports.profile.class" ) ) ) { String fileName = computeReportFileName( pReport ); LOGGER.info( McCabeMessages.getString( "logs.cpp.class.preprocess", fileName ) ); // Lecture du contenu de ce fichier pour en extraire les noms de // classes et les stocker dans le CppParser CSVParser parser = new CSVParser( McCabeMessages.getString( "csv.config.file" ) ); parser.parseLines( McCabeMessages.getString( mClassTemplate ), fileName, this ); } } /** * {@inheritDoc} * * @see org.squale.squalix.util.csv.CSVParser.CSVHandler#processLine(java.util.ArrayList) */ public void processLine( List pLine ) { ( (CppParser) mParser ).addKnownClass( (String) pLine.get( 0 ) ); } }