def __init__(self): self.monitored = ImageMonitor( docker.Client('unix://var/run/docker.sock', '1.18')) self.monitored.get_images() self.image_data = [] self.images = {} self.edit = AlwaysFocusedEdit("filter: ", multiline=False) self.listing = self.init_listing() self.filter = "" self.marked_widgets = {} self.in_history = False self.in_inspect = False self.size = () Pane.__init__(self, urwid.Frame( self.listing, self.edit, )) self.original_widget.focus_position = 'body' urwid.connect_signal(self.monitored, 'image-list', self.set_images)
def __init__(self): self.monitored = ImageMonitor(docker.Client("unix://var/run/docker.sock", "1.18")) self.monitored.get_images() self.image_data = [] self.images = {} self.edit = AlwaysFocusedEdit("filter: ", multiline=False) self.listing = self.init_listing() self.filter = "" self.marked_widgets = {} self.in_history = False self.in_inspect = False self.size = () Pane.__init__(self, urwid.Frame(self.listing, self.edit)) self.original_widget.focus_position = "body" urwid.connect_signal(self.monitored, "image-list", self.set_images)
class ImagePane(Pane): def __init__(self): self.monitored = ImageMonitor( docker.Client('unix://var/run/docker.sock', '1.18')) self.monitored.get_images() self.image_data = [] self.images = {} self.edit = AlwaysFocusedEdit("filter: ", multiline=False) self.listing = self.init_listing() self.filter = "" self.marked_widgets = {} self.in_history = False self.in_inspect = False self.size = () Pane.__init__(self, urwid.Frame( self.listing, self.edit, )) self.original_widget.focus_position = 'body' urwid.connect_signal(self.monitored, 'image-list', self.set_images) def init_listing(self): schema = ( { 'name': 'Tag', 'align': 'right', 'weight': 1 }, { 'name': 'Id', 'align': 'center' }, { 'name': 'Created' }, ) return Table(schema, header=True) def make_image_row(self, image): row = self.listing.create_row({ 'Tag': image['tag'], 'Id': image['id'][:12], 'Created': "%s days ago" % image['days_old'], }) row.tag = image['tag'] row.image = image['id'] self.images[row.tag] = row return row def set_images(self, images, force=False): # save the current position _, current_focus = self.listing.get_focus() if images == self.image_data and not force: return self.listing.clear() self.old_images = self.images self.images = {} untagged = [i for i in images if i['tag'] == '<none>:<none>'] tagged = [i for i in images if i['tag'] != '<none>:<none>'] filter = self.filter.lower() def remove_highlight(row): highlighter.remove(row) for image in tagged: in_tag = filter in image['tag'].lower() in_id = filter in image['id'].lower() row = self.make_image_row(image) if in_tag or in_id: self.listing.walker.append(row) if self.old_images and row.tag not in self.old_images: highlighter.apply(row, 'created', 'created') reactor.callLater(1, highlighter.remove, row) for image in untagged: in_tag = filter in image['tag'].lower() in_id = filter in image['id'].lower() row = self.make_image_row(image) if in_tag or in_id: self.listing.walker.append(row) if self.old_images and row.tag not in self.old_images: highlighter.apply(row, 'created', 'created') reactor.callLater(1, highlighter.remove, row) self.image_data = images self.listing.set_focus(current_focus) self.listing.fix_focus() app.draw_screen() def thread(self): return True def keypress(self, size, event): self.size = size self.since_time = time.time() if event == 'close-dialog': if self.in_history: self.in_history = False if self.in_inspect: self.in_inspect = False if event == 'scroll-close': event = 'close-dialog' if self.dialog: return super(ImagePane, self).keypress(size, event) if self.listing.keypress(size, event): if self.handle_event(event): if not self.dialog and self.edit.keypress((size[0], ), event): return super(ImagePane, self).keypress(size, event) else: self.filter = self.edit.edit_text self.set_images(self.image_data, force=True) if event not in [ 'next-image', 'prev-image', 'set-mark', 'unmark-images' ]: thread = threading.Thread(target=self.thread) listener = threading.Thread(target=self.listener) listener.setDaemon(True) listener.start() thread.start() def handle_event(self, event): if event == 'next-image': self.on_next() if self.in_history or self.in_inspect: self.keypress(self.size, 'scroll-close') if self.in_history: self.on_history() if self.in_inspect: self.on_inspect() elif event == 'prev-image': self.on_prev() if self.in_history or self.in_inspect: self.keypress(self.size, 'scroll-close') if self.in_history: self.on_history() if self.in_inspect: self.on_inspect() elif event == 'toggle-show-all': self.on_all() self.monitored.get_images() elif event == 'delete-image': self.delete_marked() elif event == 'tag-image': self.on_tag() elif event == 'inspect-details': self.in_inspect = True self.on_inspect() elif event == 'help': self.on_help() elif event == 'set-mark': self.on_marked() elif event == 'unmark-images': self.on_unmark() elif event == 'view-history': self.in_history = True self.on_history() elif event == 'push-image': self.monitored.get_images() self.push() elif event == 'pull-image': self.pull() self.monitored.get_images() else: self.monitored.get_images() return super(ImagePane, self).handle_event(event) def on_next(self): self.listing.next() def on_prev(self): self.listing.prev() def on_all(self): self.monitored.all = not self.monitored.all def on_marked(self): marked_widget, idx = self.listing.get_focus() if (marked_widget in self.marked_widgets and self.marked_widgets[marked_widget] == "marked"): self.marked_widgets[marked_widget] = "unmarked" self.listing.unmark() else: self.marked_widgets[marked_widget] = "marked" self.listing.mark() def on_unmark(self): for key, value in self.marked_widgets.items(): if value == "marked": self.marked_widgets[key] = "unmarked" key.set_attr_map({None: None}) def _show_history(self, history_json, image_id): history = history_json histories = [(d.get('Id', '')[:12], d.get('CreatedBy', '')) for d in history] dialog = TableDialog("History for %s" % image_id[:12], histories, [{ 'value': "image id", 'weight': 1, 'align': 'center' }, { 'value': "command", 'weight': 4, 'align': 'center' }]) dialog.width = ('relative', 90) self.show_dialog(dialog, ) @catch_docker_errors def on_history(self): widget, idx = self.listing.get_focus() d = threads.deferToThread(app.client.history, widget.image) d.addCallback(self._show_history, widget.image) d.addCallback(lambda r: app.draw_screen()) return d def delete_marked(self): none_marked = True for key, value in self.marked_widgets.items(): if value == "marked" and key.tag != '<none>:<none>': widget = key self.on_delete(widget) del self.marked_widgets[key] none_marked = False if none_marked: widget, idx = self.listing.get_focus() if widget.tag != '<none>:<none>': self.on_delete(widget) @catch_docker_errors def on_delete(self, widget): highlighter.apply(widget, 'deleted', 'deleted') reactor.callLater(10, highlighter.remove, widget) if widget.tag == "<none>:<none>": widget.tag = widget.image d = threads.deferToThread(app.client.remove_image, widget.tag) d.addErrback(lambda _: highlighter.remove(widget) or _) return d @catch_docker_errors def perform_tag(self, image, repo_name): name, tag = split_repo_name(repo_name) repo_name = name + ":" + (tag or 'latest') self.close_dialog() return threads.deferToThread(app.client.tag, image, name, tag or 'latest') def on_tag(self): widget, idx = self.listing.get_focus() name, tag = split_repo_name(widget.tag) prompt = Prompt(lambda name: self.perform_tag(widget.image, name), title="Tag Image", initial=name) self.show_dialog(prompt) @catch_docker_errors def push(self): widget, idx = self.listing.get_focus() name, tag = split_repo_name(widget.tag) highlighter.apply(widget, 'uploading', 'uploading_focus') d = threads.deferToThread(app.client.push, name) def handle_response(r): r = r.replace("}{", "},{") r = r.replace("1)\"}", "1)\"},") r = r.replace("2)\"}", "2)\"},") r = "[%s]" % r messages = [ d.get('status') or d.get('error') for d in json.loads(r) ] self.show_dialog( MessageListBox(messages, title='Push Response', width=100)) reactor.callLater(5.0, highlighter.remove, widget) d.addCallback(handle_response) return d @catch_docker_errors def perform_pull(self, repo_name): name, tag = split_repo_name(repo_name) self.close_dialog() return threads.deferToThread(app.client.pull, name, tag or 'latest') def pull(self): repo_name = '' prompt = Prompt(lambda repo_name: self.perform_pull(repo_name), title="Pull Repository", initial=repo_name) self.show_dialog(prompt) @catch_docker_errors def on_inspect(self): widget, idx = self.listing.get_focus() d = threads.deferToThread(app.client.inspect_image, widget.image) d.addCallback(lambda data: self.show_dialog(ImageInspector(data))) return d def listener(self): s = socket.socket(socket.AF_UNIX) s.connect('/var/run/docker.sock') with closing(s): s.sendall(b'GET /events?since=%d HTTP/1.1\n\n' % self.since_time) header = s.recv(4096) chunk = s.recv(4096) self.monitored.get_images()
class ImagePane(Pane): def __init__(self): self.monitored = ImageMonitor(docker.Client("unix://var/run/docker.sock", "1.18")) self.monitored.get_images() self.image_data = [] self.images = {} self.edit = AlwaysFocusedEdit("filter: ", multiline=False) self.listing = self.init_listing() self.filter = "" self.marked_widgets = {} self.in_history = False self.in_inspect = False self.size = () Pane.__init__(self, urwid.Frame(self.listing, self.edit)) self.original_widget.focus_position = "body" urwid.connect_signal(self.monitored, "image-list", self.set_images) def init_listing(self): schema = ( {"name": "Tag", "align": "right", "weight": 1}, {"name": "Id", "align": "center"}, {"name": "Created"}, ) return Table(schema, header=True) def make_image_row(self, image): row = self.listing.create_row( {"Tag": image["tag"], "Id": image["id"][:12], "Created": "%s days ago" % image["days_old"]} ) row.tag = image["tag"] row.image = image["id"] self.images[row.tag] = row return row def set_images(self, images, force=False): # save the current position _, current_focus = self.listing.get_focus() if images == self.image_data and not force: return self.listing.clear() self.old_images = self.images self.images = {} untagged = [i for i in images if i["tag"] == "<none>:<none>"] tagged = [i for i in images if i["tag"] != "<none>:<none>"] filter = self.filter.lower() def remove_highlight(row): highlighter.remove(row) for image in tagged: in_tag = filter in image["tag"].lower() in_id = filter in image["id"].lower() row = self.make_image_row(image) if in_tag or in_id: self.listing.walker.append(row) if self.old_images and row.tag not in self.old_images: highlighter.apply(row, "created", "created") reactor.callLater(1, highlighter.remove, row) for image in untagged: in_tag = filter in image["tag"].lower() in_id = filter in image["id"].lower() row = self.make_image_row(image) if in_tag or in_id: self.listing.walker.append(row) if self.old_images and row.tag not in self.old_images: highlighter.apply(row, "created", "created") reactor.callLater(1, highlighter.remove, row) self.image_data = images self.listing.set_focus(current_focus) self.listing.fix_focus() app.draw_screen() def thread(self): return True def keypress(self, size, event): self.size = size self.since_time = time.time() if event == "close-dialog": if self.in_history: self.in_history = False if self.in_inspect: self.in_inspect = False if event == "scroll-close": event = "close-dialog" if self.dialog: return super(ImagePane, self).keypress(size, event) if self.listing.keypress(size, event): if self.handle_event(event): if not self.dialog and self.edit.keypress((size[0],), event): return super(ImagePane, self).keypress(size, event) else: self.filter = self.edit.edit_text self.set_images(self.image_data, force=True) if event not in ["next-image", "prev-image", "set-mark", "unmark-images"]: thread = threading.Thread(target=self.thread) listener = threading.Thread(target=self.listener) listener.setDaemon(True) listener.start() thread.start() def handle_event(self, event): if event == "next-image": self.on_next() if self.in_history or self.in_inspect: self.keypress(self.size, "scroll-close") if self.in_history: self.on_history() if self.in_inspect: self.on_inspect() elif event == "prev-image": self.on_prev() if self.in_history or self.in_inspect: self.keypress(self.size, "scroll-close") if self.in_history: self.on_history() if self.in_inspect: self.on_inspect() elif event == "toggle-show-all": self.on_all() self.monitored.get_images() elif event == "delete-image": self.delete_marked() elif event == "tag-image": self.on_tag() elif event == "inspect-details": self.in_inspect = True self.on_inspect() elif event == "help": self.on_help() elif event == "set-mark": self.on_marked() elif event == "unmark-images": self.on_unmark() elif event == "view-history": self.in_history = True self.on_history() elif event == "push-image": self.monitored.get_images() self.push() elif event == "pull-image": self.pull() self.monitored.get_images() else: self.monitored.get_images() return super(ImagePane, self).handle_event(event) def on_next(self): self.listing.next() def on_prev(self): self.listing.prev() def on_all(self): self.monitored.all = not self.monitored.all def on_marked(self): marked_widget, idx = self.listing.get_focus() if marked_widget in self.marked_widgets and self.marked_widgets[marked_widget] == "marked": self.marked_widgets[marked_widget] = "unmarked" self.listing.unmark() else: self.marked_widgets[marked_widget] = "marked" self.listing.mark() def on_unmark(self): for key, value in self.marked_widgets.items(): if value == "marked": self.marked_widgets[key] = "unmarked" key.set_attr_map({None: None}) def _show_history(self, history_json, image_id): history = history_json histories = [(d.get("Id", "")[:12], d.get("CreatedBy", "")) for d in history] dialog = TableDialog( "History for %s" % image_id[:12], histories, [ {"value": "image id", "weight": 1, "align": "center"}, {"value": "command", "weight": 4, "align": "center"}, ], ) dialog.width = ("relative", 90) self.show_dialog(dialog) @catch_docker_errors def on_history(self): widget, idx = self.listing.get_focus() d = threads.deferToThread(app.client.history, widget.image) d.addCallback(self._show_history, widget.image) d.addCallback(lambda r: app.draw_screen()) return d def delete_marked(self): none_marked = True for key, value in self.marked_widgets.items(): if value == "marked" and key.tag != "<none>:<none>": widget = key self.on_delete(widget) del self.marked_widgets[key] none_marked = False if none_marked: widget, idx = self.listing.get_focus() if widget.tag != "<none>:<none>": self.on_delete(widget) @catch_docker_errors def on_delete(self, widget): highlighter.apply(widget, "deleted", "deleted") reactor.callLater(10, highlighter.remove, widget) if widget.tag == "<none>:<none>": widget.tag = widget.image d = threads.deferToThread(app.client.remove_image, widget.tag) d.addErrback(lambda _: highlighter.remove(widget) or _) return d @catch_docker_errors def perform_tag(self, image, repo_name): name, tag = split_repo_name(repo_name) repo_name = name + ":" + (tag or "latest") self.close_dialog() return threads.deferToThread(app.client.tag, image, name, tag or "latest") def on_tag(self): widget, idx = self.listing.get_focus() name, tag = split_repo_name(widget.tag) prompt = Prompt(lambda name: self.perform_tag(widget.image, name), title="Tag Image", initial=name) self.show_dialog(prompt) @catch_docker_errors def push(self): widget, idx = self.listing.get_focus() name, tag = split_repo_name(widget.tag) highlighter.apply(widget, "uploading", "uploading_focus") d = threads.deferToThread(app.client.push, name) def handle_response(r): r = r.replace("}{", "},{") r = r.replace('1)"}', '1)"},') r = r.replace('2)"}', '2)"},') r = "[%s]" % r messages = [d.get("status") or d.get("error") for d in json.loads(r)] self.show_dialog(MessageListBox(messages, title="Push Response", width=100)) reactor.callLater(5.0, highlighter.remove, widget) d.addCallback(handle_response) return d @catch_docker_errors def perform_pull(self, repo_name): name, tag = split_repo_name(repo_name) self.close_dialog() return threads.deferToThread(app.client.pull, name, tag or "latest") def pull(self): repo_name = "" prompt = Prompt(lambda repo_name: self.perform_pull(repo_name), title="Pull Repository", initial=repo_name) self.show_dialog(prompt) @catch_docker_errors def on_inspect(self): widget, idx = self.listing.get_focus() d = threads.deferToThread(app.client.inspect_image, widget.image) d.addCallback(lambda data: self.show_dialog(ImageInspector(data))) return d def listener(self): s = socket.socket(socket.AF_UNIX) s.connect("/var/run/docker.sock") with closing(s): s.sendall(b"GET /events?since=%d HTTP/1.1\n\n" % self.since_time) header = s.recv(4096) chunk = s.recv(4096) self.monitored.get_images()