001package org.apache.archiva.common.utils; 002 003/* 004 * Licensed to the Apache Software Foundation (ASF) under one 005 * or more contributor license agreements. See the NOTICE file 006 * distributed with this work for additional information 007 * regarding copyright ownership. The ASF licenses this file 008 * to you under the Apache License, Version 2.0 (the 009 * "License"); you may not use this file except in compliance 010 * with the License. You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, 015 * software distributed under the License is distributed on an 016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 017 * KIND, either express or implied. See the License for the 018 * specific language governing permissions and limitations 019 * under the License. 020 */ 021 022import org.apache.commons.lang.StringUtils; 023 024import java.util.regex.Matcher; 025import java.util.regex.Pattern; 026 027/** 028 * Version utility methods. 029 */ 030public class VersionUtil 031{ 032 /** 033 * These are the version patterns found in the filenames of the various artifact's versions IDs. 034 * These patterns are all tackling lowercase version IDs. 035 */ 036 private static final String versionPatterns[] = 037 new String[]{ "([0-9][_.0-9a-z]*)", "(snapshot)", "(g?[_.0-9ab]*(pre|rc|g|m)[_.0-9]*)", "(dev[_.0-9]*)", 038 "(alpha[_.0-9]*)", "(beta[_.0-9]*)", "(rc[_.0-9]*)", 039// "(test[_.0-9]*)", -- omitted for MRM-681, can be reinstated as part of MRM-712 040 "(debug[_.0-9]*)", "(unofficial[_.0-9]*)", "(current)", "(latest)", "(fcs)", "(release[_.0-9]*)", 041 "(nightly)", "(final)", "(incubating)", "(incubator)", "([ab][_.0-9]+)" }; 042 043 public static final String SNAPSHOT = "SNAPSHOT"; 044 045 public static final Pattern UNIQUE_SNAPSHOT_PATTERN = Pattern.compile( "^(.*)-([0-9]{8}\\.[0-9]{6})-([0-9]+)$" ); 046 047 public static final Pattern TIMESTAMP_PATTERN = Pattern.compile( "^([0-9]{8})\\.([0-9]{6})$" ); 048 049 public static final Pattern GENERIC_SNAPSHOT_PATTERN = Pattern.compile( "^(.*)-" + SNAPSHOT ); 050 051 private static final Pattern VERSION_MEGA_PATTERN = 052 Pattern.compile( StringUtils.join( versionPatterns, '|' ), Pattern.CASE_INSENSITIVE ); 053 054 /** 055 * <p> 056 * Tests if the unknown string contains elements that identify it as a version string (or not). 057 * </p> 058 * 059 * <p> 060 * The algorithm tests each part of the string that is delimited by a '-' (dash) character. 061 * If 75% or more of the sections are identified as 'version' strings, the result is 062 * determined to be of a high probability to be version identifier string. 063 * </p> 064 * 065 * @param unknown the unknown string to test. 066 * @return true if the unknown string is likely a version string. 067 */ 068 public static boolean isVersion( String unknown ) 069 { 070 String versionParts[] = StringUtils.split( unknown, '-' ); 071 072 Matcher mat; 073 074 int countValidParts = 0; 075 076 for ( int i = 0; i < versionParts.length; i++ ) 077 { 078 String part = versionParts[i]; 079 mat = VERSION_MEGA_PATTERN.matcher( part ); 080 081 if ( mat.matches() ) 082 { 083 if ( i == 0 ) // loosen rule to return true if first token matches 084 { 085 return true; 086 } 087 countValidParts++; 088 } 089 } 090 091 /* Calculate version probability as true if 3/4's of the input string has pieces of 092 * of known version identifier strings. 093 */ 094 int threshold = (int) Math.floor( Math.max( (double) 1.0, (double) ( versionParts.length * 0.75 ) ) ); 095 096 return ( countValidParts >= threshold ); 097 } 098 099 /** 100 * <p> 101 * Tests if the identifier is a known simple version keyword. 102 * </p> 103 * 104 * <p> 105 * This method is different from {@link #isVersion(String)} in that it tests the whole input string in 106 * one go as a simple identifier. (eg "alpha", "1.0", "beta", "debug", "latest", "rc#", etc...) 107 * </p> 108 * 109 * @param identifier the identifier to test. 110 * @return true if the unknown string is likely a version string. 111 */ 112 public static boolean isSimpleVersionKeyword( String identifier ) 113 { 114 Matcher mat = VERSION_MEGA_PATTERN.matcher( identifier ); 115 116 return mat.matches(); 117 } 118 119 public static boolean isSnapshot( String version ) 120 { 121 Matcher m = UNIQUE_SNAPSHOT_PATTERN.matcher( version ); 122 if ( m.matches() ) 123 { 124 return true; 125 } 126 else 127 { 128 return isGenericSnapshot( version ); 129 } 130 } 131 132 public static String getBaseVersion( String version ) 133 { 134 Matcher m = UNIQUE_SNAPSHOT_PATTERN.matcher( version ); 135 if ( m.matches() ) 136 { 137 return m.group( 1 ) + "-" + SNAPSHOT; 138 } 139 else 140 { 141 return version; 142 } 143 } 144 145 /** 146 * <p> 147 * Get the release version of the snapshot version. 148 * </p> 149 * 150 * <p> 151 * If snapshot version is 1.0-SNAPSHOT, then release version would be 1.0 152 * And if snapshot version is 1.0-20070113.163208-1.jar, then release version would still be 1.0 153 * </p> 154 * 155 * @param snapshotVersion snapshot version 156 * @return release version 157 */ 158 public static String getReleaseVersion( String snapshotVersion ) 159 { 160 Matcher m = UNIQUE_SNAPSHOT_PATTERN.matcher( snapshotVersion ); 161 162 if ( isGenericSnapshot( snapshotVersion ) ) 163 { 164 m = GENERIC_SNAPSHOT_PATTERN.matcher( snapshotVersion ); 165 } 166 167 if ( m.matches() ) 168 { 169 return m.group( 1 ); 170 } 171 else 172 { 173 return snapshotVersion; 174 } 175 } 176 177 public static boolean isUniqueSnapshot( String version ) 178 { 179 Matcher m = UNIQUE_SNAPSHOT_PATTERN.matcher( version ); 180 return m.matches(); 181 } 182 183 public static boolean isGenericSnapshot( String version ) 184 { 185 return version.endsWith( SNAPSHOT ); 186 } 187 188 public static String getVersionFromGenericSnapshot( String version ) 189 { 190 Matcher m = GENERIC_SNAPSHOT_PATTERN.matcher( version ); 191 if ( m.matches() ) 192 { 193 return m.group( 1 ); 194 } 195 return version; 196 } 197}