1
0
mirror of https://github.com/openSUSE/osc.git synced 2025-01-13 17:16:23 +01:00

- add 'edituser' command for editing the metadata of a user account. It tries

to create a user if it doesn't exist yet. A new command 'usermeta' replaces
  'id' respectively 'userid'.
- add preliminary support for doing uploads with a subsequent "commit" request
  (not switched on now, since I want to do more testing on this, and there is
  no way to pass on a commit message yet anyway.)
- add runtime check for build.rpm version, so the rpm package dependencies is
  no longer required
- fix typo introduced last time in the editmeta, deletepac, deleteprj commands
- rewrite the PUT and DELETE request methods to 
  - transparently handle HTTPS 
  - handle path parameters (for commits)
  - send user agent
- rename get_user_id() function to get_user_meta()
- change copyright notice from Peter Poeml to Peter Poeml / Novell Inc.
- fix testsuite
- add CREDITS file
This commit is contained in:
Dr. Peter Poeml 2006-10-12 13:22:56 +00:00
parent 39779ec9bc
commit baafea955b
9 changed files with 175 additions and 108 deletions

5
CREDITS Normal file
View File

@ -0,0 +1,5 @@
There is a number of people who have helped:
Marcus Rueckert - help and countless suggestions
Christoph Thiel - patch enabling build log following.
Adrian Schroeter - one-liner showing how to handle an error ;-)

7
TODO
View File

@ -2,17 +2,10 @@
- implement 'info' command - implement 'info' command
- implement 'mv' command - implement 'mv' command
- editing of user data
<watchlist>
<project name="ASCIIParadize"/>
<project name="crashtest"/>
</watchlist>
- editmeta: the API will return a 500 if the xml is broken... the document - editmeta: the API will return a 500 if the xml is broken... the document
could be presented for editing again in that case could be presented for editing again in that case
- updatepacmetafromspec -- is that useful? - updatepacmetafromspec -- is that useful?
In which form would this be integrated best? In which form would this be integrated best?
- clean up the way how a .oscrc template is being added: at the moment, there
are two places doing this
checkin: checkin:

View File

@ -1,6 +1,6 @@
#!/usr/bin/python #!/usr/bin/python
# Copyright (C) 2006 Peter Poeml. All rights reserved. # Copyright (C) 2006 Peter Poeml / Novell Inc. All rights reserved.
# This program is free software; it may be used, copied, modified # This program is free software; it may be used, copied, modified
# and distributed under the terms of the GNU General Public Licence, # and distributed under the terms of the GNU General Public Licence,
# either version 2, or (at your option) any later version. # either version 2, or (at your option) any later version.

View File

@ -1,6 +1,6 @@
#!/usr/bin/python #!/usr/bin/python
# Copyright (C) 2006 Peter Poeml. All rights reserved. # Copyright (C) 2006 Peter Poeml / Novell Inc. All rights reserved.
# This program is free software; it may be used, copied, modified # This program is free software; it may be used, copied, modified
# and distributed under the terms of the GNU General Public Licence, # and distributed under the terms of the GNU General Public Licence,
# either version 2, or (at your option) any later version. # either version 2, or (at your option) any later version.
@ -134,6 +134,20 @@ usage: osc editmeta FooPrj # edit meta of project 'FooPrj'
edit_meta(project, None) edit_meta(project, None)
def edituser(args):
"""edituser: Edit user meta information
usage: osc edituser <user>
If the named user id does not exist, it will be created.
"""
if not args or len(args) != 1:
user = conf.config['user']
else:
user = args[0]
edit_user_meta(user)
def linkpac(args): def linkpac(args):
""""Link" a package to another package -- possibly cross-project. """"Link" a package to another package -- possibly cross-project.
@ -473,6 +487,8 @@ usage: osc ci # current dir
for filename in p.todo_delete: for filename in p.todo_delete:
p.delete_source_file(filename) p.delete_source_file(filename)
p.to_be_deleted.remove(filename) p.to_be_deleted.remove(filename)
if conf.config['do_commits'] == '1':
p.commit(msg='MESSAGE')
p.update_filesmeta() p.update_filesmeta()
p.write_deletelist() p.write_deletelist()
@ -606,17 +622,17 @@ usage: osc resolved <filename>
p.clear_from_conflictlist(filename) p.clear_from_conflictlist(filename)
def userid(args): def usermeta(args):
"""id: show metadata about user <userid> """usermeta: show metadata about user <userid>
usage: osc id <userid> usage: osc usermeta <userid>
""" """
if not args: if not args:
print 'this command requires at least one argument' print 'this command requires at least one argument'
sys.exit(1) sys.exit(1)
r = get_user_id(args[0]) r = get_user_meta(args[0])
if r: if r:
print ''.join(r) print ''.join(r)
@ -842,6 +858,9 @@ BUILD_ROOT or OSC_BUILD_ROOT overrides the build-root.
import osc.build import osc.build
if not os.path.exists('/usr/lib/build/debsort'):
sys.exit('Error: you need build.rpm with version 2006.6.14 or newer.\nSee http://software.opensuse.org/download/openSUSE:/Tools/')
builddist = os.getenv('BUILD_DIST') builddist = os.getenv('BUILD_DIST')
if builddist: if builddist:
#sys.argv[4] = sys.argv[1] #sys.argv[4] = sys.argv[1]
@ -981,7 +1000,8 @@ cmd_dict = {
help: ['help'], help: ['help'],
buildhistory: ['buildhistory', 'buildhist'], buildhistory: ['buildhistory', 'buildhist'],
linkpac: ['linkpac'], linkpac: ['linkpac'],
userid: ['id'], # <- small difference here usermeta: ['usermeta'],
edituser: ['edituser'],
init: ['init'], # depracated init: ['init'], # depracated
log: ['log'], log: ['log'],
ls: ['ls', 'list'], ls: ['ls', 'list'],

View File

@ -1,6 +1,6 @@
#!/usr/bin/python #!/usr/bin/python
# Copyright (C) 2006 Peter Poeml. All rights reserved. # Copyright (C) 2006 Peter Poeml / Novell Inc. All rights reserved.
# This program is free software; it may be used, copied, modified # This program is free software; it may be used, copied, modified
# and distributed under the terms of the GNU General Public Licence, # and distributed under the terms of the GNU General Public Licence,
# either version 2, or (at your option) any later version. # either version 2, or (at your option) any later version.
@ -56,6 +56,9 @@ DEFAULTS = { 'apisrv': 'api.opensuse.org',
# direct access to "full" tree # direct access to "full" tree
'http://api.opensuse.org/rpm/%(project)s/%(repository)s/_repository/%(buildarch)s/%(name)s', 'http://api.opensuse.org/rpm/%(project)s/%(repository)s/_repository/%(buildarch)s/%(name)s',
], ],
# switched off for now (testing)
'do_commits': '0',
} }
new_conf_template = """ new_conf_template = """

View File

@ -1,6 +1,6 @@
#!/usr/bin/python #!/usr/bin/python
# Copyright (C) 2006 Peter Poeml. All rights reserved. # Copyright (C) 2006 Peter Poeml / Novell Inc. All rights reserved.
# This program is free software; it may be used, copied, modified # This program is free software; it may be used, copied, modified
# and distributed under the terms of the GNU General Public Licence, # and distributed under the terms of the GNU General Public Licence,
# either version 2, or (at your option) any later version. # either version 2, or (at your option) any later version.
@ -97,6 +97,24 @@ HERE
</package> </package>
""" """
new_user_template = """\
<person>
<login>%(user)s</login>
<email>PUT_EMAIL_ADDRESS_HERE</email>
<realname>PUT_REAL_NAME_HERE</realname>
<source_backend>
<host></host>
<port></port>
</source_backend>
<rpm_backend>
<host></host>
<port></port>
</rpm_backend>
<watchlist>
<project name="home:%(user)s"/>
</watchlist>
</person>
"""
buildstatus_symbols = {'succeeded': '.', buildstatus_symbols = {'succeeded': '.',
'disabled': ' ', 'disabled': ' ',
@ -271,10 +289,22 @@ class Package:
# escaping '+' in the URL path (note: not in the URL query string) is # escaping '+' in the URL path (note: not in the URL query string) is
# only a workaround for ruby on rails, which swallows it otherwise # only a workaround for ruby on rails, which swallows it otherwise
u = makeurl(['source', self.prjname, self.name, pathname2url(n)]) u = makeurl(['source', self.prjname, self.name, pathname2url(n)])
if conf.config['do_commits'] == '1':
u += '?rev=upload'
othermethods.putfile(u, conf.config['user'], conf.config['pass'], file = os.path.join(self.dir, n)) othermethods.putfile(u, conf.config['user'], conf.config['pass'], file = os.path.join(self.dir, n))
shutil.copy2(os.path.join(self.dir, n), os.path.join(self.storedir, n)) shutil.copy2(os.path.join(self.dir, n), os.path.join(self.storedir, n))
def commit(self, msg=''):
import othermethods
u = makeurl(['source', self.prjname, self.name])
u += '?cmd=commit&rev=upload'
u += '&user=%s' % conf.config['user']
u += '&comment=%s' % quote_plus(msg)
#print u
f = urlopen(u, data='')
#print f.read()
def write_conflictlist(self): def write_conflictlist(self):
if len(self.in_conflict) == 0: if len(self.in_conflict) == 0:
@ -721,7 +751,7 @@ def edit_meta(prj, pac, template=new_package_templ, change_is_required=True):
m = urllib2.urlopen(u).readlines() m = urllib2.urlopen(u).readlines()
except urllib2.HTTPError, e: except urllib2.HTTPError, e:
if e.code == 404: if e.code == 404:
m = template % (pac, conf.config['username']) m = template % (pac, conf.config['user'])
else: else:
print 'error getting package meta for project \'%s\' package \'%s\':' % (prj, pac) print 'error getting package meta for project \'%s\' package \'%s\':' % (prj, pac)
print e print e
@ -734,7 +764,7 @@ def edit_meta(prj, pac, template=new_package_templ, change_is_required=True):
m = urllib2.urlopen(u).readlines() m = urllib2.urlopen(u).readlines()
except urllib2.HTTPError, e: except urllib2.HTTPError, e:
if e.code == 404: if e.code == 404:
m = new_project_templ % (prj, conf.config['username']) m = new_project_templ % (prj, conf.config['user'])
else: else:
print 'error getting package meta for project \'%s\':' % prj print 'error getting package meta for project \'%s\':' % prj
print e print e
@ -760,6 +790,42 @@ def edit_meta(prj, pac, template=new_package_templ, change_is_required=True):
print 'Done.' print 'Done.'
def edit_user_meta(user, change_is_required=True):
import othermethods
import tempfile
u = makeurl(['person', quote_plus(user)])
try:
m = urllib2.urlopen(u).readlines()
except urllib2.HTTPError, e:
if e.code == 404:
m = new_user_template % { 'user': user }
else:
print 'error getting metadata for user \'%s\':' % user
print e
sys.exit(1)
(fd, filename) = tempfile.mkstemp(prefix = 'osc_edituser.', suffix = '.xml', dir = '/tmp')
f = os.fdopen(fd, 'w')
f.write(''.join(m))
f.close()
timestamp = os.path.getmtime(filename)
editor = os.getenv('EDITOR', default='vim')
os.system('%s %s' % (editor, filename))
if change_is_required == True and os.path.getmtime(filename) == timestamp:
print 'File unchanged. Not saving.'
os.unlink(filename)
else:
print 'Sending meta data...',
othermethods.putfile(u, conf.config['user'], conf.config['pass'], file=filename)
os.unlink(filename)
print 'Done.'
def show_files_meta(prj, pac): def show_files_meta(prj, pac):
f = urlopen(makeurl(['source', prj, pac])) f = urlopen(makeurl(['source', prj, pac]))
return f.readlines() return f.readlines()
@ -799,7 +865,7 @@ def read_meta_from_spec(specfile):
return name, summary, descr return name, summary, descr
def get_user_id(user): def get_user_meta(user):
u = makeurl(['person', quote_plus(user)]) u = makeurl(['person', quote_plus(user)])
try: try:
f = urllib2.urlopen(u) f = urllib2.urlopen(u)
@ -1001,14 +1067,14 @@ def delete_package(prj, pac):
import othermethods import othermethods
u = makeurl(['source', prj, pac]) u = makeurl(['source', prj, pac])
othermethods.delfile(u, pac, conf.config['username'], conf.config['pass']) othermethods.delfile(u, pac, conf.config['user'], conf.config['pass'])
def delete_project(prj): def delete_project(prj):
import othermethods import othermethods
u = makeurl(['source', prj]) u = makeurl(['source', prj])
othermethods.delfile(u, prj, conf.config['username'], conf.config['pass']) othermethods.delfile(u, prj, conf.config['user'], conf.config['pass'])
def get_platforms(): def get_platforms():

View File

@ -1,6 +1,6 @@
#!/usr/bin/python #!/usr/bin/python
# Copyright (C) 2006 Peter Poeml. All rights reserved. # Copyright (C) 2006 Peter Poeml / Novell Inc. All rights reserved.
# This program is free software; it may be used, copied, modified # This program is free software; it may be used, copied, modified
# and distributed under the terms of the GNU General Public Licence, # and distributed under the terms of the GNU General Public Licence,
# either version 2, or (at your option) any later version. # either version 2, or (at your option) any later version.

View File

@ -1,6 +1,6 @@
#!/usr/bin/python #!/usr/bin/python
# Copyright (C) 2006 Peter Poeml. All rights reserved. # Copyright (C) 2006 Peter Poeml / Novell Inc. All rights reserved.
# This program is free software; it may be used, copied, modified # This program is free software; it may be used, copied, modified
# and distributed under the terms of the GNU General Public Licence, # and distributed under the terms of the GNU General Public Licence,
# either version 2, or (at your option) any later version. # either version 2, or (at your option) any later version.
@ -16,100 +16,81 @@ import httplib
import base64 import base64
import os import os
import urlparse import urlparse
from osc.core import __version__
BLOCKSIZE=4096 BLOCKSIZE=4096
def delfile(url, file, username, password): def request(method, url, username, password, file=None, strbuf=None):
"""call with method = (PUT|DELETE)"""
auth_string = base64.encodestring('%s:%s' % (username, password)).strip()
u = urlparse.urlparse(url) if method == 'PUT':
host = u[1] if file == None and strbuf == None:
path = u[2] print >>sys.stderr, 'putting a file requires either a filename or a string buffer'
sys.exit(1)
if strbuf:
size = len(strbuf)
else:
size = os.path.getsize(file)
conn = httplib.HTTP(host) scheme, host, path, params, query, fragment = urlparse.urlparse(url)
conn.putrequest('DELETE', '%s' % path) if query:
path += '?' + query
if scheme == 'https':
conn = httplib.HTTPS(host)
elif scheme == 'http':
conn = httplib.HTTP(host)
else:
sys.exit('unknown scheme %s' % scheme)
# Headers
conn.putrequest(method, '%s' % path)
conn.putheader('Host', host) conn.putheader('Host', host)
conn.putheader('User-agent', 'osc/%s' % __version__)
auth_string = base64.encodestring('%s:%s' % (username, password)).strip()
conn.putheader('Authorization', 'Basic %s' % auth_string) conn.putheader('Authorization', 'Basic %s' % auth_string)
if method == 'PUT':
conn.putheader('Content-Type', 'text/plain')
conn.putheader('Content-Length', str(size))
conn.endheaders() conn.endheaders()
# Body
if method == 'PUT':
if strbuf:
conn.send(strbuf)
else:
fp = open(file, 'rb')
#n = 0
while 1:
buf = fp.read(BLOCKSIZE)
#n+=1
#if n % 10 == 0:
# print 'upload-sending blocknum=', n
# print '.',
if not buf: break
try:
conn.send(buf)
except:
sys.exit('ERROR uploading %s' % file)
fp.close()
reply, msg, headers = conn.getreply() reply, msg, headers = conn.getreply()
if reply != 200: if reply != 200:
print 'error deleting %s' % file print >>sys.stderr, 'Error: can\'t %s \'%s\'' % (method, url)
print 'upload-DELETE reply=', reply, ' msg=', msg, 'headers=', headers print >>sys.stderr, 'reply:', reply
print >>sys.stderr, '\nDebugging output follows.\nurl:\n%s\nheaders:\n%s\nresponse:\n%s' % (url, headers, msg)
def delfile(url, file, username, password):
return request('DELETE', url, username, password, file=file)
def putfile(url, username, password, file=None, strbuf=None): def putfile(url, username, password, file=None, strbuf=None):
return request('PUT', url, username, password, file=file, strbuf=strbuf)
if file == None and strbuf == None:
print >>sys.stderr, 'putfile requires either a filename or a string buffer'
sys.exit(1)
if strbuf:
size = len(strbuf)
else:
size = os.stat(file)[6]
auth_string = base64.encodestring('%s:%s' % (username, password)).strip()
u = urlparse.urlparse(url)
host = u[1]
path = u[2]
conn = httplib.HTTP(host)
conn.putrequest('PUT', '%s' % path)
conn.putheader('Host', host)
conn.putheader('Content-Type', 'text/plain')
conn.putheader('Content-Length', str(size))
conn.putheader('Authorization', 'Basic %s' % auth_string)
conn.endheaders()
if strbuf:
conn.send(strbuf)
else:
fp = open(file, 'rb')
n = 0
while 1:
buf = fp.read(BLOCKSIZE)
n+=1
if n % 10 == 0:
#print 'upload-sending blocknum=', n
#print '.',
pass
if not buf: break
try:
conn.send(buf)
except:
print
print 'ERROR uploading %s' % file
print
os._exit(1)
fp.close()
reply, msg, headers = conn.getreply()
if reply != 200:
print 'error uploading %s' % file
print 'upload-PUT reply=', reply, ' msg=', msg, 'headers=', headers
def main():
import sys
username = 'yourusername'
password = 'yourpassword'
file = sys.argv[1]
url = 'http://api.opensuse.org/source/exim/exim/%s' % os.path.basename(file)
putfile(url, file, username, password)
delfile(url, file, username, password)
if __name__ == '__main__':
main()

View File

@ -4,7 +4,6 @@ import os, sys, time
import unittest import unittest
import shutil import shutil
from osc.core import init_basicauth
from osc import commandline from osc import commandline
PRJ = 'home:poeml' PRJ = 'home:poeml'
@ -25,11 +24,11 @@ class TestOsc(unittest.TestCase):
##################################################################### #####################################################################
def testId(self): def testUsermeta(self):
expect = """<person> expect = """<person>
<login>poeml</login> <login>poeml</login>
<email>poeml@suse.de</email> <email>poeml@suse.de</email>
<realname>Dr. Peter Peoml</realname> <realname>Dr. Peter Poeml</realname>
<source_backend> <source_backend>
<host></host> <host></host>
<port></port> <port></port>
@ -50,12 +49,14 @@ class TestOsc(unittest.TestCase):
<project name="Tidy"/> <project name="Tidy"/>
<project name="validators"/> <project name="validators"/>
<project name="zsh"/> <project name="zsh"/>
<project name="home:poeml"/>
<project name="Apache:Modules"/>
</watchlist> </watchlist>
</person> </person>
""" """
self.out, self.err = runosc('id poeml') self.out, self.err = runosc('usermeta poeml')
self.assertEqual(self.err, '') self.assertEqual(self.err, '')
self.assertEqual(self.out, expect) self.assertEqual(self.out, expect)
@ -91,7 +92,7 @@ class TestOsc(unittest.TestCase):
def testMetaPac(self): def testMetaPac(self):
self.out, self.err = runosc('meta Apache apache2') self.out, self.err = runosc('meta Apache apache2')
self.assertEqual(self.err, '') self.assertEqual(self.err, '')
self.assert_('<package name="apache2" project="Apache">' in self.out) self.assert_('<package project="Apache" name="apache2">' in self.out)
##################################################################### #####################################################################
@ -251,8 +252,6 @@ def touch(filename):
if __name__ == '__main__': if __name__ == '__main__':
init_basicauth()
#unittest.main() #unittest.main()
oldpwd = os.getcwd() oldpwd = os.getcwd()
suite = unittest.makeSuite(TestOsc) suite = unittest.makeSuite(TestOsc)