"""P4Python - Python interface to Perforce API
Perforce is the fast SCM system at www.perforce.com.
This package provides a simple interface from Python wrapping the
Perforce C++ API to gain performance and ease of coding.
Similar to interfaces available for Ruby and Perl.
"""
classifiers = """\
Development Status :: 5 - Production/Stable
Intended Audience :: Developers
License :: Freely Distributable
Programming Language :: Python
Topic :: Software Development :: Libraries :: Python Modules
Topic :: Software Development :: Version Control
Topic :: Software Development
Topic :: Utilities
Operating System :: Microsoft :: Windows
Operating System :: Unix
"""
# Customisations needed to use to build:
# 1. Set directory for p4api in setup.cfg
# See notes in P4API documentation for building with API on different
# platforms:
# http://www.perforce.com/perforce/doc.current/manuals/p4api/02_clientprog.html
from distutils.core import setup, Extension
import ConfigParser
import os, os.path, sys, re, shutil, stat
from platform import uname
# Fix for older versions of Python
if sys.version_info < (2, 3):
_setup = setup
def setup(**kwargs):
if kwargs.has_key("classifiers"):
del kwargs["classifiers"]
_setup(**kwargs)
class VersionInfo:
def __init__(self, p4ApiDir):
self.release_year = None
self.release_version = None
self.release_special = None
self.patchlevel = None
self.suppdate_year = None
self.suppdate_month = None
self.suppdate_day = None
releasePattern = re.compile("RELEASE\s+=\s+(?P<year>\d+)\s+(?P<version>\d+)\s*(?P<special>\w+)?")
patchlevelPattern = re.compile("PATCHLEVEL\s+=\s(?P<level>\d+)")
suppdatePattern = re.compile("SUPPDATE\s+=\s(?P<year>\d+)\s+(?P<month>\d+)\s+(?P<day>\d+)")
self.patterns=[]
self.patterns.append((releasePattern, self.handleRelease))
self.patterns.append((patchlevelPattern, self.handlePatchlevel))
self.patterns.append((suppdatePattern, self.handleSuppDate))
verFile = os.path.join(p4ApiDir, "sample", "Version")
if not os.path.exists(verFile):
verFile = os.path.join(p4ApiDir, "Version")
input = open(verFile)
for line in input:
for pattern, handler in self.patterns:
m = pattern.match(line)
if m:
handler(**m.groupdict())
input.close()
def handleRelease(self, year=0, version=0, special=''):
self.release_year = year
self.release_version = version
self.release_special = special
def handlePatchlevel(self, level=0):
self.patchlevel = level
def handleSuppDate(self, year=0, month=0, day=0):
self.suppdate_year = year
self.suppdate_month = month
self.suppdate_day = day
def getP4Version(self):
return "%s.%s" % (self.release_year, self.release_version)
def getFullP4Version(self):
version = "%s.%s" % (self.release_year, self.release_version)
if self.release_special:
version += ".%s" % self.release_special
return version
doclines = __doc__.split("\n")
NAME = "P4Python"
VERSION = "2007.3"
PY_MODULES = ["P4"]
P4_API_DIR = "p4api"
DESCRIPTION=doclines[0]
AUTHOR="Perforce Software Inc"
MAINTAINER="Perforce Software Inc"
AUTHOR_EMAIL="support@perforce.com"
MAINTAINER_EMAIL="support@perforce.com"
LICENSE="LICENSE.txt"
URL="http://www.perforce.com"
KEYWORDS="Perforce perforce P4Python"
P4_CONFIG_SECTION="p4python_config"
P4_CONFIG_P4APIDIR="p4_api"
P4_DOC_RELNOTES="../p4-doc/user/p4pythonnotes.txt"
P4_RELNOTES="RELNOTES.txt"
def copyReleaseNotes():
"""Copies the relnotes from the doc directory to the local directory if they exist
Returns True if the release notes were copied, otherwise False
"""
if os.path.exists(P4_DOC_RELNOTES):
try:
shutil.copy(P4_DOC_RELNOTES, P4_RELNOTES)
return True
except Exception, e:
print e
return False
else:
return False
def deleteReleaseNotes():
"""Removes RELNOTES.txt from the current directory again"""
os.chmod(P4_RELNOTES, stat.S_IWRITE)
os.remove(P4_RELNOTES)
class PlatformInfo:
def __init__(self, apiVersion, releaseVersion):
self.libraries=None
self.extra_compile_args=None
self.define_macros=None
self.extra_link_args=None
if os.name == "nt":
self.ID_OS=self.inStrStr("NTX86")
self.ID_REL=self.inStrStr(releaseVersion.getFullP4Version())
self.ID_PATCH=self.inStrStr(releaseVersion.patchlevel)
self.ID_API=self.inStrStr(apiVersion.getP4Version())
self.ID_Y=self.inStrStr(releaseVersion.suppdate_year)
self.ID_M=self.inStrStr(releaseVersion.suppdate_month)
self.ID_D=self.inStrStr(releaseVersion.suppdate_day)
self.libraries=["oldnames", "wsock32", "advapi32", # MSVC libs
"libclient", "librpc", "libsupp"] # P4API libs
self.extra_compile_args=["/DOS_NT", "/DMT", "/DCASE_INSENSITIVE"]
self.extra_link_args=["/NODEFAULTLIB:libcmt"]
elif os.name == "posix":
self.libraries=["client", "rpc", "supp"] # P4API libs
self.extra_compile_args = []
# it is UNIX, but which one? Let's ask uname()
# details later
unameOut = uname()
if unameOut[0] == "Linux":
unix = "LINUX"
release = unameOut[2][0:1] + unameOut[2][2:3]
platform = self.architecture(unameOut[4])
elif unameOut[0] == "Darwin":
unix = "MACOSX"
release = "104"
platform = self.architecture(unameOut[4])
elif unameOut[0] == "SunOS":
unix = "SUNSOLARIS"
release = re.match("5.(\d+)", unameOut[2]).group(1)
platform = self.architecture(unameOut[4])
elif unameOut[0] == 'FreeBSD':
unix = "FREEBSD"
release = unameOut[2][0]
if release == '5':
release += unameOut[2][2]
platform = self.architecture(unameOut[4])
self.ID_OS = self.inStr(unix + release + platform)
self.ID_REL=self.inStr(releaseVersion.getFullP4Version())
self.ID_PATCH=self.inStr(releaseVersion.patchlevel)
self.ID_API=self.inStr(apiVersion.getP4Version())
self.ID_Y=self.inStr(releaseVersion.suppdate_year)
self.ID_M=self.inStr(releaseVersion.suppdate_month)
self.ID_D=self.inStr(releaseVersion.suppdate_day)
self.extra_compile_args.append("-DOS_" + unix)
self.extra_compile_args.append("-DOS_" + unix + release)
self.extra_compile_args.append("-DOS_" + unix + platform)
self.extra_compile_args.append("-DOS_" + unix + release + platform)
self.define_macros = [('ID_OS', self.ID_OS),
('ID_REL', self.ID_REL),
('ID_PATCH', self.ID_PATCH),
('ID_API', self.ID_API),
('ID_Y', self.ID_Y),
('ID_M', self.ID_M),
('ID_D', self.ID_D)]
def inStr(self, str):
return '"' + str + '"'
def inStrStr(self, str):
return '"\\"' + str + '\\""'
def architecture(self, str):
if str == 'x86_64':
return "X86_64"
elif re.match('i.86', str):
return "X86"
elif str == 'i86pc':
return "X86"
elif str == 'Power Macintosh':
return 'PPC'
elif str == 'powerpc':
return 'PPC'
elif str == 'amd64':
return 'X86_64'
elif str == 'sparc':
return 'SPARC'
def do_setup():
config = ConfigParser.ConfigParser()
config.read('setup.cfg')
p4_api_dir = None
if config.has_section(P4_CONFIG_SECTION):
if config.has_option(P4_CONFIG_SECTION, P4_CONFIG_P4APIDIR):
p4_api_dir = config.get(P4_CONFIG_SECTION, P4_CONFIG_P4APIDIR)
if not p4_api_dir:
print "Error: %s section in setup.cfg needs option %s set to the directory containing the perforce API!" % (
P4_CONFIG_SECTION, P4_CONFIG_P4APIDIR)
sys.exit(100)
try:
apiVersion = VersionInfo(p4_api_dir)
releaseVersion = VersionInfo(".")
except IOError:
print "Cannot find Version file in API dir or distribution dir."
print "API path = ", p4_api_dir
exit(1)
ryear = int(apiVersion.release_year)
rversion = int(apiVersion.release_version)
if (ryear < 2007) or (ryear == 2007 and rversion < 3):
print "API Release %s.%s not supported. Minimum requirement is 2007.3." % (ryear, rversion)
print "Please download a more recent API release from the Perforce ftp site."
exit(1)
else:
print "API Release %s.%s" % (ryear, rversion)
inc_path = [p4_api_dir, os.path.join(p4_api_dir, "include", "p4")]
lib_path = [p4_api_dir, os.path.join(p4_api_dir, "lib")]
info = PlatformInfo(apiVersion, releaseVersion)
setup(name=NAME,
version=VERSION,
description=DESCRIPTION,
author=AUTHOR,
author_email=AUTHOR_EMAIL,
maintainer=MAINTAINER,
maintainer_email=MAINTAINER_EMAIL,
license=LICENSE,
url=URL,
keywords=KEYWORDS,
classifiers = filter(None, classifiers.split("\n")),
long_description = "\n".join(doclines[2:]),
py_modules=PY_MODULES,
ext_modules=[Extension("P4API", ["P4API.cpp", "PythonClientAPI.cpp",
"PythonClientUser.cpp", "SpecMgr.cpp",
"P4Result.cpp"],
include_dirs = inc_path,
library_dirs = lib_path,
libraries = info.libraries,
extra_compile_args = info.extra_compile_args,
define_macros = info.define_macros,
extra_link_args = info.extra_link_args
)])
if __name__ == "__main__":
# The following is a hack to ensure that the RELNOTES.txt are copied from the doc
# directory and removed again after the distribution is built
copied = False
if 'sdist' in sys.argv:
copied = copyReleaseNotes()
do_setup()
if copied:
deleteReleaseNotes()