/*
* .NET tools :: Commons
* Copyright (C) 2010 Jose Chillan, Alexandre Victoor and SonarSource
* dev@sonar.codehaus.org
*
* This program 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 (at your option) any later version.
*
* This program 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
*/
/*
* Created on Apr 16, 2009
*/
package org.sonar.dotnet.tools.commons.visualstudio;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Set;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* A visual studio solution model.
*
* @author Fabrice BELLINGARD
* @author Jose CHILLAN Apr 16, 2009
*/
public class VisualStudioSolution {
private static final Logger LOG = LoggerFactory.getLogger(VisualStudioSolution.class);
private File solutionFile;
private File solutionDir;
private String name;
private List<VisualStudioProject> projects;
private List<String> buildConfigurations;
public VisualStudioSolution(File solutionFile, List<VisualStudioProject> projects) {
this.solutionFile = solutionFile;
this.solutionDir = solutionFile.getParentFile();
this.projects = projects;
initializeFileAssociations();
removeAssemblyNameDuplicates();
}
/**
* Remove some projects
*
* @param skippedProjects
* List of the excluded projects, using ',' as delimiter
*/
public void filterProjects(String skippedProjects) {
if (StringUtils.isEmpty(skippedProjects)) {
return;
}
Set<String> skippedProjectSet = new HashSet<String>();
skippedProjectSet.addAll(Arrays.asList(StringUtils.split(skippedProjects, ',')));
ListIterator<VisualStudioProject> projectIterator = projects.listIterator();
while (projectIterator.hasNext()) {
VisualStudioProject visualStudioProject = projectIterator.next();
if (skippedProjectSet.contains(visualStudioProject.getName())) {
projectIterator.remove();
}
}
}
/**
* Override default locations for the assemblies generated by the solution
*
* @param assemblyDirectories
* A map where keys are project names and values path to the generated assemblies?
*/
public void overrideAssemblyDirectories(Map<String, String> assemblyDirectories) {
if (assemblyDirectories == null) {
return;
}
Map<String, VisualStudioProject> projectMap = new HashMap<String, VisualStudioProject>();
for (VisualStudioProject project : projects) {
projectMap.put(project.getName(), project);
}
for (Map.Entry<String, String> entry : assemblyDirectories.entrySet()) {
VisualStudioProject project = projectMap.get(entry.getKey());
if (project == null) {
LOG.error("Unknown project name '" + entry.getKey() + "' used in assembly directories settings");
} else {
project.setForcedOutputDir(entry.getValue());
}
}
}
private void removeAssemblyNameDuplicates() {
Map<String, VisualStudioProject> projectMap = new HashMap<String, VisualStudioProject>();
for (VisualStudioProject project : projects) {
String assemblyName = project.getAssemblyName();
if (projectMap.containsKey(assemblyName)) {
int i = 1;
String newAssemblyName;
do {
i++;
newAssemblyName = assemblyName + "_" + i;
} while (projectMap.containsKey(newAssemblyName));
project.setAssemblyName(newAssemblyName);
projectMap.put(newAssemblyName, project);
} else {
projectMap.put(assemblyName, project);
}
}
}
/**
* Clean-up file/project associations in order to avoid having the same file in several projects.
*/
private void initializeFileAssociations() {
Set<File> csFiles = new HashSet<File>();
for (VisualStudioProject project : projects) {
Set<File> projectFiles = project.getSourceFileMap().keySet();
Set<File> projectFilesToRemove = new HashSet<File>();
for (File file : projectFiles) {
if (getProjectByLocation(file) == null) {
projectFilesToRemove.add(file);
}
}
// remove files not present in the project directory
projectFiles.removeAll(projectFilesToRemove);
// remove files present in other projects
projectFiles.removeAll(csFiles);
csFiles.addAll(projectFiles);
}
}
/**
* Gets the project a cs file belongs to.
*
* @param file
* @return the project contains the file, or <code>null</code> if none is matching
*/
public VisualStudioProject getProject(File file) {
for (VisualStudioProject project : projects) {
if (project.contains(file)) {
return project;
}
}
return null;
}
/**
* Gets the project whose base directory contains the file/directory.
*
* @param file
* the file to look for
* @return the associated project, or <code>null</code> if none is matching
*/
public final VisualStudioProject getProjectByLocation(File file) {
String canonicalPath;
try {
canonicalPath = file.getCanonicalPath();
for (VisualStudioProject project : projects) {
File directory = project.getDirectory();
String projectFolderPath = directory.getPath();
if (canonicalPath.startsWith(projectFolderPath) && project.isParentDirectoryOf(file)) {
return project;
}
}
} catch (IOException e) {
LOG.debug("getProjectByLocation i/o exception", e);
}
return null;
}
/**
* Returns the solutionFile.
*
* @return The solutionFile to return.
*/
public File getSolutionFile() {
return this.solutionFile;
}
/**
* Returns the solutionDir.
*
* @return The solutionDir to return.
*/
public File getSolutionDir() {
return this.solutionDir;
}
/**
* Gets a project by its assembly name.
*
* @param assemblyName
* the name of the assembly
* @return the project, or <code>null</code> if not found
*/
public VisualStudioProject getProject(String assemblyName) {
VisualStudioProject result = null;
for (VisualStudioProject project : projects) {
if (assemblyName.equalsIgnoreCase(project.getAssemblyName())) {
result = project;
break;
}
}
if (result == null) {
// perhaps a web project
for (VisualStudioProject project : projects) {
if (project instanceof VisualStudioWebProject) {
VisualStudioWebProject webProject = (VisualStudioWebProject) project;
if (webProject.getWebAssemblyNames().contains(assemblyName)) {
result = project;
break;
}
}
}
}
return result;
}
/**
* Returns the projects.
*
* @return The projects to return.
*/
public List<VisualStudioProject> getProjects() {
return this.projects;
}
/**
* Returns the test projects.
*
* @return The projects to return.
*/
public List<VisualStudioProject> getTestProjects() {
List<VisualStudioProject> result = new ArrayList<VisualStudioProject>();
for (VisualStudioProject visualStudioProject : projects) {
if (visualStudioProject.isTest()) {
result.add(visualStudioProject);
}
}
return result;
}
/**
* Iterate through all the projects of the solution seeking for silverlight applications
*
* @return true if a silverlight application is found
*/
public boolean isSilverlightUsed() {
final Iterator<VisualStudioProject> projectIterator = projects.iterator();
boolean silverlightFound = false;
while (projectIterator.hasNext() && !silverlightFound) {
silverlightFound = projectIterator.next().isSilverlightProject();
}
return silverlightFound;
}
/**
* Iterate through all the projects of the solution seeking for asp.net applications
*
* @return true if an asp.net project is found
*/
public boolean isAspUsed() {
final Iterator<VisualStudioProject> projectIterator = projects.iterator();
boolean aspFound = false;
while (projectIterator.hasNext() && !aspFound) {
aspFound = projectIterator.next().isWebProject();
}
return aspFound;
}
/**
* Returns the name.
*
* @return The name to return.
*/
public String getName() {
return this.name;
}
/**
* Sets the name.
*
* @param name
* The name to set.
*/
void setName(String name) {
this.name = name;
}
List<String> getBuildConfigurations() {
return buildConfigurations;
}
void setBuildConfigurations(List<String> buildConfigurations) {
this.buildConfigurations = buildConfigurations;
}
@Override
public String toString() {
return "Solution(path=" + solutionFile + ")";
}
}