package jetbrains.mps.build.mps.util; /*Generated by MPS */ import jetbrains.mps.build.util.RelativePathHelper; import jetbrains.mps.baseLanguage.tuples.runtime.Tuples; import org.jetbrains.mps.openapi.model.SNode; import jetbrains.mps.build.behavior.BuildProject__BehaviorDescriptor; import jetbrains.mps.build.util.Context; import java.util.List; import jetbrains.mps.internal.collections.runtime.ListSequence; import java.util.ArrayList; import jetbrains.mps.internal.collections.runtime.Sequence; import jetbrains.mps.lang.smodel.generator.smodelAdapter.SNodeOperations; import jetbrains.mps.lang.smodel.generator.smodelAdapter.SLinkOperations; import jetbrains.mps.smodel.adapter.structure.MetaAdapterFactory; import jetbrains.mps.internal.collections.runtime.IVisitor; import jetbrains.mps.build.behavior.BuildFolderMacro__BehaviorDescriptor; import jetbrains.mps.baseLanguage.tuples.runtime.MultiTuple; import jetbrains.mps.internal.collections.runtime.ISelector; import jetbrains.mps.lang.smodel.generator.smodelAdapter.SPropertyOperations; import java.io.File; import java.io.IOException; public class PathConverter { private final RelativePathHelper workingDirectory; private final Iterable<Tuples._2<String, SNode>> macros; private final Iterable<SNode> macrosWithoutPath; public PathConverter(SNode project) { String workingDir = BuildProject__BehaviorDescriptor.getBasePath_id4jjtc7WZOyG.invoke(project, Context.defaultContext()); this.workingDirectory = new RelativePathHelper(workingDir); final List<Tuples._2<String, SNode>> result = ListSequence.fromList(new ArrayList<Tuples._2<String, SNode>>()); final List<SNode> withoutPath = ListSequence.fromList(new ArrayList<SNode>()); Sequence.fromIterable(SNodeOperations.ofConcept(SLinkOperations.getChildren(project, MetaAdapterFactory.getContainmentLink(0x798100da4f0a421aL, 0xb99171f8c50ce5d2L, 0x4df58c6f18f84a13L, 0x4df58c6f18f84a22L, "macros")), MetaAdapterFactory.getConcept(0x798100da4f0a421aL, 0xb99171f8c50ce5d2L, 0x668c6cfbafadd002L, "jetbrains.mps.build.structure.BuildFolderMacro"))).visitAll(new IVisitor<SNode>() { public void visit(SNode it) { String path = normalizePath(BuildFolderMacro__BehaviorDescriptor.evaluate_id4jjtc7WZOzA.invoke(it, Context.defaultContext()), true); if (path != null && path.length() > 1) { ListSequence.fromList(result).addElement(MultiTuple.<String,SNode>from(path, it)); } else { ListSequence.fromList(withoutPath).addElement(it); } } }); macros = ListSequence.fromList(result).sort(new ISelector<Tuples._2<String, SNode>, Integer>() { public Integer select(Tuples._2<String, SNode> it) { return it._0().length() * 2; } }, false); macrosWithoutPath = withoutPath; } public String getWorkingDir() { return workingDirectory.getBasePath(); } /** * Produce a path node using supplied path factory/builder to instatiate them * * @return never null */ public List<SNode> convertPath(String path, PathBuilder pathBuilder) throws PathConverter.PathConvertException { path = normalizePath(path, false); String withSlash = normalizePath(path, true); List<SNode> result = new ArrayList<SNode>(); final boolean startsWithMacroPrefix = path.startsWith("$"); for (Tuples._2<String, SNode> m : Sequence.fromIterable(macros)) { String mdir = (startsWithMacroPrefix ? "${" + SPropertyOperations.getString(m._1(), MetaAdapterFactory.getProperty(0xceab519525ea4f22L, 0x9b92103b95ca8c0cL, 0x110396eaaa4L, 0x110396ec041L, "name")) + "}/" : m._0()); // XXX what's the check path.length < mdir.length supposed to do? If the path is shorter // than macro path, it would never match? String currPath = (path.length() < mdir.length() ? withSlash : path); if (currPath.startsWith(mdir)) { currPath = currPath.substring(mdir.length()); ListSequence.fromList(result).addElement(pathBuilder.buildRelative(m._1(), currPath)); } } if (workingDirectory.isRelative(withSlash)) { try { ListSequence.fromList(result).addElement(pathBuilder.buildRelative(workingDirectory.makeRelative(withSlash))); } catch (RelativePathHelper.PathException ex) { throw new PathConverter.PathConvertException(ex.toString()); } } if (startsWithMacroPrefix) { for (SNode m : Sequence.fromIterable(macrosWithoutPath)) { String mdir = "${" + SPropertyOperations.getString(m, MetaAdapterFactory.getProperty(0xceab519525ea4f22L, 0x9b92103b95ca8c0cL, 0x110396eaaa4L, 0x110396ec041L, "name")) + "}/"; String currPath = (path.length() < mdir.length() ? withSlash : path); if (currPath.startsWith(mdir)) { currPath = currPath.substring(mdir.length()); ListSequence.fromList(result).addElement(pathBuilder.buildRelative(m, currPath)); } } } if (ListSequence.fromList(result).isEmpty()) { throw new PathConverter.PathConvertException(String.format("source path (%s) should be under working directory (%s), or any macros default directory", path, workingDirectory.getBasePath())); } return result; } private static String normalizePath(String path, boolean addSlash) { // FIXME much similar to RelativePathHelper.normalize, except that this one resorts to full path when there's no macro variable (which is generally not the case // provided PathConverter is used to populate build project from module descriptor (where BP macros are not available) if (path == null || (path == null || path.length() == 0)) { return null; } try { path = (path.startsWith("${") ? path : new File(path).getCanonicalPath()); path = path.replace("\\", "/"); } catch (IOException ignore) { // ignore } if (addSlash && !(path.endsWith("/"))) { path = path + "/"; } return path; } public static class PathConvertException extends Exception { public PathConvertException(String message) { super(message); } } }