def test_suspend_multi(self): (doc, rev1, rev_s1) = self.createSuspendDoc() with Connector().update(self.store1, doc, rev1) as w: w.writeAll('FILE', 'forward') w.commit() rev2 = w.getRev() with Connector().update(self.store1, doc, rev2) as w: w.writeAll('FILE', 'Hail to the king, baby!') w.suspend() rev_s2 = w.getRev() l = Connector().lookupDoc(doc) self.assertEqual(l.revs(), [rev2]) self.assertEqual(len(l.preRevs()), 2) self.assertTrue(rev_s1 in l.preRevs()) self.assertTrue(rev_s2 in l.preRevs()) s = Connector().stat(rev_s1) self.assertEqual(s.parents(), [rev1]) s = Connector().stat(rev_s2) self.assertEqual(s.parents(), [rev2]) self.assertRevContent(self.store1, rev1, {'FILE' : 'ok'}) self.assertRevContent(self.store1, rev_s1, {'FILE' : 'update'}) self.assertRevContent(self.store1, rev2, {'FILE' : 'forward'}) self.assertRevContent(self.store1, rev_s2, {'FILE' : 'Hail to the king, baby!'})
def __addCreateActions(self, menu): newMenu = menu.addMenu(QtGui.QIcon("icons/filenew.png"), "New document") action = newMenu.addAction(QtGui.QIcon("icons/uti/folder.png"), "Folder") action.triggered.connect(self.__doCreateFolder) newMenu.addSeparator() items = {} sysStore = Connector().enum().sysStore().sid sysDict = struct.Folder(connector.DocLink(sysStore, sysStore)) templatesDoc = sysDict.get("templates") if templatesDoc: templatesDict = struct.Folder(templatesDoc.update(sysStore)) items = templatesDict.items() items.sort(key=lambda item: item[0]) if items: for (name, link) in items: rev = link.rev() icon = QtGui.QIcon(Registry().getIcon( Connector().stat(rev).type())) action = newMenu.addAction(icon, name) action.triggered.connect( lambda x, r=rev, n=name: self.__doCreateFromTemplate( sysStore, r, n)) else: action = newMenu.addAction("No templates found") action.setEnabled(False)
def tearDown(self): CommonParts.tearDown(self) # make sure stores are unmounted to kill sync if Connector().enum().isMounted(STORE1): Connector().unmount(STORE1) if Connector().enum().isMounted(STORE2): Connector().unmount(STORE2)
def setUp(self): # make sure stores are unmounted to kill sync if Connector().enum().isMounted(STORE1): Connector().unmount(STORE1) if Connector().enum().isMounted(STORE2): Connector().unmount(STORE2) CommonParts.setUp(self)
def __updateColumns(self, stat=None): # This makes only sense if we're a valid entry if not self.__valid: return try: if stat is None: stat = Connector().stat(self.__rev) with Connector().peek(self.__store, self.__rev) as r: try: metaData = r.getData("/org.peerdrive.annotation") except: metaData = {} for i in xrange(len(self.__columnDefs)): column = self.__columnDefs[i] if column.derived(): self.__columnValues[i] = column.extract(stat, metaData) self.__metaData = metaData except IOError: self.__metaData = None for i in xrange(len(self.__columnDefs)): column = self.__columnDefs[i] if column.derived(): self.__columnValues[i] = column.default()
def __init__(self, link, parent=None): super(PropertiesDialog, self).__init__(parent) mainLayout = QtGui.QVBoxLayout() #mainLayout.setSizeConstraint(QtGui.QLayout.SetFixedSize) self.__doc = link.doc() self.__rev = link.rev() if self.__doc: isDoc = True banner = "document" l = Connector().lookupDoc(self.__doc) stores = [ s for s in l.stores() if Connector().lookupRev(l.rev(s), [s]) == [s] ] else: isDoc = False banner = "revision" stores = Connector().lookupRev(self.__rev) if len(stores) == 0: QtGui.QMessageBox.warning( self, 'Missing document', 'The requested document was not found on any store.') sys.exit(1) self.__docTab = DocumentTab(link.store(), stores, banner) self.__docTab.switchStore.connect(self.__switchStore) self.__revTab = RevisionTab() self.__annoTab = AnnotationTab(isDoc) self.__annoTab.changed.connect(self.__changed) self.__hisTab = HistoryTab() tabWidget = QtGui.QTabWidget() tabWidget.addTab(self.__annoTab, "Annotation") tabWidget.addTab(self.__hisTab, "History") if isDoc: self.__buttonBox = QtGui.QDialogButtonBox( QtGui.QDialogButtonBox.Save | QtGui.QDialogButtonBox.Close) self.__buttonBox.button( QtGui.QDialogButtonBox.Save).setEnabled(False) self.__buttonBox.accepted.connect(self.__save) self.__buttonBox.rejected.connect(self.reject) else: self.__buttonBox = QtGui.QDialogButtonBox( QtGui.QDialogButtonBox.Ok) self.__buttonBox.accepted.connect(self.accept) mainLayout.addWidget(self.__docTab) mainLayout.addWidget(self.__revTab) mainLayout.addWidget(tabWidget) mainLayout.addWidget(self.__buttonBox) self.setLayout(mainLayout) self.__switchStore(self.__docTab.activeStore()) self.setWindowTitle("Properties of %s" % (self.__annoTab.getTitle()))
def test_forward(self): (doc, rev1) = self.createCommon([self.store1, self.store2]) with Connector().update(self.store1, doc, rev1) as w: w.writeAll('FILE', 'update') w.commit() rev2 = w.getRev() Connector().forwardDoc(self.store2, doc, rev1, rev2, self.store1) self.assertEqual(Connector().lookupDoc(doc).revs(), [rev2])
def test_resume_wrong(self): (doc, rev1, rev2) = self.createSuspendDoc() self.assertRaises(IOError, Connector().resume, self.store1, doc, rev1) l = Connector().lookupDoc(doc) self.assertEqual(l.revs(), [rev1]) self.assertEqual(l.preRevs(), [rev2]) self.assertRevContent(self.store1, rev1, {'FILE' : 'ok'}) self.assertRevContent(self.store1, rev2, {'FILE' : 'update'})
def assertRevContent(self, store, rev, content): with Connector().peek(store, rev) as r: for (part, data) in content.items(): revData = r.readAll(part) self.assertEqual(revData, data) s = Connector().stat(rev, [store]) for part in s.parts(): self.assertTrue(part in content)
def test_not_updatable(self): (doc, rev1) = self.createCommon([self.store1, self.store2]) with Connector().update(self.store1, doc, rev1) as w: w.writeAll('FILE', 'update') w.commit() rev2 = w.getRev() self.assertRaises(IOError, Connector().forwardDoc, self.store1, doc, rev1, rev2, self.store2) self.assertEqual(Connector().lookupDoc(doc).rev(self.store1), rev2) self.assertEqual(Connector().lookupDoc(doc).rev(self.store2), rev1)
def __doReplicate(self, srcStore, link, dstStore): if isinstance(link, connector.DocLink): Connector().replicateDoc(srcStore, link.doc(), dstStore, verbose=True) else: Connector().replicateRev(srcStore, link.rev(), dstStore, verbose=True)
def test_update_change(self): w = self.create(self.store1) w.commit() doc = w.getDoc() rev = w.getRev() with Connector().update(self.store1, doc, rev) as w: w.setFlags([0, 3, 8]) w.commit() rev = w.getRev() s = Connector().stat(rev) self.assertEqual(s.flags(), set([0, 3, 8]))
def update(self, updateItem=True): # reset everything self.__valid = False self.__icon = None for i in xrange(len(self.__columnDefs)): column = self.__columnDefs[i] if column.derived(): self.__columnValues[i] = column.default() # determine revision needMerge = False isReplicated = False if self.__doc: l = Connector().lookupDoc(self.__doc) isReplicated = len(l.stores()) > 1 revisions = l.revs() if len(revisions) == 0: return elif len(revisions) > 1: needMerge = True if updateItem: self.__item[''].update() self.__rev = self.__item[''].rev() # stat try: s = Connector().stat(self.__rev) except IOError: return self.__uti = s.type() if needMerge or isReplicated: image = QtGui.QImage(Registry().getIcon(s.type())) painter = QtGui.QPainter() painter.begin(image) if needMerge: painter.drawImage(0, 16, QtGui.QImage("icons/emblems/split.png")) elif isReplicated: painter.drawImage( 0, 16, QtGui.QImage("icons/emblems/distributed.png")) painter.end() self.__icon = QtGui.QIcon(QtGui.QPixmap.fromImage(image)) else: self.__icon = QtGui.QIcon(Registry().getIcon(s.type())) self.__isFolder = Registry().conformes(self.__uti, "org.peerdrive.folder") self.__replacable = not needMerge and not self.__isFolder self.__valid = True self.__updateColumns(s)
def test_update_change(self): w = self.create(self.store1, creator="test.foo") w.commit() doc = w.getDoc() rev1 = w.getRev() with Connector().update(self.store1, doc, rev1, "test.baz") as w: w.commit() rev2 = w.getRev() s = Connector().stat(rev1) self.assertEqual(s.creator(), "test.foo") s = Connector().stat(rev2) self.assertEqual(s.creator(), "test.baz")
def test_collect(self): # deliberately close handle after creating! with Connector().create(self.store1, "public.data", "test.ignore") as w: w.commit() doc = w.getDoc() rev = w.getRev() # perform a GC cycle self.gc(self.store1) l = Connector().lookupDoc(doc) self.assertEqual(l.revs(), []) self.assertEqual(l.preRevs(), []) self.assertRaises(IOError, Connector().stat, rev)
def test_create_keep_handle(self): with Connector().create(self.store1, "public.data", "test.ignore") as w: w.commit() doc = w.getDoc() rev = w.getRev() # perform a GC cycle self.gc(self.store1) l = Connector().lookupDoc(doc) self.assertEqual(l.revs(), [rev]) self.assertEqual(l.preRevs(), []) Connector().stat(rev)
def test_update_keep(self): w = self.create(self.store1, creator="test.foo") w.commit() doc = w.getDoc() rev1 = w.getRev() with Connector().update(self.store1, doc, rev1) as w: w.write('FILE', 'update') w.commit() rev2 = w.getRev() s = Connector().stat(rev1) self.assertEqual(s.creator(), "test.foo") s = Connector().stat(rev2) self.assertEqual(s.creator(), "test.foo")
def __doCreateFromTemplate(self, srcStore, srcRev, name): info = Connector().stat(srcRev, [srcStore]) dstStore = self.store() with Connector().create(dstStore, info.type(), info.creator()) as w: with Connector().peek(srcStore, srcRev) as r: w.set_data('', r.get_data('')) for att in info.attachments(): w.write(att, r.readAll(att)) w.setFlags(r.stat().flags()) w.commit("Created from template") destDoc = w.getDoc() # add link self.model().insertLink(connector.DocLink(dstStore, destDoc)) # save immediately self.save("Added '" + name + "' from templates")
def test_fork(self): w = self.create(self.store1, creator="test.foo") w.commit() doc1 = w.getDoc() rev1 = w.getRev() w = self.fork(self.store1, rev1, "test.bar") w.commit() doc2 = w.getDoc() rev2 = w.getRev() s = Connector().stat(rev1) self.assertEqual(s.creator(), "test.foo") s = Connector().stat(rev2) self.assertEqual(s.creator(), "test.bar")
def __addReplicateActions(self, menu, link): c = Connector() try: allVolumes = set(c.lookupRev(self.rev())) if isinstance(link, connector.DocLink): lookup = c.lookupDoc(link.doc()) curVolumes = set(lookup.stores()) try: for rev in lookup.revs(): curVolumes = curVolumes & set( c.lookupRev(rev, curVolumes)) except IOError: curVolumes = set() else: curVolumes = set(c.lookupRev(link.rev())) except IOError: return if not curVolumes: return srcVol = list(curVolumes)[0] repVolumes = allVolumes - curVolumes for store in repVolumes: name = struct.readTitle(connector.DocLink(store, store), "Unknown store") action = menu.addAction("Replicate item to '%s'" % name) action.triggered.connect( lambda x, l=link, s=store: self.__doReplicate(srcVol, l, s))
def load(self, store, rev): try: stat = Connector().stat(rev, [store]) self.__typeLabel.setText(Registry().getDisplayString(stat.type())) self.__crtimeLabel.setText(str(stat.crtime())) self.__mtimeLabel.setText(str(stat.mtime())) size = stat.dataSize() for a in stat.attachments(): size += stat.size(a) for unit in ['Bytes', 'KiB', 'MiB', 'GiB']: if size < (1 << 10): break else: size = size >> 10 sizeText = "%d %s (%d attachments)" % (size, unit, len(stat.attachments())) self.__sizeLabel.setText(sizeText) if stat.flags(): flagsText = reduce(lambda x, y: x + ", " + y, [ flagToText.get(f, "<" + str(f) + ">") for f in stat.flags() ]) else: flagsText = "-" self.__flagsLabel.setText(flagsText) except IOError: self.__typeLabel.setText("n/a") self.__mtimeLabel.setText("n/a") self.__sizeLabel.setText("n/a")
def test_resume_suspend_orig(self): (doc, rev1, rev2) = self.createSuspendDoc() with Connector().resume(self.store1, doc, rev2) as w: w.suspend() rev3 = w.getRev() l = Connector().lookupDoc(doc) self.assertEqual(l.revs(), [rev1]) self.assertEqual(l.preRevs(), [rev3]) s = Connector().stat(rev3) self.assertEqual(s.parents(), [rev1]) self.assertRevContent(self.store1, rev1, {'FILE' : 'ok'}) self.assertRevContent(self.store1, rev3, {'FILE' : 'update'})
def __setViewHandler(self, link): link.update() try: type = Connector().stat(link.rev()).type() executables = Registry().getExecutables(type) except IOError: executables = [] if not executables: # Probably a bad idea to leave the current view widget, but what # else can we do? return for executable in executables: if executable in BrowserWindow.TYPES: break handler = BrowserWindow.TYPES[executable] if self.__viewHandler: if isinstance(self.__viewHandler, handler): return self.__viewHandler.delete() self.__viewHandler = handler(self) self.setCentralWidget(self.__viewHandler.getView()) self.__viewHandler.getView().distributionChanged.connect( self.__updateStoreButtons)
def __update(self): if self.__seen: self.__unwatch() self.__available = len(Connector().lookupRev(self.__rev)) > 0 else: self.__available = False try: stat = Connector().stat(self.__rev) self.__mtime = stat.mtime() self.__seen = True self.__available = True self.__view._addParents(stat.parents()) self.__unwatch() except IOError: self.__watch() return
def test_fork(self): w = self.create(self.store1) w.setFlags([1, 2, 3]) w.commit() rev1 = w.getRev() w = self.fork(self.store1, rev1) w.writeAll('FILE', "asdfafd") self.assertEqual(w.getFlags(), set([1, 2, 3])) w.commit() rev2 = w.getRev() s = Connector().stat(rev1) self.assertEqual(s.flags(), set([1, 2, 3])) s = Connector().stat(rev2) self.assertEqual(s.flags(), set([1, 2, 3]))
def test_resume_commit(self): (doc, rev1, rev2) = self.createSuspendDoc() with Connector().resume(self.store1, doc, rev2) as w: w.writeAll('FILE', 'What are you waiting for, christmas?') w.commit() rev3 = w.getRev() l = Connector().lookupDoc(doc) self.assertEqual(l.revs(), [rev3]) self.assertEqual(len(l.preRevs()), 0) s = Connector().stat(rev3) self.assertEqual(s.parents(), [rev1]) self.assertRevContent(self.store1, rev1, {'FILE' : 'ok'}) self.assertRevContent(self.store1, rev3, {'FILE' : 'What are you waiting for, christmas?'})
def __switchStore(self, store): if self.__doc: self.__rev = Connector().lookupDoc(self.__doc, [store]).rev(store) self.__store = store self.__revTab.load(store, self.__rev) self.__annoTab.load(store, self.__rev) self.__hisTab.load(store, self.__rev)
def test_suspend(self): (doc, rev1, rev2) = self.createSuspendDoc() l = Connector().lookupDoc(doc) self.assertEqual(l.revs(), [rev1]) self.assertEqual(l.preRevs(), [rev2]) self.assertRevContent(self.store1, rev1, {'FILE' : 'ok'}) self.assertRevContent(self.store1, rev2, {'FILE' : 'update'})
def test_resume_abort(self): (doc, rev1, rev2) = self.createSuspendDoc() with Connector().resume(self.store1, doc, rev2) as w: w.writeAll('FILE', 'Hail to the king, baby!') l = Connector().lookupDoc(doc) self.assertEqual(l.revs(), [rev1]) self.assertEqual(l.preRevs(), [rev2]) w.close() l = Connector().lookupDoc(doc) self.assertEqual(l.revs(), [rev1]) self.assertEqual(l.preRevs(), [rev2]) self.assertRevContent(self.store1, rev1, {'FILE' : 'ok'}) self.assertRevContent(self.store1, rev2, {'FILE' : 'update'})
def test_create(self): w = self.create(self.store1, creator="test.foo") w.commit() doc = w.getDoc() rev = w.getRev() s = Connector().stat(rev) self.assertEqual(s.creator(), "test.foo")