|
11 | 11 |
|
12 | 12 | __docformat__ = 'restructuredtext' |
13 | 13 |
|
14 | | -from collections import OrderedDict |
| 14 | +from functools import partial |
15 | 15 |
|
16 | 16 | from .base import Interface |
17 | 17 | # import reproman.interface.base # Needed for test patching |
@@ -55,50 +55,86 @@ class Ls(Interface): |
55 | 55 |
|
56 | 56 | @staticmethod |
57 | 57 | def __call__(resrefs=None, verbose=False, refresh=False): |
58 | | - id_length = 19 # todo: make it possible to output them long |
59 | | - template = '{:<20} {:<20} {:<%(id_length)s} {!s:<10}' % locals() |
60 | | - ui.message(template.format('RESOURCE NAME', 'TYPE', 'ID', 'STATUS')) |
61 | | - ui.message(template.format('-------------', '----', '--', '------')) |
| 58 | + from pyout import Tabular |
62 | 59 |
|
63 | | - results = OrderedDict() |
64 | 60 | manager = get_manager() |
65 | 61 | if not resrefs: |
66 | 62 | resrefs = (manager.inventory[n]["id"] for n in sorted(manager) |
67 | 63 | if not n.startswith("_")) |
68 | 64 |
|
69 | | - for resref in resrefs: |
70 | | - try: |
71 | | - resource = manager.get_resource(resref) |
72 | | - name = resource.name |
73 | | - except ResourceError as e: |
74 | | - lgr.warning("Manager did not return a resource for %s: %s", |
75 | | - resref, exc_str(e)) |
76 | | - continue |
77 | | - |
| 65 | + table = Tabular( |
| 66 | + # Note: We're going with the name as the row key even though ID |
| 67 | + # would be the more natural choice because (1) inventory already |
| 68 | + # uses the name as the key, so we know it's unique and (2) sadly we |
| 69 | + # can't rely on the ID saying set after a .connect() calls (e.g., |
| 70 | + # see docker_container.connect()). |
| 71 | + ["name", "type", "id", "status"], |
| 72 | + style={ |
| 73 | + "default_": {"width": {"marker": "…", "truncate": "center"}}, |
| 74 | + "header_": {"underline": True, |
| 75 | + "transform": str.upper}, |
| 76 | + "status": {"color": |
| 77 | + {"re_lookup": [["^running$", "green"], |
| 78 | + ["^(stopped|exited)$", "red"], |
| 79 | + ["(ERROR|NOT FOUND)", "red"]]}, |
| 80 | + "bold": |
| 81 | + {"re_lookup": [["(ERROR|NOT FOUND)", True]]}}}) |
| 82 | + |
| 83 | + def get_status(res): |
78 | 84 | if refresh: |
| 85 | + def fn(): |
| 86 | + try: |
| 87 | + res.connect() |
| 88 | + except Exception as e: |
| 89 | + status = 'CONNECTION ERROR' |
| 90 | + else: |
| 91 | + status = res.status if res.id else 'NOT FOUND' |
| 92 | + return status |
| 93 | + return "querying…", fn |
| 94 | + else: |
| 95 | + return res.status |
| 96 | + |
| 97 | + # Store a list of actions to do after the table is finalized so that we |
| 98 | + # don't interrupt the table's output. |
| 99 | + do_after = [] |
| 100 | + # The refresh happens in an asynchronous call. Keep a list of resources |
| 101 | + # that we should ask pyout about once the table is finalized. |
| 102 | + resources_to_refresh = [] |
| 103 | + with table: |
| 104 | + for resref in resrefs: |
79 | 105 | try: |
80 | | - resource.connect() |
81 | | - if not resource.id: |
82 | | - resource.status = 'NOT FOUND' |
83 | | - except Exception as e: |
84 | | - lgr.debug("%s resource query error: %s", name, exc_str(e)) |
85 | | - resource.status = 'CONNECTION ERROR' |
86 | | - |
87 | | - manager.inventory[name].update({'status': resource.status}) |
88 | | - |
89 | | - id_ = manager.inventory[name]['id'] |
90 | | - msgargs = ( |
91 | | - name, |
92 | | - resource.type, |
93 | | - id_[:id_length], |
94 | | - resource.status, |
95 | | - ) |
96 | | - ui.message(template.format(*msgargs)) |
97 | | - results[(name,)] = dict(zip(["name", "type", "id", "status"], |
98 | | - msgargs)) |
| 106 | + resource = manager.get_resource(resref) |
| 107 | + name = resource.name |
| 108 | + except ResourceError as e: |
| 109 | + do_after.append( |
| 110 | + partial(lgr.warning, |
| 111 | + "Manager did not return a resource for %s: %s", |
| 112 | + resref, |
| 113 | + exc_str(e))) |
| 114 | + continue |
| 115 | + |
| 116 | + id_ = manager.inventory[name]['id'] |
| 117 | + assert id_ == resource.id, "bug in resource logic" |
| 118 | + table([name, |
| 119 | + resource.type, |
| 120 | + id_, |
| 121 | + get_status(resource)]) |
| 122 | + resources_to_refresh.append(resource) |
| 123 | + |
| 124 | + if do_after or not refresh: |
| 125 | + # Distinguish between the table and added information. |
| 126 | + ui.message("\n") |
| 127 | + |
| 128 | + for fn in do_after: |
| 129 | + fn() |
99 | 130 |
|
100 | 131 | if refresh: |
101 | | - manager.save_inventory() |
| 132 | + if resources_to_refresh: |
| 133 | + for res in resources_to_refresh: |
| 134 | + name = res.name |
| 135 | + status = table[(name,)]["status"] |
| 136 | + manager.inventory[name].update({'status': status}) |
| 137 | + manager.save_inventory() |
102 | 138 | else: |
103 | 139 | ui.message('Use --refresh option to view updated status.') |
104 | | - return results |
| 140 | + return table |
0 commit comments