mirror of
https://github.com/openSUSE/osc.git
synced 2024-11-10 06:46:15 +01:00
- added new importfromsrcpkg command:
* now a package can be imported from a src.rpm * thanks to Peter for his is_rpm() and is_srcrpm() methods - split out some methods into smaller ones (so they can be reused for other tasks) - added some new methods for unpacking a src.rpm - changed read_meta_from_spec() method to be more flexible (it is possible to specify the tags and sections).
This commit is contained in:
parent
7bde6453fd
commit
f36e3133c7
@ -776,7 +776,6 @@ class Osc(cmdln.Cmdln):
|
||||
osc add FILE [FILE...]
|
||||
${cmd_option_list}
|
||||
"""
|
||||
|
||||
if not args:
|
||||
print >>sys.stderr, 'Missing argument.'
|
||||
self.do_help([None, 'add'])
|
||||
@ -1656,6 +1655,89 @@ class Osc(cmdln.Cmdln):
|
||||
else:
|
||||
print 'No matches found for \'%s\' in %ss' % (args[0], kind)
|
||||
|
||||
@cmdln.option('-p', '--project', metavar='project',
|
||||
help='specify a project name')
|
||||
@cmdln.option('-n', '--name', metavar='name',
|
||||
help='specify a package name')
|
||||
@cmdln.option('-t', '--title', metavar='title',
|
||||
help='set a title')
|
||||
@cmdln.option('-d', '--description', metavar='description',
|
||||
help='set the description of the package')
|
||||
def do_importsrcpkg(self, subcmd, opts, *args):
|
||||
"""${cmd_name}: import a new package from a src.rpm
|
||||
|
||||
A new package dir will be created inside the project dir
|
||||
(if no project is specified and the current working dir is a
|
||||
project dir the package will be created in this project). If
|
||||
the package does not exist on the server it will be created
|
||||
too otherwise the meta data of the existing package will be
|
||||
updated (<title /> and <description />).
|
||||
The src.rpm will be extracted into the package dir.
|
||||
|
||||
usage:
|
||||
osc importsrcpkg /path/to/src.rpm <options>
|
||||
${cmd_option_list}
|
||||
"""
|
||||
import glob
|
||||
|
||||
if len(args) < 1:
|
||||
print >>sys.stderr, 'too few arguments'
|
||||
sys.exit(1)
|
||||
elif len(args) > 1:
|
||||
print >>sys.stderr, 'too many arguments'
|
||||
sys.exit(1)
|
||||
else:
|
||||
srpm = os.path.abspath(args[0])
|
||||
|
||||
if opts.project:
|
||||
project_dir = opts.project
|
||||
else:
|
||||
project_dir = os.getcwd()
|
||||
|
||||
if not is_project_dir(project_dir):
|
||||
print >>sys.stderr, 'project dir \'%s\' does not exist' % project
|
||||
sys.exit(1)
|
||||
else:
|
||||
project = store_read_project(project_dir)
|
||||
|
||||
if not opts.name or not opts.description or not opts.title:
|
||||
title, pac, descr = ( v for k, v in \
|
||||
data_from_srcrpm(srpm, 'Name:', 'Summary:', '%description').iteritems() )
|
||||
|
||||
if opts.title:
|
||||
title = opts.title
|
||||
if opts.name:
|
||||
pac = opts.name
|
||||
if opts.description:
|
||||
descr = opts.description
|
||||
|
||||
if not os.path.exists(os.path.join(project_dir, pac)):
|
||||
os.mkdir(os.path.join(project_dir, pac))
|
||||
os.chdir(os.path.join(project_dir, pac))
|
||||
data = meta_exists(metatype='pkg',
|
||||
path_args=(quote_plus(project), quote_plus(pac)),
|
||||
template_args=(pac, conf.config['user']))
|
||||
if data:
|
||||
data = ET.fromstring(''.join(data))
|
||||
data.find('title').text = title
|
||||
data.find('description').text = ''.join(descr)
|
||||
data = ET.tostring(data)
|
||||
else:
|
||||
print >>sys.stderr, 'error - cannot get meta data'
|
||||
sys.exit(1)
|
||||
edit_meta(metatype='pkg',
|
||||
path_args=(quote_plus(project), quote_plus(pac)),
|
||||
data = data)
|
||||
init_package_dir(conf.config['apiurl'], project, pac, os.path.join(project, pac))
|
||||
unpack_srcrpm(srpm, os.getcwd())
|
||||
print 'Adding files to working copy...'
|
||||
self.do_add(None, {}, *glob.glob('*'))
|
||||
else:
|
||||
print >>sys.stderr, 'error - package already exists'
|
||||
sys.exit(1)
|
||||
|
||||
print 'Package \'%s\' imported successfully' % pac
|
||||
|
||||
# load subcommands plugged-in locally
|
||||
plugin_dirs = ['/var/lib/osc-plugins', os.path.expanduser('~/.osc-plugins')]
|
||||
for plugin_dir in plugin_dirs:
|
||||
|
258
osc/core.py
258
osc/core.py
@ -557,14 +557,9 @@ rev: %s
|
||||
'with --specfile'
|
||||
sys.exit(1)
|
||||
|
||||
summary, descr = read_meta_from_spec(specfile)
|
||||
|
||||
if not summary and not descr:
|
||||
print >>sys.stderr, 'aborting'
|
||||
sys.exit(1)
|
||||
else:
|
||||
self.summary = summary
|
||||
self.descr = descr
|
||||
data = read_meta_from_spec(specfile, 'Summary:', '%description')
|
||||
self.summary = data['Summary:']
|
||||
self.descr = data['%description']
|
||||
|
||||
|
||||
def update_package_meta(self):
|
||||
@ -997,6 +992,40 @@ metatypes = { 'prj': { 'path': 'source/%s/_meta',
|
||||
},
|
||||
}
|
||||
|
||||
def meta_exists(metatype,
|
||||
path_args=None,
|
||||
template_args=None,
|
||||
create_new=True):
|
||||
|
||||
data = None
|
||||
url = make_meta_url(metatype, path_args)
|
||||
try:
|
||||
data = http_GET(url).readlines()
|
||||
except urllib2.HTTPError, e:
|
||||
if e.code == 404:
|
||||
if create_new:
|
||||
data = metatypes[metatype]['template']
|
||||
if template_args:
|
||||
data = data % template_args
|
||||
else:
|
||||
print >>sys.stderr, 'error getting metadata for type \'%s\' at URL \'%s\':' \
|
||||
% (metatype, url)
|
||||
if data:
|
||||
return data
|
||||
else:
|
||||
return None
|
||||
|
||||
def make_meta_url(metatype, path_args=None):
|
||||
if metatype not in metatypes.keys():
|
||||
sys.exit('unknown metatype %s' % metatype)
|
||||
path = metatypes[metatype]['path']
|
||||
|
||||
if path_args:
|
||||
path = path % path_args
|
||||
|
||||
return makeurl(conf.config['apiurl'], [path])
|
||||
|
||||
|
||||
def edit_meta(metatype,
|
||||
path_args=None,
|
||||
data=None,
|
||||
@ -1004,32 +1033,16 @@ def edit_meta(metatype,
|
||||
edit=False,
|
||||
change_is_required=False):
|
||||
|
||||
if metatype not in metatypes.keys():
|
||||
sys.exit('unknown metatype %s' % metatype)
|
||||
|
||||
path = metatypes[metatype]['path']
|
||||
if path_args:
|
||||
path = path % path_args
|
||||
|
||||
url = makeurl(conf.config['apiurl'], [path])
|
||||
|
||||
if not data:
|
||||
try:
|
||||
data = http_GET(url).readlines()
|
||||
except urllib2.HTTPError, e:
|
||||
if e.code == 404:
|
||||
data = metatypes[metatype]['template']
|
||||
if template_args:
|
||||
data = data % template_args
|
||||
else:
|
||||
print >>sys.stderr, 'error getting metadata for type \'%s\' at URL \'%s\':' \
|
||||
% (metatype, url)
|
||||
print >>sys.stderr, e
|
||||
sys.exit(1)
|
||||
data = meta_exists(metatype,
|
||||
path_args,
|
||||
template_args,
|
||||
create_new=True)
|
||||
|
||||
if edit:
|
||||
change_is_required = True
|
||||
|
||||
url = make_meta_url(metatype, path_args)
|
||||
f=metafile(url, data, change_is_required)
|
||||
|
||||
if edit:
|
||||
@ -1063,45 +1076,62 @@ def show_upstream_rev(apiurl, prj, pac):
|
||||
return ET.parse(StringIO(''.join(m))).getroot().get('rev')
|
||||
|
||||
|
||||
def read_meta_from_spec(specfile):
|
||||
def read_meta_from_spec(specfile, *args):
|
||||
import codecs, locale
|
||||
"""read Name, Summary and %description from spec file"""
|
||||
"""
|
||||
Read tags and sections from spec file. To read out
|
||||
a tag the passed argument must end with a colon. To
|
||||
read out a section the passed argument must start with
|
||||
a '%'.
|
||||
This method returns a dictionary which contains the
|
||||
requested data.
|
||||
"""
|
||||
|
||||
if not os.path.isfile(specfile):
|
||||
print 'file \'%s\' is not a readable file' % specfile
|
||||
return (None, None)
|
||||
sys.exit(1)
|
||||
|
||||
try:
|
||||
lines = codecs.open(specfile, 'r', locale.getpreferredencoding()).readlines()
|
||||
except UnicodeDecodeError:
|
||||
lines = open(specfile).readlines()
|
||||
|
||||
for line in lines:
|
||||
if line.startswith('Name:'):
|
||||
name = line.split(':')[1].strip()
|
||||
break
|
||||
|
||||
summary = None
|
||||
for line in lines:
|
||||
if line.startswith('Summary:'):
|
||||
summary = line.split(':')[1].strip()
|
||||
break
|
||||
if summary == None:
|
||||
print 'cannot find \'Summary:\' tag'
|
||||
return (None, None)
|
||||
tags = []
|
||||
sections = []
|
||||
spec_data = {}
|
||||
|
||||
descr = []
|
||||
try:
|
||||
start = lines.index('%description\n') + 1
|
||||
except ValueError:
|
||||
print 'cannot find %description'
|
||||
return (None, None)
|
||||
for line in lines[start:]:
|
||||
if line.startswith('%'):
|
||||
break
|
||||
descr.append(line)
|
||||
|
||||
return (summary, descr)
|
||||
for itm in args:
|
||||
if itm.endswith(':'):
|
||||
tags.append(itm)
|
||||
elif itm.startswith('%'):
|
||||
sections.append(itm)
|
||||
else:
|
||||
print >>sys.stderr, 'error - \'%s\' is not a tag nor a section' % itm
|
||||
sys.exit(1)
|
||||
|
||||
for tag in tags:
|
||||
for line in lines:
|
||||
if line.startswith(tag):
|
||||
spec_data[tag] = line.split(':')[1].strip()
|
||||
break
|
||||
if not spec_data.has_key(tag):
|
||||
print >>sys.stderr, 'error - tag \'%s\' does not exist' % tag
|
||||
sys.exit(1)
|
||||
|
||||
for section in sections:
|
||||
try:
|
||||
start = lines.index(section + '\n') + 1
|
||||
except ValueError:
|
||||
print >>sys.stderr, 'error - section \'%s\' does not exist' % section
|
||||
sys.exit(1)
|
||||
data = []
|
||||
for line in lines[start:]:
|
||||
if line.startswith('%'):
|
||||
break
|
||||
data.append(line)
|
||||
spec_data[section] = data
|
||||
|
||||
return spec_data
|
||||
|
||||
|
||||
def get_user_meta(apiurl, user):
|
||||
@ -1814,3 +1844,117 @@ def search(apiurl, search_list, kind, search_term, verbose = False, exact_matche
|
||||
return result
|
||||
else:
|
||||
return None
|
||||
|
||||
def delete_tmpdir(tmpdir):
|
||||
"""
|
||||
This method deletes a tempdir. This tempdir
|
||||
must be located under /tmp/$DIR. If "tmpdir" is not
|
||||
a valid tempdir it'll return False. If os.unlink() / os.rmdir()
|
||||
throws an exception we will return False too - otherwise
|
||||
True.
|
||||
"""
|
||||
|
||||
# small security checks
|
||||
if os.path.islink(tmpdir):
|
||||
return False
|
||||
elif os.path.abspath(tmpdir) == '/':
|
||||
return False
|
||||
|
||||
head, tail = os.path.split(tmpdir)
|
||||
if not head.startswith('/tmp') or not tail:
|
||||
return False
|
||||
|
||||
if not os.path.isdir(tmpdir):
|
||||
return False
|
||||
|
||||
for dirpath, dirnames, filenames in os.walk(tmpdir, topdown=False):
|
||||
for file in filenames:
|
||||
try:
|
||||
os.unlink(os.path.join(dirpath, file))
|
||||
except:
|
||||
return False
|
||||
for dirname in dirnames:
|
||||
try:
|
||||
os.rmdir(os.path.join(dirpath, dirname))
|
||||
except:
|
||||
return False
|
||||
try:
|
||||
os.rmdir(tmpdir)
|
||||
except:
|
||||
return False
|
||||
return True
|
||||
|
||||
def unpack_srcrpm(srpm, dir, *files):
|
||||
"""
|
||||
This method unpacks the passed srpm into the
|
||||
passed dir. If arguments are passed to the \'files\' tuple
|
||||
only this files will be unpacked.
|
||||
"""
|
||||
if not is_srcrpm(srpm):
|
||||
print >>sys.stderr, 'error - \'%s\' is not a source rpm.' % srpm
|
||||
sys.exit(1)
|
||||
curdir = os.getcwd()
|
||||
if not os.path.isdir(dir):
|
||||
dir = curdir
|
||||
else:
|
||||
os.chdir(dir)
|
||||
cmd = 'rpm2cpio %s | cpio -i %s &> /dev/null' % (srpm, ' '.join(files))
|
||||
ret = os.system(cmd)
|
||||
if ret != 0:
|
||||
print >>sys.stderr, 'error \'%s\' - cannot extract \'%s\'' % (ret, srpm)
|
||||
sys.exit(1)
|
||||
os.chdir(curdir)
|
||||
|
||||
# TODO: is there an easy way to read the 'Name:' directly
|
||||
# from the RPM? (we can't use the rpm lead because this
|
||||
# would also contains the version number and is limited to 65 bytes)
|
||||
def data_from_srcrpm(srpm, *rpmdata):
|
||||
"""
|
||||
This method reads spec file tags and sections
|
||||
from a src.rpm
|
||||
"""
|
||||
import tempfile
|
||||
import glob
|
||||
|
||||
tmpdir = tempfile.mkdtemp(prefix='osc', dir='/tmp')
|
||||
try:
|
||||
unpack_srcrpm(srpm, tmpdir, '*.spec')
|
||||
speclist = glob.glob(os.path.join(tmpdir, '*.spec'))
|
||||
if len(speclist) == 1:
|
||||
data = read_meta_from_spec(os.path.join(tmpdir, speclist[0]), *rpmdata)
|
||||
else:
|
||||
print >>sys.stderr, 'error - cannot read package information from source ' \
|
||||
'rpm (please specify the required data with --title, --name, ' \
|
||||
'--description'
|
||||
sys.exit(1)
|
||||
finally:
|
||||
delete_tmpdir(tmpdir)
|
||||
return data
|
||||
|
||||
def is_rpm(f):
|
||||
"""check if the named file is an RPM package"""
|
||||
try:
|
||||
h = open(f).read(4)
|
||||
except:
|
||||
return False
|
||||
|
||||
if h == '\xed\xab\xee\xdb':
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def is_srcrpm(f):
|
||||
"""check if the named file is a source RPM"""
|
||||
|
||||
if not is_rpm(f):
|
||||
return False
|
||||
|
||||
try:
|
||||
h = open(f).read(8)
|
||||
except:
|
||||
return False
|
||||
|
||||
if h[7] == '\x01':
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
Loading…
Reference in New Issue
Block a user