From ea92f8d6b5d8d627954295e14ccec7b793facdc8 Mon Sep 17 00:00:00 2001 From: Florian Brosch Date: Thu, 10 Jul 2014 20:35:22 +0200 Subject: Introduce [Version (...)] Parameters: since: string, version number experimental: bool (was: [Experimental]) experimental_until: string, version number deprecated_since: string, version number (was: [Deprecated (since="")]) replacement: string, symbol name (was: [Deprecated (replacement="")]) deprecated: bool (was: [Deprecated]) Used symbols labeled with [Version (since = "")] are checked against the locally installed package version. Use --disable-since-check to avoid this behaviour. Fixes bug 678912. --- vala/valaversionattribute.vala | 231 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 231 insertions(+) create mode 100644 vala/valaversionattribute.vala (limited to 'vala/valaversionattribute.vala') diff --git a/vala/valaversionattribute.vala b/vala/valaversionattribute.vala new file mode 100644 index 000000000..9c3df391f --- /dev/null +++ b/vala/valaversionattribute.vala @@ -0,0 +1,231 @@ +/* valaversionattribute.vala + * + * Copyright (C) 2013 Florian Brosch + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Author: + * Florian Brosch + */ + +using GLib; + + +/** + * Represents a [Version] attribute + */ +public class Vala.VersionAttribute { + private weak Symbol symbol; + + private bool? _deprecated; + private bool? _experimental; + + /** + * Constructs a new VersionAttribute. + * + * @param symbol the owner + * @return a new VersionAttribute + * @see Vala.Symbol + */ + public VersionAttribute (Symbol symbol) { + this.symbol = symbol; + } + + + + /** + * Specifies whether this symbol has been deprecated. + */ + public bool deprecated { + get { + if (_deprecated == null) { + _deprecated = symbol.get_attribute_bool ("Version", "deprecated", false) + || symbol.get_attribute_string ("Version", "deprecated_since") != null + || symbol.get_attribute_string ("Version", "replacement") != null + // [Deprecated] is deprecated + || symbol.get_attribute ("Deprecated") != null; + } + return _deprecated; + } + set { + _deprecated = value; + symbol.set_attribute_bool ("Version", "deprecated", _deprecated); + } + } + + /** + * Specifies what version this symbol has been deprecated since. + */ + public string? deprecated_since { + owned get { + return symbol.get_attribute_string ("Version", "deprecated_since") + // [Deprecated] is deprecated + ?? symbol.get_attribute_string ("Deprecated", "since"); + } + set { + symbol.set_attribute_string ("Version", "deprecated_since", value); + } + } + + /** + * Specifies the replacement if this symbol has been deprecated. + */ + public string? replacement { + owned get { + return symbol.get_attribute_string ("Version", "replacement") + // [Deprecated] is deprecated + ?? symbol.get_attribute_string ("Deprecated", "replacement"); + } + set { + symbol.set_attribute_string ("Version", "replacement", value); + } + } + + + + /** + * Specifies whether this symbol is experimental. + */ + public bool experimental { + get { + if (_experimental == null) { + _experimental = symbol.get_attribute_bool ("Version", "experimental", false) + || symbol.get_attribute_string ("Version", "experimental_until") != null + || symbol.get_attribute ("Experimental") != null; + } + return _experimental; + } + set { + _experimental = value; + symbol.set_attribute_bool ("Version", "experimental", value); + } + } + + /** + * Specifies until which version this symbol is experimental. + */ + public string? experimental_until { + owned get { + return symbol.get_attribute_string ("Version", "experimental_until"); + } + set { + symbol.set_attribute_string ("Version", "experimental_until", value); + } + } + + + + /** + * The minimum version for {@link Vala.VersionAttribute.symbol} + */ + public string? since { + owned get { + return symbol.get_attribute_string ("Version", "since"); + } + set { + symbol.set_attribute_string ("Version", "since", value); + } + } + + + + /** + * Check to see if the symbol is experimental, deprecated or not available + * and emit a warning if it is. + */ + public bool check (SourceReference? source_ref = null) { + bool result = false; + + // deprecation: + if (symbol.external_package && deprecated) { + if (!CodeContext.get ().deprecated) { + 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))); + } + result = true; + } + + // availability: + if (symbol.external_package && since != null) { + string? package_version = symbol.source_reference.file.installed_version; + + if (CodeContext.get ().since_check && package_version != null && VersionAttribute.cmp_versions (package_version, since) < 0) { + unowned string filename = symbol.source_reference.file.filename; + string pkg = Path.get_basename (filename[0:filename.last_index_of_char ('.')]); + Report.error (source_ref, "%s is not available in %s %s. Use %s >= %s".printf (symbol.get_full_name (), pkg, package_version, pkg, since)); + } + result = true; + } + + // experimental: + if (symbol.external_package && experimental) { + if (!CodeContext.get ().experimental) { + string? package_version = symbol.source_reference.file.installed_version; + string? experimental_until = this.experimental_until; + + if (experimental_until == null || package_version == null || VersionAttribute.cmp_versions (package_version, experimental_until) < 0) { + Report.experimental (source_ref, "%s is experimental%s".printf (symbol.get_full_name (), (experimental_until != null) ? " until %s".printf (experimental_until) : "")); + } + } + result = true; + } + + return result; + } + + + /** + * A simple version comparison function. + * + * @param v1str a version number + * @param v2str a version number + * @return an integer less than, equal to, or greater than zero, if v1str is <, == or > than v2str + * @see GLib.CompareFunc + */ + public static int cmp_versions (string v1str, string v2str) { + string[] v1arr = v1str.split ("."); + string[] v2arr = v2str.split ("."); + int i = 0; + + while (v1arr[i] != null && v2arr[i] != null) { + int v1num = int.parse (v1arr[i]); + int v2num = int.parse (v2arr[i]); + + if (v1num < 0 || v2num < 0) { + // invalid format + return 0; + } + + if (v1num > v2num) { + return 1; + } + + if (v1num < v2num) { + return -1; + } + + i++; + } + + if (v1arr[i] != null && v2arr[i] == null) { + return 1; + } + + if (v1arr[i] == null && v2arr[i] != null) { + return -1; + } + + return 0; + } +} -- cgit v1.2.1