diff --git a/modoboa_installer/compatibility_matrix.py b/modoboa_installer/compatibility_matrix.py new file mode 100644 index 0000000..8da21a4 --- /dev/null +++ b/modoboa_installer/compatibility_matrix.py @@ -0,0 +1,8 @@ +"""Modoboa compatibility matrix.""" + +COMPATIBILITY_MATRIX = { +} + +EXTENSIONS_AVAILABILITY = { + "modoboa-contacts": "1.7.4", +} diff --git a/modoboa_installer/scripts/modoboa.py b/modoboa_installer/scripts/modoboa.py index a7b7512..6c8361e 100644 --- a/modoboa_installer/scripts/modoboa.py +++ b/modoboa_installer/scripts/modoboa.py @@ -7,6 +7,7 @@ import shutil import stat import sys +from .. import compatibility_matrix from .. import package from .. import python from .. import utils @@ -50,10 +51,36 @@ class Modoboa(base.Installer): else: self.extensions.remove("modoboa-amavis") + def is_extension_ok_for_version(self, extension, version): + """Check if extension can be installed with this modo version.""" + if extension not in compatibility_matrix.EXTENSIONS_AVAILABILITY: + return True + version = utils.convert_version_to_int(version) + min_version = compatibility_matrix.EXTENSIONS_AVAILABILITY[extension] + min_version = utils.convert_version_to_int(min_version) + return version >= min_version + def _setup_venv(self): """Prepare a dedicated virtualenv.""" python.setup_virtualenv(self.venv_path, sudo_user=self.user) - packages = ["modoboa", "rrdtool"] + packages = ["rrdtool"] + version = self.config.get("modoboa", "version") + if version == "latest": + packages += ["modoboa"] + self.extensions + else: + matrix = compatibility_matrix.COMPATIBILITY_MATRIX[version] + packages.append("modoboa=={}".format(version)) + for extension in list(self.extensions): + if not self.is_extension_ok_for_version(extension, version): + self.extensions.remove(extension) + continue + if extension in matrix: + req_version = matrix[extension] + req_version = req_version.replace("<", "\<") + req_version = req_version.replace(">", "\>") + packages.append("{}{}".format(extension, req_version)) + else: + packages.append(extension) if self.dbengine == "postgres": packages.append("psycopg2") else: @@ -91,6 +118,7 @@ class Modoboa(base.Installer): "--timezone", self.config.get("modoboa", "timezone"), "--domain", self.config.get("general", "hostname"), "--extensions", " ".join(self.extensions), + "--dont-install-extensions", "--dburl", "'default:{0}://{1}:{2}@{3}/{1}'".format( self.config.get("database", "engine"), self.dbname, self.dbpasswd, self.dbhost) diff --git a/modoboa_installer/utils.py b/modoboa_installer/utils.py index 68e43f4..e4baee8 100644 --- a/modoboa_installer/utils.py +++ b/modoboa_installer/utils.py @@ -171,6 +171,8 @@ def has_colours(stream): except: # guess false in case of error return False + + has_colours = has_colours(sys.stdout) @@ -179,3 +181,30 @@ def printcolor(message, color): if has_colours: message = "\x1b[1;{}m{}\x1b[0m".format(30 + color, message) print(message) + + +def convert_version_to_int(version): + """Convert a version string to an integer.""" + number_bits = (8, 8, 16) + + numbers = [int(number_string) for number_string in version.split(".")] + if len(numbers) > len(number_bits): + raise NotImplementedError( + "Versions with more than {0} decimal places are not supported" + .format(len(number_bits) - 1) + ) + # add 0s for missing numbers + numbers.extend([0] * (len(number_bits) - len(numbers))) + # convert to single int and return + number = 0 + total_bits = 0 + for num, bits in reversed(list(zip(numbers, number_bits))): + max_num = (bits + 1) - 1 + if num >= 1 << max_num: + raise ValueError( + "Number {0} cannot be stored with only {1} bits. Max is {2}" + .format(num, bits, max_num) + ) + number += num << total_bits + total_bits += bits + return number diff --git a/run.py b/run.py index e0f600b..385829e 100755 --- a/run.py +++ b/run.py @@ -8,10 +8,11 @@ try: except ImportError: import ConfigParser as configparser -from modoboa_installer import scripts -from modoboa_installer import utils +from modoboa_installer import compatibility_matrix from modoboa_installer import package +from modoboa_installer import scripts from modoboa_installer import ssl +from modoboa_installer import utils def main(): @@ -23,6 +24,10 @@ def main(): help="Force installation") parser.add_argument("--configfile", default="installer.cfg", help="Configuration file to use") + parser.add_argument( + "--version", default="latest", + choices=["latest"] + compatibility_matrix.COMPATIBILITY_MATRIX.keys(), + help="Modoboa version to install") parser.add_argument( "--stop-after-configfile-check", action="store_true", default=False, help="Check configuration, generate it if needed and exit") @@ -42,6 +47,7 @@ def main(): if not config.has_section("general"): config.add_section("general") config.set("general", "domain", args.domain) + config.set("modoboa", "version", args.version) utils.printcolor( "Your mail server will be installed with the following components:", utils.BLUE) @@ -80,5 +86,6 @@ def main(): .format(config.get("general", "hostname")), utils.GREEN) + if __name__ == "__main__": main()