| /* |
| * |
| * 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; |
| } |
| } |