/* * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package flex2.compiler; import flex2.compiler.io.FileUtil; import flex2.compiler.io.LocalFile; import flex2.compiler.io.VirtualFile; import flex2.compiler.util.CompilerMessage; import flex2.compiler.util.ThreadLocalToolkit; import java.io.File; import java.util.*; /** * A SourceList represents a list of files, following the single * public definition rule, and an associated path where dependencies * can be found. When compiling via mxmlc, the files specified on the * command line are put into the <code>SourceList</code>. When * compiling via Flash Builder, the root or application is included in * the <code>SourceList</code>. * * @author Clement Wong */ public final class SourceList { public SourceList(List<VirtualFile> files, VirtualFile[] classPath, VirtualFile appPath, String[] mimeTypes) throws CompilerException { this(files, classPath, appPath, mimeTypes, true); } public SourceList(List<VirtualFile> files, VirtualFile[] classPath, VirtualFile appPath, String[] mimeTypes, boolean lastIsRoot) throws CompilerException { VirtualFile[] vfiles = new VirtualFile[files.size()]; files.toArray(vfiles); init(vfiles, classPath, appPath, mimeTypes, lastIsRoot); } private void init(VirtualFile[] files, VirtualFile[] classPath, VirtualFile appPath, String[] mimeTypes, boolean lastIsRoot) throws CompilerException { this.mimeTypes = mimeTypes; sources = new LinkedHashMap<String, Source>(files.length); directories = new ArrayList<File>(classPath == null ? 0 : classPath.length); SourcePath.addApplicationParentToSourcePath(appPath, classPath, directories); SourcePath.addPathElements(classPath, directories, true, null); for (int i = 0, length = files.length; i < length; i++) { // No need to check to see if the appPath is supported again. if ((appPath != null && files[i].getName().equals(appPath.getName())) || isSupported(files[i])) { String name = files[i].getName(); VirtualFile pathRoot = calculatePathRoot(files[i]); if (pathRoot != null) { String relativePath = calculateRelativePath(name); String namespaceURI = relativePath.replace('/', '.'); String localPart = calculateLocalPart(name); Source source = new Source(files[i], pathRoot, relativePath, localPart, this, false, (i == length - 1) && lastIsRoot); String className = CompilerAPI.constructClassName(namespaceURI, localPart); sources.put(className, source); } else { // Files in SourceList must be in --source-path. // output an error here... FileNotInSourcePath ex = new FileNotInSourcePath(name); ThreadLocalToolkit.log(ex); throw ex; } } else { UnsupportedFileType ex = new UnsupportedFileType(files[i].getName()); ThreadLocalToolkit.log(ex); throw ex; } } } private VirtualFile calculatePathRoot(VirtualFile f) { return calculatePathRoot(f, directories); } static VirtualFile calculatePathRoot(VirtualFile f, List<File> directories) { String name = f.getName(); if(directories != null) { for (File directory : directories) { String dir = directory.getAbsolutePath(); if (name.startsWith(dir)) { return new LocalFile(FileUtil.openFile(dir)); } } } // return new LocalFile(FileUtil.openFile(f.getParent())); return null; } private String calculateRelativePath(String name) { if(directories != null) { // C: name is canonical. for (File directory : directories) { // Tack on the separatorChar to handle directories, which // are the same as other, just longer. Like "a" and "a1". // See SDK-24084. String dir = directory.getAbsolutePath() + File.separatorChar; if (name.startsWith(dir)) { name = name.substring(dir.length()); int index = name.lastIndexOf(File.separatorChar); if (index != -1) { return name.substring(0, index).replace(File.separatorChar, '/'); } else { return ""; } } } } return ""; } private String calculateLocalPart(String name) { String leafName = name.substring(name.lastIndexOf(File.separatorChar) + 1); String localPart = leafName.substring(0, leafName.lastIndexOf('.')); return localPart; } private Map<String, Source> sources; private List<File> directories; private String[] mimeTypes; public List<Source> retrieveSources() { List<Source> sources = new ArrayList<Source>(this.sources.size()); for (String name : this.sources.keySet()) { Source s = this.sources.get(name); // CompilationUnit u = (s != null) ? s.getCompilationUnit() : null; if (s != null && !s.exists()) { // C: This is a SourceList. If the source doesn't exist, the compiler should get a warning... s = null; } // else if ((u != null && !u.isDone()) || (s != null && s.isUpdated())) // { // s.removeCompilationUnit(); // } // else if (u != null) // { // s = s.copy(); // assert s != null; // } if (s != null) { sources.add(s); } } return sources; } /* public Source findSource(String namespaceURI, String localPart) { if (sources.size() == 0) { return null; } assert localPart.indexOf('.') == -1 && localPart.indexOf('/') == -1 && localPart.indexOf(':') == -1 : "findSource(" + namespaceURI + "," + localPart + ") has bad localPart"; // classname format is a.b:c String className = CompilerAPI.constructClassName(namespaceURI, localPart); Source s = sources.get(className); CompilationUnit u = (s != null) ? s.getCompilationUnit() : null; if (s != null && !s.exists()) { s = null; } // If the compilation unit does exist and the top level definition name doesn't match // the specified class name, we don't count it as a match. if (s != null && u != null && u.topLevelDefinitions.size() == 1) { if (!u.topLevelDefinitions.contains(namespaceURI, localPart)) { String realName = u.topLevelDefinitions.first().toString(); sources.put(realName, s); s = null; u = null; } } if (s != null && ((u != null && !u.isDone()) || s.isUpdated())) { // s.removeCompilationUnit(); } else if (s != null && u != null) { s = s.copy(); assert s != null; } return s; } String[] checkClassNameFileName(Source s) { String defName = null, pathName = null; if (s.getOwner() == this) { QName def = s.getCompilationUnit().topLevelDefinitions.last(); defName = def.getLocalPart(); pathName = s.getShortName(); if (defName.equals(pathName)) { return null; } } return new String[] { pathName, defName }; } String[] checkPackageNameDirectoryName(Source s) { String defPackage = null, pathPackage = null; if (s.getOwner() == this) { QName def = s.getCompilationUnit().topLevelDefinitions.last(); defPackage = NameFormatter.normalizePackageName(def.getNamespace()); pathPackage = NameFormatter.toDot(s.getRelativePath(), '/'); if (defPackage.equals(pathPackage)) { return null; } } return new String[] { pathPackage, defPackage }; } */ private boolean isSupported(VirtualFile file) { for (String mimeType : mimeTypes) { if (mimeType.equals(file.getMimeType())) { return true; } } return false; } public List<File> getPaths() { return directories; } String[] getMimeTypes() { return mimeTypes; } /** * Checks if there is a cached Source for each local Source and if * found, copies it's CompilationUnit into it. public void applyApplicationCache(ApplicationCache applicationCache) { for (Map.Entry<String, Source> entry : sources.entrySet()) { String className = entry.getKey(); Source source = entry.getValue(); Source cachedSource = applicationCache.getSource(className); if ((cachedSource != null) && !cachedSource.isUpdated()) { CompilationUnit cachedCompilationUnit = cachedSource.getCompilationUnit(); if (cachedSource.getPathRoot().equals(source.getPathRoot()) && (cachedCompilationUnit != null) && cachedCompilationUnit.hasTypeInfo) { CompilationUnit compilationUnit = source.newCompilationUnit(cachedCompilationUnit.getSyntaxTree(), new CompilerContext()); Source.copyCompilationUnit(cachedCompilationUnit, compilationUnit, true); source.setFileTime(cachedSource.getFileTime()); cachedSource.reused(); } } } } */ public Map<String, Source> sources() { return sources; } // error messages public static class FileNotInSourcePath extends CompilerMessage.CompilerError { private static final long serialVersionUID = -1516975612657669682L; public FileNotInSourcePath(String name) { super(); this.name = name; } public final String name; } public static class UnsupportedFileType extends CompilerMessage.CompilerError { private static final long serialVersionUID = 5300063184460255877L; public UnsupportedFileType(String name) { super(); this.name = name; } public final String name; } }