"""Common utility functions
"""
-import errno, optparse, os, os.path, re, sys
+import errno, os, os.path, re, sys
from stgit.exception import *
from stgit.config import config
from stgit.out import *
class EditorException(StgException):
pass
+def get_editor():
+ for editor in [os.environ.get('GIT_EDITOR'),
+ config.get('stgit.editor'), # legacy
+ config.get('core.editor'),
+ os.environ.get('VISUAL'),
+ os.environ.get('EDITOR'),
+ 'vi']:
+ if editor:
+ return editor
+
def call_editor(filename):
"""Run the editor on the specified filename."""
-
- # the editor
- editor = config.get('stgit.editor')
- if not editor:
- editor = os.environ.get('EDITOR', 'vi')
- editor += ' %s' % filename
-
- out.start('Invoking the editor: "%s"' % editor)
- err = os.system(editor)
+ cmd = '%s %s' % (get_editor(), filename)
+ out.start('Invoking the editor: "%s"' % cmd)
+ err = os.system(cmd)
if err:
raise EditorException, 'editor failed, exit code: %d' % err
out.done()
os.remove(filename)
return s
+def append_comment(s, comment, separator = '---'):
+ return ('%s\n\n%s\nEverything following the line with "%s" will be'
+ ' ignored\n\n%s' % (s, separator, separator, comment))
+
+def strip_comment(s, separator = '---'):
+ try:
+ return s[:s.index('\n%s\n' % separator)]
+ except ValueError:
+ return s
+
+def find_patch_name(patchname, unacceptable):
+ """Find a patch name which is acceptable."""
+ if unacceptable(patchname):
+ suffix = 0
+ while unacceptable('%s-%d' % (patchname, suffix)):
+ suffix += 1
+ patchname = '%s-%d' % (patchname, suffix)
+ return patchname
+
def patch_name_from_msg(msg):
"""Return a string to be used as a patch name. This is generated
from the top line of the string passed as argument."""
if not msg:
return None
- name_len = config.get('stgit.namelength')
+ name_len = config.getint('stgit.namelength')
if not name_len:
name_len = 30
patchname = patch_name_from_msg(msg)
if not patchname:
patchname = default_name
- if unacceptable(patchname):
- suffix = 0
- while unacceptable('%s-%d' % (patchname, suffix)):
- suffix += 1
- patchname = '%s-%d' % (patchname, suffix)
- return patchname
+ return find_patch_name(patchname, unacceptable)
# any and all functions are builtin in Python 2.5 and higher, but not
# in 2.4.
return False
return True
-def make_sign_options():
- def callback(option, opt_str, value, parser, sign_str):
- if parser.values.sign_str not in [None, sign_str]:
- raise optparse.OptionValueError(
- '--ack and --sign were both specified')
- parser.values.sign_str = sign_str
- return [optparse.make_option('--sign', action = 'callback',
- callback = callback, dest = 'sign_str',
- callback_args = ('Signed-off-by',),
- help = 'add Signed-off-by line'),
- optparse.make_option('--ack', action = 'callback',
- callback = callback, dest = 'sign_str',
- callback_args = ('Acked-by',),
- help = 'add Acked-by line')]
-
def add_sign_line(desc, sign_str, name, email):
if not sign_str:
return desc
desc = desc + '\n'
return '%s\n%s\n' % (desc, sign_str)
-def make_message_options():
- def no_dup(parser):
- if parser.values.message != None:
- raise optparse.OptionValueError(
- 'Cannot give more than one --message or --file')
- def no_combine(parser):
- if (parser.values.message != None
- and parser.values.save_template != None):
- raise optparse.OptionValueError(
- 'Cannot give both --message/--file and --save-template')
- def msg_callback(option, opt_str, value, parser):
- no_dup(parser)
- parser.values.message = value
- no_combine(parser)
- def file_callback(option, opt_str, value, parser):
- no_dup(parser)
- if value == '-':
- parser.values.message = sys.stdin.read()
- else:
- f = file(value)
- parser.values.message = f.read()
- f.close()
- no_combine(parser)
- def templ_callback(option, opt_str, value, parser):
- if value == '-':
- def w(s):
- sys.stdout.write(s)
- else:
- def w(s):
- f = file(value, 'w+')
- f.write(s)
- f.close()
- parser.values.save_template = w
- no_combine(parser)
- m = optparse.make_option
- return [m('-m', '--message', action = 'callback', callback = msg_callback,
- dest = 'message', type = 'string',
- help = 'use MESSAGE instead of invoking the editor'),
- m('-f', '--file', action = 'callback', callback = file_callback,
- dest = 'message', type = 'string', metavar = 'FILE',
- help = 'use FILE instead of invoking the editor'),
- m('--save-template', action = 'callback', callback = templ_callback,
- metavar = 'FILE', dest = 'save_template', type = 'string',
- help = 'save the message template to FILE and exit')]
-
-def make_diff_opts_option():
- def diff_opts_callback(option, opt_str, value, parser):
- if value:
- parser.values.diff_flags.extend(value.split())
- else:
- parser.values.diff_flags = []
- return [optparse.make_option(
- '-O', '--diff-opts', dest = 'diff_flags',
- default = (config.get('stgit.diff-opts') or '').split(),
- action = 'callback', callback = diff_opts_callback,
- type = 'string', metavar = 'OPTIONS',
- help = 'extra options to pass to "git diff"')]
-
def parse_name_email(address):
"""Return a tuple consisting of the name and email parsed from a
standard 'name <email>' or 'email (name)' string."""
return None
return str_list[0]
-def make_person_options(person, short):
- """Sets options.<person> to a function that modifies a Person
- according to the commandline options."""
- def short_callback(option, opt_str, value, parser, field):
- f = getattr(parser.values, person)
- setattr(parser.values, person,
- lambda p: getattr(f(p), 'set_' + field)(value))
- def full_callback(option, opt_str, value, parser):
- ne = parse_name_email(value)
- if not ne:
- raise optparse.OptionValueError(
- 'Bad %s specification: %r' % (opt_str, value))
- name, email = ne
- short_callback(option, opt_str, name, parser, 'name')
- short_callback(option, opt_str, email, parser, 'email')
- return ([optparse.make_option(
- '--%s' % person, metavar = '"NAME <EMAIL>"', type = 'string',
- action = 'callback', callback = full_callback, dest = person,
- default = lambda p: p, help = 'set the %s details' % person)]
- + [optparse.make_option(
- '--%s%s' % (short, f), metavar = f.upper(), type = 'string',
- action = 'callback', callback = short_callback, dest = person,
- callback_args = (f,), help = 'set the %s %s' % (person, f))
- for f in ['name', 'email', 'date']])
-
-def make_author_committer_options():
- return (make_person_options('author', 'auth')
- + make_person_options('committer', 'comm'))
-
# Exit codes.
STGIT_SUCCESS = 0 # everything's OK
STGIT_GENERAL_ERROR = 1 # seems to be non-command-specific error
STGIT_CONFLICT = 3 # merge conflict, otherwise OK
STGIT_BUG_ERROR = 4 # a bug in StGit
-def strip_leading(prefix, s):
- """Strip leading prefix from a string. Blow up if the prefix isn't
- there."""
- assert s.startswith(prefix)
- return s[len(prefix):]
-
def add_dict(d1, d2):
"""Return a new dict with the contents of both d1 and d2. In case of
conflicting mappings, d2 takes precedence."""