package org.fandev.module.pod; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.module.Module; import com.intellij.openapi.projectRoots.Sdk; import com.intellij.openapi.util.Pair; import com.intellij.openapi.vfs.VirtualFile; import org.fandev.sdk.FanSdkType; import org.fandev.utils.FanUtil; import org.fandev.utils.VirtualFileUtil; import java.lang.reflect.Method; import java.net.URLClassLoader; import java.util.LinkedList; /** * @author Dror Bereznitsky * @date Feb 23, 2009 11:47:00 PM */ public class PodFileParser { private static final String DEPENDENCIES_FIELD = "depends"; private static final String VERSION_FIELD = "version"; private static final String DEPENDENCIES_DIR_FIELD = "dependsDir"; private static final String DESCRIPTION_FIELD = "summary"; private static final String SRC_DIRS_FIELD = "srcDirs"; private static final String RES_DIRS_FIELD = "resDirs"; private static final String INDEXES_FIELD = "index"; private static final String METAS_FIELD = "meta"; private static final String OUT_DIR_FIELD = "outDir"; private static final String DOC_API_FIELD = "docApi"; private static final String DOC_SRC_FIELD = "docSrc"; private static final String POD_NAME_FIELD = "podName"; private static final Logger logger = Logger.getInstance("org.fandev.module.pod.PodFileParser"); public static PodModel parse(final VirtualFile buildScript, final Module module) { return parse(buildScript, FanUtil.getSdk(module)); } public static PodModel parse(final VirtualFile buildScript, final Sdk sdk) { if (buildScript == null) { logger.warn("Invalid build script"); return null; } if (sdk == null || !sdk.getSdkType().equals(FanSdkType.getInstance())) { logger.warn("Module has no Fantom sdk"); return null; } FanUtil.setFanHome(sdk); URLClassLoader cl = FanUtil.getSysClassloader(sdk.getHomePath()); try { final Class envClass = Class.forName("fan.sys.Env", true, cl); final Class versionClass = Class.forName("fan.sys.Version", true, cl); final Class typeClass = Class.forName("fan.sys.Type", true, cl); final Class fieldClass = Class.forName("fan.sys.Field", true, cl); final Class uriClass = Class.forName("fan.sys.Uri", true, cl); final Class listClass = Class.forName("fan.sys.List", true, cl); final Class fileClass = Class.forName("fan.sys.File", true, cl); final Class mapClass = Class.forName("fan.sys.Map", true, cl); final PodModel model = new PodModel(); model.setBuildScriptFile(buildScript); FanUtil.setFanHome(sdk); final Object uri = uriClass.getDeclaredMethod("fromStr", String.class).invoke(null, VirtualFileUtil.constructLocalUrl(buildScript.getPath())); final Object file = fileClass.getDeclaredMethod("make", uriClass).invoke(null, uri); final Object envClassInstance = envClass.getDeclaredMethod("cur").invoke(null); final Method fieldMethod = typeClass.getDeclaredMethod("field", String.class); final Method getMethod = fieldClass.getDeclaredMethod("get", Object.class); final Method getAtMethod = listClass.getDeclaredMethod("get", long.class); final Method sizeMethod = listClass.getDeclaredMethod("size"); final Method uriToStrMethod = uriClass.getDeclaredMethod("toStr"); final Method mapKeysMethod = mapClass.getDeclaredMethod("keys"); final Method mapGetKeyMethod = mapClass.getDeclaredMethod("get", Object.class); final Object buildScriptType = envClass.getDeclaredMethod("compileScript", fileClass).invoke(envClassInstance, file); if (buildScriptType == null) { logger.warn("Unable to compile script file: " + buildScript.getPath() + " could not synchronize module state."); return null; } final Object buildClassInstance = typeClass.getDeclaredMethod("make").invoke(buildScriptType); // fan.sys.Type // pod name Object field = fieldMethod.invoke(buildScriptType, POD_NAME_FIELD); String s = (String) getMethod.invoke(field, buildClassInstance); s = s != null ? s : ""; model.setName(s); // description field = fieldMethod.invoke(buildScriptType, DESCRIPTION_FIELD); s = (String) getMethod.invoke(field, buildClassInstance); s = s != null ? s : ""; model.setDescription(s); // version field = fieldMethod.invoke(buildScriptType, VERSION_FIELD); Object o = getMethod.invoke(field, buildClassInstance); s = ""; if (null != o) { s = (String) versionClass.getDeclaredMethod("toStr").invoke(o); } model.setVersion(s); // outDir field = fieldMethod.invoke(buildScriptType, OUT_DIR_FIELD); o = getMethod.invoke(field, buildClassInstance); if (o != null) { model.setOutDir((String)uriToStrMethod.invoke(o)); } else { model.setOutDir(null); } // docApi field = fieldMethod.invoke(buildScriptType, DOC_API_FIELD); Boolean b = (Boolean) getMethod.invoke(field, buildClassInstance); model.setDocApi(b == null ? false : b); // docSrc field = fieldMethod.invoke(buildScriptType, DOC_SRC_FIELD); b = (Boolean) getMethod.invoke(field, buildClassInstance); model.setDocSrc(b == null ? false : b); // dependencies dir field = fieldMethod.invoke(buildScriptType, DEPENDENCIES_DIR_FIELD); final Object dependsDir = fieldClass.getDeclaredMethod("get", Object.class).invoke(field, buildClassInstance); // fan.sys.Uri VirtualFile dependsDirFile; if (dependsDir != null) { String dependsDirPath = (String) uriClass.getDeclaredMethod("toStr").invoke(dependsDir); dependsDirFile = VirtualFileUtil.findFileByLocalPath(dependsDirPath); } else { String dependsDirPath = sdk.getHomePath() + VirtualFileUtil.VFS_PATH_SEPARATOR + FanSdkType.getFanLibDir(); dependsDirFile = VirtualFileUtil.findFileByLocalPath(dependsDirPath); } final String fanLibPath = dependsDirFile.getPath(); // dependencies field = fieldMethod.invoke(buildScriptType, DEPENDENCIES_FIELD); o = getMethod.invoke(field, buildClassInstance); if (o != null) { final Long size = (Long)sizeMethod.invoke(o); for (int i = 0; i < size; i++) { s = (String) getAtMethod.invoke(o, i); if (s != null) { model.addDependency(s); } } } else { model.setDependencies(new LinkedList<String>()); } // source dirs field = fieldMethod.invoke(buildScriptType, SRC_DIRS_FIELD); o = getMethod.invoke(field, buildClassInstance); if (o != null) { final Long size = (Long)sizeMethod.invoke(o); for (int i = 0; i < size; i++) { Object srcDir = getAtMethod.invoke(o, i); s = (String) uriToStrMethod.invoke(srcDir); Pair<String,String> p = new Pair<String,String>(s, s); model.addSrcDir(p); } } else { model.setSrcDirs(new LinkedList<Pair<String,String>>()); } // res dirs field = fieldMethod.invoke(buildScriptType, RES_DIRS_FIELD); o = getMethod.invoke(field, buildClassInstance); if (o != null) { final Long size = (Long)sizeMethod.invoke(o); for (int i = 0; i < size; i++) { Object resDir = getAtMethod.invoke(o, i); s = (String) uriToStrMethod.invoke(resDir); Pair<String,String> p = new Pair<String,String>(s, s); model.addResDir(p); } } else { model.setResDirs(new LinkedList<Pair<String,String>>()); } // indexes field = fieldMethod.invoke(buildScriptType, INDEXES_FIELD); o = getMethod.invoke(field, buildClassInstance); if (o != null) { Object keys = mapKeysMethod.invoke(o); final Long size = (Long)sizeMethod.invoke(keys); for (int i = 0; i < size; i++) { final String key = (String) getAtMethod.invoke(keys, i); final String val = (String) mapGetKeyMethod.invoke(o, key); model.addIndex(new Pair<String,String>(key,val)); } } else { model.setIndexes(new LinkedList<Pair<String,String>>()); } // metas field = fieldMethod.invoke(buildScriptType, METAS_FIELD); o = getMethod.invoke(field, buildClassInstance); if (o != null) { Object keys = mapKeysMethod.invoke(o); final Long size = (Long)sizeMethod.invoke(keys); for (int i = 0; i < size; i++) { final String key = (String) getAtMethod.invoke(keys, i); final String val = (String) mapGetKeyMethod.invoke(o, key); model.addMeta(new Pair<String,String>(key,val)); } } else { model.setMetas(new LinkedList<Pair<String,String>>()); } return model; } catch (Exception e) { logger.warn("Failed to parse build script metadata", e); return null; } finally { cl = null; } } }