From 7eb260a9cf6010a74ce8a0f11a19b98d9a95cbb0 Mon Sep 17 00:00:00 2001
From: Zooko O'Whielacronx <zooko@zooko.com>
Date: Wed, 11 Feb 2009 17:18:16 -0700
Subject: [PATCH] versioning: include an "appname" in the application version
 string in the versioning protocol, and make that appname be controlled by
 setup.py It is currently hardcoded in setup.py to be 'allmydata-tahoe'. 
 Ticket #556 is to make it configurable by a runtime command-line argument to
 setup.py: "--appname=foo", but I suddenly wondered if we really wanted that
 and at the same time realized that we don't need that for tahoe-1.3.0
 release, so this patch just hardcodes it in setup.py. setup.py inspects a
 file named 'src/allmydata/_appname.py' and assert that it contains the string
 "__appname__ = 'allmydata-tahoe'", and creates it if it isn't already
 present.  src/allmydata/__init__.py import _appname and reads __appname__
 from it.  The rest of the Python code imports allmydata and inspects
 "allmydata.__appname__", although actually every use it uses
 "allmydata.__full_version__" instead, where "allmydata.__full_version__" is
 created in src/allmydata/__init__.py to be:

__full_version__ = __appname + '-' + str(__version__).

All the code that emits an "application version string" when describing what version of a protocol it supports (introducer server, storage server, upload helper), or when describing itself in general (introducer client), usese allmydata.__full_version__.

This fixes ticket #556 at least well enough for tahoe-1.3.0 release.
---
 setup.py                             | 15 ++++++++++++++-
 src/allmydata/__init__.py            | 12 ++++++++++++
 src/allmydata/client.py              |  2 +-
 src/allmydata/immutable/offloaded.py |  6 +++---
 src/allmydata/introducer/server.py   |  2 +-
 src/allmydata/scripts/common_http.py |  4 ++--
 src/allmydata/storage.py             |  4 ++--
 src/allmydata/test/test_client.py    |  6 +++---
 src/allmydata/test/test_upload.py    |  6 +++---
 9 files changed, 41 insertions(+), 16 deletions(-)

diff --git a/setup.py b/setup.py
index 7183b684..acfd1046 100644
--- a/setup.py
+++ b/setup.py
@@ -302,7 +302,20 @@ class MySdist(sdist.sdist):
 # _auto_deps.install_requires list, which is used in the call to setup() below.
 from _auto_deps import install_requires
 
-setup(name='allmydata-tahoe',
+APPNAME='allmydata-tahoe'
+APPNAMEFILE = os.path.join('src', 'allmydata', '_appname.py')
+APPNAMEFILESTR = "__appname__ = '%s'" % (APPNAME,)
+try:
+    curappnamefilestr = open(APPNAMEFILE, 'rU').read()
+except EnvironmentError:
+    # No file, or unreadable or something, okay then let's try to write one.
+    open(APPNAMEFILE, "w").write(APPNAMEFILESTR)
+else:
+    if curappnamefilestr.strip() != APPNAMEFILESTR:
+        print "Error -- this setup.py file is configured with the 'application name' to be '%s', but there is already a file in place in '%s' which contains the contents '%s'.  If the file is wrong, please remove it and setup.py will regenerate it and write '%s' into it." % (APPNAME, APPNAMEFILE, curappnamefilestr, APPNAMEFILESTR)
+        sys.exit(-1)
+
+setup(name=APPNAME,
       description='secure, decentralized, fault-tolerant filesystem',
       long_description=LONG_DESCRIPTION,
       author='the allmydata.org Tahoe project',
diff --git a/src/allmydata/__init__.py b/src/allmydata/__init__.py
index a442d842..dacb8c6a 100644
--- a/src/allmydata/__init__.py
+++ b/src/allmydata/__init__.py
@@ -15,6 +15,18 @@ except ImportError:
     # not happen very often.
     pass
 
+__appname__ = "unknown"
+try:
+    from _appname import __appname__
+except ImportError:
+    # We're running in a tree that hasn't run "./setup.py".  This shouldn't happen.
+    pass
+
+# __full_version__ is the one that you ought to use when identifying yourself in the
+# "application" part of the Tahoe versioning scheme:
+# http://allmydata.org/trac/tahoe/wiki/Versioning
+__full_version__ = __appname__ + '-' + str(__version__)
+
 hush_pyflakes = __version__
 del hush_pyflakes
 
diff --git a/src/allmydata/client.py b/src/allmydata/client.py
index 10369bdf..73849c98 100644
--- a/src/allmydata/client.py
+++ b/src/allmydata/client.py
@@ -115,7 +115,7 @@ class Client(node.Node, pollmixin.PollMixin):
         self.introducer_furl = self.get_config("client", "introducer.furl")
         ic = IntroducerClient(self.tub, self.introducer_furl,
                               self.nickname,
-                              str(allmydata.__version__),
+                              str(allmydata.__full_version__),
                               str(self.OLDEST_SUPPORTED_VERSION))
         self.introducer_client = ic
         # hold off on starting the IntroducerClient until our tub has been
diff --git a/src/allmydata/immutable/offloaded.py b/src/allmydata/immutable/offloaded.py
index 775b71e6..60a40624 100644
--- a/src/allmydata/immutable/offloaded.py
+++ b/src/allmydata/immutable/offloaded.py
@@ -5,7 +5,7 @@ from twisted.application import service
 from twisted.internet import defer
 from foolscap import Referenceable, DeadReferenceError
 from foolscap.eventual import eventually
-import allmydata
+import allmydata # for __full_version__
 from allmydata import interfaces, storage, uri
 from allmydata.immutable import upload
 from allmydata.immutable.layout import ReadBucketProxy
@@ -132,7 +132,7 @@ class CHKUploadHelper(Referenceable, upload.CHKUploader):
     implements(interfaces.RICHKUploadHelper)
     VERSION = { "http://allmydata.org/tahoe/protocols/helper/chk-upload/v1" :
                  { },
-                "application-version": str(allmydata.__version__),
+                "application-version": str(allmydata.__full_version__),
                 }
 
     def __init__(self, storage_index, helper,
@@ -492,7 +492,7 @@ class Helper(Referenceable, service.MultiService):
     name = "helper"
     VERSION = { "http://allmydata.org/tahoe/protocols/helper/v1" :
                  { },
-                "application-version": str(allmydata.__version__),
+                "application-version": str(allmydata.__full_version__),
                 }
     chk_upload_helper_class = CHKUploadHelper
     MAX_UPLOAD_STATUSES = 10
diff --git a/src/allmydata/introducer/server.py b/src/allmydata/introducer/server.py
index 3005b54d..5e519533 100644
--- a/src/allmydata/introducer/server.py
+++ b/src/allmydata/introducer/server.py
@@ -49,7 +49,7 @@ class IntroducerService(service.MultiService, Referenceable):
     name = "introducer"
     VERSION = { "http://allmydata.org/tahoe/protocols/introducer/v1":
                  { },
-                "application-version": str(allmydata.__version__),
+                "application-version": str(allmydata.__full_version__),
                 }
 
     def __init__(self, basedir="."):
diff --git a/src/allmydata/scripts/common_http.py b/src/allmydata/scripts/common_http.py
index c654927b..0c7680e2 100644
--- a/src/allmydata/scripts/common_http.py
+++ b/src/allmydata/scripts/common_http.py
@@ -1,7 +1,7 @@
 
 from cStringIO import StringIO
 import urlparse, httplib
-import allmydata # for __version__
+import allmydata # for __full_version__
 
 # copied from twisted/web/client.py
 def parse_url(url, defaultPort=None):
@@ -44,7 +44,7 @@ def do_http(method, url, body=""):
         raise ValueError("unknown scheme '%s', need http or https" % scheme)
     c.putrequest(method, path)
     c.putheader("Hostname", host)
-    c.putheader("User-Agent", "tahoe_cli/%s" % allmydata.__version__)
+    c.putheader("User-Agent", "tahoe_cli/%s" % allmydata.__full_version__)
     c.putheader("Connection", "close")
 
     old = body.tell()
diff --git a/src/allmydata/storage.py b/src/allmydata/storage.py
index e2fbb4f8..ac6de53c 100644
--- a/src/allmydata/storage.py
+++ b/src/allmydata/storage.py
@@ -8,7 +8,7 @@ from allmydata.interfaces import RIStorageServer, RIBucketWriter, \
      RIBucketReader, BadWriteEnablerError, IStatsProducer
 from allmydata.util import base32, fileutil, idlib, log, time_format
 from allmydata.util.assertutil import precondition
-import allmydata # for __version__
+import allmydata # for __full_version__
 
 class DataTooLargeError(Exception):
     pass
@@ -968,7 +968,7 @@ class StorageServer(service.MultiService, Referenceable):
                       "tolerates-immutable-read-overrun": True,
                       "delete-mutable-shares-with-zero-length-writev": True,
                       },
-                    "application-version": str(allmydata.__version__),
+                    "application-version": str(allmydata.__full_version__),
                     }
         return version
 
diff --git a/src/allmydata/test/test_client.py b/src/allmydata/test/test_client.py
index 099c40a7..f878101a 100644
--- a/src/allmydata/test/test_client.py
+++ b/src/allmydata/test/test_client.py
@@ -174,12 +174,12 @@ class Basic(unittest.TestCase):
         ss = c.getServiceNamed("storage")
         verdict = ss.remote_get_version()
         self.failUnlessEqual(verdict["application-version"],
-                             str(allmydata.__version__))
+                             str(allmydata.__full_version__))
         self.failIfEqual(str(allmydata.__version__), "unknown")
-        self.failUnless("." in str(allmydata.__version__),
+        self.failUnless("." in str(allmydata.__full_version__),
                         "non-numeric version in '%s'" % allmydata.__version__)
         all_versions = allmydata.get_package_versions_string()
-        self.failUnless("allmydata" in all_versions)
+        self.failUnless("allmydata-tahoe" in all_versions)
         log.msg("tahoe versions: %s" % all_versions)
         # also test stats
         stats = c.get_stats()
diff --git a/src/allmydata/test/test_upload.py b/src/allmydata/test/test_upload.py
index 42c56101..8ed01e2c 100644
--- a/src/allmydata/test/test_upload.py
+++ b/src/allmydata/test/test_upload.py
@@ -7,7 +7,7 @@ from twisted.python import log
 from twisted.internet import defer
 from foolscap import eventual
 
-import allmydata
+import allmydata # for __full_version__
 from allmydata import uri, monitor
 from allmydata.immutable import upload
 from allmydata.interfaces import IFileURI, FileTooLargeError, NotEnoughSharesError
@@ -84,12 +84,12 @@ class FakeStorageServer:
         self.queries = 0
         self.version = { "http://allmydata.org/tahoe/protocols/storage/v1" :
                          { "maximum-immutable-share-size": 2**32 },
-                         "application-version": str(allmydata.__version__),
+                         "application-version": str(allmydata.__full_version__),
                          }
         if mode == "small":
             self.version = { "http://allmydata.org/tahoe/protocols/storage/v1" :
                              { "maximum-immutable-share-size": 10 },
-                             "application-version": str(allmydata.__version__),
+                             "application-version": str(allmydata.__full_version__),
                              }
 
 
-- 
2.45.2