<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[225199] trunk/Tools</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/225199">225199</a></dd>
<dt>Author</dt> <dd>jbedard@apple.com</dd>
<dt>Date</dt> <dd>2017-11-27 15:21:28 -0800 (Mon, 27 Nov 2017)</dd>
</dl>

<h3>Log Message</h3>
<pre>webkitpy: Better name-version mapping (Part 1)
https://bugs.webkit.org/show_bug.cgi?id=179621
<rdar://problem/35589585>

Reviewed by David Kilzer.

Mapping version numbers to version names should occur in a central location.
This has a few advantages. First, it makes iterating through versions easier.
Second, it allows for apple_additions to define an additional set of name
mappings. Lastly, it will allow, in a future patch, for us to track version
instead of version name, only mapping version to version name when required.

* Scripts/webkitpy/common/system/platforminfo.py:
(PlatformInfo.__init__):
(PlatformInfo._determine_os_name): Use VersionNameMap instead of custom functions
mapping version to name.
(PlatformInfo._determine_linux_version): Deleted.
(PlatformInfo._determine_mac_version): Deleted.
(PlatformInfo._determine_win_version): Deleted.
* Scripts/webkitpy/common/system/platforminfo_unittest.py:
(TestPlatformInfo.test_os_name_and_wrappers):
(TestPlatformInfo.test_os_version):
(TestPlatformInfo.test_display_name):
(TestPlatformInfo.test_total_bytes_memory):
* Scripts/webkitpy/common/version.py:
(Version.contained_in): Add partial version mapping.
* Scripts/webkitpy/common/version_name_map.py: Added.
(VersionNameMap): Holds a mapping of version name to version object.
(VersionNameMap.map): Don't re-create VersionNameMap every time.
(VersionNameMap.__init__): Initialize mapping, use platform to
define the default system platform.
(VersionNameMap._automap_to_major_version): Some operating systems, such
as iOS, have a naming scheme based on their major version and os name.
Automatically generate such mappings.
(VersionNameMap.to_name): Given a version object, platform name and
table, find the closest matching version name.
(VersionNameMap.strip_name_formatting): Remove spaces and extract the major version,
if a version string is included in the name.
(VersionNameMap.from_name): Return an os name and version given a version name.
* Scripts/webkitpy/common/version_name_map_unittest.py: Added.
(VersionMapTestCase):
(VersionMapTestCase.test_default_system_platform):
(VersionMapTestCase.test_mac_version_by_name):
(VersionMapTestCase.test_ios_version_by_name):
(VersionMapTestCase.test_mac_name_by_version):
(VersionMapTestCase.test_ios_name_by_version):
* Scripts/webkitpy/common/version_unittest.py:
(VersionTestCase.test_contained_in):
* Scripts/webkitpy/port/ios_device.py:
(IOSDevicePort.ios_version): Map os_version name to version number.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkToolsChangeLog">trunk/Tools/ChangeLog</a></li>
<li><a href="#trunkToolsScriptswebkitpycommonsystemplatforminfopy">trunk/Tools/Scripts/webkitpy/common/system/platforminfo.py</a></li>
<li><a href="#trunkToolsScriptswebkitpycommonsystemplatforminfo_unittestpy">trunk/Tools/Scripts/webkitpy/common/system/platforminfo_unittest.py</a></li>
<li><a href="#trunkToolsScriptswebkitpycommonversionpy">trunk/Tools/Scripts/webkitpy/common/version.py</a></li>
<li><a href="#trunkToolsScriptswebkitpycommonversion_unittestpy">trunk/Tools/Scripts/webkitpy/common/version_unittest.py</a></li>
<li><a href="#trunkToolsScriptswebkitpyportios_devicepy">trunk/Tools/Scripts/webkitpy/port/ios_device.py</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkToolsScriptswebkitpycommonversion_name_mappy">trunk/Tools/Scripts/webkitpy/common/version_name_map.py</a></li>
<li><a href="#trunkToolsScriptswebkitpycommonversion_name_map_unittestpy">trunk/Tools/Scripts/webkitpy/common/version_name_map_unittest.py</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkToolsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Tools/ChangeLog (225198 => 225199)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/ChangeLog    2017-11-27 23:13:54 UTC (rev 225198)
+++ trunk/Tools/ChangeLog       2017-11-27 23:21:28 UTC (rev 225199)
</span><span class="lines">@@ -1,3 +1,56 @@
</span><ins>+2017-11-27  Jonathan Bedard  <jbedard@apple.com>
+
+        webkitpy: Better name-version mapping (Part 1)
+        https://bugs.webkit.org/show_bug.cgi?id=179621
+        <rdar://problem/35589585>
+
+        Reviewed by David Kilzer.
+
+        Mapping version numbers to version names should occur in a central location.
+        This has a few advantages. First, it makes iterating through versions easier.
+        Second, it allows for apple_additions to define an additional set of name
+        mappings. Lastly, it will allow, in a future patch, for us to track version
+        instead of version name, only mapping version to version name when required.
+
+        * Scripts/webkitpy/common/system/platforminfo.py:
+        (PlatformInfo.__init__):
+        (PlatformInfo._determine_os_name): Use VersionNameMap instead of custom functions
+        mapping version to name.
+        (PlatformInfo._determine_linux_version): Deleted.
+        (PlatformInfo._determine_mac_version): Deleted.
+        (PlatformInfo._determine_win_version): Deleted.
+        * Scripts/webkitpy/common/system/platforminfo_unittest.py:
+        (TestPlatformInfo.test_os_name_and_wrappers):
+        (TestPlatformInfo.test_os_version):
+        (TestPlatformInfo.test_display_name):
+        (TestPlatformInfo.test_total_bytes_memory):
+        * Scripts/webkitpy/common/version.py:
+        (Version.contained_in): Add partial version mapping.
+        * Scripts/webkitpy/common/version_name_map.py: Added.
+        (VersionNameMap): Holds a mapping of version name to version object.
+        (VersionNameMap.map): Don't re-create VersionNameMap every time.
+        (VersionNameMap.__init__): Initialize mapping, use platform to
+        define the default system platform.
+        (VersionNameMap._automap_to_major_version): Some operating systems, such
+        as iOS, have a naming scheme based on their major version and os name.
+        Automatically generate such mappings.
+        (VersionNameMap.to_name): Given a version object, platform name and
+        table, find the closest matching version name.
+        (VersionNameMap.strip_name_formatting): Remove spaces and extract the major version,
+        if a version string is included in the name.
+        (VersionNameMap.from_name): Return an os name and version given a version name.
+        * Scripts/webkitpy/common/version_name_map_unittest.py: Added.
+        (VersionMapTestCase):
+        (VersionMapTestCase.test_default_system_platform):
+        (VersionMapTestCase.test_mac_version_by_name):
+        (VersionMapTestCase.test_ios_version_by_name):
+        (VersionMapTestCase.test_mac_name_by_version):
+        (VersionMapTestCase.test_ios_name_by_version):
+        * Scripts/webkitpy/common/version_unittest.py:
+        (VersionTestCase.test_contained_in):
+        * Scripts/webkitpy/port/ios_device.py:
+        (IOSDevicePort.ios_version): Map os_version name to version number.
+
</ins><span class="cx"> 2017-11-27  Don Olmstead  <don.olmstead@sony.com>
</span><span class="cx"> 
</span><span class="cx">         [CMake][Win] Conditionally select DLL CRT or static CRT
</span></span></pre></div>
<a id="trunkToolsScriptswebkitpycommonsystemplatforminfopy"></a>
<div class="modfile"><h4>Modified: trunk/Tools/Scripts/webkitpy/common/system/platforminfo.py (225198 => 225199)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/Scripts/webkitpy/common/system/platforminfo.py       2017-11-27 23:13:54 UTC (rev 225198)
+++ trunk/Tools/Scripts/webkitpy/common/system/platforminfo.py  2017-11-27 23:21:28 UTC (rev 225199)
</span><span class="lines">@@ -31,6 +31,7 @@
</span><span class="cx"> import sys
</span><span class="cx"> 
</span><span class="cx"> from webkitpy.common.version import Version
</span><ins>+from webkitpy.common.version_name_map import VersionNameMap
</ins><span class="cx"> from webkitpy.common.system.executive import Executive
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -51,16 +52,27 @@
</span><span class="cx">         self._executive = executive
</span><span class="cx">         self._platform_module = platform_module
</span><span class="cx">         self.os_name = self._determine_os_name(sys_module.platform)
</span><del>-        if self.os_name == 'linux':
-            self.os_version = self._determine_linux_version()
-        if self.os_name == 'freebsd' or self.os_name == 'openbsd' or self.os_name == 'netbsd' or self.os_name == 'ios':
-            self.os_version = platform_module.release()
</del><ins>+        self.os_version = None
+
</ins><span class="cx">         if self.os_name.startswith('mac'):
</span><del>-            self.os_version = self._determine_mac_version(Version(platform_module.mac_ver()[0]))
-        if self.os_name.startswith('win'):
-            self.os_version = self._determine_win_version(self._win_version(sys_module))
</del><ins>+            version = Version(platform_module.mac_ver()[0])
+        elif self.os_name.startswith('win'):
+            version = self._win_version(sys_module)
+        elif self.os_name == 'linux' or self.os_name == 'freebsd' or self.os_name == 'openbsd' or self.os_name == 'netbsd':
+            version = None
+        else:
+            # Most other platforms (namely iOS) return conforming version strings.
+            version = Version(platform_module.release())
+
</ins><span class="cx">         self._is_cygwin = sys_module.platform == 'cygwin'
</span><span class="cx"> 
</span><ins>+        if version is None:
+            return
+
+        self.os_version = VersionNameMap.map(self).to_name(version, table='public')
+        assert self.os_version is not None
+        self.os_version = self.os_version.lower().replace(' ', '')
+
</ins><span class="cx">     def is_mac(self):
</span><span class="cx">         return self.os_name == 'mac'
</span><span class="cx"> 
</span><span class="lines">@@ -164,40 +176,6 @@
</span><span class="cx">             return 'haiku'
</span><span class="cx">         raise AssertionError('unrecognized platform string "%s"' % sys_platform)
</span><span class="cx"> 
</span><del>-    def _determine_mac_version(self, mac_version):
-        version_strings = {
-            5: 'leopard',
-            6: 'snowleopard',
-            7: 'lion',
-            8: 'mountainlion',
-            9: 'mavericks',
-            10: 'yosemite',
-            11: 'elcapitan',
-            12: 'sierra',
-            13: 'highsierra',
-        }
-        assert mac_version.minor >= min(version_strings.keys())
-        return version_strings.get(mac_version.minor, 'future')
-
-    def _determine_linux_version(self):
-        # FIXME: we ignore whatever the real version is and pretend it's lucid for now.
-        return 'lucid'
-
-    def _determine_win_version(self, win_version):
-        if self._platform_module.release() == '10':
-            return 'win10'
-        if win_version.major == 0 and win_version.minor == 0:
-            if win_version[2] > 10000:
-                return 'win10'
-        if win_version == Version([6, 1, 7600]):
-            return '7sp0'
-        if win_version.major == 6 and win_version.minor == 0:
-            return 'vista'
-        if win_version.major == 5 and win_version.minor == 1:
-            return 'xp'
-        assert win_version[0] > 6 or win_version[1] >= 1, 'Unrecognized Windows version: "{}"'.format(win_version)
-        return 'future'
-
</del><span class="cx">     def _win_version(self, sys_module):
</span><span class="cx">         if hasattr(sys_module, 'getwindowsversion'):
</span><span class="cx">             return Version(sys_module.getwindowsversion()[0:3])
</span></span></pre></div>
<a id="trunkToolsScriptswebkitpycommonsystemplatforminfo_unittestpy"></a>
<div class="modfile"><h4>Modified: trunk/Tools/Scripts/webkitpy/common/system/platforminfo_unittest.py (225198 => 225199)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/Scripts/webkitpy/common/system/platforminfo_unittest.py      2017-11-27 23:13:54 UTC (rev 225198)
+++ trunk/Tools/Scripts/webkitpy/common/system/platforminfo_unittest.py 2017-11-27 23:21:28 UTC (rev 225199)
</span><span class="lines">@@ -87,13 +87,13 @@
</span><span class="cx">             self.assertIsNone(info.total_bytes_memory())
</span><span class="cx"> 
</span><span class="cx">     def test_os_name_and_wrappers(self):
</span><del>-        info = self.make_info(fake_sys('linux2'))
</del><ins>+        info = self.make_info(fake_sys('linux2'), fake_platform('', '10.4'))
</ins><span class="cx">         self.assertTrue(info.is_linux())
</span><span class="cx">         self.assertFalse(info.is_mac())
</span><span class="cx">         self.assertFalse(info.is_win())
</span><span class="cx">         self.assertFalse(info.is_freebsd())
</span><span class="cx"> 
</span><del>-        info = self.make_info(fake_sys('linux3'))
</del><ins>+        info = self.make_info(fake_sys('linux3'), fake_platform('', '10.4'))
</ins><span class="cx">         self.assertTrue(info.is_linux())
</span><span class="cx">         self.assertFalse(info.is_mac())
</span><span class="cx">         self.assertFalse(info.is_win())
</span><span class="lines">@@ -122,7 +122,7 @@
</span><span class="cx">         self.assertFalse(info.is_native_win())
</span><span class="cx">         self.assertFalse(info.is_freebsd())
</span><span class="cx"> 
</span><del>-        info = self.make_info(fake_sys('freebsd8'))
</del><ins>+        info = self.make_info(fake_sys('freebsd8'), fake_platform('', '8.3-PRERELEASE'))
</ins><span class="cx">         self.assertEqual(info.os_name, 'freebsd')
</span><span class="cx">         self.assertFalse(info.is_linux())
</span><span class="cx">         self.assertFalse(info.is_mac())
</span><span class="lines">@@ -144,19 +144,20 @@
</span><span class="cx">         self.assertEqual(self.make_info(fake_sys('darwin'), fake_platform('10.13.0')).os_version, 'highsierra')
</span><span class="cx">         self.assertEqual(self.make_info(fake_sys('darwin'), fake_platform('10.14.0')).os_version, 'future')
</span><span class="cx"> 
</span><del>-        self.assertEqual(self.make_info(fake_sys('linux2')).os_version, 'lucid')
</del><ins>+        self.assertEqual(self.make_info(fake_sys('linux2'), fake_platform('', '10.4')).os_version, None)
</ins><span class="cx"> 
</span><del>-        self.assertEqual(self.make_info(fake_sys('freebsd8'), fake_platform('', '8.3-PRERELEASE')).os_version, '8.3-PRERELEASE')
-        self.assertEqual(self.make_info(fake_sys('freebsd9'), fake_platform('', '9.0-RELEASE')).os_version, '9.0-RELEASE')
</del><ins>+        self.assertEqual(self.make_info(fake_sys('freebsd8'), fake_platform('', '8.3-PRERELEASE')).os_version, None)
+        self.assertEqual(self.make_info(fake_sys('freebsd9'), fake_platform('', '9.0-RELEASE')).os_version, None)
</ins><span class="cx"> 
</span><span class="cx">         self.assertRaises(AssertionError, self.make_info, fake_sys('win32', tuple([5, 0, 1234])))
</span><del>-        self.assertEqual(self.make_info(fake_sys('win32', tuple([6, 2, 1234]))).os_version, 'future')
</del><ins>+        self.assertEqual(self.make_info(fake_sys('win32', tuple([10, 0, 14393]))).os_version, 'win10')
+        self.assertEqual(self.make_info(fake_sys('win32', tuple([6, 2, 1234]))).os_version, '8')
</ins><span class="cx">         self.assertEqual(self.make_info(fake_sys('win32', tuple([6, 1, 7600]))).os_version, '7sp0')
</span><span class="cx">         self.assertEqual(self.make_info(fake_sys('win32', tuple([6, 0, 1234]))).os_version, 'vista')
</span><span class="cx">         self.assertEqual(self.make_info(fake_sys('win32', tuple([5, 1, 1234]))).os_version, 'xp')
</span><span class="cx"> 
</span><span class="cx">         self.assertRaises(AssertionError, self.make_info, fake_sys('win32'), executive=fake_executive('5.0.1234'))
</span><del>-        self.assertEqual(self.make_info(fake_sys('cygwin'), executive=fake_executive('6.2.1234')).os_version, 'future')
</del><ins>+        self.assertEqual(self.make_info(fake_sys('cygwin'), executive=fake_executive('6.2.1234')).os_version, '8')
</ins><span class="cx">         self.assertEqual(self.make_info(fake_sys('cygwin'), executive=fake_executive('6.1.7600')).os_version, '7sp0')
</span><span class="cx">         self.assertEqual(self.make_info(fake_sys('cygwin'), executive=fake_executive('6.0.1234')).os_version, 'vista')
</span><span class="cx">         self.assertEqual(self.make_info(fake_sys('cygwin'), executive=fake_executive('5.1.1234')).os_version, 'xp')
</span><span class="lines">@@ -168,10 +169,10 @@
</span><span class="cx">         info = self.make_info(fake_sys('win32', tuple([6, 1, 7600])))
</span><span class="cx">         self.assertNotEquals(info.display_name(), '')
</span><span class="cx"> 
</span><del>-        info = self.make_info(fake_sys('linux2'))
</del><ins>+        info = self.make_info(fake_sys('linux2'), fake_platform('', '10.4'))
</ins><span class="cx">         self.assertNotEquals(info.display_name(), '')
</span><span class="cx"> 
</span><del>-        info = self.make_info(fake_sys('freebsd9'))
</del><ins>+        info = self.make_info(fake_sys('freebsd9'), fake_platform('', '9.0-RELEASE'))
</ins><span class="cx">         self.assertNotEquals(info.display_name(), '')
</span><span class="cx"> 
</span><span class="cx">     def test_total_bytes_memory(self):
</span><span class="lines">@@ -181,8 +182,8 @@
</span><span class="cx">         info = self.make_info(fake_sys('win32', tuple([6, 1, 7600])))
</span><span class="cx">         self.assertIsNone(info.total_bytes_memory())
</span><span class="cx"> 
</span><del>-        info = self.make_info(fake_sys('linux2'))
</del><ins>+        info = self.make_info(fake_sys('linux2'), fake_platform('', '10.4'))
</ins><span class="cx">         self.assertIsNone(info.total_bytes_memory())
</span><span class="cx"> 
</span><del>-        info = self.make_info(fake_sys('freebsd9'))
</del><ins>+        info = self.make_info(fake_sys('freebsd9'), fake_platform('', '9.0-RELEASE'))
</ins><span class="cx">         self.assertIsNone(info.total_bytes_memory())
</span></span></pre></div>
<a id="trunkToolsScriptswebkitpycommonversionpy"></a>
<div class="modfile"><h4>Modified: trunk/Tools/Scripts/webkitpy/common/version.py (225198 => 225199)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/Scripts/webkitpy/common/version.py   2017-11-27 23:13:54 UTC (rev 225198)
+++ trunk/Tools/Scripts/webkitpy/common/version.py      2017-11-27 23:21:28 UTC (rev 225199)
</span><span class="lines">@@ -92,6 +92,16 @@
</span><span class="cx">             raise ValueError('Version key must be major, minor, tiny, micro or nano')
</span><span class="cx">         raise ValueError('Expected version key to be string or integer')
</span><span class="cx"> 
</span><ins>+    # 11.2 is contained in 11, but 11 is not contained in 11.2
+    def contained_in(self, version):
+        does_match = True
+        for i in xrange(len(self)):
+            if self[i] != version[i]:
+                does_match = False
+            if not does_match and version[i] != 0:
+                return False
+        return True
+
</ins><span class="cx">     def __str__(self):
</span><span class="cx">         len_to_print = 1
</span><span class="cx">         for i in xrange(len(self)):
</span></span></pre></div>
<a id="trunkToolsScriptswebkitpycommonversion_name_mappy"></a>
<div class="addfile"><h4>Added: trunk/Tools/Scripts/webkitpy/common/version_name_map.py (0 => 225199)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/Scripts/webkitpy/common/version_name_map.py                          (rev 0)
+++ trunk/Tools/Scripts/webkitpy/common/version_name_map.py     2017-11-27 23:21:28 UTC (rev 225199)
</span><span class="lines">@@ -0,0 +1,124 @@
</span><ins>+# Copyright (C) 2017 Apple Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1.  Redistributions of source code must retain the above copyright
+#     notice, this list of conditions and the following disclaimer.
+# 2.  Redistributions in binary form must reproduce the above copyright
+#     notice, this list of conditions and the following disclaimer in the
+#     documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR
+# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import re
+
+from webkitpy.common.memoized import memoized
+from webkitpy.common.version import Version
+
+
+class VersionNameMap(object):
+
+    # Allows apple_additions to define a custom mapping
+    @staticmethod
+    @memoized
+    def map(platform=None):
+        return VersionNameMap(platform=platform)
+
+    def __init__(self, platform=None):
+        if platform is None:
+            from webkitpy.common.system.systemhost import SystemHost
+            platform = SystemHost().platform
+        self.mapping = {}
+
+        self.default_system_platform = platform.os_name
+        self.mapping['public'] = {
+            'mac': {
+                'Leopard': Version('10.5'),
+                'Snow Leopard': Version('10.6'),
+                'Lion': Version('10.7'),
+                'Mountain Lion': Version('10.8'),
+                'Mavericks': Version('10.9'),
+                'Yosemite': Version('10.10'),
+                'El Capitan': Version('10.11'),
+                'Sierra': Version('10.12'),
+                'High Sierra': Version('10.13'),
+                'Future': Version('10.14'),
+            },
+            'ios': self._automap_to_major_version('iOS', minimum=Version('10'), maximum=Version('12')),
+            'win': {
+                'Win10': Version('10'),
+                '8.1': Version('6.3'),
+                '8': Version('6.2'),
+                '7sp0': Version('6.1.7600'),
+                'Vista': Version('6'),
+                'XP': Version('5.1'),
+            },
+        }
+
+    @classmethod
+    def _automap_to_major_version(cls, prefix, minimum=Version('1'), maximum=Version('1')):
+        result = {}
+        assert minimum <= maximum
+        for i in xrange((maximum.major + 1) - minimum.major):
+            result['{} {}'.format(prefix, str(Version(str(minimum.major + i))))] = Version(str(minimum.major + i))
+        return result
+
+    def to_name(self, version, platform=None, table='public'):
+        platform = self.default_system_platform if platform is None else platform
+        assert table in self.mapping
+        assert platform in self.mapping[table]
+        closest_match = (None, None)
+        version = Version(version)
+        for os_name, os_version in self.mapping[table][platform].iteritems():
+            if version == os_version:
+                return os_name
+            elif version.contained_in(os_version):
+                if closest_match[1] and closest_match[1].contained_in(os_version):
+                    continue
+                closest_match = (os_name, os_version)
+        return closest_match[0]
+
+    @staticmethod
+    def strip_name_formatting(name):
+        # <OS> major.minor.tiny should map to <OS> major
+        if ' ' in name:
+            try:
+                name = '{}{}'.format(''.join(name.split(' ')[:-1]), Version(name.split(' ')[-1]).major)
+            except ValueError:
+                pass
+        else:
+            try:
+                split = re.split(r'\d', name)
+                name = '{}{}'.format(split[0], Version(name[(len(split) - 1):]).major)
+            except ValueError:
+                pass
+
+        # Strip out any spaces, make everything lower-case
+        result = name.replace(' ', '').lower()
+        return result
+
+    def from_name(self, name):
+        # Exact match
+        for _, map in self.mapping.iteritems():
+            for os_name, os_map in map.iteritems():
+                if name in os_map:
+                    return (os_name, os_map[name])
+
+        # It's not an exact match, let's try unifying formatting
+        unformatted = self.strip_name_formatting(name)
+        for _, map in self.mapping.iteritems():
+            for os_name, os_map in map.iteritems():
+                for version_name, version in os_map.iteritems():
+                    if self.strip_name_formatting(version_name) == unformatted:
+                        return (os_name, version)
+        return (None, None)
</ins></span></pre></div>
<a id="trunkToolsScriptswebkitpycommonversion_name_map_unittestpy"></a>
<div class="addfile"><h4>Added: trunk/Tools/Scripts/webkitpy/common/version_name_map_unittest.py (0 => 225199)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/Scripts/webkitpy/common/version_name_map_unittest.py                         (rev 0)
+++ trunk/Tools/Scripts/webkitpy/common/version_name_map_unittest.py    2017-11-27 23:21:28 UTC (rev 225199)
</span><span class="lines">@@ -0,0 +1,63 @@
</span><ins>+# Copyright (C) 2017 Apple Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1.  Redistributions of source code must retain the above copyright
+#     notice, this list of conditions and the following disclaimer.
+# 2.  Redistributions in binary form must reproduce the above copyright
+#     notice, this list of conditions and the following disclaimer in the
+#     documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR
+# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import unittest
+
+from webkitpy.common.system.systemhost import SystemHost
+from webkitpy.common.version import Version
+from version_name_map import VersionNameMap
+
+
+class VersionMapTestCase(unittest.TestCase):
+
+    def test_default_system_platform(self):
+        host = SystemHost()
+        map = VersionNameMap(platform=host.platform)
+        self.assertEqual(map.default_system_platform, host.platform.os_name)
+
+    def test_mac_version_by_name(self):
+        map = VersionNameMap()
+        self.assertEqual(('mac', Version('10.12')), map.from_name('Sierra'))
+        self.assertEqual(('mac', Version('10.12')), map.from_name('sierra'))
+        self.assertEqual(('mac', Version('10.11')), map.from_name('El Capitan'))
+        self.assertEqual(('mac', Version('10.11')), map.from_name('elcapitan'))
+        self.assertEqual(('mac', Version('10.11')), map.from_name('el Capitan'))
+
+    def test_ios_version_by_name(self):
+        map = VersionNameMap()
+        self.assertEqual(('ios', Version(11)), map.from_name('iOS 11'))
+        self.assertEqual(('ios', Version(11)), map.from_name('ios11'))
+        self.assertEqual(('ios', Version(11)), map.from_name('iOS 11.2'))
+        self.assertEqual(('ios', Version(11)), map.from_name('ios11.2'))
+        self.assertEqual(('ios', Version(11)), map.from_name('iOS11.2'))
+
+    def test_mac_name_by_version(self):
+        map = VersionNameMap()
+        self.assertEqual('Sierra', map.to_name(version=Version('10.12'), platform='mac'))
+        self.assertEqual('El Capitan', map.to_name(version=Version('10.11'), platform='mac'))
+        self.assertEqual('El Capitan', map.to_name(version=Version('10.11.3'), platform='mac'))
+
+    def test_ios_name_by_version(self):
+        map = VersionNameMap()
+        self.assertEqual('iOS 11', map.to_name(version=Version('11'), platform='ios'))
+        self.assertEqual('iOS 10', map.to_name(version=Version('10'), platform='ios'))
+        self.assertEqual('iOS 10', map.to_name(version=Version('10.3'), platform='ios'))
</ins></span></pre></div>
<a id="trunkToolsScriptswebkitpycommonversion_unittestpy"></a>
<div class="modfile"><h4>Modified: trunk/Tools/Scripts/webkitpy/common/version_unittest.py (225198 => 225199)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/Scripts/webkitpy/common/version_unittest.py  2017-11-27 23:13:54 UTC (rev 225198)
+++ trunk/Tools/Scripts/webkitpy/common/version_unittest.py     2017-11-27 23:21:28 UTC (rev 225199)
</span><span class="lines">@@ -125,6 +125,22 @@
</span><span class="cx">         self.assertEqual(str(Version('1.2')), '1.2')
</span><span class="cx">         self.assertEqual(str(Version('0.0.3')), '0.0.3')
</span><span class="cx"> 
</span><ins>+    def test_contained_in(self):
+        self.assertTrue(Version('11.1').contained_in(Version('11')))
+        self.assertTrue(Version('11.1.2').contained_in(Version('11.1')))
+        self.assertFalse(Version('11').contained_in(Version('11.1')))
+        self.assertFalse(Version('11').contained_in(Version('11.1.2')))
+        self.assertFalse(Version('11.1').contained_in(Version('11.1.2')))
+        self.assertTrue(Version('11').contained_in(Version('11')))
+        self.assertTrue(Version('11.1').contained_in(Version('11.1')))
+        self.assertTrue(Version('11.1.2').contained_in(Version('11.1.2')))
+        self.assertTrue(Version('11').contained_in(Version('11.0')))
+        self.assertTrue(Version('11.0').contained_in(Version('11')))
+        self.assertTrue(Version('11').contained_in(Version('11.0.0')))
+        self.assertTrue(Version('11.0.0').contained_in(Version('11')))
+        self.assertTrue(Version('11.1').contained_in(Version('11.1.0')))
+        self.assertTrue(Version('11.1.0').contained_in(Version('11.1')))
+
</ins><span class="cx">     def test_compare_versions(self):
</span><span class="cx">         self.assertEqual(Version('1.2.3'), Version('1.2.3'))
</span><span class="cx">         self.assertGreater(Version('1.2.4'), Version('1.2.3'))
</span></span></pre></div>
<a id="trunkToolsScriptswebkitpyportios_devicepy"></a>
<div class="modfile"><h4>Modified: trunk/Tools/Scripts/webkitpy/port/ios_device.py (225198 => 225199)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/Scripts/webkitpy/port/ios_device.py  2017-11-27 23:13:54 UTC (rev 225198)
+++ trunk/Tools/Scripts/webkitpy/port/ios_device.py     2017-11-27 23:21:28 UTC (rev 225199)
</span><span class="lines">@@ -25,6 +25,7 @@
</span><span class="cx"> from webkitpy.common.memoized import memoized
</span><span class="cx"> from webkitpy.common.system.crashlogs import CrashLogs
</span><span class="cx"> from webkitpy.common.version import Version
</span><ins>+from webkitpy.common.version_name_map import VersionNameMap
</ins><span class="cx"> from webkitpy.port.config import apple_additions
</span><span class="cx"> from webkitpy.port.ios import IOSPort
</span><span class="cx"> 
</span><span class="lines">@@ -108,7 +109,8 @@
</span><span class="cx">             else:
</span><span class="cx">                 if device.platform.os_version != version:
</span><span class="cx">                     raise RuntimeError('Multiple connected devices have different iOS versions')
</span><del>-
</del><ins>+        if version:
+            return VersionNameMap.map(self.host.platform).from_name(version)[1]
</ins><span class="cx">         return Version(version)
</span><span class="cx"> 
</span><span class="cx">     # FIXME: These need device implementations <rdar://problem/30497991>.
</span></span></pre>
</div>
</div>

</body>
</html>