Skip to content

Commit

Permalink
Initial version
Browse files Browse the repository at this point in the history
  • Loading branch information
sebasmannem committed Oct 16, 2017
1 parent b5ff819 commit 457a818
Showing 2 changed files with 232 additions and 0 deletions.
189 changes: 189 additions & 0 deletions specbuilder
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
#!/usr/bin/env python
import xml.etree.ElementTree as ET
try:
#Python3
from urllib.request import urlopen, urlretrieve
except:
#Python2
from urllib import urlretrieve
import urllib2
def urlopen(url):
request = urllib2.Request(url)
return urllib2.urlopen(request)
import tarfile
import sys
import os.path
import xmltodict
import re
import argparse
from jinja2 import Environment, PackageLoader, select_autoescape, FileSystemLoader
from lxml.html import fromstring, tostring
import subprocess
import json
from datetime import datetime
from traceback import print_exc

setupconfigfilescript = '''
def writesetupconfig(**kwargs):
import json
setupconfig=dict()
for k in kwargs.keys():
try:
#If it is JSON serializable
dummy = json.dumps(kwargs[k])
#Keep it
setupconfig[k] = kwargs[k]
except:
#If not, don't keep it
pass
with open('{0}','w') as f:
f.write(json.dumps(setupconfig))
'''

re_requiresplit = re.compile('([^<>=]*)([<>]?=.*)')
re_setupfile = re.compile('setup\s*\(')
re_setupimport = re.compile('^(\s*)(from\s+(setuptools|distutils.core)\s+import.*setup(,|$)|import\s+(setuptools|distutils.core))')

def get_package(modulename, version=None, template='/tmp/templates/spec.jinja2', buildername='J. Doe', buildermail='[email protected]'):
if version:
url="https://pypi.python.org/pypi?:action=doap&name={0}&version={1}".format(modulename, version)
else:
url="https://pypi.python.org/pypi?:action=doap&name={0}".format(modulename)
handler = urlopen(url)
xmlkeyvals=xmltodict.parse(handler.read())
xmlkeyvals=xmlkeyvals['rdf:RDF']['Project']
if not version:
version = xmlkeyvals['release']['Version']['revision']

pck = { 'name': modulename, 'version': version}
pck['url'] = downloadpage(modulename, version)
pck['filename'] = os.path.basename(pck['url'])
pck['filename'] = pck['filename'].split('#')[0]
pck['path'] = os.path.expanduser('~/rpmbuild/SOURCES/'+pck['filename'])

if not os.path.exists(pck['path']):
urlretrieve(pck['url'], pck['path'])
modulepath = '/tmp/{0}-{1}'.format(modulename, version)
setupconfigfilepath = '{0}/writesetupconfig.py'.format(modulepath, modulename)
setupconfigjsonpath = '{0}/writesetupconfig.json'.format(modulepath, modulename)
if not os.path.exists(modulepath):
tar = tarfile.open(pck['path'], mode='r:gz')
tar.extractall(path="/tmp")
if not os.path.exists(setupconfigfilepath):
setupfile = open('{0}/setup.py'.format(modulepath), 'rb')
setupconfigfile = open(setupconfigfilepath, 'w')
for l in setupfile:
l=l.decode('ascii', 'ignore')
l = re_setupfile.sub('writesetupconfig(',l)
setupconfigfile.write(l)
m = re_setupimport.search(l)
if m:
indent = m.group(1)
for scriptline in setupconfigfilescript.format(setupconfigjsonpath).split('\n'):
setupconfigfile.write(indent+scriptline+'\n')
setupfile.close()
setupconfigfile.close()
if not os.path.exists(setupconfigjsonpath):
writer = subprocess.Popen(['python', '{0}/writesetupconfig.py'.format(modulepath)], cwd=modulepath)
writer.wait()

setupconfig = open(setupconfigjsonpath).read()
if not len(setupconfig):
raise Exception('Error getting setupconfig for {0} - {1}. {2} contains no data...'.format(modulename, version, setupconfigjsonpath))
setupconfig = json.loads(open(setupconfigjsonpath).read())

try:
pck['requires'] = setupconfig['install_requires']
except:
pck['requires'] = []

pck['summary'] = xmlkeyvals['shortdesc']
if 'long_description' in setupconfig:
pck['description'] = description_sanitizer(setupconfig['long_description'])
else:
pck['description'] = description_sanitizer(setupconfig['description'])
pck['spec'] = os.path.expanduser('~/rpmbuild/SPECS/{0}-{1}.spec'.format(modulename, version))
pck['date'] = datetime.now().strftime('%a %b %-d %Y')
pck['buildername'] = buildername
pck['buildermail'] = buildermail
pck['license'] = setupconfig['license']

if not os.path.exists(pck['spec']):
templatepath = os.path.dirname(template)
templatefile = os.path.basename(template)
env = Environment(
loader = FileSystemLoader(templatepath),
autoescape=select_autoescape(['html', 'xml'])
)
template = env.get_template(templatefile)
spec=open(pck['spec'], 'w')
spec.write(template.render(pck))
spec.close()

return pck

def module_versions(modulename):
versionsurl = 'https://pypi.org/project/{0}/#history'.format(modulename)
versionshandler = urlopen(versionsurl)
versionsroot = fromstring(versionshandler.read())
for div in versionsroot.find_class("release__version"):
for l in div.iterlinks():
yield(l[0].text)

def downloadpage(modulename, version):
dlpageurl = 'https://pypi.python.org/pypi/{0}/{1}'.format(modulename, version)
dlpagehandler = urlopen(dlpageurl)
dlpageroot = fromstring(dlpagehandler.read())
tablerows = dlpageroot.xpath("//tr")
for tr in tablerows:
try:
tablecols = tr.xpath("td")
dlurl = tablecols[0].xpath("span/a")[0].attrib['href']
dltype = tablecols[1].text.strip()
if dltype == 'Source':
return dlurl
except:
pass
return None

def description_sanitizer(desc):
desc=desc.encode('ascii', 'ignore').decode()
tag_re = re.compile(':[a-z]+:')
empty_re = re.compile('^\s*$')
empty_count = 0
ret = []
for l in desc.split('\n'):
if '-----' in l:
ret = ret[:-1]
break
elif '>>>' in l:
pass
elif '===' in l:
pass
elif '::' in l:
pass
elif tag_re.search(l):
pass
elif empty_re.search(l):
empty_count += 1
if empty_count == 1:
ret.append(l)
else:
empty_count = 0
ret.append(l)
return '\n'.join(ret)

parser = argparse.ArgumentParser(description='Generate a spec file for a python module')
parser.add_argument('-p', '--package', required=True, help='The python package to generate a spec for')
parser.add_argument('-v', '--version', default=None, help='the version of the module to build a spec for')
parser.add_argument('-t', '--template', default='~/templates/spec.jinja2', help='the jinja2 template to use')
parser.add_argument('-n', '--buildername', default='J. Doe', help='the name of the person who is building')
parser.add_argument('-e', '--buildermail', default='[email protected]', help='the jinja2 template to use')

options = parser.parse_args()
template = os.path.abspath(os.path.expanduser(options.template))
try:
get_package(modulename=options.package, version=options.version, template=template, buildername=options.buildername, buildermail=options.buildermail)
except:
print('Error while building module', options)
print_exc()
43 changes: 43 additions & 0 deletions templates/spec.jinja2
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
%global modname {{name}}
%global modname2 {{name|lower}}

Summary: {{summary}}
Name: python%{python3_pkgversion}-%{modname2}
Version: {{version}}
Release: 1%{?dist}
License: {{license}}
Group: Development/Libraries
Url: https://pypi.python.org/pypi/%{modname}
Source0: %{modname}-%{version}.tar.gz
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-buildroot-%(%{__id_u} -n)
BuildArch: noarch
{% for req in requires %}Requires: python%{python3_pkgversion}-{{req}}
{% endfor%}
BuildRequires: python%{python3_pkgversion}-devel
BuildRequires: python%{python3_pkgversion}-setuptools

%description
{{description}}

%prep
%setup -n %{modname}-%{version} -q

%build
%py3_build

%install
%py3_install

%clean
rm -rf $RPM_BUILD_ROOT

%files
%defattr(-,root,root)
%{python3_sitelib}/%{modname}-%{version}-py%{python3_version}.egg-info
%{python3_sitelib}/%{modname}

%changelog
* {{date}} - {{buildername}} <{{buildermail}}>
- Initial build of this spec
* Mon Oct 9 2017 - Sebastiaan Mannem <sebas@mannem.nl>
- Template

0 comments on commit 457a818

Please sign in to comment.