/* * Copyright 2000-2018 JetBrains s.r.o. * * 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 jetbrains.buildServer.buildTriggers.vcs.clearcase; import java.io.File; import java.util.ArrayList; import java.util.List; import java.util.Stack; import java.util.regex.Pattern; import jetbrains.buildServer.serverSide.TeamCityProperties; import jetbrains.buildServer.util.StringUtil; import jetbrains.buildServer.vcs.VcsException; import jetbrains.buildServer.vcs.clearcase.Constants; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; public class CCPathElement { public static final String MAIN = "main"; private static final Pattern PLATFORM_SEPARATOR_REGEXP = Pattern.compile(File.separatorChar == '\\' ? "\\\\" : String.valueOf(File.separatorChar)); private final String myPathElement; private String myVersion; private boolean myIsFromViewPath = false; public CCPathElement(final String pathElement, final boolean hasVersion) { myPathElement = pathElement; myVersion = hasVersion ? CCParseUtil.CC_VERSION_SEPARATOR : null; } private void appendVersion(final String version) { if (myVersion == null) { myVersion = CCParseUtil.CC_VERSION_SEPARATOR; } myVersion += File.separator + version; } public String getPathElement() { return myPathElement; } public String getVersion() { return myVersion; } public void setVersion(@Nullable final String objectVersion) { if (objectVersion == null) { myVersion = null; } else if (objectVersion.startsWith(CCParseUtil.CC_VERSION_SEPARATOR)) { myVersion = objectVersion; } else { myVersion = CCParseUtil.CC_VERSION_SEPARATOR + objectVersion; } } public boolean isIsFromViewPath() { return myIsFromViewPath; } public static boolean isInsideView(final String objectName, final String viewPath) { final List pathElements = splitIntoPathElements(objectName); final List viewPathElements = createViewPathElementList(viewPath, pathElements); if (viewPathElements.size() > pathElements.size()) { return false; } for (int i = 0; i < viewPathElements.size(); i++) { if (!viewPathElements.get(i).equals(pathElements.get(i).getPathElement())) { return false; } } return true; } private static List createViewPathElementList(final String viewPath, final List pathElements) { final List viewPathElements = StringUtil.split(viewPath, false, File.separatorChar); if (pathElements.size() > 0 && pathElements.get(0).getPathElement().length() == 0) { if (viewPathElements.size() > 0) { viewPathElements.set(0, ""); } } return viewPathElements; } public static List splitIntoPathAntVersions(final String objectName, final String viewPath, final int skipAtBeginCount) { List result = splitIntoPathElements(objectName); setInViewAttributes(result, viewPath, skipAtBeginCount); return result; } public static List splitIntoPathElements(final String objectName) { final List result = new ArrayList(); boolean hadVersionSeparator = false; boolean treatMainAsVersionId = !TeamCityProperties.getBoolean(Constants.TEAMCITY_PROPERTY_DO_NOT_TREAT_MAIN_AS_VERSION_IDENTIFIER); final List subNames = StringUtil.split(normalizeSeparators(objectName), false, File.separatorChar); for (int i = 0, size = subNames.size(); i < size; i++) { final String subName = subNames.get(i); if (subName.endsWith(CCParseUtil.CC_VERSION_SEPARATOR)) { final CCPathElement currentPair = new CCPathElement(subName.substring(0, subName.length() - CCParseUtil.CC_VERSION_SEPARATOR.length()), true); result.add(currentPair); i = processVersion(currentPair, i, subNames); hadVersionSeparator = true; } else if (hadVersionSeparator && treatMainAsVersionId && i + 1 < size && MAIN.equalsIgnoreCase(subNames.get(i + 1))) { final CCPathElement currentPair = new CCPathElement(subName, true); result.add(currentPair); i = processVersion(currentPair, i, subNames); } else { result.add(new CCPathElement(subName, false)); } } return removeDots(result); } private static int processVersion(final CCPathElement currentPair, int i, final List subNames) { for (i += 1; i < subNames.size(); i++) { currentPair.appendVersion(subNames.get(i)); try { Integer.parseInt(subNames.get(i)); break; } catch (final NumberFormatException ignore) {} } return i; } private static List removeDots(final List result) { int i = 1; while (i < result.size()) { final CCPathElement curElement = result.get(i); if (curElement.getPathElement().equals(".")) { final CCPathElement prevElement = result.get(i - 1); prevElement.setVersion(chooseVersion(prevElement.getVersion(), curElement.getVersion())); result.remove(i); } else i++; } return result; } private static String chooseVersion(final String version1, final String version2) { return version1 == null ? version2 : version1; } private static void setInViewAttributes(List pathElements, String viewPath, int skipAtBeginCount) { final List viewPathElements = createViewPathElementList(viewPath, pathElements); for (int i = 0; i < skipAtBeginCount; i++) { if (viewPathElements.isEmpty()) break; viewPathElements.remove(viewPathElements.size() - 1); } for (CCPathElement pathElement : pathElements) { String currentViewPath = null; if (viewPathElements.size() > 0) { currentViewPath = viewPathElements.remove(0); } pathElement.setCorrespondingViewElement(currentViewPath); } } private void setCorrespondingViewElement(final String currentViewPath) { myIsFromViewPath = myPathElement.equals(currentViewPath); } public static String createPath(final List ccPathElements) { return createPath(ccPathElements, true); } public static String createPath(final List ccPathElements, final boolean appentVersion) { return createPath(ccPathElements, ccPathElements.size(), appentVersion); } public static String createPath(final List ccPathElements, final int length, final boolean appentVersion) { return createPath(ccPathElements, 0, length, appentVersion); } public static String createPath(final List ccPathElements, final int startIndex, final int endIndex, final boolean appentVersion) { StringBuffer result = new StringBuffer(); boolean first = true; for (int i = startIndex; i < endIndex; i++) { final CCPathElement element = ccPathElements.get(i); try { if (!first) { result.append(File.separatorChar); } } finally { first = false; } result.append(element.getPathElement()); if (appentVersion && element.getVersion() != null) { result.append(element.getVersion()); } } return result.toString(); } private static void appendNameToBuffer(final StringBuffer result, final String subName) { result.append(File.separatorChar); result.append(subName); } public static String createRelativePathWithVersions(final List pathElementList) { StringBuffer result = new StringBuffer(); for (CCPathElement pathElement : pathElementList) { if (!pathElement.isIsFromViewPath()) { if (pathElement.getVersion() == null) { appendNameToBuffer(result, pathElement.getPathElement()); } else { appendNameToBuffer(result, pathElement.getPathElement() + pathElement.getVersion()); } } } return removeFirstSeparatorIfNeeded(result.toString()); } public static String removeFirstSeparatorIfNeeded(final CharSequence s) { return String.valueOf(s.length() > 0 ? s.subSequence(1, s.length()) : ""); } public static String createPathWithoutVersions(final List pathElementList) { StringBuffer result = new StringBuffer(); for (CCPathElement pathElement : pathElementList) { appendNameToBuffer(result, pathElement.getPathElement()); } return removeFirstSeparatorIfNeeded(result.toString()); } public static String replaceLastVersionAndReturnFullPathWithVersions(final String parentDirFullPath, final String viewName, final String version) { final List pathElements = splitIntoPathAntVersions(parentDirFullPath, viewName, 0); pathElements.get(pathElements.size() - 1).setVersion(version); return createPath(pathElements); } public static String normalizeFileName(final String fullFileName) throws VcsException { final String[] dirs = PLATFORM_SEPARATOR_REGEXP.split(fullFileName); Stack stack = new Stack(); for (String dir : dirs) { if (".".equals(dir)) continue; if ("..".equals(dir)) { if (stack.isEmpty()) { throw new VcsException("Invalid parent links balance: \"" + fullFileName + "\""); } stack.pop(); } else { stack.push(dir); } } StringBuilder sb = new StringBuilder(""); for (String dir : stack) { sb.append(File.separator).append(dir); } return removeFirstSeparatorIfNeeded(sb); } @NotNull private static String removeLastSeparatorIfNeeded(@NotNull final String path) { return path.endsWith(File.separator) && path.length() > 1 ? path.substring(0, path.length() - 1) : path; } @NotNull public static String normalizePath(@Nullable final String path) throws VcsException { return normalizeFileName(removeLastSeparatorIfNeeded(normalizeSeparators(getNotNullString(path).trim()))); } @NotNull private static String getNotNullString(@Nullable final String path) { return path == null ? "" : path; } @NotNull public static String normalizeSeparators(@NotNull String path) { return path.replace('/', File.separatorChar).replace('\\', File.separatorChar); } public static boolean areFilesEqual(@NotNull final File file1, @NotNull final File file2) throws VcsException { return normalizePath(file1.getAbsolutePath()).equals(normalizePath(file2.getAbsolutePath())); } public static String removeUnneededDots(final String fullPath) { return createPath(splitIntoPathElements(fullPath)); } @Override public String toString(){ return new StringBuilder().append(getPathElement()).append(getVersion()).toString(); } }