blob: 06978c521438973a988ced12e2fde3d18ebd8ccc [file] [log] [blame]
/*
*
* 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;
}
}