Merge lp:~midori/midori/desktop into lp:midori

Proposed by Cris Dywan
Status: Merged
Approved by: Paweł Forysiuk
Approved revision: 6423
Merged at revision: 6547
Proposed branch: lp:~midori/midori/desktop
Merge into: lp:midori
Diff against target: 418 lines (+183/-97)
5 files modified
cmake/ContainTest.cmake (+1/-0)
extensions/apps.vala (+132/-61)
midori/midori-dialog.vala (+32/-1)
tests/completion.vala (+17/-34)
tests/extensions.c (+1/-1)
To merge this branch: bzr merge lp:~midori/midori/desktop
Reviewer Review Type Date Requested Status
Paweł Forysiuk Approve
Review via email: mp+195292@code.launchpad.net

Commit message

More robust app/ profile creation

Description of the change

This branch includes new Test.init and Test.Job API which were found to be invaluable specifically with the apps test.

To post a comment you must log in.
lp:~midori/midori/desktop updated
6423. By Cris Dywan

Remove contained folders in ContainTest

Revision history for this message
Paweł Forysiuk (tuxator) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'cmake/ContainTest.cmake'
2--- cmake/ContainTest.cmake 2013-10-01 21:35:39 +0000
3+++ cmake/ContainTest.cmake 2014-01-26 21:49:39 +0000
4@@ -7,6 +7,7 @@
5 set(TEST_ENV "")
6 foreach(VARIABLE XDG_DATA_HOME XDG_CONFIG_HOME XDG_CACHE_HOME XDG_DATA_HOME XDG_RUNTIME_DIR TMPDIR)
7 set(CONTAINER "${CMAKE_CURRENT_BINARY_DIR}/${test_name}-folders/${VARIABLE}")
8+ file(REMOVE_RECURSE ${CONTAINER})
9 file(MAKE_DIRECTORY ${CONTAINER})
10 set(TEST_ENV "${TEST_ENV}${VARIABLE}=${CONTAINER};")
11 endforeach()
12
13=== modified file 'extensions/apps.vala'
14--- extensions/apps.vala 2013-08-09 22:48:35 +0000
15+++ extensions/apps.vala 2014-01-26 21:49:39 +0000
16@@ -20,10 +20,37 @@
17 internal string exec;
18 internal string uri;
19
20- internal static async void create (string prefix, GLib.File folder, string uri, string title, Gtk.Widget proxy) {
21- /* Strip LRE leading character and / */
22- string name = title.delimit ("‪/", ' ').strip();
23- string filename = Midori.Download.clean_filename (name);
24+ internal static string get_favicon_name_for_uri (string prefix, GLib.File folder, string uri, bool testing)
25+ {
26+ string icon_name = Midori.Stock.WEB_BROWSER;
27+
28+ if (testing == true)
29+ return icon_name;
30+
31+ if (prefix != PROFILE_PREFIX)
32+ {
33+ try {
34+ var pixbuf = Midori.Paths.get_icon (uri, null);
35+ if (pixbuf == null)
36+ throw new FileError.EXIST ("No favicon loaded");
37+ string icon_filename = folder.get_child ("icon.png").get_path ();
38+ pixbuf.save (icon_filename, "png", null, "compression", "7", null);
39+#if HAVE_WIN32
40+ string doubleslash_icon = icon_filename.replace ("\\", "\\\\");
41+ icon_name = doubleslash_icon;
42+#else
43+ icon_name = icon_filename;
44+#endif
45+ }
46+ catch (Error error) {
47+ GLib.warning (_("Failed to fetch application icon in %s: %s"), folder.get_path (), error.message);
48+ }
49+ }
50+ return icon_name;
51+ }
52+
53+ internal static string prepare_desktop_file (string prefix, string name, string uri, string title, string icon_name)
54+ {
55 string exec;
56 #if HAVE_WIN32
57 string doubleslash_uri = uri.replace ("\\", "\\\\");
58@@ -32,62 +59,100 @@
59 #else
60 exec = prefix + uri;
61 #endif
62+ var keyfile = new GLib.KeyFile ();
63+ string entry = "Desktop Entry";
64+
65+ keyfile.set_string (entry, "Version", "1.0");
66+ keyfile.set_string (entry, "Type", "Application");
67+ keyfile.set_string (entry, "Name", name);
68+ keyfile.set_string (entry, "Exec", exec);
69+ keyfile.set_string (entry, "TryExec", PACKAGE_NAME);
70+ keyfile.set_string (entry, "Icon", icon_name);
71+ keyfile.set_string (entry, "Categories", "Network;");
72+
73+ return keyfile.to_data();
74+ }
75+
76+ internal static File get_app_folder () {
77+ var data_dir = File.new_for_path (Midori.Paths.get_user_data_dir ()).get_child (PACKAGE_NAME);
78+ return data_dir.get_child ("apps");
79+ }
80+
81+ internal static async File create_app (string uri, string title, Gtk.Widget? proxy) {
82+ string checksum = Checksum.compute_for_string (ChecksumType.MD5, uri, -1);
83+ var folder = get_app_folder ();
84+ yield Launcher.create (APP_PREFIX, folder.get_child (checksum),
85+ uri, title, proxy);
86+ return folder.get_child (checksum);
87+ }
88+
89+ internal static File get_profile_folder () {
90+ var data_dir = File.new_for_path (Midori.Paths.get_user_data_dir ()).get_child (PACKAGE_NAME);
91+ return data_dir.get_child ("profiles");
92+ }
93+
94+ internal static async File create_profile (Gtk.Widget? proxy) {
95+ string uuid = g_dbus_generate_guid ();
96+ string config = Path.build_path (Path.DIR_SEPARATOR_S,
97+ Midori.Paths.get_user_data_dir (), PACKAGE_NAME, "profiles", uuid);
98+ var folder = get_profile_folder ();
99+ yield Launcher.create (PROFILE_PREFIX, folder.get_child (uuid),
100+ config, _("Midori (%s)").printf (uuid), proxy);
101+ return folder.get_child (uuid);
102+ }
103+
104+ internal static async void create (string prefix, GLib.File folder, string uri, string title, Gtk.Widget proxy) {
105+ /* Strip LRE leading character and / */
106+ string name = title.delimit ("‪/", ' ').strip();
107+ string filename = Midori.Download.clean_filename (name);
108+ string icon_name = Midori.Stock.WEB_BROWSER;
109+ bool testing = false;
110+ if (proxy == null)
111+ testing = true;
112+ var file = folder.get_child ("desc");
113+
114 try {
115 folder.make_directory_with_parents (null);
116- }
117- catch (Error error) {
118- /* It's not an error if the folder already exists;
119- any fatal problems will fail further down the line */
120- }
121-
122- string icon_name = Midori.Stock.WEB_BROWSER;
123- try {
124- var pixbuf = Midori.Paths.get_icon (uri, null);
125- if (pixbuf == null)
126- throw new FileError.EXIST ("No favicon loaded");
127- string icon_filename = folder.get_child ("icon.png").get_path ();
128- pixbuf.save (icon_filename, "png", null, "compression", "7", null);
129-#if HAVE_WIN32
130- string doubleslash_icon = icon_filename.replace ("\\", "\\\\");
131- icon_name = doubleslash_icon;
132-#else
133- icon_name = icon_filename;
134-#endif
135- }
136- catch (Error error) {
137- GLib.warning (_("Failed to fetch application icon in %s: %s"), folder.get_path (), error.message);
138- }
139- string contents = """
140- [Desktop Entry]
141- Version=1.0
142- Type=Application
143- Name=%s
144- Exec=%s
145- TryExec=%s
146- Icon=%s
147- Categories=Network;
148- """.printf (name, exec, PACKAGE_NAME, icon_name);
149- var file = folder.get_child ("desc");
150- var browser = proxy.get_toplevel () as Midori.Browser;
151+ } catch (IOError.EXISTS exist_error) {
152+ /* It's no error if the folder already exists */
153+ } catch (Error error) {
154+ warning (_("Failed to create new launcher (%s): %s"), file.get_path (), error.message);
155+ }
156+
157+ icon_name = get_favicon_name_for_uri (prefix, folder, uri, testing);
158+ string desktop_file = prepare_desktop_file (prefix, name, uri, title, icon_name);
159+
160 try {
161 var stream = yield file.replace_async (null, false, GLib.FileCreateFlags.NONE);
162- yield stream.write_async (contents.data);
163+ yield stream.write_async (desktop_file.data);
164 // Create a launcher/ menu
165 #if HAVE_WIN32
166 Midori.Sokoke.create_win32_desktop_lnk (prefix, filename, uri);
167 #else
168 var data_dir = File.new_for_path (Midori.Paths.get_user_data_dir ());
169- yield file.copy_async (data_dir.get_child ("applications").get_child (filename + ".desktop"),
170+ var desktop_dir = data_dir.get_child ("applications");
171+ try {
172+ desktop_dir.make_directory_with_parents (null);
173+ } catch (IOError.EXISTS exist_error) {
174+ /* It's no error if the folder already exists */
175+ }
176+
177+ yield file.copy_async (desktop_dir.get_child (filename + ".desktop"),
178 GLib.FileCopyFlags.NONE);
179 #endif
180-
181- browser.send_notification (_("Launcher created"),
182- _("You can now run <b>%s</b> from your launcher or menu").printf (name));
183+ if (proxy != null) {
184+ var browser = proxy.get_toplevel () as Midori.Browser;
185+ browser.send_notification (_("Launcher created"),
186+ _("You can now run <b>%s</b> from your launcher or menu").printf (name));
187+ }
188 }
189 catch (Error error) {
190 warning (_("Failed to create new launcher (%s): %s"), file.get_path (), error.message);
191- browser.send_notification (_("Error creating launcher"),
192- _("Failed to create new launcher (%s): %s").printf (file.get_path (), error.message));
193+ if (proxy != null) {
194+ var browser = proxy.get_toplevel () as Midori.Browser;
195+ browser.send_notification (_("Error creating launcher"),
196+ _("Failed to create new launcher (%s): %s").printf (file.get_path (), error.message));
197+ }
198 }
199 }
200
201@@ -139,11 +204,7 @@
202 profile.is_important = true;
203 profile.show ();
204 profile.clicked.connect (() => {
205- string uuid = g_dbus_generate_guid ();
206- string config = Path.build_path (Path.DIR_SEPARATOR_S,
207- Midori.Paths.get_user_data_dir (), PACKAGE_NAME, "profiles", uuid);
208- Launcher.create.begin (PROFILE_PREFIX, profile_folder.get_child (uuid),
209- config, _("Midori (%s)").printf (uuid), this);
210+ Launcher.create_profile.begin (this);
211 });
212 toolbar.insert (profile, -1);
213 #endif
214@@ -349,10 +410,8 @@
215 try {
216 try {
217 app_folder.make_directory_with_parents (null);
218- }
219- catch (IOError folder_error) {
220- if (!(folder_error is IOError.EXISTS))
221- throw folder_error;
222+ } catch (IOError.EXISTS exist_error) {
223+ /* It's no error if the folder already exists */
224 }
225
226 var monitor = app_folder.monitor_directory (0, null);
227@@ -392,9 +451,7 @@
228 _("Creates a new app for a specific site"), null);
229 action.activate.connect (() => {
230 var view = browser.tab as Midori.View;
231- string checksum = Checksum.compute_for_string (ChecksumType.MD5, view.get_display_uri (), -1);
232- Launcher.create.begin (APP_PREFIX, app_folder.get_child (checksum),
233- view.get_display_uri (), view.get_display_title (), browser);
234+ Launcher.create_app.begin (view.get_display_uri (), view.get_display_title (), view);
235 });
236 action_group.add_action_with_accel (action, "<Ctrl><Shift>A");
237 action.set_accel_group (accels);
238@@ -408,12 +465,11 @@
239
240 void activated (Midori.App app) {
241 array = new Katze.Array (typeof (Launcher));
242- var data_dir = File.new_for_path (Midori.Paths.get_user_data_dir ()).get_child (PACKAGE_NAME);
243 monitors = new GLib.List<GLib.FileMonitor> ();
244- app_folder = data_dir.get_child ("apps");
245+ app_folder = Launcher.get_app_folder ();
246 populate_apps.begin (app_folder);
247 /* FIXME: Profiles are broken on win32 because of no multi instance support */
248- profile_folder = data_dir.get_child ("profiles");
249+ profile_folder = Launcher.get_profile_folder ();
250 #if !HAVE_WIN32
251 populate_apps.begin (profile_folder);
252 #endif
253@@ -456,3 +512,18 @@
254 return new Apps.Manager ();
255 }
256
257+class ExtensionsAppsDesktop : Midori.Test.Job {
258+ public static void test () { new ExtensionsAppsDesktop ().run_sync (); }
259+ public override async void run (Cancellable cancellable) throws GLib.Error {
260+ var folder = yield Apps.Launcher.create_app ("http://example.com", "Example", null);
261+ var launcher = new Apps.Launcher (folder);
262+ launcher.init ();
263+ Katze.assert_str_equal (folder.get_path (), launcher.uri, "http://example.com");
264+ yield Apps.Launcher.create_profile (null);
265+ }
266+}
267+
268+public void extension_test () {
269+ Test.add_func ("/extensions/apps/desktop", ExtensionsAppsDesktop.test);
270+}
271+
272
273=== modified file 'midori/midori-dialog.vala'
274--- midori/midori-dialog.vala 2013-11-05 14:51:49 +0000
275+++ midori/midori-dialog.vala 2014-01-26 21:49:39 +0000
276@@ -24,13 +24,24 @@
277 }
278
279 namespace Test {
280+ public void init ([CCode (array_length_pos = 0.9)] ref unowned string[] args) {
281+ GLib.Test.init (ref args);
282+
283+ /* Always log to stderr */
284+ Log.set_handler (null,
285+ LogLevelFlags.LEVEL_MASK | LogLevelFlags.FLAG_FATAL | LogLevelFlags.FLAG_RECURSION,
286+ (domain, log_levels, message) => {
287+ stderr.printf ("** %s\n", message);
288+ });
289+ }
290+
291 internal static uint test_max_timeout = 0;
292 internal static string? test_first_try = null;
293 public void grab_max_timeout () {
294 int seconds = (Environment.get_variable ("MIDORI_TIMEOUT") ?? "42").to_int ();
295 test_first_try = "once";
296 test_max_timeout = GLib.Timeout.add_seconds (seconds > 0 ? seconds / 2 : 0, ()=>{
297- stdout.printf ("Timed out %s%s\n", test_first_try,
298+ stderr.printf ("Timed out %s%s\n", test_first_try,
299 MainContext.default ().pending () ? " (loop)" : "");
300 if (test_first_try == "twice")
301 Process.exit (0);
302@@ -50,6 +61,26 @@
303 test_idle_timeouts = true;
304 }
305
306+ public abstract class Job : GLib.Object {
307+ bool done;
308+ public abstract async void run (Cancellable cancellable) throws GLib.Error;
309+ async void run_wrapped (Cancellable cancellable) {
310+ try {
311+ yield run (cancellable);
312+ } catch (Error error) {
313+ GLib.error (error.message);
314+ }
315+ done = true;
316+ }
317+ public void run_sync () {
318+ var loop = MainContext.default ();
319+ var cancellable = new Cancellable ();
320+ done = false;
321+ run_wrapped.begin (cancellable);
322+ do { loop.iteration (true); } while (!done);
323+ }
324+ }
325+
326 public void log_set_fatal_handler_for_icons () {
327 GLib.Test.log_set_fatal_handler ((domain, log_levels, message)=> {
328 return !message.contains ("Error loading theme icon")
329
330=== modified file 'tests/completion.vala'
331--- tests/completion.vala 2013-12-16 22:38:24 +0000
332+++ tests/completion.vala 2014-01-26 21:49:39 +0000
333@@ -87,43 +87,26 @@
334 error ("Expected %d but got %d", 3, n);
335 }
336
337-async void complete_history (Midori.HistoryDatabase history) {
338- try {
339- history.insert ("http://example.com", "Ejemplo", 0, 0);
340- } catch (Error error) {
341- assert_not_reached ();
342- }
343- var cancellable = new Cancellable ();
344- var results = yield history.list_by_count_with_bookmarks ("example", 1, cancellable);
345- assert (results.length () == 1);
346- var first = results.nth_data (0);
347- assert (first.title == "Ejemplo");
348- results = yield history.list_by_count_with_bookmarks ("ejemplo", 1, cancellable);
349- assert (results.length () == 1);
350- first = results.nth_data (0);
351- assert (first.title == "Ejemplo");
352- complete_history_done = true;
353-}
354-
355-bool complete_history_done = false;
356-void completion_history () {
357- var app = new Midori.App ();
358- Midori.HistoryDatabase history;
359- try {
360+class CompletionHistory : Midori.Test.Job {
361+ public static void test () { new CompletionHistory ().run_sync (); }
362+ public override async void run (Cancellable cancellable) throws GLib.Error {
363 var bookmarks_database = new Midori.BookmarksDatabase ();
364 assert (bookmarks_database.db != null);
365- history = new Midori.HistoryDatabase (app);
366+
367+ Midori.HistoryDatabase history = new Midori.HistoryDatabase (null);
368 assert (history.db != null);
369 history.clear (0);
370- } catch (Midori.DatabaseError error) {
371- assert_not_reached();
372+
373+ history.insert ("http://example.com", "Ejemplo", 0, 0);
374+ var results = yield history.list_by_count_with_bookmarks ("example", 1, cancellable);
375+ assert (results.length () == 1);
376+ var first = results.nth_data (0);
377+ assert (first.title == "Ejemplo");
378+ results = yield history.list_by_count_with_bookmarks ("ejemplo", 1, cancellable);
379+ assert (results.length () == 1);
380+ first = results.nth_data (0);
381+ assert (first.title == "Ejemplo");
382 }
383-
384- Midori.Test.grab_max_timeout ();
385- var loop = MainContext.default ();
386- complete_history.begin (history);
387- do { loop.iteration (true); } while (!complete_history_done);
388- Midori.Test.release_max_timeout ();
389 }
390
391 struct TestCaseRender {
392@@ -154,11 +137,11 @@
393 }
394
395 void main (string[] args) {
396- Test.init (ref args);
397+ Midori.Test.init (ref args);
398 Midori.App.setup (ref args, null);
399 Midori.Paths.init (Midori.RuntimeMode.NORMAL, null);
400 Test.add_func ("/completion/autocompleter", completion_autocompleter);
401- Test.add_func ("/completion/history", completion_history);
402+ Test.add_func ("/completion/history", CompletionHistory.test);
403 Test.add_func ("/completion/location-action", completion_location_action);
404 Test.run ();
405 }
406
407=== modified file 'tests/extensions.c'
408--- tests/extensions.c 2013-10-29 18:45:01 +0000
409+++ tests/extensions.c 2014-01-26 21:49:39 +0000
410@@ -216,7 +216,7 @@
411 main (int argc,
412 char** argv)
413 {
414- g_test_init (&argc, &argv, NULL);
415+ midori_test_init (&argc, &argv);
416 midori_app_setup (&argc, &argv, NULL);
417 midori_paths_init (MIDORI_RUNTIME_MODE_NORMAL, NULL);
418 #ifndef HAVE_WEBKIT2

Subscribers

People subscribed via source and target branches

to all changes: