Merge lp:~urbanape/bindwood/work-with-folders into lp:bindwood
- work-with-folders
- Merge into trunk
Status: | Superseded |
---|---|
Proposed branch: | lp:~urbanape/bindwood/work-with-folders |
Merge into: | lp:bindwood |
Diff against target: | None lines |
To merge this branch: | bzr merge lp:~urbanape/bindwood/work-with-folders |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Ubuntu One hackers | Pending | ||
Review via email: mp+12078@code.launchpad.net |
This proposal has been superseded by a proposal from 2009-09-18.
Commit message
Description of the change
Zachery Bir (urbanape) wrote : | # |
Zachery Bir (urbanape) wrote : | # |
> * If you use multiple profiles, you'll be able to sync each of
> them, without collisions between profiles. There are
> additional views registered for each profile that will show
> you only the bookmarks per profile.
Actually, this last part is a lie. I was manually creating these views.
They'll show up automatically in a later branch.
Zachery Bir (urbanape) wrote : | # |
> > * If you use multiple profiles, you'll be able to sync each of
> > them, without collisions between profiles. There are
> > additional views registered for each profile that will show
> > you only the bookmarks per profile.
>
> Actually, this last part is a lie. I was manually creating these views.
> They'll show up automatically in a later branch.
Actually this last part is a lie, and the first part is the truth. I've just pushed the requisite bits that create per-profile views, so the user has something a little more in-line with their expectations.
- 31. By Zachery Bir
-
Create per-profile views with just that profile's bookmarks, and rename the default two
- 32. By Zachery Bir
-
s/itemId/aItemId/ and take an anti-stupid pill for next time
Unmerged revisions
Preview Diff
1 | === modified file 'content/sync.js' |
2 | --- content/sync.js 2009-09-15 17:35:12 +0000 |
3 | +++ content/sync.js 2009-09-18 16:16:41 +0000 |
4 | @@ -30,8 +30,8 @@ |
5 | .getService(Ci.nsIIOService), |
6 | envService: Cc["@mozilla.org/process/environment;1"] |
7 | .getService(Ci.nsIEnvironment), |
8 | - profileService: Cc["@mozilla.org/toolkit/profile-service;1"] |
9 | - .getService(Ci.nsIToolkitProfileService), |
10 | + directoryService: Cc["@mozilla.org/file/directory_service;1"] |
11 | + .getService(Ci.nsIProperties), |
12 | windowService: Cc["@mozilla.org/appshell/window-mediator;1"] |
13 | .getService(Ci.nsIWindowMediator), |
14 | |
15 | @@ -52,20 +52,37 @@ |
16 | Bindwood.consoleService.logStringMessage("Bindwood: " + aMessage + " message: '" + e.message + "', reason: '" + e.reason + "', description: '" + e.description + "', error: '" + e.error + "'"); |
17 | }, |
18 | |
19 | + extractProfileName: function(path) { |
20 | + // We want the last part of the profile path |
21 | + // ('default' for '/home/zbir/.mozilla/firefox/ixlw0nvl.default') |
22 | + // For profiles that have not been created via the Profile Manager, |
23 | + // we just take the last path segment as the profile name. |
24 | + // |
25 | + // Actually, there's a degenerate case, where the last segment |
26 | + // doesn't have the Firefox-provided random string: |
27 | + // '/home/zbir/canonical.com' => 'com' |
28 | + // But as I said, this is maybe degenerate. |
29 | + |
30 | + var segments = path.split('/'); |
31 | + var possible_profile = segments[segments.length - 1]; |
32 | + var first_period = possible_profile.indexOf('.'); |
33 | + if (first_period == -1) { |
34 | + return possible_profile; // no periods in the last segment, return as is |
35 | + } else { |
36 | + return possible_profile.substr(first_period + 1); |
37 | + } |
38 | + }, |
39 | + |
40 | // Setup the environment and go |
41 | init: function() { |
42 | // Start the process and de-register ourself |
43 | // http://forums.mozillazine.org/viewtopic.php?f=19&t=657911&start=0 |
44 | // It ensures that we're only running that code on the first window. |
45 | |
46 | - Bindwood.currentProfile = Bindwood.profileService.selectedProfile.name; |
47 | + Bindwood.currentProfile = Bindwood.extractProfileName(Bindwood.directoryService.get('ProfD', Ci.nsIFile).path); |
48 | |
49 | - if (Bindwood.currentProfile == 'default') { // We only currently operate on the 'default' profile |
50 | - if(Bindwood.windowService.getEnumerator("").getNext() == window) { |
51 | - Bindwood.getCouchEnvironment(Bindwood.startProcess); |
52 | - } |
53 | - } else { |
54 | - Bindwood.writeError("Bindwood currently only supports the default profile.", undefined); |
55 | + if(Bindwood.windowService.getEnumerator("").getNext() == window) { |
56 | + Bindwood.getCouchEnvironment(Bindwood.startProcess); |
57 | } |
58 | }, |
59 | |
60 | @@ -178,48 +195,65 @@ |
61 | } catch(e) { |
62 | Bindwood.writeError("Error when calling pushBookmarks: ", e); |
63 | } |
64 | - Bindwood.createView(); |
65 | + Bindwood.createViews(); |
66 | Bindwood.pullBookmarks(); |
67 | }, |
68 | |
69 | - createView: function() { |
70 | - var DDID = "_design/views"; |
71 | - var current_doc; |
72 | - try { |
73 | - current_doc = Bindwood.couch.open(DDID); |
74 | - if (current_doc !== null) { |
75 | - Bindwood.writeMessage("View already exists; leaving it alone"); |
76 | - } else { |
77 | - new_doc = { |
78 | - _id: DDID, |
79 | - views: { |
80 | - display: { |
81 | - map: "function(doc) { " + |
82 | + createViews: function() { |
83 | + var views = [{ id: "_design/views", |
84 | + map: "function(doc) { " + |
85 | "var scheme = doc.uri.split(':',1)[0]; " + |
86 | "var uri; " + |
87 | "if (scheme == 'http' || scheme == 'https') {" + |
88 | - "uri = doc.uri.split('/')[2];" + |
89 | - "if (uri.length < 30) {" + |
90 | - " uri += '/' + " + |
91 | - "doc.uri.split('/',4)[3].substr(0,30-uri.length) + '...';" + |
92 | - "}" + |
93 | + "uri = doc.uri.split('/')[2];" + |
94 | + "if (uri.length < 30) {" + |
95 | + " uri += '/' + " + |
96 | + "doc.uri.split('/',4)[3].substr(0,30-uri.length) + '...';" + |
97 | + "}" + |
98 | "} else {" + |
99 | - "uri = scheme + ' URL';" + |
100 | - "}" + |
101 | - "emit(doc.title, uri);" + |
102 | - "}" |
103 | - } |
104 | - } |
105 | - }; |
106 | - try { |
107 | - Bindwood.couch.save(new_doc); |
108 | - } catch(e) { |
109 | - Bindwood.writeError("Problem saving view: ", e); |
110 | - } |
111 | + "uri = scheme + ' URL';" + |
112 | + "}" + |
113 | + "if (!doc.deleted) {" + |
114 | + "emit(doc.title, uri);" + |
115 | + "}" + |
116 | + "}" }, |
117 | + { id: "_design/deleted", |
118 | + map: "function(doc) { if (doc.deleted) { emit (doc.title, doc.uri); } }" }]; |
119 | + for (var i = 0; i < views.length; i++) { |
120 | + var view_info = views[i]; |
121 | + var dirty = false; |
122 | + try { |
123 | + var new_doc; |
124 | + var current_doc = Bindwood.couch.open(view_info.id); |
125 | + if (current_doc !== null) { |
126 | + var old_map = current_doc.views.display.map; |
127 | + if (old_map != view_info.map) { // Ours is definitive |
128 | + new_doc = current_doc; |
129 | + new_doc.views.display.map = view_info.map; |
130 | + dirty = true; |
131 | + } |
132 | + } else { |
133 | + new_doc = { |
134 | + _id: view_info.id, |
135 | + views: { |
136 | + display: { |
137 | + map: view_info.map |
138 | + } |
139 | + } |
140 | + }; |
141 | + dirty = true; |
142 | + } |
143 | + if (dirty) { |
144 | + try { |
145 | + Bindwood.couch.save(new_doc); |
146 | + } catch(e) { |
147 | + Bindwood.writeError("Problem saving view: ", e); |
148 | + } |
149 | + } |
150 | + } catch(e) { |
151 | + // some kind of error fetching the existing design doc |
152 | + Bindwood.writeError("Problem checking for view: ", e); |
153 | } |
154 | - } catch(e) { |
155 | - // some kind of error fetching the existing design doc |
156 | - Bindwood.writeError("Problem checking for view: ", e); |
157 | } |
158 | }, |
159 | |
160 | @@ -316,21 +350,13 @@ |
161 | couchReadyObjectForNodeInBookmarksFolder: function(node, bookmarksFolderName) { |
162 | var itemId = node.itemId; |
163 | |
164 | - var title = node.title; |
165 | - Bindwood.writeMessage("Title: " + title); |
166 | - var uri = node.uri; |
167 | - Bindwood.writeMessage("URI: " + uri); |
168 | + var title = Bindwood.bookmarksService.getItemTitle(itemId); |
169 | var uuid = Bindwood.uuidForItemId(itemId); |
170 | - Bindwood.writeMessage("UUID: " + uuid); |
171 | var folder = bookmarksFolderName; |
172 | - Bindwood.writeMessage("Folder: " + folder); |
173 | var profile = Bindwood.currentProfile; |
174 | - Bindwood.writeMessage("Profile: " + profile); |
175 | |
176 | var bookmark = { |
177 | title: title, |
178 | - uri: uri, |
179 | - record_type: null, |
180 | application_annotations: { |
181 | Firefox: { |
182 | uuid: uuid, |
183 | @@ -343,6 +369,7 @@ |
184 | switch(Bindwood.bookmarksService.getItemType(itemId)) { |
185 | case Bindwood.bookmarksService.TYPE_BOOKMARK: |
186 | bookmark.record_type = "http://www.freedesktop.org/wiki/Specifications/desktopcouch/bookmark"; |
187 | + bookmark.uri = Bindwood.bookmarksService.getBookmarkURI(itemId).spec; |
188 | break; |
189 | case Bindwood.bookmarksService.TYPE_FOLDER: |
190 | bookmark.record_type = "http://www.freedesktop.org/wiki/Specifications/desktopcouch/folder"; |
191 | @@ -384,58 +411,50 @@ |
192 | } |
193 | |
194 | try { |
195 | - Bindwood.pushBookmarksFromFolder("toolbarFolder"); |
196 | + Bindwood.pushBookmarksFromFolder("toolbarFolder", Bindwood.bookmarksService.toolbarFolder); |
197 | } catch(e) { |
198 | Bindwood.writeError("Error pushing toolbarFolder bookmarks: ", e); |
199 | } |
200 | |
201 | try { |
202 | - Bindwood.pushBookmarksFromFolder("bookmarksMenuFolder"); |
203 | + Bindwood.pushBookmarksFromFolder("bookmarksMenuFolder", Bindwood.bookmarksService.bookmarksMenuFolder); |
204 | } catch(e) { |
205 | Bindwood.writeError("Error pushing bookmarksMenuFolder bookmarks: ", e); |
206 | } |
207 | |
208 | try { |
209 | - Bindwood.pushBookmarksFromFolder("unfiledBookmarksFolder"); |
210 | + Bindwood.pushBookmarksFromFolder("unfiledBookmarksFolder", Bindwood.bookmarksService.unfiledBookmarksFolder); |
211 | } catch(e) { |
212 | Bindwood.writeError("Error pushing unfiledBookmarksFolder bookmarks: ", e); |
213 | } |
214 | }, |
215 | |
216 | - getBookmarksFromFolder: function(bookmarksFolderName) { |
217 | + getBookmarksFromFolder: function(bookmarksFolderName, bookmarksFolder, accum) { |
218 | Bindwood.writeMessage("Fetching bookmarks from: " + bookmarksFolderName); |
219 | - var retval = []; |
220 | - var bookmarksFolder; |
221 | var options = Bindwood.historyService.getNewQueryOptions(); |
222 | var query = Bindwood.historyService.getNewQuery(); |
223 | - switch (bookmarksFolderName) { |
224 | - case "toolbarFolder": |
225 | - bookmarksFolder = Bindwood.bookmarksService.toolbarFolder; |
226 | - break; |
227 | - case "bookmarksMenuFolder": |
228 | - bookmarksFolder = Bindwood.bookmarksService.bookmarksMenuFolder; |
229 | - break; |
230 | - case "unfiledBookmarksFolder": |
231 | - bookmarksFolder = Bindwood.bookmarksService.unfiledBookmarksFolder; |
232 | - break; |
233 | - default: |
234 | - break; |
235 | - } |
236 | query.setFolders([bookmarksFolder], 1); |
237 | var result = Bindwood.historyService.executeQuery(query, options); |
238 | var rootNode = result.root; |
239 | rootNode.containerOpen = true; |
240 | for (var i=0; i<rootNode.childCount; i++) { |
241 | var node = rootNode.getChild(i); |
242 | - retval.push([node.itemId, Bindwood.couchReadyObjectForNodeInBookmarksFolder(node, bookmarksFolderName)]); |
243 | + // If node is a folder, descend into it, looking for its contents |
244 | + if (node.type == 6) { // RESULT_TYPE_FOLDER |
245 | + Bindwood.writeMessage("Descending into folder: " + node.title); |
246 | + accum = accum.concat(Bindwood.getBookmarksFromFolder(node.title, node.itemId, accum)); |
247 | + } else if (node.type == 0 || node.type == 7) { // RESULT_TYPE_URI or RESULT_TYPE_SEPARATOR |
248 | + Bindwood.writeMessage("Adding current node: " + node.title); |
249 | + accum.push([node.itemId, Bindwood.couchReadyObjectForNodeInBookmarksFolder(node, bookmarksFolderName)]); |
250 | + } |
251 | } |
252 | rootNode.containerOpen = false; |
253 | - return retval; |
254 | + return accum; |
255 | }, |
256 | |
257 | - pushBookmarksFromFolder: function(bookmarksFolderName) { |
258 | + pushBookmarksFromFolder: function(bookmarksFolderName, bookmarksFolder) { |
259 | Bindwood.writeMessage("Pushing bookmarks from " + bookmarksFolderName); |
260 | - var bookmarkData = Bindwood.getBookmarksFromFolder(bookmarksFolderName); |
261 | + var bookmarkData = Bindwood.getBookmarksFromFolder(bookmarksFolderName, bookmarksFolder, new Array()); |
262 | for (var i = 0; i < bookmarkData.length; i++) { |
263 | // find this bookmark in CouchDB |
264 | var itemId = bookmarkData[i][0]; |
265 | @@ -483,7 +502,11 @@ |
266 | // include the literal value |
267 | try { |
268 | var rows = Bindwood.couch.query(function (doc) { |
269 | - if (doc.record_type == "http://www.freedesktop.org/wiki/Specifications/desktopcouch/bookmark") { |
270 | + if (doc.record_type == "http://www.freedesktop.org/wiki/Specifications/desktopcouch/bookmark" && |
271 | + doc.application_annotations && |
272 | + doc.application_annotations.Firefox && |
273 | + doc.application_annotations.Firefox.profile && |
274 | + doc.application_annotations.Firefox.profile == Bindwood.currentProfile) { |
275 | emit(doc._id,doc); |
276 | } |
277 | }); |
Summary: Handle bookmarks per-profile, sync sub-folders, and
provide additional views in Couch.
Branches represented in this merge proposal ======= ======= ======= ======= ======= ===
=====
deleted-view:
Provide a deleted objects view, so when all client machines
have synced deletions, the owner can purge them from Couch.
Also, filter them out of the regular view.
handle- all-profiles:
Properly sync whichever profile is currently being used.
We tag each bookmark as belonging to the current profile, and
we use the current profile as a filter when pulling
bookmarks.
To test, you'll need this Bindwood branch installed on at
least two profiles. If you need a second profile, you can run
the Profile Manager from the command line:
$ firefox --profilemanager
Re-create the <email address hidden> extension file in mozilla/ firefox/ <new profile directory> /extensions/ with
~/.
the following contents (note no trailing slash):
/ path/to/ bindwood/ checkout
If you start up Firefox using your new profile:
$ firefox -P newprofilename &
And navigate to your CouchDB, you should see the combined annotations` object,
bookmarks of all profiles. However, if you look at any
individual bookmark, in its `application_
you'll see it tied to a specific profile. Similarly, Bindwood
will only pull that profile's bookmarks, so no cross-profile
pollution should happen.
work- with-folders:
This branch ensures that all bookmarks are synced. Previous lder, and marksFolder. This branch recursively descends into
branches only dealt with immediate children of the three main
bookmark folders: toolbarFolder, bookmarksMenuFo
unfiledBook
any subfolders located here, syncing any bookmarks it finds.
To test, create a profile without Bindwood installed, and
create arbitrarily nested folders in any of these bookmark
folders. When Bindwood is enabled, you should see all
bookmarks throughout the hierarchy represented in
Couch. Previous versions of Bindwood would only sync the
immediate child bookmarks of the top folder.
Testing strategies
==================
* If you have any deleted bookmarks, you'll be able to select
the 'deleted' view in Couch to see them, separate from your
live bookmarks.
* If you use multiple profiles, you'll be able to sync each of
them, without collisions between profiles. There are
additional views registered for each profile that will show
you only the bookmarks per profile.
* If you have sub-folders of any of the three main lder, and marksFolder) , those will also be synced to Couch.
folders (toolbarFolder, bookmarksMenuFo
unfiledBook