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
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 });

Subscribers

People subscribed via source and target branches