nncli

NextCloud Notes Command Line Interface
git clone git://git.danielmoch.com/nncli.git
Log | Files | Refs | LICENSE

commit 9888cb7e1af42b79dc1fffb439486744a59a7833
parent c0cb5f29881697cd3c8f3691b1d4cd9fc25e73e6
Author: Eric Davis <edavis@insanum.com>
Date:   Mon,  7 Jul 2014 14:04:16 -0700

unified status message logging and print paths

Diffstat:
Mconfig.py | 8++++----
Mnotes_db.py | 38+++++++++++++++++---------------------
Msncli.py | 126++++++++++++++++++++++++++++++++++++++-----------------------------------------
Mview_titles.py | 4++--
4 files changed, 83 insertions(+), 93 deletions(-)

diff --git a/config.py b/config.py @@ -58,8 +58,8 @@ def __init__(self): 'clr_default_bg' : 'default', 'clr_status_bar_fg' : 'dark gray', 'clr_status_bar_bg' : 'light gray', - 'clr_status_message_fg' : 'dark gray', - 'clr_status_message_bg' : 'light gray', + 'clr_log_fg' : 'dark gray', + 'clr_log_bg' : 'light gray', 'clr_search_bar_fg' : 'white', 'clr_search_bar_bg' : 'light red', 'clr_note_focus_fg' : 'white', @@ -163,8 +163,8 @@ def __init__(self): 'default_bg' : [ cp.get(cfg_sec, 'clr_default_bg'), 'Default bg' ], 'status_bar_fg' : [ cp.get(cfg_sec, 'clr_status_bar_fg'), 'Status bar fg' ], 'status_bar_bg' : [ cp.get(cfg_sec, 'clr_status_bar_bg'), 'Status bar bg' ], - 'status_message_fg' : [ cp.get(cfg_sec, 'clr_status_message_fg'), 'Status message fg' ], - 'status_message_bg' : [ cp.get(cfg_sec, 'clr_status_message_bg'), 'Status message bg' ], + 'log_fg' : [ cp.get(cfg_sec, 'clr_log_fg'), 'Log message fg' ], + 'log_bg' : [ cp.get(cfg_sec, 'clr_log_bg'), 'Log message bg' ], 'search_bar_fg' : [ cp.get(cfg_sec, 'clr_search_bar_fg'), 'Search bar fg' ], 'search_bar_bg' : [ cp.get(cfg_sec, 'clr_search_bar_bg'), 'Search bar bg' ], 'note_focus_fg' : [ cp.get(cfg_sec, 'clr_note_focus_fg'), 'Note title focus fg' ], diff --git a/notes_db.py b/notes_db.py @@ -7,7 +7,6 @@ import glob import os import json -import logging from Queue import Queue, Empty import re import simplenote @@ -30,10 +29,11 @@ class WriteError(RuntimeError): class NotesDB(utils.SubjectMixin): """NotesDB will take care of the local notes database and syncing with SN. """ - def __init__(self, config): + def __init__(self, config, log): utils.SubjectMixin.__init__(self) self.config = config + self.log = log # create db dir if it does not exist if not os.path.exists(self.config.get_config('db_path')): @@ -50,12 +50,10 @@ def __init__(self, config): n = json.load(open(fn, 'rb')) except IOError, e: - logging.error('NotesDB_init: Error opening %s: %s' % (fn, str(e))) - raise ReadError ('Error opening note file') + raise ReadError ('Error opening {0}: {1}'.format(fn, str(e))) except ValueError, e: - logging.error('NotesDB_init: Error reading %s: %s' % (fn, str(e))) - raise ReadError ('Error reading note file') + raise ReadError ('Error reading {0}: {1}'.format(fn, str(e))) else: # we always have a localkey, also when we don't have a note['key'] yet (no sync) @@ -432,7 +430,7 @@ def sync_note(self, k, check_for_new): # update if note has no key or it has been modified since last sync if not note.get('key') or \ float(note.get('modifydate')) > float(note.get('syncdate')): - logging.debug('Sync worker: updating note %s', k) + self.log('Sync worker: updating note {0}'.format(k)) # only send required fields cn = copy.deepcopy(note) @@ -465,17 +463,17 @@ def sync_note(self, k, check_for_new): # store when we've synced n['syncdate'] = time.time() note.update(n) - logging.debug('Sync worker: updated note %s', k) + self.log('Sync worker: updated note {0}'.format(k)) return (k, new_content) else: - logging.debug('ERROR: Sync worker: update failed for note %s', k) + self.log('ERROR: Sync worker: update failed for note {0}'.format(k)) return None else: if not check_for_new: return None - logging.debug('Sync worker: checking for server update of note %s', k) + self.log('Sync worker: checking for server update of note {0}'.format(k)) # our note is synced so lets check if server has something newer gret = self.simplenote.get_note(note['key']) @@ -486,18 +484,18 @@ def sync_note(self, k, check_for_new): # store what we pulled down from the server n['syncdate'] = time.time() note.update(n) - logging.debug('Sync worker: server had an update for note %s', k) + self.log('Sync worker: server had an update for note {0}'.format(k)) return (k, True) else: - logging.debug('Sync worker: server in sync with note %s', k) + self.log('Sync worker: server in sync with note {0}'.format(k)) return (k, False) else: - logging.debug('ERROR: Sync worker: get failed for note %s', k) + self.log('ERROR: Sync worker: get failed for note {0}'.format(k)) return None # sync worker thread... def sync_worker(self): - logging.debug('Sync worker: started') + self.log('Sync worker: started') while True: time.sleep(5) now = time.time() @@ -620,7 +618,7 @@ def sync_full(self): try: self.helper_save_note(uk, self.notes[uk]) except WriteError, e: - raise WriteError(e) + raise WriteError (str(e)) for dk in local_deletes.keys(): fn = self.helper_key_to_fname(dk) @@ -633,10 +631,10 @@ def sync_full(self): # save worker thread... def save_worker(self): - logging.debug('Save worker: started') + self.log('Save worker: started') while True: time.sleep(5) - #logging.debug('Save worker: checking for work') + #self.log('Save worker: checking for work') for k,n in self.notes.items(): savedate = float(n.get('savedate')) if float(n.get('modifydate')) > savedate or \ @@ -644,10 +642,8 @@ def save_worker(self): try: # this will write the new savedate into the note self.helper_save_note(k, n) - logging.debug('Save worker: saved note %s', k) + self.log('Save worker: saved note {0}'.format(k)) except WriteError, e: - msg = 'ERROR: Failed to write file to the filesystem!' - logging.error(msg) - print msg + self.log('ERROR: Failed to write file to the filesystem!') os._exit(1) diff --git a/sncli.py b/sncli.py @@ -32,9 +32,9 @@ def __init__(self): logging.debug('sncli logging initialized') try: - self.ndb = NotesDB(self.config) + self.ndb = NotesDB(self.config, self.log) except Exception, e: - print e + self.log(str(e)) sys.exit(1) def sync_full(self): @@ -47,29 +47,21 @@ def gui_sync_full_initial(self, loop, arg): self.gui_sync_full_threaded() def gui_observer_notes_db_change_note_status(self, ndb, evt_type, evt): - logging.debug(evt.msg) - self.gui_status_message_set(evt.msg) + self.log(evt.msg) def gui_observer_notes_db_sync_full(self, ndb, evt_type, evt): - logging.debug(evt.msg) - self.gui_status_message_set(evt.msg) + self.log(evt.msg) def gui_observer_notes_db_synced_note(self, ndb, evt_type, evt): - logging.debug(evt.msg) - self.gui_status_message_set(evt.msg) - # XXX - # update view if note synced back is the visible one + self.log(evt.msg) + # XXX update view if note synced back is the visible one def get_editor(self): editor = self.config.get_config('editor') if not editor and os.environ['EDITOR']: editor = os.environ['EDITOR'] if not editor: - msg = u'No editor configured!' - if self.gui: - self.gui_status_message_set(msg) - else: - print msg + self.log(u'No editor configured!') return None return editor @@ -78,11 +70,7 @@ def get_pager(self): if not pager and os.environ['PAGER']: pager = os.environ['PAGER'] if not pager: - msg = u'No pager configured!' - if self.gui: - self.gui_status_message_set(msg) - else: - print msg + self.log(u'No pager configured!') return None return pager @@ -129,47 +117,53 @@ def gui_body_get(self): def gui_body_focus(self): self.master_frame.focus_position = 'body' - def gui_status_message_timeout(self, loop, arg): - self.status_message_lock.acquire() + def log_timeout(self, loop, arg): + self.log_lock.acquire() - self.status_message_alarm = None + self.log_alarm = None self.gui_footer_clear() - self.status_message_lock.release() + self.log_lock.release() + + def log_cancel(self): + self.log_lock.acquire() - def gui_status_message_cancel(self): - self.status_message_lock.acquire() + if self.log_alarm: + self.sncli_loop.remove_alarm(self.log_alarm) + self.log_alarm = None - if self.status_message_alarm: - self.sncli_loop.remove_alarm(self.status_message_alarm) - self.status_message_alarm = None + self.log_lock.release() - self.status_message_lock.release() + def log(self, msg): + logging.debug(msg) + + if not self.do_gui: + print msg + return - def gui_status_message_set(self, msg): - self.status_message_lock.acquire() + self.log_lock.acquire() # if there is already a message showing then concatenate them existing_msg = '' - if self.status_message_alarm and \ + if self.log_alarm and \ 'footer' in self.master_frame.contents.keys(): existing_msg = \ self.master_frame.contents['footer'][0].base_widget.text + u'\n' # cancel any existing state message alarm - if self.status_message_alarm: - self.sncli_loop.remove_alarm(self.status_message_alarm) - self.status_message_alarm = None + if self.log_alarm: + self.sncli_loop.remove_alarm(self.log_alarm) + self.log_alarm = None self.gui_footer_set(urwid.AttrMap(urwid.Text(existing_msg + msg), - 'status_message')) + 'log')) - self.status_message_alarm = \ + self.log_alarm = \ self.sncli_loop.set_alarm_at(time.time() + 5, - self.gui_status_message_timeout, + self.log_timeout, None) - self.status_message_lock.release() + self.log_lock.release() def gui_update_status_bar(self): if self.status_bar != 'yes': @@ -231,7 +225,7 @@ def gui_pipe_input(self, cmd): pipe.stdin.close() pipe.wait() except OSError, e: - self.gui_status_message_set(u'Pipe error: ' + str(e)) + self.log(u'Pipe error: ' + str(e)) finally: self.gui_reset() @@ -365,7 +359,7 @@ def gui_frame_keypress(self, size, key): self.gui_clear() subprocess.check_call(editor + u' ' + temp.tempfile_name(tf), shell=True) except Exception, e: - self.gui_status_message_set(u'Editor error: ' + str(e)) + self.log(u'Editor error: ' + str(e)) temp.tempfile_delete(tf) return None finally: @@ -373,7 +367,7 @@ def gui_frame_keypress(self, size, key): content = ''.join(temp.tempfile_content(tf)) if content: - self.gui_status_message_set(u'New note created') + self.log(u'New note created') self.ndb.create_note(content) temp.tempfile_delete(tf) @@ -400,7 +394,7 @@ def gui_frame_keypress(self, size, key): self.gui_clear() subprocess.check_call(editor + u' ' + temp.tempfile_name(tf), shell=True) except Exception, e: - self.gui_status_message_set(u'Editor error: ' + str(e)) + self.log(u'Editor error: ' + str(e)) temp.tempfile_delete(tf) return None finally: @@ -409,7 +403,7 @@ def gui_frame_keypress(self, size, key): new_content = ''.join(temp.tempfile_content(tf)) md5_new = md5.new(new_content).digest() if md5_old != md5_new: - self.gui_status_message_set(u'Note updated') + self.log(u'Note updated') self.ndb.set_note_content(note['key'], new_content) if self.gui_body_get().__class__ == view_titles.ViewTitles: lb.update_note_title(None) @@ -450,7 +444,7 @@ def gui_frame_keypress(self, size, key): self.gui_clear() subprocess.check_call(pager + u' ' + temp.tempfile_name(tf), shell=True) except Exception, e: - self.gui_status_message_set(u'Pager error: ' + str(e)) + self.log(u'Pager error: ' + str(e)) temp.tempfile_delete(tf) return None finally: @@ -459,7 +453,7 @@ def gui_frame_keypress(self, size, key): new_content = ''.join(temp.tempfile_content(tf)) md5_new = md5.new(new_content).digest() if md5_old != md5_new: - self.gui_status_message_set(u'Note updated') + self.log(u'Note updated') self.ndb.set_note_content(note['key'], new_content) lb.update_note_title(None) @@ -477,7 +471,7 @@ def gui_frame_keypress(self, size, key): else: # self.gui_body_get().__class__ == view_note.ViewNote: note = lb.note - self.gui_status_message_cancel() + self.log_cancel() self.gui_footer_set( urwid.AttrMap( user_input.UserInput(self.config, @@ -518,7 +512,7 @@ def gui_frame_keypress(self, size, key): if self.gui_body_get().__class__ != view_titles.ViewTitles: return key - self.gui_status_message_cancel() + self.log_cancel() self.gui_footer_set(urwid.AttrMap( user_input.UserInput(self.config, key, '', @@ -604,7 +598,7 @@ def gui_frame_keypress(self, size, key): else: # self.gui_body_get().__class__ == view_note.ViewNote: note = lb.note - self.gui_status_message_cancel() + self.log_cancel() self.gui_footer_set( urwid.AttrMap( user_input.UserInput(self.config, @@ -660,8 +654,8 @@ def gui(self, do_sync): self.last_view = [] self.status_bar = self.config.get_config('status_bar') - self.status_message_alarm = None - self.status_message_lock = threading.Lock() + self.log_alarm = None + self.log_lock = threading.Lock() self.thread_save = threading.Thread(target=self.ndb.save_worker) self.thread_save.setDaemon(True) @@ -676,16 +670,16 @@ def gui(self, do_sync): self.view_titles = \ view_titles.ViewTitles(self.config, { - 'ndb' : self.ndb, - 'search_string' : None, - 'status_message' : self.gui_status_message_set + 'ndb' : self.ndb, + 'search_string' : None, + 'log' : self.log }) self.view_note = \ view_note.ViewNote(self.config, { - 'ndb' : self.ndb, - 'key' : None, - 'status_message' : self.gui_status_message_set + 'ndb' : self.ndb, + 'key' : None, + 'log' : self.log }) self.view_log = view_log.ViewLog(self.config) @@ -699,9 +693,9 @@ def gui(self, do_sync): ('status_bar', self.config.get_color('status_bar_fg'), self.config.get_color('status_bar_bg') ), - ('status_message', - self.config.get_color('status_message_fg'), - self.config.get_color('status_message_bg') ), + ('log', + self.config.get_color('log_fg'), + self.config.get_color('log_bg') ), ('search_bar', self.config.get_color('search_bar_fg'), self.config.get_color('search_bar_bg') ), @@ -795,7 +789,7 @@ def cli_create_note(self, from_stdin): def save_new_note(content): if content and content != u'\n': - print u'New note created' + self.log(u'New note created') self.ndb.create_note(content) self.ndb.sync_full() @@ -813,7 +807,7 @@ def save_new_note(content): try: subprocess.check_call(editor + u' ' + temp.tempfile_name(tf), shell=True) except Exception, e: - print u'Editor error: ' + str(e) + self.log(u'Editor error: ' + str(e)) temp.tempfile_delete(tf) return @@ -824,13 +818,13 @@ def save_new_note(content): def SIGINT_handler(signum, frame): - print('\nSignal caught, bye!') + print u'\nSignal caught, bye!' sys.exit(1) signal.signal(signal.SIGINT, SIGINT_handler) def usage(): - print 'Usage: sncli ...' + print u'Usage: sncli ...' sys.exit(0) def main(argv): @@ -854,7 +848,7 @@ def main(argv): elif opt == '--key': key = arg else: - print "ERROR: Unhandled option" + print u'ERROR: Unhandled option' usage() if gui and args: usage() # not quite right... diff --git a/view_titles.py b/view_titles.py @@ -8,7 +8,7 @@ def __init__(self, config, args): self.config = config self.ndb = args['ndb'] self.search_string = args['search_string'] - self.status_message = args['status_message'] + self.log = args['log'] self.note_list, match_regex, self.all_notes_cnt = \ self.ndb.filter_notes(self.search_string) super(ViewTitles, self).__init__( @@ -21,7 +21,7 @@ def update_note_list(self, search_string): self.body[:] = \ urwid.SimpleFocusListWalker(self.get_note_titles()) if len(self.note_list) == 0: - self.status_message(u'No notes found!') + self.log(u'No notes found!') else: self.focus_position = 0