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);
}
}
}