def generate_version():
    """
    This is a generator function optimised for Joomla! version generation.
    In order to ensure validity of versions, we restrict the range of random choice by looking on the previously
    selected number. Finally we check the validity of version based on regexes that describe supported versions.
    :return: A joomla version in string format.
    """
    digit_1 = {'min': 1, 'max': 3}

    digit_2 = {
        1: {'min': 6, 'max': 7},
        2: {'min': 5, 'max': 5},
        3: {'min': 0, 'max': 4}
    }

    digit_3 = {
        1: {6: {'min': 0, 'max': 6}, 7: {'min': 0, 'max': 5}},
        2: {5: {'min': 0, 'max': 28}},
        3: {0: {'min': 0, 'max': 3}, 1: {'min': 0, 'max': 6}, 2: {'min': 0, 'max': 4}, 3: {'min': 0, 'max': 4},
            4: {'min': 0, 'max': 3}}
    }

    while True:
        try:
            first_digit = random.randint(digit_1['min'], digit_1['max'])
            second_digit = random.randint(digit_2[first_digit]['min'], digit_2[first_digit]['max'])
            third_digit = random.randint(digit_3[first_digit][second_digit]['min'],
                                         digit_3[first_digit][second_digit]['max'])
            version = '.'.join((str(first_digit), str(second_digit), str(third_digit)))
            if SUPPORTED_VERSIONS.match(version):
                return version
            else:
                raise ValueError
        except KeyError:
            raise RuntimeError
def generate_legacy_versions():
    """
    Joomla generator only for legacy versions!!!
    :return:
    """
    try:
        digit2 = {'min': 6, 'max': 7}
        digit3 = {6: {'min': 0, 'max': 6}, 7: {'min': 0, 'max': 5}}
        second_digit = random.randint(digit2['min'], digit2['max'])
        third_digit = random.randint(digit3[second_digit]['min'],
                                     digit3[second_digit]['max'])
        version = '.'.join((str(1), str(second_digit), str(third_digit)))
        if SUPPORTED_VERSIONS.match(version):
            return version
        else:
            raise ValueError
    except KeyError:
        raise RuntimeError
def dependency_solver_wrapper(current_version, latest_version, offline=False):
    """
    This is the wrapper function for the dependency solving algorithm. Given current, version and latest version will
    produce the essential steps to update. It checks if an update is required, if the server complies with new versions
    and if the version is supported by our tool. Then it retrieves all possible upgrade paths and calls the solver
    to provide the steps. If the server is not supported, if the version is not supported or if the system is already
    running the latest version, relevant messages appear.
    :param current_version: String containing the version. eg '3.4.1'
    :param latest_version: String containing the latest version eg '3.4.3'
    :return: A tuple with first value a boolean if the tool succeeded or not and second element either the steps or
    the error message.
    """
    if current_version < latest_version:
        if validate_server(latest_version, SERVER_CONFIG):
            if SUPPORTED_VERSIONS.match(current_version):
                dependencies = retrieve_manifest() if not offline else get_fixture_manifest()
                if current_version < LooseVersion("2.5.0"):
                    dependencies += retrieve_manifest(True) if not offline else get_fixture_manifest(True)
                return dependency_solver(current_version, dependencies, latest_version)
        else:
            return False, "Server Config Not Supported"
    elif current_version == latest_version:
        return False, "System Already Up-To-Date"
    return False, "Joomla Version is not supported"