| 1 | #!/usr/bin/python |
| 2 | # -*- coding: utf-8 -*- |
| 3 | # |
| 4 | # Copyright (C) 2015 - Michael Jeanson <mjeanson@efficios.com> |
| 5 | # Jonathan Rajotte <jonathan.rajotte-julien@efficios.com> |
| 6 | # |
| 7 | # This program is free software: you can redistribute it and/or modify |
| 8 | # it under the terms of the GNU General Public License as published by |
| 9 | # the Free Software Foundation, either version 3 of the License, or |
| 10 | # (at your option) any later version. |
| 11 | # |
| 12 | # This program is distributed in the hope that it will be useful, |
| 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 15 | # GNU General Public License for more details. |
| 16 | # |
| 17 | # You should have received a copy of the GNU General Public License |
| 18 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 19 | |
| 20 | """ This script is used to generate a yaml list of kernel version tag """ |
| 21 | |
| 22 | import os |
| 23 | import re |
| 24 | import yaml |
| 25 | import argparse |
| 26 | |
| 27 | from distutils.version import Version |
| 28 | from git import Repo |
| 29 | |
| 30 | |
| 31 | class KernelVersion(Version): |
| 32 | """ Kernel version class """ |
| 33 | |
| 34 | re26 = re.compile(r'^(2\.\d+) \. (\d+) (\. (\d+))? (\-rc(\d+))?$', |
| 35 | re.VERBOSE) |
| 36 | re30 = re.compile(r'^(\d+) \. (\d+) (\. (\d+))? (\-rc(\d+))?$', re.VERBOSE) |
| 37 | |
| 38 | |
| 39 | def __init__(self, vstring=None): |
| 40 | self._rc = None |
| 41 | self._version = None |
| 42 | if vstring: |
| 43 | self.parse(vstring) |
| 44 | |
| 45 | |
| 46 | def parse(self, vstring): |
| 47 | """ Parse version string """ |
| 48 | |
| 49 | self._vstring = vstring |
| 50 | |
| 51 | if self._vstring.startswith("2"): |
| 52 | match = self.re26.match(self._vstring) |
| 53 | else: |
| 54 | match = self.re30.match(self._vstring) |
| 55 | |
| 56 | if not match: |
| 57 | raise ValueError("invalid version number '%s'" % self._vstring) |
| 58 | |
| 59 | (major, minor, patch, rc_num) = match.group(1, 2, 4, 6) |
| 60 | |
| 61 | major = int(float(major) * 10) |
| 62 | |
| 63 | if patch: |
| 64 | self._version = tuple(map(int, [major, minor, patch])) |
| 65 | else: |
| 66 | self._version = tuple(map(int, [major, minor])) + (0,) |
| 67 | |
| 68 | if rc_num: |
| 69 | self._rc = int(rc_num) |
| 70 | else: |
| 71 | self._rc = None |
| 72 | |
| 73 | |
| 74 | def isrc(self): |
| 75 | """ Is this version an RC """ |
| 76 | return self._rc is not None |
| 77 | |
| 78 | |
| 79 | def __str__(self): |
| 80 | return self._vstring |
| 81 | |
| 82 | |
| 83 | def __repr__(self): |
| 84 | return "KernelVersion ('%s')" % str(self) |
| 85 | |
| 86 | |
| 87 | def _cmp(self, other): |
| 88 | if isinstance(other, str): |
| 89 | other = KernelVersion(other) |
| 90 | |
| 91 | if self._version != other._version: |
| 92 | # numeric versions don't match |
| 93 | # prerelease stuff doesn't matter |
| 94 | if self._version < other._version: |
| 95 | return -1 |
| 96 | else: |
| 97 | return 1 |
| 98 | |
| 99 | # have to compare rc |
| 100 | # case 1: neither has rc; they're equal |
| 101 | # case 2: self has rc, other doesn't; other is greater |
| 102 | # case 3: self doesn't have rc, other does: self is greater |
| 103 | # case 4: both have rc: must compare them! |
| 104 | |
| 105 | if (not self._rc and not other._rc): |
| 106 | return 0 |
| 107 | elif (self._rc and not other._rc): |
| 108 | return -1 |
| 109 | elif (not self._rc and other._rc): |
| 110 | return 1 |
| 111 | elif (self._rc and other._rc): |
| 112 | if self._rc == other._rc: |
| 113 | return 0 |
| 114 | elif self._rc < other._rc: |
| 115 | return -1 |
| 116 | else: |
| 117 | return 1 |
| 118 | else: |
| 119 | assert False, "never get here" |
| 120 | |
| 121 | def main(): |
| 122 | """ Main """ |
| 123 | |
| 124 | versions = [] |
| 125 | kernel_cutoff = KernelVersion("2.6.36") |
| 126 | kernel_git = "git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git" |
| 127 | kernel_path = os.getcwd() + "/kernel" |
| 128 | |
| 129 | parser = argparse.ArgumentParser() |
| 130 | parser.add_argument("--kernel-path", help="The location of the kernel. Default to the currentdir/linux") |
| 131 | parser.add_argument("--kernel-git-remote", help="The git url of the kernel. Default to git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git") |
| 132 | parser.add_argument("--kernel-cutoff", help="The lower bersion cutoff in X.X.X format. Default to 2.6.36") |
| 133 | args = parser.parse_args() |
| 134 | |
| 135 | if args.kernel_path: |
| 136 | kernel_path = args.kernel_path |
| 137 | if args.kernel_git_remote: |
| 138 | kernel_git = args.kernel_git_remote |
| 139 | if args.kernel_cutoff: |
| 140 | kernel_cutoff = KernelVersion(args.kernel_cutoff) |
| 141 | |
| 142 | # Open or create the local repository |
| 143 | if os.path.isdir(kernel_path): |
| 144 | linux_repo = Repo(kernel_path) |
| 145 | else: |
| 146 | linux_repo = Repo.clone_from(kernel_git, kernel_path) |
| 147 | |
| 148 | # Pull the latest |
| 149 | linux_repo.remote().pull() |
| 150 | |
| 151 | # First get all valid versions |
| 152 | for tag in linux_repo.tags: |
| 153 | try: |
| 154 | version = KernelVersion(tag.name.lstrip('v')) |
| 155 | |
| 156 | # Add only those who are superior to the cutoff version |
| 157 | if version >= kernel_cutoff: |
| 158 | versions.append(version) |
| 159 | except ValueError: |
| 160 | #print(tag.name) |
| 161 | continue |
| 162 | |
| 163 | # Sort the list by version order |
| 164 | versions.sort() |
| 165 | |
| 166 | # Keep only one rc if it's the latest version |
| 167 | last = True |
| 168 | for version in reversed(versions): |
| 169 | if version.isrc() and not last: |
| 170 | versions.remove(version) |
| 171 | last = False |
| 172 | |
| 173 | #for version in versions: |
| 174 | # print(version) |
| 175 | |
| 176 | # Build yaml object |
| 177 | yversions = [] |
| 178 | |
| 179 | for version in versions: |
| 180 | yversions.append(version.__str__()) |
| 181 | |
| 182 | print(yaml.dump(yversions, default_flow_style=False)) |
| 183 | |
| 184 | |
| 185 | |
| 186 | |
| 187 | if __name__ == "__main__": |
| 188 | main() |
| 189 | |
| 190 | # EOF |