Głupi git!
authorŁukasz Rekucki <lrekucki@gmail.com>
Mon, 21 Sep 2009 09:25:11 +0000 (11:25 +0200)
committerŁukasz Rekucki <lrekucki@gmail.com>
Mon, 21 Sep 2009 09:25:11 +0000 (11:25 +0200)
.gitignore
apps/api/tests.py [deleted file]
apps/toolbar/fixtures/przyciski.xml
lib/wlrepo/__init__.py
lib/wlrepo/backend_mercurial.py
project/settings.py
project/static/js/editor.js
project/urls.py

index 106ca70..c91e29e 100644 (file)
@@ -7,3 +7,4 @@ media
 files
 nbproject
 nbproject/*
 files
 nbproject
 nbproject/*
+.coverage
diff --git a/apps/api/tests.py b/apps/api/tests.py
deleted file mode 100644 (file)
index 2247054..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-"""
-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
-"""}
-
index e2aa914..2c4fdc0 100755 (executable)
       <object pk="23"/>
     </field>
   </object>
       <object pk="23"/>
     </field>
   </object>
+  <object pk="90" model="toolbar.button">
+    <field type="CharField" name="label">Wyszukaj</field>
+    <field type="SlugField" name="slug">wyszukaj</field>
+    <field type="TextField" name="params">["#find-dialog"]</field>
+    <field to="toolbar.scriptlet" name="scriptlet" rel="ManyToOneRel">show_dialog</field>
+    <field type="CharField" name="link"/>
+    <field type="CharField" name="key">f</field>
+    <field type="PositiveIntegerField" name="key_mod">2</field>
+    <field type="CharField" name="tooltip"/>
+    <field to="toolbar.buttongroup" name="group" rel="ManyToManyRel">
+      <object pk="23"/>
+    </field>
+  </object>
   <object pk="2" model="toolbar.button">
     <field type="CharField" name="label">Zamień dywiz</field>
     <field type="SlugField" name="slug">zamien_dywiz</field>
   <object pk="2" model="toolbar.button">
     <field type="CharField" name="label">Zamień dywiz</field>
     <field type="SlugField" name="slug">zamien_dywiz</field>
@@ -1239,4 +1252,7 @@ $('#split-dialog').jqmShow({
 
 }) ;</field>
   </object>
 
 }) ;</field>
   </object>
+  <object pk="show_dialog" model="toolbar.scriptlet">
+    <field type="TextField" name="code">$(params[0]).jqmShow({editor: editor, panel: panel, params: params});</field>
+  </object>
 </django-objects>
 </django-objects>
index 5c27dc9..606f2d4 100644 (file)
@@ -44,6 +44,10 @@ class Cabinet(object):
         else:
             raise ValueError("You must provide either name or doc and user.")
 
         else:
             raise ValueError("You must provide either name or doc and user.")
 
+
+    def __str__(self):
+        return "Cabinet(%s)" % self._name
+
     def documents(self):
         """Lists all documents and sub-documents in this cabinet."""
         pass
     def documents(self):
         """Lists all documents and sub-documents in this cabinet."""
         pass
@@ -57,14 +61,13 @@ class Cabinet(object):
         as the name for the main document"""
         pass
 
         as the name for the main document"""
         pass
 
-    def create(self, name):
+    def create(self, name, initial_data=''):
         """Create a new sub-document in the cabinet with the given name."""
         pass
     
     def maindoc_name(self):
         return self._maindoc
 
         """Create a new sub-document in the cabinet with the given name."""
         pass
     
     def maindoc_name(self):
         return self._maindoc
 
-
     @property
     def library(self):
         return self._library
     @property
     def library(self):
         return self._library
@@ -73,6 +76,9 @@ class Cabinet(object):
     def name(self):
         return self._name
 
     def name(self):
         return self._name
 
+    def shelf(self, selector=None):
+        pass
+
 class Document(object):
     def __init__(self, cabinet, name):
         self._cabinet = cabinet
 class Document(object):
     def __init__(self, cabinet, name):
         self._cabinet = cabinet
@@ -92,7 +98,28 @@ class Document(object):
     def library(self):
         return self._cabinet.library
 
     def library(self):
         return self._cabinet.library
 
+    @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()
+
+
+class Shelf(object):
+
+    def __init__(self, cabinet):
+        self._cabinet = cabinet
+        
+    
 #
 # Exception classes
 #
 #
 # Exception classes
 #
@@ -104,6 +131,8 @@ class LibraryException(Exception):
         self.cause = cause
 
 class CabinetNotFound(LibraryException):
         self.cause = cause
 
 class CabinetNotFound(LibraryException):
+    def __init__(self, cabname):
+        LibraryException.__init__(self, "Cabinet '%s' not found." % cabname)
     pass
 
 
     pass
 
 
index 38f01da..1271122 100644 (file)
@@ -1,4 +1,5 @@
 # -*- encoding: utf-8 -*-
 # -*- encoding: utf-8 -*-
+
 __author__ = "Łukasz Rekucki"
 __date__ = "$2009-09-18 10:49:24$"
 
 __author__ = "Łukasz Rekucki"
 __date__ = "$2009-09-18 10:49:24$"
 
@@ -7,6 +8,7 @@ __doc__ = """RAL implementation over Mercurial"""
 import mercurial
 from mercurial import localrepo as hglrepo
 from mercurial import ui as hgui
 import mercurial
 from mercurial import localrepo as hglrepo
 from mercurial import ui as hgui
+from mercurial.node import hex as to_hex
 import re
 import wlrepo
 
 import re
 import wlrepo
 
@@ -36,8 +38,8 @@ class MercurialLibrary(wlrepo.Library):
             try:
                 self._hgrepo = hglrepo.localrepository(self._hgui, path)
             except mercurial.error.RepoError:
             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['create']:
+                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)
             os.makedirs(path)
             try:
                 self._hgrepo = hglrepo.localrepository(self._hgui, path, create=1)
@@ -62,6 +64,9 @@ class MercurialLibrary(wlrepo.Library):
     def main_cabinet(self):
         return self._maincab
 
     def main_cabinet(self):
         return self._maincab
 
+    def document(self, docid, user):
+        return self.cabinet(docid, user, create=False).retrieve()
+
     def cabinet(self, docid, user, create=False):
         bname = self._bname(user, docid)
 
     def cabinet(self, docid, user, create=False):
         bname = self._bname(user, docid)
 
@@ -71,23 +76,20 @@ class MercurialLibrary(wlrepo.Library):
                 return MercurialCabinet(self, bname, doc=docid, user=user)
 
             if not create:
                 return MercurialCabinet(self, bname, doc=docid, user=user)
 
             if not create:
-                raise wlrepo.CabinetNotFound(docid, user)
+                raise wlrepo.CabinetNotFound(bname)
 
             # check if the docid exists in the main cabinet
 
             # check if the docid exists in the main cabinet
-            needs_touch = not self._maincab.exists(docid)
-            print "Creating branch: ", needs_touch
+            needs_touch = not self._maincab.exists(docid)            
             cab = MercurialCabinet(self, bname, doc=docid, user=user)
 
             cab = MercurialCabinet(self, bname, doc=docid, user=user)
 
-            fileid = cab._fileid(None)
+            name, fileid = cab._filename(None)
 
             def cleanup_action(l):
 
             def cleanup_action(l):
-                if needs_touch:
-                    print "Touch for file", docid
+                if needs_touch:                    
                     l._fileopener()(fileid, "w").write('')
                     l._fileadd(fileid)
                 
                     l._fileopener()(fileid, "w").write('')
                     l._fileadd(fileid)
                 
-                garbage = [fid for (fid, did) in l._filelist() if not did.startswith(docid)]
-                print "Garbage: ", garbage
+                garbage = [fid for (fid, did) in l._filelist() if not did.startswith(docid)]                
                 l._filesrm(garbage)
 
             # create the branch
                 l._filesrm(garbage)
 
             # create the branch
@@ -128,10 +130,8 @@ class MercurialLibrary(wlrepo.Library):
     def _common_ancestor(self, revA, revB):
         return self._hgrepo[revA].ancestor(self.repo[revB])
 
     def _common_ancestor(self, revA, revB):
         return self._hgrepo[revA].ancestor(self.repo[revB])
 
-    def _commit(self, message, user="library"):
-        return self._hgrepo.commit(\
-                                   text=self._sanitize_string(message), \
-                                   user=self._sanitize_string(user))
+    def _commit(self, message, user=u"library"):
+        return self._hgrepo.commit(text=message, user=user)
 
 
     def _fileexists(self, fileid):
 
 
     def _fileexists(self, fileid):
@@ -158,6 +158,9 @@ class MercurialLibrary(wlrepo.Library):
 
     def _fileopener(self):
         return self._hgrepo.wopener
 
     def _fileopener(self):
         return self._hgrepo.wopener
+
+    def _filectx(self, fileid, branchid):
+        return self._hgrepo.filectx(fileid, changeid=branchid)
     
     #
     # BASIC BRANCH routines
     
     #
     # BASIC BRANCH routines
@@ -191,7 +194,6 @@ class MercurialLibrary(wlrepo.Library):
 
         if before_commit: before_commit(self)
 
 
         if before_commit: before_commit(self)
 
-        print "commiting"
         self._commit("[AUTO] Initial commit for branch '%s'." % name, user='library')
         
         # revert back to main
         self._commit("[AUTO] Initial commit for branch '%s'." % name, user='library')
         
         # revert back to main
@@ -218,11 +220,10 @@ class MercurialLibrary(wlrepo.Library):
     #
 
     @staticmethod
     #
 
     @staticmethod
-    def _sanitize_string(s):
-        if isinstance(s, unicode): #
-            return s.encode('utf-8')
-        else: # it's a string, so we have no idea what encoding it is
-            return s
+    def _sanitize_string(s):        
+        if isinstance(s, unicode):
+            s = s.encode('utf-8')
+        return s
 
 class MercurialCabinet(wlrepo.Cabinet):
     
 
 class MercurialCabinet(wlrepo.Cabinet):
     
@@ -234,19 +235,25 @@ class MercurialCabinet(wlrepo.Cabinet):
             
         self._branchname = branchname
 
             
         self._branchname = branchname
 
+    def shelf(self, selector=None):
+        if selector is not None:
+            raise NotImplementedException()
+
+        return MercurialShelf(self, self._hgtip())
+
     def documents(self):        
     def documents(self):        
-        return self._execute_in_branch(action=lambda l, c: ( e[1] for e in l._filelist()) )
+        return self._execute_in_branch(action=lambda l, c: (e[1] for e in l._filelist()))
 
 
-    def retrieve(self, part=None, shelve=None):
-        fileid = self._fileid(part)
+    def retrieve(self, part=None, shelf=None):
+        name, fileid = self._filename(part)
 
         if fileid is None:
             raise wlrepo.LibraryException("Can't retrieve main document from main cabinet.")
                 
 
         if fileid is None:
             raise wlrepo.LibraryException("Can't retrieve main document from main cabinet.")
                 
-        return self._execute_in_branch(lambda l, c: MercurialDocument(c, fileid))
+        return self._execute_in_branch(lambda l, c: MercurialDocument(c, name, fileid))
 
 
-    def create(self, name, initial_data=''):
-        fileid = self._fileid(name)
+    def create(self, name, initial_data):
+        name, fileid = self._filename(name)
 
         if name is None:
             raise ValueError("Can't create main doc for maincabinet.")
 
         if name is None:
             raise ValueError("Can't create main doc for maincabinet.")
@@ -257,18 +264,18 @@ class MercurialCabinet(wlrepo.Cabinet):
 
             fd = l._fileopener()(fileid, "w")
             fd.write(initial_data)
 
             fd = l._fileopener()(fileid, "w")
             fd.write(initial_data)
-            l._fileadd(fileid)
-            l._commit("File '%d' created.")
-
-            return MercurialDocument(c, fileid)
+            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)
 
 
         return self._execute_in_branch(create_action)
 
-    def exists(self, part=None, shelve=None):
-        fileid = self._fileid(part)
+    def exists(self, part=None, shelf=None):
+        name, filepath = self._filename(part)
 
 
-        if fileid is None: return false
-        return self._execute_in_branch(lambda l, c: l._fileexists(fileid))
+        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):
     
     def _execute_in_branch(self, action, write=False):
         def switch_action(library):
@@ -280,16 +287,17 @@ class MercurialCabinet(wlrepo.Cabinet):
 
         return self._library._transaction(write_mode=write, action=switch_action)
 
 
         return self._library._transaction(write_mode=write, action=switch_action)
 
-    def _fileid(self, part):
+    def _filename(self, part):
+        part = self._library._sanitize_string(part)
         fileid = None
 
         if self._maindoc == '':
         fileid = None
 
         if self._maindoc == '':
-            if part is None: return None              
+            if part is None: return [None, None]
             fileid = part
         else:
             fileid = self._maindoc + (('$' + part) if part else '')
 
             fileid = part
         else:
             fileid = self._maindoc + (('$' + part) if part else '')
 
-        return 'pub_' + fileid + '.xml'        
+        return fileid, 'pub_' + fileid + '.xml'
 
     def _fileopener(self):
         return self._library._fileopener()
 
     def _fileopener(self):
         return self._library._fileopener()
@@ -297,17 +305,143 @@ class MercurialCabinet(wlrepo.Cabinet):
     def _hgtip(self):
         return self._library._branch_tip(self._branchname)
 
     def _hgtip(self):
         return self._library._branch_tip(self._branchname)
 
+    def _filectx(self, fileid):
+        return self._library._filectx(fileid, self._branchname)
+
 class MercurialDocument(wlrepo.Document):
 
 class MercurialDocument(wlrepo.Document):
 
-    def __init__(self, cabinet, fileid):
-        super(MercurialDocument, self).__init__(cabinet, fileid)
-        self._opener = self._cabinet._fileopener()        
+    def __init__(self, cabinet, name, fileid):
+        super(MercurialDocument, self).__init__(cabinet, name=name)
+        self._opener = self._cabinet._fileopener()
+        self._fileid = fileid
+        self._refresh()
+
+    def _refresh(self):
+        self._filectx = self._cabinet._filectx(self._fileid)
+        self._shelf = MercurialShelf(self, self._filectx.node())
 
     def read(self):
 
     def read(self):
-        return self._opener(self._name, "r").read()
+        return self._opener(self._filectx.path(), "r").read()
 
     def write(self, data):
 
     def write(self, data):
-        return self._opener(self._name, "w").write(data)
+        return self._opener(self._filectx.path(), "w").write(data)
+
+    def commit(self, message, user):
+        self.library._fileadd(self._fileid)
+        self.library._commit(self._fileid, message, user)
+
+    def update(self):
+        if self._cabinet.is_main():
+            return True # always up-to-date
+
+        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)
+
+        return rc.ALL_OK
+
+    def share(self, message, user):
+        if self._cabinet.is_main():
+            return True # always shared
+
+        main = self.shared_version()
+        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):
+            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 main.has_common_ancestor(local):
+            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):
+            if not local.parentof(main):
+                local.merge_with(main, user=user, message='Local branch update.')
+                no_changes = False
+        else:
+            local.merge_with(main, user=user, message='Local branch update.')
+
+            self._refresh()
+            local = self.shelf()
+
+            main.merge_with(local, user=user, message=message)
+               
+    def shared(self):
+        return self.library.document(self._fileid)
+
+    @property
+    def size(self):
+        return self._filectx.size()
+
+    
+    def shelf(self):
+        return self._shelf
+
+    @property
+    def last_modified(self):
+        return self._filectx.date()
+
+    def __str__(self):
+        return u"Document(%s->%s)" % (self._cabinet.name, self._name)
+
+
+class MercurialShelf(wlrepo.Shelf):
+
+    def __init__(self, cabinet, revision):
+        super(MercurialShelf, self).__init__(cabinet)
+        self._revision = revision
+
+    @property
+    def _rev(self):
+        return _revision
+
+    def __str__(self):
+        return to_hex(self._revision)
 
 
 class MergeStatus(object):
 
 
 class MergeStatus(object):
@@ -335,5 +469,4 @@ class UpdateStatus(object):
         return bool(len(self.modified) + len(self.added) + \
                     len(self.removed) + len(self.deleted))
 
         return bool(len(self.modified) + len(self.added) + \
                     len(self.removed) + len(self.deleted))
 
-
-__all__ = ["MercurialLibrary", "MercurialCabinet", "MercurialDocument"]
\ No newline at end of file
+__all__ = ["MercurialLibrary"]
\ No newline at end of file
index b2c7f85..178a104 100644 (file)
@@ -113,6 +113,7 @@ INSTALLED_APPS = (
     
     'explorer',
     'toolbar',
     
     'explorer',
     'toolbar',
+    'api',
 )
 
 
 )
 
 
index 7951ee7..0cbb934 100644 (file)
@@ -253,7 +253,9 @@ Panel.prototype.isHotkey = function(event) {
     if(event.ctrlKey) code = code | 0x200;
     if(event.shiftKey) code = code | 0x400;
 
     if(event.ctrlKey) code = code | 0x200;
     if(event.shiftKey) code = code | 0x400;
 
-    if(this.hotkeys[code] !== null) {
+    $.log(event.character, this.hotkeys[code]);
+
+    if(this.hotkeys[code]) {
         return true;
     }
     return false;
         return true;
     }
     return false;
@@ -301,6 +303,10 @@ Editor.prototype.loadConfig = function() {
     
     this.fileOptions = this.options;
     var self = this;
     
     this.fileOptions = this.options;
     var self = this;
+
+    if(!this.options.recentFiles)
+        this.options.recentFiles = [];
+
     $.each(this.options.recentFiles, function(index) {
         if (fileId == self.options.recentFiles[index].fileId) {
             $.log('Found options for', fileId);
     $.each(this.options.recentFiles, function(index) {
         if (fileId == self.options.recentFiles[index].fileId) {
             $.log('Found options for', fileId);
index ae7a636..a9fad54 100644 (file)
@@ -40,6 +40,9 @@ urlpatterns = patterns('',
     # Authorization
     url(r'^accounts/login/$', 'django.contrib.auth.views.login', {'redirect_field_name': 'next'}),
     url(r'^accounts/logout/$', 'django.contrib.auth.views.logout', {'next_page': '/'}),
     # Authorization
     url(r'^accounts/login/$', 'django.contrib.auth.views.login', {'redirect_field_name': 'next'}),
     url(r'^accounts/logout/$', 'django.contrib.auth.views.logout', {'next_page': '/'}),
+
+    # Our uber-restful api
+    url(r'^api/', include('api.urls') ),
 )
 
 
 )