enhance version management
When making an official release of scapy, one must:
* Modify the hardcoded version in setup.py and scapy/config.py
* Create a commit with this change
* Create a git tag with the same version
* Run ./setup.py sdist register upload
* Modify the hardcoded version in setup.py and scapy/config.py again to
append '-dev'.
* Create another commit with the modified version.
* Push the 3 commits and the tag.
Not only this is tedious but it is also error prone.
Add utility functions in scapy/__init__.py to determine current version.
If git is available (thus running from a git clone), use "git describe" to
get the current version. Write the version for future reference to a
text file (scapy/VERSION).
If git is not available (running from an installed scapy package) read
the version from the scapy/VERSION file.
This changes the release process as follows:
* Create a git tag on the commit where you want to release
* Run ./setup.py sdist register upload
* Push the tag
This allows to have a single place where the version is managed: git.
Note: change the development versions to X.Y.Z.devN where N is the
number of commits after the last tag. This complies to PEP 440
https://www.python.org/dev/peps/pep-0440/#developmental-releases
Signed-off-by: Robin Jarry <robin.jarry@6wind.com>
diff --git a/.gitignore b/.gitignore
index 52e4e61..820ef36 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,7 @@
*.pyc
*.pyo
+dist/
+build/
+MANIFEST
+*.egg-info/
+scapy/VERSION
diff --git a/MANIFEST.in b/MANIFEST.in
index 7c33aff..880a3f5 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -3,3 +3,4 @@
recursive-include bin *
recursive-include doc *
recursive-include test *
+include scapy/VERSION
diff --git a/README b/README
new file mode 120000
index 0000000..42061c0
--- /dev/null
+++ b/README
@@ -0,0 +1 @@
+README.md
\ No newline at end of file
diff --git a/scapy/__init__.py b/scapy/__init__.py
index 443b367..2be2f82 100644
--- a/scapy/__init__.py
+++ b/scapy/__init__.py
@@ -3,6 +3,8 @@
## Copyright (C) Philippe Biondi <phil@secdev.org>
## This program is published under a GPLv2 license
+from __future__ import with_statement
+
"""
Scapy: create, send, sniff, dissect and manipulate network packets.
@@ -10,6 +12,71 @@
http://www.secdev.org/projects/scapy
"""
+import os
+import re
+import subprocess
+
+
+_SCAPY_PKG_DIR = os.path.dirname(__file__)
+
+def _version_from_git_describe():
+ """
+ Read the version from ``git describe``. It returns the latest tag with an
+ optional suffix if the current directory is not exactly on the tag.
+
+ Example::
+
+ $ git describe --always
+ v2.3.2-346-g164a52c075c8
+
+ The tag prefix (``v``) and the git commit sha1 (``-g164a52c075c8``) are
+ removed if present.
+
+ If the current directory is not exactly on the tag, a ``.devN`` suffix is
+ appended where N is the number of commits made after the last tag.
+
+ Example::
+
+ >>> _version_from_git_describe()
+ '2.3.2.dev346'
+ """
+ p = subprocess.Popen(['git', 'describe', '--always'], cwd=_SCAPY_PKG_DIR,
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+
+ out, err = p.communicate()
+
+ if p.returncode == 0:
+ tag = out.strip()
+ match = re.match(r'^v?(.+?)-(\d+)-g[a-f0-9]+$', tag)
+ if match:
+ # remove the 'v' prefix and add a '.devN' suffix
+ return '%s.dev%s' % (match.group(1), match.group(2))
+ else:
+ # just remove the 'v' prefix
+ return re.sub(r'^v', '', tag)
+ else:
+ raise subprocess.CalledProcessError(p.returncode, err)
+
+def _version():
+ version_file = os.path.join(_SCAPY_PKG_DIR, 'VERSION')
+ try:
+ tag = _version_from_git_describe()
+ # successfully read the tag from git, write it in VERSION for
+ # installation and/or archive generation.
+ with open(version_file, 'w') as f:
+ f.write(tag)
+ return tag
+ except:
+ # failed to read the tag from git, try to read it from a VERSION file
+ try:
+ with open(version_file, 'r') as f:
+ tag = f.read()
+ return tag
+ except:
+ return 'unknown.version'
+
+VERSION = _version()
+
if __name__ == "__main__":
from scapy.main import interact
interact()
diff --git a/scapy/config.py b/scapy/config.py
index 9160a88..f11bcc5 100755
--- a/scapy/config.py
+++ b/scapy/config.py
@@ -9,6 +9,7 @@
import os,time,socket,sys
+from scapy import VERSION
from scapy.data import *
from scapy import base_classes
from scapy import themes
@@ -319,7 +320,7 @@
AS_resolver: choose the AS resolver class to use
extensions_paths: path or list of paths where extensions are to be looked for
"""
- version = "2.3.2-dev"
+ version = VERSION
session = ""
interactive = False
interactive_shell = ""
diff --git a/setup.cfg b/setup.cfg
index b88034e..609d6df 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,2 +1,7 @@
[metadata]
description-file = README.md
+
+[sdist]
+formats=gztar
+owner=root
+group=root
diff --git a/setup.py b/setup.py
index f677142..53bf808 100755
--- a/setup.py
+++ b/setup.py
@@ -47,7 +47,7 @@
setup(
name='scapy',
- version='2.3.2-dev',
+ version=__import__('scapy').VERSION,
packages=[
'scapy',
'scapy/arch',
@@ -62,6 +62,9 @@
],
scripts=SCRIPTS,
data_files=[('share/man/man1', ["doc/scapy.1.gz"])],
+ package_data={
+ 'scapy': ['VERSION'],
+ },
# Metadata
author='Philippe BIONDI',