1/*
2 * Copyright 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package androidx.build
18
19import java.io.File
20import java.util.regex.Matcher
21import java.util.regex.Pattern
22
23/**
24 * Utility class which represents a version
25 */
26data class Version(
27        val major: Int,
28        val minor: Int,
29        val patch: Int,
30        val extra: String? = null
31) : Comparable<Version> {
32
33    constructor(versionString: String) : this(
34            Integer.parseInt(checkedMatcher(versionString).group(1)),
35            Integer.parseInt(checkedMatcher(versionString).group(2)),
36            Integer.parseInt(checkedMatcher(versionString).group(3)),
37            if (checkedMatcher(versionString).groupCount() == 4) checkedMatcher(
38                    versionString).group(4) else null)
39
40    fun isPatch(): Boolean = patch != 0
41
42    fun isSnapshot(): Boolean = "-SNAPSHOT" == extra
43
44    fun isAlpha(): Boolean = extra?.toLowerCase()?.startsWith("-alpha") ?: false
45
46    fun isFinalApi(): Boolean = !isSnapshot() && !isAlpha()
47
48    override fun compareTo(other: Version) = compareValuesBy(this, other,
49            { it.major },
50            { it.minor },
51            { it.patch },
52            { it.extra == null }, // False (no extra) sorts above true (has extra)
53            { it.extra } // gradle uses lexicographic ordering
54    )
55
56    override fun toString(): String {
57        return "$major.$minor.$patch${extra ?: ""}"
58    }
59
60    companion object {
61        private val VERSION_FILE_REGEX = Pattern.compile("^(\\d+\\.\\d+\\.\\d+).txt$")
62        private val VERSION_REGEX = Pattern.compile("^(\\d+)\\.(\\d+)\\.(\\d+)(-.+)?$")
63
64        private fun checkedMatcher(versionString: String): Matcher {
65            val matcher = VERSION_REGEX.matcher(versionString)
66            if (!matcher.matches()) {
67                throw IllegalArgumentException("Can not parse version: " + versionString)
68            }
69            return matcher
70        }
71
72        /**
73         * @return Version or null, if a name of the given file doesn't match
74         */
75        fun parseOrNull(file: File): Version? {
76            if (!file.isFile) return null
77            val matcher = VERSION_FILE_REGEX.matcher(file.name)
78            return if (matcher.matches()) Version(matcher.group(1)) else null
79        }
80
81        /**
82         * @return Version or null, if the given string doesn't match
83         */
84        fun parseOrNull(versionString: String): Version? {
85            val matcher = VERSION_REGEX.matcher(versionString)
86            return if (matcher.matches()) Version(versionString) else null
87        }
88    }
89}
90