/*
* Copyright 2013-2016 Sergey Ignatov, Alexander Zolotov, Florin Patan
*
* Licensed 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 com.goide.util;
import com.goide.GoConstants;
import com.goide.psi.GoFile;
import com.goide.sdk.GoSdkUtil;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiFile;
import com.intellij.util.ThreeState;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.regex.Pattern;
/**
* @see "$GOROOT/src/go/build/build.go" and relevant functions
*/
public class GoBuildMatcher {
private static final Pattern WHITESPACES = Pattern.compile("\\s+");
@NotNull private final GoTargetSystem myTarget;
public GoBuildMatcher(@NotNull GoTargetSystem target) {
myTarget = target;
}
public boolean matchFile(@NotNull PsiFile file) {
return matchFile(file, true);
}
/**
* @param checkBuildFlags should be false for directly used files: go run gen.go
*/
private boolean matchFile(@NotNull PsiFile file, boolean checkBuildFlags) {
if (!(file instanceof GoFile)) {
// TODO support .c, .cpp and other
return false;
}
if (((GoFile)file).hasCPathImport() && myTarget.cgoEnabled != ThreeState.YES) return false;
return match(file.getName(), ((GoFile)file).getBuildFlags(), checkBuildFlags);
}
private boolean match(@NotNull String fileName, @Nullable String buildFlags, boolean checkBuildFlags) {
if (!matchFileName(fileName)) return false;
if (!checkBuildFlags || buildFlags == null) return true;
for (String line : StringUtil.split(buildFlags, "|")) {
if (!matchBuildFlagsLine(line)) return false;
}
return true;
}
private boolean matchBuildFlagsLine(@NotNull String line) {
for (String tag : WHITESPACES.split(line)) {
if (matchBuildFlag(tag)) return true;
}
return false;
}
public boolean matchBuildFlag(@NotNull String name) {
if (name.isEmpty()) return false;
if (StringUtil.containsChar(name, ',')) { // comma separated list
for (String tag : StringUtil.split(name, ",")) {
if (!matchBuildFlag(tag)) {
return false;
}
}
return true;
}
// bad syntax, reject always
if (name.startsWith("!!")) return false;
// negation
if (name.startsWith("!")) return !matchBuildFlag(name.substring(1));
if (matchOS(name)) return true;
if (GoConstants.KNOWN_COMPILERS.contains(name)) {
return myTarget.compiler == null || name.equals(myTarget.compiler);
}
if (GoConstants.KNOWN_VERSIONS.contains(name)) {
return myTarget.goVersion == null || GoSdkUtil.compareVersions(myTarget.goVersion, StringUtil.trimStart(name, "go")) >= 0;
}
if ("cgo".equals(name)) {
return myTarget.cgoEnabled == ThreeState.YES;
}
return myTarget.supportsFlag(name);
}
public boolean matchFileName(@NotNull String fileName) {
String name = StringUtil.substringAfter(fileName, "_");
if (StringUtil.isEmpty(name)) {
return true;
}
name = StringUtil.trimEnd(FileUtil.getNameWithoutExtension(name), GoConstants.TEST_SUFFIX);
List<String> parts = StringUtil.split(name, "_");
int n = parts.size();
if (n >= 2 && GoConstants.KNOWN_OS.contains(parts.get(n - 2)) && GoConstants.KNOWN_ARCH.contains(parts.get(n - 1))) {
if (!myTarget.arch.equals(parts.get(n - 1))) {
return false;
}
return matchOS(parts.get(n - 2));
}
if (n >= 1) {
if (GoConstants.KNOWN_OS.contains(parts.get(n - 1))) {
return matchOS(parts.get(n - 1));
}
if (GoConstants.KNOWN_ARCH.contains(parts.get(n - 1))) {
return myTarget.arch.equals(parts.get(n - 1));
}
}
return true;
}
private boolean matchOS(@NotNull String name) {
if (myTarget.os.equals(name) || myTarget.arch.equals(name)) {
return true;
}
return GoConstants.LINUX_OS.equals(name) && GoConstants.ANDROID_OS.equals(myTarget.os);
}
}