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
=== modified file 'cmake/ContainTest.cmake'
--- cmake/ContainTest.cmake 2013-10-01 21:35:39 +0000
+++ cmake/ContainTest.cmake 2014-01-26 21:49:39 +0000
@@ -7,6 +7,7 @@
7 set(TEST_ENV "")7 set(TEST_ENV "")
8 foreach(VARIABLE XDG_DATA_HOME XDG_CONFIG_HOME XDG_CACHE_HOME XDG_DATA_HOME XDG_RUNTIME_DIR TMPDIR)8 foreach(VARIABLE XDG_DATA_HOME XDG_CONFIG_HOME XDG_CACHE_HOME XDG_DATA_HOME XDG_RUNTIME_DIR TMPDIR)
9 set(CONTAINER "${CMAKE_CURRENT_BINARY_DIR}/${test_name}-folders/${VARIABLE}")9 set(CONTAINER "${CMAKE_CURRENT_BINARY_DIR}/${test_name}-folders/${VARIABLE}")
10 file(REMOVE_RECURSE ${CONTAINER})
10 file(MAKE_DIRECTORY ${CONTAINER})11 file(MAKE_DIRECTORY ${CONTAINER})
11 set(TEST_ENV "${TEST_ENV}${VARIABLE}=${CONTAINER};")12 set(TEST_ENV "${TEST_ENV}${VARIABLE}=${CONTAINER};")
12 endforeach()13 endforeach()
1314
=== modified file 'extensions/apps.vala'
--- extensions/apps.vala 2013-08-09 22:48:35 +0000
+++ extensions/apps.vala 2014-01-26 21:49:39 +0000
@@ -20,10 +20,37 @@
20 internal string exec;20 internal string exec;
21 internal string uri;21 internal string uri;
2222
23 internal static async void create (string prefix, GLib.File folder, string uri, string title, Gtk.Widget proxy) {23 internal static string get_favicon_name_for_uri (string prefix, GLib.File folder, string uri, bool testing)
24 /* Strip LRE leading character and / */24 {
25 string name = title.delimit ("‪/", ' ').strip();25 string icon_name = Midori.Stock.WEB_BROWSER;
26 string filename = Midori.Download.clean_filename (name);26
27 if (testing == true)
28 return icon_name;
29
30 if (prefix != PROFILE_PREFIX)
31 {
32 try {
33 var pixbuf = Midori.Paths.get_icon (uri, null);
34 if (pixbuf == null)
35 throw new FileError.EXIST ("No favicon loaded");
36 string icon_filename = folder.get_child ("icon.png").get_path ();
37 pixbuf.save (icon_filename, "png", null, "compression", "7", null);
38#if HAVE_WIN32
39 string doubleslash_icon = icon_filename.replace ("\\", "\\\\");
40 icon_name = doubleslash_icon;
41#else
42 icon_name = icon_filename;
43#endif
44 }
45 catch (Error error) {
46 GLib.warning (_("Failed to fetch application icon in %s: %s"), folder.get_path (), error.message);
47 }
48 }
49 return icon_name;
50 }
51
52 internal static string prepare_desktop_file (string prefix, string name, string uri, string title, string icon_name)
53 {
27 string exec;54 string exec;
28#if HAVE_WIN3255#if HAVE_WIN32
29 string doubleslash_uri = uri.replace ("\\", "\\\\");56 string doubleslash_uri = uri.replace ("\\", "\\\\");
@@ -32,62 +59,100 @@
32#else59#else
33 exec = prefix + uri;60 exec = prefix + uri;
34#endif61#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
35 try {114 try {
36 folder.make_directory_with_parents (null);115 folder.make_directory_with_parents (null);
37 }116 } catch (IOError.EXISTS exist_error) {
38 catch (Error error) {117 /* It's no error if the folder already exists */
39 /* It's not an error if the folder already exists;118 } catch (Error error) {
40 any fatal problems will fail further down the line */119 warning (_("Failed to create new launcher (%s): %s"), file.get_path (), error.message);
41 }120 }
42121
43 string icon_name = Midori.Stock.WEB_BROWSER;122 icon_name = get_favicon_name_for_uri (prefix, folder, uri, testing);
44 try {123 string desktop_file = prepare_desktop_file (prefix, name, uri, title, icon_name);
45 var pixbuf = Midori.Paths.get_icon (uri, null);124
46 if (pixbuf == null)
47 throw new FileError.EXIST ("No favicon loaded");
48 string icon_filename = folder.get_child ("icon.png").get_path ();
49 pixbuf.save (icon_filename, "png", null, "compression", "7", null);
50#if HAVE_WIN32
51 string doubleslash_icon = icon_filename.replace ("\\", "\\\\");
52 icon_name = doubleslash_icon;
53#else
54 icon_name = icon_filename;
55#endif
56 }
57 catch (Error error) {
58 GLib.warning (_("Failed to fetch application icon in %s: %s"), folder.get_path (), error.message);
59 }
60 string contents = """
61 [Desktop Entry]
62 Version=1.0
63 Type=Application
64 Name=%s
65 Exec=%s
66 TryExec=%s
67 Icon=%s
68 Categories=Network;
69 """.printf (name, exec, PACKAGE_NAME, icon_name);
70 var file = folder.get_child ("desc");
71 var browser = proxy.get_toplevel () as Midori.Browser;
72 try {125 try {
73 var stream = yield file.replace_async (null, false, GLib.FileCreateFlags.NONE);126 var stream = yield file.replace_async (null, false, GLib.FileCreateFlags.NONE);
74 yield stream.write_async (contents.data);127 yield stream.write_async (desktop_file.data);
75 // Create a launcher/ menu128 // Create a launcher/ menu
76#if HAVE_WIN32129#if HAVE_WIN32
77 Midori.Sokoke.create_win32_desktop_lnk (prefix, filename, uri);130 Midori.Sokoke.create_win32_desktop_lnk (prefix, filename, uri);
78#else131#else
79 var data_dir = File.new_for_path (Midori.Paths.get_user_data_dir ());132 var data_dir = File.new_for_path (Midori.Paths.get_user_data_dir ());
80 yield file.copy_async (data_dir.get_child ("applications").get_child (filename + ".desktop"),133 var desktop_dir = data_dir.get_child ("applications");
134 try {
135 desktop_dir.make_directory_with_parents (null);
136 } catch (IOError.EXISTS exist_error) {
137 /* It's no error if the folder already exists */
138 }
139
140 yield file.copy_async (desktop_dir.get_child (filename + ".desktop"),
81 GLib.FileCopyFlags.NONE);141 GLib.FileCopyFlags.NONE);
82#endif142#endif
83143 if (proxy != null) {
84 browser.send_notification (_("Launcher created"),144 var browser = proxy.get_toplevel () as Midori.Browser;
85 _("You can now run <b>%s</b> from your launcher or menu").printf (name));145 browser.send_notification (_("Launcher created"),
146 _("You can now run <b>%s</b> from your launcher or menu").printf (name));
147 }
86 }148 }
87 catch (Error error) {149 catch (Error error) {
88 warning (_("Failed to create new launcher (%s): %s"), file.get_path (), error.message);150 warning (_("Failed to create new launcher (%s): %s"), file.get_path (), error.message);
89 browser.send_notification (_("Error creating launcher"),151 if (proxy != null) {
90 _("Failed to create new launcher (%s): %s").printf (file.get_path (), error.message));152 var browser = proxy.get_toplevel () as Midori.Browser;
153 browser.send_notification (_("Error creating launcher"),
154 _("Failed to create new launcher (%s): %s").printf (file.get_path (), error.message));
155 }
91 }156 }
92 }157 }
93158
@@ -139,11 +204,7 @@
139 profile.is_important = true;204 profile.is_important = true;
140 profile.show ();205 profile.show ();
141 profile.clicked.connect (() => {206 profile.clicked.connect (() => {
142 string uuid = g_dbus_generate_guid ();207 Launcher.create_profile.begin (this);
143 string config = Path.build_path (Path.DIR_SEPARATOR_S,
144 Midori.Paths.get_user_data_dir (), PACKAGE_NAME, "profiles", uuid);
145 Launcher.create.begin (PROFILE_PREFIX, profile_folder.get_child (uuid),
146 config, _("Midori (%s)").printf (uuid), this);
147 });208 });
148 toolbar.insert (profile, -1);209 toolbar.insert (profile, -1);
149#endif210#endif
@@ -349,10 +410,8 @@
349 try {410 try {
350 try {411 try {
351 app_folder.make_directory_with_parents (null);412 app_folder.make_directory_with_parents (null);
352 }413 } catch (IOError.EXISTS exist_error) {
353 catch (IOError folder_error) {414 /* It's no error if the folder already exists */
354 if (!(folder_error is IOError.EXISTS))
355 throw folder_error;
356 }415 }
357416
358 var monitor = app_folder.monitor_directory (0, null);417 var monitor = app_folder.monitor_directory (0, null);
@@ -392,9 +451,7 @@
392 _("Creates a new app for a specific site"), null);451 _("Creates a new app for a specific site"), null);
393 action.activate.connect (() => {452 action.activate.connect (() => {
394 var view = browser.tab as Midori.View;453 var view = browser.tab as Midori.View;
395 string checksum = Checksum.compute_for_string (ChecksumType.MD5, view.get_display_uri (), -1);454 Launcher.create_app.begin (view.get_display_uri (), view.get_display_title (), view);
396 Launcher.create.begin (APP_PREFIX, app_folder.get_child (checksum),
397 view.get_display_uri (), view.get_display_title (), browser);
398 });455 });
399 action_group.add_action_with_accel (action, "<Ctrl><Shift>A");456 action_group.add_action_with_accel (action, "<Ctrl><Shift>A");
400 action.set_accel_group (accels);457 action.set_accel_group (accels);
@@ -408,12 +465,11 @@
408465
409 void activated (Midori.App app) {466 void activated (Midori.App app) {
410 array = new Katze.Array (typeof (Launcher));467 array = new Katze.Array (typeof (Launcher));
411 var data_dir = File.new_for_path (Midori.Paths.get_user_data_dir ()).get_child (PACKAGE_NAME);
412 monitors = new GLib.List<GLib.FileMonitor> ();468 monitors = new GLib.List<GLib.FileMonitor> ();
413 app_folder = data_dir.get_child ("apps");469 app_folder = Launcher.get_app_folder ();
414 populate_apps.begin (app_folder);470 populate_apps.begin (app_folder);
415 /* FIXME: Profiles are broken on win32 because of no multi instance support */471 /* FIXME: Profiles are broken on win32 because of no multi instance support */
416 profile_folder = data_dir.get_child ("profiles");472 profile_folder = Launcher.get_profile_folder ();
417#if !HAVE_WIN32473#if !HAVE_WIN32
418 populate_apps.begin (profile_folder);474 populate_apps.begin (profile_folder);
419#endif475#endif
@@ -456,3 +512,18 @@
456 return new Apps.Manager ();512 return new Apps.Manager ();
457}513}
458514
515class ExtensionsAppsDesktop : Midori.Test.Job {
516 public static void test () { new ExtensionsAppsDesktop ().run_sync (); }
517 public override async void run (Cancellable cancellable) throws GLib.Error {
518 var folder = yield Apps.Launcher.create_app ("http://example.com", "Example", null);
519 var launcher = new Apps.Launcher (folder);
520 launcher.init ();
521 Katze.assert_str_equal (folder.get_path (), launcher.uri, "http://example.com");
522 yield Apps.Launcher.create_profile (null);
523 }
524}
525
526public void extension_test () {
527 Test.add_func ("/extensions/apps/desktop", ExtensionsAppsDesktop.test);
528}
529
459530
=== modified file 'midori/midori-dialog.vala'
--- midori/midori-dialog.vala 2013-11-05 14:51:49 +0000
+++ midori/midori-dialog.vala 2014-01-26 21:49:39 +0000
@@ -24,13 +24,24 @@
24 }24 }
2525
26 namespace Test {26 namespace Test {
27 public void init ([CCode (array_length_pos = 0.9)] ref unowned string[] args) {
28 GLib.Test.init (ref args);
29
30 /* Always log to stderr */
31 Log.set_handler (null,
32 LogLevelFlags.LEVEL_MASK | LogLevelFlags.FLAG_FATAL | LogLevelFlags.FLAG_RECURSION,
33 (domain, log_levels, message) => {
34 stderr.printf ("** %s\n", message);
35 });
36 }
37
27 internal static uint test_max_timeout = 0;38 internal static uint test_max_timeout = 0;
28 internal static string? test_first_try = null;39 internal static string? test_first_try = null;
29 public void grab_max_timeout () {40 public void grab_max_timeout () {
30 int seconds = (Environment.get_variable ("MIDORI_TIMEOUT") ?? "42").to_int ();41 int seconds = (Environment.get_variable ("MIDORI_TIMEOUT") ?? "42").to_int ();
31 test_first_try = "once";42 test_first_try = "once";
32 test_max_timeout = GLib.Timeout.add_seconds (seconds > 0 ? seconds / 2 : 0, ()=>{43 test_max_timeout = GLib.Timeout.add_seconds (seconds > 0 ? seconds / 2 : 0, ()=>{
33 stdout.printf ("Timed out %s%s\n", test_first_try,44 stderr.printf ("Timed out %s%s\n", test_first_try,
34 MainContext.default ().pending () ? " (loop)" : "");45 MainContext.default ().pending () ? " (loop)" : "");
35 if (test_first_try == "twice")46 if (test_first_try == "twice")
36 Process.exit (0);47 Process.exit (0);
@@ -50,6 +61,26 @@
50 test_idle_timeouts = true;61 test_idle_timeouts = true;
51 }62 }
5263
64 public abstract class Job : GLib.Object {
65 bool done;
66 public abstract async void run (Cancellable cancellable) throws GLib.Error;
67 async void run_wrapped (Cancellable cancellable) {
68 try {
69 yield run (cancellable);
70 } catch (Error error) {
71 GLib.error (error.message);
72 }
73 done = true;
74 }
75 public void run_sync () {
76 var loop = MainContext.default ();
77 var cancellable = new Cancellable ();
78 done = false;
79 run_wrapped.begin (cancellable);
80 do { loop.iteration (true); } while (!done);
81 }
82 }
83
53 public void log_set_fatal_handler_for_icons () {84 public void log_set_fatal_handler_for_icons () {
54 GLib.Test.log_set_fatal_handler ((domain, log_levels, message)=> {85 GLib.Test.log_set_fatal_handler ((domain, log_levels, message)=> {
55 return !message.contains ("Error loading theme icon")86 return !message.contains ("Error loading theme icon")
5687
=== modified file 'tests/completion.vala'
--- tests/completion.vala 2013-12-16 22:38:24 +0000
+++ tests/completion.vala 2014-01-26 21:49:39 +0000
@@ -87,43 +87,26 @@
87 error ("Expected %d but got %d", 3, n);87 error ("Expected %d but got %d", 3, n);
88}88}
8989
90async void complete_history (Midori.HistoryDatabase history) {90class CompletionHistory : Midori.Test.Job {
91 try {91 public static void test () { new CompletionHistory ().run_sync (); }
92 history.insert ("http://example.com", "Ejemplo", 0, 0);92 public override async void run (Cancellable cancellable) throws GLib.Error {
93 } catch (Error error) {
94 assert_not_reached ();
95 }
96 var cancellable = new Cancellable ();
97 var results = yield history.list_by_count_with_bookmarks ("example", 1, cancellable);
98 assert (results.length () == 1);
99 var first = results.nth_data (0);
100 assert (first.title == "Ejemplo");
101 results = yield history.list_by_count_with_bookmarks ("ejemplo", 1, cancellable);
102 assert (results.length () == 1);
103 first = results.nth_data (0);
104 assert (first.title == "Ejemplo");
105 complete_history_done = true;
106}
107
108bool complete_history_done = false;
109void completion_history () {
110 var app = new Midori.App ();
111 Midori.HistoryDatabase history;
112 try {
113 var bookmarks_database = new Midori.BookmarksDatabase ();93 var bookmarks_database = new Midori.BookmarksDatabase ();
114 assert (bookmarks_database.db != null);94 assert (bookmarks_database.db != null);
115 history = new Midori.HistoryDatabase (app);95
96 Midori.HistoryDatabase history = new Midori.HistoryDatabase (null);
116 assert (history.db != null);97 assert (history.db != null);
117 history.clear (0);98 history.clear (0);
118 } catch (Midori.DatabaseError error) {99
119 assert_not_reached();100 history.insert ("http://example.com", "Ejemplo", 0, 0);
101 var results = yield history.list_by_count_with_bookmarks ("example", 1, cancellable);
102 assert (results.length () == 1);
103 var first = results.nth_data (0);
104 assert (first.title == "Ejemplo");
105 results = yield history.list_by_count_with_bookmarks ("ejemplo", 1, cancellable);
106 assert (results.length () == 1);
107 first = results.nth_data (0);
108 assert (first.title == "Ejemplo");
120 }109 }
121
122 Midori.Test.grab_max_timeout ();
123 var loop = MainContext.default ();
124 complete_history.begin (history);
125 do { loop.iteration (true); } while (!complete_history_done);
126 Midori.Test.release_max_timeout ();
127}110}
128111
129struct TestCaseRender {112struct TestCaseRender {
@@ -154,11 +137,11 @@
154}137}
155138
156void main (string[] args) {139void main (string[] args) {
157 Test.init (ref args);140 Midori.Test.init (ref args);
158 Midori.App.setup (ref args, null);141 Midori.App.setup (ref args, null);
159 Midori.Paths.init (Midori.RuntimeMode.NORMAL, null);142 Midori.Paths.init (Midori.RuntimeMode.NORMAL, null);
160 Test.add_func ("/completion/autocompleter", completion_autocompleter);143 Test.add_func ("/completion/autocompleter", completion_autocompleter);
161 Test.add_func ("/completion/history", completion_history);144 Test.add_func ("/completion/history", CompletionHistory.test);
162 Test.add_func ("/completion/location-action", completion_location_action);145 Test.add_func ("/completion/location-action", completion_location_action);
163 Test.run ();146 Test.run ();
164}147}
165148
=== modified file 'tests/extensions.c'
--- tests/extensions.c 2013-10-29 18:45:01 +0000
+++ tests/extensions.c 2014-01-26 21:49:39 +0000
@@ -216,7 +216,7 @@
216main (int argc,216main (int argc,
217 char** argv)217 char** argv)
218{218{
219 g_test_init (&argc, &argv, NULL);219 midori_test_init (&argc, &argv);
220 midori_app_setup (&argc, &argv, NULL);220 midori_app_setup (&argc, &argv, NULL);
221 midori_paths_init (MIDORI_RUNTIME_MODE_NORMAL, NULL);221 midori_paths_init (MIDORI_RUNTIME_MODE_NORMAL, NULL);
222 #ifndef HAVE_WEBKIT2222 #ifndef HAVE_WEBKIT2

Subscribers

People subscribed via source and target branches

to all changes: