Merge lp:~quickly-committers/quickly/add_widgets into lp:quickly
- add_widgets
- Merge into trunk
Status: | Needs review |
---|---|
Proposed branch: | lp:~quickly-committers/quickly/add_widgets |
Merge into: | lp:quickly |
Diff against target: |
759 lines (+334/-147) 16 files modified
data/templates/ubuntu-application/add.py (+164/-26) data/templates/ubuntu-application/configure.py (+2/-3) data/templates/ubuntu-application/create.py (+1/-1) data/templates/ubuntu-application/edit.py (+2/-1) data/templates/ubuntu-application/internal/apportutils.py (+2/-2) data/templates/ubuntu-application/internal/quicklyutils.py (+0/-62) data/templates/ubuntu-application/store/dialog.py (+3/-3) data/templates/ubuntu-application/store/help-guide.py (+1/-1) data/templates/ubuntu-application/store/help-topic.py (+1/-1) data/templates/ubuntu-application/store/indicator.py (+1/-1) data/templates/ubuntu-application/upgrade.py (+1/-1) data/templates/ubuntu-flash-game/create.py (+1/-1) data/templates/ubuntu-flash-game/internal/apportutils.py (+4/-3) data/templates/ubuntu-flash-game/internal/quicklyutils.py (+0/-40) quickly/builtincommands.py (+33/-1) quickly/templatetools.py (+118/-0) |
To merge this branch: | bzr merge lp:~quickly-committers/quickly/add_widgets |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Quickly Developers | Pending | ||
Review via email: mp+62222@code.launchpad.net |
Commit message
Description of the change
Allows $quickly add to add files from outside a quickly template
Tony Byrne (tony-badwolf) wrote : | # |
The point of this branch is for the developer who wants to make a
small modification to the template but have most of it maintained by
quickly-
pull in the developer's mods to the project itself.
Without $quickly add <outside files> means that the developer needs to
$quickly create ubuntu-application app. Then put in his favourite
files manually, app/app/foo.py, app/tests/
contents of test_foo.py so it can import app.foo.
Imagine having commands like
$quickly add foo that does all of the above
$quickly add company-logo (not general enough for quickly)
$quickly add dbus-client
$quickly add dbus-server
$quickly add threading (unpopular)
Using quickly-widgets is only a proof of concept - the simplest
plugin does not need to conform to any requirements. $quickly help add
can read the plugin docstring but doesn't require it.
A complex plugin will have a loader like store/dialog.py.
The primary use case, developer's favourite files, are unlikely to be
importable on the target box.
On 27/05/2011, Michael Terry <email address hidden> wrote:
> This would be a lot easier to read if the ide branch wasn't interwoven. You
> can specify a prerequisite branch when filing a merge (and unfortunately,
> seemingly only then) which would hide that prerequisite branch on this page.
> Just FYI. For now I can review this using bzr directly.
>
> Changes like this and the preferences might best be discussed on
> quickly-talk first, to get a sense of your direction and the technical
> ramifications. Especially if the discussion might change how you implement
> it (so you don't waste work).
>
> I'm not sure what the goal of adding outside files from quickly widgets is?
> Quickly widgets is an external library meant to be used like any other
> python library, not pulled in directly.
> --
> https:/
> You proposed lp:~quickly-committers/quickly/add_widgets for merging.
>
Unmerged revisions
- 622. By Tony Byrne <email address hidden>
-
moved function file_from_
template( ...) from quicklyutils to templatetools
updated $quickly preferences command (introduced in branch ide) to display default values
$quickly add command can add files from outside quickly
default outside files are from quickly-widgets - 621. By Tony Byrne <email address hidden>
-
removed some junk
- 620. By Tony Byrne <email address hidden>
-
allow preferences to be edited outside project
removed quickly configure preferences
added quickly preferences
moved read_input from templates/ubuntu- application/ quicklyutils. py
to quickly/templatetools. py - 619. By Tony Byrne <email address hidden>
-
added command configure preferences
- 618. By Tony Byrne <email address hidden>
-
moved get_quickly_
editors( ) into templatetools: same code for all templates
use a config file to allow developer use an ide for editing project keeping gedit for read_input()
Preview Diff
1 | === modified file 'data/templates/ubuntu-application/add.py' |
2 | --- data/templates/ubuntu-application/add.py 2010-11-12 00:28:53 +0000 |
3 | +++ data/templates/ubuntu-application/add.py 2011-05-24 23:28:25 +0000 |
4 | @@ -16,61 +16,199 @@ |
5 | #You should have received a copy of the GNU General Public License along |
6 | #with this program. If not, see <http://www.gnu.org/licenses/>. |
7 | |
8 | +'''Add something to your project |
9 | + |
10 | +where something can identify a python file or a script |
11 | +usual role for script is to mangle a file, load non-python files, or both''' |
12 | + |
13 | +import ast |
14 | +import glob |
15 | +import os.path |
16 | +import subprocess |
17 | import sys |
18 | -from quickly import templatetools, commands |
19 | - |
20 | -import gettext |
21 | -from gettext import gettext as _ |
22 | + |
23 | + |
24 | +from gettext import textdomain, gettext as _ |
25 | # set domain text |
26 | -gettext.textdomain('quickly') |
27 | +textdomain('quickly') |
28 | |
29 | -argv = sys.argv |
30 | +from quickly import templatetools, commands, configurationhandler |
31 | |
32 | from store import * |
33 | import store |
34 | |
35 | -addable = [x for x in dir(store) if x[0] != '_'] |
36 | +ADDABLE = [x for x in dir(store) if x[0] != '_'] |
37 | |
38 | -options = {} |
39 | -for module in addable: |
40 | +OPTIONS = {} |
41 | +for module in ADDABLE: |
42 | try: |
43 | - options[module] = getattr(store, module).option |
44 | + OPTIONS[module] = getattr(store, module).option |
45 | except AttributeError: |
46 | # ignore files in store that have no option for us |
47 | pass |
48 | |
49 | +# if config not already loaded |
50 | +if not configurationhandler.project_config: |
51 | + configurationhandler.loadConfig() |
52 | + PROJECT_CONFIG = configurationhandler.project_config |
53 | + |
54 | +def get_options_from_plugin(plugin): |
55 | + '''if the plugin needs options it should describe them''' |
56 | + |
57 | + quickly_options = '' |
58 | + for subnode in ast.iter_child_nodes(plugin[2]): |
59 | + if type(subnode) == ast.Assign: |
60 | + |
61 | + result_as_dict = {} |
62 | + for item in ast.iter_child_nodes(subnode): |
63 | + field = dict(ast.iter_fields(item)) |
64 | + if field.get('id') == 'QUICKLY_OPTIONS': |
65 | + result_as_dict['id'] = 'QUICKLY_OPTIONS' |
66 | + if field.get('s') is not None: |
67 | + result_as_dict['s'] = field.get('s') |
68 | + |
69 | + if result_as_dict.get('id') == 'QUICKLY_OPTIONS': |
70 | + quickly_options = result_as_dict.get('s') |
71 | + |
72 | + result = 'quickly add %s %s' % (plugin[0], quickly_options) |
73 | + return result |
74 | + |
75 | + |
76 | +def get_plugins_from_path(_path): |
77 | + '''parse plugin files using ast''' |
78 | + _path = os.path.expanduser(_path) |
79 | + globs = glob.glob('%s/*' % _path) |
80 | + # get only files |
81 | + plugin_files = [y for y in globs if os.path.isfile(y)] |
82 | + # exclude __init__.py |
83 | + plugin_files = [y for y in plugin_files if os.path.basename(y)[0] != '_'] |
84 | + |
85 | + _basenames = [os.path.basename(y) for y in plugin_files] |
86 | + _names = [os.path.splitext(y)[0] for y in _basenames] |
87 | + |
88 | + nodes = [] |
89 | + for plugin_file in plugin_files: |
90 | + with open(plugin_file) as filepointer: |
91 | + contents = filepointer.read() |
92 | + node = ast.parse(contents) |
93 | + nodes.append(node) |
94 | + |
95 | + plugin_list = zip(_names, plugin_files, nodes) |
96 | + results = [(y[0], y[1:]) for y in plugin_list] |
97 | + |
98 | + _adds = [get_options_from_plugin(y) for y in plugin_list] |
99 | + |
100 | + plugin_options = zip(_names, _adds) |
101 | + OPTIONS.update(plugin_options) |
102 | + |
103 | + return results |
104 | + |
105 | +PLUGIN_PATH = templatetools.option( |
106 | + PROJECT_CONFIG['template'], 'plugin_path') |
107 | + |
108 | +PLUGINS = {} |
109 | +PLUGIN_PATHS = PLUGIN_PATH.split(':') |
110 | +for path in PLUGIN_PATHS: |
111 | + # handle preference with superfluous colons e.g. plugin_path = :::/path1: |
112 | + if len(path): |
113 | + PLUGINS.update(get_plugins_from_path(path)) |
114 | + |
115 | +def get_help_from_plugin(_plugin_name): |
116 | + 'use first line of docstring as help text' |
117 | + |
118 | + _docstring = ast.get_docstring(PLUGINS.get(_plugin_name)[1], clean=True) |
119 | + if _docstring is not None: |
120 | + docstring_lines = _docstring.split('\n') |
121 | + help_text = docstring_lines[0] |
122 | + else: |
123 | + help_text = 'no help for %s yet' % _plugin_name |
124 | + |
125 | + return '%s\n%s' % (_plugin_name, help_text) |
126 | + |
127 | +def insert_plugin(chosen_plugin): |
128 | + '''copy plugin to project |
129 | + or run plugin in project''' |
130 | + _path = chosen_plugin[0] |
131 | + if not os.access(_path, os.X_OK): |
132 | + project_name = PROJECT_CONFIG['project'] |
133 | + python_name = templatetools.python_name(project_name) |
134 | + |
135 | + #to add non-python files use a runnable plugin script |
136 | + target_dir = os.path.join(os.getcwd(), python_name) |
137 | + templatetools.file_from_template( |
138 | + '', _path, target_dir, [], False) |
139 | + else: |
140 | + # run a plugin script - similar to store/dialog.py |
141 | + _instance = subprocess.Popen([_path] + sys.argv[2:], cwd=os.getcwd()) |
142 | + _instance.wait() |
143 | + |
144 | +# skeleton for runnable plugin script |
145 | +"""#!/usr/bin/python |
146 | +# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- |
147 | +### BEGIN LICENSE |
148 | +# This file is in the public domain |
149 | +### END LICENSE |
150 | + |
151 | +'''A simple plugin''' |
152 | +import os |
153 | +import sys |
154 | + |
155 | +QUICKLY_OPTIONS = '<option>' |
156 | + |
157 | +if __name__ == "__main__": |
158 | + SRC, DEST = os.path.dirname(os.path.abspath(__file__)), os.getcwd() |
159 | + print __doc__ |
160 | + print 'plugin files path', SRC |
161 | + print 'quickly project path', DEST |
162 | + print 'options', sys.argv |
163 | + assert SRC != DEST """ |
164 | + |
165 | def usage(): |
166 | - templatetools.print_usage(options.values()) |
167 | + '''a quickly API''' |
168 | + templatetools.print_usage(OPTIONS.values()) |
169 | |
170 | -def help(): |
171 | +def help(): # pylint: disable=W0622 |
172 | + '''a quickly API''' |
173 | help_list = [_('Add something to your project\n')] |
174 | - for module in addable: |
175 | + for store_module in ADDABLE: |
176 | try: |
177 | - help_list.append(getattr(store, module).help_text) |
178 | + help_list.append(getattr(store, store_module).help_text) |
179 | except AttributeError: |
180 | # ignore files in store that have no help for us |
181 | pass |
182 | + for plugin in PLUGINS: |
183 | + help_list.append(get_help_from_plugin(plugin)) |
184 | + |
185 | help_text = '\n\n'.join(help_list) |
186 | print help_text |
187 | |
188 | +ARGV = sys.argv |
189 | + |
190 | def shell_completion(argv): |
191 | ''' Complete args ''' |
192 | # option completion |
193 | - rv = [] |
194 | + allowable_args = [] |
195 | if len(argv) == 1: |
196 | - rv = options.keys() |
197 | - if rv: |
198 | - rv.sort() |
199 | - print ' '.join(rv) |
200 | -templatetools.handle_additional_parameters(sys.argv, help, shell_completion, usage=usage) |
201 | + allowable_args = OPTIONS.keys() |
202 | + if allowable_args: |
203 | + allowable_args.sort() |
204 | + print ' '.join(allowable_args) |
205 | + |
206 | +templatetools.handle_additional_parameters( |
207 | + sys.argv, help, shell_completion, usage=usage) |
208 | |
209 | if len(sys.argv) < 2: |
210 | - cmd = commands.get_command('add', 'ubuntu-application') |
211 | - templatetools.usage_error(_("Cannot add, no plugin name provided."), cmd=cmd, template='ubuntu-application') |
212 | + CMD = commands.get_command('add', 'ubuntu-application') |
213 | + templatetools.usage_error(_("Cannot add, no plugin name provided."), |
214 | + cmd=CMD, template='ubuntu-application') |
215 | |
216 | -if argv[1] in addable: |
217 | - getattr(store, argv[1]).add(options) |
218 | +if sys.argv[1] in ADDABLE: |
219 | + getattr(store, sys.argv[1]).add(OPTIONS) |
220 | +elif sys.argv[1] in PLUGINS.keys(): |
221 | + insert_plugin(PLUGINS[sys.argv[1]]) |
222 | else: |
223 | - cmd = commands.get_command('add', 'ubuntu-application') |
224 | - templatetools.usage_error(_('Cannot add, did not recognize plugin name: %s' % argv[1]), cmd=cmd, template='ubuntu-application') |
225 | + CMD = commands.get_command('add', 'ubuntu-application') |
226 | + templatetools.usage_error( |
227 | + _('Cannot add, did not recognize plugin name: %s' % sys.argv[1]), |
228 | + cmd=CMD, template='ubuntu-application') |
229 | sys.exit(4) |
230 | |
231 | === modified file 'data/templates/ubuntu-application/configure.py' |
232 | --- data/templates/ubuntu-application/configure.py 2010-10-18 18:39:04 +0000 |
233 | +++ data/templates/ubuntu-application/configure.py 2011-05-24 23:28:25 +0000 |
234 | @@ -82,7 +82,7 @@ |
235 | if len(argv) > 2: |
236 | project_name = argv[2] |
237 | else: |
238 | - project_name = quicklyutils.read_input() |
239 | + project_name = templatetools.read_input() |
240 | # need to try and get the original project name if it exists. We'll need this |
241 | # to replace any existing settings |
242 | if not configurationhandler.project_config: |
243 | @@ -158,7 +158,7 @@ |
244 | dependencies = [elem.strip() for elem in configurationhandler.project_config['dependencies'].split(',') if elem] |
245 | except KeyError: |
246 | dependencies = [] |
247 | - userinput = quicklyutils.read_input('\n'.join(dependencies)) |
248 | + userinput = templatetools.read_input('\n'.join(dependencies)) |
249 | dependencies = [] |
250 | for depends in userinput.split('\n'): |
251 | dependencies.extend([elem.strip() for elem in depends.split(',') if elem]) |
252 | @@ -174,4 +174,3 @@ |
253 | configurationhandler.loadConfig() |
254 | configurationhandler.project_config["target_distribution"] = argv[2] |
255 | configurationhandler.saveConfig() |
256 | - |
257 | |
258 | === modified file 'data/templates/ubuntu-application/create.py' |
259 | --- data/templates/ubuntu-application/create.py 2011-02-08 14:30:08 +0000 |
260 | +++ data/templates/ubuntu-application/create.py 2011-05-24 23:28:25 +0000 |
261 | @@ -90,7 +90,7 @@ |
262 | directory = directory.replace('python', python_name) |
263 | os.mkdir(os.path.join(relative_dir, directory)) |
264 | for filename in files: |
265 | - quicklyutils.file_from_template(root, filename, relative_dir, substitutions) |
266 | + templatetools.file_from_template(root, filename, relative_dir, substitutions) |
267 | |
268 | # set the mode to executable for executable file |
269 | exec_file = os.path.join('bin', project_name) |
270 | |
271 | === modified file 'data/templates/ubuntu-application/edit.py' |
272 | --- data/templates/ubuntu-application/edit.py 2011-04-27 15:02:41 +0000 |
273 | +++ data/templates/ubuntu-application/edit.py 2011-05-24 23:28:25 +0000 |
274 | @@ -65,7 +65,8 @@ |
275 | # add helpfile sources |
276 | filelist.extend(glob.glob('help/C/*.page')) |
277 | |
278 | -editor = quicklyutils.get_quickly_editors() |
279 | +editor = templatetools.get_ide(configurationhandler.project_config['template']) |
280 | + |
281 | if templatetools.in_verbose_mode(): |
282 | instance = subprocess.Popen([editor] + filelist) |
283 | else: |
284 | |
285 | === modified file 'data/templates/ubuntu-application/internal/apportutils.py' |
286 | --- data/templates/ubuntu-application/internal/apportutils.py 2011-04-04 14:28:36 +0000 |
287 | +++ data/templates/ubuntu-application/internal/apportutils.py 2011-05-24 23:28:25 +0000 |
288 | @@ -80,13 +80,13 @@ |
289 | print _("Creating new apport crashdb configuration") |
290 | if not os.path.isdir(relative_crashdb_dir): |
291 | os.makedirs(relative_crashdb_dir) |
292 | - quicklyutils.file_from_template(template_crashdb_dir, "project_name-crashdb.conf", relative_crashdb_dir, subst_new) |
293 | + templatetools.file_from_template(template_crashdb_dir, "project_name-crashdb.conf", relative_crashdb_dir, subst_new) |
294 | |
295 | if not os.path.isfile(existing_hook) and os.path.isdir(template_hook_dir): |
296 | print _("Creating new apport hooks") |
297 | if not os.path.isdir(relative_apport_dir): |
298 | os.makedirs(relative_apport_dir) |
299 | - quicklyutils.file_from_template(template_hook_dir, "source_project_name.py", relative_apport_dir, subst_new) |
300 | + templatetools.file_from_template(template_hook_dir, "source_project_name.py", relative_apport_dir, subst_new) |
301 | |
302 | def insert_lpi_if_required(project_name): |
303 | camel_case_project_name = quickly.templatetools.get_camel_case_name(project_name) |
304 | |
305 | === modified file 'data/templates/ubuntu-application/internal/quicklyutils.py' |
306 | --- data/templates/ubuntu-application/internal/quicklyutils.py 2011-03-02 15:04:44 +0000 |
307 | +++ data/templates/ubuntu-application/internal/quicklyutils.py 2011-05-24 23:28:25 +0000 |
308 | @@ -43,30 +43,6 @@ |
309 | camel_case_name = templatetools.get_camel_case_name(name) |
310 | return sentence_name, camel_case_name |
311 | |
312 | -def file_from_template(template_dir, template_file, target_dir, substitutions=[], rename = True): |
313 | - |
314 | - if not os.path.isfile(os.path.join(template_dir, template_file)): |
315 | - return |
316 | - target_file = os.path.basename(template_file) # to get only file name (template_file can be internal/file) |
317 | - if rename: |
318 | - for s in substitutions: |
319 | - pattern, sub = s |
320 | - target_file = target_file.replace(pattern,sub) |
321 | - |
322 | - fin = open(os.path.join(template_dir, template_file),'r') |
323 | - file_contents = fin.read() |
324 | - for s in substitutions: |
325 | - pattern, sub = s |
326 | - file_contents = file_contents.replace(pattern,sub) |
327 | - |
328 | - target_path = os.path.join(target_dir, target_file) |
329 | - if os.path.exists(target_path): |
330 | - print _("Failed to add file to project\n cannot add: %s - this file already exists." % target_path) |
331 | - sys.exit(4) |
332 | - |
333 | - templatetools.set_file_contents(target_path, file_contents) |
334 | - fin.close() |
335 | - |
336 | def update_file(target_file, substitutions=[], rename = True): |
337 | |
338 | if not os.path.isfile(target_file): |
339 | @@ -229,44 +205,6 @@ |
340 | buffered_message +=' %s' % line |
341 | return(changelog) |
342 | |
343 | - |
344 | -def get_quickly_editors(): |
345 | - '''Return prefered editor for ubuntu-application template''' |
346 | - |
347 | - default_editor = os.environ.get("QUICKLY_EDITOR") |
348 | - if not default_editor: |
349 | - default_editor = os.environ.get("EDITOR") |
350 | - if not default_editor: |
351 | - default_editor = os.environ.get("SELECTED_EDITOR") |
352 | - if default_editor: |
353 | - editor = default_editor |
354 | - elif templatetools.is_X_display(): |
355 | - editor = "gedit" |
356 | - else: |
357 | - editor = "nano" |
358 | - return editor |
359 | - |
360 | -def read_input(start=''): |
361 | - depfile_name = tempfile.mkstemp()[1] |
362 | - open(depfile_name,'w').write(start) |
363 | - |
364 | - # Run the editor with a new tmpdir. This is because gedit uses tmpdir |
365 | - # to find other instances of gedit, and we don't want that. If we allowed |
366 | - # that, gedit would return immediately and open a new tab in the other |
367 | - # gedit. This makes it difficult to tell when user is done editing (how |
368 | - # to detect that vs nano opening and closing without the user saving it?). |
369 | - editor = get_quickly_editors() |
370 | - subenv = dict(os.environ) |
371 | - subenv['TMPDIR'] = tempfile.mkdtemp() |
372 | - subprocess.call([editor, depfile_name], stdout=subprocess.PIPE, env=subenv) |
373 | - os.rmdir(subenv['TMPDIR']) |
374 | - |
375 | - # Grab file contents |
376 | - rv = file(depfile_name, 'r').read().strip() |
377 | - os.remove(depfile_name) |
378 | - |
379 | - return rv |
380 | - |
381 | def take_email_from_string(value): |
382 | '''Try to take an email from a string''' |
383 | |
384 | |
385 | === modified file 'data/templates/ubuntu-application/store/dialog.py' |
386 | --- data/templates/ubuntu-application/store/dialog.py 2010-11-12 00:28:53 +0000 |
387 | +++ data/templates/ubuntu-application/store/dialog.py 2011-05-24 23:28:25 +0000 |
388 | @@ -109,17 +109,17 @@ |
389 | ("dialog_sentence_name",dialog_sentence_name), |
390 | ("python_name",python_name)) |
391 | |
392 | - quicklyutils.file_from_template(template_ui_dir, |
393 | + templatetools.file_from_template(template_ui_dir, |
394 | "dialog_camel_case_nameDialog.ui", |
395 | target_ui_dir, |
396 | substitutions) |
397 | |
398 | - quicklyutils.file_from_template(template_ui_dir, |
399 | + templatetools.file_from_template(template_ui_dir, |
400 | "dialog_python_name_dialog.xml", |
401 | target_ui_dir, |
402 | substitutions) |
403 | |
404 | - quicklyutils.file_from_template(template_python_dir, |
405 | + templatetools.file_from_template(template_python_dir, |
406 | "dialog_camel_case_nameDialog.py", |
407 | target_python_dir, |
408 | substitutions) |
409 | |
410 | === modified file 'data/templates/ubuntu-application/store/help-guide.py' |
411 | --- data/templates/ubuntu-application/store/help-guide.py 2010-11-22 16:01:03 +0000 |
412 | +++ data/templates/ubuntu-application/store/help-guide.py 2011-05-24 23:28:25 +0000 |
413 | @@ -80,6 +80,6 @@ |
414 | ('sentence_name', sentence_name), |
415 | ) |
416 | |
417 | - quicklyutils.file_from_template(template_help_dir, |
418 | + templatetools.file_from_template(template_help_dir, |
419 | 'g_u_i_d_e.page', |
420 | target_help_dir, substitutions) |
421 | |
422 | === modified file 'data/templates/ubuntu-application/store/help-topic.py' |
423 | --- data/templates/ubuntu-application/store/help-topic.py 2010-11-22 16:01:03 +0000 |
424 | +++ data/templates/ubuntu-application/store/help-topic.py 2011-05-24 23:28:25 +0000 |
425 | @@ -83,6 +83,6 @@ |
426 | ('sentence_name', sentence_name), |
427 | ) |
428 | |
429 | - quicklyutils.file_from_template(template_help_dir, |
430 | + templatetools.file_from_template(template_help_dir, |
431 | 't_o_p_i_c.page', |
432 | target_help_dir, substitutions) |
433 | |
434 | === modified file 'data/templates/ubuntu-application/store/indicator.py' |
435 | --- data/templates/ubuntu-application/store/indicator.py 2010-11-22 16:01:03 +0000 |
436 | +++ data/templates/ubuntu-application/store/indicator.py 2011-05-24 23:28:25 +0000 |
437 | @@ -59,7 +59,7 @@ |
438 | substitutions = (("project_name",project_name), |
439 | ( "python_name",python_name)) |
440 | |
441 | - quicklyutils.file_from_template(template_python_dir, |
442 | + templatetools.file_from_template(template_python_dir, |
443 | "indicator.py", |
444 | target_python_dir, |
445 | substitutions) |
446 | |
447 | === modified file 'data/templates/ubuntu-application/upgrade.py' |
448 | --- data/templates/ubuntu-application/upgrade.py 2011-01-31 21:59:12 +0000 |
449 | +++ data/templates/ubuntu-application/upgrade.py 2011-05-24 23:28:25 +0000 |
450 | @@ -150,7 +150,7 @@ |
451 | if not os.path.isfile('%s/helpers.py' % python_name) and os.path.isdir(python_name): |
452 | source_dir = os.path.join(os.path.dirname(__file__), 'project_root', |
453 | 'python') |
454 | - quicklyutils.file_from_template(source_dir, |
455 | + templatetools.file_from_template(source_dir, |
456 | "helpers.py", |
457 | python_name, |
458 | substitutions) |
459 | |
460 | === modified file 'data/templates/ubuntu-flash-game/create.py' |
461 | --- data/templates/ubuntu-flash-game/create.py 2011-01-31 21:12:12 +0000 |
462 | +++ data/templates/ubuntu-flash-game/create.py 2011-05-24 23:28:25 +0000 |
463 | @@ -121,7 +121,7 @@ |
464 | directory = python_name |
465 | os.mkdir(os.path.join(relative_dir, directory)) |
466 | for filename in files: |
467 | - quicklyutils.file_from_template(root, filename, relative_dir, substitutions) |
468 | + templatetools.file_from_template(root, filename, relative_dir, substitutions) |
469 | |
470 | # set the mode to executable for executable file |
471 | exec_file = os.path.join('bin', project_name) |
472 | |
473 | === modified file 'data/templates/ubuntu-flash-game/internal/apportutils.py' |
474 | --- data/templates/ubuntu-flash-game/internal/apportutils.py 2011-01-03 15:07:28 +0000 |
475 | +++ data/templates/ubuntu-flash-game/internal/apportutils.py 2011-05-24 23:28:25 +0000 |
476 | @@ -6,6 +6,7 @@ |
477 | |
478 | import quickly |
479 | import quicklyutils |
480 | +from quickly import templatetools |
481 | |
482 | from lxml import etree |
483 | |
484 | @@ -66,18 +67,18 @@ |
485 | |
486 | if os.path.isfile(existing_crashdb): |
487 | print _("Updating project name references in existing apport crashdb configuration") |
488 | - quicklyutils.file_from_template(relative_crashdb_dir, crashdb_file, relative_crashdb_dir, subst_existing) |
489 | + templatetools.file_from_template(relative_crashdb_dir, crashdb_file, relative_crashdb_dir, subst_existing) |
490 | elif os.path.isdir(template_crashdb_dir): |
491 | print _("Creating new apport crashdb configuration") |
492 | if not os.path.isdir(relative_crashdb_dir): |
493 | os.makedirs(relative_crashdb_dir) |
494 | - quicklyutils.file_from_template(template_crashdb_dir, "project_name-crashdb.conf", relative_crashdb_dir, subst_new) |
495 | + templatetools.file_from_template(template_crashdb_dir, "project_name-crashdb.conf", relative_crashdb_dir, subst_new) |
496 | |
497 | if not os.path.isfile(existing_hook) and os.path.isdir(template_hook_dir): |
498 | print _("Creating new apport hooks") |
499 | if not os.path.isdir(relative_apport_dir): |
500 | os.makedirs(relative_apport_dir) |
501 | - quicklyutils.file_from_template(template_hook_dir, "source_project_name.py", relative_apport_dir, subst_new) |
502 | + templatetools.file_from_template(template_hook_dir, "source_project_name.py", relative_apport_dir, subst_new) |
503 | |
504 | def insert_lpi_if_required(project_name): |
505 | existing_bin_filename = os.path.join("bin",project_name) |
506 | |
507 | === modified file 'data/templates/ubuntu-flash-game/internal/quicklyutils.py' |
508 | --- data/templates/ubuntu-flash-game/internal/quicklyutils.py 2011-01-03 15:07:28 +0000 |
509 | +++ data/templates/ubuntu-flash-game/internal/quicklyutils.py 2011-05-24 23:28:25 +0000 |
510 | @@ -42,33 +42,6 @@ |
511 | camel_case_name = templatetools.get_camel_case_name(name) |
512 | return sentence_name, camel_case_name |
513 | |
514 | -def file_from_template(template_dir, template_file, target_dir, substitutions=[], rename = True): |
515 | - |
516 | - if not os.path.isfile(os.path.join(template_dir, template_file)): |
517 | - return |
518 | - target_file = os.path.basename(template_file) # to get only file name (template_file can be internal/file) |
519 | - if rename: |
520 | - for s in substitutions: |
521 | - pattern, sub = s |
522 | - target_file = target_file.replace(pattern,sub) |
523 | - |
524 | - fin = open(os.path.join(template_dir, template_file),'r') |
525 | - file_contents = fin.read() |
526 | - for s in substitutions: |
527 | - pattern, sub = s |
528 | - file_contents = file_contents.replace(pattern,sub) |
529 | - |
530 | - target_path = os.path.join(target_dir, target_file) |
531 | - if os.path.exists(target_path): |
532 | - print _("Failed to add file to project\n cannot add: %s - this file already exists." % target_path) |
533 | - sys.exit(4) |
534 | - |
535 | - fout = open(target_path, 'w') |
536 | - fout.write(file_contents) |
537 | - fout.flush() |
538 | - fout.close() |
539 | - fin.close() |
540 | - |
541 | def get_setup_value(key): |
542 | """ get value from setup.py file. |
543 | |
544 | @@ -209,19 +182,6 @@ |
545 | buffered_message +=' %s' % line |
546 | return(changelog) |
547 | |
548 | - |
549 | -def get_quickly_editors(): |
550 | - '''Return prefered editor for ubuntu-application template''' |
551 | - |
552 | - editor = "gedit" |
553 | - default_editor = os.environ.get("EDITOR") |
554 | - if not default_editor: |
555 | - default_editor = os.environ.get("SELECTED_EDITOR") |
556 | - if default_editor: |
557 | - editor = default_editor |
558 | - return editor |
559 | - |
560 | - |
561 | def take_email_from_string(value): |
562 | '''Try to take an email from a string''' |
563 | |
564 | |
565 | === modified file 'quickly/builtincommands.py' |
566 | --- quickly/builtincommands.py 2010-11-29 15:18:46 +0000 |
567 | +++ quickly/builtincommands.py 2011-05-24 23:28:25 +0000 |
568 | @@ -15,8 +15,10 @@ |
569 | #You should have received a copy of the GNU General Public License along |
570 | #with this program. If not, see <http://www.gnu.org/licenses/>. |
571 | |
572 | +import ConfigParser |
573 | import os |
574 | import shutil |
575 | +import StringIO |
576 | import sys |
577 | |
578 | import configurationhandler |
579 | @@ -211,7 +213,37 @@ |
580 | os.rename(filedest.name, commandsconfig_path) |
581 | return 0 |
582 | |
583 | - |
584 | +help_preferences = _("Edit developers preferences") |
585 | +usage_preferences = _("Usage: quickly preferences") |
586 | +def preferences(project_template, project_dir, command_args, shell_completion=False): |
587 | + """Configure preferences""" |
588 | + |
589 | + # We have nothing for this |
590 | + if shell_completion: |
591 | + return("") |
592 | + |
593 | + preferences = templatetools.get_preferences() |
594 | + |
595 | + #convert preferences into editable contents |
596 | + fp_current = StringIO.StringIO() |
597 | + # TODO use a pretty printer |
598 | + preferences.write(fp_current) |
599 | + contents = fp_current.getvalue() |
600 | + fp_current.close() |
601 | + |
602 | + # ask developer to edit the contents |
603 | + newcontents = templatetools.read_input(contents) |
604 | + |
605 | + # convert the contents back into a ConfigParser object |
606 | + newIO = StringIO.StringIO(newcontents) |
607 | + new_preferences = ConfigParser.SafeConfigParser() |
608 | + # an exception here reject bad edits |
609 | + new_preferences.readfp(newIO) |
610 | + |
611 | + templatetools.set_preferences(new_preferences) |
612 | + |
613 | + |
614 | + return 0 |
615 | |
616 | # here, special builtin commands properties (if nothing specified, commands can be launched inside and outside projects) |
617 | launched_inside_project_only = [] |
618 | |
619 | === modified file 'quickly/templatetools.py' |
620 | --- quickly/templatetools.py 2010-12-20 20:33:12 +0000 |
621 | +++ quickly/templatetools.py 2011-05-24 23:28:25 +0000 |
622 | @@ -15,15 +15,20 @@ |
623 | #You should have received a copy of the GNU General Public License along |
624 | #with this program. If not, see <http://www.gnu.org/licenses/>. |
625 | |
626 | +import ConfigParser |
627 | import os |
628 | import stat |
629 | import string |
630 | +import subprocess |
631 | import sys |
632 | import re |
633 | +import tempfile |
634 | |
635 | import gettext |
636 | from gettext import gettext as _ |
637 | |
638 | +import glib |
639 | + |
640 | import configurationhandler |
641 | import tools |
642 | import quicklyconfig |
643 | @@ -256,3 +261,116 @@ |
644 | print_command_candidates(template) |
645 | sys.exit(4) |
646 | |
647 | +def get_preferences(): |
648 | + 'parse ~/.config/quickly/preferences for configuration' |
649 | + |
650 | + # fill in defaults |
651 | + defaults = {} |
652 | + defaults['plugin_path'] = '/usr/share/pyshared/quickly/widgets' |
653 | + defaults['#plugin_path'] = 'files which can be used with quickly add command' |
654 | + |
655 | + ide = get_quickly_editors() |
656 | + defaults['ide'] = get_quickly_editors() |
657 | + defaults['#ide'] = 'editor defined in environment' |
658 | + |
659 | + preferences = ConfigParser.RawConfigParser(defaults) |
660 | + |
661 | + # ensure there is a section for each template |
662 | + template_names = commands.get_all_templates() |
663 | + for template_name in template_names: |
664 | + preferences.add_section(template_name) |
665 | + |
666 | + config_dir = os.path.join(glib.get_user_config_dir(), 'quickly') |
667 | + config_file = os.path.join(config_dir, 'preferences') |
668 | + preferences.read(config_file) |
669 | + |
670 | + return preferences |
671 | + |
672 | +def set_preferences(new_preferences): |
673 | + 'write ~/.config/quickly/preferences' |
674 | + |
675 | + config_dir = os.path.join(glib.get_user_config_dir(), 'quickly') |
676 | + config_file = os.path.join(config_dir, 'preferences') |
677 | + |
678 | + # ensure config_dir exists |
679 | + if not os.path.isdir(config_dir): |
680 | + os.makedirs(config_dir) |
681 | + |
682 | + # write the preferences file |
683 | + with open(config_file, 'w') as fp: |
684 | + new_preferences.write(fp) |
685 | + |
686 | +def get_quickly_editors(): |
687 | + '''Return prefered editor for any template''' |
688 | + |
689 | + default_editor = os.environ.get("QUICKLY_EDITOR") |
690 | + if not default_editor: |
691 | + default_editor = os.environ.get("EDITOR") |
692 | + if not default_editor: |
693 | + default_editor = os.environ.get("SELECTED_EDITOR") |
694 | + if default_editor: |
695 | + editor = default_editor |
696 | + elif is_X_display(): |
697 | + editor = "gedit" |
698 | + else: |
699 | + editor = "nano" |
700 | + return editor |
701 | + |
702 | +def read_input(start=''): |
703 | + depfile_name = tempfile.mkstemp()[1] |
704 | + open(depfile_name,'w').write(start) |
705 | + |
706 | + # Run the editor with a new tmpdir. This is because gedit uses tmpdir |
707 | + # to find other instances of gedit, and we don't want that. If we allowed |
708 | + # that, gedit would return immediately and open a new tab in the other |
709 | + # gedit. This makes it difficult to tell when user is done editing (how |
710 | + # to detect that vs nano opening and closing without the user saving it?). |
711 | + editor = get_quickly_editors() |
712 | + subenv = dict(os.environ) |
713 | + subenv['TMPDIR'] = tempfile.mkdtemp() |
714 | + subprocess.call([editor, depfile_name], stdout=subprocess.PIPE, env=subenv) |
715 | + os.rmdir(subenv['TMPDIR']) |
716 | + |
717 | + # Grab file contents |
718 | + rv = file(depfile_name, 'r').read().strip() |
719 | + os.remove(depfile_name) |
720 | + |
721 | + return rv |
722 | + |
723 | +def get_ide(template): |
724 | + '''Return prefered editor for specified template''' |
725 | + preferences = get_preferences() |
726 | + |
727 | + if preferences.has_option(template, 'ide'): |
728 | + return preferences.get(template, 'ide') |
729 | + else: |
730 | + return get_quickly_editors() |
731 | + |
732 | +def option(template, option): |
733 | + '''Return prefered option for specified template''' |
734 | + preferences = get_preferences() |
735 | + return preferences.get(template, option) |
736 | + |
737 | +def file_from_template(template_dir, template_file, target_dir, substitutions=[], rename = True): |
738 | + |
739 | + if not os.path.isfile(os.path.join(template_dir, template_file)): |
740 | + return |
741 | + target_file = os.path.basename(template_file) # to get only file name (template_file can be internal/file) |
742 | + if rename: |
743 | + for s in substitutions: |
744 | + pattern, sub = s |
745 | + target_file = target_file.replace(pattern,sub) |
746 | + |
747 | + fin = open(os.path.join(template_dir, template_file),'r') |
748 | + file_contents = fin.read() |
749 | + for s in substitutions: |
750 | + pattern, sub = s |
751 | + file_contents = file_contents.replace(pattern,sub) |
752 | + |
753 | + target_path = os.path.join(target_dir, target_file) |
754 | + if os.path.exists(target_path): |
755 | + print _("Failed to add file to project\n cannot add: %s - this file already exists." % target_path) |
756 | + sys.exit(4) |
757 | + |
758 | + set_file_contents(target_path, file_contents) |
759 | + fin.close() |
This would be a lot easier to read if the ide branch wasn't interwoven. You can specify a prerequisite branch when filing a merge (and unfortunately, seemingly only then) which would hide that prerequisite branch on this page. Just FYI. For now I can review this using bzr directly.
Changes like this and the preferences might best be discussed on quickly-talk first, to get a sense of your direction and the technical ramifications. Especially if the discussion might change how you implement it (so you don't waste work).
I'm not sure what the goal of adding outside files from quickly widgets is? Quickly widgets is an external library meant to be used like any other python library, not pulled in directly.