Merge lp:~gtg-contributors/gtg/code-layout-2 into lp:~gtg/gtg/old-trunk
- code-layout-2
- Merge into old-trunk
Status: | Superseded |
---|---|
Proposed branch: | lp:~gtg-contributors/gtg/code-layout-2 |
Merge into: | lp:~gtg/gtg/old-trunk |
Diff against target: |
687 lines (+216/-284) 6 files modified
GTG/__init__.py (+47/-39) GTG/cli/__init__.py (+37/-47) GTG/gtg.py (+85/-94) gtcli (+12/-0) gtg (+24/-28) gtg_new_task (+11/-76) |
To merge this branch: | bzr merge lp:~gtg-contributors/gtg/code-layout-2 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Bryce Harrington (community) | code | Needs Fixing | |
Lionel Dricot (community) | Needs Information | ||
Review via email: mp+27538@code.launchpad.net |
This proposal has been superseded by a proposal from 2010-07-16.
Commit message
Description of the change
This is the second part of the code relayout previously mentioned. The logic behind this branch is: since the GTK UI goes in its own module, so does the CLI.
I asked Bryce about this before starting and he didn't think it was badly needed — but I've gone ahead and done it anyway :)
See the r806 commit message for a description of the changes. The main benefit is that it becomes more clear which imports etc. are dependencies of GTG generally, and which are specific just to the GTK UI. In GTG/gtg.py, the major if statement in main() will eventually also handle a choice to not start any UI at all, instead starting the GTG server.
Lionel Dricot (ploum-deactivatedaccount) wrote : | # |
Paul Natsuo Kishimoto (khaeru) wrote : | # |
Whoops — I didn't realize I could request a review from someone through Launchpad, instead of via e-mail.
Bryce Harrington (bryce) wrote : | # |
I do like most of this branch, it has some good cleanup in it. However, I prefer to keep gtcli separate from the gtg executable for now, as I'm trying to keep it limited to being purely a dbus client.
If you restructure the branch to leave the cli separate from gtg itself, I'm fine with this going in.
Paul Natsuo Kishimoto (khaeru) wrote : | # |
Comparing the imports...
Previously (in ./gtcli): cgi, datetime, dbus, getopt, os, re, string, sys, textwrap
Now: os, optparse, GTG.gtg (dbus, GTG.cli (cgi, datetime, dbus, os, re, string, sys, textwrap), GTG.info, logging, os)
The changes are:
* getopt replaced by optparse.
* logging added (only when the command-line debug flag is given)
* GTG.info added (this file defines some strings only)
Also, the entire CLI is in a single file, as it was previously, and that file still does not import any of the GTG internals. So, it is still purely DBus.
To keep the old ./gtcli pure would mean to avoid adding GTG.-- imports to that one file. I admit there will now be *three* files in which to prevent these imports: gtg, GTG/gtg.py and GTG/cli/
One, this doesn't seem difficult. I could even add comments ("DO NOT import GTG.whatever here!") to help. Two, when the client-server separation is finished, the GTK UI will *also* use DBus only. That is, we will more likely push imports out of GTG/gtg.py into the GTK and server submodules, than add more.
- 807. By Paul Natsuo Kishimoto
-
Further cleaning of imports, add some documentation.
- 808. By Paul Natsuo Kishimoto
-
Another comment.
- 809. By Paul Natsuo Kishimoto
-
Resolve conflicts with trunk.
Unmerged revisions
- 809. By Paul Natsuo Kishimoto
-
Resolve conflicts with trunk.
- 808. By Paul Natsuo Kishimoto
-
Another comment.
- 807. By Paul Natsuo Kishimoto
-
Further cleaning of imports, add some documentation.
- 806. By Paul Natsuo Kishimoto
-
* gtg: prune out UI-specific code.
* GTG/gtg.py: add UI-specific code from gtg.
* Choose a UI based on the command-line selection.
* "import" heavy lifting only when the GTK UI is specified.
* Simpler check for X via DISPLAY environmental variable (instead of
running xset).
* GTG/__init__.py: cleanup; add __all__ to track which names are used
by other parts of GTG.
* gtcli:
* Move to GTG/cli/__init_ _.py:
* Add main() method around existing code.
* usage() now returns a string instead of printing to stderr.
* Some checks on options removed (handled by optparse in gtg).
* Replace with a shell script calling "gtg -u cli".
* gtg_new_task: replace with a shell script calling "gtg -u cli new".
Preview Diff
1 | === modified file 'GTG/__init__.py' |
2 | --- GTG/__init__.py 2010-03-12 11:16:15 +0000 |
3 | +++ GTG/__init__.py 2010-07-16 18:30:55 +0000 |
4 | @@ -19,76 +19,84 @@ |
5 | """ |
6 | Getting Things Gnome! A personal organizer for the GNOME desktop |
7 | """ |
8 | - |
9 | +import locale |
10 | import os |
11 | -import locale |
12 | -#Fallback to LANG C if unsupported locale |
13 | -try: |
14 | - locale.setlocale(locale.LC_ALL, '') |
15 | -except: |
16 | - locale.setlocale(locale.LC_ALL, 'C') |
17 | - |
18 | +from os.path import abspath, dirname, isdir, join, pardir |
19 | import gettext |
20 | + |
21 | + |
22 | try: |
23 | from gtk import glade |
24 | loaded_glade = glade |
25 | except: |
26 | #that's not pretty but it looks functional. |
27 | loaded_glade = None |
28 | -from os.path import pardir, abspath, dirname, join |
29 | - |
30 | try: |
31 | from xdg.BaseDirectory import xdg_config_home |
32 | config_home = xdg_config_home |
33 | except ImportError: |
34 | - config_home = os.path.dirname(__file__) |
35 | - |
36 | -LOCAL_ROOTDIR = os.path.abspath(os.path.join(os.path.dirname(__file__), '..')) |
37 | -DIST_ROOTDIR_LOCAL = "/usr/local/share/gtg" |
38 | -DIST_ROOTDIR = "/usr/share/gtg" |
39 | - |
40 | -#Translation setup (from pyroom) |
41 | + config_home = dirname(__file__) |
42 | + |
43 | + |
44 | +__all__ = ('DATA_DIR', 'PLUGIN_DIR', '_', 'ngettext',) |
45 | + |
46 | + |
47 | GETTEXT_DOMAIN = 'gtg' |
48 | -LOCALE_PATH = abspath(join(dirname(__file__), pardir, 'locales')) |
49 | -if not os.path.isdir(LOCALE_PATH): |
50 | - if os.path.isdir('/usr/local/share/locale') and os.uname()[0] != 'Linux': |
51 | +# paths |
52 | +DIST_ROOTDIR = '/usr/share/gtg' |
53 | +DIST_ROOTDIR_LOCAL = '/usr/local/share/gtg' |
54 | +LOCAL_ROOTDIR = abspath(join(dirname(__file__), pardir)) |
55 | + |
56 | +### translation setup (from pyroom) |
57 | + |
58 | +# fallback to LANG C if unsupported locale |
59 | +try: |
60 | + locale.setlocale(locale.LC_ALL, '') |
61 | +except: |
62 | + locale.setlocale(locale.LC_ALL, 'C') |
63 | +# find the path containing locales |
64 | +LOCALE_PATH = join(LOCAL_ROOTDIR, 'locales') |
65 | +if not isdir(LOCALE_PATH): |
66 | + if isdir('/usr/local/share/locale') and os.uname()[0] != 'Linux': |
67 | LOCALE_PATH = '/usr/local/share/locale' |
68 | else: |
69 | LOCALE_PATH = '/usr/share/locale' |
70 | +# list the languages in use: default locale first |
71 | languages_used = [] |
72 | lc, encoding = locale.getdefaultlocale() |
73 | if lc: |
74 | - languages_used = [lc] |
75 | + languages_used.append(lc) |
76 | +# add values from the LANGUAGE environment variable |
77 | lang_in_env = os.environ.get('LANGUAGE', None) |
78 | if lang_in_env: |
79 | languages_used.extend(lang_in_env.split(':')) |
80 | - |
81 | +# set text domains in both gettext and glade. The latter avoids an error in |
82 | +# the Fedora build farm |
83 | for module in gettext, loaded_glade: |
84 | - #check if glade is well loaded to avoid error in Fedora build farm |
85 | if module: |
86 | module.bindtextdomain(GETTEXT_DOMAIN, LOCALE_PATH) |
87 | module.textdomain(GETTEXT_DOMAIN) |
88 | - |
89 | +# finally, get the translation |
90 | translation = gettext.translation(GETTEXT_DOMAIN, LOCALE_PATH, |
91 | languages=languages_used, |
92 | fallback=True) |
93 | - |
94 | _ = translation.gettext |
95 | ngettext = translation.ngettext |
96 | |
97 | -#GTG directories setup |
98 | -if os.path.isdir(os.path.join(LOCAL_ROOTDIR, 'data')): |
99 | - DATA_DIR = os.path.join(LOCAL_ROOTDIR, 'data') |
100 | -elif os.path.isdir(DIST_ROOTDIR_LOCAL): |
101 | - DATA_DIR = DIST_ROOTDIR_LOCAL |
102 | -else: |
103 | - DATA_DIR = DIST_ROOTDIR |
104 | - |
105 | -#GTG plugin dir setup |
106 | -if not os.path.isdir(os.path.join(LOCAL_ROOTDIR, 'GTG/plugins/')): |
107 | +### directory paths |
108 | + |
109 | +# find the path to the data directory |
110 | +DATA_DIR = join(LOCAL_ROOTDIR, 'data') |
111 | +if not isdir(DATA_DIR): |
112 | + if isdir(DIST_ROOTDIR_LOCAL): |
113 | + DATA_DIR = DIST_ROOTDIR_LOCAL |
114 | + else: |
115 | + DATA_DIR = DIST_ROOTDIR |
116 | + |
117 | +# find the path(s) to the plugin directory or directories |
118 | +PLUGIN_DIR = [join(LOCAL_ROOTDIR, 'GTG', 'plugins')] |
119 | +if not isdir(PLUGIN_DIR[0]): |
120 | PLUGIN_DIR = [DIST_ROOTDIR] |
121 | -else: |
122 | - PLUGIN_DIR = [os.path.join(LOCAL_ROOTDIR, 'GTG/plugins/')] |
123 | +if isdir(join(config_home, 'gtg', 'plugins')): |
124 | + PLUGIN_DIR.append(abspath(join(config_home, 'gtg', 'plugins'))) |
125 | |
126 | -if os.path.isdir(os.path.join(config_home, 'gtg/plugins')): |
127 | - PLUGIN_DIR.append(os.path.join(config_home, 'gtg/plugins')) |
128 | |
129 | === added directory 'GTG/cli' |
130 | === renamed file 'gtcli' => 'GTG/cli/__init__.py' (properties changed: +x to -x) |
131 | --- gtcli 2010-07-03 05:46:35 +0000 |
132 | +++ GTG/cli/__init__.py 2010-07-16 18:30:55 +0000 |
133 | @@ -11,52 +11,49 @@ |
134 | option) any later version. See http://www.gnu.org/copyleft/gpl.html for |
135 | the full text of the license. |
136 | ''' |
137 | - |
138 | import re |
139 | import sys |
140 | import os |
141 | import dbus |
142 | import cgi |
143 | -import getopt |
144 | import textwrap |
145 | from datetime import datetime, date, timedelta |
146 | from string import split |
147 | |
148 | +# Note: do not add imports from GTG.*! |
149 | +# The CLI interacts with GTG solely through the DBus interface. |
150 | + |
151 | + |
152 | def _(text): |
153 | return text |
154 | |
155 | + |
156 | def usage(): |
157 | - f = " %-30s %s\n" |
158 | - progname = sys.argv[0] |
159 | - |
160 | - text = _("gtcli -- a command line interface to gtg\n") |
161 | - text += "\n" |
162 | - |
163 | - text += _("Options:\n") |
164 | - text += f%( "-h, --help", _("This help") ) |
165 | - text += "\n" |
166 | - |
167 | - text += _("Basic commands:\n") |
168 | - text += f%( "gtcli new", _("Create a new task") ) |
169 | - text += f%( "gtcli show <tid>", _("Display detailed information on given task id") ) |
170 | - text += f%( "gtcli edit <tid>", _("Opens the GUI editor for the given task id") ) |
171 | - text += f%( "gtcli delete <tid>", _("Removes task identified by tid") ) |
172 | - text += f%( "gtcli list [all|today|<filter>|<tag>]...", _("List tasks") ) |
173 | - text += f%( "gtcli count [all|today|<filter>|<tag>]...", _("Number of tasks") ) |
174 | - text += f%( "gtcli summary [all|today|<filter>|<tag>]...", _("Report how many tasks starting/due each day") ) |
175 | - text += f%( "gtcli postpone <tid> <date>", _("Updates the start date of task") ) |
176 | - text += f%( "gtcli close <tid>", _("Sets state of task identified by tid to closed") ) |
177 | - text += f%( "gtcli browse [hide|show]", _("Hides or shows the task browser window")) |
178 | - |
179 | - text += "\n" |
180 | - text += "http://gtg.fritalk.com/\n" |
181 | - sys.stderr.write( text ) |
182 | + commands = [ |
183 | + ('new', _("Create a new task") ), |
184 | + ('show <tid>', _("Display detailed information on given task id") ), |
185 | + ('edit <tid>', _("Opens the GUI editor for the given task id") ), |
186 | + ('delete <tid>', _("Removes task identified by tid") ), |
187 | + ('list [SPEC]', _("List tasks") ), |
188 | + ('count [SPEC]', _("Number of tasks") ), |
189 | + ('summary [SPEC]', _("Report how many tasks starting/due each day") ), |
190 | + ('postpone <tid> <date>', _("Updates the start date of task") ), |
191 | + ('close <tid>', _("Sets state of task identified by tid to closed") ), |
192 | + ('browse [hide|show]', _("Hides or shows the task browser window")), |
193 | + ] |
194 | + |
195 | + text = 'Command-line options (with "gtg -u cli" or "gtcli"):\n' |
196 | + text += '\n'.join([' %-30s %s' % (cmd, help) for (cmd, help) in commands]) |
197 | + text += '\n\nSPEC is: all|today|<filter>|<tag>' |
198 | + return text |
199 | + |
200 | |
201 | def die(code=1, err=None): |
202 | if err: |
203 | sys.stderr.write(str(err)) |
204 | sys.exit(code) |
205 | |
206 | + |
207 | def connect_to_gtg(): |
208 | try: |
209 | bus = dbus.SessionBus() |
210 | @@ -73,16 +70,19 @@ |
211 | remote_object = bus.get_object(busname,"/org/GTG") |
212 | return dbus.Interface(remote_object,dbus_interface="org.GTG") |
213 | |
214 | + |
215 | def new_task(title, body): |
216 | """ Retrieve task via dbus """ |
217 | timi = connect_to_gtg() |
218 | timi.new_task("Active", title, '', '', '', [], body, []) |
219 | |
220 | + |
221 | def delete_task(tid): |
222 | """ Remove a task via dbus """ |
223 | timi = connect_to_gtg() |
224 | timi.delete_task(tid) |
225 | |
226 | + |
227 | def close_task(tid): |
228 | """ Marks a task closed """ |
229 | timi = connect_to_gtg() |
230 | @@ -90,6 +90,7 @@ |
231 | task_data['status'] = "Done" |
232 | timi.modify_task(tid, task_data) |
233 | |
234 | + |
235 | def show_task(tid): |
236 | """ Displays a given task """ |
237 | timi = connect_to_gtg() |
238 | @@ -111,6 +112,7 @@ |
239 | |
240 | print content |
241 | |
242 | + |
243 | def postpone(identifier, startdate): |
244 | """ Change the start date of a task """ |
245 | timi = connect_to_gtg() |
246 | @@ -129,11 +131,13 @@ |
247 | print task['id'] |
248 | timi.modify_task(task['id'], task) |
249 | |
250 | + |
251 | def open_task_editor(tid): |
252 | """ Load task in the task editor gui """ |
253 | timi = connect_to_gtg() |
254 | task_data = timi.open_task_editor(tid) |
255 | |
256 | + |
257 | def toggle_browser_visibility(state): |
258 | """ Cause the task browser to be displayed """ |
259 | timi = connect_to_gtg() |
260 | @@ -146,6 +150,7 @@ |
261 | else: |
262 | timi.show_task_browser() |
263 | |
264 | + |
265 | def _criteria_to_filters(criteria): |
266 | if not criteria: |
267 | filters = ['active'] |
268 | @@ -158,6 +163,7 @@ |
269 | filters.remove('today') |
270 | return filters |
271 | |
272 | + |
273 | def count_tasks(criteria): |
274 | """ Print a simple count of tasks matching criteria """ |
275 | |
276 | @@ -174,6 +180,7 @@ |
277 | print total |
278 | return total |
279 | |
280 | + |
281 | def summary_of_tasks(criteria): |
282 | """ Print report showing number of tasks starting and due each day """ |
283 | |
284 | @@ -222,7 +229,7 @@ |
285 | report[dstr]['due']) |
286 | else: |
287 | print "%-20s %5d %5d" %(dstr, 0, 0) |
288 | - |
289 | + |
290 | |
291 | def list_tasks(criteria, count_only=False): |
292 | """ Display a listing of tasks |
293 | @@ -271,24 +278,8 @@ |
294 | subsequent_indent=' ') |
295 | print " %-8s %s" %(task['id'], text) |
296 | |
297 | -if __name__ == '__main__': |
298 | - try: |
299 | - opts, args = getopt.gnu_getopt(sys.argv[1:], "h", ["help"]) |
300 | - except getopt.GetoptError, err: |
301 | - sys.stderr.write("Error: " + str(err) + "\n\n") |
302 | - usage() |
303 | - sys.exit(2) |
304 | - for o, a in opts: |
305 | - if o in ("-h", "--help"): |
306 | - usage() |
307 | - sys.exit(0) |
308 | - else: |
309 | - assert False, "unhandled option" |
310 | - |
311 | - if len(args) < 1: |
312 | - usage() |
313 | - sys.exit(2) |
314 | - |
315 | + |
316 | +def main(options=None, args=None): |
317 | command = args[0] |
318 | |
319 | if command == "new" or command == "add": |
320 | @@ -363,4 +354,3 @@ |
321 | else: |
322 | die("Unknown command '%s'\n" %(command)) |
323 | |
324 | - |
325 | |
326 | === modified file 'GTG/gtg.py' (properties changed: +x to -x) |
327 | --- GTG/gtg.py 2010-06-22 19:55:15 +0000 |
328 | +++ GTG/gtg.py 2010-07-16 18:30:55 +0000 |
329 | @@ -45,104 +45,95 @@ |
330 | """This is the top-level exec script for running GTG""" |
331 | |
332 | #=== IMPORT =================================================================== |
333 | +from __future__ import with_statement |
334 | import os |
335 | -import logging |
336 | - |
337 | -import dbus |
338 | - |
339 | -#our own imports |
340 | -from GTG.backends import BackendFactory |
341 | -from GTG import _ |
342 | -from GTG.core import CoreConfig |
343 | -from GTG.core.datastore import DataStore |
344 | -from GTG.gtk.crashhandler import signal_catcher |
345 | -from GTG.gtk.manager import Manager |
346 | -from GTG.tools.logger import Log |
347 | - |
348 | -#=== OBJECTS ================================================================== |
349 | - |
350 | -#code borrowed from Specto. Avoid having multiples instances of gtg |
351 | -#reading the same tasks |
352 | -#that's why we put the pid file in the data directory : |
353 | -#we allow one instance of gtg by data directory. |
354 | - |
355 | -def check_instance(directory): |
356 | - """Check if gtg is already running.""" |
357 | - pidfile = os.path.join(directory, "gtg.pid") |
358 | - if not os.path.exists(pidfile): |
359 | - open(pidfile, "w").close() |
360 | - os.chmod(pidfile, 0600) |
361 | - |
362 | - #see if gtg is already running |
363 | - pid = open(pidfile, "r").readline() |
364 | - if pid: |
365 | - p = os.system("/bin/ps %s >/dev/null" % pid) |
366 | - p_name = os.popen("/bin/ps -f %s" % pid).read() |
367 | - if p == 0 and "gtg" in p_name: |
368 | - print _("gtg is already running!") |
369 | - d=dbus.SessionBus().get_object(CoreConfig.BUSNAME,\ |
370 | - CoreConfig.BUSINTERFACE) |
371 | - d.show_task_browser() |
372 | - raise SystemExit |
373 | - |
374 | - #write the pid file |
375 | - with open(pidfile, "w") as f: |
376 | - f.write(`os.getpid()`) |
377 | - |
378 | -#=== MAIN CLASS =============================================================== |
379 | + |
380 | +# No GTG imports here; add them under the appropriate section of main(). |
381 | + |
382 | |
383 | def main(options=None, args=None): |
384 | - ''' |
385 | - Calling this starts the full GTG experience ( :-D ) |
386 | - ''' |
387 | - config, ds, req = core_main_init(options, args) |
388 | - # Launch task browser |
389 | - manager = Manager(req, config) |
390 | - #main loop |
391 | - #To be more user friendly and get the logs of crashes, we show an apport |
392 | - # hooked window upon crashes |
393 | - with signal_catcher(manager.close_browser): |
394 | - manager.main() |
395 | - core_main_quit(config, ds) |
396 | - |
397 | -def core_main_init(options = None, args = None): |
398 | - ''' |
399 | - Part of the main function prior to the UI initialization. |
400 | - ''' |
401 | - # Debugging subsystem initialization |
402 | + '''Run GTG according to user options & arguments.''' |
403 | + # debugging system: start, if the user asked for it |
404 | if options.debug: |
405 | + import logging |
406 | + from GTG.tools.logger import Log |
407 | Log.setLevel(logging.DEBUG) |
408 | - Log.debug("Debug output enabled.") |
409 | + Log.debug('Debug output enabled.') |
410 | Log.set_debugging_mode(True) |
411 | - config = CoreConfig() |
412 | - check_instance(config.get_data_dir()) |
413 | - backends_list = BackendFactory().get_saved_backends_list() |
414 | - # Load data store |
415 | - ds = DataStore() |
416 | - # Register backends |
417 | - for backend_dic in backends_list: |
418 | - ds.register_backend(backend_dic) |
419 | - #save directly the backends to be sure to write projects.xml |
420 | - ds.save(quit = False) |
421 | + # launch one or another of the user interfaces |
422 | + if options.interface == 'cli': |
423 | + # the command-line interface |
424 | + import GTG.cli |
425 | + return GTG.cli.main(options, args) |
426 | + elif options.interface == 'gtk': |
427 | + # TODO: separate the backend and GTK parts of this code block |
428 | + # import a lot of stuff not needed for the CLI |
429 | + from contextlib import contextmanager |
430 | |
431 | - # Launch task browser |
432 | - req = ds.get_requester() |
433 | - return config, ds, req |
434 | - |
435 | -def core_main_quit(config, ds): |
436 | - ''' |
437 | - Last bits of code executed in GTG, after the UI has been shut off. |
438 | - Currently, it's just saving everything. |
439 | - ''' |
440 | - # Ideally we should load window geometry configuration from a config. |
441 | - # backend like gconf at some point, and restore the appearance of the |
442 | - # application as the user last exited it. |
443 | - # |
444 | - # Ending the application: we save configuration |
445 | - config.save() |
446 | - ds.save(quit = True) |
447 | - |
448 | -#=== EXECUTION ================================================================ |
449 | - |
450 | -if __name__ == "__main__": |
451 | - main() |
452 | + from GTG import _, info |
453 | + from GTG.backends import BackendFactory |
454 | + from GTG.core import CoreConfig |
455 | + from GTG.core.datastore import DataStore |
456 | + from GTG.gtk.crashhandler import signal_catcher |
457 | + from GTG.gtk.manager import Manager |
458 | + |
459 | + def check_instance(config): |
460 | + '''Check if gtg is already running. |
461 | + |
462 | + Code borrowed from Specto. Avoid having multiples instances of gtg |
463 | + reading the same tasks. That's why we put the pid file in the data |
464 | + directory; we allow one instance of gtg by data directory. |
465 | + |
466 | + ''' |
467 | + # file containing the process ID |
468 | + pidfile = os.path.join(config.get_data_dir(), 'gtg.pid') |
469 | + # create the pidfile if necessary |
470 | + if not os.path.exists(pidfile): |
471 | + open(pidfile, 'w').close() |
472 | + os.chmod(pidfile, 0600) |
473 | + # see if gtg is already running |
474 | + pid = open(pidfile, 'r').readline() |
475 | + if pid: |
476 | + # the file contained a PID! Check if it's stale or not |
477 | + p = os.system('/bin/ps %s >/dev/null' % pid) |
478 | + p_name = os.popen('/bin/ps -f %s' % pid).read() |
479 | + if p == 0 and 'gtg' in p_name: |
480 | + print _('gtg is already running!') |
481 | + # raise the TaskBrowser for the user |
482 | + import dbus |
483 | + d = dbus.SessionBus().get_object(config.BUSNAME, |
484 | + config.BUSINTERFACE) |
485 | + d.show_task_browser() |
486 | + raise SystemExit |
487 | + # write the current PID |
488 | + with open(pidfile, 'w') as f: |
489 | + f.write(`os.getpid()`) |
490 | + |
491 | + # check that the X server is running |
492 | + if 'DISPLAY' not in os.environ: |
493 | + raise SystemExit(1) |
494 | + # load configuration information |
495 | + config = CoreConfig() |
496 | + # check that GTG is not already running |
497 | + check_instance(config) |
498 | + # load data store and register configured backends |
499 | + ds = DataStore() |
500 | + for backend_dic in BackendFactory().get_saved_backends_list(): |
501 | + ds.register_backend(backend_dic) |
502 | + # save directly the backends to be sure to write projects.xml |
503 | + ds.save(quit = False) |
504 | + # get a Requester object and start the ViewManager |
505 | + req = ds.get_requester() |
506 | + manager = Manager(req, config) |
507 | + # TODO: ideally we should load window geometry configuration from a |
508 | + # config.backend like gconf at some point, and restore the |
509 | + # appearance of the application as the user last exited it. |
510 | + |
511 | + # we listen for signals from the system in order to save our |
512 | + # configuration if GTG is forcefully terminated (e.g.: on shutdown). |
513 | + with signal_catcher(manager.close_browser): |
514 | + manager.main() |
515 | + # Ending the application: we save configuration |
516 | + config.save() |
517 | + ds.save(quit=True) |
518 | + |
519 | |
520 | === added file 'gtcli' |
521 | --- gtcli 1970-01-01 00:00:00 +0000 |
522 | +++ gtcli 2010-07-16 18:30:55 +0000 |
523 | @@ -0,0 +1,12 @@ |
524 | +#!/bin/sh -e |
525 | + |
526 | +# Copyright (c) 2010 Paul Kishimoto |
527 | +# |
528 | +# This file is part of Getting Things GNOME!. Getting Things GNOME! is free |
529 | +# software; you can redistribute it and/or modify it under the terms of the GNU |
530 | +# General Public License as published by the Free Software Foundation, either |
531 | +# version 3 of the License, or (at your option) any later version. See the file |
532 | +# LICENSE or <http://www.gnu.org/licenses/> for the full text of the license. |
533 | + |
534 | +exec gtg -u cli "$@" |
535 | + |
536 | |
537 | === modified file 'gtg' |
538 | --- gtg 2010-06-02 18:12:23 +0000 |
539 | +++ gtg 2010-07-16 18:30:55 +0000 |
540 | @@ -26,31 +26,27 @@ |
541 | :copyright: 2008,2009 Lionel Dricot & Bertrand Rousseau |
542 | :license: GNU General Public License, version 3 or later |
543 | """ |
544 | - |
545 | -import sys |
546 | -from optparse import OptionParser |
547 | - |
548 | - |
549 | -def X_is_running(): |
550 | - from subprocess import Popen, PIPE |
551 | - p = Popen(["xset", "-q"], stdout=PIPE, stderr=PIPE) |
552 | - p.communicate() |
553 | - return p.returncode == 0 |
554 | - |
555 | - |
556 | -try: |
557 | - parser = OptionParser() |
558 | - parser.add_option('-d', '--debug', action='store_true', dest='debug', |
559 | - help="enable debug output", default=False) |
560 | - (options, args) = parser.parse_args() |
561 | - |
562 | - if not X_is_running(): |
563 | - print "Could not open X display" |
564 | - sys.exit(1) |
565 | - |
566 | - else: |
567 | - import GTG.gtg |
568 | - sys.exit(GTG.gtg.main(options, args)) |
569 | - |
570 | -except KeyboardInterrupt: |
571 | - sys.exit(1) |
572 | +from optparse import OptionGroup, OptionParser |
573 | +import os # capture DISPLAY: http://docs.python.org/library/os.html#os.environ |
574 | + |
575 | +from GTG.cli import usage |
576 | +# No GTG.* imports here; add them in GTG/gtg.py instead. |
577 | + |
578 | + |
579 | +parser = OptionParser(usage='%prog [options] [[command] [command_opts]] \n\n' + |
580 | + usage()) |
581 | +# options common to all invocations of 'gtg' |
582 | +parser.add_option('-d', '--debug', action='store_true', dest='debug', |
583 | + help="enable debug output", default=False) |
584 | +parser.add_option('-u', '--interface', dest='interface', choices=('cli', |
585 | + 'gtk', 'none',), default='gtk', metavar='IFACE', help='Use the IFACE user ' |
586 | + 'interface. Available UIs: gtk (default), cli, none.') |
587 | +# parse command-line options |
588 | +(options, args) = parser.parse_args() |
589 | +if options.interface == 'cli' and len(args) < 1: |
590 | + parser.print_help() |
591 | + raise SystemExit(2) |
592 | +# if that wasn't a problem, run the application! |
593 | +import GTG.gtg |
594 | +raise SystemExit(GTG.gtg.main(options, args)) |
595 | + |
596 | |
597 | === modified file 'gtg_new_task' |
598 | --- gtg_new_task 2010-02-08 11:08:25 +0000 |
599 | +++ gtg_new_task 2010-07-16 18:30:55 +0000 |
600 | @@ -1,77 +1,12 @@ |
601 | -#!/usr/bin/env python |
602 | -# -*- coding:utf-8 -*- |
603 | - |
604 | -# ----------------------------------------------------------------------------- |
605 | -# Getting Things Gnome! - A personal organizer for the GNOME desktop |
606 | -# Copyright (c) 2008,2009 Lionel Dricot & Bertrand Rousseau |
607 | -# |
608 | -# This program is free software: you can redistribute it and/or modify it under |
609 | -# the terms of the GNU General Public License as published by the Free Software |
610 | -# Foundation, either version 3 of the License, or (at your option) any later |
611 | -# version. |
612 | -# |
613 | -# This program is distributed in the hope that it will be useful, but WITHOUT |
614 | -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
615 | -# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more |
616 | -# details. |
617 | -# |
618 | -# You should have received a copy of the GNU General Public License along with |
619 | -# this program. If not, see <http://www.gnu.org/licenses/>. |
620 | -# ----------------------------------------------------------------------------- |
621 | - |
622 | -""" |
623 | -This script create a new task and launch the editor to display it. GTG should be running |
624 | -""" |
625 | - |
626 | -import re |
627 | -import sys |
628 | -import dbus |
629 | -import cgi |
630 | -import getopt |
631 | -from GTG import _ |
632 | - |
633 | -def get_task(title, body) : |
634 | - #We will connect on the session bus |
635 | - bus = dbus.SessionBus() |
636 | - liste = bus.list_names() |
637 | - busname = "org.GTG" |
638 | - remote_object = bus.get_object(busname,"/org/GTG") |
639 | - timi = dbus.Interface(remote_object,dbus_interface="org.GTG") |
640 | - #Calling the method |
641 | - timi.open_new_task(title, body) |
642 | - |
643 | -def usage(): |
644 | - print _("Usage: %s [-i | --interactive] [-h | --help]") % sys.argv[0] |
645 | - |
646 | -if __name__ == '__main__': |
647 | - interactive = False |
648 | - #Command line options handling |
649 | - try: |
650 | - opts, args = getopt.getopt(sys.argv[1:], "hi", ["help", "interactive"]) |
651 | - except getopt.GetoptError, err: |
652 | - # print help information and exit: |
653 | - print str(err) # will print something like "option -a not recognized" |
654 | - usage() |
655 | - sys.exit(2) |
656 | - for o, a in opts: |
657 | - if o in ("-i", "--interactive"): |
658 | - interactive = True |
659 | - elif o in ("-h", "--help"): |
660 | - usage() |
661 | - sys.exit() |
662 | - else: |
663 | - assert False, "unhandled option" |
664 | - |
665 | - title = " ".join(args) |
666 | - if interactive: |
667 | - optlist, args = getopt.getopt(args, 'i::') |
668 | - body = sys.stdin.read() |
669 | - subject_regex = re.compile("^Subject: (.*)$", re.M | re.I) |
670 | - if subject_regex.search(body): |
671 | - subject = subject_regex.findall(body)[0] |
672 | - title = title + ": " + subject |
673 | - else: |
674 | - body = "" |
675 | - get_task(title, cgi.escape(body)) |
676 | - |
677 | +#!/bin/sh -e |
678 | + |
679 | +# Copyright (c) 2010 Paul Kishimoto |
680 | +# |
681 | +# This file is part of Getting Things GNOME!. Getting Things GNOME! is free |
682 | +# software; you can redistribute it and/or modify it under the terms of the GNU |
683 | +# General Public License as published by the Free Software Foundation, either |
684 | +# version 3 of the License, or (at your option) any later version. See the file |
685 | +# LICENSE or <http://www.gnu.org/licenses/> for the full text of the license. |
686 | + |
687 | +exec gtg -u cli new "$@" |
688 |
Seems good but I want Bryce opinion on this.