1/* valaversionattribute.vala 2 * 3 * Copyright (C) 2013 Florian Brosch 4 * 5 * This library is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU Lesser General Public 7 * License as published by the Free Software Foundation; either 8 * version 2.1 of the License, or (at your option) any later version. 9 * 10 * This library is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 * Lesser General Public License for more details. 14 * 15 * You should have received a copy of the GNU Lesser General Public 16 * License along with this library; if not, write to the Free Software 17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 * 19 * Author: 20 * Florian Brosch <flo.brosch@gmail.com> 21 */ 22 23using GLib; 24 25 26/** 27 * Represents a [Version] attribute 28 */ 29public class Vala.VersionAttribute { 30 private weak Symbol symbol; 31 32 private bool? _deprecated; 33 private bool? _experimental; 34 35 /** 36 * Constructs a new VersionAttribute. 37 * 38 * @param symbol the owner 39 * @return a new VersionAttribute 40 * @see Vala.Symbol 41 */ 42 public VersionAttribute (Symbol symbol) { 43 this.symbol = symbol; 44 } 45 46 47 48 /** 49 * Specifies whether this symbol has been deprecated. 50 */ 51 public bool deprecated { 52 get { 53 if (_deprecated == null) { 54 _deprecated = symbol.get_attribute_bool ("Version", "deprecated", false) 55 || symbol.get_attribute_string ("Version", "deprecated_since") != null 56 || symbol.get_attribute_string ("Version", "replacement") != null 57 // [Deprecated] is deprecated 58 || symbol.get_attribute ("Deprecated") != null; 59 } 60 return _deprecated; 61 } 62 set { 63 _deprecated = value; 64 symbol.set_attribute_bool ("Version", "deprecated", _deprecated); 65 } 66 } 67 68 /** 69 * Specifies what version this symbol has been deprecated since. 70 */ 71 public string? deprecated_since { 72 owned get { 73 return symbol.get_attribute_string ("Version", "deprecated_since") 74 // [Deprecated] is deprecated 75 ?? symbol.get_attribute_string ("Deprecated", "since"); 76 } 77 set { 78 symbol.set_attribute_string ("Version", "deprecated_since", value); 79 } 80 } 81 82 /** 83 * Specifies the replacement if this symbol has been deprecated. 84 */ 85 public string? replacement { 86 owned get { 87 return symbol.get_attribute_string ("Version", "replacement") 88 // [Deprecated] is deprecated 89 ?? symbol.get_attribute_string ("Deprecated", "replacement"); 90 } 91 set { 92 symbol.set_attribute_string ("Version", "replacement", value); 93 } 94 } 95 96 97 98 /** 99 * Specifies whether this symbol is experimental. 100 */ 101 public bool experimental { 102 get { 103 if (_experimental == null) { 104 _experimental = symbol.get_attribute_bool ("Version", "experimental", false) 105 || symbol.get_attribute_string ("Version", "experimental_until") != null 106 || symbol.get_attribute ("Experimental") != null; 107 } 108 return _experimental; 109 } 110 set { 111 _experimental = value; 112 symbol.set_attribute_bool ("Version", "experimental", value); 113 } 114 } 115 116 /** 117 * Specifies until which version this symbol is experimental. 118 */ 119 public string? experimental_until { 120 owned get { 121 return symbol.get_attribute_string ("Version", "experimental_until"); 122 } 123 set { 124 symbol.set_attribute_string ("Version", "experimental_until", value); 125 } 126 } 127 128 129 130 /** 131 * The minimum version for {@link Vala.VersionAttribute.symbol} 132 */ 133 public string? since { 134 owned get { 135 return symbol.get_attribute_string ("Version", "since"); 136 } 137 set { 138 symbol.set_attribute_string ("Version", "since", value); 139 } 140 } 141 142 143 144 /** 145 * Check to see if the symbol is experimental, deprecated or not available 146 * and emit a warning if it is. 147 */ 148 public bool check (SourceReference? source_ref = null) { 149 bool result = false; 150 151 // deprecation: 152 if (symbol.external_package && deprecated) { 153 string? package_version = symbol.source_reference.file.installed_version; 154 155 if (!CodeContext.get ().deprecated && (package_version == null || deprecated_since == null || VersionAttribute.cmp_versions (package_version, deprecated_since) >= 0)) { 156 Report.deprecated (source_ref, "`%s' %s%s".printf (symbol.get_full_name (), (deprecated_since == null) ? "is deprecated" : "has been deprecated since %s".printf (deprecated_since), (replacement == null) ? "" : ". Use %s".printf (replacement))); 157 } 158 result = true; 159 } 160 161 // availability: 162 if (symbol.external_package && since != null) { 163 string? package_version = symbol.source_reference.file.installed_version; 164 165 if (CodeContext.get ().since_check && package_version != null && VersionAttribute.cmp_versions (package_version, since) < 0) { 166 unowned string filename = symbol.source_reference.file.filename; 167 string pkg = Path.get_basename (filename[0:filename.last_index_of_char ('.')]); 168 Report.error (source_ref, "`%s' is not available in %s %s. Use %s >= %s".printf (symbol.get_full_name (), pkg, package_version, pkg, since)); 169 } 170 result = true; 171 } 172 173 // experimental: 174 if (symbol.external_package && experimental) { 175 if (!CodeContext.get ().experimental) { 176 string? package_version = symbol.source_reference.file.installed_version; 177 string? experimental_until = this.experimental_until; 178 179 if (experimental_until == null || package_version == null || VersionAttribute.cmp_versions (package_version, experimental_until) < 0) { 180 Report.experimental (source_ref, "`%s' is experimental%s".printf (symbol.get_full_name (), (experimental_until != null) ? " until %s".printf (experimental_until) : "")); 181 } 182 } 183 result = true; 184 } 185 186 return result; 187 } 188 189 190 /** 191 * A simple version comparison function. 192 * 193 * @param v1str a version number 194 * @param v2str a version number 195 * @return an integer less than, equal to, or greater than zero, if v1str is <, == or > than v2str 196 * @see GLib.CompareFunc 197 */ 198 public static int cmp_versions (string v1str, string v2str) { 199 string[] v1arr = v1str.split ("."); 200 string[] v2arr = v2str.split ("."); 201 int i = 0; 202 203 while (v1arr[i] != null && v2arr[i] != null) { 204 int v1num = int.parse (v1arr[i]); 205 int v2num = int.parse (v2arr[i]); 206 207 if (v1num < 0 || v2num < 0) { 208 // invalid format 209 return 0; 210 } 211 212 if (v1num > v2num) { 213 return 1; 214 } 215 216 if (v1num < v2num) { 217 return -1; 218 } 219 220 i++; 221 } 222 223 if (v1arr[i] != null && v2arr[i] == null) { 224 return 1; 225 } 226 227 if (v1arr[i] == null && v2arr[i] != null) { 228 return -1; 229 } 230 231 return 0; 232 } 233} 234