/*
* Copyright Red Hat Inc. and/or its affiliates and other contributors
* as indicated by the authors tag. All rights reserved.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU General Public License version 2.
*
* This particular file is subject to the "Classpath" exception as provided in the
* LICENSE file that accompanied this code.
*
* This program is distributed in the hope that it will be useful, but WITHOUT A
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU General Public License for more details.
* You should have received a copy of the GNU General Public License,
* along with this distribution; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*/
package com.redhat.ceylon.ant;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.util.List;
import org.apache.tools.ant.BuildEvent;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.BuildListener;
import org.apache.tools.ant.Project;
import com.redhat.ceylon.launcher.CeylonClassLoader;
import com.redhat.ceylon.launcher.ClassLoaderSetupException;
import com.redhat.ceylon.launcher.Launcher;
import com.redhat.ceylon.launcher.LauncherUtil;
public class Util {
/**
* Name of the project reference in which we cache the class loader
*/
private static final String CEYLON_CLASSLOADER_REFERENCE = "ceylon.classloader";
private static final boolean IS_WINDOWS = System.getProperty("os.name").toLowerCase().indexOf("windows") > -1;
public static String getScriptName(String name) {
if(IS_WINDOWS)
return name + ".bat";
return name;
}
public static String quoteParameter(String param) {
if (IS_WINDOWS) {
return "\"" + param + "\"";
}
return param;
}
/**
* Tries to find the given script either user-specified or detected
*/
public static String findCeylonScript(File defaultValue, Project project) {
String scriptName = getScriptName("ceylon");
if(defaultValue != null){
if(!defaultValue.exists())
throw new BuildException("Failed to find '"+scriptName+"' executable in "+defaultValue.getPath());
if(!defaultValue.canExecute())
throw new BuildException("Cannot execute '"+scriptName+"' executable in "+defaultValue.getPath()+" (not executable)");
return defaultValue.getAbsolutePath();
}
File ceylonHome = null;
try {
ceylonHome = LauncherUtil.determineHome();
} catch (URISyntaxException e) {
throw new BuildException("Failed to determine Ceylon home", e);
}
if(ceylonHome == null)
throw new BuildException("Failed to find Ceylon home, specify the ceylon.home property or set the CEYLON_HOME environment variable");
// now try to find the executable
File script = new File(new File(ceylonHome, "bin"), scriptName);
if(!script.exists())
throw new BuildException("Failed to find '"+scriptName+"' executable in "+ceylonHome);
if(!script.canExecute())
throw new BuildException("Cannot execute '"+scriptName+"' executable in "+ceylonHome+" (not executable)");
return script.getAbsolutePath();
}
// duplicated from /ceylon-common/src/com/redhat/ceylon/common/FileUtil.java because it's not in Ant's classpath :(
public static boolean isChildOfOrEquals(File parent, File child){
// doing a single comparison is likely cheaper than walking up to the root
try {
String parentPath = parent.getCanonicalPath();
String childPath = child.getCanonicalPath();
if(parentPath.equals(childPath))
return true;
// make sure we compare with a separator, otherwise /foo would be considered a parent of /foo-bar
if(!parentPath.endsWith(File.separator))
parentPath += File.separator;
return childPath.startsWith(parentPath);
} catch (IOException e) {
return false;
}
}
public static CeylonClassLoader getCeylonClassLoaderCachedInProject(final Project project) throws ClassLoaderSetupException {
Object classLoader = project.getReference(CEYLON_CLASSLOADER_REFERENCE);
if(classLoader != null){
CeylonClassLoader oldLoader = (CeylonClassLoader) classLoader;
// make sure it's still valid
try{
List<File> classPath = CeylonClassLoader.getClassPath();
if(oldLoader.hasSignature(CeylonClassLoader.getClassPathSignature(classPath))){
// compatible
return oldLoader;
}else{
project.log("Needs a new class loader: cp changed!", Project.MSG_VERBOSE);
CeylonClassLoader loader = CeylonClassLoader.newInstance(classPath);
project.addReference(CEYLON_CLASSLOADER_REFERENCE, loader);
return loader;
}
}catch(FileNotFoundException x){
throw new ClassLoaderSetupException(x);
} catch (URISyntaxException x) {
throw new ClassLoaderSetupException(x);
} catch (MalformedURLException x) {
throw new ClassLoaderSetupException(x);
}
}
CeylonClassLoader loader = Launcher.getClassLoader();
project.addReference(CEYLON_CLASSLOADER_REFERENCE, loader);
// only add the build listed once, even if we change the class loader later
project.addBuildListener(new BuildListener(){
@Override
public void buildFinished(BuildEvent arg0) {
project.log("Build done, cleaning up Ceylon class loader", Project.MSG_VERBOSE);
// make sure we get the latest one
Object reference = project.getReference(CEYLON_CLASSLOADER_REFERENCE);
project.getReferences().remove(CEYLON_CLASSLOADER_REFERENCE);
if(reference instanceof CeylonClassLoader){
((CeylonClassLoader) reference).clearCache();
}
}
@Override
public void buildStarted(BuildEvent arg0) {
}
@Override
public void messageLogged(BuildEvent arg0) {
}
@Override
public void targetFinished(BuildEvent arg0) {
}
@Override
public void targetStarted(BuildEvent arg0) {
}
@Override
public void taskFinished(BuildEvent arg0) {
}
@Override
public void taskStarted(BuildEvent arg0) {
}
});
return loader;
}
}