mirror of
https://github.com/outbackdingo/patroni.git
synced 2026-08-26 07:30:14 +00:00
Compare commits
5
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b3f109751c | ||
|
|
52761ac46c | ||
|
|
7c409f59d7 | ||
|
|
ee79a390c2 | ||
|
|
6dcaa697c0 |
+37
-22
@@ -1,3 +1,4 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
Patroni Control
|
||||
'''
|
||||
@@ -32,8 +33,8 @@ from patroni.postgresql.misc import postgres_version_to_int
|
||||
from patroni.utils import cluster_as_json, patch_config, polling_loop
|
||||
from patroni.request import PatroniRequest
|
||||
from patroni.version import __version__
|
||||
from prettytable import ALL, FRAME, PrettyTable
|
||||
from six.moves.urllib_parse import urlparse
|
||||
from texttable import Texttable
|
||||
|
||||
CONFIG_DIR_PATH = click.get_app_dir('patroni')
|
||||
CONFIG_FILE_PATH = os.path.join(CONFIG_DIR_PATH, 'patronictl.yaml')
|
||||
@@ -47,32 +48,42 @@ class PatroniCtlException(ClickException):
|
||||
pass
|
||||
|
||||
|
||||
class PatronictlPrettyTable(PrettyTable):
|
||||
class PatronictlPrettyTable(Texttable):
|
||||
|
||||
def __init__(self, header, *args, **kwargs):
|
||||
PrettyTable.__init__(self, *args, **kwargs)
|
||||
def __init__(self, header=None):
|
||||
Texttable.__init__(self, 0)
|
||||
self.__table_header = header
|
||||
self.__hline_num = 0
|
||||
self.__hline = None
|
||||
|
||||
if sys.platform != 'win32':
|
||||
self._char_horiz = u'─'
|
||||
self._char_vert = u'│'
|
||||
self._hline_header = self._hline
|
||||
self._char_header = self._char_horiz
|
||||
|
||||
def _is_first_hline(self):
|
||||
return self.__hline_num == 0
|
||||
|
||||
def _set_hline(self, value):
|
||||
self.__hline = value
|
||||
def _is_last_hline(self):
|
||||
return self.__hline_num > (len(self._rows) if self._has_hlines() else int(bool(self._header)))
|
||||
|
||||
def _get_hline(self):
|
||||
ret = self.__hline
|
||||
def _hline(self):
|
||||
if sys.platform == 'win32':
|
||||
left = right = self._char_corner
|
||||
elif self._is_first_hline():
|
||||
left, self._char_corner, right = u'┌', u'┬', u'┐'
|
||||
elif not self._is_last_hline():
|
||||
left, self._char_corner, right = u'├', u'┼', u'┤'
|
||||
else:
|
||||
left, self._char_corner, right = u'└', u'┴', u'┘'
|
||||
|
||||
line = self._build_hline()
|
||||
|
||||
# Inject nice table header
|
||||
if self._is_first_hline() and self.__table_header:
|
||||
header = self.__table_header[:len(ret) - 2]
|
||||
ret = "".join([ret[0], header, ret[1 + len(header):]])
|
||||
left += self.__table_header
|
||||
|
||||
self.__hline_num += 1
|
||||
return ret
|
||||
|
||||
_hrule = property(_get_hline, _set_hline)
|
||||
return left + line[len(left):-2] + right + '\n'
|
||||
|
||||
|
||||
def parse_dcs(dcs):
|
||||
@@ -186,13 +197,17 @@ def print_output(columns, rows, alignment=None, fmt='pretty', header=None, delim
|
||||
for r in ([columns] if columns else []) + rows:
|
||||
click.echo(delimiter.join(map(str, r)))
|
||||
else:
|
||||
hrules = ALL if any(any(isinstance(c, six.string_types) and '\n' in c for c in r) for r in rows) else FRAME
|
||||
table = PatronictlPrettyTable(header, columns, hrules=hrules)
|
||||
for k, v in (alignment or {}).items():
|
||||
table.align[k] = v
|
||||
for r in rows:
|
||||
table.add_row(r)
|
||||
click.echo(table)
|
||||
table = PatronictlPrettyTable(header)
|
||||
if not any(any(isinstance(c, six.string_types) and '\n' in c for c in r) for r in rows):
|
||||
table.set_deco(Texttable.VLINES | Texttable.BORDER | Texttable.HEADER)
|
||||
if rows:
|
||||
if columns:
|
||||
table.header(columns)
|
||||
table.set_cols_align([(alignment or {}).get(c, 'l') for c in columns])
|
||||
table.add_rows(rows, header=False)
|
||||
else:
|
||||
table.add_rows([columns], header=False)
|
||||
click.echo(table.draw())
|
||||
|
||||
|
||||
def watching(w, watch, max_count=None, clear=True):
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@ kazoo>=1.3.1
|
||||
python-etcd>=0.4.3,<0.5
|
||||
python-consul>=0.7.1
|
||||
click>=4.1
|
||||
prettytable>=0.7
|
||||
texttable
|
||||
python-dateutil
|
||||
psutil>=2.0.0
|
||||
cdiff
|
||||
|
||||
+9
-3
@@ -5,9 +5,9 @@ import unittest
|
||||
from click.testing import CliRunner
|
||||
from datetime import datetime, timedelta
|
||||
from mock import patch, Mock
|
||||
from patroni.ctl import ctl, store_config, load_config, output_members, get_dcs, parse_dcs, \
|
||||
get_all_members, get_any_member, get_cursor, query_member, configure, PatroniCtlException, apply_config_changes, \
|
||||
format_config_for_editing, show_diff, invoke_editor, format_pg_version, find_executable, CONFIG_FILE_PATH
|
||||
from patroni.ctl import ctl, store_config, load_config, output_members, get_dcs, parse_dcs, get_all_members, \
|
||||
get_any_member, get_cursor, query_member, configure, PatroniCtlException, apply_config_changes, show_diff, \
|
||||
format_config_for_editing, invoke_editor, format_pg_version, find_executable, print_output, CONFIG_FILE_PATH
|
||||
from patroni.dcs.etcd import Client, Failover
|
||||
from patroni.utils import tzutc
|
||||
from psycopg2 import OperationalError
|
||||
@@ -165,6 +165,12 @@ class TestCtl(unittest.TestCase):
|
||||
def test_get_dcs(self):
|
||||
self.assertRaises(PatroniCtlException, get_dcs, {'dummy': {}}, 'dummy')
|
||||
|
||||
@patch('sys.platform', 'win32')
|
||||
@patch('click.echo')
|
||||
def test_print_output(self, mock_click_echo):
|
||||
print_output(['a'], [])
|
||||
mock_click_echo.assert_called_once_with('+---+\n| a |\n+---+')
|
||||
|
||||
@patch('psycopg2.connect', psycopg2_connect)
|
||||
@patch('patroni.ctl.query_member', Mock(return_value=([['mock column']], None)))
|
||||
@patch('patroni.ctl.get_dcs')
|
||||
|
||||
Reference in New Issue
Block a user