mirror of
https://git.launchpad.net/ubuntu-dev-tools
synced 2025-04-16 12:51:08 +00:00
Configuration system uses a class, add test suite
This commit is contained in:
parent
9c62fb8723
commit
254be7bb5d
@ -30,7 +30,7 @@ from debian.deb822 import Dsc
|
||||
import launchpadlib.launchpad
|
||||
import lsb_release
|
||||
|
||||
from ubuntutools.config import get_value, ubu_email
|
||||
from ubuntutools.config import UDTConfig, ubu_email
|
||||
from ubuntutools.builder import getBuilder
|
||||
from ubuntutools.logger import Logger
|
||||
from ubuntutools.question import YesNoQuestion
|
||||
@ -71,12 +71,12 @@ def parse(args):
|
||||
help='Build the package before uploading (default: %default)')
|
||||
p.add_option('-B', '--builder',
|
||||
dest='builder',
|
||||
default=get_value('BUILDER'),
|
||||
help='Specify the package builder (default: %default)',
|
||||
default=None,
|
||||
help='Specify the package builder (default: pbuilder)',
|
||||
metavar='BUILDER')
|
||||
p.add_option('-U', '--update',
|
||||
dest='update',
|
||||
default=get_value('UPDATE_BUILDER'),
|
||||
default=False,
|
||||
action='store_true',
|
||||
help='Update the build environment before attempting to build')
|
||||
p.add_option('-u', '--upload',
|
||||
@ -95,23 +95,32 @@ def parse(args):
|
||||
metavar='VERSION')
|
||||
p.add_option('-w', '--workdir',
|
||||
dest='workdir',
|
||||
default=get_value('WORKDIR'),
|
||||
default=None,
|
||||
help='Specify a working directory (default: temporary dir)',
|
||||
metavar='WORKDIR')
|
||||
p.add_option('-l', '--launchpad',
|
||||
dest='launchpad',
|
||||
default=get_value('LPINSTANCE'),
|
||||
help='Launchpad instance to connect to (default: %default)',
|
||||
default=None,
|
||||
help='Launchpad instance to connect to (default: production)',
|
||||
metavar='INSTANCE')
|
||||
p.add_option('--no-conf', '--noconf',
|
||||
dest='no_configuration',
|
||||
dest='no_conf',
|
||||
default=False,
|
||||
help="Don't read config files, must be the first option given",
|
||||
help="Don't read config files or environment variables",
|
||||
action='store_true')
|
||||
|
||||
opts, args = p.parse_args(args)
|
||||
if len(args) != 1:
|
||||
p.error('You must specify a single source package or a .dsc URL/path.')
|
||||
config = UDTConfig(opts.no_conf)
|
||||
if opts.builder is None:
|
||||
opts.builder = config.get_value('BUILDER')
|
||||
if not opts.update:
|
||||
opts.update = config.get_value('UPDATE_BUILDER')
|
||||
if opts.workdir is None:
|
||||
opts.workdir = config.get_value('WORKDIR')
|
||||
if opts.launchpad is None:
|
||||
opts.launchpad = config.get_value('LPINSTANCE')
|
||||
if not opts.upload and not opts.workdir:
|
||||
p.error('Please specify either a working dir or an upload target!')
|
||||
|
||||
@ -239,7 +248,6 @@ def do_backport(workdir, package, dscfile, version, suffix, release, build,
|
||||
bp_version = get_backport_version(version, suffix, upload, release)
|
||||
bp_dist = get_backport_dist(upload, release)
|
||||
|
||||
ubu_email()
|
||||
check_call(['dch',
|
||||
'--force-bad-version',
|
||||
'--preserve',
|
||||
@ -262,6 +270,7 @@ def do_backport(workdir, package, dscfile, version, suffix, release, build,
|
||||
|
||||
def main(args):
|
||||
os.environ['DEB_VENDOR'] = 'Ubuntu'
|
||||
ubu_email()
|
||||
|
||||
opts, (package_or_dsc,) = parse(args[1:])
|
||||
|
||||
|
1
debian/copyright
vendored
1
debian/copyright
vendored
@ -189,7 +189,6 @@ Files:
|
||||
sponsor-patch,
|
||||
suspicious-source,
|
||||
ubuntutools/builder.py,
|
||||
ubuntutools/common.py,
|
||||
ubuntutools/config.py,
|
||||
ubuntutools/logger.py,
|
||||
ubuntutools/question.py,
|
||||
|
@ -22,7 +22,6 @@
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
from ubuntutools.config import get_value
|
||||
from ubuntutools.logger import Logger
|
||||
|
||||
class Builder(object):
|
||||
@ -145,10 +144,7 @@ class Sbuild(Builder):
|
||||
return 0
|
||||
|
||||
|
||||
def getBuilder(builder=None):
|
||||
if not builder:
|
||||
builder = get_value('BUILDER')
|
||||
|
||||
def getBuilder(builder='pbuilder'):
|
||||
if builder == 'pbuilder':
|
||||
return Pbuilder()
|
||||
elif builder == 'pbuilder-dist':
|
||||
|
@ -1,25 +0,0 @@
|
||||
# common.py - provides functions which are commonly used by the
|
||||
# ubuntu-dev-tools package.
|
||||
#
|
||||
# Copyright (C) 2010, Stefano Rivera <stefanor@ubuntu.com>
|
||||
#
|
||||
# Permission to use, copy, modify, and/or distribute this software for any
|
||||
# purpose with or without fee is hereby granted, provided that the above
|
||||
# copyright notice and this permission notice appear in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||
# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
# AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||
# OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
# PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
def memoize_noargs(func):
|
||||
"Simple memoization wrapper, for functions without arguments"
|
||||
func.cache = None
|
||||
def wrapper():
|
||||
if func.cache is None:
|
||||
func.cache = func()
|
||||
return func.cache
|
||||
return wrapper
|
@ -22,65 +22,70 @@ import re
|
||||
import socket
|
||||
import sys
|
||||
|
||||
from ubuntutools.common import memoize_noargs
|
||||
class UDTConfig(object):
|
||||
|
||||
defaults = {
|
||||
'BUILDER': 'pbuilder',
|
||||
'UPDATE_BUILDER': False,
|
||||
'LPINSTANCE': 'production',
|
||||
}
|
||||
defaults = {
|
||||
'BUILDER': 'pbuilder',
|
||||
'UPDATE_BUILDER': False,
|
||||
'LPINSTANCE': 'production',
|
||||
}
|
||||
|
||||
@memoize_noargs
|
||||
def get_devscripts_config():
|
||||
"""Read the devscripts configuration files, and return the values as a
|
||||
dictionary
|
||||
"""
|
||||
config = {}
|
||||
var_re = re.compile(r'^\s*([A-Z_]+?)=(.+?)\s*$')
|
||||
for fn in ('/etc/devscripts.conf', '~/.devscripts'):
|
||||
f = open(os.path.expanduser(fn), 'r')
|
||||
for line in f:
|
||||
m = var_re.match(line)
|
||||
if m:
|
||||
value = m.group(2)
|
||||
# This isn't quite the same as bash's parsing, but
|
||||
# mostly-compatible for configuration files that aren't broken
|
||||
# like this: KEY=foo bar
|
||||
if (len(value) > 2 and value[0] == value[-1]
|
||||
and value[0] in ("'", '"')):
|
||||
value = value[1:-1]
|
||||
config[m.group(1)] = value
|
||||
f.close()
|
||||
return config
|
||||
def __init__(self, no_conf=False, prefix=None):
|
||||
|
||||
def get_value(key, default=None, prefix=None, compat_keys=[]):
|
||||
"""Retrieve a value from the environment or configuration files.
|
||||
keys are prefixed with the script name + _, or prefix.
|
||||
self.no_conf = no_conf
|
||||
if prefix is None:
|
||||
prefix = os.path.basename(sys.argv[0]).upper().replace('-', '_')
|
||||
self.prefix = prefix
|
||||
if not no_conf:
|
||||
self.config = self.parse_devscripts_config()
|
||||
|
||||
Store Priority: Environment variables, user config file, system config file
|
||||
Variable Priority: PREFIX_KEY, UBUNTUTOOLS_KEY, compat_keys
|
||||
def parse_devscripts_config(self):
|
||||
"""Read the devscripts configuration files, and return the values as a
|
||||
dictionary
|
||||
"""
|
||||
config = {}
|
||||
var_re = re.compile(r'^\s*([A-Z_]+?)=(.+?)\s*$')
|
||||
for fn in ('/etc/devscripts.conf', '~/.devscripts'):
|
||||
f = open(os.path.expanduser(fn), 'r')
|
||||
for line in f:
|
||||
m = var_re.match(line)
|
||||
if m:
|
||||
value = m.group(2)
|
||||
# This isn't quite the same as bash's parsing, but
|
||||
# mostly-compatible for configuration files that aren't
|
||||
# broken like this: KEY=foo bar
|
||||
if (len(value) > 2 and value[0] == value[-1]
|
||||
and value[0] in ("'", '"')):
|
||||
value = value[1:-1]
|
||||
config[m.group(1)] = value
|
||||
f.close()
|
||||
return config
|
||||
|
||||
Historical variable names can be supplied via compat_keys, no prefix is
|
||||
applied to them.
|
||||
"""
|
||||
if default is None and key in defaults:
|
||||
default = defaults[key]
|
||||
if len(sys.argv) > 1 and sys.argv[1] in ('--no-conf', '--noconf'):
|
||||
def get_value(self, key, default=None, compat_keys=[]):
|
||||
"""Retrieve a value from the environment or configuration files.
|
||||
keys are prefixed with the script name, falling back to UBUNTUTOOLS for
|
||||
package-wide keys.
|
||||
|
||||
Store Priority: Environment variables, user conf, system conf
|
||||
Variable Priority: PREFIX_KEY, UBUNTUTOOLS_KEY, compat_keys
|
||||
|
||||
Historical variable names can be supplied via compat_keys, no prefix is
|
||||
applied to them.
|
||||
"""
|
||||
if default is None and key in self.defaults:
|
||||
default = self.defaults[key]
|
||||
|
||||
keys = [self.prefix + '_' + key, 'UBUNTUTOOLS_' + key] + compat_keys
|
||||
|
||||
for store in (os.environ, self.config):
|
||||
for k in keys:
|
||||
if k in store:
|
||||
value = store[k]
|
||||
if value in ('yes', 'no'):
|
||||
value = value == 'yes'
|
||||
return value
|
||||
return default
|
||||
|
||||
if prefix is None:
|
||||
prefix = os.path.basename(sys.argv[0]).upper().replace('-', '_') + '_'
|
||||
|
||||
keys = [prefix + key, 'UBUNTUTOOLS_' + key] + compat_keys
|
||||
|
||||
for store in (os.environ, get_devscripts_config()):
|
||||
for k in keys:
|
||||
if k in store:
|
||||
value = store[k]
|
||||
if value in ('yes', 'no'):
|
||||
value = value == 'yes'
|
||||
return value
|
||||
return default
|
||||
|
||||
def ubu_email(name=None, email=None, export=True):
|
||||
"""Find the developer's Ubuntu e-mail address, and export it in
|
||||
|
@ -1,35 +0,0 @@
|
||||
# test_common.py - Test suite for ubuntutools.common
|
||||
#
|
||||
# Copyright (C) 2010, Stefano Rivera <stefanor@ubuntu.com>
|
||||
#
|
||||
# Permission to use, copy, modify, and/or distribute this software for any
|
||||
# purpose with or without fee is hereby granted, provided that the above
|
||||
# copyright notice and this permission notice appear in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||
# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
# AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||
# OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
# PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
from ubuntutools.test import unittest
|
||||
from ubuntutools.common import memoize_noargs
|
||||
|
||||
class MemoizeTestCase(unittest.TestCase):
|
||||
def test_memoize_noargs(self):
|
||||
global run_count
|
||||
run_count = 0
|
||||
|
||||
@memoize_noargs
|
||||
def test_func():
|
||||
global run_count
|
||||
run_count += 1
|
||||
return 42
|
||||
|
||||
self.assertEqual(run_count, 0)
|
||||
self.assertEqual(test_func(), 42)
|
||||
self.assertEqual(run_count, 1)
|
||||
self.assertEqual(test_func(), 42)
|
||||
self.assertEqual(run_count, 1)
|
169
ubuntutools/test/test_config.py
Normal file
169
ubuntutools/test/test_config.py
Normal file
@ -0,0 +1,169 @@
|
||||
# test_config.py - Test suite for ubuntutools.config
|
||||
#
|
||||
# Copyright (C) 2010, Stefano Rivera <stefanor@ubuntu.com>
|
||||
#
|
||||
# Permission to use, copy, modify, and/or distribute this software for any
|
||||
# purpose with or without fee is hereby granted, provided that the above
|
||||
# copyright notice and this permission notice appear in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||
# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
# AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||
# OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
# PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
import os
|
||||
import os.path
|
||||
from StringIO import StringIO
|
||||
|
||||
import ubuntutools.config
|
||||
from ubuntutools.config import UDTConfig, ubu_email
|
||||
from ubuntutools.test import unittest
|
||||
|
||||
config_files = {
|
||||
'system': '',
|
||||
'user': '',
|
||||
}
|
||||
|
||||
def fake_open(filename, mode='r'):
|
||||
if mode != 'r':
|
||||
raise IOError("Read only fake-file")
|
||||
files = {
|
||||
'/etc/devscripts.conf': config_files['system'],
|
||||
os.path.expanduser('~/.devscripts'): config_files['user'],
|
||||
}
|
||||
if filename not in files:
|
||||
raise IOError("No such file or directory: '%s'" % filename)
|
||||
return StringIO(files[filename])
|
||||
|
||||
|
||||
class ConfigTestCase(unittest.TestCase):
|
||||
def setUp(self):
|
||||
ubuntutools.config.open = fake_open
|
||||
self.cleanEnvironment()
|
||||
|
||||
def tearDown(self):
|
||||
del ubuntutools.config.open
|
||||
self.cleanEnvironment()
|
||||
|
||||
def cleanEnvironment(self):
|
||||
config_files['system'] = ''
|
||||
config_files['user'] = ''
|
||||
for k in os.environ.keys():
|
||||
if k.startswith(('UBUNTUTOOLS_', 'TEST_')):
|
||||
del os.environ[k]
|
||||
|
||||
def test_config_parsing(self):
|
||||
config_files['user'] = """#COMMENT=yes
|
||||
\tTAB_INDENTED=yes
|
||||
SPACE_INDENTED=yes
|
||||
SPACE_SUFFIX=yes
|
||||
SINGLE_QUOTE='yes no'
|
||||
DOUBLE_QUOTE="yes no"
|
||||
QUOTED_QUOTE="it's"
|
||||
INHERIT=user
|
||||
REPEAT=no
|
||||
REPEAT=yes
|
||||
"""
|
||||
config_files['system'] = 'INHERIT=system'
|
||||
self.assertEqual(UDTConfig(prefix='TEST').config, {
|
||||
'TAB_INDENTED': 'yes',
|
||||
'SPACE_INDENTED': 'yes',
|
||||
'SPACE_SUFFIX': 'yes',
|
||||
'SINGLE_QUOTE': 'yes no',
|
||||
'DOUBLE_QUOTE': 'yes no',
|
||||
'QUOTED_QUOTE': "it's",
|
||||
'INHERIT': 'user',
|
||||
'REPEAT': 'yes',
|
||||
})
|
||||
|
||||
def get_value(self, key, default=None, compat_keys=[]):
|
||||
config = UDTConfig(prefix='TEST')
|
||||
return config.get_value(key, default=default, compat_keys=compat_keys)
|
||||
|
||||
def test_defaults(self):
|
||||
self.assertEqual(self.get_value('BUILDER'), 'pbuilder')
|
||||
|
||||
def test_provided_default(self):
|
||||
self.assertEqual(self.get_value('BUILDER', default='foo'), 'foo')
|
||||
|
||||
def test_scriptname_precedence(self):
|
||||
config_files['user'] = """TEST_BUILDER=foo
|
||||
UBUNTUTOOLS_BUILDER=bar"""
|
||||
self.assertEqual(self.get_value('BUILDER'), 'foo')
|
||||
|
||||
def test_configfile_precedence(self):
|
||||
config_files['system'] = "UBUNTUTOOLS_BUILDER=foo"
|
||||
config_files['user'] = "UBUNTUTOOLS_BUILDER=bar"
|
||||
self.assertEqual(self.get_value('BUILDER'), 'bar')
|
||||
|
||||
def test_environment_precedence(self):
|
||||
config_files['user'] = "UBUNTUTOOLS_BUILDER=bar"
|
||||
os.environ['UBUNTUTOOLS_BUILDER'] = 'baz'
|
||||
self.assertEqual(self.get_value('BUILDER'), 'baz')
|
||||
|
||||
def test_any_environment_precedence(self):
|
||||
config_files['user'] = "TEST_BUILDER=bar"
|
||||
os.environ['UBUNTUTOOLS_BUILDER'] = 'foo'
|
||||
self.assertEqual(self.get_value('BUILDER'), 'foo')
|
||||
|
||||
def test_compat_environment_precedence(self):
|
||||
config_files['user'] = "TEST_BUILDER=bar"
|
||||
os.environ['BUILDER'] = 'baz'
|
||||
self.assertEqual(self.get_value('BUILDER', compat_keys=['BUILDER']),
|
||||
'baz')
|
||||
|
||||
def test_boolean(self):
|
||||
config_files['user'] = "TEST_BOOLEAN=yes"
|
||||
self.assertEqual(self.get_value('BOOLEAN'), True)
|
||||
config_files['user'] = "TEST_BOOLEAN=no"
|
||||
self.assertEqual(self.get_value('BOOLEAN'), False)
|
||||
|
||||
class UbuEmailTestCase(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.cleanEnvironment()
|
||||
|
||||
def tearDown(self):
|
||||
self.cleanEnvironment()
|
||||
|
||||
def cleanEnvironment(self):
|
||||
for k in ('UBUMAIL', 'DEBEMAIL', 'DEBFULLNAME'):
|
||||
if k in os.environ:
|
||||
del os.environ[k]
|
||||
|
||||
def test_pristine(self):
|
||||
os.environ['DEBFULLNAME'] = name = 'Joe Developer'
|
||||
os.environ['DEBEMAIL'] = email = 'joe@example.net'
|
||||
self.assertEqual(ubu_email(), (name, email))
|
||||
|
||||
def test_two_hat(self):
|
||||
os.environ['DEBFULLNAME'] = name = 'Joe Developer'
|
||||
os.environ['DEBEMAIL'] = 'joe@debian.org'
|
||||
os.environ['UBUMAIL'] = email = 'joe@ubuntu.com'
|
||||
self.assertEqual(ubu_email(), (name, email))
|
||||
self.assertEqual(os.environ['DEBFULLNAME'], name)
|
||||
self.assertEqual(os.environ['DEBEMAIL'], email)
|
||||
|
||||
def test_two_hat_with_name(self):
|
||||
os.environ['DEBFULLNAME'] = 'Joe Developer'
|
||||
os.environ['DEBEMAIL'] = 'joe@debian.org'
|
||||
name = 'Joe Ubuntunista'
|
||||
email = 'joe@ubuntu.com'
|
||||
os.environ['UBUMAIL'] = '%s <%s>' % (name, email)
|
||||
self.assertEqual(ubu_email(), (name, email))
|
||||
self.assertEqual(os.environ['DEBFULLNAME'], name)
|
||||
self.assertEqual(os.environ['DEBEMAIL'], email)
|
||||
|
||||
def test_debfullname_with_email(self):
|
||||
name = 'Joe Developer'
|
||||
email = 'joe@example.net'
|
||||
os.environ['DEBFULLNAME'] = '%s <%s>' % (name, email)
|
||||
self.assertEqual(ubu_email(), (name, email))
|
||||
|
||||
def test_debemail_with_name(self):
|
||||
name = 'Joe Developer'
|
||||
email = 'joe@example.net'
|
||||
os.environ['DEBEMAIL'] = '%s <%s>' % (name, email)
|
||||
self.assertEqual(ubu_email(), (name, email))
|
Loading…
x
Reference in New Issue
Block a user