Merge lp:~urbanape/bindwood/work-with-folders into lp:bindwood

Proposed by Zachery Bir
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
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.

To post a comment you must log in.
Revision history for this message
Zachery Bir (urbanape) wrote :

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
    bookmarks of all profiles. However, if you look at any
    individual bookmark, in its `application_annotations` object,
    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
    branches only dealt with immediate children of the three main
    bookmark folders: toolbarFolder, bookmarksMenuFolder, and
    unfiledBookmarksFolder. This branch recursively descends into
    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
    folders (toolbarFolder, bookmarksMenuFolder, and
    unfiledBookmarksFolder), those will also be synced to Couch.

Revision history for this message
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.

Revision history for this message
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

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'content/sync.js'
--- content/sync.js 2009-09-15 17:35:12 +0000
+++ content/sync.js 2009-09-18 16:16:41 +0000
@@ -30,8 +30,8 @@
30 .getService(Ci.nsIIOService),30 .getService(Ci.nsIIOService),
31 envService: Cc["@mozilla.org/process/environment;1"]31 envService: Cc["@mozilla.org/process/environment;1"]
32 .getService(Ci.nsIEnvironment),32 .getService(Ci.nsIEnvironment),
33 profileService: Cc["@mozilla.org/toolkit/profile-service;1"]33 directoryService: Cc["@mozilla.org/file/directory_service;1"]
34 .getService(Ci.nsIToolkitProfileService),34 .getService(Ci.nsIProperties),
35 windowService: Cc["@mozilla.org/appshell/window-mediator;1"]35 windowService: Cc["@mozilla.org/appshell/window-mediator;1"]
36 .getService(Ci.nsIWindowMediator),36 .getService(Ci.nsIWindowMediator),
3737
@@ -52,20 +52,37 @@
52 Bindwood.consoleService.logStringMessage("Bindwood: " + aMessage + " message: '" + e.message + "', reason: '" + e.reason + "', description: '" + e.description + "', error: '" + e.error + "'");52 Bindwood.consoleService.logStringMessage("Bindwood: " + aMessage + " message: '" + e.message + "', reason: '" + e.reason + "', description: '" + e.description + "', error: '" + e.error + "'");
53 },53 },
5454
55 extractProfileName: function(path) {
56 // We want the last part of the profile path
57 // ('default' for '/home/zbir/.mozilla/firefox/ixlw0nvl.default')
58 // For profiles that have not been created via the Profile Manager,
59 // we just take the last path segment as the profile name.
60 //
61 // Actually, there's a degenerate case, where the last segment
62 // doesn't have the Firefox-provided random string:
63 // '/home/zbir/canonical.com' => 'com'
64 // But as I said, this is maybe degenerate.
65
66 var segments = path.split('/');
67 var possible_profile = segments[segments.length - 1];
68 var first_period = possible_profile.indexOf('.');
69 if (first_period == -1) {
70 return possible_profile; // no periods in the last segment, return as is
71 } else {
72 return possible_profile.substr(first_period + 1);
73 }
74 },
75
55 // Setup the environment and go76 // Setup the environment and go
56 init: function() {77 init: function() {
57 // Start the process and de-register ourself78 // Start the process and de-register ourself
58 // http://forums.mozillazine.org/viewtopic.php?f=19&t=657911&start=079 // http://forums.mozillazine.org/viewtopic.php?f=19&t=657911&start=0
59 // It ensures that we're only running that code on the first window.80 // It ensures that we're only running that code on the first window.
6081
61 Bindwood.currentProfile = Bindwood.profileService.selectedProfile.name;82 Bindwood.currentProfile = Bindwood.extractProfileName(Bindwood.directoryService.get('ProfD', Ci.nsIFile).path);
6283
63 if (Bindwood.currentProfile == 'default') { // We only currently operate on the 'default' profile84 if(Bindwood.windowService.getEnumerator("").getNext() == window) {
64 if(Bindwood.windowService.getEnumerator("").getNext() == window) {85 Bindwood.getCouchEnvironment(Bindwood.startProcess);
65 Bindwood.getCouchEnvironment(Bindwood.startProcess);
66 }
67 } else {
68 Bindwood.writeError("Bindwood currently only supports the default profile.", undefined);
69 }86 }
70 },87 },
7188
@@ -178,48 +195,65 @@
178 } catch(e) {195 } catch(e) {
179 Bindwood.writeError("Error when calling pushBookmarks: ", e);196 Bindwood.writeError("Error when calling pushBookmarks: ", e);
180 }197 }
181 Bindwood.createView();198 Bindwood.createViews();
182 Bindwood.pullBookmarks();199 Bindwood.pullBookmarks();
183 },200 },
184201
185 createView: function() {202 createViews: function() {
186 var DDID = "_design/views";203 var views = [{ id: "_design/views",
187 var current_doc;204 map: "function(doc) { " +
188 try {
189 current_doc = Bindwood.couch.open(DDID);
190 if (current_doc !== null) {
191 Bindwood.writeMessage("View already exists; leaving it alone");
192 } else {
193 new_doc = {
194 _id: DDID,
195 views: {
196 display: {
197 map: "function(doc) { " +
198 "var scheme = doc.uri.split(':',1)[0]; " +205 "var scheme = doc.uri.split(':',1)[0]; " +
199 "var uri; " +206 "var uri; " +
200 "if (scheme == 'http' || scheme == 'https') {" +207 "if (scheme == 'http' || scheme == 'https') {" +
201 "uri = doc.uri.split('/')[2];" +208 "uri = doc.uri.split('/')[2];" +
202 "if (uri.length < 30) {" +209 "if (uri.length < 30) {" +
203 " uri += '/' + " +210 " uri += '/' + " +
204 "doc.uri.split('/',4)[3].substr(0,30-uri.length) + '...';" +211 "doc.uri.split('/',4)[3].substr(0,30-uri.length) + '...';" +
205 "}" +212 "}" +
206 "} else {" +213 "} else {" +
207 "uri = scheme + ' URL';" +214 "uri = scheme + ' URL';" +
208 "}" +215 "}" +
209 "emit(doc.title, uri);" +216 "if (!doc.deleted) {" +
210 "}"217 "emit(doc.title, uri);" +
211 }218 "}" +
212 }219 "}" },
213 };220 { id: "_design/deleted",
214 try {221 map: "function(doc) { if (doc.deleted) { emit (doc.title, doc.uri); } }" }];
215 Bindwood.couch.save(new_doc);222 for (var i = 0; i < views.length; i++) {
216 } catch(e) {223 var view_info = views[i];
217 Bindwood.writeError("Problem saving view: ", e);224 var dirty = false;
218 }225 try {
226 var new_doc;
227 var current_doc = Bindwood.couch.open(view_info.id);
228 if (current_doc !== null) {
229 var old_map = current_doc.views.display.map;
230 if (old_map != view_info.map) { // Ours is definitive
231 new_doc = current_doc;
232 new_doc.views.display.map = view_info.map;
233 dirty = true;
234 }
235 } else {
236 new_doc = {
237 _id: view_info.id,
238 views: {
239 display: {
240 map: view_info.map
241 }
242 }
243 };
244 dirty = true;
245 }
246 if (dirty) {
247 try {
248 Bindwood.couch.save(new_doc);
249 } catch(e) {
250 Bindwood.writeError("Problem saving view: ", e);
251 }
252 }
253 } catch(e) {
254 // some kind of error fetching the existing design doc
255 Bindwood.writeError("Problem checking for view: ", e);
219 }256 }
220 } catch(e) {
221 // some kind of error fetching the existing design doc
222 Bindwood.writeError("Problem checking for view: ", e);
223 }257 }
224 },258 },
225259
@@ -316,21 +350,13 @@
316 couchReadyObjectForNodeInBookmarksFolder: function(node, bookmarksFolderName) {350 couchReadyObjectForNodeInBookmarksFolder: function(node, bookmarksFolderName) {
317 var itemId = node.itemId;351 var itemId = node.itemId;
318352
319 var title = node.title;353 var title = Bindwood.bookmarksService.getItemTitle(itemId);
320 Bindwood.writeMessage("Title: " + title);
321 var uri = node.uri;
322 Bindwood.writeMessage("URI: " + uri);
323 var uuid = Bindwood.uuidForItemId(itemId);354 var uuid = Bindwood.uuidForItemId(itemId);
324 Bindwood.writeMessage("UUID: " + uuid);
325 var folder = bookmarksFolderName;355 var folder = bookmarksFolderName;
326 Bindwood.writeMessage("Folder: " + folder);
327 var profile = Bindwood.currentProfile;356 var profile = Bindwood.currentProfile;
328 Bindwood.writeMessage("Profile: " + profile);
329357
330 var bookmark = {358 var bookmark = {
331 title: title,359 title: title,
332 uri: uri,
333 record_type: null,
334 application_annotations: {360 application_annotations: {
335 Firefox: {361 Firefox: {
336 uuid: uuid,362 uuid: uuid,
@@ -343,6 +369,7 @@
343 switch(Bindwood.bookmarksService.getItemType(itemId)) {369 switch(Bindwood.bookmarksService.getItemType(itemId)) {
344 case Bindwood.bookmarksService.TYPE_BOOKMARK:370 case Bindwood.bookmarksService.TYPE_BOOKMARK:
345 bookmark.record_type = "http://www.freedesktop.org/wiki/Specifications/desktopcouch/bookmark";371 bookmark.record_type = "http://www.freedesktop.org/wiki/Specifications/desktopcouch/bookmark";
372 bookmark.uri = Bindwood.bookmarksService.getBookmarkURI(itemId).spec;
346 break;373 break;
347 case Bindwood.bookmarksService.TYPE_FOLDER:374 case Bindwood.bookmarksService.TYPE_FOLDER:
348 bookmark.record_type = "http://www.freedesktop.org/wiki/Specifications/desktopcouch/folder";375 bookmark.record_type = "http://www.freedesktop.org/wiki/Specifications/desktopcouch/folder";
@@ -384,58 +411,50 @@
384 }411 }
385412
386 try {413 try {
387 Bindwood.pushBookmarksFromFolder("toolbarFolder");414 Bindwood.pushBookmarksFromFolder("toolbarFolder", Bindwood.bookmarksService.toolbarFolder);
388 } catch(e) {415 } catch(e) {
389 Bindwood.writeError("Error pushing toolbarFolder bookmarks: ", e);416 Bindwood.writeError("Error pushing toolbarFolder bookmarks: ", e);
390 }417 }
391418
392 try {419 try {
393 Bindwood.pushBookmarksFromFolder("bookmarksMenuFolder");420 Bindwood.pushBookmarksFromFolder("bookmarksMenuFolder", Bindwood.bookmarksService.bookmarksMenuFolder);
394 } catch(e) {421 } catch(e) {
395 Bindwood.writeError("Error pushing bookmarksMenuFolder bookmarks: ", e);422 Bindwood.writeError("Error pushing bookmarksMenuFolder bookmarks: ", e);
396 }423 }
397424
398 try {425 try {
399 Bindwood.pushBookmarksFromFolder("unfiledBookmarksFolder");426 Bindwood.pushBookmarksFromFolder("unfiledBookmarksFolder", Bindwood.bookmarksService.unfiledBookmarksFolder);
400 } catch(e) {427 } catch(e) {
401 Bindwood.writeError("Error pushing unfiledBookmarksFolder bookmarks: ", e);428 Bindwood.writeError("Error pushing unfiledBookmarksFolder bookmarks: ", e);
402 }429 }
403 },430 },
404431
405 getBookmarksFromFolder: function(bookmarksFolderName) {432 getBookmarksFromFolder: function(bookmarksFolderName, bookmarksFolder, accum) {
406 Bindwood.writeMessage("Fetching bookmarks from: " + bookmarksFolderName);433 Bindwood.writeMessage("Fetching bookmarks from: " + bookmarksFolderName);
407 var retval = [];
408 var bookmarksFolder;
409 var options = Bindwood.historyService.getNewQueryOptions();434 var options = Bindwood.historyService.getNewQueryOptions();
410 var query = Bindwood.historyService.getNewQuery();435 var query = Bindwood.historyService.getNewQuery();
411 switch (bookmarksFolderName) {
412 case "toolbarFolder":
413 bookmarksFolder = Bindwood.bookmarksService.toolbarFolder;
414 break;
415 case "bookmarksMenuFolder":
416 bookmarksFolder = Bindwood.bookmarksService.bookmarksMenuFolder;
417 break;
418 case "unfiledBookmarksFolder":
419 bookmarksFolder = Bindwood.bookmarksService.unfiledBookmarksFolder;
420 break;
421 default:
422 break;
423 }
424 query.setFolders([bookmarksFolder], 1);436 query.setFolders([bookmarksFolder], 1);
425 var result = Bindwood.historyService.executeQuery(query, options);437 var result = Bindwood.historyService.executeQuery(query, options);
426 var rootNode = result.root;438 var rootNode = result.root;
427 rootNode.containerOpen = true;439 rootNode.containerOpen = true;
428 for (var i=0; i<rootNode.childCount; i++) {440 for (var i=0; i<rootNode.childCount; i++) {
429 var node = rootNode.getChild(i);441 var node = rootNode.getChild(i);
430 retval.push([node.itemId, Bindwood.couchReadyObjectForNodeInBookmarksFolder(node, bookmarksFolderName)]);442 // If node is a folder, descend into it, looking for its contents
443 if (node.type == 6) { // RESULT_TYPE_FOLDER
444 Bindwood.writeMessage("Descending into folder: " + node.title);
445 accum = accum.concat(Bindwood.getBookmarksFromFolder(node.title, node.itemId, accum));
446 } else if (node.type == 0 || node.type == 7) { // RESULT_TYPE_URI or RESULT_TYPE_SEPARATOR
447 Bindwood.writeMessage("Adding current node: " + node.title);
448 accum.push([node.itemId, Bindwood.couchReadyObjectForNodeInBookmarksFolder(node, bookmarksFolderName)]);
449 }
431 }450 }
432 rootNode.containerOpen = false;451 rootNode.containerOpen = false;
433 return retval;452 return accum;
434 },453 },
435454
436 pushBookmarksFromFolder: function(bookmarksFolderName) {455 pushBookmarksFromFolder: function(bookmarksFolderName, bookmarksFolder) {
437 Bindwood.writeMessage("Pushing bookmarks from " + bookmarksFolderName);456 Bindwood.writeMessage("Pushing bookmarks from " + bookmarksFolderName);
438 var bookmarkData = Bindwood.getBookmarksFromFolder(bookmarksFolderName);457 var bookmarkData = Bindwood.getBookmarksFromFolder(bookmarksFolderName, bookmarksFolder, new Array());
439 for (var i = 0; i < bookmarkData.length; i++) {458 for (var i = 0; i < bookmarkData.length; i++) {
440 // find this bookmark in CouchDB459 // find this bookmark in CouchDB
441 var itemId = bookmarkData[i][0];460 var itemId = bookmarkData[i][0];
@@ -483,7 +502,11 @@
483 // include the literal value502 // include the literal value
484 try {503 try {
485 var rows = Bindwood.couch.query(function (doc) {504 var rows = Bindwood.couch.query(function (doc) {
486 if (doc.record_type == "http://www.freedesktop.org/wiki/Specifications/desktopcouch/bookmark") {505 if (doc.record_type == "http://www.freedesktop.org/wiki/Specifications/desktopcouch/bookmark" &&
506 doc.application_annotations &&
507 doc.application_annotations.Firefox &&
508 doc.application_annotations.Firefox.profile &&
509 doc.application_annotations.Firefox.profile == Bindwood.currentProfile) {
487 emit(doc._id,doc);510 emit(doc._id,doc);
488 }511 }
489 });512 });

Subscribers

People subscribed via source and target branches