1
0
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:
Marcus Hüwe 2007-07-23 16:03:30 +00:00
parent 7bde6453fd
commit f36e3133c7
2 changed files with 284 additions and 58 deletions

View File

@ -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:

View File

@ -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