Patchwork D8003: wix: more robust normalization of RC version components

login
register
mail settings
Submitter phabricator
Date Jan. 25, 2020, 4:34 a.m.
Message ID <differential-rev-PHID-DREV-dwzptbia4tz6votuvy5e-req@mercurial-scm.org>
Download mbox | patch
Permalink /patch/44651/
State Superseded
Headers show

Comments

phabricator - Jan. 25, 2020, 4:34 a.m.
indygreg created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  MSI has strict version requirements where the format is
  `A.B.C[.D]` and all fields must be numeric
  (https://docs.microsoft.com/en-us/windows/win32/msi/productversion?redirectedfrom=MSDN).
  Only the first 3 are used by the installer itself.
  
  Mercurial's version strings can have `rcN` and an optional
  `+<commit>-<date>` fragment at the end.
  
  This commit teaches the MSI version normalization to handle
  both of these more robustly.
  
  Before, we would throw away the `.rcN` component completely.
  e.g. `5.3rc1` would get normalized to `5.3.0`. And worse,
  `5.3rc0+5-abcdef` would get normalized to `5.3.5`.
  
  After this commit, presence of an `.rcN` provides the
  value for a 4th field. e.g. `5.3rc1` -> `5.3.0.1`. In
  addition, the commit count from the `+` suffix gets
  normalized into the 4th version component, but only if
  the original version string didn't have a 4th version
  component or if no `rcN` is present. e.g. `5.3+5-abcdef`
  is `5.3.0.5`.

REPOSITORY
  rHG Mercurial

BRANCH
  stable

REVISION DETAIL
  https://phab.mercurial-scm.org/D8003

AFFECTED FILES
  contrib/packaging/hgpackaging/wix.py

CHANGE DETAILS




To: indygreg, #hg-reviewers
Cc: mercurial-devel
phabricator - Jan. 25, 2020, 4:38 a.m.
indygreg added a comment.


  This series is for stable in case it gets missed in the Phabricator UI.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D8003/new/

REVISION DETAIL
  https://phab.mercurial-scm.org/D8003

To: indygreg, #hg-reviewers
Cc: mercurial-devel

Patch

diff --git a/contrib/packaging/hgpackaging/wix.py b/contrib/packaging/hgpackaging/wix.py
--- a/contrib/packaging/hgpackaging/wix.py
+++ b/contrib/packaging/hgpackaging/wix.py
@@ -74,9 +74,36 @@ 
 def normalize_version(version):
     """Normalize Mercurial version string so WiX accepts it.
 
-    Version strings have to be numeric X.Y.Z.
+    Version strings have to be numeric ``A.B.C[.D]`` to conform with MSI's
+    requirements.
+
+    We normalize RC version or the commit count to a 4th version component.
+    We store this in the 4th component because ``A.B.C`` releases do occur
+    and we want an e.g. ``5.3rc0`` version to be semantically less than a
+    ``5.3.1rc2`` version. This requires always reserving the 3rd version
+    component for the point release and the ``X.YrcN`` release is always
+    point release 0.
+
+    In the case of an RC and presence of ``+`` suffix data, we can't use both
+    because the version format is limited to 4 components. We choose to use
+    RC and throw away the commit count in the suffix. This means we could
+    produce multiple installers with the same normalized version string.
+
+    >>> normalize_version("5.3")
+    '5.3.0'
+
+    >>> normalize_version("5.3rc0")
+    '5.3.0.0'
+
+    >>> normalize_version("5.3rc1")
+    '5.3.0.1'
+
+    >>> normalize_version("5.3rc1+2-abcdef")
+    '5.3.0.1'
+
+    >>> normalize_version("5.3+2-abcdef")
+    '5.3.0.2'
     """
-
     if '+' in version:
         version, extra = version.split('+', 1)
     else:
@@ -84,19 +111,24 @@ 
 
     # 4.9rc0
     if version[:-1].endswith('rc'):
+        rc = int(version[-1:])
         version = version[:-3]
+    else:
+        rc = None
 
+    # Ensure we have at least X.Y version components.
     versions = [int(v) for v in version.split('.')]
     while len(versions) < 3:
         versions.append(0)
 
-    major, minor, build = versions[:3]
+    if len(versions) < 4:
+        if rc is not None:
+            versions.append(rc)
+        elif extra:
+            # <commit count>-<hash>+<date>
+            versions.append(int(extra.split('-')[0]))
 
-    if extra:
-        # <commit count>-<hash>+<date>
-        build = int(extra.split('-')[0])
-
-    return '.'.join('%d' % x for x in (major, minor, build))
+    return '.'.join('%d' % x for x in versions[0:4])
 
 
 def ensure_vc90_merge_modules(build_dir):