331 lines
9.5 KiB
Python
331 lines
9.5 KiB
Python
# -*- test-case-name: twisted.scripts.test.test_tap2rpm -*-
|
|
# Copyright (c) Twisted Matrix Laboratories.
|
|
# See LICENSE for details.
|
|
|
|
import sys, os, shutil, time, glob
|
|
import subprocess
|
|
import tempfile
|
|
import tarfile
|
|
from StringIO import StringIO
|
|
import warnings
|
|
|
|
from twisted.python import usage, log, versions, deprecate
|
|
|
|
|
|
#################################
|
|
# data that goes in /etc/inittab
|
|
initFileData = '''\
|
|
#!/bin/sh
|
|
#
|
|
# Startup script for a Twisted service.
|
|
#
|
|
# chkconfig: - 85 15
|
|
# description: Start-up script for the Twisted service "%(tap_file)s".
|
|
|
|
PATH=/usr/bin:/bin:/usr/sbin:/sbin
|
|
|
|
pidfile=/var/run/%(rpm_file)s.pid
|
|
rundir=/var/lib/twisted-taps/%(rpm_file)s/
|
|
file=/etc/twisted-taps/%(tap_file)s
|
|
logfile=/var/log/%(rpm_file)s.log
|
|
|
|
# load init function library
|
|
. /etc/init.d/functions
|
|
|
|
[ -r /etc/default/%(rpm_file)s ] && . /etc/default/%(rpm_file)s
|
|
|
|
# check for required files
|
|
if [ ! -x /usr/bin/twistd ]
|
|
then
|
|
echo "$0: Aborting, no /usr/bin/twistd found"
|
|
exit 0
|
|
fi
|
|
if [ ! -r "$file" ]
|
|
then
|
|
echo "$0: Aborting, no file $file found."
|
|
exit 0
|
|
fi
|
|
|
|
# set up run directory if necessary
|
|
if [ ! -d "${rundir}" ]
|
|
then
|
|
mkdir -p "${rundir}"
|
|
fi
|
|
|
|
|
|
case "$1" in
|
|
start)
|
|
echo -n "Starting %(rpm_file)s: twistd"
|
|
daemon twistd \\
|
|
--pidfile=$pidfile \\
|
|
--rundir=$rundir \\
|
|
--%(twistd_option)s=$file \\
|
|
--logfile=$logfile
|
|
status %(rpm_file)s
|
|
;;
|
|
|
|
stop)
|
|
echo -n "Stopping %(rpm_file)s: twistd"
|
|
kill `cat "${pidfile}"`
|
|
status %(rpm_file)s
|
|
;;
|
|
|
|
restart)
|
|
"${0}" stop
|
|
"${0}" start
|
|
;;
|
|
|
|
*)
|
|
echo "Usage: ${0} {start|stop|restart|}" >&2
|
|
exit 1
|
|
;;
|
|
esac
|
|
|
|
exit 0
|
|
'''
|
|
|
|
#######################################
|
|
# the data for creating the spec file
|
|
specFileData = '''\
|
|
Summary: %(description)s
|
|
Name: %(rpm_file)s
|
|
Version: %(version)s
|
|
Release: 1
|
|
License: Unknown
|
|
Group: Networking/Daemons
|
|
Source: %(tarfile_basename)s
|
|
BuildRoot: %%{_tmppath}/%%{name}-%%{version}-root
|
|
Requires: /usr/bin/twistd
|
|
BuildArch: noarch
|
|
|
|
%%description
|
|
%(long_description)s
|
|
|
|
%%prep
|
|
%%setup
|
|
%%build
|
|
|
|
%%install
|
|
[ ! -z "$RPM_BUILD_ROOT" -a "$RPM_BUILD_ROOT" != '/' ] \
|
|
&& rm -rf "$RPM_BUILD_ROOT"
|
|
mkdir -p "$RPM_BUILD_ROOT"/etc/twisted-taps
|
|
mkdir -p "$RPM_BUILD_ROOT"/etc/init.d
|
|
mkdir -p "$RPM_BUILD_ROOT"/var/lib/twisted-taps
|
|
cp "%(tap_file)s" "$RPM_BUILD_ROOT"/etc/twisted-taps/
|
|
cp "%(rpm_file)s.init" "$RPM_BUILD_ROOT"/etc/init.d/"%(rpm_file)s"
|
|
|
|
%%clean
|
|
[ ! -z "$RPM_BUILD_ROOT" -a "$RPM_BUILD_ROOT" != '/' ] \
|
|
&& rm -rf "$RPM_BUILD_ROOT"
|
|
|
|
%%post
|
|
/sbin/chkconfig --add %(rpm_file)s
|
|
/sbin/chkconfig --level 35 %(rpm_file)s
|
|
/etc/init.d/%(rpm_file)s start
|
|
|
|
%%preun
|
|
/etc/init.d/%(rpm_file)s stop
|
|
/sbin/chkconfig --del %(rpm_file)s
|
|
|
|
%%files
|
|
%%defattr(-,root,root)
|
|
%%attr(0755,root,root) /etc/init.d/%(rpm_file)s
|
|
%%attr(0660,root,root) /etc/twisted-taps/%(tap_file)s
|
|
|
|
%%changelog
|
|
* %(date)s %(maintainer)s
|
|
- Created by tap2rpm: %(rpm_file)s (%(version)s)
|
|
'''
|
|
|
|
###############################
|
|
class MyOptions(usage.Options):
|
|
optFlags = [['quiet', 'q']]
|
|
optParameters = [
|
|
["tapfile", "t", "twistd.tap"],
|
|
["maintainer", "m", "tap2rpm"],
|
|
["protocol", "p", None],
|
|
["description", "e", None],
|
|
["long_description", "l",
|
|
"Automatically created by tap2rpm"],
|
|
["set-version", "V", "1.0"],
|
|
["rpmfile", "r", None],
|
|
["type", "y", "tap", "type of configuration: 'tap', 'xml, "
|
|
"'source' or 'python'"],
|
|
]
|
|
|
|
compData = usage.Completions(
|
|
optActions={"type": usage.CompleteList(["tap", "xml", "source",
|
|
"python"]),
|
|
"rpmfile": usage.CompleteFiles("*.rpm")}
|
|
)
|
|
|
|
def postOptions(self):
|
|
"""
|
|
Calculate the default values for certain command-line options.
|
|
"""
|
|
# Options whose defaults depend on other parameters.
|
|
if self['protocol'] is None:
|
|
base_tapfile = os.path.basename(self['tapfile'])
|
|
self['protocol'] = os.path.splitext(base_tapfile)[0]
|
|
if self['description'] is None:
|
|
self['description'] = "A TCP server for %s" % (self['protocol'],)
|
|
if self['rpmfile'] is None:
|
|
self['rpmfile'] = 'twisted-%s' % (self['protocol'],)
|
|
|
|
# Values that aren't options, but are calculated from options and are
|
|
# handy to have around.
|
|
self['twistd_option'] = type_dict[self['type']]
|
|
self['release-name'] = '%s-%s' % (self['rpmfile'], self['set-version'])
|
|
|
|
|
|
def opt_unsigned(self):
|
|
"""
|
|
Generate an unsigned rather than a signed RPM. (DEPRECATED; unsigned
|
|
is the default)
|
|
"""
|
|
msg = deprecate.getDeprecationWarningString(
|
|
self.opt_unsigned, versions.Version("Twisted", 12, 1, 0))
|
|
warnings.warn(msg, category=DeprecationWarning, stacklevel=2)
|
|
|
|
# Maintain the -u short flag
|
|
opt_u = opt_unsigned
|
|
|
|
|
|
type_dict = {
|
|
'tap': 'file',
|
|
'python': 'python',
|
|
'source': 'source',
|
|
'xml': 'xml',
|
|
}
|
|
|
|
|
|
|
|
##########################
|
|
def makeBuildDir():
|
|
"""
|
|
Set up the temporary directory for building RPMs.
|
|
|
|
Returns: buildDir, a randomly-named subdirectory of baseDir.
|
|
"""
|
|
tmpDir = tempfile.mkdtemp()
|
|
# set up initial directory contents
|
|
os.makedirs(os.path.join(tmpDir, 'RPMS', 'noarch'))
|
|
os.makedirs(os.path.join(tmpDir, 'SPECS'))
|
|
os.makedirs(os.path.join(tmpDir, 'BUILD'))
|
|
os.makedirs(os.path.join(tmpDir, 'SOURCES'))
|
|
os.makedirs(os.path.join(tmpDir, 'SRPMS'))
|
|
|
|
log.msg(format="Created RPM build structure in %(path)r",
|
|
path=tmpDir)
|
|
return tmpDir
|
|
|
|
|
|
|
|
def setupBuildFiles(buildDir, config):
|
|
"""
|
|
Create files required to build an RPM in the build directory.
|
|
"""
|
|
# Create the source tarball in the SOURCES directory.
|
|
tarballName = "%s.tar" % (config['release-name'],)
|
|
tarballPath = os.path.join(buildDir, "SOURCES", tarballName)
|
|
tarballHandle = tarfile.open(tarballPath, "w")
|
|
|
|
sourceDirInfo = tarfile.TarInfo(config['release-name'])
|
|
sourceDirInfo.type = tarfile.DIRTYPE
|
|
sourceDirInfo.mode = 0755
|
|
tarballHandle.addfile(sourceDirInfo)
|
|
|
|
tapFileBase = os.path.basename(config['tapfile'])
|
|
|
|
initFileInfo = tarfile.TarInfo(
|
|
os.path.join(
|
|
config['release-name'],
|
|
'%s.init' % config['rpmfile'],
|
|
)
|
|
)
|
|
initFileInfo.type = tarfile.REGTYPE
|
|
initFileInfo.mode = 0755
|
|
initFileRealData = initFileData % {
|
|
'tap_file': tapFileBase,
|
|
'rpm_file': config['release-name'],
|
|
'twistd_option': config['twistd_option'],
|
|
}
|
|
initFileInfo.size = len(initFileRealData)
|
|
tarballHandle.addfile(initFileInfo, StringIO(initFileRealData))
|
|
|
|
tapFileHandle = open(config['tapfile'], 'rb')
|
|
tapFileInfo = tarballHandle.gettarinfo(
|
|
arcname=os.path.join(config['release-name'], tapFileBase),
|
|
fileobj=tapFileHandle,
|
|
)
|
|
tapFileInfo.mode = 0644
|
|
tarballHandle.addfile(tapFileInfo, tapFileHandle)
|
|
|
|
tarballHandle.close()
|
|
|
|
log.msg(format="Created dummy source tarball %(tarballPath)r",
|
|
tarballPath=tarballPath)
|
|
|
|
# Create the spec file in the SPECS directory.
|
|
specName = "%s.spec" % (config['release-name'],)
|
|
specPath = os.path.join(buildDir, "SPECS", specName)
|
|
specHandle = open(specPath, "w")
|
|
specFileRealData = specFileData % {
|
|
'description': config['description'],
|
|
'rpm_file': config['rpmfile'],
|
|
'version': config['set-version'],
|
|
'tarfile_basename': tarballName,
|
|
'tap_file': tapFileBase,
|
|
'date': time.strftime('%a %b %d %Y', time.localtime(time.time())),
|
|
'maintainer': config['maintainer'],
|
|
'long_description': config['long_description'],
|
|
}
|
|
specHandle.write(specFileRealData)
|
|
specHandle.close()
|
|
|
|
log.msg(format="Created RPM spec file %(specPath)r",
|
|
specPath=specPath)
|
|
|
|
return specPath
|
|
|
|
|
|
|
|
def run(options=None):
|
|
# parse options
|
|
try:
|
|
config = MyOptions()
|
|
config.parseOptions(options)
|
|
except usage.error, ue:
|
|
sys.exit("%s: %s" % (sys.argv[0], ue))
|
|
|
|
# create RPM build environment
|
|
tmpDir = makeBuildDir()
|
|
specPath = setupBuildFiles(tmpDir, config)
|
|
|
|
# build rpm
|
|
job = subprocess.Popen([
|
|
"rpmbuild",
|
|
"-vv",
|
|
"--define", "_topdir %s" % (tmpDir,),
|
|
"-ba", specPath,
|
|
], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
|
stdout, _ = job.communicate()
|
|
|
|
# If there was a problem, show people what it was.
|
|
if job.returncode != 0:
|
|
print stdout
|
|
|
|
# copy the RPMs to the local directory
|
|
rpmPath = glob.glob(os.path.join(tmpDir, 'RPMS', 'noarch', '*'))[0]
|
|
srpmPath = glob.glob(os.path.join(tmpDir, 'SRPMS', '*'))[0]
|
|
if not config['quiet']:
|
|
print 'Writing "%s"...' % os.path.basename(rpmPath)
|
|
shutil.copy(rpmPath, '.')
|
|
if not config['quiet']:
|
|
print 'Writing "%s"...' % os.path.basename(srpmPath)
|
|
shutil.copy(srpmPath, '.')
|
|
|
|
# remove the build directory
|
|
shutil.rmtree(tmpDir)
|
|
|
|
return [os.path.basename(rpmPath), os.path.basename(srpmPath)]
|