[zorg] r323925 - Checks for Xcode and SDK versions

Chris Matthews via llvm-commits llvm-commits at lists.llvm.org
Wed Jan 31 14:37:34 PST 2018


Author: cmatthews
Date: Wed Jan 31 14:37:34 2018
New Revision: 323925

URL: http://llvm.org/viewvc/llvm-project?rev=323925&view=rev
Log:
Checks for Xcode and SDK versions

Modified:
    zorg/trunk/dep/dep.py
    zorg/trunk/dep/tests/test_dep.py

Modified: zorg/trunk/dep/dep.py
URL: http://llvm.org/viewvc/llvm-project/zorg/trunk/dep/dep.py?rev=323925&r1=323924&r2=323925&view=diff
==============================================================================
--- zorg/trunk/dep/dep.py (original)
+++ zorg/trunk/dep/dep.py Wed Jan 31 14:37:34 2018
@@ -20,6 +20,7 @@ from __future__ import print_function
 from __future__ import unicode_literals
 
 import argparse
+import collections
 import json
 import platform
 import re
@@ -370,9 +371,142 @@ class Brew(Dependency):
         return "{} {} {}".format(self.str_kind, self.package, self.version)
 
 
+class Xcode(Dependency):
+    """Verify and Inject Xcode version dependencies."""
+
+    # xcode <operator> <version>.  Operator may not have spaces around it.
+    xcode_dep_re = re.compile(r'(?P<command>\w+)\s+(?P<operator>>=|<=|==)\s*(?P<version_text>[\d.-_]+)')
+
+    def __init__(self, line, kind):
+        # type: (Line, Text) -> None
+        """Parse and xcode version installed.
+
+        :param line: the Line with the deceleration of the dependency.
+        :param kind: the detected dependency kind.
+        """
+        super(Xcode, self).__init__(line, kind)
+        self.command = None
+        self.operator = None
+        self.version = None
+        self.version_text = None
+        self.installed_version = None
+
+    def parse(self):
+        """Parse this dependency."""
+        text = self.line.text
+        match = self.xcode_dep_re.match(text)
+        if not match:
+            raise MalformedDependency("Expression does not compile in {}: {}".format(self.__class__.__name__,
+                                                                                     self.line))
+        self.__dict__.update(match.groupdict())
+
+        self.version = Version(self.version_text)
+
+    def verify(self):
+        """Verify the installed Xcode matches this dependency."""
+        installed_version_output = subprocess.check_output(['/usr/bin/xcrun', 'xcodebuild', "-version"])
+        installed_version_re = re.compile(r"^Xcode\s(?P<version_text>[\d/.]+)")
+        match = installed_version_re.match(installed_version_output)
+        if not match:
+            raise MissingDependencyError(self, "Did not find Xcode version in output:" + installed_version_output)
+        version = match.groupdict().get('version_text')
+        if not version:
+            # The package is not installed at all.
+            raise AssertionError("No version text found.")
+        self.installed_version = Version(version)
+        return check_version(self.installed_version, self.operator, self.version)
+
+    def inject(self):
+        """Not implemented."""
+        raise NotImplementedError()
+
+    def __str__(self):
+        """Dependency kind, package and version, for printing in error messages."""
+        return "{} {}".format(self.str_kind, self.version)
+
+
+class Sdk(Dependency):
+    """Verify and Inject Sdk version dependencies."""
+
+    # sdk <operator> <version>.  Operator may not have spaces around it.
+    sdk_dep_re = re.compile(r'(?P<command>\w+)\s+(?P<sdk>[\w/.]+)\s*(?P<operator>>=|<=|==)\s*(?P<version_text>[\d.-_]+)')
+
+    def __init__(self, line, kind):
+        # type: (Line, Text) -> None
+        """Parse and sdk version installed.
+
+        :param line: the Line with the deceleration of the dependency.
+        :param kind: the detected dependency kind.
+        """
+        super(Sdk, self).__init__(line, kind)
+        self.command = None
+        self.sdk = None
+        self.operator = None
+        self.version = None
+        self.version_text = None
+        self.installed_version = None
+
+    def parse(self):
+        """Parse this dependency."""
+        text = self.line.text
+        match = self.sdk_dep_re.match(text)
+        if not match:
+            raise MalformedDependency("Expression does not compile in {}: {}".format(self.__class__.__name__,
+                                                                                     self.line))
+        self.__dict__.update(match.groupdict())
+
+        self.version = Version(self.version_text)
+
+    def verify(self):
+        """Verify the installed Sdk matches this dependency."""
+        installed_version_output = subprocess.check_output(['/usr/bin/xcrun', 'xcodebuild', "-showsdks"])
+        installed_version_re = re.compile(r".*-sdk\s+(?P<sdk_text>\S+)")
+
+        matches = [installed_version_re.match(l).groupdict()['sdk_text']
+                   for l in installed_version_output.split('\n') if installed_version_re.match(l)]
+
+        if not matches:
+            raise MissingDependencyError(self, "Did not find Sdk version in output:" + installed_version_output)
+
+        extract_version_names = re.compile(r'(?P<pre>\D*)(?P<version_text>[\d+/.]*)(?P<post>.*)')
+
+        sdks = [extract_version_names.match(sdk_text).groupdict()
+                for sdk_text in matches if extract_version_names.match(sdk_text)]
+
+        installed_sdks = collections.defaultdict(list)
+        for sdk in sdks:
+            name = sdk['pre']
+            if sdk.get('post'):
+                name += "." + sdk.get('post')
+            if sdk.get('version_text'):
+                version = Version(sdk['version_text'].rstrip('.'))
+            else:
+                continue
+            installed_sdks[name].append(version)
+
+        if self.sdk not in installed_sdks.keys():
+            raise MissingDependencyError("{} not found in installed SDKs.".format(self.sdk))
+
+        self.installed_version = installed_sdks[self.sdk]
+
+        satisfied = [check_version(s, self.operator, self.version) for s in self.installed_version]
+        return any(satisfied)
+
+    def inject(self):
+        """Not implemented."""
+        raise NotImplementedError()
+
+    def __str__(self):
+        """Dependency kind, package and version, for printing in error messages."""
+        return "{} {}".format(self.str_kind, self.version)
+
+
 dependencies_implementations = {'brew': Brew,
                                 'os_version': HostOSVersion,
-                                'config_manager': ConMan}
+                                'config_manager': ConMan,
+                                'xcode': Xcode,
+                                'sdk': Sdk,
+                                }
 
 
 def dependency_factory(line):

Modified: zorg/trunk/dep/tests/test_dep.py
URL: http://llvm.org/viewvc/llvm-project/zorg/trunk/dep/tests/test_dep.py?rev=323925&r1=323924&r2=323925&view=diff
==============================================================================
--- zorg/trunk/dep/tests/test_dep.py (original)
+++ zorg/trunk/dep/tests/test_dep.py Wed Jan 31 14:37:34 2018
@@ -9,7 +9,7 @@ import sys
 import pytest
 
 import dep
-from dep import Line, Brew, Version, MissingDependencyError, ConMan, HostOSVersion
+from dep import Line, Brew, Version, MissingDependencyError, ConMan, HostOSVersion, Xcode, Sdk
 
 here = os.path.dirname(os.path.realpath(__file__))
 
@@ -132,3 +132,93 @@ def test_host_os_version_requirement(moc
     bad.parse()
     with pytest.raises(MissingDependencyError):
         bad.verify_and_act()
+
+
+XCODE_VERSION_OUTPUT = """Xcode 1.0
+Build version 1A123b
+"""
+
+
+def test_xcode_version_requirement(mocker):
+    """Unittest of the Xcode version check."""
+    line = Line("foo.c", 11, "xcode == 1.0", "test")
+    mocker.patch('dep.subprocess.check_output')
+    dep.subprocess.check_output.return_value = XCODE_VERSION_OUTPUT
+    b = Xcode(line, "xcode")
+    b.parse()
+    assert b.operator == "=="
+    assert b.command == "xcode"
+    assert b.version_text == "1.0"
+
+    b.verify_and_act()
+
+    line = Line("foo.c", 10, "xcode == 2.0", "test")
+    bad = Xcode(line, "xcode")
+    bad.parse()
+    with pytest.raises(MissingDependencyError):
+        bad.verify_and_act()
+
+
+SDK_VERSION_OUTPUT = """iOS SDKs:
+	iOS 1.0                      	-sdk iphoneos1.0
+
+iOS Simulator SDKs:
+	Simulator - iOS 1.0          	-sdk iphonesimulator1.0
+
+macOS SDKs:
+	macOS 10.11                   	-sdk macosx10.11
+	macOS 10.12                   	-sdk macosx10.12
+
+macOS Additional SDKs:
+	iDishwasher SDK                	-sdk iwash
+"""  # noqa This is literal output, it is okay to mix tabs.
+
+
+def test_sdk_version_requirement(mocker):
+    """Unittest of the SDK version check."""
+    line = Line("foo.c", 11, "sdk iphoneos == 1.0", "test")
+    mocker.patch('dep.subprocess.check_output')
+    dep.subprocess.check_output.return_value = SDK_VERSION_OUTPUT
+    b = Sdk(line, "sdk")
+    b.parse()
+    assert b.operator == "=="
+    assert b.command == "sdk"
+    assert b.sdk == "iphoneos"
+    assert b.version_text == "1.0"
+
+    b.verify_and_act()
+
+    line = Line("foo.c", 10, "sdk iphoneos == 2.0", "test")
+    bad = Sdk(line, "sdk")
+    bad.parse()
+    with pytest.raises(MissingDependencyError):
+        bad.verify_and_act()
+
+    b = Sdk(Line("foo.c", 11, "sdk iphoneos == 1.0", "test"), "sdk")
+    b.parse()
+    b.verify_and_act()
+
+    b = Sdk(Line("foo.c", 11, "sdk iphoneos <= 1.0", "test"), "sdk")
+    b.parse()
+    b.verify_and_act()
+
+    b = Sdk(Line("foo.c", 11, "sdk iphonesimulator <= 1.0", "test"), "sdk")
+    b.parse()
+    b.verify_and_act()
+
+    b = Sdk(Line("foo.c", 11, "sdk iwash == 1.0", "test"), "sdk")
+    b.parse()
+    # TODO handle unversioned SDKs.
+    with pytest.raises(MissingDependencyError):
+        b.verify_and_act()
+
+    b = Sdk(Line("foo.c", 11, "sdk macosx == 10.12", "test"), "sdk")
+    b.parse()
+    b.verify_and_act()
+
+    b = Sdk(Line("foo.c", 11, "sdk macosx == 10.11", "test"), "sdk")
+    b.parse()
+    b.verify_and_act()
+
+
+




More information about the llvm-commits mailing list