From 352b8591bd1c7163835a6fa1db34d3e2861c1071 Mon Sep 17 00:00:00 2001 From: =?utf8?q?=C5=81ukasz=20Rekucki?= Date: Fri, 25 Sep 2009 17:18:54 +0200 Subject: [PATCH 1/1] Updated API tests. Handlers refactor. Addded Toolbar API. --- .../empty/.library => handlers/__init__.py} | 0 .../library_handlers.py} | 148 ++- apps/api/handlers/toolbar_handlers.py | 32 + apps/api/resources.py | 39 + apps/api/tests/__init__.py | 126 +- .../data/{test2/.library => clean/$meta} | 0 .../data/{empty => clean}/.hg/00changelog.i | Bin apps/api/tests/data/clean/.hg/dirstate | Bin 0 -> 112 bytes .../tests/data/{empty => clean}/.hg/requires | 0 .../tests/data/clean/.hg/store/00changelog.i | Bin 0 -> 367 bytes .../tests/data/clean/.hg/store/00manifest.i | Bin 0 -> 255 bytes .../.hg/store/data/$meta.i} | Bin .../.hg/store/data/.hgignore.i} | Bin .../tests/data/clean/.hg/store/data/.hgtags.i | Bin 0 -> 118 bytes apps/api/tests/data/clean/.hg/store/fncache | 3 + apps/api/tests/data/clean/.hg/store/undo | Bin 0 -> 52 bytes .../data/{empty => clean}/.hg/undo.branch | 0 apps/api/tests/data/clean/.hg/undo.dirstate | Bin 0 -> 112 bytes .../{testone/.library => clean/.hgignore} | 0 apps/api/tests/data/clean/.hgtags | 1 + .../tests/data/empty/.hg/branchheads.cache | 2 - apps/api/tests/data/empty/.hg/dirstate | Bin 65 -> 0 bytes .../tests/data/empty/.hg/store/00changelog.i | Bin 169 -> 0 bytes .../tests/data/empty/.hg/store/00manifest.i | Bin 115 -> 0 bytes apps/api/tests/data/empty/.hg/store/fncache | 1 - apps/api/tests/data/empty/.hg/store/undo | Bin 49 -> 0 bytes apps/api/tests/data/empty/.hg/undo.dirstate | Bin 65 -> 0 bytes .../api/tests/data/simple/$meta | 0 .../data/{test2 => simple}/.hg/00changelog.i | Bin .../tests/data/{test2 => simple}/.hg/branch | 0 .../tests/data/simple/.hg/branchheads.cache | 4 + apps/api/tests/data/simple/.hg/dirstate | Bin 0 -> 112 bytes .../tests/data/{test2 => simple}/.hg/requires | 0 .../tests/data/simple/.hg/store/00changelog.i | Bin 0 -> 759 bytes .../tests/data/simple/.hg/store/00manifest.i | Bin 0 -> 588 bytes .../.hg/store/data/$meta.i} | Bin .../data/simple/.hg/store/data/.hgignore.i | Bin 0 -> 64 bytes .../data/simple/.hg/store/data/.hgtags.i | Bin 0 -> 118 bytes .../data/simple/.hg/store/data/sample.parts.i | Bin .../data/simple/.hg/store/data/sample.xml.i | Bin 0 -> 77 bytes .../simple/.hg/store/data/sample__pl.xml.i | Bin 0 -> 79 bytes apps/api/tests/data/simple/.hg/store/fncache | 6 + apps/api/tests/data/simple/.hg/store/undo | Bin 0 -> 52 bytes .../.hg/strip-backup/26716f931d95-backup | Bin 0 -> 867 bytes .../data/{testone => simple}/.hg/undo.branch | 0 apps/api/tests/data/simple/.hg/undo.dirstate | Bin 0 -> 112 bytes .../api/tests/data/simple/.hgignore | 0 apps/api/tests/data/simple/.hgtags | 1 + .../tests/data/test2/.hg/branchheads.cache | 3 - apps/api/tests/data/test2/.hg/dirstate | Bin 98 -> 0 bytes .../tests/data/test2/.hg/store/00changelog.i | Bin 553 -> 0 bytes .../tests/data/test2/.hg/store/00manifest.i | Bin 372 -> 0 bytes .../test2/.hg/store/data/pub__testfile.xml.i | Bin 85 -> 0 bytes apps/api/tests/data/test2/.hg/store/fncache | 2 - apps/api/tests/data/test2/.hg/store/undo | Bin 35 -> 0 bytes apps/api/tests/data/test2/.hg/undo.branch | 1 - apps/api/tests/data/test2/.hg/undo.dirstate | Bin 98 -> 0 bytes apps/api/tests/data/test2/pub_testfile.xml | 1 - apps/api/tests/data/testone/.hg/00changelog.i | Bin 57 -> 0 bytes .../tests/data/testone/.hg/branchheads.cache | 2 - apps/api/tests/data/testone/.hg/dirstate | Bin 98 -> 0 bytes apps/api/tests/data/testone/.hg/requires | 3 - .../data/testone/.hg/store/00changelog.i | Bin 348 -> 0 bytes .../tests/data/testone/.hg/store/00manifest.i | Bin 249 -> 0 bytes .../.hg/store/data/pub__testfile.xml.i | Bin 85 -> 0 bytes apps/api/tests/data/testone/.hg/store/fncache | 2 - apps/api/tests/data/testone/.hg/store/undo | Bin 61 -> 0 bytes apps/api/tests/data/testone/.hg/undo.dirstate | Bin 98 -> 0 bytes apps/api/tests/data/testone/pub_testfile.xml | 1 - apps/api/urls.py | 17 +- apps/toolbar/models.py | 20 + .../ignored_file => apps/wysiwyg/__init__.py | 0 apps/wysiwyg/models.py | 3 + apps/wysiwyg/tests.py | 23 + apps/wysiwyg/urls.py | 12 + apps/wysiwyg/views.py | 5 + lib/wlrepo/__init__.py | 155 +-- lib/wlrepo/backend_mercurial.py | 1130 ++++++++--------- lib/wlrepo/mercurial_backend/__init__.py | 84 ++ lib/wlrepo/mercurial_backend/document.py | 173 +++ lib/wlrepo/mercurial_backend/library.py | 250 ++++ lib/wlrepo/tests/data/clean/$meta | 0 lib/wlrepo/tests/data/clean/.hg/dirstate | Bin 130 -> 88 bytes .../tests/data/clean/.hg/store/00changelog.i | Bin 366 -> 176 bytes .../tests/data/clean/.hg/store/00manifest.i | Bin 265 -> 130 bytes .../tests/data/clean/.hg/store/data/$meta.i | Bin 0 -> 64 bytes lib/wlrepo/tests/data/clean/.hg/store/fncache | 3 +- lib/wlrepo/tests/data/clean/.hg/store/undo | Bin 85 -> 65 bytes lib/wlrepo/tests/data/clean/.hg/undo.dirstate | Bin 130 -> 88 bytes lib/wlrepo/tests/data/simple/$meta | 0 lib/wlrepo/tests/data/simple/.hg/branch | 1 + .../tests/data/simple/.hg/branchheads.cache | 4 + lib/wlrepo/tests/data/simple/.hg/dirstate | Bin 166 -> 112 bytes .../tests/data/simple/.hg/store/00changelog.i | Bin 545 -> 759 bytes .../tests/data/simple/.hg/store/00manifest.i | Bin 442 -> 588 bytes .../tests/data/simple/.hg/store/data/$meta.i | Bin 0 -> 64 bytes .../data/simple/.hg/store/data/.hgtags.i | Bin 0 -> 118 bytes .../simple/.hg/store/data/ignored__file.i | Bin 64 -> 0 bytes .../.hg/store/data/pub__polish__file.xml.i | Bin 73 -> 0 bytes .../.hg/store/data/pub__valid__file.xml.i | Bin 152 -> 0 bytes .../.hg/store/data/sample.parts.i} | Bin .../data/simple/.hg/store/data/sample.xml.i | Bin 0 -> 77 bytes .../simple/.hg/store/data/sample__pl.xml.i | Bin 0 -> 79 bytes .../tests/data/simple/.hg/store/fncache | 8 +- lib/wlrepo/tests/data/simple/.hg/store/undo | Bin 93 -> 52 bytes .../.hg/strip-backup/26716f931d95-backup | Bin 0 -> 867 bytes .../tests/data/simple/.hg/undo.dirstate | Bin 166 -> 112 bytes lib/wlrepo/tests/data/simple/.hgtags | 1 + .../tests/data/simple/pub_polish_file.xml | 1 - .../tests/data/simple/pub_valid_file.xml | 1 - lib/wlrepo/tests/test_mercurial.py | 362 +++--- project/settings.py | 2 +- project/templates/manager/pull_request.html | 7 + project/templates/toolbar_api/scriptlets.js | 15 + project/templates/wysiwyg.html | 92 ++ 115 files changed, 1734 insertions(+), 1013 deletions(-) rename apps/api/{tests/data/empty/.library => handlers/__init__.py} (100%) rename apps/api/{handlers.py => handlers/library_handlers.py} (53%) create mode 100644 apps/api/handlers/toolbar_handlers.py create mode 100644 apps/api/resources.py rename apps/api/tests/data/{test2/.library => clean/$meta} (100%) rename apps/api/tests/data/{empty => clean}/.hg/00changelog.i (100%) create mode 100644 apps/api/tests/data/clean/.hg/dirstate rename apps/api/tests/data/{empty => clean}/.hg/requires (100%) create mode 100644 apps/api/tests/data/clean/.hg/store/00changelog.i create mode 100644 apps/api/tests/data/clean/.hg/store/00manifest.i rename apps/api/tests/data/{empty/.hg/store/data/.library.i => clean/.hg/store/data/$meta.i} (100%) rename apps/api/tests/data/{test2/.hg/store/data/.library.i => clean/.hg/store/data/.hgignore.i} (100%) create mode 100644 apps/api/tests/data/clean/.hg/store/data/.hgtags.i create mode 100644 apps/api/tests/data/clean/.hg/store/fncache create mode 100644 apps/api/tests/data/clean/.hg/store/undo rename apps/api/tests/data/{empty => clean}/.hg/undo.branch (100%) create mode 100644 apps/api/tests/data/clean/.hg/undo.dirstate rename apps/api/tests/data/{testone/.library => clean/.hgignore} (100%) create mode 100644 apps/api/tests/data/clean/.hgtags delete mode 100644 apps/api/tests/data/empty/.hg/branchheads.cache delete mode 100644 apps/api/tests/data/empty/.hg/dirstate delete mode 100644 apps/api/tests/data/empty/.hg/store/00changelog.i delete mode 100644 apps/api/tests/data/empty/.hg/store/00manifest.i delete mode 100644 apps/api/tests/data/empty/.hg/store/fncache delete mode 100644 apps/api/tests/data/empty/.hg/store/undo delete mode 100644 apps/api/tests/data/empty/.hg/undo.dirstate rename lib/wlrepo/tests/data/clean/ignored_file => apps/api/tests/data/simple/$meta (100%) rename apps/api/tests/data/{test2 => simple}/.hg/00changelog.i (100%) rename apps/api/tests/data/{test2 => simple}/.hg/branch (100%) create mode 100644 apps/api/tests/data/simple/.hg/branchheads.cache create mode 100644 apps/api/tests/data/simple/.hg/dirstate rename apps/api/tests/data/{test2 => simple}/.hg/requires (100%) create mode 100644 apps/api/tests/data/simple/.hg/store/00changelog.i create mode 100644 apps/api/tests/data/simple/.hg/store/00manifest.i rename apps/api/tests/data/{testone/.hg/store/data/.library.i => simple/.hg/store/data/$meta.i} (100%) create mode 100644 apps/api/tests/data/simple/.hg/store/data/.hgignore.i create mode 100644 apps/api/tests/data/simple/.hg/store/data/.hgtags.i rename lib/wlrepo/tests/data/clean/.hg/store/data/ignored__file.i => apps/api/tests/data/simple/.hg/store/data/sample.parts.i (100%) create mode 100644 apps/api/tests/data/simple/.hg/store/data/sample.xml.i create mode 100644 apps/api/tests/data/simple/.hg/store/data/sample__pl.xml.i create mode 100644 apps/api/tests/data/simple/.hg/store/fncache create mode 100644 apps/api/tests/data/simple/.hg/store/undo create mode 100644 apps/api/tests/data/simple/.hg/strip-backup/26716f931d95-backup rename apps/api/tests/data/{testone => simple}/.hg/undo.branch (100%) create mode 100644 apps/api/tests/data/simple/.hg/undo.dirstate rename lib/wlrepo/tests/data/clean/pub_valid_file.xml => apps/api/tests/data/simple/.hgignore (100%) create mode 100644 apps/api/tests/data/simple/.hgtags delete mode 100644 apps/api/tests/data/test2/.hg/branchheads.cache delete mode 100644 apps/api/tests/data/test2/.hg/dirstate delete mode 100644 apps/api/tests/data/test2/.hg/store/00changelog.i delete mode 100644 apps/api/tests/data/test2/.hg/store/00manifest.i delete mode 100644 apps/api/tests/data/test2/.hg/store/data/pub__testfile.xml.i delete mode 100644 apps/api/tests/data/test2/.hg/store/fncache delete mode 100644 apps/api/tests/data/test2/.hg/store/undo delete mode 100644 apps/api/tests/data/test2/.hg/undo.branch delete mode 100644 apps/api/tests/data/test2/.hg/undo.dirstate delete mode 100644 apps/api/tests/data/test2/pub_testfile.xml delete mode 100644 apps/api/tests/data/testone/.hg/00changelog.i delete mode 100644 apps/api/tests/data/testone/.hg/branchheads.cache delete mode 100644 apps/api/tests/data/testone/.hg/dirstate delete mode 100644 apps/api/tests/data/testone/.hg/requires delete mode 100644 apps/api/tests/data/testone/.hg/store/00changelog.i delete mode 100644 apps/api/tests/data/testone/.hg/store/00manifest.i delete mode 100644 apps/api/tests/data/testone/.hg/store/data/pub__testfile.xml.i delete mode 100644 apps/api/tests/data/testone/.hg/store/fncache delete mode 100644 apps/api/tests/data/testone/.hg/store/undo delete mode 100644 apps/api/tests/data/testone/.hg/undo.dirstate delete mode 100644 apps/api/tests/data/testone/pub_testfile.xml rename lib/wlrepo/tests/data/simple/ignored_file => apps/wysiwyg/__init__.py (100%) create mode 100644 apps/wysiwyg/models.py create mode 100644 apps/wysiwyg/tests.py create mode 100644 apps/wysiwyg/urls.py create mode 100644 apps/wysiwyg/views.py create mode 100644 lib/wlrepo/mercurial_backend/__init__.py create mode 100644 lib/wlrepo/mercurial_backend/document.py create mode 100644 lib/wlrepo/mercurial_backend/library.py create mode 100644 lib/wlrepo/tests/data/clean/$meta create mode 100644 lib/wlrepo/tests/data/clean/.hg/store/data/$meta.i create mode 100644 lib/wlrepo/tests/data/simple/$meta create mode 100644 lib/wlrepo/tests/data/simple/.hg/branch create mode 100644 lib/wlrepo/tests/data/simple/.hg/branchheads.cache create mode 100644 lib/wlrepo/tests/data/simple/.hg/store/data/$meta.i create mode 100644 lib/wlrepo/tests/data/simple/.hg/store/data/.hgtags.i delete mode 100644 lib/wlrepo/tests/data/simple/.hg/store/data/ignored__file.i delete mode 100644 lib/wlrepo/tests/data/simple/.hg/store/data/pub__polish__file.xml.i delete mode 100644 lib/wlrepo/tests/data/simple/.hg/store/data/pub__valid__file.xml.i rename lib/wlrepo/tests/data/{clean/.hg/store/data/pub__valid__file.xml.i => simple/.hg/store/data/sample.parts.i} (100%) create mode 100644 lib/wlrepo/tests/data/simple/.hg/store/data/sample.xml.i create mode 100644 lib/wlrepo/tests/data/simple/.hg/store/data/sample__pl.xml.i create mode 100644 lib/wlrepo/tests/data/simple/.hg/strip-backup/26716f931d95-backup create mode 100644 lib/wlrepo/tests/data/simple/.hgtags delete mode 100644 lib/wlrepo/tests/data/simple/pub_polish_file.xml delete mode 100644 lib/wlrepo/tests/data/simple/pub_valid_file.xml create mode 100644 project/templates/manager/pull_request.html create mode 100644 project/templates/toolbar_api/scriptlets.js create mode 100644 project/templates/wysiwyg.html diff --git a/apps/api/tests/data/empty/.library b/apps/api/handlers/__init__.py similarity index 100% rename from apps/api/tests/data/empty/.library rename to apps/api/handlers/__init__.py diff --git a/apps/api/handlers.py b/apps/api/handlers/library_handlers.py similarity index 53% rename from apps/api/handlers.py rename to apps/api/handlers/library_handlers.py index 9a54ce8c..b47d41cc 100644 --- a/apps/api/handlers.py +++ b/apps/api/handlers/library_handlers.py @@ -1,5 +1,11 @@ +# -*- encoding: utf-8 -*- + +__author__= "Łukasz Rekucki" +__date__ = "$2009-09-25 15:49:50$" +__doc__ = "Module documentation." + from piston.handler import BaseHandler, AnonymousBaseHandler -from piston.utils import rc, validate +from piston.utils import rc import settings import librarian @@ -7,7 +13,7 @@ import api.forms as forms from datetime import date from django.core.urlresolvers import reverse -from wlrepo import MercurialLibrary, CabinetNotFound +from wlrepo import MercurialLibrary, RevisionNotFound from librarian import dcparser @@ -20,16 +26,12 @@ class BasicLibraryHandler(AnonymousBaseHandler): def read(self, request): """Return the list of documents.""" lib = MercurialLibrary(path=settings.REPOSITORY_PATH) - cab = lib.main_cabinet document_list = [{ 'url': reverse('document_view', args=[docid]), - 'name': docid } for docid in cab.documents() ] + 'name': docid } for docid in lib.documents() ] - return { - 'cabinet': cab.name, - 'latest_rev': cab.shelf(), - 'documents' : document_list } + return {'documents' : document_list} class LibraryHandler(BaseHandler): allowed_methods = ('GET', 'POST') @@ -38,21 +40,16 @@ class LibraryHandler(BaseHandler): def read(self, request): """Return the list of documents.""" lib = MercurialLibrary(path=settings.REPOSITORY_PATH) - cab = lib.main_cabinet document_list = [{ 'url': reverse('document_view', args=[docid]), - 'name': docid } for docid in cab.documents() ] + 'name': docid } for docid in lib.documents() ] - return { - 'cabinet': cab.name, - 'latest_rev': cab.shelf(), - 'documents' : document_list } + return {'documents' : document_list } def create(self, request): """Create a new document.""" lib = MercurialLibrary(path=settings.REPOSITORY_PATH) - cab = lib.main_cabinet form = forms.DocumentUploadForm(request.POST, request.FILES) if not form.is_valid(): @@ -65,13 +62,14 @@ class LibraryHandler(BaseHandler): data = librarian.wrap_text(data, unicode(date.today())) # TODO: what if the file exists ? - doc = cab.create(form.cleaned_data['bookname'], initial_data=data) - + doc = lib.document_create(form.cleaned_data['bookname']) + doc.quickwrite('xml', data, '$AUTO$ XML data uploaded.', + user=request.user.username) + return { - 'url': reverse('document_view', args=[doc.name]), - 'name': doc.name, - 'size': doc.size, - 'revision': doc.shelf() } + 'url': reverse('document_view', args=[doc.id]), + 'name': doc.id, + 'revision': doc.revision } # # Document Handlers @@ -86,21 +84,16 @@ class BasicDocumentHandler(AnonymousBaseHandler): if not opts.is_valid(): return rc.BAD_REQUEST - document = lib.main_cabinet.retrieve(docid) + doc = lib.document(docid) result = { - 'name': document.name, - 'size': document.size, - 'text_url': reverse('doctext_view', args=[docid]), - #'dc_url': reverse('docdc_view', docid=document.name), - #'parts_url': reverse('docparts_view', docid=document.name), - 'latest_rev': document.shelf(), + 'name': doc.id, + 'text_url': reverse('doctext_view', args=[doc.id]), + 'dc_url': reverse('docdc_view', docid=doc.id), + 'latest_rev': doc.revision, } - if request.GET.get('with_part', 'no') == 'yes': - result['parts'] = document.parts() - - return result + return result # # Document Meta Data @@ -108,42 +101,39 @@ class BasicDocumentHandler(AnonymousBaseHandler): class DocumentHandler(BaseHandler): allowed_methods = ('GET', 'PUT') anonymous = BasicDocumentHandler - + def read(self, request, docid): - """Read document's meta data""" + """Read document's meta data""" lib = MercurialLibrary(path=settings.REPOSITORY_PATH) opts = forms.DocumentGetForm(request.GET) if not opts.is_valid(): return rc.BAD_REQUEST - - document = lib.cabinet(docid, request.user.username, \ - create=opts.cleaned_data['autocabinet'] ).retrieve() - if not document: + try: + doc = lib.document(docid) + udoc = doc.take(request.user.username) + except RevisionNotFound: return rc.NOT_HERE - - shared = lib.main_cabinet.retrieve(docid) - is_shared = document.ancestorof(shared) + # is_shared = udoc.ancestorof(doc) # is_uptodate = is_shared or shared.ancestorof(document) result = { - 'name': document.name, - 'size': document.size, - 'text_url': reverse('doctext_view', args=[docid]), - 'dc_url': reverse('docdc_view', args=[docid]), - 'parts_url': reverse('docparts_view', args=[docid]), - 'latest_rev': document.shelf(), - 'latest_shared_rev': shared.shelf(), - 'shared': is_shared, + 'name': udoc.id, + 'text_url': reverse('doctext_view', args=[udoc.id]), + 'dc_url': reverse('docdc_view', args=[udoc.id]), + 'parts_url': reverse('docparts_view', args=[udoc.id]), + 'latest_rev': udoc.revision, + 'latest_shared_rev': doc.revision, + # 'shared': is_shared, # 'up_to_date': is_uptodate, } #if request.GET.get('with_part', 'no') == 'yes': # result['parts'] = document.parts() - return result + return result # # Document Text View @@ -155,23 +145,33 @@ class DocumentTextHandler(BaseHandler): """Read document as raw text""" lib = MercurialLibrary(path=settings.REPOSITORY_PATH) try: - # latest rev - # comment - return lib.document(docid, request.user.username).read() - except CabinetNotFound: + return lib.document(docid, request.user.username).data('xml') + except RevisionNotFound: return rc.NOT_HERE def update(self, request, docid): lib = MercurialLibrary(path=settings.REPOSITORY_PATH) try: - # check latest REV data = request.PUT['contents'] - lib.document(docid, request.user.username).write(data) + prev = request.PUT['revision'] + + if request.PUT.has_key('message'): + msg = u"$USER$ " + request.PUT['message'] + else: + msg = u"$AUTO$ XML content update." + + current = lib.document(docid, request.user.username) + orig = lib.document_for_rev(prev) + + if current != orig: + return rc.DUPLICATE_ENTRY + + doc.quickwrite('xml', data, msg) + return rc.ALL_OK - except (CabinetNotFound, KeyError): + except (RevisionNotFound, KeyError): return rc.NOT_HERE - # # Dublin Core handlers # @@ -184,20 +184,36 @@ class DocumentDublinCoreHandler(BaseHandler): """Read document as raw text""" lib = MercurialLibrary(path=settings.REPOSITORY_PATH) try: - doc = lib.document(docid, request.user.username) - - # TODO: RAL:document should support file-like ops + doc = lib.document(docid, request.user.username).data('xml') bookinfo = dcparser.BookInfo.from_string(doc.read()) + return bookinfo.serialize() - except CabinetNotFound: + except RevisionNotFound: return rc.NOT_HERE def update(self, request, docid): lib = MercurialLibrary(path=settings.REPOSITORY_PATH) try: - data = request.PUT['contents'] - lib.document(docid, request.user.username).write(data) + bi_json = request.PUT['contents'] + prev = request.PUT['revision'] + if request.PUT.has_key('message'): + msg = u"$USER$ " + request.PUT['message'] + else: + msg = u"$AUTO$ Dublin core update." + + current = lib.document(docid, request.user.username) + orig = lib.document_for_rev(prev) + + if current != orig: + return rc.DUPLICATE_ENTRY + + xmldoc = parser.WLDocument.from_string(current.data('xml')) + document.book_info = dcparser.BookInfo.from_json(bi_json) + + # zapisz + current.quickwrite('xml', document.serialize().encode('utf-8'),\ + message=msg, user=request.user.username) + return rc.ALL_OK - except (CabinetNotFound, KeyError): + except (RevisionNotFound, KeyError): return rc.NOT_HERE - diff --git a/apps/api/handlers/toolbar_handlers.py b/apps/api/handlers/toolbar_handlers.py new file mode 100644 index 00000000..be773590 --- /dev/null +++ b/apps/api/handlers/toolbar_handlers.py @@ -0,0 +1,32 @@ +# -*- encoding: utf-8 -*- + +__author__= "Łukasz Rekucki" +__date__ = "$2009-09-25 15:55:33$" +__doc__ = "Module documentation." + +from django.views.generic.simple import direct_to_template +from piston.handler import BaseHandler +from piston.utils import rc + +import settings + +import toolbar.models + +class ToolbarHandler(BaseHandler): + allowed_methods = ('GET',) + + def read(self, request): + groups = toolbar.models.ButtonGroup.objects.all() + return [ {'name': g.name, 'position': g.position,\ + 'buttons': g.button_set.all()} for g in groups ] + + +class ScriptletsHandler(BaseHandler): + allowed_methods = ('GET',) + + def read(self, request): + scriptlets = toolbar.models.Scriptlet.objects.all() + + return direct_to_template(request, 'toolbar_api/scriptlets.js', + extra_context = {'scriptlets': scriptlets }, + mimetype='text/javascript' ) \ No newline at end of file diff --git a/apps/api/resources.py b/apps/api/resources.py new file mode 100644 index 00000000..d45fa1d7 --- /dev/null +++ b/apps/api/resources.py @@ -0,0 +1,39 @@ +# -*- encoding: utf-8 -*- + +__author__= "Łukasz Rekucki" +__date__ = "$2009-09-25 15:53:00$" +__doc__ = "Module documentation." + +from piston.resource import Resource +from api.utils import DjangoAuth + + + + +authdata = {'authentication': DjangoAuth()} + +# +# Library resources +# + +import api.handlers.library_handlers as dh +library_resource = Resource(dh.LibraryHandler, **authdata) +document_resource = Resource(dh.DocumentHandler, **authdata) +document_text_resource = Resource(dh.DocumentTextHandler, **authdata) +document_dc_resource = Resource(dh.DocumentDublinCoreHandler, **authdata) + +# +# Toolbar resources +# +import api.handlers.toolbar_handlers as th +toolbar_buttons = Resource(th.ToolbarHandler, **authdata) +scriptlets = Resource(th.ScriptletsHandler, **authdata) + +__all__ = [ + 'library_resource', + 'document_resource', + 'document_text_resource', + 'document_dc_resource', + 'toolbar_buttons', + 'scriptlets' +] \ No newline at end of file diff --git a/apps/api/tests/__init__.py b/apps/api/tests/__init__.py index ca575fe7..2292e7dd 100644 --- a/apps/api/tests/__init__.py +++ b/apps/api/tests/__init__.py @@ -1,10 +1,3 @@ -""" -This file demonstrates two different styles of tests (one doctest and one -unittest). These will both pass when you run "manage.py test". - -Replace these with more appropriate tests for your application. -""" - from django.test import TestCase from django.test.client import Client from django.core.urlresolvers import reverse @@ -21,8 +14,6 @@ import tempfile REPO_TEMPLATES = join(dirname(__file__), 'data') - - def temprepo(name): from functools import wraps @@ -32,7 +23,7 @@ def temprepo(name): def decorated(self, *args, **kwargs): clean = False try: - temp = tempfile.mkdtemp("", "testdir_" ) + temp = tempfile.mkdtemp("-test", func.__name__) shutil.copytree(join(REPO_TEMPLATES, name), join(temp, 'repo'), False) settings.REPOSITORY_PATH = join(temp, 'repo') func(self, *args, **kwargs) @@ -43,7 +34,7 @@ def temprepo(name): print self.response print "<<<" - shutil.rmtree(temp, True) + # shutil.rmtree(temp, True) settings.REPOSITORY_PATH = '' return decorated @@ -57,27 +48,23 @@ class SimpleTest(TestCase): u = User.objects.create_user('admin', 'test@localhost', 'admin') u.save() - @temprepo('empty') + @temprepo('clean') def test_documents_get_anonymous(self): self.response = self.client.get( reverse("document_list_view") ) - self.assert_json_response({ - u'latest_rev': u'e56b2a7e06a97d7c3697fc4295974e0f20a66190', - u'documents': [], - u'cabinet': u'default', - }, exclude=['latest_shared_rev']) + self.assert_json_response({ + u'documents': [], + }) - @temprepo('empty') + @temprepo('clean') def test_documents_get_with_login(self): self.assertTrue(self.client.login(username='admin', password='admin')) self.response = self.client.get( reverse("document_list_view") ) - self.assert_json_response({ - u'latest_rev': u'e56b2a7e06a97d7c3697fc4295974e0f20a66190', - u'documents': [], - u'cabinet': u'default', + self.assert_json_response({ + u'documents': [], }) - @temprepo('empty') + @temprepo('clean') def test_documents_post(self): self.assertTrue(self.client.login(username='admin', password='admin')) @@ -85,8 +72,8 @@ class SimpleTest(TestCase): infile.write('0123456789') infile.flush() infile.seek(0) - - self.response = self.client.post( reverse("document_list_view"), + + self.response = self.client.post( reverse("document_list_view"), data = { 'bookname': 'testbook', 'ocr': infile, @@ -94,15 +81,15 @@ class SimpleTest(TestCase): }) infile.close() - - result = self.assert_json_response({ + + self.assert_json_response({ 'url': reverse('document_view', args=['testbook']), 'name': 'testbook', - 'size': 10, + # 'size': 10, # can't test revision number, 'cause it's random },) - @temprepo('empty') + @temprepo('clean') def test_document_creation(self): self.assertTrue(self.client.login(username='admin', password='admin')) @@ -117,73 +104,82 @@ class SimpleTest(TestCase): 'ocr': infile, 'generate_dc': False, }) - + r = self.assert_json_response({ 'url': reverse('document_view', args=['testbook']), - 'name': 'testbook', - 'size': 15, + 'name': 'testbook', # can't test revision number, 'cause it's random }) created_rev = r['revision'] self.response = self.client.get( \ - reverse("document_view", args=["testbook"])+'?autocabinet=true' ) + reverse("document_view", args=["testbook"]) ) result = self.assert_json_response({ u'latest_shared_rev': created_rev, - u'size': 15, + # u'size': 15, }) - @temprepo('testone') + @temprepo('simple') def test_document_meta_get_with_login(self): self.assertTrue(self.client.login(username='admin', password='admin')) self.response = self.client.get( reverse("document_list_view") ) self.assert_json_response({ - u'latest_rev': u'f94a263812dbe46a3a13d5209bb119988d0078d5', - u'documents': [{u'url': u'/api/documents/testfile', u'name': u'testfile'}], - u'cabinet': u'default', + # u'latest_rev': u'f94a263812dbe46a3a13d5209bb119988d0078d5', + u'documents': [{u'url': u'/api/documents/sample', u'name': u'sample'}, + {u'url': u'/api/documents/sample_pl', u'name': u'sample_pl'}], }) self.response = self.client.get( \ - reverse("document_view", args=['testfile'])+'?autocabinet=true' ) + reverse("document_view", args=['sample']) ) self.assert_json_response({ - u'latest_shared_rev': u'f94a263812dbe46a3a13d5209bb119988d0078d5', - u'text_url': reverse("doctext_view", args=[u'testfile']), - u'dc_url': reverse("docdc_view", args=[u'testfile']), - u'parts_url': reverse("docparts_view", args=[u'testfile']), - u'name': u'testfile', - u'size': 20, + #u'latest_shared_rev': u'f94a263812dbe46a3a13d5209bb119988d0078d5', + u'text_url': reverse("doctext_view", args=[u'sample']), + u'dc_url': reverse("docdc_view", args=[u'sample']), + # u'parts_url': reverse("docparts_view", args=[u'sample']), + u'name': u'sample', + # u'size': 20, }) - - - @temprepo('test2') - def test_document_text_with_login(self): - self.assertTrue(self.client.login(username='admin', password='admin')) - - self.response = self.client.get( \ - reverse("doctext_view", args=['testfile']) ) - - self.assertEqual(self.response.status_code, 200) - self.assertEqual(self.response.content, "Test file contents.\n") - @temprepo('test2') - def test_document_text_update(self): + @temprepo('simple') + def test_document_text_with_login(self): self.assertTrue(self.client.login(username='admin', password='admin')) - TEXT = u"Ala ma kota i psa" - - self.response = self.client.put( \ - reverse("doctext_view", args=['testfile']), {'contents': TEXT }) - self.assertEqual(self.response.status_code, 200) self.response = self.client.get( \ - reverse("doctext_view", args=['testfile']) ) + reverse("document_view", args=['sample']) ) + + resp = self.assert_json_response({ + #u'latest_shared_rev': u'f94a263812dbe46a3a13d5209bb119988d0078d5', + u'text_url': reverse("doctext_view", args=[u'sample']), + u'dc_url': reverse("docdc_view", args=[u'sample']), + # u'parts_url': reverse("docparts_view", args=[u'sample']), + u'name': u'sample', + # u'size': 20, + }) + + self.response = self.client.get(resp['text_url']) self.assertEqual(self.response.status_code, 200) - self.assertEqual(self.response.content, TEXT) + self.assertEqual(self.response.content, "Ala ma kota\n") +# +# +# @temprepo('simple') +# def test_document_text_update(self): +# self.assertTrue(self.client.login(username='admin', password='admin')) +# TEXT = u"Ala ma kota i psa" +# +# self.response = self.client.put( \ +# reverse("doctext_view", args=['testfile']), {'contents': TEXT }) +# self.assertEqual(self.response.status_code, 200) +# +# self.response = self.client.get( \ +# reverse("doctext_view", args=['testfile']) ) +# self.assertEqual(self.response.status_code, 200) +# self.assertEqual(self.response.content, TEXT) def assert_json_response(self, must_have={}, exclude=[]): self.assertEqual(self.response.status_code, 200) diff --git a/apps/api/tests/data/test2/.library b/apps/api/tests/data/clean/$meta similarity index 100% rename from apps/api/tests/data/test2/.library rename to apps/api/tests/data/clean/$meta diff --git a/apps/api/tests/data/empty/.hg/00changelog.i b/apps/api/tests/data/clean/.hg/00changelog.i similarity index 100% rename from apps/api/tests/data/empty/.hg/00changelog.i rename to apps/api/tests/data/clean/.hg/00changelog.i diff --git a/apps/api/tests/data/clean/.hg/dirstate b/apps/api/tests/data/clean/.hg/dirstate new file mode 100644 index 0000000000000000000000000000000000000000..417cb6ba33ecbf45913dc7737122d86570b6b292 GIT binary patch literal 112 zcmZ<_H#T@K_L?y-?PXk>vwV8^xM|9{(@34H6XfTj_ff*zQYPU z3f z%l3+1dS!@iNcrBjpX*ODv|oJwB#q~??ZT}E)u$Bnl!2ihho(aITiwj9-UGK|OO$NsD=BviZ!eEAzh}f4U^!a&Df)zsi^<;gZa>PbR`kRTf#Y zYXz6atgebQF)otH{bP9b&YXV5^yz9X>7P0tuin0R%U`KZOWu8Ny$)pU_#Afa*3LIv ar^}mfoxW9aomnNTWQmUAGI_QvtkqQ=;^b`$9s!`x1o>cqf4hf&ikA{t?#88 z$IakAL)sB+8pv)223sJW3}!JvTm^E3;RW&8NttQocV9GT`ADC6bpOSMtxz>E3gl`K zHq^^VFG)-n|w9fCc0+Ff=X!iF@t1QVOIv^)k{k)ARC+QWHU< d|DgcLWCzNWB&HW5bnNMW0u*Oe$xSUu1OT6)BANgI literal 0 HcmV?d00001 diff --git a/apps/api/tests/data/testone/.library b/apps/api/tests/data/clean/.hgignore similarity index 100% rename from apps/api/tests/data/testone/.library rename to apps/api/tests/data/clean/.hgignore diff --git a/apps/api/tests/data/clean/.hgtags b/apps/api/tests/data/clean/.hgtags new file mode 100644 index 00000000..0b061138 --- /dev/null +++ b/apps/api/tests/data/clean/.hgtags @@ -0,0 +1 @@ +d5e516ebd357bca24c6afb737e97db3b3d4f111a $branchbase diff --git a/apps/api/tests/data/empty/.hg/branchheads.cache b/apps/api/tests/data/empty/.hg/branchheads.cache deleted file mode 100644 index 022ec463..00000000 --- a/apps/api/tests/data/empty/.hg/branchheads.cache +++ /dev/null @@ -1,2 +0,0 @@ -e56b2a7e06a97d7c3697fc4295974e0f20a66190 0 -e56b2a7e06a97d7c3697fc4295974e0f20a66190 default diff --git a/apps/api/tests/data/empty/.hg/dirstate b/apps/api/tests/data/empty/.hg/dirstate deleted file mode 100644 index 3996f8935c27433de5a801e0a195d61a27d4dff4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 65 zcmaEwtyRaivbM%-`X8sM)BX4rmL*PLzyk6Z7#f#=#J#ph($ diff --git a/apps/api/tests/data/empty/.hg/store/00changelog.i b/apps/api/tests/data/empty/.hg/store/00changelog.i deleted file mode 100644 index f6361419fd9f94de756b336366331ce573bd6ebb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 169 zcmZQzWME`~fJ`8j17$P(hk~csT6JtIYirD=|8bf+-H%^kS>gnk8W3GENA{Q@-(dwF zh68ukpJ4CG5o)@*>zm{;POVA8B8Mj34}aymeCY+ZLz?bimYkSra{NSRcb-teLxI1u zB-Xs2zHjZy8{6+5{#*Wz`9ynVWTo4jxQoh7n`iC*!v3K6THsN&+~a}mzZnmPDAWM} DWl~7n diff --git a/apps/api/tests/data/empty/.hg/store/00manifest.i b/apps/api/tests/data/empty/.hg/store/00manifest.i deleted file mode 100644 index 267c71add2ecbb538408cc402e6b67403377ed04..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 115 zcmZQzWME`~0AnC!1Z6Y)hl2ATFRqwfpm?BLW_!hqKeqxr!qsNL)PU$xy`0RXqQs&~ uh9nDvlvL9cLt_hbQwviQ!(`Jm15+b2)5H`*6O+Uw%d|ubvlPRWBrX7{+9C)5 diff --git a/apps/api/tests/data/empty/.hg/store/fncache b/apps/api/tests/data/empty/.hg/store/fncache deleted file mode 100644 index d4a556ec..00000000 --- a/apps/api/tests/data/empty/.hg/store/fncache +++ /dev/null @@ -1 +0,0 @@ -data/.library.i diff --git a/apps/api/tests/data/empty/.hg/store/undo b/apps/api/tests/data/empty/.hg/store/undo deleted file mode 100644 index 33dec7fc70c95eb8c560f0c6dda39cdb4bff7542..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 49 vcmYdEEJ@VY%gIbCN-V0>%VaR%GBC(Z%*#wmEiQp_lQRLVSAd^EcCo`!iv8WONnu-gB diff --git a/lib/wlrepo/tests/data/clean/ignored_file b/apps/api/tests/data/simple/$meta similarity index 100% rename from lib/wlrepo/tests/data/clean/ignored_file rename to apps/api/tests/data/simple/$meta diff --git a/apps/api/tests/data/test2/.hg/00changelog.i b/apps/api/tests/data/simple/.hg/00changelog.i similarity index 100% rename from apps/api/tests/data/test2/.hg/00changelog.i rename to apps/api/tests/data/simple/.hg/00changelog.i diff --git a/apps/api/tests/data/test2/.hg/branch b/apps/api/tests/data/simple/.hg/branch similarity index 100% rename from apps/api/tests/data/test2/.hg/branch rename to apps/api/tests/data/simple/.hg/branch diff --git a/apps/api/tests/data/simple/.hg/branchheads.cache b/apps/api/tests/data/simple/.hg/branchheads.cache new file mode 100644 index 00000000..713758bd --- /dev/null +++ b/apps/api/tests/data/simple/.hg/branchheads.cache @@ -0,0 +1,4 @@ +65046aefea667e38c7a01d7ca62412d7e81f68bc 2 +d5e516ebd357bca24c6afb737e97db3b3d4f111a default +00e4aa6f4f53f31020e4d3e0579cb3c0fa0bd056 $doc:sample +65046aefea667e38c7a01d7ca62412d7e81f68bc $doc:sample_pl diff --git a/apps/api/tests/data/simple/.hg/dirstate b/apps/api/tests/data/simple/.hg/dirstate new file mode 100644 index 0000000000000000000000000000000000000000..46fefcaa468b88fb29e0420523ca5b04a4bdfcff GIT binary patch literal 112 zcmbOgX>n)ruZ_#X`Er;_rpAaae|J!Z0Sm}uU}#(d68G9OK>Sd&7rsw4sr2=Ib Z82&>6kjV~|DM?H(M%TfrlABtR2mmQ-Ag}-c literal 0 HcmV?d00001 diff --git a/apps/api/tests/data/test2/.hg/requires b/apps/api/tests/data/simple/.hg/requires similarity index 100% rename from apps/api/tests/data/test2/.hg/requires rename to apps/api/tests/data/simple/.hg/requires diff --git a/apps/api/tests/data/simple/.hg/store/00changelog.i b/apps/api/tests/data/simple/.hg/store/00changelog.i new file mode 100644 index 0000000000000000000000000000000000000000..f2451544100dace4441a882fc545eacf3724a8ce GIT binary patch literal 759 zcmZQzWME`~fC3;@3S~3=hk~n5#a>?y-?PXk>vwV8^xM|9{(@34H6XfTj_ff*zQYPU z3f z%l3+1dS!@iNcrBjpX*ODv|oJwB#q~??ZT}E)u$Bnl!2igh^K*B3=ltnoXqfKRla}lX90yLmmh@B*?iy^_k}R18ZcEc$MnoW zu0sYqY!BvsXNvRw_{cGHQ%-KXI{!ZR>svHR*5&Zk)L6GS_RpW+5^^=)Px^pC#D$5? z;cGZ&^332n`0AL;>KK(E*~IASkE0)UYbV^6=;iX5$M=G{~IzZ2E(>*t-(yiy&r zY4-io`)iJE`THoU;4Cr+W*w W>tkqQ=;^b`$9s!`x1o>cqf4hf&ikA{t?#88 z$IakAL)sB+8pv)2hBP2P17{)!0gqead6{KiP4%~Bj`y8xaBw?c|p6JIdPN))z*NGxD3j zR;>V&&OmY|n8m=r1foH%R55;RHo0celQ*jyW^!y;$@-vcu`E;#i~@x%$am(&iMa(i zsqqCldKI}j3>Fr~hAC#IDM_Y=mX_v8hK7cTCZ>soNlB(@CT597X_i1KW78yaF0eVT z!DJ$koD9UwPz-j0;RW&8NttQocV9GT`ADC6bpOSMtzgwqqGHa})4K(M0mTrI^=!d2 zl{NE^PgK3_Iq`|!hX01l>+5eXkKbp~{ANys&&?SI6%6u+=6O6>%V+L+X4|{t@sb>SBa?WTXMFz6hZ>OpIxEcl literal 0 HcmV?d00001 diff --git a/apps/api/tests/data/testone/.hg/store/data/.library.i b/apps/api/tests/data/simple/.hg/store/data/$meta.i similarity index 100% rename from apps/api/tests/data/testone/.hg/store/data/.library.i rename to apps/api/tests/data/simple/.hg/store/data/$meta.i diff --git a/apps/api/tests/data/simple/.hg/store/data/.hgignore.i b/apps/api/tests/data/simple/.hg/store/data/.hgignore.i new file mode 100644 index 0000000000000000000000000000000000000000..2431023a17b1e7b5c96e5db8e264c251f39beab0 GIT binary patch literal 64 ncmZQzWME{#0{%n64&J91ElOJ*kA4VBT`S_X^H8UyS=|B-vGZQWV Du}=?# literal 0 HcmV?d00001 diff --git a/apps/api/tests/data/simple/.hg/strip-backup/26716f931d95-backup b/apps/api/tests/data/simple/.hg/strip-backup/26716f931d95-backup new file mode 100644 index 0000000000000000000000000000000000000000..424de921845804ff60f1d4facdde7f2b0d54ca0e GIT binary patch literal 867 zcmV-p1DyOwM=>x$T4*^jL0KkKSu2faxBvhdfB(<K$&&y7|Ml@yI_%v) z>W12qZ`n><{5n7aO(91y2~<|M$}|!noTqs9-0KudU~drG&F3Z z$^oGDJtw4O2c&7~lpaaFDeX@xAZTRMO))YCni(1yG|Qq*S-H>#6|h%&|P?W6ap&LK~E!F+v$UntzorO1egr!-PGmONx_zMU@NkuMAb~dBKT;fRNcS|o(iVP`9 zkg_%2#ha63B5#A)m>4u^|6Hv315#uQSPzHzdkMB}#l9~H8gjqE8SJFcfp`GXfpOZ# z3sY3-$l_v4o+^ZzDQzI-n-@d93@TG-VO*xP6@$++CtqwzLC8(sSxuhHGrp>rQ< zn_db;hd~}@j%>i(1;pwM1x3Dd_}_Sx7_oj3r`Ljdax~`VV>SGvJL^)QV5wiLZK{}S z#bQ=Mt3zIYk#7|pYBxCOK(j`vmw?La#CVn0Gb|x9q`kY}+`q+SmT82(Li@nLwb;)1 tc>VWXDRq>?a4G>yCU6Sq1E3UMEdFP9{|K>&Cr*Ehxgwk>NEODj+yEVTdWrx5 literal 0 HcmV?d00001 diff --git a/apps/api/tests/data/testone/.hg/undo.branch b/apps/api/tests/data/simple/.hg/undo.branch similarity index 100% rename from apps/api/tests/data/testone/.hg/undo.branch rename to apps/api/tests/data/simple/.hg/undo.branch diff --git a/apps/api/tests/data/simple/.hg/undo.dirstate b/apps/api/tests/data/simple/.hg/undo.dirstate new file mode 100644 index 0000000000000000000000000000000000000000..310d94169efd6c83346d29be1d8fcd225cf795a2 GIT binary patch literal 112 zcmccmRP6QT@I8xsvVIrWO}}kz>n|w9fCc0+Ff=X!iF@stpa7&e^)k{k)ARC+QWHU< Y|DgcLWCzNWB&HXm>tI#MO)W_T0Cd|SLI3~& literal 0 HcmV?d00001 diff --git a/lib/wlrepo/tests/data/clean/pub_valid_file.xml b/apps/api/tests/data/simple/.hgignore similarity index 100% rename from lib/wlrepo/tests/data/clean/pub_valid_file.xml rename to apps/api/tests/data/simple/.hgignore diff --git a/apps/api/tests/data/simple/.hgtags b/apps/api/tests/data/simple/.hgtags new file mode 100644 index 00000000..0b061138 --- /dev/null +++ b/apps/api/tests/data/simple/.hgtags @@ -0,0 +1 @@ +d5e516ebd357bca24c6afb737e97db3b3d4f111a $branchbase diff --git a/apps/api/tests/data/test2/.hg/branchheads.cache b/apps/api/tests/data/test2/.hg/branchheads.cache deleted file mode 100644 index 650c9b01..00000000 --- a/apps/api/tests/data/test2/.hg/branchheads.cache +++ /dev/null @@ -1,3 +0,0 @@ -93618f13c33aab5a3d049e0860cd3d21a457cd7d 2 -f94a263812dbe46a3a13d5209bb119988d0078d5 default -93618f13c33aab5a3d049e0860cd3d21a457cd7d personal_admin_file_testfile diff --git a/apps/api/tests/data/test2/.hg/dirstate b/apps/api/tests/data/test2/.hg/dirstate deleted file mode 100644 index cc53c86d99604fa2d38ed9038393593999c14043..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 98 zcmezArDh>?`$?9S@KuG`8zpD-GE`h;zyk6>V*jB4$mGz=$xJFrEUE-bG%f)OhW^(u060L2v^h5!Hn diff --git a/apps/api/tests/data/test2/.hg/store/00changelog.i b/apps/api/tests/data/test2/.hg/store/00changelog.i deleted file mode 100644 index 4d3d86a3c0176126e1d5b8f2e123ea1608d00901..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 553 zcmZQzWME`~fJ`8j17$P(hk~csT6JtIYirD=|8bf+-H%^kS>gnk8W3GENA{Q@-(dwF zh68ukpJ4CG5o)@*>zm{;POVA8B8Mj34}aymeCY+ZLz?bimYkSra{NSRcb-teLxI1u zB-Xs2zHjZy8{6+5{#*Wz`9ynVWTo4jxQoh7n`iC*!v3K6THsN&+~a}mzZnmPDAa*1 z1v!y{p%{oO!7K)d<3Voy>7`~Nbo)t`mGD)C*&8Ki^fFXjg{lEl6?2jk7?^zp{Jc%P zy#0(lx0v`CdYYMf8~b}2ni+2Q*lOTuVqj!!?qTL_k*V26 z12bcTunVT`CJ$3awPoMF;y86Uf#+7}nk7N|Y3Vl31eFGUhH4gwS=DjRe z0k-!JnCu0Ti-DL4iWxypo}Ab(eAsGrlr76Vj)b$eic7-J)`C?-iHbS8XMFjZ6$Bg} z+Ae>9z9v(du&OA#PdCF z@}EU`7CdU}FL^wxVSAO=_h84sYrK2s*T}QgO3pR3GSkT1EqCKwRD*a#xt6!uG1m`M l^h1t+IeE)_WwoMW!rWK;CclW8Z6{^x_`&|wy~&fz`T(I_&I#eZ32$2-xUWg@08ifQ`M14)B&-9gh7zUZTMYmdt7j4b diff --git a/apps/api/tests/data/test2/.hg/store/data/pub__testfile.xml.i b/apps/api/tests/data/test2/.hg/store/data/pub__testfile.xml.i deleted file mode 100644 index ca4178107ebf5027b772f30f678589caa752ccef..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 85 zcmZQzWME`~08t<%0%bG)hk~CxNzXT^`)faL+&ynYW1#g5TmH9DHDIbVB(=CiAuTf} QRUtV)uOv0Eq*#v&0PM0E`Tzg` diff --git a/apps/api/tests/data/test2/.hg/store/fncache b/apps/api/tests/data/test2/.hg/store/fncache deleted file mode 100644 index d55636d5..00000000 --- a/apps/api/tests/data/test2/.hg/store/fncache +++ /dev/null @@ -1,2 +0,0 @@ -data/.library.i -data/pub_testfile.xml.i diff --git a/apps/api/tests/data/test2/.hg/store/undo b/apps/api/tests/data/test2/.hg/store/undo deleted file mode 100644 index 33e82075c7b90539bd21b2f83f0e543cbe9e8aac..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 35 pcmXpo$W6@4OiL{;(aU5oGO^?`Fi6fw%u7$r$xjE07@Jsd0RY2O3P1n= diff --git a/apps/api/tests/data/test2/.hg/undo.branch b/apps/api/tests/data/test2/.hg/undo.branch deleted file mode 100644 index 998eac45..00000000 --- a/apps/api/tests/data/test2/.hg/undo.branch +++ /dev/null @@ -1 +0,0 @@ -personal_admin_file_testfile \ No newline at end of file diff --git a/apps/api/tests/data/test2/.hg/undo.dirstate b/apps/api/tests/data/test2/.hg/undo.dirstate deleted file mode 100644 index 431d58a88ab736b290be83c1791c3c9361d4e3e6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 98 zcmezArDh>?`$?9S@KuG`8zpD-GE`h;zygZU#5nYFGLwoDiz@RN7#f!VB}KfpEwKmE V0tKZ>@g=FnC25&Csd^Q;IRHKv7P0^U diff --git a/apps/api/tests/data/test2/pub_testfile.xml b/apps/api/tests/data/test2/pub_testfile.xml deleted file mode 100644 index 57873f23..00000000 --- a/apps/api/tests/data/test2/pub_testfile.xml +++ /dev/null @@ -1 +0,0 @@ -Test file contents. diff --git a/apps/api/tests/data/testone/.hg/00changelog.i b/apps/api/tests/data/testone/.hg/00changelog.i deleted file mode 100644 index d3a8311050e54c57c5be7cfe169e60a95768812c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 57 zcmWN_K?=Yi3?`$?9S@KuG`8zpD-GE`h;zyk6Z7#f!V#YMb!Tqy<80tKZ>@g=FnC25&C Xsd^Q;IWPqbPz4-%IhjdCiA9wF59=C+ diff --git a/apps/api/tests/data/testone/.hg/requires b/apps/api/tests/data/testone/.hg/requires deleted file mode 100644 index 5175383b..00000000 --- a/apps/api/tests/data/testone/.hg/requires +++ /dev/null @@ -1,3 +0,0 @@ -revlogv1 -store -fncache diff --git a/apps/api/tests/data/testone/.hg/store/00changelog.i b/apps/api/tests/data/testone/.hg/store/00changelog.i deleted file mode 100644 index c466ccb53e983604d8937c5ab7e29e7bce13d986..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 348 zcmZQzWME`~fJ`8j17$P(hk~csT6JtIYirD=|8bf+-H%^kS>gnk8W3GENA{Q@-(dwF zh68ukpJ4CG5o)@*>zm{;POVA8B8Mj34}aymeCY+ZLz?bimYkSra{NSRcb-teLxI1u zB-Xs2zHjZy8{6+5{#*Wz`9ynVWTo4jxQoh7n`iC*!v3K6THsN&+~a}mzZnmPDAa*1 z1v!y{p%{oO!7K)d<3Voy>7`~Nbo)t`mGD)C*&8Ki^fFXjg{lEl6?2jk7?^zp{Jc%P zy#0(lx0v`CdYYMf8~b}2ni+2Q*lOTuVqj!!?qTL_k*V26 z12bcTunVT`CJ$3awPoMF;y86Uf#+7}nk7N|Y3Vl31eFGUhH4gwS=DjRe F0RTDwd*}cF diff --git a/apps/api/tests/data/testone/.hg/store/00manifest.i b/apps/api/tests/data/testone/.hg/store/00manifest.i deleted file mode 100644 index 0239a8f7899d5bdcd848c8340ba48fe20f00258e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 249 zcmZQzWME`~0AnC!1Z6Y)hl2ATFRqwfpm?BLW_!hqKeqxr!qsNL)PU$xy`0RXqQs&~ zh9nDvlvL9cLt_hbQwviQ!(`Jm15+b2)5H`*6O+Uw%d|ubvlPRWBrdRakYx-EZa|y^ zW-&mV0kZX%{&}y7SB~b_UUu(mS)f*MZ1dmiP&F_Lxml|json|yaml)$" -library_resource = Resource(LibraryHandler, **authdata) -document_resource = Resource(DocumentHandler, **authdata) -document_text_resource = Resource(DocumentTextHandler, **authdata) -document_dc_resource = Resource(DocumentDublinCoreHandler, **authdata) - urlpatterns = patterns('', # url(r'^hello$', hello_resource, {'emitter_format': 'json'}), # url(r'^hello\.(?P.+)$', hello_resource), + # Toolbar + url(r'^toolbar/buttons$', toolbar_buttons, {'emitter_format': 'json'}), + + # Toolbar + url(r'^toolbar/scriptlets$', scriptlets, {'emitter_format': 'json'}), + # Documents url(r'^documents$', library_resource, {'emitter_format': 'json'}, name="document_list_view"), diff --git a/apps/toolbar/models.py b/apps/toolbar/models.py index d1f4952c..04146223 100644 --- a/apps/toolbar/models.py +++ b/apps/toolbar/models.py @@ -14,6 +14,26 @@ class ButtonGroup(models.Model): def __unicode__(self): return self.name + +#class ButtonGroupManager(models.Manager): +# +# def with_buttons(self): +# from django.db import connection +# cursor = connection.cursor() +# cursor.execute(""" +# SELECT g.name, g.slug, CONCAT(b.slug), +# FROM toolbar_buttongroup as g LEFT JOIN toolbar_button as b +# +# WHERE p.id = r.poll_id +# GROUP BY 1, 2, 3 +# ORDER BY 3 DESC""") +# result_list = [] +# for row in cursor.fetchall(): +# p = self.model(id=row[0], question=row[1], poll_date=row[2]) +# p.num_responses = row[3] +# result_list.append(p) +# return result_list + class Button(models.Model): label = models.CharField(max_length=32) slug = models.SlugField(unique=True) #unused diff --git a/lib/wlrepo/tests/data/simple/ignored_file b/apps/wysiwyg/__init__.py similarity index 100% rename from lib/wlrepo/tests/data/simple/ignored_file rename to apps/wysiwyg/__init__.py diff --git a/apps/wysiwyg/models.py b/apps/wysiwyg/models.py new file mode 100644 index 00000000..71a83623 --- /dev/null +++ b/apps/wysiwyg/models.py @@ -0,0 +1,3 @@ +from django.db import models + +# Create your models here. diff --git a/apps/wysiwyg/tests.py b/apps/wysiwyg/tests.py new file mode 100644 index 00000000..2247054b --- /dev/null +++ b/apps/wysiwyg/tests.py @@ -0,0 +1,23 @@ +""" +This file demonstrates two different styles of tests (one doctest and one +unittest). These will both pass when you run "manage.py test". + +Replace these with more appropriate tests for your application. +""" + +from django.test import TestCase + +class SimpleTest(TestCase): + def test_basic_addition(self): + """ + Tests that 1 + 1 always equals 2. + """ + self.failUnlessEqual(1 + 1, 2) + +__test__ = {"doctest": """ +Another way to test that 1 + 1 is equal to 2. + +>>> 1 + 1 == 2 +True +"""} + diff --git a/apps/wysiwyg/urls.py b/apps/wysiwyg/urls.py new file mode 100644 index 00000000..ca19ea97 --- /dev/null +++ b/apps/wysiwyg/urls.py @@ -0,0 +1,12 @@ +# -*- encoding: utf-8 -*- + +__author__= "Łukasz Rekucki" +__date__ = "$2009-09-23 15:57:38$" +__doc__ = "Module documentation." + +from django.conf.urls.defaults import * + + +urlpatterns = patterns('', + (r'^$', 'wysiwyg.views.index'), +) diff --git a/apps/wysiwyg/views.py b/apps/wysiwyg/views.py new file mode 100644 index 00000000..e588c49e --- /dev/null +++ b/apps/wysiwyg/views.py @@ -0,0 +1,5 @@ +# Create your views here. +from django.views.generic.simple import direct_to_template + +def index(request): + return direct_to_template(request, 'wysiwyg.html', extra_context={}) \ No newline at end of file diff --git a/lib/wlrepo/__init__.py b/lib/wlrepo/__init__.py index 1c1335e8..cbc0c2c6 100644 --- a/lib/wlrepo/__init__.py +++ b/lib/wlrepo/__init__.py @@ -1,7 +1,6 @@ # -*- encoding: utf-8 -*- __author__="Łukasz Rekucki" __date__ ="$2009-09-18 10:49:24$" - __doc__ = """Main module for the Repository Abstraction Layer""" class Library(object): @@ -9,157 +8,107 @@ class Library(object): def __init__(self, create=False): """Open an existing library, or create a new one. By default, fails if the library doesn't exist.""" - self.create = create - - def main_cabinet(self): - """Return the "main" cabinet of the library.""" - pass + self.create = create - def cabinets(self): - """List all cabinets in the library.""" + def documents(self): + """List all documents in the library.""" pass - def cabinet(self, document, user, create=False): - """Open a cabinet belonging to the _user_ for a given _document_. - If the _document_ is actually a sub-document, it's parent's cabinet is - opened istead. - - If the cabinet doesn't exists and create is False (the default), a - CabinetNotFound exception is raised. - - If create is True, a new cabinet is created if it doesn't exist yet.""" + def document_for_rev(self, rev): + """Retrieve a document in the specified revision.""" pass - - def document(self, docid, user, part=None, shelve=None): + def document(self, docid, user=None): + """Retrieve a document from a library.""" pass + def get_revision(self, revid): + """Retrieve a handle to a specified revision.""" + return None -class Cabinet(object): + def document_create(self, docid): + """Create a new document. The document will have it's own branch.""" + + +class Document(object): + """A class representing a document package boundled with a revision.""" - def __init__(self, library, name=None, doc=None, user=None): + def __init__(self, library, revision): + """_library_ should be an instance of a Library.""" self._library = library - if name: - self._name = name - self._maindoc = '' - self._user = self._document = None - elif doc and user: - self._user = user - self._document = doc - self._name = user + ':' + doc - self._maindoc = doc + if isinstance(revision, Revision): + self._revision = revision else: - raise ValueError("You must provide either name or doc and user.") + self._revision = library.get_revision(revision) - print "new cab:", self._name, self._user, self._document - - @property - def username(self): - return self._user - def __str__(self): - return "Cabinet(%s)" % self._name - - def parts(self): - """Lists all parts in this cabinet.""" + def take(self, user): + """Make a user copy of the document. This is persistant.""" pass - - def retrieve(self, part='xml', shelve=None): - """Retrieve a document from a given shelve in the cabinet. If no - part is given, the main document is retrieved. If no shelve is given, - the top-most shelve is used. - If parts is a list, all the given parts are retrieved atomicly. Use None - as the name for the main document""" + def giveback(self): + """Informs the library, that the user no longer needs this document. + Should be called on the user version of document. If not, it doesn nothing.""" + + def data(self, entry): + """Returns the specified entry as a file-like object.""" pass - def create(self, name, initial_data=''): - """Create a new part in the cabinet with the given name.""" - pass - - @property - def maindoc_name(self): - return self._maindoc - @property def library(self): return self._library @property - def name(self): - return self._name - - def shelf(self, selector=None): - pass - -class Document(object): - def __init__(self, cabinet, name): - self._cabinet = cabinet - self._name = name - - def read(self): - pass - - def write(self, data): - pass - - @property - def cabinet(self): - return self._cabinet + def revision(self): + return self._revision @property - def library(self): - return self._cabinet.library + def id(self): + return self._revision.document_name @property - def name(self): - return self._name - - def shelf(self): - return self._cabinet.shelf() - - @property - def size(self): - raise NotImplemented() - - @property - def parts(self): - raise NotImplemented() + def owner(self): + return self._revision.user_name def parentof(self, other): - return self.shelf().parentof(other.shelf()) + return self._revision.parentof(other._revision) def ancestorof(self, other): - return self.shelf().ancestorof(other.shelf()) + return self._revision.ancestorof(other._revision) -class Shelf(object): +class Revision(object): def __init__(self, lib): self._library = lib - def parentof(self, other): return False def ancestorof(self, other): return False - + + @property + def document_name(self): + raise ValueError() + + @property + def user_name(self): + raise ValueError() + # # Exception classes # -class LibraryException(Exception): - +class LibraryException(Exception): def __init__(self, msg, cause=None): Exception.__init__(self, msg) self.cause = cause -class CabinetNotFound(LibraryException): - def __init__(self, cabname): - LibraryException.__init__(self, "Cabinet '%s' not found." % cabname) +class RevisionNotFound(LibraryException): + def __init__(self, rev): + LibraryException.__init__(self, "Revision %r not found." % rev) pass - # import backends to local namespace -from backend_mercurial import MercurialLibrary \ No newline at end of file +from mercurial_backend.library import MercurialLibrary \ No newline at end of file diff --git a/lib/wlrepo/backend_mercurial.py b/lib/wlrepo/backend_mercurial.py index a082b8b4..35e4442e 100644 --- a/lib/wlrepo/backend_mercurial.py +++ b/lib/wlrepo/backend_mercurial.py @@ -1,565 +1,565 @@ -# -*- encoding: utf-8 -*- - -__author__ = "Łukasz Rekucki" -__date__ = "$2009-09-18 10:49:24$" - -__doc__ = """RAL implementation over Mercurial""" - -import mercurial -from mercurial import localrepo as hglrepo -from mercurial import ui as hgui -from mercurial.node import nullid -import re -import wlrepo - -FILTER = re.compile(r"^pub_(.+)\.xml$", re.UNICODE) - -def default_filter(name): - m = FILTER.match(name) - if m is not None: - return name, m.group(1) - return None - -class MercurialLibrary(wlrepo.Library): - - def __init__(self, path, maincabinet="default", ** kwargs): - super(wlrepo.Library, self).__init__( ** kwargs) - - self._hgui = hgui.ui() - self._hgui.config('ui', 'quiet', 'true') - self._hgui.config('ui', 'interactive', 'false') - - import os.path - self._ospath = self._sanitize_string(os.path.realpath(path)) - - maincabinet = self._sanitize_string(maincabinet) - - if os.path.isdir(path): - try: - self._hgrepo = hglrepo.localrepository(self._hgui, path) - except mercurial.error.RepoError: - raise wlrepo.LibraryException("[HGLibrary] Not a valid repository at path '%s'." % path) - elif kwargs.get('create', False): - os.makedirs(path) - try: - self._hgrepo = hglrepo.localrepository(self._hgui, path, create=1) - except mercurial.error.RepoError: - raise wlrepo.LibraryException("[HGLibrary] Can't create a repository on path '%s'." % path) - else: - raise wlrepo.LibraryException("[HGLibrary] Can't open a library on path '%s'." % path) - - # fetch the main cabinet - lock = self._hgrepo.lock() - try: - btags = self._hgrepo.branchtags() - - if not self._has_branch(maincabinet): - raise wlrepo.LibraryException("[HGLibrary] No branch named '%s' to init main cabinet" % maincabinet) - - self._maincab = MercurialCabinet(self, maincabinet) - finally: - lock.release() - - @property - def ospath(self): - return self._ospath - - @property - def main_cabinet(self): - return self._maincab - - def document(self, docid, user, part=None, shelve=None): - return self.cabinet(docid, user, create=False).retrieve(part=part, shelve=shelve) - - def cabinet(self, docid, user, create=False): - docid = self._sanitize_string(docid) - user = self._sanitize_string(user) - - bname = self._bname(user, docid) - - lock = self._lock(True) - try: - if self._has_branch(bname): - return MercurialCabinet(self, doc=docid, user=user) - - if not create: - raise wlrepo.CabinetNotFound(bname) - - # check if the docid exists in the main cabinet - needs_touch = not self._maincab.exists(docid) - cab = MercurialCabinet(self, doc=docid, user=user) - - name, fileid = cab._filename(None) - - def cleanup_action(l): - if needs_touch: - l._fileopener()(fileid, "w").write('') - l._fileadd(fileid) - - garbage = [fid for (fid, did) in l._filelist() if not did.startswith(docid)] - l._filesrm(garbage) - print "removed: ", garbage - - # create the branch - self._create_branch(bname, before_commit=cleanup_action) - return MercurialCabinet(self, doc=docid, user=user) - finally: - lock.release() - - # - # Private methods - # - - # - # Locking - # - - def _lock(self, write_mode=False): - return self._hgrepo.wlock() # no support for read/write mode yet - - def _transaction(self, write_mode, action): - lock = self._lock(write_mode) - try: - return action(self) - finally: - lock.release() - - # - # Basic repo manipulation - # - - def _checkout(self, rev, force=True): - return MergeStatus(mercurial.merge.update(self._hgrepo, rev, False, force, None)) - - def _merge(self, rev): - """ Merge the revision into current working directory """ - return MergeStatus(mercurial.merge.update(self._hgrepo, rev, True, False, None)) - - def _common_ancestor(self, revA, revB): - return self._hgrepo[revA].ancestor(self.repo[revB]) - - def _commit(self, message, user=u"library"): - return self._hgrepo.commit(text=message, user=user) - - - def _fileexists(self, fileid): - return (fileid in self._hgrepo[None]) - - def _fileadd(self, fileid): - return self._hgrepo.add([fileid]) - - def _filesadd(self, fileid_list): - return self._hgrepo.add(fileid_list) - - def _filerm(self, fileid): - return self._hgrepo.remove([fileid]) - - def _filesrm(self, fileid_list): - return self._hgrepo.remove(fileid_list) - - def _filelist(self, filter=default_filter): - for name in self._hgrepo[None]: - result = filter(name) - if result is None: continue - - yield result - - def _fileopener(self): - return self._hgrepo.wopener - - def _filectx(self, fileid, branchid): - return self._hgrepo.filectx(fileid, changeid=branchid) - - def _changectx(self, nodeid): - return self._hgrepo.changectx(nodeid) - - # - # BASIC BRANCH routines - # - - def _bname(self, user, docid): - """Returns a branch name for a given document and user.""" - docid = self._sanitize_string(docid) - uname = self._sanitize_string(user) - return "personal_" + uname + "_file_" + docid; - - def _has_branch(self, name): - return self._hgrepo.branchmap().has_key(self._sanitize_string(name)) - - def _branch_tip(self, name): - name = self._sanitize_string(name) - return self._hgrepo.branchtags()[name] - - def _create_branch(self, name, parent=None, before_commit=None): - name = self._sanitize_string(name) - - if self._has_branch(name): return # just exit - - if parent is None: - parent = self._maincab - - parentrev = parent._hgtip() - - self._checkout(parentrev) - self._hgrepo.dirstate.setbranch(name) - - if before_commit: before_commit(self) - - self._commit("[AUTO] Initial commit for branch '%s'." % name, user='library') - - # revert back to main - self._checkout(self._maincab._hgtip()) - return self._branch_tip(name) - - def _switch_to_branch(self, branchname): - current = self._hgrepo[None].branch() - - if current == branchname: - return current # quick exit - - self._checkout(self._branch_tip(branchname)) - return branchname - - def shelf(self, nodeid=None): - if nodeid is None: - nodeid = self._maincab._name - return MercurialShelf(self, self._changectx(nodeid)) - - - # - # Utils - # - - @staticmethod - def _sanitize_string(s): - if isinstance(s, unicode): - s = s.encode('utf-8') - return s - -class MercurialCabinet(wlrepo.Cabinet): - - def __init__(self, library, branchname=None, doc=None, user=None): - if doc and user: - super(MercurialCabinet, self).__init__(library, doc=doc, user=user) - self._branchname = library._bname(user=user, docid=doc) - elif branchname: - super(MercurialCabinet, self).__init__(library, name=branchname) - self._branchname = branchname - else: - raise ValueError("Provide either doc/user or branchname") - - def shelf(self): - return self._library.shelf(self._branchname) - - def parts(self): - return self._execute_in_branch(action=lambda l, c: (e[1] for e in l._filelist())) - - def retrieve(self, part=None, shelf=None): - name, fileid = self._filename(part) - - print "Retrieving document %s from cab %s" % (name, self._name) - - if fileid is None: - raise wlrepo.LibraryException("Can't retrieve main document from main cabinet.") - - def retrieve_action(l,c): - if l._fileexists(fileid): - return MercurialDocument(c, name=name, fileid=fileid) - print "File %s not found " % fileid - return None - - return self._execute_in_branch(retrieve_action) - - def create(self, name, initial_data): - name, fileid = self._filename(name) - - if name is None: - raise ValueError("Can't create main doc for maincabinet.") - - def create_action(l, c): - if l._fileexists(fileid): - raise wlrepo.LibraryException("Can't create document '%s' in cabinet '%s' - it already exists" % (fileid, c.name)) - - fd = l._fileopener()(fileid, "w") - fd.write(initial_data) - fd.close() - l._fileadd(fileid) - l._commit("File '%s' created." % fileid) - return MercurialDocument(c, fileid=fileid, name=name) - - return self._execute_in_branch(create_action) - - def exists(self, part=None, shelf=None): - name, filepath = self._filename(part) - - if filepath is None: return False - return self._execute_in_branch(lambda l, c: l._fileexists(filepath)) - - def _execute_in_branch(self, action, write=False): - def switch_action(library): - old = library._switch_to_branch(self._branchname) - try: - return action(library, self) - finally: - library._switch_to_branch(old) - - return self._library._transaction(write_mode=write, action=switch_action) - - - def _filename(self, docid): - return self._partname(docid, 'xml') - - def _partname(self, docid, part): - docid = self._library._sanitize_string(part) - part = self._library._sanitize_string(part) - - if part is None: - part = 'xml' - - if self._maindoc == '' and docid is None: - return None - - return 'pub_' + docid + '.' + part - - def _fileopener(self): - return self._library._fileopener() - - def _hgtip(self): - return self._library._branch_tip(self._branchname) - - def _filectx(self, fileid): - return self._library._filectx(fileid, self._branchname) - - def ismain(self): - return (self._library.main_cabinet == self) - -class MercurialDocument(wlrepo.Document): - - def __init__(self, cabinet, docid): - super(MercurialDocument, self).__init__(cabinet, name=docid) - self._opener = self._cabinet._fileopener() - self._docid = docid - self._ctxs = {} - - def _ctx(self, part): - if not self._ctxs.has_key(part): - self._ctxs[part] = self._cabinet._filectx(self._fileid()) - return self._ctxs[part] - - def _fileid(self, part='xml'): - return self._cabinet._partname(self._docid, part) - - def read(self, part='xml'): - return self._opener(self._ctx(part).path(), "r").read() - - def write(self, data, part='xml'): - return self._opener(self._ctx(part).path(), "w").write(data) - - def commit(self, message, user): - """Commit all parts of the document.""" - self.library._fileadd(self._fileid) - self.library._commit(self._fileid, message, user) - - def update(self): - """Update parts of the document.""" - lock = self.library._lock() - try: - if self._cabinet.ismain(): - return True # always up-to-date - - user = self._cabinet.username or 'library' - mdoc = self.library.document(self._fileid) - - mshelf = mdoc.shelf() - shelf = self.shelf() - - if not mshelf.ancestorof(shelf) and not shelf.parentof(mshelf): - shelf.merge_with(mshelf, user=user) - - return True - finally: - lock.release() - - def share(self, message): - lock = self.library._lock() - try: - print "sharing from", self._cabinet, self._cabinet.username - - if self._cabinet.ismain(): - return True # always shared - - if self._cabinet.username is None: - raise ValueError("Can only share documents from personal cabinets.") - - user = self._cabinet.username - - main = self.library.shelf() - local = self.shelf() - - no_changes = True - - # Case 1: - # * local - # | - # * <- can also be here! - # /| - # / | - # main * * - # | | - # The local branch has been recently updated, - # so we don't need to update yet again, but we need to - # merge down to default branch, even if there was - # no commit's since last update - - if main.ancestorof(local): - print "case 1" - main.merge_with(local, user=user, message=message) - no_changes = False - # Case 2: - # - # main * * local - # |\ | - # | \| - # | * - # | | - # - # Default has no changes, to update from this branch - # since the last merge of local to default. - elif local.has_common_ancestor(main): - print "case 2" - if not local.parentof(main): - main.merge_with(local, user=user, message=message) - no_changes = False - - # Case 3: - # main * - # | - # * <- this case overlaps with previos one - # |\ - # | \ - # | * local - # | | - # - # There was a recent merge to the defaul branch and - # no changes to local branch recently. - # - # Use the fact, that user is prepared to see changes, to - # update his branch if there are any - elif local.ancestorof(main): - print "case 3" - if not local.parentof(main): - local.merge_with(main, user=user, message='Local branch update.') - no_changes = False - else: - print "case 4" - local.merge_with(main, user=user, message='Local branch update.') - local = self.shelf() - main.merge_with(local, user=user, message=message) - - print "no_changes: ", no_changes - return no_changes - finally: - lock.release() - - def shared(self): - return self.library.main_cabinet.retrieve(self._name) - - def exists(self, part='xml'): - return self._cabinet.exists(self._fileid(part)) - - @property - def size(self): - return self._filectx.size() - - def shelf(self): - return self._cabinet.shelf() - - @property - def last_modified(self): - return self._filectx.date() - - def __str__(self): - return u"Document(%s->%s)" % (self._cabinet.name, self._name) - - def __eq__(self, other): - return self._filectx == other._filectx - - - -class MercurialShelf(wlrepo.Shelf): - - def __init__(self, lib, changectx): - super(MercurialShelf, self).__init__(lib) - - if isinstance(changectx, str): - self._changectx = lib._changectx(changectx) - else: - self._changectx = changectx - - @property - def _rev(self): - return self._changectx.node() - - def __str__(self): - return self._changectx.hex() - - def __repr__(self): - return "MercurialShelf(%s)" % self._changectx.hex() - - def ancestorof(self, other): - nodes = list(other._changectx._parents) - while nodes[0].node() != nullid: - v = nodes.pop(0) - if v == self._changectx: - return True - nodes.extend( v._parents ) - return False - - def parentof(self, other): - return self._changectx in other._changectx._parents - - def has_common_ancestor(self, other): - a = self._changectx.ancestor(other._changectx) - # print a, self._changectx.branch(), a.branch() - - return (a.branch() == self._changectx.branch()) - - def merge_with(self, other, user, message): - lock = self._library._lock(True) - try: - self._library._checkout(self._changectx.node()) - self._library._merge(other._changectx.node()) - self._library._commit(user=user, message=message) - finally: - lock.release() - - def __eq__(self, other): - return self._changectx.node() == other._changectx.node() - - -class MergeStatus(object): - def __init__(self, mstatus): - self.updated = mstatus[0] - self.merged = mstatus[1] - self.removed = mstatus[2] - self.unresolved = mstatus[3] - - def isclean(self): - return self.unresolved == 0 - -class UpdateStatus(object): - - def __init__(self, mstatus): - self.modified = mstatus[0] - self.added = mstatus[1] - self.removed = mstatus[2] - self.deleted = mstatus[3] - self.untracked = mstatus[4] - self.ignored = mstatus[5] - self.clean = mstatus[6] - - def has_changes(self): - return bool(len(self.modified) + len(self.added) + \ - len(self.removed) + len(self.deleted)) - -__all__ = ["MercurialLibrary"] \ No newline at end of file +## -*- encoding: utf-8 -*- +# +#__author__ = "Łukasz Rekucki" +#__date__ = "$2009-09-18 10:49:24$" +# +#__doc__ = """RAL implementation over Mercurial""" +# +#import mercurial +#from mercurial import localrepo as hglrepo +#from mercurial import ui as hgui +#from mercurial.node import nullid +#import re +#import wlrepo +# +#FILTER = re.compile(r"^pub_(.+)\.xml$", re.UNICODE) +# +#def default_filter(name): +# m = FILTER.match(name) +# if m is not None: +# return name, m.group(1) +# return None +# +#class MercurialLibrary(wlrepo.Library): +# +# def __init__(self, path, maincabinet="default", ** kwargs): +# super(wlrepo.Library, self).__init__( ** kwargs) +# +# self._hgui = hgui.ui() +# self._hgui.config('ui', 'quiet', 'true') +# self._hgui.config('ui', 'interactive', 'false') +# +# import os.path +# self._ospath = self._sanitize_string(os.path.realpath(path)) +# +# maincabinet = self._sanitize_string(maincabinet) +# +# if os.path.isdir(path): +# try: +# self._hgrepo = hglrepo.localrepository(self._hgui, path) +# except mercurial.error.RepoError: +# raise wlrepo.LibraryException("[HGLibrary] Not a valid repository at path '%s'." % path) +# elif kwargs.get('create', False): +# os.makedirs(path) +# try: +# self._hgrepo = hglrepo.localrepository(self._hgui, path, create=1) +# except mercurial.error.RepoError: +# raise wlrepo.LibraryException("[HGLibrary] Can't create a repository on path '%s'." % path) +# else: +# raise wlrepo.LibraryException("[HGLibrary] Can't open a library on path '%s'." % path) +# +# # fetch the main cabinet +# lock = self._hgrepo.lock() +# try: +# btags = self._hgrepo.branchtags() +# +# if not self._has_branch(maincabinet): +# raise wlrepo.LibraryException("[HGLibrary] No branch named '%s' to init main cabinet" % maincabinet) +# +# self._maincab = MercurialCabinet(self, maincabinet) +# finally: +# lock.release() +# +# @property +# def ospath(self): +# return self._ospath +# +# @property +# def main_cabinet(self): +# return self._maincab +# +# def document(self, docid, user, part=None, shelve=None): +# return self.cabinet(docid, user, create=False).retrieve(part=part, shelve=shelve) +# +# def cabinet(self, docid, user, create=False): +# docid = self._sanitize_string(docid) +# user = self._sanitize_string(user) +# +# bname = self._bname(user, docid) +# +# lock = self._lock(True) +# try: +# if self._has_branch(bname): +# return MercurialCabinet(self, doc=docid, user=user) +# +# if not create: +# raise wlrepo.CabinetNotFound(bname) +# +# # check if the docid exists in the main cabinet +# needs_touch = not self._maincab.exists(docid) +# cab = MercurialCabinet(self, doc=docid, user=user) +# +# name, fileid = cab._filename(None) +# +# def cleanup_action(l): +# if needs_touch: +# l._fileopener()(fileid, "w").write('') +# l._fileadd(fileid) +# +# garbage = [fid for (fid, did) in l._filelist() if not did.startswith(docid)] +# l._filesrm(garbage) +# print "removed: ", garbage +# +# # create the branch +# self._create_branch(bname, before_commit=cleanup_action) +# return MercurialCabinet(self, doc=docid, user=user) +# finally: +# lock.release() +# +# # +# # Private methods +# # +# +# # +# # Locking +# # +# +# def _lock(self, write_mode=False): +# return self._hgrepo.wlock() # no support for read/write mode yet +# +# def _transaction(self, write_mode, action): +# lock = self._lock(write_mode) +# try: +# return action(self) +# finally: +# lock.release() +# +# # +# # Basic repo manipulation +# # +# +# def _checkout(self, rev, force=True): +# return MergeStatus(mercurial.merge.update(self._hgrepo, rev, False, force, None)) +# +# def _merge(self, rev): +# """ Merge the revision into current working directory """ +# return MergeStatus(mercurial.merge.update(self._hgrepo, rev, True, False, None)) +# +# def _common_ancestor(self, revA, revB): +# return self._hgrepo[revA].ancestor(self.repo[revB]) +# +# def _commit(self, message, user=u"library"): +# return self._hgrepo.commit(text=message, user=user) +# +# +# def _fileexists(self, fileid): +# return (fileid in self._hgrepo[None]) +# +# def _fileadd(self, fileid): +# return self._hgrepo.add([fileid]) +# +# def _filesadd(self, fileid_list): +# return self._hgrepo.add(fileid_list) +# +# def _filerm(self, fileid): +# return self._hgrepo.remove([fileid]) +# +# def _filesrm(self, fileid_list): +# return self._hgrepo.remove(fileid_list) +# +# def _filelist(self, filter=default_filter): +# for name in self._hgrepo[None]: +# result = filter(name) +# if result is None: continue +# +# yield result +# +# def _fileopener(self): +# return self._hgrepo.wopener +# +# def _filectx(self, fileid, branchid): +# return self._hgrepo.filectx(fileid, changeid=branchid) +# +# def _changectx(self, nodeid): +# return self._hgrepo.changectx(nodeid) +# +# # +# # BASIC BRANCH routines +# # +# +# def _bname(self, user, docid): +# """Returns a branch name for a given document and user.""" +# docid = self._sanitize_string(docid) +# uname = self._sanitize_string(user) +# return "personal_" + uname + "_file_" + docid; +# +# def _has_branch(self, name): +# return self._hgrepo.branchmap().has_key(self._sanitize_string(name)) +# +# def _branch_tip(self, name): +# name = self._sanitize_string(name) +# return self._hgrepo.branchtags()[name] +# +# def _create_branch(self, name, parent=None, before_commit=None): +# name = self._sanitize_string(name) +# +# if self._has_branch(name): return # just exit +# +# if parent is None: +# parent = self._maincab +# +# parentrev = parent._hgtip() +# +# self._checkout(parentrev) +# self._hgrepo.dirstate.setbranch(name) +# +# if before_commit: before_commit(self) +# +# self._commit("[AUTO] Initial commit for branch '%s'." % name, user='library') +# +# # revert back to main +# self._checkout(self._maincab._hgtip()) +# return self._branch_tip(name) +# +# def _switch_to_branch(self, branchname): +# current = self._hgrepo[None].branch() +# +# if current == branchname: +# return current # quick exit +# +# self._checkout(self._branch_tip(branchname)) +# return branchname +# +# def shelf(self, nodeid=None): +# if nodeid is None: +# nodeid = self._maincab._name +# return MercurialShelf(self, self._changectx(nodeid)) +# +# +# # +# # Utils +# # +# +# @staticmethod +# def _sanitize_string(s): +# if isinstance(s, unicode): +# s = s.encode('utf-8') +# return s +# +#class MercurialCabinet(wlrepo.Cabinet): +# +# def __init__(self, library, branchname=None, doc=None, user=None): +# if doc and user: +# super(MercurialCabinet, self).__init__(library, doc=doc, user=user) +# self._branchname = library._bname(user=user, docid=doc) +# elif branchname: +# super(MercurialCabinet, self).__init__(library, name=branchname) +# self._branchname = branchname +# else: +# raise ValueError("Provide either doc/user or branchname") +# +# def shelf(self): +# return self._library.shelf(self._branchname) +# +# def parts(self): +# return self._execute_in_branch(action=lambda l, c: (e[1] for e in l._filelist())) +# +# def retrieve(self, part=None, shelf=None): +# name, fileid = self._filename(part) +# +# print "Retrieving document %s from cab %s" % (name, self._name) +# +# if fileid is None: +# raise wlrepo.LibraryException("Can't retrieve main document from main cabinet.") +# +# def retrieve_action(l,c): +# if l._fileexists(fileid): +# return MercurialDocument(c, name=name, fileid=fileid) +# print "File %s not found " % fileid +# return None +# +# return self._execute_in_branch(retrieve_action) +# +# def create(self, name, initial_data): +# name, fileid = self._filename(name) +# +# if name is None: +# raise ValueError("Can't create main doc for maincabinet.") +# +# def create_action(l, c): +# if l._fileexists(fileid): +# raise wlrepo.LibraryException("Can't create document '%s' in cabinet '%s' - it already exists" % (fileid, c.name)) +# +# fd = l._fileopener()(fileid, "w") +# fd.write(initial_data) +# fd.close() +# l._fileadd(fileid) +# l._commit("File '%s' created." % fileid) +# return MercurialDocument(c, fileid=fileid, name=name) +# +# return self._execute_in_branch(create_action) +# +# def exists(self, part=None, shelf=None): +# name, filepath = self._filename(part) +# +# if filepath is None: return False +# return self._execute_in_branch(lambda l, c: l._fileexists(filepath)) +# +# def _execute_in_branch(self, action, write=False): +# def switch_action(library): +# old = library._switch_to_branch(self._branchname) +# try: +# return action(library, self) +# finally: +# library._switch_to_branch(old) +# +# return self._library._transaction(write_mode=write, action=switch_action) +# +# +# def _filename(self, docid): +# return self._partname(docid, 'xml') +# +# def _partname(self, docid, part): +# docid = self._library._sanitize_string(part) +# part = self._library._sanitize_string(part) +# +# if part is None: +# part = 'xml' +# +# if self._maindoc == '' and docid is None: +# return None +# +# return 'pub_' + docid + '.' + part +# +# def _fileopener(self): +# return self._library._fileopener() +# +# def _hgtip(self): +# return self._library._branch_tip(self._branchname) +# +# def _filectx(self, fileid): +# return self._library._filectx(fileid, self._branchname) +# +# def ismain(self): +# return (self._library.main_cabinet == self) +# +#class MercurialDocument(wlrepo.Document): +# +# def __init__(self, cabinet, docid): +# super(MercurialDocument, self).__init__(cabinet, name=docid) +# self._opener = self._cabinet._fileopener() +# self._docid = docid +# self._ctxs = {} +# +# def _ctx(self, part): +# if not self._ctxs.has_key(part): +# self._ctxs[part] = self._cabinet._filectx(self._fileid()) +# return self._ctxs[part] +# +# def _fileid(self, part='xml'): +# return self._cabinet._partname(self._docid, part) +# +# def read(self, part='xml'): +# return self._opener(self._ctx(part).path(), "r").read() +# +# def write(self, data, part='xml'): +# return self._opener(self._ctx(part).path(), "w").write(data) +# +# def commit(self, message, user): +# """Commit all parts of the document.""" +# self.library._fileadd(self._fileid) +# self.library._commit(self._fileid, message, user) +# +# def update(self): +# """Update parts of the document.""" +# lock = self.library._lock() +# try: +# if self._cabinet.ismain(): +# return True # always up-to-date +# +# user = self._cabinet.username or 'library' +# mdoc = self.library.document(self._fileid) +# +# mshelf = mdoc.shelf() +# shelf = self.shelf() +# +# if not mshelf.ancestorof(shelf) and not shelf.parentof(mshelf): +# shelf.merge_with(mshelf, user=user) +# +# return True +# finally: +# lock.release() +# +# def share(self, message): +# lock = self.library._lock() +# try: +# print "sharing from", self._cabinet, self._cabinet.username +# +# if self._cabinet.ismain(): +# return True # always shared +# +# if self._cabinet.username is None: +# raise ValueError("Can only share documents from personal cabinets.") +# +# user = self._cabinet.username +# +# main = self.library.shelf() +# local = self.shelf() +# +# no_changes = True +# +# # Case 1: +# # * local +# # | +# # * <- can also be here! +# # /| +# # / | +# # main * * +# # | | +# # The local branch has been recently updated, +# # so we don't need to update yet again, but we need to +# # merge down to default branch, even if there was +# # no commit's since last update +# +# if main.ancestorof(local): +# print "case 1" +# main.merge_with(local, user=user, message=message) +# no_changes = False +# # Case 2: +# # +# # main * * local +# # |\ | +# # | \| +# # | * +# # | | +# # +# # Default has no changes, to update from this branch +# # since the last merge of local to default. +# elif local.has_common_ancestor(main): +# print "case 2" +# if not local.parentof(main): +# main.merge_with(local, user=user, message=message) +# no_changes = False +# +# # Case 3: +# # main * +# # | +# # * <- this case overlaps with previos one +# # |\ +# # | \ +# # | * local +# # | | +# # +# # There was a recent merge to the defaul branch and +# # no changes to local branch recently. +# # +# # Use the fact, that user is prepared to see changes, to +# # update his branch if there are any +# elif local.ancestorof(main): +# print "case 3" +# if not local.parentof(main): +# local.merge_with(main, user=user, message='Local branch update.') +# no_changes = False +# else: +# print "case 4" +# local.merge_with(main, user=user, message='Local branch update.') +# local = self.shelf() +# main.merge_with(local, user=user, message=message) +# +# print "no_changes: ", no_changes +# return no_changes +# finally: +# lock.release() +# +# def shared(self): +# return self.library.main_cabinet.retrieve(self._name) +# +# def exists(self, part='xml'): +# return self._cabinet.exists(self._fileid(part)) +# +# @property +# def size(self): +# return self._filectx.size() +# +# def shelf(self): +# return self._cabinet.shelf() +# +# @property +# def last_modified(self): +# return self._filectx.date() +# +# def __str__(self): +# return u"Document(%s->%s)" % (self._cabinet.name, self._name) +# +# def __eq__(self, other): +# return self._filectx == other._filectx +# +# +# +#class MercurialShelf(wlrepo.Shelf): +# +# def __init__(self, lib, changectx): +# super(MercurialShelf, self).__init__(lib) +# +# if isinstance(changectx, str): +# self._changectx = lib._changectx(changectx) +# else: +# self._changectx = changectx +# +# @property +# def _rev(self): +# return self._changectx.node() +# +# def __str__(self): +# return self._changectx.hex() +# +# def __repr__(self): +# return "MercurialShelf(%s)" % self._changectx.hex() +# +# def ancestorof(self, other): +# nodes = list(other._changectx._parents) +# while nodes[0].node() != nullid: +# v = nodes.pop(0) +# if v == self._changectx: +# return True +# nodes.extend( v._parents ) +# return False +# +# def parentof(self, other): +# return self._changectx in other._changectx._parents +# +# def has_common_ancestor(self, other): +# a = self._changectx.ancestor(other._changectx) +# # print a, self._changectx.branch(), a.branch() +# +# return (a.branch() == self._changectx.branch()) +# +# def merge_with(self, other, user, message): +# lock = self._library._lock(True) +# try: +# self._library._checkout(self._changectx.node()) +# self._library._merge(other._changectx.node()) +# self._library._commit(user=user, message=message) +# finally: +# lock.release() +# +# def __eq__(self, other): +# return self._changectx.node() == other._changectx.node() +# +# +#class MergeStatus(object): +# def __init__(self, mstatus): +# self.updated = mstatus[0] +# self.merged = mstatus[1] +# self.removed = mstatus[2] +# self.unresolved = mstatus[3] +# +# def isclean(self): +# return self.unresolved == 0 +# +#class UpdateStatus(object): +# +# def __init__(self, mstatus): +# self.modified = mstatus[0] +# self.added = mstatus[1] +# self.removed = mstatus[2] +# self.deleted = mstatus[3] +# self.untracked = mstatus[4] +# self.ignored = mstatus[5] +# self.clean = mstatus[6] +# +# def has_changes(self): +# return bool(len(self.modified) + len(self.added) + \ +# len(self.removed) + len(self.deleted)) +# +#__all__ = ["MercurialLibrary"] \ No newline at end of file diff --git a/lib/wlrepo/mercurial_backend/__init__.py b/lib/wlrepo/mercurial_backend/__init__.py new file mode 100644 index 00000000..10a4cf8a --- /dev/null +++ b/lib/wlrepo/mercurial_backend/__init__.py @@ -0,0 +1,84 @@ +# -*- encoding: utf-8 -*- + +__author__= "Łukasz Rekucki" +__date__ = "$2009-09-25 09:20:22$" +__doc__ = "Module documentation." + +import wlrepo + + + +class MercurialRevision(wlrepo.Revision): + + def __init__(self, lib, changectx): + super(MercurialRevision, self).__init__(lib) + self._changectx = changectx + + branchname = self._changectx.branch() + if branchname.startswith("$doc:"): + self._docname = branchname[5:] + self._username = None + elif branchname.startswith("$user:"): + idx = branchname.find("$doc:") + if(idx < 0): + raise ValueError("Revision %s is not a valid document revision." % changectx.hex()); + self._username = branchname[0:idx] + self._docname = branchname[idx+5:] + else: + raise ValueError("Revision %s is not a valid document revision." % changectx.hex()); + + @property + def document_name(self): + return self._docname + + @property + def user_name(self): + return self._username + + def hgrev(self): + return self._changectx.node() + + def hgcontext(self): + return self._changectx + + def hgbranch(self): + return self._changectx.branch() + + def __unicode__(self): + return u"%s" % self._changectx.hex() + + def __repr__(self): + return "%s" % self._changectx.hex() + + def ancestorof(self, other): + nodes = list(other._changectx._parents) + while nodes[0].node() != nullid: + v = nodes.pop(0) + if v == self._changectx: + return True + nodes.extend( v._parents ) + return False + + def parentof(self, other): + return self._changectx in other._changectx._parents + + def has_common_ancestor(self, other): + a = self._changectx.ancestor(other._changectx) + return (a.branch() == self._changectx.branch()) + + def merge_with(self, other, user, message): + lock = self._library._lock(True) + try: + self._library._checkout(self._changectx.node()) + self._library._merge(other._changectx.node()) + self._library._commit(user=user, message=message) + finally: + lock.release() + + def __eq__(self, other): + return self._changectx.node() == other._changectx.node() + + +from wlrepo.mercurial_backend.library import MercurialLibrary + + diff --git a/lib/wlrepo/mercurial_backend/document.py b/lib/wlrepo/mercurial_backend/document.py new file mode 100644 index 00000000..bced6741 --- /dev/null +++ b/lib/wlrepo/mercurial_backend/document.py @@ -0,0 +1,173 @@ +# -*- encoding: utf-8 -*- + +__author__ = "Łukasz Rekucki" +__date__ = "$2009-09-25 09:35:06$" +__doc__ = "Module documentation." + +import wlrepo + +class MercurialDocument(wlrepo.Document): + + def data(self, entry): + path = self._revision._docname + '.' + entry + return self._library._filectx(path, \ + self._revision.hgrev()).data() + + def quickwrite(self, entry, data, msg, user=None): + user = user or self.owner + if user is None: + raise ValueError("Can't determine user.") + + def write(l, r): + f = l._fileopen(r(entry), "w+") + f.write(data) + f.close() + l._fileadd(r(entry)) + + return self.invoke_and_commit(write, lambda d: (msg, user)) + + def invoke_and_commit(self, ops, before_commit): + lock = self._library._lock() + try: + self._library._checkout(self._revision.hgrev()) + + def entry_path(entry): + return self.id + '.' + entry + + ops(self._library, entry_path) + message, user = before_commit(self) + self._library._commit(message, user) + + return self._library.document(docid=self.id, user=self.owner) + finally: + lock.release() + + # def commit(self, message, user): + # """Make a new commit.""" + # self.invoke_and_commit(message, user, lambda *a: True) + + def ismain(self): + return self._revision.user_name() is None + + def shared(self): + if self.ismain(): + return self + return self._library.document(docid=self._revision.document_name()) + + + def take(self, user): + fullid = self._library.fulldocid(self.id, user) + + def take_action(library, resolve): + # branch from latest + library._create_branch(fullid, parent=self._revision) + + if not self._library.has_revision(fullid): + self.invoke_and_commit(take_action, \ + lambda d: ("$AUTO$ File checkout.", user) ) + + return self._library.document_for_rev(fullid) + + def update(self, user): + """Update parts of the document.""" + lock = self.library._lock() + try: + if self.ismain(): + # main revision of the document + return True + + if self._revision.has_children(): + # can't update non-latest revision + return False + + sv = self.shared() + + if not sv.ancestorof(self) and not self.parentof(sv): + self._revision.merge_with(sv._revision, user=user) + + return True + finally: + lock.release() + + def share(self, message): + lock = self.library._lock() + try: + if self.ismain(): + return True # always shared + + user = self._revision.user_name() + + main = self.shared()._revision + local = self._revision + + no_changes = True + + # Case 1: + # * local + # | + # * <- can also be here! + # /| + # / | + # main * * + # | | + # The local branch has been recently updated, + # so we don't need to update yet again, but we need to + # merge down to default branch, even if there was + # no commit's since last update + + if main.ancestorof(local): + print "case 1" + main.merge_with(local, user=user, message=message) + no_changes = False + # Case 2: + # + # main * * local + # |\ | + # | \| + # | * + # | | + # + # Default has no changes, to update from this branch + # since the last merge of local to default. + elif local.has_common_ancestor(main): + print "case 2" + if not local.parentof(main): + main.merge_with(local, user=user, message=message) + no_changes = False + + # Case 3: + # main * + # | + # * <- this case overlaps with previos one + # |\ + # | \ + # | * local + # | | + # + # There was a recent merge to the defaul branch and + # no changes to local branch recently. + # + # Use the fact, that user is prepared to see changes, to + # update his branch if there are any + elif local.ancestorof(main): + print "case 3" + if not local.parentof(main): + local.merge_with(main, user=user, message='Local branch update.') + no_changes = False + else: + print "case 4" + local.merge_with(main, user=user, message='Local branch update.') + local = self.shelf() + main.merge_with(local, user=user, message=message) + + print "no_changes: ", no_changes + return no_changes + finally: + lock.release() + + def __str__(self): + return u"Document(%s:%s)" % (self.name, self.owner) + + def __eq__(self, other): + return (self._revision == other._revision) and (self.name == other.name) + diff --git a/lib/wlrepo/mercurial_backend/library.py b/lib/wlrepo/mercurial_backend/library.py new file mode 100644 index 00000000..219a01df --- /dev/null +++ b/lib/wlrepo/mercurial_backend/library.py @@ -0,0 +1,250 @@ +# -*- encoding: utf-8 -*- + +__author__= "Łukasz Rekucki" +__date__ = "$2009-09-25 09:33:02$" +__doc__ = "Module documentation." + +import mercurial +from mercurial import localrepo as hglrepo +from mercurial import ui as hgui +from mercurial import error +import wlrepo + +from wlrepo.mercurial_backend.document import MercurialDocument +from wlrepo.mercurial_backend import MercurialRevision + +class MergeStatus(object): + def __init__(self, mstatus): + self.updated = mstatus[0] + self.merged = mstatus[1] + self.removed = mstatus[2] + self.unresolved = mstatus[3] + + def isclean(self): + return self.unresolved == 0 + +class UpdateStatus(object): + + def __init__(self, mstatus): + self.modified = mstatus[0] + self.added = mstatus[1] + self.removed = mstatus[2] + self.deleted = mstatus[3] + self.untracked = mstatus[4] + self.ignored = mstatus[5] + self.clean = mstatus[6] + + def has_changes(self): + return bool(len(self.modified) + len(self.added) + \ + len(self.removed) + len(self.deleted)) + +class MercurialLibrary(wlrepo.Library): + """Mercurial implementation of the Library API""" + + def __init__(self, path, **kwargs): + super(wlrepo.Library, self).__init__( ** kwargs) + + self._revcache = {} + self._doccache = {} + + self._hgui = hgui.ui() + self._hgui.config('ui', 'quiet', 'true') + self._hgui.config('ui', 'interactive', 'false') + + import os.path + self._ospath = self._sanitize_string(os.path.realpath(path)) + + if os.path.isdir(path): + try: + self._hgrepo = hglrepo.localrepository(self._hgui, path) + except mercurial.error.RepoError: + raise wlrepo.LibraryException("[HGLibrary] Not a valid repository at path '%s'." % path) + elif kwargs.get('create', False): + os.makedirs(path) + try: + self._hgrepo = hglrepo.localrepository(self._hgui, path, create=1) + except mercurial.error.RepoError: + raise wlrepo.LibraryException("[HGLibrary] Can't create a repository on path '%s'." % path) + else: + raise wlrepo.LibraryException("[HGLibrary] Can't open a library on path '%s'." % path) + + + def documents(self): + return [ key[5:] for key in \ + self._hgrepo.branchmap() if key.startswith("$doc:") ] + + @property + def ospath(self): + return self._ospath + + def document_for_rev(self, revision): + if revision is None: + raise ValueError("Revision can't be None.") + + if not isinstance(revision, MercurialRevision): + rev = self.get_revision(revision) + else: + rev = revision + + if not self._doccache.has_key(str(rev)): + self._doccache[str(rev)] = MercurialDocument(self, rev) + + # every revision is a document + return self._doccache[str(rev)] + + def document(self, docid, user=None): + return self.document_for_rev(self.fulldocid(docid, user)) + + def get_revision(self, revid): + ctx = self._changectx(revid) + + if ctx is None: + raise RevisionNotFound(revid) + + if self._revcache.has_key(ctx): + return self._revcache[ctx] + + return MercurialRevision(self, ctx) + + def fulldocid(self, docid, user=None): + fulldocid = '' + if user is not None: + fulldocid += '$user:' + user + fulldocid += '$doc:' + docid + return fulldocid + + + def has_revision(self, revid): + try: + self._hgrepo[revid] + return True + except error.RepoError: + return False + + def document_create(self, docid): + # check if it already exists + fullid = self.fulldocid(docid) + + if self.has_revision(fullid): + raise LibraryException("Document already exists!"); + + # doesn't exist + self._create_branch(fullid) + return self.document_for_rev(fullid) + + # + # Private methods + # + + # + # Locking + # + + def _lock(self, write_mode=False): + return self._hgrepo.wlock() # no support for read/write mode yet + + def _transaction(self, write_mode, action): + lock = self._lock(write_mode) + try: + return action(self) + finally: + lock.release() + + # + # Basic repo manipulation + # + + def _checkout(self, rev, force=True): + return MergeStatus(mercurial.merge.update(self._hgrepo, rev, False, force, None)) + + def _merge(self, rev): + """ Merge the revision into current working directory """ + return MergeStatus(mercurial.merge.update(self._hgrepo, rev, True, False, None)) + + def _common_ancestor(self, revA, revB): + return self._hgrepo[revA].ancestor(self.repo[revB]) + + def _commit(self, message, user=u"library"): + return self._hgrepo.commit(text=message, user=user) + + + def _fileexists(self, fileid): + return (fileid in self._hgrepo[None]) + + def _fileadd(self, fileid): + return self._hgrepo.add([fileid]) + + def _filesadd(self, fileid_list): + return self._hgrepo.add(fileid_list) + + def _filerm(self, fileid): + return self._hgrepo.remove([fileid]) + + def _filesrm(self, fileid_list): + return self._hgrepo.remove(fileid_list) + + def _fileopen(self, path, mode): + return self._hgrepo.wopener(path, mode) + + def _filectx(self, fileid, revid): + return self._hgrepo.filectx(fileid, changeid=revid) + + def _changectx(self, nodeid): + return self._hgrepo.changectx(nodeid) + + # + # BASIC BRANCH routines + # + + def _bname(self, user, docid): + """Returns a branch name for a given document and user.""" + docid = self._sanitize_string(docid) + uname = self._sanitize_string(user) + return "personal_" + uname + "_file_" + docid; + + def _has_branch(self, name): + return self._hgrepo.branchmap().has_key(self._sanitize_string(name)) + + def _branch_tip(self, name): + name = self._sanitize_string(name) + return self._hgrepo.branchtags()[name] + + def _create_branch(self, name, parent=None, before_commit=None): + name = self._sanitize_string(name) + + if self._has_branch(name): return # just exit + + if parent is None: + parentrev = self._hgrepo['$branchbase'].node() + else: + parentrev = parent.hgrev() + + self._checkout(parentrev) + self._hgrepo.dirstate.setbranch(name) + + if before_commit: before_commit(self) + + self._commit("$ADMN$ Initial commit for branch '%s'." % name, user='$library') + + def _switch_to_branch(self, branchname): + current = self._hgrepo[None].branch() + + if current == branchname: + return current # quick exit + + self._checkout(self._branch_tip(branchname)) + return branchname + + # + # Utils + # + + @staticmethod + def _sanitize_string(s): + if isinstance(s, unicode): + s = s.encode('utf-8') + + if ' ' in s: + raise ValueError('Whitespace is forbidden!') + + return s \ No newline at end of file diff --git a/lib/wlrepo/tests/data/clean/$meta b/lib/wlrepo/tests/data/clean/$meta new file mode 100644 index 00000000..e69de29b diff --git a/lib/wlrepo/tests/data/clean/.hg/dirstate b/lib/wlrepo/tests/data/clean/.hg/dirstate index b0aa1e64d7160678a5b8ebfb9e45514b5895d31b..20ad845e81172cc7fbccbdafcd1c583b172e7630 100644 GIT binary patch literal 88 zcmccmRP6QT@I8xsvVIrWO}}kz>n|w9fCc0+Ff=X!iF@t1QVOIv^)k{k)ARC+QV}wH O`kw%0SXFXUOA-Ne{uhn_ literal 130 zcmb1jTb{A&AIr?E;>@Mjj?cSw?dOV93|K%O14H8ykhs_8E;k@0R8X1}UzV7YnG&Ct mnUktlk(-00q*Ds0gi|jgJu^KozbF++rpq2E!vhh9XaxYsUnMaB diff --git a/lib/wlrepo/tests/data/clean/.hg/store/00changelog.i b/lib/wlrepo/tests/data/clean/.hg/store/00changelog.i index 45c1c46177d336ccad272b8c6cf07f3c682a4075..b6c919d52b6cb4ba8328972cb1253fd92bb5945a 100644 GIT binary patch literal 176 zcmZQzWME`~fC3;@3S~3=hk~n5#a>?y-?PXk>vwV8^xM|9{(@34H6XfTj_ff*zQYPU z3f z%l3+1dS!@iNcrBjpX*ODv|oJwB#q~??ZT}E)u$BpJ44eP?&Q=>!}Lgg#MNVsycgXm+pBvQQfmqH1bi?Id;E1{~d`7Vkf0PT(L>h z@#RnH`%7JQ(|5O5hJ9veKizXL>d;Ho4BZ)@cl6z=VvF#;X7%+?=6BPm|1<5GY7`fN ztpz!ffuR|QyTL35i1R_Nm33R5vFjhp%&X$erPq$nyLIj7ic?TEV5(w{>S;&5Lka?{ z7uM};h~B1`Bay(eE$-k}vxduUEn=6$9)Dz=`$V_y-~4sI?{3@}m((G+_}FG8<=$fs zhbnm$<_JAtl=0fIrceLsTBZprmWX;u*BJ$IOk1{e%@>JdQ#x(q6Dxkt`M2@^nVq)x dR|mtkqQ=;^b`$9s!`x1o>cqf4hf&ikA{t?#88 L$IakAL)sAlUlA(1 literal 265 zcmZQzWME`~023f(3}rL?hXN1xn^|f#K@!t0{?*p>uWc(kRlNkJ21J+YWu#}O=j9ir zG9+0Tq@{0V2{o&YfH71pwttR|x1QX%_ literal 85 zcmYdEEJ@VQOwY?NN==DR%gjmD%VaR%N&$%$lqSWOCFW#8#Vc}iz;Xr#xruq1X{p5} aK(3*o8JB@UazLVSAd^!sBRw-cFTW@iU4~U9H?<@Y03`kv4FCWD literal 130 zcmX>*D?aq(G7Fzt-i9s5jTdvvzicRFzycCMV*jB4$P_9lO^Po|%*jlNPs_|n)vL(O j$zxz>Tmn+&wYgIYNO9_Aq-Un*n)ruZ_#X`Er;_rpAaae|J!Z0Sm}uU}#(d68G9OK>Sd&7rsw4sr2=Ib Z82&>6kjV~|DM?H(M%TfrlABtR2mmQ-Ag}-c literal 166 zcmX@}KrDGy@9Kc&^{&f4ig7tfPI;WifCT^r8?y-?PXk>vwV8^xM|9{(@34H6XfTj_ff*zQYPU z3f z%l3+1dS!@iNcrBjpX*ODv|oJwB#q~??ZT}E)u$Bnl!2igh^K*B3=ltnoXqfKRla}lX90yLmmh@B*?iy^_k}R18ZcEc$MnoW zu0sYqY!BvsXNvRw_{cGHQ%-KXI{!ZR>svHR*5&Zk)L6GS_RpW+5^^=)Px^pC#D$5? z;cGZ&^332n`0AL;>KK(E*~IASkE0)UYbV^6=;iX5$M=G{~IzZ2E(>*t-(yiy&r zY4-io`)iJE`THoU;4Cr+W*w W>pJ44eP?&Q=>!}Lgg#MNVsycgXm+pBvQQfmqH1bi?Id;E1{~d`7Vkf0PT(L>h z@#RnH`%7JQ(|5O5hJ9veKizXL>d;Ho4BZ)@cl6z=VvF#;X7%+?=6BPm|1<5GY7`fN ztpz!ffuR|QyTL35i1R_Nm33R5vFjhp%&X$erPq$nyLIj7ic?TEV5(w{>S;&5Lka?{ z7uM};h~B1`Bay(eE$-k}vxduUEn=6$9)Dz=`$V_y-~4sI?{3@}m((G+_}FG8<=$fs zhbnm$<_JAtl=0fIrceLsTBZprmWX;u*BJ$IOk1{e%@>JdQ#x(q6Dxkt`M2@^nVq)x zR|mtkqQ=;^b`$9s!`x1o>cqf4hf&ikA{t?#88 z$IakAL)sB+8pv)2hBP2P17{)!0gqead6{KiP4%~Bj`y8xaBw?c|p6JIdPN))z*NGxD3j zR;>V&&OmY|n8m=r1foH%R55;RHo0celQ*jyW^!y;$@-vcu`E;#i~@x%$am(&iMa(i zsqqCldKI}j3>Fr~hAC#IDM_Y=mX_v8hK7cTCZ>soNlB(@CT597X_i1KW78yaF0eVT z!DJ$koD9UwPz-j0;RW&8NttQocV9GT`ADC6bpOSMtzgwqqGHa})4K(M0mTrI^=!d2 zl{NE^PgK3_Iq`|!hX01l>+5eXkKbp~{ANys&&?SI6%6u+=6O6>%V+L+X4|{t@sb>SBa?WTXMFz6hZ>OpIxEcl literal 442 zcmZQzWME`~023f(3}rL?hXN1xn^|f#K@!t0{?*p>uWc(kRlNkJ21J+YWu#}O=j9ir zG9+0Tq@{0V2{o&YfH71=!?HFj)vBAAwm63`{_p5#*?s97-9I{z^erhG`zsf+EJ( zW(1o-)qtsrIj*N2xtI)j7!J(&ZaAszvPtFHNh#4fAu$53@=xrqPHwm4W8h(^sNdVS zJO6lT-|foR$=fb}HgYuVPSO(dY2{fu%cNLc>5I_L?5kI^qUwGo7QgwgJ?l)t*&8#J ar|exU_&q~W?oDRuMq8(8{1-XYCIA58f0nHP diff --git a/lib/wlrepo/tests/data/simple/.hg/store/data/$meta.i b/lib/wlrepo/tests/data/simple/.hg/store/data/$meta.i new file mode 100644 index 0000000000000000000000000000000000000000..2431023a17b1e7b5c96e5db8e264c251f39beab0 GIT binary patch literal 64 ncmZQzWME{#0{%n64&J91ElOJ*kA4VBT`S_X^HQPrLGn6+WD*P;%#K*02?S1MgRZ+ diff --git a/lib/wlrepo/tests/data/simple/.hg/store/data/pub__polish__file.xml.i b/lib/wlrepo/tests/data/simple/.hg/store/data/pub__polish__file.xml.i deleted file mode 100644 index 3488bccb18f799c89d416b5fca591ba90e6ee85c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 73 zcmZQzWME`~08Svq0cA7&hk^+j6GYdfge+)Z@oKk=!`4GTE3FElYQR*f`;pe->_kN_ E0K(N3$^ZZW diff --git a/lib/wlrepo/tests/data/simple/.hg/store/data/pub__valid__file.xml.i b/lib/wlrepo/tests/data/simple/.hg/store/data/pub__valid__file.xml.i deleted file mode 100644 index fd3c7f7b76f7cc2c3d01256a69093bd8f5817e58..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 152 zcmZQzWME{#1dRWoUQPrLGn6+WD*P;%!XjU=ax*$pe*R0?{BNI;9pE m@u!`cwx7%G&ztUJ8_l}zoPer9r+6H55*2b26|(b761f1Y*(LG- diff --git a/lib/wlrepo/tests/data/clean/.hg/store/data/pub__valid__file.xml.i b/lib/wlrepo/tests/data/simple/.hg/store/data/sample.parts.i similarity index 100% rename from lib/wlrepo/tests/data/clean/.hg/store/data/pub__valid__file.xml.i rename to lib/wlrepo/tests/data/simple/.hg/store/data/sample.parts.i diff --git a/lib/wlrepo/tests/data/simple/.hg/store/data/sample.xml.i b/lib/wlrepo/tests/data/simple/.hg/store/data/sample.xml.i new file mode 100644 index 0000000000000000000000000000000000000000..b115f4d6a1758906cc71810e4f01acc727168502 GIT binary patch literal 77 zcmZQzWME`~0A3))17$P*hXSUK9INyt-MW=IVP04Bx9fz}gnojm0aK-pIf)9ni3-{I HC5c=B-e46M literal 0 HcmV?d00001 diff --git a/lib/wlrepo/tests/data/simple/.hg/store/data/sample__pl.xml.i b/lib/wlrepo/tests/data/simple/.hg/store/data/sample__pl.xml.i new file mode 100644 index 0000000000000000000000000000000000000000..920c5742f9629791a8e8bb72c9d49dd40bc7762d GIT binary patch literal 79 zcmZQzWME`~0Dd6F2W2z;hk_2nYq47;r*9No5+%L$OP2oB+os#0YQR*f`_VnA=|}e* L-h8wvJCO?jQ*#;t literal 0 HcmV?d00001 diff --git a/lib/wlrepo/tests/data/simple/.hg/store/fncache b/lib/wlrepo/tests/data/simple/.hg/store/fncache index 8730267a..c228181f 100644 --- a/lib/wlrepo/tests/data/simple/.hg/store/fncache +++ b/lib/wlrepo/tests/data/simple/.hg/store/fncache @@ -1,4 +1,6 @@ +data/$meta.i data/.hgignore.i -data/ignored_file.i -data/pub_valid_file.xml.i -data/pub_polish_file.xml.i +data/sample.parts.i +data/sample.xml.i +data/sample_pl.xml.i +data/.hgtags.i diff --git a/lib/wlrepo/tests/data/simple/.hg/store/undo b/lib/wlrepo/tests/data/simple/.hg/store/undo index 62ca7e43c419bfee7c1f6abc157924b8650a34d8..3ad8b3279b620f5cbc3057b2b6d10eb99f0b26f6 100644 GIT binary patch literal 52 zcmYdEEJ@VY%SbOtOfS~UWH8_|Fvv~J%S=lxE&*~)jLd-o$r*`x>8UyS=|B-vGZQWV Du}=?# literal 93 zcmYdEEJ@TaC{2nl$j`|v&WKOT%t_U&$j#BqWH8`Lfk~Dn=47TI%bA&Q85ray=4Ga( c7MB3k8kv~_1(Guo^U_mu^3#DL#%5+*00amglK=n! diff --git a/lib/wlrepo/tests/data/simple/.hg/strip-backup/26716f931d95-backup b/lib/wlrepo/tests/data/simple/.hg/strip-backup/26716f931d95-backup new file mode 100644 index 0000000000000000000000000000000000000000..424de921845804ff60f1d4facdde7f2b0d54ca0e GIT binary patch literal 867 zcmV-p1DyOwM=>x$T4*^jL0KkKSu2faxBvhdfB(<K$&&y7|Ml@yI_%v) z>W12qZ`n><{5n7aO(91y2~<|M$}|!noTqs9-0KudU~drG&F3Z z$^oGDJtw4O2c&7~lpaaFDeX@xAZTRMO))YCni(1yG|Qq*S-H>#6|h%&|P?W6ap&LK~E!F+v$UntzorO1egr!-PGmONx_zMU@NkuMAb~dBKT;fRNcS|o(iVP`9 zkg_%2#ha63B5#A)m>4u^|6Hv315#uQSPzHzdkMB}#l9~H8gjqE8SJFcfp`GXfpOZ# z3sY3-$l_v4o+^ZzDQzI-n-@d93@TG-VO*xP6@$++CtqwzLC8(sSxuhHGrp>rQ< zn_db;hd~}@j%>i(1;pwM1x3Dd_}_Sx7_oj3r`Ljdax~`VV>SGvJL^)QV5wiLZK{}S z#bQ=Mt3zIYk#7|pYBxCOK(j`vmw?La#CVn0Gb|x9q`kY}+`q+SmT82(Li@nLwb;)1 tc>VWXDRq>?a4G>yCU6Sq1E3UMEdFP9{|K>&Cr*Ehxgwk>NEODj+yEVTdWrx5 literal 0 HcmV?d00001 diff --git a/lib/wlrepo/tests/data/simple/.hg/undo.dirstate b/lib/wlrepo/tests/data/simple/.hg/undo.dirstate index fb1041a549c5d0289f62fc04475b8dd4faed9138..310d94169efd6c83346d29be1d8fcd225cf795a2 100644 GIT binary patch literal 112 zcmccmRP6QT@I8xsvVIrWO}}kz>n|w9fCc0+Ff=X!iF@stpa7&e^)k{k)ARC+QWHU< Y|DgcLWCzNWB&HXm>tI#MO)W_T0Cd|SLI3~& literal 166 zcmb1jTb{A&AIr?E;>@Mjj?cSw?dOV93|K%O14H8ykhs_8E;k@0R8X1}UzV7YnG&Ct ynUktlk(-08q!g%xQ!gVuGd(ZAC^ZqJ@jny*nZh8=1^GFd#Thtt^FXvhj0XS(AvNLv diff --git a/lib/wlrepo/tests/data/simple/.hgtags b/lib/wlrepo/tests/data/simple/.hgtags new file mode 100644 index 00000000..0b061138 --- /dev/null +++ b/lib/wlrepo/tests/data/simple/.hgtags @@ -0,0 +1 @@ +d5e516ebd357bca24c6afb737e97db3b3d4f111a $branchbase diff --git a/lib/wlrepo/tests/data/simple/pub_polish_file.xml b/lib/wlrepo/tests/data/simple/pub_polish_file.xml deleted file mode 100644 index c7ada58c..00000000 --- a/lib/wlrepo/tests/data/simple/pub_polish_file.xml +++ /dev/null @@ -1 +0,0 @@ -Gąska! diff --git a/lib/wlrepo/tests/data/simple/pub_valid_file.xml b/lib/wlrepo/tests/data/simple/pub_valid_file.xml deleted file mode 100644 index 84321884..00000000 --- a/lib/wlrepo/tests/data/simple/pub_valid_file.xml +++ /dev/null @@ -1 +0,0 @@ -Ala ma kota diff --git a/lib/wlrepo/tests/test_mercurial.py b/lib/wlrepo/tests/test_mercurial.py index 9d37f9fd..09780671 100644 --- a/lib/wlrepo/tests/test_mercurial.py +++ b/lib/wlrepo/tests/test_mercurial.py @@ -6,14 +6,11 @@ __doc__ = "Tests for RAL mercurial backend." from nose.tools import * -import wlrepo from wlrepo import MercurialLibrary -from wlrepo.backend_mercurial import * import os, os.path, tempfile import shutil - REPO_TEMPLATES = os.path.join( os.path.dirname(__file__), 'data') def temprepo(name): @@ -46,191 +43,200 @@ def temprepo(name): def test_opening(library): pass -@temprepo('clean') -def test_main_cabinet(library): - mcab = library.main_cabinet - assert_equal(mcab.maindoc_name, '') - - doclist = mcab.parts() - assert_equal( list(doclist), ['valid_file']) - @temprepo('simple') def test_read_document(library): - doc = library.main_cabinet.retrieve('valid_file') - assert_equal(doc.read().strip(), 'Ala ma kota') + doc = library.document('sample') + assert_equal(doc.data('xml'), 'Ala ma kota\n') @temprepo('simple') def test_read_UTF8_document(library): - doc = library.main_cabinet.retrieve('polish_file') - assert_equal(doc.read().strip(), u'Gąska!'.encode('utf-8')) + doc = library.document('sample_pl') + assert_equal(doc.data('xml'), u'Gżegżółka\n'.encode('utf-8')) @temprepo('simple') -def test_write_document(library): - doc = library.main_cabinet.retrieve('valid_file') - assert_equal(doc.read().strip(), 'Ala ma kota') +def test_change_document(library): + doc = library.document('sample') STRING = u'Gąski lubią pływać!\n'.encode('utf-8') - doc.write(STRING) - assert_equal(doc.read(), STRING) + + def write_action(library, resolve): + f = library._fileopen(resolve('xml'), 'r+') + assert_equal(f.read(), 'Ala ma kota\n') + f.seek(0) + f.write(STRING) + f.flush() + f.seek(0) + assert_equal(f.read(), STRING) + + def commit_info(document): + return ("Document rewrite", "library") + + ndoc = doc.invoke_and_commit(write_action, commit_info) + assert_equal(ndoc.data('xml'), STRING) + @temprepo('simple') def test_create_document(library): - doc = library.main_cabinet.create("another_file", "Some text") - assert_equal( doc.read(), "Some text") - assert_true( os.path.isfile( os.path.join(library.ospath, "pub_another_file.xml")) ) - -@temprepo('branched') -def test_switch_branch(library): - tester_cab = library.cabinet("valid_file", "tester", create=False) - assert_equal( list(tester_cab.parts()), ['valid_file']) - -@raises(wlrepo.CabinetNotFound) -@temprepo('branched') -def test_branch_not_found(library): - tester_cab = library.cabinet("ugh", "tester", create=False) - -@temprepo('branched') -def test_no_branches(library): - n4 = library.shelf(4) - n3 = library.shelf(3) - n2 = library.shelf(2) - n1 = library.shelf(1) - n0 = library.shelf(0) - - assert_true( n3.parentof(n4) ) - assert_false( n4.parentof(n3) ) - assert_true( n0.parentof(n1) ) - assert_false( n1.parentof(n0) ) - assert_false( n0.parentof(n4) ) - -# def test_ancestor_of_simple(self): - assert_true( n3.ancestorof(n4) ) - assert_true( n2.ancestorof(n4) ) - assert_true( n1.ancestorof(n4) ) - assert_true( n0.ancestorof(n4) ) - - assert_true( n2.ancestorof(n3) ) - assert_true( n1.ancestorof(n3) ) - assert_true( n0.ancestorof(n3) ) - - assert_false( n4.ancestorof(n4) ) - assert_false( n4.ancestorof(n3) ) - assert_false( n3.ancestorof(n2) ) - assert_false( n3.ancestorof(n1) ) - assert_false( n3.ancestorof(n0) ) - -# def test_common_ancestor_simple(self): - assert_true( n3.has_common_ancestor(n4) ) - assert_true( n3.has_common_ancestor(n3) ) - assert_true( n3.has_common_ancestor(n3) ) - - -@temprepo('branched2') -def test_once_branched(library): - n7 = library.shelf(7) - n6 = library.shelf(6) - n5 = library.shelf(5) - n4 = library.shelf(4) - n3 = library.shelf(3) - n2 = library.shelf(2) - - assert_true( n2.parentof(n3) ) - assert_false( n3.parentof(n2) ) - - assert_true( n2.parentof(n5) ) - assert_false( n5.parentof(n2) ) - - assert_false( n2.parentof(n4) ) - assert_false( n2.parentof(n6) ) - assert_false( n3.parentof(n5) ) - assert_false( n5.parentof(n3) ) - -# def test_ancestorof_branched(self): - assert_true( n2.ancestorof(n7) ) - assert_false( n7.ancestorof(n2) ) - assert_true( n2.ancestorof(n6) ) - assert_false( n6.ancestorof(n2) ) - assert_true( n2.ancestorof(n5) ) - assert_false( n5.ancestorof(n2) ) - - assert_false( n3.ancestorof(n5) ) - assert_false( n5.ancestorof(n3) ) - assert_false( n4.ancestorof(n5) ) - assert_false( n5.ancestorof(n4) ) - assert_false( n3.ancestorof(n7) ) - assert_false( n7.ancestorof(n3) ) - assert_false( n4.ancestorof(n6) ) - assert_false( n6.ancestorof(n4) ) - -# def test_common_ancestor_branched(self): - assert_true( n2.has_common_ancestor(n4) ) - assert_true( n2.has_common_ancestor(n7) ) - assert_true( n2.has_common_ancestor(n6) ) - - # cause it's not in the right branch - assert_false( n5.has_common_ancestor(n3) ) - assert_false( n7.has_common_ancestor(n4) ) - -@temprepo('merged') -def test_after_merge(library): - n8 = library.shelf(8) - n7 = library.shelf(7) - n6 = library.shelf(6) - - assert_true( n7.parentof(n8) ) - assert_false( n8.parentof(n7) ) - - assert_true( n7.ancestorof(n8) ) - assert_true( n6.ancestorof(n8) ) - - - assert_true( n7.has_common_ancestor(n8) ) - # cause it's not in the right branch - assert_false( n8.has_common_ancestor(n7) ) - -@temprepo('merged_with_local_commit') -def test_after_merge_and_local_commit(library): - n9 = library.shelf(9) - n8 = library.shelf(8) - n7 = library.shelf(7) - n6 = library.shelf(6) - - assert_true( n7.parentof(n8) ) - assert_false( n8.parentof(n7) ) - - assert_true( n9.has_common_ancestor(n8) ) - # cause it's not in the right branch - assert_false( n8.has_common_ancestor(n9) ) - - -@temprepo('branched2') -def test_merge_personal_to_default(library): - main = library.shelf(2) - print main - - local = library.shelf(7) - print local + assert_equal(sorted(library.documents()), sorted(['sample', 'sample_pl'])) - document = library.document("ala", "admin") - shared = document.shared() - assert_true( shared is None ) - document.share("Here is my copy!") - - assert_equal( document.shelf(), local) # local didn't change - - shared = document.shared() - assert_true( shared is not None ) - - print library.shelf() - - new_main = shared.shelf() - assert_not_equal( new_main, main) # main has new revision - - # check for parents - assert_true( main.parentof(new_main) ) - assert_true( local.parentof(new_main) ) - -@temprepo('clean') -def test_create_branch(library): - tester_cab = library.cabinet("anotherone", "tester", create=True) - assert_equal( list(tester_cab.parts()), ['anotherone']) + doc = library.document_create("creation") + doc.quickwrite("xml", "", "Quick write", user="library") + + assert_equal(sorted(library.documents()), sorted(['sample', 'sample_pl', 'creation'])) + +# +#@temprepo('branched') +#def test_switch_branch(library): +# tester_cab = library.cabinet("valid_file", "tester", create=False) +# assert_equal( list(tester_cab.parts()), ['valid_file']) +# +#@raises(wlrepo.CabinetNotFound) +#@temprepo('branched') +#def test_branch_not_found(library): +# tester_cab = library.cabinet("ugh", "tester", create=False) +# +#@temprepo('branched') +#def test_no_branches(library): +# n4 = library.shelf(4) +# n3 = library.shelf(3) +# n2 = library.shelf(2) +# n1 = library.shelf(1) +# n0 = library.shelf(0) +# +# assert_true( n3.parentof(n4) ) +# assert_false( n4.parentof(n3) ) +# assert_true( n0.parentof(n1) ) +# assert_false( n1.parentof(n0) ) +# assert_false( n0.parentof(n4) ) +# +## def test_ancestor_of_simple(self): +# assert_true( n3.ancestorof(n4) ) +# assert_true( n2.ancestorof(n4) ) +# assert_true( n1.ancestorof(n4) ) +# assert_true( n0.ancestorof(n4) ) +# +# assert_true( n2.ancestorof(n3) ) +# assert_true( n1.ancestorof(n3) ) +# assert_true( n0.ancestorof(n3) ) +# +# assert_false( n4.ancestorof(n4) ) +# assert_false( n4.ancestorof(n3) ) +# assert_false( n3.ancestorof(n2) ) +# assert_false( n3.ancestorof(n1) ) +# assert_false( n3.ancestorof(n0) ) +# +## def test_common_ancestor_simple(self): +# assert_true( n3.has_common_ancestor(n4) ) +# assert_true( n3.has_common_ancestor(n3) ) +# assert_true( n3.has_common_ancestor(n3) ) +# +# +#@temprepo('branched2') +#def test_once_branched(library): +# n7 = library.shelf(7) +# n6 = library.shelf(6) +# n5 = library.shelf(5) +# n4 = library.shelf(4) +# n3 = library.shelf(3) +# n2 = library.shelf(2) +# +# assert_true( n2.parentof(n3) ) +# assert_false( n3.parentof(n2) ) +# +# assert_true( n2.parentof(n5) ) +# assert_false( n5.parentof(n2) ) +# +# assert_false( n2.parentof(n4) ) +# assert_false( n2.parentof(n6) ) +# assert_false( n3.parentof(n5) ) +# assert_false( n5.parentof(n3) ) +# +## def test_ancestorof_branched(self): +# assert_true( n2.ancestorof(n7) ) +# assert_false( n7.ancestorof(n2) ) +# assert_true( n2.ancestorof(n6) ) +# assert_false( n6.ancestorof(n2) ) +# assert_true( n2.ancestorof(n5) ) +# assert_false( n5.ancestorof(n2) ) +# +# assert_false( n3.ancestorof(n5) ) +# assert_false( n5.ancestorof(n3) ) +# assert_false( n4.ancestorof(n5) ) +# assert_false( n5.ancestorof(n4) ) +# assert_false( n3.ancestorof(n7) ) +# assert_false( n7.ancestorof(n3) ) +# assert_false( n4.ancestorof(n6) ) +# assert_false( n6.ancestorof(n4) ) +# +## def test_common_ancestor_branched(self): +# assert_true( n2.has_common_ancestor(n4) ) +# assert_true( n2.has_common_ancestor(n7) ) +# assert_true( n2.has_common_ancestor(n6) ) +# +# # cause it's not in the right branch +# assert_false( n5.has_common_ancestor(n3) ) +# assert_false( n7.has_common_ancestor(n4) ) +# +#@temprepo('merged') +#def test_after_merge(library): +# n8 = library.shelf(8) +# n7 = library.shelf(7) +# n6 = library.shelf(6) +# +# assert_true( n7.parentof(n8) ) +# assert_false( n8.parentof(n7) ) +# +# assert_true( n7.ancestorof(n8) ) +# assert_true( n6.ancestorof(n8) ) +# +# +# assert_true( n7.has_common_ancestor(n8) ) +# # cause it's not in the right branch +# assert_false( n8.has_common_ancestor(n7) ) +# +#@temprepo('merged_with_local_commit') +#def test_after_merge_and_local_commit(library): +# n9 = library.shelf(9) +# n8 = library.shelf(8) +# n7 = library.shelf(7) +# n6 = library.shelf(6) +# +# assert_true( n7.parentof(n8) ) +# assert_false( n8.parentof(n7) ) +# +# assert_true( n9.has_common_ancestor(n8) ) +# # cause it's not in the right branch +# assert_false( n8.has_common_ancestor(n9) ) +# +# +#@temprepo('branched2') +#def test_merge_personal_to_default(library): +# main = library.shelf(2) +# print main +# +# local = library.shelf(7) +# print local +# +# document = library.document("ala", "admin") +# shared = document.shared() +# assert_true( shared is None ) +# document.share("Here is my copy!") +# +# assert_equal( document.shelf(), local) # local didn't change +# +# shared = document.shared() +# assert_true( shared is not None ) +# +# print library.shelf() +# +# new_main = shared.shelf() +# assert_not_equal( new_main, main) # main has new revision +# +# # check for parents +# assert_true( main.parentof(new_main) ) +# assert_true( local.parentof(new_main) ) +# +#@temprepo('clean') +#def test_create_branch(library): +# tester_cab = library.cabinet("anotherone", "tester", create=True) +# assert_equal( list(tester_cab.parts()), ['anotherone']) diff --git a/project/settings.py b/project/settings.py index 0e9ba8d8..1a064762 100644 --- a/project/settings.py +++ b/project/settings.py @@ -82,7 +82,7 @@ MIDDLEWARE_CLASSES = ( ROOT_URLCONF = 'urls' TEMPLATE_DIRS = ( - PROJECT_ROOT + '/templates' + PROJECT_ROOT + '/templates', ) # CSS and JS files to compress diff --git a/project/templates/manager/pull_request.html b/project/templates/manager/pull_request.html new file mode 100644 index 00000000..c03caab3 --- /dev/null +++ b/project/templates/manager/pull_request.html @@ -0,0 +1,7 @@ +{% if objects %} + {% for pullreq in objects %} +

{{ pullreq }}

+ {% endfor %} +{% else %} +

Brak żądań

+{% endif %} diff --git a/project/templates/toolbar_api/scriptlets.js b/project/templates/toolbar_api/scriptlets.js new file mode 100644 index 00000000..ae7e2df4 --- /dev/null +++ b/project/templates/toolbar_api/scriptlets.js @@ -0,0 +1,15 @@ +function SciptletCenter() { + + this.scriptlets = { + {% for scriptlet in scriptlets %} + "{{scriptlet.name}}": function(context, params) { + {{scriptlet.code|safe}} + }, + {% endfor %} + + _none: null + }; + +} + +scriptletCenter = new ScriptletCenter(); \ No newline at end of file diff --git a/project/templates/wysiwyg.html b/project/templates/wysiwyg.html new file mode 100644 index 00000000..409e4f25 --- /dev/null +++ b/project/templates/wysiwyg.html @@ -0,0 +1,92 @@ +{% extends 'base.html' %} + +{% block extrahead %} + +{% endblock %} + +{% block maincontent %} +

Wysiwyg editor

+
This part is not editable!
+
+ +

+

Lorem ipsum dolor sit amet, consectetur adipiscing elit. + Suspendisse a urna eu enim rutrum elementum nec sed nibh. Quisque sed tortor + nulla, et euismod turpis. Morbi purus nulla, vulputate in vulputate id, gravida + id eros. In interdum est tempor est consequat imperdiet. Vivamus vitae ligula quam. + Proin nibh quam, tincidunt sit amet auctor eget, laoreet sit amet eros. Cras augue + lectus, euismod nec posuere ac, ultricies sed magna. Aliquam a lacinia sapien. + Cras imperdiet urna vel dui accumsan mollis. Suspendisse convallis tincidunt ornare. + Aenean convallis libero in lectus dictum vestibulum interdum ipsum suscipit. + Suspendisse sed justo sapien, eu egestas libero. Sed tincidunt sagittis sollicitudin. + Aliquam erat volutpat. Nullam egestas dolor id massa sagittis at sagittis ipsum + hendrerit. +

+ +

Phasellus sed purus non orci eleifend posuere ac eu elit. Etiam orci justo, porta vitae varius in, scelerisque sed metus. Phasellus faucibus lorem at metus scelerisque sit amet sollicitudin dolor dignissim. Aliquam eu justo in diam blandit posuere at a diam. Pellentesque tristique sem eu odio gravida eleifend. Phasellus cursus adipiscing metus, nec pharetra enim pharetra ac. Pellentesque faucibus volutpat lorem nec vulputate. Mauris in faucibus ipsum. Nulla ut urna nulla. Sed at tellus nec diam posuere porttitor. Duis faucibus, libero nec rhoncus facilisis, tortor ligula adipiscing massa, nec varius justo ante et magna. Donec orci mauris, ultrices nec blandit vel, lacinia in ante. Maecenas libero mi, pretium id ultricies eget, fringilla sit amet risus. Integer ut ante sem, et condimentum odio. Nam nec est erat. Etiam ut metus ligula. In vel condimentum orci.

+ +

Suspendisse potenti. Proin in augue nibh. Curabitur in sollicitudin ipsum. In ut leo vel purus volutpat tempus. Proin ut neque at augue euismod ullamcorper nec ac dui. Vestibulum id quam nunc, eu porta augue. Pellentesque interdum neque eu nulla rhoncus vulputate. Sed viverra diam ac sem consectetur semper. Quisque consectetur fringilla quam, in feugiat nisl vulputate quis. Fusce vel ipsum lectus, eu interdum nunc. Donec luctus libero vitae mauris imperdiet at iaculis magna aliquet. Curabitur ullamcorper, diam nec pulvinar venenatis, nibh ante volutpat mauris, nec tristique lectus sem in urna. Aenean eu malesuada metus. Integer auctor nulla sit amet ligula sollicitudin ut accumsan velit ullamcorper. Donec nec auctor augue.

+ +

Maecenas eget lacus vitae velit tincidunt bibendum quis et diam. In ullamcorper condimentum velit, et elementum felis vestibulum facilisis. Donec vitae cursus ipsum. Cras accumsan tincidunt aliquet. Nulla pellentesque mattis magna aliquet hendrerit. Pellentesque pellentesque odio enim. Duis viverra rhoncus tristique. In in risus ligula. Nullam dapibus lacinia facilisis. Ut eu neque neque, tristique laoreet nisl. Aliquam placerat dignissim leo, tristique tempor est vestibulum ut.

+ +

Donec semper tempus ante, eget gravida erat varius et. Suspendisse aliquam rutrum nunc ac pulvinar. Aliquam erat volutpat. Nulla consectetur ultricies imperdiet. Nulla tincidunt est vitae augue porttitor a faucibus odio facilisis. In nec nisl odio. Aliquam et libero tortor, eu tincidunt mi. Vivamus suscipit erat sed mi hendrerit fringilla. Integer iaculis tempus nulla, at egestas velit faucibus ut. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Vestibulum vel massa enim. Aliquam erat volutpat. In ligula tortor, fermentum eu suscipit at, posuere vel nunc. Nullam nibh magna, sollicitudin at semper et, mattis ut quam. Curabitur accumsan semper elit ac posuere. Sed sit amet lorem tortor, vel porttitor justo. Fusce odio metus, bibendum ut bibendum sit amet, luctus a ipsum.

+
+{% endblock %} + +{% block extrabody %} + +{% endblock %} \ No newline at end of file -- 2.20.1