2006-10-10 16:04:34 +02:00
|
|
|
#!/usr/bin/python
|
|
|
|
|
2006-10-12 15:22:56 +02:00
|
|
|
# Copyright (C) 2006 Peter Poeml / Novell Inc. All rights reserved.
|
2006-10-10 16:04:34 +02:00
|
|
|
# This program is free software; it may be used, copied, modified
|
|
|
|
# and distributed under the terms of the GNU General Public Licence,
|
|
|
|
# either version 2, or (at your option) any later version.
|
|
|
|
|
|
|
|
"""Read osc configuration and store it in a dictionary
|
|
|
|
|
|
|
|
This module reads and parses ~/.oscrc. The resulting configuration is stored
|
|
|
|
for later usage in a dictionary named 'config'.
|
|
|
|
|
|
|
|
In the absence of .oscrc, it tries .netrc.
|
|
|
|
If information is missing, it asks the user questions.
|
|
|
|
|
|
|
|
After reading the config, urllib2 is initialized.
|
|
|
|
|
|
|
|
The configuration dictionary could look like this:
|
|
|
|
|
2007-04-25 12:24:51 +02:00
|
|
|
{'apisrv': 'https://api.opensuse.org/',
|
2006-10-10 16:04:34 +02:00
|
|
|
'user': 'poeml',
|
|
|
|
'auth_dict': {'api.opensuse.org': {'user': 'poeml', 'pass': 'secret'},
|
|
|
|
'apitest.opensuse.org': {'user': 'poeml', 'pass': 'secret'},
|
|
|
|
'foo.opensuse.org': {'user': 'foo', 'pass': 'foo'}},
|
|
|
|
'build-cmd': '/usr/bin/build',
|
|
|
|
'build-root': '/abuild/oscbuild-%(repo)s-%(arch)s',
|
|
|
|
'packagecachedir': '/var/cache/osbuild',
|
|
|
|
'su-wrapper': 'sudo',
|
|
|
|
'urllist': ['http://software.opensuse.org/download/%(project)s/%(repository)s/%(arch)s/%(filename)s',
|
|
|
|
'http://api.opensuse.org/rpm/%(project)s/%(repository)s/_repository/%(buildarch)s/%(name)s'],
|
|
|
|
}
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
import ConfigParser
|
|
|
|
|
|
|
|
# being global to this module, this dict can be accessed from outside
|
|
|
|
# it will hold the parsed configuration
|
|
|
|
config = { }
|
|
|
|
|
2007-04-25 12:24:51 +02:00
|
|
|
DEFAULTS = { 'apisrv': 'https://api.opensuse.org/',
|
2006-10-13 11:19:28 +02:00
|
|
|
'scheme': 'https',
|
2006-10-10 16:04:34 +02:00
|
|
|
'user': 'your_username',
|
|
|
|
'packagecachedir': '/var/tmp/osbuild-packagecache',
|
|
|
|
'su-wrapper': 'su -c',
|
|
|
|
'build-cmd': '/usr/bin/build',
|
|
|
|
'build-root': '/var/tmp/build-root',
|
|
|
|
|
|
|
|
# default list of download URLs, which will be tried in order
|
|
|
|
'urllist': [
|
|
|
|
# the normal repo server, redirecting to mirrors
|
|
|
|
'http://software.opensuse.org/download/%(project)s/%(repository)s/%(arch)s/%(filename)s',
|
|
|
|
# direct access to "full" tree
|
2007-05-07 22:14:20 +02:00
|
|
|
'%(scheme)s://%(apisrv)s/build/%(project)s/%(repository)s/%(buildarch)s/_repository/%(name)s',
|
2006-10-10 16:04:34 +02:00
|
|
|
],
|
2006-10-12 15:22:56 +02:00
|
|
|
|
2007-04-19 10:47:22 +02:00
|
|
|
'http_debug': '0',
|
2007-04-19 12:40:18 +02:00
|
|
|
'cookiejar': '~/.osc_cookiejar',
|
2007-04-19 10:47:22 +02:00
|
|
|
|
2006-10-12 15:22:56 +02:00
|
|
|
# switched off for now (testing)
|
|
|
|
'do_commits': '0',
|
2006-10-10 16:04:34 +02:00
|
|
|
}
|
2007-04-25 01:00:12 +02:00
|
|
|
boolean_opts = ['http_debug', 'do_commits']
|
2006-10-10 16:04:34 +02:00
|
|
|
|
|
|
|
new_conf_template = """
|
|
|
|
[general]
|
|
|
|
|
2007-04-25 12:24:51 +02:00
|
|
|
# URL to access API server, e.g. %(apisrv)s
|
|
|
|
# you also need a section [%(apisrv)s] with the credentials
|
|
|
|
#apisrv = %(apisrv)s
|
|
|
|
|
2006-10-10 16:04:34 +02:00
|
|
|
# Downloaded packages are cached here. Must be writable by you.
|
|
|
|
#packagecachedir = %(packagecachedir)s
|
|
|
|
|
|
|
|
# Wrapper to call build as root (sudo, su -, ...)
|
|
|
|
#su-wrapper = %(su-wrapper)s
|
|
|
|
|
|
|
|
# rootdir to setup the chroot environment
|
2007-04-18 02:26:14 +02:00
|
|
|
# can contain %%(repo)s and/or %%(arch)s for replacement, e.g.
|
|
|
|
# /srv/oscbuild/%%(repo)s-%%(arch)s
|
2006-10-10 16:04:34 +02:00
|
|
|
#build-root = %(build-root)s
|
|
|
|
|
2007-04-19 10:47:22 +02:00
|
|
|
# show HTTP traffic useful for debugging
|
2007-04-25 12:24:51 +02:00
|
|
|
#http_debug = 1
|
2007-04-19 10:47:22 +02:00
|
|
|
|
2006-10-10 16:04:34 +02:00
|
|
|
[%(apisrv)s]
|
|
|
|
user = %(user)s
|
|
|
|
pass = %(pass)s
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
account_not_configured_text ="""
|
|
|
|
Your user account / password are not configured yet.
|
|
|
|
You will be asked for them below, and they will be stored in
|
|
|
|
%s for future use.
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
config_incomplete_text = """
|
|
|
|
|
|
|
|
Your configuration file %s is not complete.
|
|
|
|
Make sure that it has a [general] section.
|
|
|
|
(You can copy&paste the below. Some commented defaults are shown.)
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
2007-04-19 12:40:18 +02:00
|
|
|
cookiejar = None
|
2006-10-10 16:04:34 +02:00
|
|
|
|
2007-04-25 12:24:51 +02:00
|
|
|
def parse_apisrv_url(scheme, apisrv):
|
|
|
|
import urlparse
|
|
|
|
if apisrv.startswith('http://') or apisrv.startswith('https://'):
|
|
|
|
return urlparse.urlsplit(apisrv)[0:2]
|
|
|
|
else:
|
|
|
|
return scheme, apisrv
|
|
|
|
|
2006-10-10 16:04:34 +02:00
|
|
|
def init_basicauth(config):
|
|
|
|
"""initialize urllib2 with the credentials for Basic Authentication"""
|
2007-04-19 10:47:22 +02:00
|
|
|
|
2006-10-10 16:04:34 +02:00
|
|
|
from osc.core import __version__
|
2007-04-19 12:40:18 +02:00
|
|
|
import os, urllib2
|
|
|
|
import cookielib
|
|
|
|
|
|
|
|
global cookiejar
|
2006-10-10 16:04:34 +02:00
|
|
|
|
2007-04-25 01:00:12 +02:00
|
|
|
if config['http_debug']:
|
2007-04-19 10:47:22 +02:00
|
|
|
# brute force
|
|
|
|
def urllib2_debug_init(self, debuglevel=0):
|
|
|
|
self._debuglevel = 1
|
|
|
|
urllib2.AbstractHTTPHandler.__init__ = urllib2_debug_init
|
2006-10-10 16:04:34 +02:00
|
|
|
|
2007-04-19 10:47:22 +02:00
|
|
|
authhandler = urllib2.HTTPBasicAuthHandler( \
|
|
|
|
urllib2.HTTPPasswordMgrWithDefaultRealm())
|
2006-10-10 16:04:34 +02:00
|
|
|
|
2007-04-19 12:40:18 +02:00
|
|
|
cookie_file = os.path.expanduser(config['cookiejar'])
|
|
|
|
cookiejar = cookielib.LWPCookieJar(cookie_file)
|
|
|
|
try:
|
|
|
|
cookiejar.load(ignore_discard=True)
|
|
|
|
except IOError:
|
|
|
|
try:
|
|
|
|
open(cookie_file, 'w').close()
|
|
|
|
os.chmod(cookie_file, 0600)
|
|
|
|
except:
|
|
|
|
#print 'Unable to create cookiejar file: \'%s\'. Using RAM-based cookies.' % cookie_file
|
|
|
|
cookiejar = cookielib.CookieJar()
|
|
|
|
|
|
|
|
opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookiejar), authhandler)
|
2006-10-10 16:04:34 +02:00
|
|
|
urllib2.install_opener(opener)
|
|
|
|
|
2007-04-19 10:47:22 +02:00
|
|
|
opener.addheaders = [('User-agent', 'osc/%s' % __version__)]
|
|
|
|
|
|
|
|
# with None as first argument, it will always use this username/password
|
|
|
|
# combination for urls for which arg2 (apisrv) is a super-url
|
2007-04-25 10:56:31 +02:00
|
|
|
for host, auth in config['auth_dict'].iteritems():
|
|
|
|
authhandler.add_password(None, host, auth['user'], auth['pass'])
|
2006-10-10 16:04:34 +02:00
|
|
|
|
|
|
|
|
|
|
|
def get_config():
|
|
|
|
"""do the actual work (see module documentation)"""
|
|
|
|
import os
|
|
|
|
import sys
|
|
|
|
global config
|
|
|
|
|
|
|
|
conffile = os.path.expanduser('~/.oscrc')
|
|
|
|
|
|
|
|
if not os.path.exists(conffile):
|
|
|
|
|
|
|
|
# okay, let's create a fresh config file
|
|
|
|
# if credentials are found in .netrc, use those
|
|
|
|
# otherwise ask
|
|
|
|
|
|
|
|
config = DEFAULTS.copy()
|
|
|
|
|
|
|
|
# try .netrc
|
|
|
|
# the needed entry needs to look like this:
|
|
|
|
# machine api.opensuse.org login your_login password your_pass
|
|
|
|
# note that it is not suited for credentials containing spaces
|
|
|
|
import netrc
|
|
|
|
try:
|
2007-05-10 16:29:04 +02:00
|
|
|
# XXX: apisrv is a URL now, thus requiring the "scheme" setting if https is to be used
|
2007-04-25 12:24:51 +02:00
|
|
|
netrc_host = parse_apisrv_url(None, DEFAULTS['apisrv'])[1]
|
2006-10-10 16:04:34 +02:00
|
|
|
config['user'], account, config['pass'] = \
|
2007-04-25 12:24:51 +02:00
|
|
|
netrc.netrc().authenticators(netrc_host)
|
2006-10-10 16:04:34 +02:00
|
|
|
print >>sys.stderr, 'Read credentials from %s.' % os.path.expanduser('~/.netrc')
|
|
|
|
except (IOError, TypeError, netrc.NetrcParseError):
|
|
|
|
#
|
|
|
|
# last resort... ask the user
|
|
|
|
#
|
|
|
|
import getpass
|
|
|
|
print >>sys.stderr, account_not_configured_text % conffile
|
|
|
|
config['user'] = raw_input('Username: ')
|
|
|
|
config['pass'] = getpass.getpass()
|
|
|
|
|
2007-01-12 04:53:44 +01:00
|
|
|
print >>sys.stderr, 'Creating osc configuration file %s ...' % conffile
|
2006-10-10 16:04:34 +02:00
|
|
|
fd = open(conffile, 'w')
|
|
|
|
os.chmod(conffile, 0600)
|
|
|
|
fd.write(new_conf_template % config)
|
|
|
|
fd.close()
|
2007-01-12 04:53:44 +01:00
|
|
|
print >>sys.stderr, 'done.'
|
2006-10-10 16:04:34 +02:00
|
|
|
#print >>sys.stderr, ('Now re-run the command.')
|
|
|
|
#sys.exit(0)
|
|
|
|
|
|
|
|
|
|
|
|
# okay, we made sure that .oscrc exists
|
|
|
|
|
|
|
|
cp = ConfigParser.SafeConfigParser(DEFAULTS)
|
|
|
|
cp.read(conffile)
|
|
|
|
|
|
|
|
if not cp.has_section('general'):
|
|
|
|
# FIXME: it might be sufficient to just assume defaults?
|
|
|
|
print >>sys.stderr, config_incomplete_text % conffile
|
|
|
|
print >>sys.stderr, new_conf_template % DEFAULTS
|
|
|
|
sys.exit(1)
|
|
|
|
|
|
|
|
config = dict(cp.items('general', raw=1))
|
|
|
|
|
2007-04-25 12:24:51 +02:00
|
|
|
config['scheme'], config['apisrv'] = \
|
|
|
|
parse_apisrv_url(config['scheme'], config['apisrv'])
|
|
|
|
|
2007-04-25 01:00:12 +02:00
|
|
|
for i in boolean_opts:
|
|
|
|
try:
|
|
|
|
if int(config.get(i)):
|
|
|
|
config[i] = True
|
|
|
|
else:
|
|
|
|
config[i] = False
|
|
|
|
except:
|
|
|
|
sys.exit('option %s requires an integer value' % i)
|
|
|
|
|
2006-10-10 16:04:34 +02:00
|
|
|
# transform 'url1, url2, url3' form into a list
|
|
|
|
if type(config['urllist']) == str:
|
|
|
|
config['urllist'] = [ i.strip() for i in config['urllist'].split(',') ]
|
|
|
|
|
2007-04-25 12:24:51 +02:00
|
|
|
# holds multiple usernames and passwords
|
|
|
|
auth_dict = { }
|
|
|
|
for url in [ x for x in cp.sections() if x != 'general' ]:
|
|
|
|
dummy, host = \
|
|
|
|
parse_apisrv_url(config['scheme'], url)
|
|
|
|
auth_dict[host] = { 'user': cp.get(url, 'user'),
|
|
|
|
'pass': cp.get(url, 'pass') }
|
|
|
|
|
2006-10-10 16:04:34 +02:00
|
|
|
# add the auth data we collected to the config dict
|
|
|
|
config['auth_dict'] = auth_dict
|
|
|
|
|