def _read_attr(self, filename, recover=True): """Read a node meta data file""" try: tree = ET.ElementTree(file=filename) except Exception as e: #if recover: # self._recover_attr(filename) # return self._read_attr(filename, recover=False) raise ConnectionError( _(u"Error reading meta data file '%s'" % filename), e) # check root root = tree.getroot() if root.tag != "node": raise ConnectionError(_("Root tag is not 'node'")) # iterate children attr = {} version = None for child in root: if child.tag == "dict": attr = plist.load_etree(child) if child.tag == "version": version = int(child.text) if version: attr["version"] = version return attr
def create_node(self, nodeid, attr, _path=None): """Create a node""" if self._filename is None: raise ConnectionError("connect() has not been called") # check for creating root if self._rootid is None: parentids = attr.get("parentids", []) if parentids != []: raise ConnectionError("root node must have parentids = []") _path = self._filename is_root = True else: is_root = False # check for existing nodeid if self.has_node(nodeid): raise NodeExists(nodeid) # generate a new nodeid if one is not given if nodeid is None: nodeid = keepnote.notebook.new_nodeid() # TODO: handle case where parent does not currently exist # TODO: handle case where parent finally shows up and # reunites with its children in the orphans dir # Determine parentid. # TODO: support multiple parents. parentids = attr.get("parentids") parentid = parentids[0] if parentids else None # Determine path. if _path: path = _path elif parentid: # Make path using parent and title. parent_path = self._get_node_path(parentid) title = attr.get("title", _("New Page")) path = get_valid_unique_filename(parent_path, title) else: # Use an orphandir since no parent exists. path = self._get_orphandir(nodeid) # Clean attributes. self._clean_attr(nodeid, attr) # Make directory and write attr try: attr_file = self._get_node_attr_file(nodeid, path) os.makedirs(path) self._write_attr(attr_file, nodeid, attr) except OSError, e: raise ConnectionError(_("Cannot create node"), e)
def _rename_node_dir(self, nodeid, attr, parentid, new_parentid, path): """Renames a node directory to resemble attr['title']""" if new_parentid is not None: # try to pick a path that closely resembles the title title = attr.get("title", _("New Page")) new_parent_path = self._get_node_path(new_parentid) new_path = get_valid_unique_filename(new_parent_path, title) basename = os.path.basename(new_path) else: # make orphan new_path = self._get_orphandir(nodeid) basename = new_path try: os.rename(path, new_path) except Exception as e: raise ConnectionError( _(u"Cannot rename '%s' to '%s'" % (path, new_path)), e) # update index self._path_cache.move(nodeid, basename, new_parentid) self._index.add_node(nodeid, new_parentid, basename, attr, mtime=get_path_mtime(new_path)) # update parent too if parentid: self._index.set_node_mtime( parentid, get_path_mtime(os.path.dirname(path))) if new_parentid and new_parentid != parentid: self._index.set_node_mtime( new_parentid, get_path_mtime(new_parent_path))
def _read_root(self): """Read root node attr""" if self._filename is None: raise ConnectionError("connect() has not been called") attr = self._read_node(None, self._filename) self._rootid = attr["nodeid"] self._init_root() return attr
def _write_attr(self, filename, nodeid, attr): """Write a node meta data file""" self._attr_mask.set_dict(attr) try: write_attr(filename, nodeid, self._attr_mask) except Exception, e: raise raise ConnectionError( _("Cannot write meta data" + " " + filename + ":" + str(e)), e)
def _list_children_attr(self, nodeid, _path=None, _full=True): """List attr of children nodes of nodeid""" path = self._path_cache.get_path(nodeid) if _path is None else _path assert path is not None try: files = os.listdir(path) except Exception, e: raise ConnectionError( _(u"Do not have permission to read folder contents: %s") % path, e)
def read_attr(filename, set_extra=True): """ Read a node meta data file. Returns an attr dict filename -- a filename or stream """ try: tree = ET.ElementTree(file=filename) except Exception, e: raise ConnectionError( _(u"Error reading meta data file '%s'" % filename), e)
def delete_node(self, nodeid): """Delete node""" # TODO: will need code that orphans any children of nodeid path = self._get_node_path(nodeid) if not os.path.exists(path): raise UnknownNode() try: shutil.rmtree(path) except Exception, e: raise ConnectionError(_(u"Do not have permission to delete"), e)
def delete_node(self, nodeid): """Delete node""" # TODO: will need code that orphans any children of nodeid try: shutil.rmtree(self._get_node_path(nodeid)) except Exception as e: raise ConnectionError( _(u"Do not have permission to delete"), e) # TODO: remove from index entire subtree self._path_cache.remove(nodeid) self._index.remove_node(nodeid)
def _move_to_lostdir(self, filename): """Moves a file/dir to the lost_found directory""" lostdir = self._get_lostdir() if not os.path.exists(lostdir): os.makedirs(lostdir) new_filename = keepnote.notebook.get_unique_filename( lostdir, os.path.basename(filename), sep=u"-") keepnote.log_message(u"moving data to lostdir '%s' => '%s'\n" % (filename, new_filename)) try: os.rename(filename, new_filename) except OSError, e: raise ConnectionError(u"unable to store lost file '%s'" % filename, e)
def _write_attr(self, filename, attr): """Write a node meta data file""" self._attr_mask.set_dict(attr) try: out = safefile.open(filename, "w", codec="utf-8") out.write(u'<?xml version="1.0" encoding="UTF-8"?>\n' u'<node>\n' u'<version>%d</version>\n' % attr.get("version", keepnote.notebook.NOTEBOOK_FORMAT_VERSION)) plist.dump(self._attr_mask, out, indent=2, depth=0) out.write(u'</node>\n') out.close() except Exception as e: raise ConnectionError( _("Cannot write meta data" + " " + filename + ":" + str(e)), e)
def _rename_node_dir(self, nodeid, attr, parentid, new_parentid, path): """Renames a node directory to resemble attr['title']""" if new_parentid is not None: # try to pick a path that closely resembles the title title = attr.get("title", _("New Page")) new_parent_path = self._get_node_path(new_parentid) new_path = get_valid_unique_filename(new_parent_path, title) basename = os.path.basename(new_path) else: # make orphan new_path = self._get_orphandir(nodeid) basename = new_path try: os.rename(path, new_path) except Exception, e: raise ConnectionError( _(u"Cannot rename '%s' to '%s'" % (path, new_path)), e)
def _list_children_attr(self, nodeid, _path=None, _full=True): """List attr of children nodes of nodeid""" path = self._path_cache.get_path(nodeid) if _path is None else _path assert path is not None try: files = os.listdir(path) except Exception as e: raise ConnectionError( _(u"Do not have permission to read folder contents: %s") % path, e) for filename in files: path2 = os.path.join(path, filename) if os.path.exists(get_node_meta_file(path2)): try: yield self._read_node(nodeid, path2, _full=_full) except ConnectionError as e: keepnote.log_error(u"error reading %s" % path2) continue # TODO: raise warning, not all children read self._path_cache.set_children_complete(nodeid, True)
def read_attr(filename, set_extra=True): """ Read a node meta data file. Returns an attr dict filename -- a filename or stream """ try: tree = ET.ElementTree(file=filename) except Exception, e: raise ConnectionError( _(u"Error reading meta data file '%s'" % filename), e) # check root root = tree.getroot() if root.tag != "node": raise ConnectionError(_("Root tag is not 'node'")) # iterate children attr = {} extra = {} for child in root: if child.tag == "dict": attr = plist.load_etree(child) elif child.tag == "version": extra['version'] = int(child.text) elif child.tag == "id": extra['nodeid'] = child.text # For backward-compatibility, use attr nodeid to set extra if needed. if 'nodeid' not in extra: extra['nodeid'] = attr['nodeid']
def create_node(self, nodeid, attr, _path=None): """Create a node""" # check for creating root if self._rootid is None: if self._filename is None: raise ConnectionError("connect() has not been called") parentids = attr.get("parentids", ()) if parentids != []: raise ConnectionError("root node must have parentids = []") _path = self._filename _root = True else: _root = False # check for existing nodeid if self.has_node(nodeid): raise NodeExists(nodeid) # generate a new nodeid if one is not given if nodeid is None: nodeid = keepnote.notebook.new_nodeid() # TODO: handle case where parent does not currently exist # TODO: handle case where parent finally shows up and # reunites with its children in the orphans dir # determine parentid parentids = attr.get("parentids", ()) if not parentids: # if parentids is None or [], it is orphan parentid = None else: parentid = parentids[0] # if no path, use title to set path if _path is None: title = attr.get("title", _("New Page")) if parentid is not None: # TODO: handle case where parentid is unknown # and therefore node is orphan parent_path = self._get_node_path(parentid) path = get_valid_unique_filename(parent_path, title) else: path = self._get_orphandir(nodeid) else: path = _path # initialize with no children attr["childrenids"] = [] # determine basename basename = os.path.basename(path) if parentid else path # make directory and write attr try: os.makedirs(path) self._write_attr(self._get_node_attr_file(nodeid, path), attr) self._path_cache.add(nodeid, basename, parentid) except OSError as e: raise ConnectionError(_("Cannot create node"), e) # finish initializing root if _root: self._rootid = attr["nodeid"] self._init_root() # update index self._index.add_node(nodeid, parentid, basename, attr, mtime=get_path_mtime(path)) return nodeid