[tor-commits] [tor/master] Rewrite updateVersions script in Python, add datestamp functionality.

nickm at torproject.org nickm at torproject.org
Tue Dec 11 14:52:42 UTC 2018


commit b16d6453adde2b13d2aa95a74ec3c09a259f185f
Author: Nick Mathewson <nickm at torproject.org>
Date:   Sat Nov 24 20:03:48 2018 -0500

    Rewrite updateVersions script in Python, add datestamp functionality.
    
    This updateVersions.pl script was one of the only essential perl
    scripts left in out maint system, and was the only one that used
    autoconf to fill in the script.
    
    This script adds a feature to define an APPROX_RELEASE_DATE macro
    that is updated when the version changes.  We'll use this to
    implement prop297, so that we have an accurate view of when a
    release date happens.
---
 Makefile.am                        |   2 +-
 configure.ac                       |  10 ++-
 doc/HACKING/ReleasingTor.md        |   6 +-
 scripts/maint/updateVersions.pl.in |  59 ----------------
 scripts/maint/update_versions.py   | 133 +++++++++++++++++++++++++++++++++++++
 5 files changed, 144 insertions(+), 66 deletions(-)

diff --git a/Makefile.am b/Makefile.am
index 803e9d00d..cbe94ad93 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -416,7 +416,7 @@ endif
 
 .PHONY: update-versions
 update-versions:
-	$(PERL) $(top_builddir)/scripts/maint/updateVersions.pl
+	abs_top_srcdir="$(abs_top_srcdir)" $(PYTHON) $(top_srcdir)/scripts/maint/update_versions.py
 
 .PHONY: callgraph
 callgraph:
diff --git a/configure.ac b/configure.ac
index 31e41c3bb..7f0d37544 100644
--- a/configure.ac
+++ b/configure.ac
@@ -8,6 +8,15 @@ AC_INIT([tor],[0.4.0.0-alpha-dev])
 AC_CONFIG_SRCDIR([src/app/main/tor_main.c])
 AC_CONFIG_MACRO_DIR([m4])
 
+# DO NOT EDIT THIS DEFINITION BY HAND UNLESS YOU KNOW WHAT YOU'RE DOING.
+#
+# The update_versions.py script updates this definition when the
+# version number changes.  Tor uses it to make sure that it
+# only shuts down for missing "required protocols" when those protocols
+# are listed as required by a consensus after this date.
+AC_DEFINE(APPROX_RELEASE_DATE, ["2019-01-15"], # for 0.4.0.0-alpha-dev
+          [Approximate date when this software was released. (Updated when the version changes.)])
+
 # "foreign" means we don't follow GNU package layout standards
 # "1.11" means we require automake version 1.11 or newer
 # "subdir-objects" means put .o files in the same directory as the .c files
@@ -2417,7 +2426,6 @@ AC_CONFIG_FILES([
 	src/config/torrc.minimal
 	src/rust/.cargo/config
 	scripts/maint/checkOptionDocs.pl
-	scripts/maint/updateVersions.pl
 ])
 
 if test "x$asciidoc" = "xtrue" && test "$ASCIIDOC" = "none"; then
diff --git a/doc/HACKING/ReleasingTor.md b/doc/HACKING/ReleasingTor.md
index b5444afa9..b260cdbb1 100644
--- a/doc/HACKING/ReleasingTor.md
+++ b/doc/HACKING/ReleasingTor.md
@@ -131,13 +131,9 @@ new Tor release:
 === III. Making the source release.
 
 1. In `maint-0.?.x`, bump the version number in `configure.ac` and run
-   `perl scripts/maint/updateVersions.pl` to update version numbers in other
+   `make update-versions` to update version numbers in other
    places, and commit.  Then merge `maint-0.?.x` into `release-0.?.x`.
 
-   (NOTE: To bump the version number, edit `configure.ac`, and then run
-   either `make`, or `perl scripts/maint/updateVersions.pl`, depending on
-   your version.)
-
    When you merge the maint branch forward to the next maint branch, or into
    master, merge it with "-s ours" to avoid a needless version bump.
 
diff --git a/scripts/maint/updateVersions.pl.in b/scripts/maint/updateVersions.pl.in
deleted file mode 100755
index 65c51a1f2..000000000
--- a/scripts/maint/updateVersions.pl.in
+++ /dev/null
@@ -1,59 +0,0 @@
-#!/usr/bin/perl -w
-
-$CONFIGURE_IN = '@abs_top_srcdir@/configure.ac';
-$ORCONFIG_H = '@abs_top_srcdir@/src/win32/orconfig.h';
-$TOR_NSI = '@abs_top_srcdir@/contrib/win32build/tor-mingw.nsi.in';
-
-$quiet = 1;
-
-sub demand {
-    my $fn = shift;
-    die "Missing file $fn" unless (-f $fn);
-}
-
-demand($CONFIGURE_IN);
-demand($ORCONFIG_H);
-demand($TOR_NSI);
-
-# extract version from configure.ac
-
-open(F, $CONFIGURE_IN) or die "$!";
-$version = undef;
-while (<F>) {
-    if (/AC_INIT\(\[tor\],\s*\[([^\]]*)\]\)/) {
-	$version = $1;
-	last;
-    }
-}
-die "No version found" unless $version;
-print "Tor version is $version\n" unless $quiet;
-close F;
-
-sub correctversion {
-    my ($fn, $defchar) = @_;
-    undef $/;
-    open(F, $fn) or die "$!";
-    my $s = <F>;
-    close F;
-    if ($s =~ /^$defchar(?:)define\s+VERSION\s+\"([^\"]+)\"/m) {
-	$oldver = $1;
-	if ($oldver ne $version) {
-	    print "Version mismatch in $fn: It thinks that the version is $oldver.  I think it's $version.  Fixing.\n";
-	    $line = $defchar . "define VERSION \"$version\"";
-	    open(F, ">$fn.bak");
-	    print F $s;
-	    close F;
-	    $s =~ s/^$defchar(?:)define\s+VERSION.*?$/$line/m;
-	    open(F, ">$fn");
-	    print F $s;
-	    close F;
-	} else {
-	    print "$fn has the correct version. Good.\n" unless $quiet;
-	}
-    } else {
-	print "Didn't find a version line in $fn -- uh oh.\n";
-    }
-}
-
-correctversion($TOR_NSI, "!");
-correctversion($ORCONFIG_H, "#");
diff --git a/scripts/maint/update_versions.py b/scripts/maint/update_versions.py
new file mode 100755
index 000000000..8067f2c6c
--- /dev/null
+++ b/scripts/maint/update_versions.py
@@ -0,0 +1,133 @@
+#!/usr/bin/env python
+
+from __future__ import print_function
+
+import io
+import os
+import re
+import sys
+import time
+
+def P(path):
+    """
+    Give 'path' as a path relative to the abs_top_srcdir environment
+    variable.
+    """
+    return os.path.join(
+        os.environ.get('abs_top_srcdir', "."),
+        path)
+
+def warn(msg):
+    """
+    Print an warning message.
+    """
+    print("WARNING: {}".format(msg), file=sys.stderr)
+
+def find_version(infile):
+    """
+    Given an open file (or some other iterator of lines) holding a
+    configure.ac file, find the current version line.
+    """
+    for line in infile:
+        m = re.search(r'AC_INIT\(\[tor\],\s*\[([^\]]*)\]\)', line)
+        if m:
+            return m.group(1)
+
+    return None
+
+def update_version_in(infile, outfile, regex, versionline):
+    """
+    Copy every line from infile to outfile. If any line matches 'regex',
+    replace it with 'versionline'.  Return True if any line was changed;
+    false otherwise.
+
+    'versionline' is either a string -- in which case it is used literally,
+    or a function that receives the output of 'regex.match'.
+    """
+    found = False
+    have_changed = False
+    for line in infile:
+        m = regex.match(line)
+        if m:
+            found = True
+            oldline = line
+            if type(versionline) == type(u""):
+                line = versionline
+            else:
+                line = versionline(m)
+            if not line.endswith("\n"):
+                line += "\n"
+            if oldline != line:
+                have_changed = True
+        outfile.write(line)
+
+    if not found:
+        warn("didn't find any version line to replace in {}".format(infile.name))
+
+    return have_changed
+
+def replace_on_change(fname, change):
+    """
+    If "change" is true, replace fname with fname.tmp.  Otherwise,
+    delete fname.tmp.  Log what we're doing to stderr.
+    """
+    if not change:
+        print("No change in {}".format(fname))
+        os.unlink(fname+".tmp")
+    else:
+        print("Updating {}".format(fname))
+        os.rename(fname+".tmp", fname)
+
+
+def update_file(fname,
+                regex,
+                versionline,
+                encoding="utf-8"):
+    """
+    Replace any line matching 'regex' in 'fname' with 'versionline'.
+    Do not modify 'fname' if there are no changes made.  Use the
+    provided encoding to read and write.
+    """
+    with io.open(fname, "r", encoding=encoding) as f, \
+         io.open(fname+".tmp", "w", encoding=encoding) as outf:
+        have_changed = update_version_in(f, outf, regex, versionline)
+
+    replace_on_change(fname, have_changed)
+
+# Find out our version
+with open("configure.ac") as f:
+    version = find_version(f)
+
+# If we have no version, we can't proceed.
+if version == None:
+    print("No version found in configure.ac", file=sys.stderr())
+    sys.exit(1)
+
+print("The version is {}".format(version))
+
+today = time.strftime("%Y-%m-%d", time.gmtime())
+
+# In configure.ac, we replace the definition of APPROX_RELEASE_DATE
+# with "{today} for {version}", but only if the version does not match
+# what is already there.
+def replace_fn(m):
+    if m.group(1) != version:
+        # The version changed -- we change the date.
+        return u'AC_DEFINE(APPROX_RELEASE_DATE, ["{}"], # for {}'.format(today, version)
+    else:
+        # No changes.
+        return m.group(0)
+update_file(P("configure.ac"),
+            re.compile(r'AC_DEFINE\(APPROX_RELEASE_DATE.* for (.*)'),
+            replace_fn)
+
+# In tor-mingw.nsi.in, we replace the definition of VERSION.
+update_file(P("contrib/win32build/tor-mingw.nsi.in"),
+            re.compile(r'!define VERSION .*'),
+            u'!define VERSION "{}"'.format(version),
+            encoding="iso-8859-1")
+
+# In src/win32/orconfig.h, we replace the definition of VERSION.
+update_file(P("src/win32/orconfig.h"),
+            re.compile(r'#define VERSION .*'),
+            u'#define VERSION "{}"'.format(version))





More information about the tor-commits mailing list