001    /*
002            Copyright (c) 2009 Olivier Chafik, All Rights Reserved
003            
004            This file is part of JNAerator (http://jnaerator.googlecode.com/).
005            
006            JNAerator is free software: you can redistribute it and/or modify
007            it under the terms of the GNU General Public License as published by
008            the Free Software Foundation, either version 3 of the License, or
009            (at your option) any later version.
010            
011            JNAerator is distributed in the hope that it will be useful,
012            but WITHOUT ANY WARRANTY; without even the implied warranty of
013            MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
014            GNU General Public License for more details.
015            
016            You should have received a copy of the GNU General Public License
017            along with JNAerator.  If not, see <http://www.gnu.org/licenses/>.
018    */
019    package com.ochafik.admin.visualstudio;
020    
021    import java.io.File;
022    import java.io.FileFilter;
023    import java.util.Collection;
024    import java.util.HashMap;
025    import java.util.HashSet;
026    import java.util.LinkedList;
027    import java.util.Map;
028    import java.util.Set;
029    import java.util.concurrent.Semaphore;
030    import java.util.regex.Matcher;
031    import java.util.regex.Pattern;
032    
033    import com.ochafik.io.ReadText;
034    
035    
036    public class Solution {
037            private static final boolean verbose = true;
038            
039            public File solutionFile;
040            public Map<String, Project> idToProject;
041            public Set<File> allFiles = new HashSet<File>(10000);
042    
043            static Pattern solutionIdPattern = Pattern.compile("Project\\(\"\\{[^}]+\\}\"\\) = \"([^\"]+)\", \"([^\"]+)\", [^{]+\\{([^}]+)\\}\"" +
044                    ".*?ProjectSection\\(ProjectDependencies\\)(.*?)EndProjectSection", Pattern.MULTILINE
045            );
046    
047            static Pattern projectDependencyPattern = Pattern.compile("\\{[^}]+\\} = \\{([^}]+)\\}");
048    
049            static Pattern projectConfigsForSolutionConfigPattern = Pattern.compile("^\\s*\\{([^}]+)\\}\\.([^\\.]+)\\.ActiveCfg\\s*=\\s*(.*)\\s*$");
050            public Solution(File solutionFile) {
051                    this.solutionFile = solutionFile;
052            }
053            public void parse() throws Exception {
054                    if (idToProject == null) {
055                            idToProject = new HashMap<String, Project>();
056                            
057                            String solutionContent = ReadText.readText(solutionFile);
058                            File solutionPath = solutionFile.getParentFile();
059                            
060                            for (Matcher solutionIdMatcher = solutionIdPattern.matcher(solutionContent.replace('\n', ' ')); solutionIdMatcher.find();) {
061                                    Project p = new Project(this, relFile(solutionPath, solutionIdMatcher.group(2)), solutionIdMatcher.group(1), solutionIdMatcher.group(3));
062                                    for (Matcher depM = projectDependencyPattern.matcher(solutionIdMatcher.group(4)); depM.find();)
063                                            p.depsIds.add(depM.group(1));
064                                    idToProject.put(p.id, p);
065                            }
066                            
067                            for (Matcher m = projectConfigsForSolutionConfigPattern.matcher(solutionContent); m.find();) {
068                                    String id = m.group(1), slnConfigName = m.group(2), projConfigName = m.group(3);
069                                    Project p = idToProject.get(id);
070                                    if (p == null)
071                                            continue;
072                                    
073                                    p.activeConfigurationNameBySolutionConfigurationName.put(slnConfigName, projConfigName);
074                            }
075                    }
076            }
077            
078            public String getName() {
079                    return solutionFile == null ? null : solutionFile.getName().replaceAll("\\.[^.]+$", "");
080            }
081            
082            public void parseProjects(final FileFilter fileFilter) throws Exception {
083                    parse();
084                    int nThreads = Runtime.getRuntime().availableProcessors() * 2;
085                    if (verbose)
086                            System.out.println("Parsing Solution: " + solutionFile.getName() + " (" + nThreads + " threads)");
087                    
088                    final Semaphore semaphore = new Semaphore(0);
089                    final LinkedList<Project> projects = new LinkedList<Project>(idToProject.values());
090                    class Worker extends Thread { public void run() {
091                            for (;;) {
092                                    try {
093                                            Project project = null;
094                                            synchronized (projects) {
095                                                    if (projects.isEmpty())
096                                                            break;
097                                                    
098                                                    project = projects.removeLast();
099                                            }
100                                            if (verbose) {
101                                                    synchronized (System.out) {
102                                                            System.out.println("Parsing Project: " + project.name);
103                                                    }
104                                            }
105                                    
106                                            project.parse(fileFilter, false, Solution.this);
107                                            synchronized (allFiles) {
108                                                    allFiles.addAll(project.files);
109                                            }
110                                    } catch (Exception ex) {
111                                            synchronized (System.err) {
112                                                    ex.printStackTrace(System.err);
113                                            }
114                                            
115                                    }
116                            }
117                            semaphore.release();
118                    }};
119                    for (int i = nThreads; i-- != 0;) 
120                            new Worker().start();
121                    
122                    semaphore.acquire(nThreads);
123            }
124            
125            static File relFile(File base, String relPath) {
126                    relPath = relPath.replace('\\', File.separatorChar).replace('/', File.separatorChar);
127                    return new File(base, relPath);
128            }
129            public Collection<Project> getProjects() {
130                    return idToProject.values();
131            }
132    }