diff --git a/.github/workflows/Linux.yml b/.github/workflows/Linux.yml new file mode 100644 index 0000000..8e96545 --- /dev/null +++ b/.github/workflows/Linux.yml @@ -0,0 +1,38 @@ +name: Linux + +on: + push: + pull_request: + schedule: + #Every Sunday at midnight + - cron: '0 0 * * 0' + +jobs: + + test: + name: "Test" + strategy: + matrix: + version_test: ["NoVersion","3.1"] + + runs-on: ubuntu-latest + steps: + + - name: Setup Python + uses: actions/setup-python@v2 + + - name: Checkout + uses: actions/checkout@v2.3.4 + + - name: Cache tools + uses: actions/cache@v2 + with: + path: tools + key: ${{ runner.os }}-cmakes + + - name: "Download cmake packages" + run: | + python3 -mvenv venv + venv/bin/pip3 install -r requirements.txt + venv/bin/python3 cmake_downloader.py --latest_patch + venv/bin/python3 cmake_min_version.py --full_search FULL_SEARCH $GITHUB_WORKSPACE/tests/${{ matrix.version_test }}/ \ No newline at end of file diff --git a/.github/workflows/MacOS.yml b/.github/workflows/MacOS.yml new file mode 100644 index 0000000..79b14c2 --- /dev/null +++ b/.github/workflows/MacOS.yml @@ -0,0 +1,36 @@ +name: MacOS + +on: + push: + pull_request: + schedule: + #Every Sunday at midnight + - cron: '0 0 * * 0' + +jobs: + test: + name: "Test" + strategy: + matrix: + version_test: ["NoVersion","3.1"] + runs-on: macos-latest + steps: + + - name: Setup Python + uses: actions/setup-python@v2 + + - name: Checkout + uses: actions/checkout@v2.3.4 + + - name: Cache tools + uses: actions/cache@v2 + with: + path: tools + key: ${{ runner.os }}-cmakes + + - name: "Download cmake packages" + run: | + python3 -mvenv venv + venv/bin/pip3 install -r requirements.txt + venv/bin/python3 cmake_downloader.py --latest_patch + venv/bin/python3 cmake_min_version.py --full_search FULL_SEARCH $GITHUB_WORKSPACE/tests/${{ matrix.version_test }}/ diff --git a/.github/workflows/Windows.yml b/.github/workflows/Windows.yml new file mode 100644 index 0000000..ef9aef6 --- /dev/null +++ b/.github/workflows/Windows.yml @@ -0,0 +1,36 @@ +name: Windows + +on: + push: + pull_request: + schedule: + #Every Sunday at midnight + - cron: '0 0 * * 0' + +jobs: + test: + name: "Test" + strategy: + matrix: + version_test: ["NoVersion","3.1"] + runs-on: windows-latest + steps: + + - name: Setup Python + uses: actions/setup-python@v2 + + - name: Checkout + uses: actions/checkout@v2.3.4 + + - name: Cache tools + uses: actions/cache@v2 + with: + path: tools + key: ${{ runner.os }}-cmakes + + - name: "Download cmake packages" + run: | + python -m venv venv + .\venv\Scripts\pip.exe install -r .\requirements.txt + .\venv\Scripts\python.exe cmake_downloader.py --latest_patch + .\venv\Scripts\python.exe cmake_min_version.py --full_search FULL_SEARCH $GITHUB_WORKSPACE\tests\${{ matrix.version_test }}\ diff --git a/cmake_downloader.py b/cmake_downloader.py index 7fdbd05..bece830 100644 --- a/cmake_downloader.py +++ b/cmake_downloader.py @@ -40,7 +40,9 @@ def download_and_extract(url: str, path: str): file_name_start_pos = url.rfind("/") + 1 file_name = url[file_name_start_pos:] file_wo_ext, file_ext = os.path.splitext(file_name) - + if file_ext != ".zip": + file_wo_ext, file_ext2 = os.path.splitext(file_wo_ext) + file_ext=file_ext+file_ext2 if not os.path.exists(os.path.join(path, file_wo_ext)): response = requests.get(url, stream=True) response.raise_for_status() diff --git a/cmake_min_version.py b/cmake_min_version.py index b488638..31599cd 100644 --- a/cmake_min_version.py +++ b/cmake_min_version.py @@ -1,16 +1,21 @@ import argparse import glob -import platform import math import os.path +import platform import re import subprocess +import sys import tempfile -from typing import List, Optional, NamedTuple +from typing import List +from typing import NamedTuple +from typing import Optional from packaging.version import parse as version_parse from termcolor import colored +sys.stdout.reconfigure(encoding="utf-8") + class CMakeBinary(NamedTuple): version: str @@ -25,22 +30,23 @@ def __init__(self, return_code: int, stderr: str): # try to read proposed minimal version from stderr output try: - self.proposed_version = re.findall(r'CMake ([^ ]+) or higher is required.', stderr)[0] + self.proposed_version = re.findall( + r"CMake ([^ ]+) or higher is required.", stderr)[0] # support ranges - if '..' in self.proposed_version: - self.proposed_version = self.proposed_version.split('..')[0] + if ".." in self.proposed_version: + self.proposed_version = self.proposed_version.split("..")[0] # make sure all versions are major.minor.patch - if self.proposed_version.count('.') == 1: - self.proposed_version += '.0' + if self.proposed_version.count(".") == 1: + self.proposed_version += ".0" except IndexError: pass try: - self.reason = re.findall(r'CMake Error at (.*):', stderr)[0] + self.reason = re.findall(r"CMake Error at (.*):", stderr)[0] except IndexError: try: - self.reason = re.findall(r'CMake Error: ([^\n]+)', stderr)[0] + self.reason = re.findall(r"CMake Error: ([^\n]+)", stderr)[0] except IndexError: pass @@ -49,35 +55,41 @@ def get_cmake_binaries(tools_dir: str) -> List[CMakeBinary]: binaries = [] # type: List[CMakeBinary] mGlob = [] if platform.system() == "Windows": - mGlob = glob.glob(tools_dir + '/**/bin/cmake.exe', recursive=True) + mGlob = glob.glob(tools_dir + "/**/bin/cmake.exe", recursive=True) else: - mGlob = glob.glob(tools_dir + '/**/bin/cmake', recursive=True) + mGlob = glob.glob(tools_dir + "/**/bin/cmake", recursive=True) for filename in mGlob: try: - version = re.findall(r'cmake-([^-]+)-', filename)[0] + version = re.findall(r"cmake-([^-]+)-", filename)[0] binaries.append(CMakeBinary(version, os.path.abspath(filename))) except IndexError: pass - print('Found {count} CMake binaries from directory {tools_dir}\n'.format( - count=len(binaries), tools_dir=tools_dir) - ) + print("Found {count} CMake binaries from directory {tools_dir}\n".format( + count=len(binaries), tools_dir=tools_dir)) return sorted(binaries, key=lambda x: version_parse(x.version)) def try_configure(binary: str, cmake_parameters: List[str]) -> ConfigureResult: tmpdir = tempfile.TemporaryDirectory() - proc = subprocess.Popen([binary] + cmake_parameters + ['-Wno-dev'], - stdout=subprocess.DEVNULL, stderr=subprocess.PIPE, cwd=tmpdir.name) + proc = subprocess.Popen( + [binary] + ["-S"] + cmake_parameters + ["-Wno-dev"], + stdout=subprocess.DEVNULL, + stderr=subprocess.PIPE, + cwd=tmpdir.name, + ) proc.wait() - return ConfigureResult(return_code=proc.returncode, stderr=proc.stderr.read().decode('utf-8')) + return ConfigureResult(return_code=proc.returncode, + stderr=proc.stderr.read().decode("utf-8")) -def binary_search(cmake_parameters: List[str], tools_dir: str) -> Optional[CMakeBinary]: +def binary_search(cmake_parameters: List[str], + tools_dir: str) -> Optional[CMakeBinary]: versions = get_cmake_binaries(tools_dir) # type: List[CMakeBinary] - longest_version_string = max([len(cmake.version) for cmake in versions]) + 1 # type: int + longest_version_string = (max([len(cmake.version) + for cmake in versions]) + 1) # type: int lower_idx = 0 # type: int upper_idx = len(versions) - 1 # type: int @@ -91,32 +103,45 @@ def binary_search(cmake_parameters: List[str], tools_dir: str) -> Optional[CMake steps += 1 remaining_versions = upper_idx - lower_idx + 1 # type: int - remaining_steps = int(math.ceil(math.log2(remaining_versions))) # type: int - - print('[{progress:3.0f}%] CMake {cmake_version:{longest_version_string}}'.format( - progress=100.0 * float(steps - 1) / (steps + remaining_steps), - cmake_version=cmake_binary.version, longest_version_string=longest_version_string), end='', flush=True + remaining_steps = int(math.ceil( + math.log2(remaining_versions))) # type: int + + print( + "[{progress:3.0f}%] CMake {cmake_version:{longest_version_string}}" + .format( + progress=100.0 * float(steps - 1) / (steps + remaining_steps), + cmake_version=cmake_binary.version, + longest_version_string=longest_version_string, + ), + end="", + flush=True, ) - result = try_configure(cmake_binary.binary, cmake_parameters) # type: ConfigureResult + # type: ConfigureResult + result = try_configure(cmake_binary.binary, cmake_parameters) if result.success: - print(colored('✔ works', 'green')) + print(colored("✔ works", "green")) last_success_idx = mid_idx upper_idx = mid_idx - 1 else: - print(colored('✘ error', 'red')) + print(colored("✘ error", "red")) if result.reason: - print(' {reason}'.format(reason=result.reason)) - proposed_binary = [x for x in versions if x.version == result.proposed_version] - lower_idx = versions.index(proposed_binary[0]) if len(proposed_binary) else mid_idx + 1 + print(" {reason}".format(reason=result.reason)) + proposed_binary = [ + x for x in versions if x.version == result.proposed_version + ] + lower_idx = (versions.index(proposed_binary[0]) + if len(proposed_binary) else mid_idx + 1) return versions[last_success_idx] if last_success_idx is not None else None -def full_search(cmake_parameters: List[str], tools_dir: str) -> Optional[CMakeBinary]: +def full_search(cmake_parameters: List[str], + tools_dir: str) -> Optional[CMakeBinary]: versions = get_cmake_binaries(tools_dir) # type: List[CMakeBinary] - longest_version_string = max([len(cmake.version) for cmake in versions]) + 1 # type: int + longest_version_string = (max([len(cmake.version) + for cmake in versions]) + 1) # type: int lower_idx = 0 # type: int upper_idx = len(versions) - 1 # type: int @@ -127,34 +152,54 @@ def full_search(cmake_parameters: List[str], tools_dir: str) -> Optional[CMakeBi for cmake_binary in versions: steps += 1 remaining_versions = upper_idx - lower_idx + 1 # type: int - remaining_steps = int(math.ceil(math.log2(remaining_versions))) # type: int - - print('[{progress:3.0f}%] CMake {cmake_version:{longest_version_string}}'.format( - progress=100.0 * float(steps - 1) / (steps + remaining_steps), - cmake_version=cmake_binary.version, longest_version_string=longest_version_string), end='', flush=True + remaining_steps = int(math.ceil( + math.log2(remaining_versions))) # type: int + + print( + "[{progress:3.0f}%] CMake {cmake_version:{longest_version_string}}" + .format( + progress=100.0 * float(steps - 1) / (steps + remaining_steps), + cmake_version=cmake_binary.version, + longest_version_string=longest_version_string, + ), + end="", + flush=True, ) - result = try_configure(cmake_binary.binary, cmake_parameters) # type: ConfigureResult + # type: ConfigureResult + result = try_configure(cmake_binary.binary, cmake_parameters) if result.success: - print(colored('✔ works', 'green')) + print(colored("\U00002714 works", "green")) if not last_success_idx or last_success_idx > steps - 1: last_success_idx = steps - 1 else: - print(colored('✘ error', 'red')) + print(colored("\U0000274C error", "red")) if result.reason: - print(' {reason}'.format(reason=result.reason)) + print(" {reason}".format(reason=result.reason)) return versions[last_success_idx] if last_success_idx is not None else None -if __name__ == '__main__': - parser = argparse.ArgumentParser(description='Find the minimal required CMake version for a project.') - parser.add_argument('params', type=str, nargs='+', help='parameters to pass to CMake') - parser.add_argument('--tools_directory', metavar='DIR', default='tools', - help='path to the CMake binaries (default: "tools")') - parser.add_argument('--full_search', default=False, - help='Searches using a top down approach instead of a binary search (default: False)') +if __name__ == "__main__": + parser = argparse.ArgumentParser( + description="Find the minimal required CMake version for a project.") + parser.add_argument("params", + type=str, + nargs="+", + help="parameters to pass to CMake") + parser.add_argument( + "--tools_directory", + metavar="DIR", + default="tools", + help='path to the CMake binaries (default: "tools")', + ) + parser.add_argument( + "--full_search", + default=False, + help= + "Searches using a top down approach instead of a binary search (default: False)", + ) args = parser.parse_args() if args.full_search: @@ -163,10 +208,14 @@ def full_search(cmake_parameters: List[str], tools_dir: str) -> Optional[CMakeBi working_version = binary_search(args.params, args.tools_directory) if working_version: - print('[100%] Minimal working version: {cmake} {version}'.format( - cmake=colored('CMake', 'blue'), version=colored(working_version.version, 'blue'))) + print("[100%] Minimal working version: {cmake} {version}".format( + cmake=colored("CMake", "blue"), + version=colored(working_version.version, "blue"), + )) - print('\ncmake_minimum_required(VERSION {version})'.format(version=working_version.version)) + print("\ncmake_minimum_required(VERSION {version})".format( + version=working_version.version)) else: - print('[100%] {message}'.format(message=colored('ERROR: Could not find working version.', 'red'))) + print("[100%] {message}".format( + message=colored("ERROR: Could not find working version.", "red"))) diff --git a/tests/3.1/CMakeLists.txt b/tests/3.1/CMakeLists.txt new file mode 100644 index 0000000..7869100 --- /dev/null +++ b/tests/3.1/CMakeLists.txt @@ -0,0 +1,6 @@ +cmake_minimum_required(VERSION 3.1.0) + +project(Test3.1) + +#https://cmake.org/cmake/help/v3.1/release/3.1.0.html +include(FindOpenCL) diff --git a/tests/NoVersion/CMakeLists.cmake b/tests/NoVersion/CMakeLists.cmake new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/tests/NoVersion/CMakeLists.cmake @@ -0,0 +1 @@ +