From rPath Wiki
#!/usr/bin/python
#
# Copyright 2005 Tim Gerla
# Copyright 2006 Stu Gott
#
# This program is distributed under the terms of the Common Public License,
# version 1.0. A copy of this license should have been distributed with this
# source file in a file called LICENSE. If it is not present, the license
# is always available at http://www.opensource.org/licenses/cpl.php.
#
# This program is distributed in the hope that it will be useful, but
# without any waranty; without even the implied warranty of merchantability
# or fitness for a particular purpose. See the Common Public License for
# full details.
#
#
# Original code by Tim Gerla
# Extensively modifed by Stu Gott
#
import os
import tempfile
import re
import subprocess
import sys
import urllib2
from urlparse import urlparse
from conary.lib import util
sys.excepthook = util.genExcepthook()
unpackerMap = {
'.tar.gz' : 'gunzip',
'.tgz' : 'gunzip',
'.tar.bz2': 'bunzip2',
'.zip' : 'unzip'
}
recipeTemplates = {
'auto': """class %(capname)s(AutoPackageRecipe):
name = '%(name)s'
version = '%(version)s'
def unpack(r):
r.addArchive('%(url)s')""",
'distutils': """class %(capname)s(PackageRecipe):
name = '%(name)s'
version = '%(version)s'
def setup(r):
r.addArchive('%(url)s')
r.Run('python setup.py build')
r.Run('python setup.py install --root=%%(destdir)s')""",
'Makefile' : """class %(capname)s(PackageRecipe):
name = '%(name)s'
version = '%(version)s'
def setup(r):
r.addArchive('%(url)s')
r.Make()
r.MakeInstall()"""
}
configMap = {
'configure' : ('autoconf configure script', 'auto'),
'setup.py' : ('Python disutils script', 'distutils'),
'install' : ('custom install script', 'auto'),
'install.sh' : ('custom install script', 'auto'),
'Makefile' : ('Makefile', 'Makefile')
}
# number of args past command line switch to be assigned to given local var.
cmdlnArgs = {'context' : 1, 'archive' : 1, 'help' : 0, 'error': 0}
cmdlnAlias = {'c' : 'context', 'a' : 'archive', 'h' : 'help'}
def parseCmdLine():
options = dict([(x, None) for x in cmdlnArgs.keys()])
index = 1
while index < len(sys.argv):
token = sys.argv[index]
if token.startswith('-') and (len(token) > 1) and token[1] != '-':
if token[1:] in cmdlnAlias:
token = '--' + cmdlnAlias[token[1:]]
else:
options['error'] = True
index += 1
continue
if token.startswith('--'):
stripTok = token[2:]
if stripTok not in cmdlnArgs:
options['error'] = True
index += 1
else:
if not cmdlnArgs[stripTok]:
options[stripTok] = True
elif cmdlnArgs[stripTok] == 1:
if index + 1 == len(sys.argv) or \
sys.argv[index + 1].startswith('-'):
options['error'] = True
else:
options[stripTok] = sys.argv[index + 1]
else:
if index + 1 + cmdlnArgs[stripTok] >= len(sys.argv) or \
[x for x in sys.argv[index + 1: index + 1 + \
cmdlnArgs[stripTok]] if \
x.startswith('-')]:
options['error'] = True
else:
options[stripTok] = sys.argv[index + 1: index + 1 + \
cmdlnArgs[stripTok]]
index += cmdlnArgs[stripTok] + 1
else:
options['archive'] = token
index += 1
options['error'] = options['error'] or not options['archive']
# replace any hyphenated arg with studly-caps form
for key in options:
if '-' in key:
newKey = key[0] + \
''.join([x.capitalize() for x in key.split('-')])[1:]
options[newKey] = options[key]
del options[key]
return options
locals().update(parseCmdLine())
if help or error:
if help:
out = sys.stdout
retCode = 0
else:
out = sys.stderr
retCode = 1
print >> out, "Usage:", sys.argv[0], "[--context <context>] <archive>"
print >> out, " Make a recipe or conary package in current directory.\n"
print >> out, " * archive is a full URL to package.\n"
print >> out, " * context is optional."
print >> out, " if not defined: a recipe will be created."
print >> out, " if defined: context will be used to make a package."
sys.exit(retCode)
ext = None
for suffix in unpackerMap.keys():
if archive.upper().endswith(suffix.upper()):
# use case insensitive extension matching
ext = archive[-1 * len(suffix):]
unpack = unpackerMap[suffix]
break
if not ext:
print >> sys.stderr, "Cannot parse archive. Unknown file extension."
print >> sys.stderr, sys.argv[0], "only knows about", \
', '.join(unpackerMap.keys())
sys.exit(1)
try:
fd, name = tempfile.mkstemp(suffix = ext, prefix = 'cvc_make')
tmpFn = name
os.close(fd)
f = file(name, "w")
print "Fetching %s as %s" % (archive, name)
url = urllib2.urlopen(sys.argv[1])
f.write(url.read())
f.close()
outputDir = tempfile.mkdtemp(prefix = 'cvc_make')
if unpack == 'unzip':
cmd = "%s %s -d %s" % (unpack, name, outputDir)
else:
cmd = "%s -d -c < %s | tar -C %s -xSf -" % (unpack, name, outputDir)
print "+", cmd
os.system(cmd)
configureScript = None
for path in os.listdir(outputDir):
if os.path.isdir(os.path.join(outputDir, path)):
for configure in configMap.keys():
if os.path.exists(os.path.join(outputDir, path, configure)):
configureScript = configure
break
found = False
for config in configMap.keys():
if configureScript == config:
print "Detected %s." % configMap[config][0]
recipeTemplate = recipeTemplates[configMap[config][1]]
found = True
break
if not found:
print "Failed to find a reasonable configure script!"
sys.exit(1)
pkgname = os.path.basename(urlparse(archive.split(ext)[0])[2])
m = re.match("(.+)-(\d[^-]*)", pkgname)
assert m, "Can't parse package name and version."
name, version = m.groups()
print "Package name: %s, version %s" % (name, version)
archive = archive.replace(name, "%(name)s")
archive = archive.replace(version, "%(version)s")
capname = ''.join([x for x in name.title() if x.isalnum() or x == '_'])
if capname[0].isdigit():
capname = '_' + capname
macros = {'name': name,
'version': version,
'url': archive,
'capname': capname}
recipeFN = '%s.recipe' % name
if recipeFN in os.listdir('.'):
print "removing stale recipe"
os.unlink(recipeFN)
print "Creating %s.recipe" % name
recipeFile = file(recipeFN, 'w')
print >> recipeFile, recipeTemplate % macros
recipeFile.close()
if context:
print "Creating %s package" % name
if name in os.listdir('.'):
util.rmtree(name)
os.system('cvc newpkg %s --context %s' % (name, context))
os.system('mv %s %s' % (recipeFN, name))
os.chdir(name)
os.system('cvc context %s' % context)
os.system('cvc add %s' % recipeFN)
os.chdir('..')
finally:
try:
os.unlink(tmpFn)
except:
pass
try:
util.rmtree(outputDir)
except:
pass