fetch: add support for the traditional FETCH_HEAD behavior
[git-cola.git] / cola / interaction.py
blob3b30183b0872648cdee212eace769283e0095b7f
1 import os
2 import sys
4 from . import core
5 from .i18n import N_
8 class Interaction:
9 """Prompts the user and answers questions"""
11 VERBOSE = bool(os.getenv('GIT_COLA_VERBOSE'))
13 @classmethod
14 def command(cls, title, cmd, status, out, err):
15 """Log a command and display error messages on failure"""
16 cls.log_status(status, out, err)
17 if status != 0:
18 cls.command_error(title, cmd, status, out, err)
20 @classmethod
21 def command_error(cls, title, cmd, status, out, err):
22 """Display an error message for a failed command"""
23 core.print_stderr(title)
24 core.print_stderr('-' * len(title))
25 core.print_stderr(cls.format_command_status(cmd, status))
26 core.print_stdout('')
27 if out:
28 core.print_stdout(out)
29 if err:
30 core.print_stderr(err)
32 @staticmethod
33 def format_command_status(cmd, status):
34 return N_('"%(command)s" returned exit status %(status)d') % {
35 'command': cmd,
36 'status': status,
39 @staticmethod
40 def format_out_err(out, err):
41 """Format stdout and stderr into a single string"""
42 details = out or ''
43 if err:
44 if details and not details.endswith('\n'):
45 details += '\n'
46 details += err
47 return details
49 @staticmethod
50 def information(title, message=None, details=None, informative_text=None):
51 if message is None:
52 message = title
53 scope = {}
54 scope['title'] = title
55 scope['title_dashes'] = '-' * len(title)
56 scope['message'] = message
57 scope['details'] = ('\n' + details) if details else ''
58 scope['informative_text'] = (
59 ('\n' + informative_text) if informative_text else ''
61 sys.stdout.write(
62 """
63 %(title)s
64 %(title_dashes)s
65 %(message)s%(informative_text)s%(details)s\n"""
66 % scope
68 sys.stdout.flush()
70 @classmethod
71 def critical(cls, title, message=None, details=None):
72 """Show a warning with the provided title and message."""
73 cls.information(title, message=message, details=details)
75 @classmethod
76 def confirm(
77 cls,
78 title,
79 text,
80 informative_text,
81 ok_text,
82 icon=None,
83 default=True,
84 cancel_text=None,
86 cancel_text = cancel_text or 'Cancel'
87 icon = icon or '?'
89 cls.information(title, message=text, informative_text=informative_text)
90 if default:
91 prompt = '%s? [Y/n] ' % ok_text
92 else:
93 prompt = '%s? [y/N] ' % ok_text
94 sys.stdout.write(prompt)
95 sys.stdout.flush()
96 answer = sys.stdin.readline().strip()
97 if answer:
98 result = answer.lower().startswith('y')
99 else:
100 result = default
101 return result
103 @classmethod
104 def question(cls, title, message, default=True):
105 return cls.confirm(title, message, '', ok_text=N_('Continue'), default=default)
107 @classmethod
108 def run_command(cls, title, cmd):
109 cls.log('# ' + title)
110 cls.log('$ ' + core.list2cmdline(cmd))
111 status, out, err = core.run_command(cmd)
112 cls.log_status(status, out, err)
113 return status, out, err
115 @classmethod
116 def confirm_config_action(cls, _context, name, _opts):
117 return cls.confirm(
118 N_('Run %s?') % name,
119 N_('Run the "%s" command?') % name,
121 ok_text=N_('Run'),
124 @classmethod
125 def log_status(cls, status, out, err=None):
126 msg = ((out + '\n') if out else '') + ((err + '\n') if err else '')
127 cls.log(msg)
128 cls.log('exit status %s' % status)
130 @classmethod
131 def log(cls, message):
132 if cls.VERBOSE:
133 core.print_stdout(message)
135 @classmethod
136 def save_as(cls, filename, title):
137 if cls.confirm(title, 'Save as %s?' % filename, '', ok_text='Save'):
138 return filename
139 return None
141 @staticmethod
142 def async_command(title, command, runtask):
143 pass
145 @classmethod
146 def choose_ref(cls, _context, title, button_text, default=None, icon=None):
147 icon = icon or '?'
148 cls.information(title, button_text)
149 return sys.stdin.readline().strip() or default