Merge lp:~didrocks/quickly/install-in-opt into lp:quickly

Proposed by Didier Roche-Tolomelli
Status: Merged
Approved by: Michael Terry
Approved revision: 568
Merged at revision: 568
Proposed branch: lp:~didrocks/quickly/install-in-opt
Merge into: lp:quickly
Diff against target: 462 lines (+384/-3)
6 files modified
data/templates/ubuntu-application/internal/packaging.py (+4/-1)
data/templates/ubuntu-application/project_root/bin/project_name (+11/-1)
data/templates/ubuntu-application/submitubuntu.py (+297/-0)
data/templates/ubuntu-application/upgrade.py (+26/-0)
quickly/quicklyconfig.py (+1/-1)
quickly/templatetools.py (+45/-0)
To merge this branch: bzr merge lp:~didrocks/quickly/install-in-opt
Reviewer Review Type Date Requested Status
Michael Terry (community) Approve
Review via email: mp+40628@code.launchpad.net

Description of the change

The branch which makes the application review board happy :)

see my comment at
https://bugs.launchpad.net/ubuntu/+source/quickly/+bug/625581

Still some work to do, like create a symlink for the .desktop file and such, but anything should now be installed in /opt/<appname> with "quickly submitubuntu".

To post a comment you must log in.
Revision history for this message
Michael Terry (mterry) wrote :

+# Copyright 2009 Didier Roche

Should that be 2010 Canonical?

17 + command = ['python-mkdebian', '--force-control', '--force-rules']

You probably want to version-guard --force-rules like we did for --force-copyright.

Could we call it 'submit' rather than 'submitubuntu'?

Could we not reduce the duplicated logic between 'submitubuntu' and 'release' more?

Is there a reason we don't just default installopt to True? Seems bad for developers to be testing one thing and submitting a different one. Especially since any hard-coded paths they used will want to be different.

Revision history for this message
Didier Roche-Tolomelli (didrocks) wrote :

+# Copyright 2009 Didier Roche

Should that be 2010 Canonical?

No, Quickly doesn't have copyright assignment and I didn't work on that part on my Canonical time (I just added an option to it)? So keeping original file copyright make sense.

17 + command = ['python-mkdebian', '--force-control', '--force-rules']
I'll update that, and also add linking the right file.

Could we not reduce the duplicated logic between 'submitubuntu' and 'release' more?

Is there a reason we don't just default installopt to True? Seems bad for developers to be testing one thing and submitting a different one. Especially since any hard-coded paths they used will want to be different.

Did you read my comment as pointed from the original message?
https://bugs.launchpad.net/ubuntu/+source/quickly/+bug/625581/comments/10

I agree with that, but that's wont be an alpha1 target given the time I have. All the testing issue is also discussed in the comment linked above and I want that we discuss that during alpha1 and alpha2 to make submitubuntu a more useful command.

lp:~didrocks/quickly/install-in-opt updated
563. By Didier Roche-Tolomelli

add support in project_name for running application in /opt/appname

564. By Didier Roche-Tolomelli

force rules under conditions

565. By Didier Roche-Tolomelli

support upgrade for /opt support and add a function to make the safe add easy

Revision history for this message
Didier Roche-Tolomelli (didrocks) wrote :

pushed the previous remark fixes. Handle now upgrades as well.

I've created a convenient function for replacing some text in files between a start and end marker. Maybe some of our function (like licence) should starts using it.

lp:~didrocks/quickly/install-in-opt updated
566. By Didier Roche-Tolomelli

install in /opt/extras

Revision history for this message
Michael Terry (mterry) wrote :

/opt/extras should be /opt/extras.ubuntu.com according to the discussion in the mailing list, I believe. But you mention that you are waiting for final, final approval.

15 if get_python_mkdebian_version() > 2.22:
16 command.append("--force-copyright")
17 + if get_python_mkdebian_version() > 2.23:
18 + command.append("--force-rules")

Should just be:

if get_python_mkdebian_version() > 2.22:
    command.append("--force-copyright")
    command.append("--force-rules")

as --force-rules was added in 2.23.

+print _("Then your application will be reviewed by the application review board.")

I didn't see anything that would notify the ARB. I assume that's a TODO item?

+def update_file_content(filename, start_marker, end_marker, replacing_content):

Nice function. :) Though ideally, it would use set_file_contents() from quicklyutils.py (after moving it to templatetools).

Revision history for this message
Didier Roche-Tolomelli (didrocks) wrote :

/opt/extras should be /opt/extras.ubuntu.com according to the discussion in the mailing list, I believe. But you mention that you are waiting for final, final approval.

15 if get_python_mkdebian_version() > 2.22:
16 command.append("--force-copyright")
17 + if get_python_mkdebian_version() > 2.23:
18 + command.append("--force-rules")

Should just be:

if get_python_mkdebian_version() > 2.22:
    command.append("--force-copyright")
    command.append("--force-rules")

as --force-rules was added in 2.23.

oopss, fixing

+print _("Then your application will be reviewed by the application review board.")

I didn't see anything that would notify the ARB. I assume that's a TODO item?

Right, as mentionned and pending email on the ARB about "what to do with the submitubuntu command, should we always install in /opt?"

+def update_file_content(filename, start_marker, end_marker, replacing_content):

Nice function. :) Though ideally, it would use set_file_contents() from quicklyutils.py (after moving it to templatetools).

Not really the same the same, set_files_contents exchanges some values, here this one is to add/remove content between tags. the licence command should use it.

lp:~didrocks/quickly/install-in-opt updated
567. By Didier Roche-Tolomelli

force versionning

568. By Didier Roche-Tolomelli

use extras.ubuntu.com

Revision history for this message
Didier Roche-Tolomelli (didrocks) wrote :

pushed the new version, I mixed the update_file_content function. Well free to merge it with my function :)

Revision history for this message
Michael Terry (mterry) wrote :

> Not really the same the same, set_files_contents exchanges some values, here this one is to add/remove content between tags. the licence command should use it.

I know they aren't the same. I was proposing that your new function use the existing set_file_contents() function instead of duplicating the whole .new/os.rename stuff again.

Revision history for this message
Didier Roche-Tolomelli (didrocks) wrote :

it can't really use it, it should rather deprecate it as there are some operations done while going through the loop) or wrapping it, like set_file_contents call update_file_content(destfile, openmarker=None, endmarker=None, sourcefile.read()), isn't it?

Revision history for this message
Allison Randal (allison) wrote :

> /opt/extras should be /opt/extras.ubuntu.com according to the discussion in
> the mailing list, I believe. But you mention that you are waiting for final,
> final approval.

Rick asked me to comment here. It's 98% sure the Tech Board will approve /opt/extras.ubuntu.com in the meeting next Tuesday (the interested TB members were involved in the ubuntu-devel discussion, and it's the only answer that satisfies all the concerns of various people). So, safe to merge before Tuesday, if that's the last thing holding up the merge.

Revision history for this message
Didier Roche-Tolomelli (didrocks) wrote :

Thanks Allison, there is still the question sent to the ARB and the "do we install always in /opt or just in the submitubuntu command and what to do with that command (and rename it to "submit"), but I think we can get to that later…

Michael: ok to merge? We will merge all the with: for writing in a file function later if you don't mind (like license, renaming and replace… and so on…)

Revision history for this message
Michael Terry (mterry) wrote :

Approved, if you fix

37 + opt_path = path.replace('/usr', '/opt/extras/python_name')

To use extras.ubuntu.com

review: Approve
Revision history for this message
Didier Roche-Tolomelli (didrocks) wrote :

argh, a one leftover :)
doing and done!

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'data/templates/ubuntu-application/internal/packaging.py'
--- data/templates/ubuntu-application/internal/packaging.py 2010-11-22 16:01:03 +0000
+++ data/templates/ubuntu-application/internal/packaging.py 2010-11-22 16:47:10 +0000
@@ -162,7 +162,7 @@
162 version = proc.communicate()[0]162 version = proc.communicate()[0]
163 return float(version)163 return float(version)
164164
165def updatepackaging(changelog=None, no_changelog=False):165def updatepackaging(changelog=None, no_changelog=False, installopt=False):
166 """create or update a package using python-mkdebian.166 """create or update a package using python-mkdebian.
167167
168 Commit after the first packaging creation"""168 Commit after the first packaging creation"""
@@ -172,8 +172,11 @@
172 command = ['python-mkdebian', '--force-control']172 command = ['python-mkdebian', '--force-control']
173 if get_python_mkdebian_version() > 2.22:173 if get_python_mkdebian_version() > 2.22:
174 command.append("--force-copyright")174 command.append("--force-copyright")
175 command.append("--force-rules")
175 if no_changelog:176 if no_changelog:
176 command.append("--no-changelog")177 command.append("--no-changelog")
178 if installopt:
179 command.append("--prefix=/opt/extras.ubuntu.com/%s" % configurationhandler.project_config['project'])
177 for message in changelog:180 for message in changelog:
178 command.extend(["--changelog", message])181 command.extend(["--changelog", message])
179 if not configurationhandler.project_config:182 if not configurationhandler.project_config:
180183
=== modified file 'data/templates/ubuntu-application/project_root/bin/project_name'
--- data/templates/ubuntu-application/project_root/bin/project_name 2010-11-17 18:44:18 +0000
+++ data/templates/ubuntu-application/project_root/bin/project_name 2010-11-22 16:47:10 +0000
@@ -16,10 +16,20 @@
16PROJECT_ROOT_DIRECTORY = os.path.abspath(16PROJECT_ROOT_DIRECTORY = os.path.abspath(
17 os.path.dirname(os.path.dirname(os.path.realpath(sys.argv[0]))))17 os.path.dirname(os.path.dirname(os.path.realpath(sys.argv[0]))))
1818
19python_path = []
20if os.path.abspath(__file__).startswith('/opt'):
21 syspath = sys.path[:] # copy to avoid infinite loop in pending objects
22 for path in syspath:
23 opt_path = path.replace('/usr', '/opt/extras/python_name')
24 python_path.insert(0, opt_path)
25 sys.path.insert(0, opt_path)
19if (os.path.exists(os.path.join(PROJECT_ROOT_DIRECTORY, 'python_name'))26if (os.path.exists(os.path.join(PROJECT_ROOT_DIRECTORY, 'python_name'))
20 and PROJECT_ROOT_DIRECTORY not in sys.path):27 and PROJECT_ROOT_DIRECTORY not in sys.path):
28 python_path.insert(0, PROJECT_ROOT_DIRECTORY)
21 sys.path.insert(0, PROJECT_ROOT_DIRECTORY)29 sys.path.insert(0, PROJECT_ROOT_DIRECTORY)
22 os.putenv('PYTHONPATH', PROJECT_ROOT_DIRECTORY) # for subprocesses30if python_path:
31 os.putenv('PYTHONPATH', "%s:%s" % (os.getenv('PYTHONPATH', ''), ':'.join(python_path))) # for subprocesses
32
2333
24from python_name import (Basecamel_case_nameWindow)34from python_name import (Basecamel_case_nameWindow)
25import python_name.helpers as helpers35import python_name.helpers as helpers
2636
=== added file 'data/templates/ubuntu-application/submitubuntu.py'
--- data/templates/ubuntu-application/submitubuntu.py 1970-01-01 00:00:00 +0000
+++ data/templates/ubuntu-application/submitubuntu.py 2010-11-22 16:47:10 +0000
@@ -0,0 +1,297 @@
1#!/usr/bin/python
2# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
3# Copyright 2009 Didier Roche
4#
5# This file is part of Quickly ubuntu-application template
6#
7#This program is free software: you can redistribute it and/or modify it
8#under the terms of the GNU General Public License version 3, as published
9#by the Free Software Foundation.
10
11#This program is distributed in the hope that it will be useful, but
12#WITHOUT ANY WARRANTY; without even the implied warranties of
13#MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
14#PURPOSE. See the GNU General Public License for more details.
15
16#You should have received a copy of the GNU General Public License along
17#with this program. If not, see <http://www.gnu.org/licenses/>.
18
19import os
20import sys
21import subprocess
22import webbrowser
23
24from internal import quicklyutils, packaging, launchpad_helper
25from internal import bzrutils
26from quickly import templatetools, configurationhandler, commands
27import license
28
29import logging
30
31from quickly import launchpadaccess
32
33import gettext
34from gettext import gettext as _
35gettext.textdomain('quickly')
36
37options = ["--ppa",]
38
39def usage():
40 templatetools.print_usage(_('quickly submitubuntu [--ppa <ppa | group/ppa>] [release-version] [comments]'))
41def help():
42 print _("""Posts a release of your project and submit it the ubuntu
43application review board so that any users can see and install the
44application ont their system.
45
46Before running quickly submitubuntu, you should: create your account
47and a project page on http://launchpad.net.
48You also have to add a PPA to your launchpad account.
49
50Name, email, and version will be automatically changed in setup.py and
51bzr will tag the current source with the new version number.
52
53If not specified, the new version number will be 'YEAR.MONTH[.RELEASE]'.
54
55For example, the third release in July 2010 would be versioned 10.07.2.
56
57You may want to make sure that the description and long description in
58setup.py are up to date before releasing.
59
60You can optionally run 'quickly package' and test your package to make
61sure it installs as expected.""")
62def shell_completion(argv):
63 ''' Complete --args '''
64 # option completion
65 rv = []
66 if argv[-1].startswith("-"):
67 rv = options
68 elif len(argv) > 1 and argv[-2] == '--ppa': # if argument following --ppa, complete by ppa
69 rv = packaging.shell_complete_ppa(argv[-1])
70 if rv:
71 rv.sort()
72 print ' '.join(rv)
73
74templatetools.handle_additional_parameters(sys.argv, help, shell_completion, usage=usage)
75
76
77launchpad = None
78project = None
79ppa_name = None
80i = 0
81args = []
82argv = sys.argv
83
84while i < len(argv):
85 arg = argv[i]
86 if arg.startswith('-'):
87 if arg == '--ppa':
88 if i + 1 < len(argv):
89 ppa_name = argv[i + 1]
90 i += 1
91 else:
92 cmd = commands.get_command('submitubuntu', 'ubuntu-application')
93 templatetools.usage_error(_("No PPA provided."), cmd=cmd)
94 else:
95 cmd = commands.get_command('submitubuntu', 'ubuntu-application')
96 templatetools.usage_error(_("Unknown option: %s." % arg), cmd=cmd)
97 else:
98 args.append(arg)
99 i += 1
100
101 commit_msg = None
102if len(args) == 1:
103 proposed_version = None
104elif len(args) == 2:
105 proposed_version = args[1]
106elif len(args) > 2:
107 proposed_version = args[1]
108 commit_msg = " ".join(args[2:])
109
110# warning: project_name can be different from project.name (one local, one on launchpad)
111if not configurationhandler.project_config:
112 configurationhandler.loadConfig()
113project_name = configurationhandler.project_config['project']
114
115# connect to LP
116try:
117 launchpad = launchpadaccess.initialize_lpi()
118except launchpadaccess.launchpad_connection_error, e:
119 print(e)
120 sys.exit(1)
121
122# push the gpg key and email to the env
123try:
124 keyid = quicklyutils.get_right_gpg_key_id(launchpad)
125except quicklyutils.gpg_error, e:
126 print(e)
127 sys.exit(1)
128
129# get the project now and save the url into setup.py
130try:
131 project = launchpadaccess.get_project(launchpad)
132except launchpadaccess.launchpad_project_error, e:
133 print(e)
134 sys.exit(1)
135project_url = launchpadaccess.launchpad_url + '/' + project.name
136quicklyutils.set_setup_value('url', project_url)
137about_dialog_file_name = quicklyutils.get_about_file_name()
138if about_dialog_file_name:
139 quicklyutils.change_xml_elem(about_dialog_file_name, "object/property",
140 "name", "website", project_url, {})
141
142# choose right ppa parameter (users, etc.) ppa or staging if ppa_name is None
143try:
144 (ppa_user, ppa_name, dput_ppa_name, ppa_url) = packaging.choose_ppa(launchpad, ppa_name)
145except packaging.user_team_not_found, e:
146 print(_("User or Team %s not found on Launchpad") % e)
147 sys.exit(1)
148except packaging.not_ppa_owner, e:
149 print(_("You have to be a member of %s team to upload to its ppas") % e)
150 sys.exit(1)
151
152try:
153 ppa_name = packaging.check_and_return_ppaname(launchpad, ppa_user, ppa_name) # ppa_name can be ppa name or ppa display name. Find the right one if exists
154except packaging.ppa_not_found, e:
155 print(_("%s does not exist. Please create it on launchpad if you want to push a package to it. %s has the following ppas available:") % (e, ppa_user.name))
156 user_has_ppa = False
157 for ppa_name, ppa_display_name in packaging.get_all_ppas(launchpad, ppa_user):
158 print "%s - %s" % (ppa_name, ppa_display_name)
159 user_has_ppa = True
160 if user_has_ppa:
161 print(_("You can temporary choose one of them with --ppa switch or definitely by executing quickly configure ppa <ppa_name>."))
162 sys.exit(1)
163
164# update license if needed. Don't change anything if not needed
165try:
166 license.licensing()
167except license.LicenceError, error_message:
168 print(error_message)
169 sys.exit(1)
170
171try:
172 release_version = packaging.updateversion(proposed_version)
173except (packaging.invalid_versionning_scheme,
174 packaging.invalid_version_in_setup), error_message:
175 print(error_message)
176 sys.exit(1)
177
178if commit_msg is None:
179 commit_msg = _('quickly released: %s' % release_version)
180
181
182# check if already released with this name
183bzr_instance = subprocess.Popen(["bzr", "tags"], stdout=subprocess.PIPE)
184bzr_tags, err = bzr_instance.communicate()
185if bzr_instance.returncode !=0:
186 print(err)
187 sys.exit(1)
188if release_version in bzr_tags:
189 print _("ERROR: quickly can't release: %s seems to be already released. Choose another name.") % release_version
190 sys.exit(1)
191
192# commit current changes
193packaging.filter_exec_command(["bzr", "add"])
194return_code = packaging.filter_exec_command(["bzr", "commit", '--unchanged', '-m',
195 _('commit before release')])
196if return_code != 0 and return_code != 3:
197 print _("ERROR: quickly can't release as it can't commit with bzr")
198 sys.exit(return_code)
199
200# try to get last available version in bzr
201previous_version = None
202bzr_instance = subprocess.Popen(['bzr', 'tags', '--sort=time'],
203 stdout=subprocess.PIPE)
204result, err = bzr_instance.communicate()
205if bzr_instance.returncode == 0 and result:
206 output = result.split('\n')
207 output.reverse()
208 for tag_line in output:
209 tag_elem = tag_line.split (' ')
210 if not (tag_elem[-1] == '?' or tag_elem[-1] == ''):
211 previous_version = tag_elem[0]
212 break
213
214changelog = quicklyutils.collect_commit_messages(previous_version)
215# creation/update debian packaging
216return_code = packaging.updatepackaging(changelog, installopt=True)
217if return_code != 0:
218 print _("ERROR: can't create or update ubuntu package")
219 sys.exit(1)
220
221# add files, setup release version, commit and push !
222#TODO: check or fix if we don't have an ssh key (don't tag otherwise to be able to release again)
223packaging.filter_exec_command(["bzr", "add"])
224return_code = packaging.filter_exec_command(["bzr", "commit", '-m', commit_msg])
225if return_code != 0 and return_code != 3:
226 print _("ERROR: quickly can't release as it can't commit with bzr")
227 sys.exit(return_code)
228packaging.filter_exec_command(["bzr", "tag", release_version]) # tag revision
229
230# check if pull branch is set
231bzr_instance = subprocess.Popen(["bzr", "info"], stdout=subprocess.PIPE)
232bzr_info, err = bzr_instance.communicate()
233if bzr_instance.returncode !=0:
234 print(err)
235 sys.exit(1)
236
237
238if (launchpadaccess.lp_server == "staging"):
239 bzr_staging = "//staging/"
240else:
241 bzr_staging = ""
242
243custom_location_in_info = None
244branch_location = []
245custom_location = bzrutils.get_bzrbranch()
246if custom_location:
247 branch_location = [custom_location]
248 custom_location_in_info = custom_location.replace('lp:', '')
249# if no branch, create it in ~user_name/project_name/quickly_trunk
250# or switch from staging to production
251if ("parent branch" in bzr_info) and not (
252 (custom_location_in_info and custom_location_in_info not in bzr_info) or
253 ((".staging." in bzr_info) and not bzr_staging) or
254 (not (".staging." in bzr_info) and bzr_staging)):
255 return_code = packaging.filter_exec_command(["bzr", "pull"])
256 if return_code != 0:
257 print _("ERROR: quickly can't release: can't pull from launchpad.")
258 sys.exit(return_code)
259
260 return_code = packaging.filter_exec_command(["bzr", "push"])
261 if return_code != 0:
262 print _("ERROR: quickly can't release: can't push to launchpad.")
263 sys.exit(return_code)
264else:
265 if not branch_location:
266 branch_location = ['lp:', bzr_staging, '~', launchpad.me.name, '/', project.name, '/quickly_trunk']
267 return_code = packaging.filter_exec_command(["bzr", "push", "--remember", "--overwrite", "".join(branch_location)])
268 if return_code != 0:
269 print _("ERROR: quickly can't release: can't push to launchpad.")
270 sys.exit(return_code)
271
272 # make first pull too
273 return_code = packaging.filter_exec_command(["bzr", "pull", "--remember", "".join(branch_location)])
274 if return_code != 0:
275 print _("ERROR: quickly can't release correctly: can't pull from launchpad.")
276 sys.exit(return_code)
277
278
279# upload to launchpad
280print _("pushing to launchpad")
281return_code = packaging.push_to_ppa(dput_ppa_name, "../%s_%s_source.changes" % (project_name, release_version), keyid=keyid) != 0
282if return_code != 0:
283 sys.exit(return_code)
284
285#create new release_date
286launchpad_helper.push_tarball_to_launchpad(project, release_version,
287 "../%s_%s.tar.gz" % (project_name,
288 release_version), changelog)
289
290print _("%s %s released and submitted to ubuntu. Wait for half an hour and have look at %s.") % (project_name, release_version, ppa_url)
291print _("Then your application will be reviewed by the application review board.")
292
293# as launchpad-open doesn't support staging server, put an url
294if launchpadaccess.lp_server == "staging":
295 webbrowser.open(launchpadaccess.LAUNCHPAD_CODE_STAGING_URL + '/' + project.name)
296else:
297 webbrowser.open(launchpadaccess.LAUNCHPAD_URL + '/' + project.name)
0298
=== modified file 'data/templates/ubuntu-application/upgrade.py'
--- data/templates/ubuntu-application/upgrade.py 2010-09-28 12:53:04 +0000
+++ data/templates/ubuntu-application/upgrade.py 2010-11-22 16:47:10 +0000
@@ -171,4 +171,30 @@
171 os.system("find . -name '*.py' -exec %s {} \;" % sedline)171 os.system("find . -name '*.py' -exec %s {} \;" % sedline)
172 os.system("%s bin/%s" % (sedline, project_name))172 os.system("%s bin/%s" % (sedline, project_name))
173173
174### 0.7 update
175if project_version < '0.7':
176 # support /opt installation
177 content_to_update = '''python_path = []
178if os.path.abspath(__file__).startswith('/opt'):
179 syspath = sys.path[:] # copy to avoid infinite loop in pending objects
180 for path in syspath:
181 opt_path = path.replace('/usr', '/opt/extras.ubuntu.com/%(python_name)s')
182 python_path.insert(0, opt_path)
183 sys.path.insert(0, opt_path)
184if (os.path.exists(os.path.join(PROJECT_ROOT_DIRECTORY, '%(python_name)s'))
185 and PROJECT_ROOT_DIRECTORY not in sys.path):
186 python_path.insert(0, PROJECT_ROOT_DIRECTORY)
187 sys.path.insert(0, PROJECT_ROOT_DIRECTORY)
188if python_path:
189 os.putenv('PYTHONPATH', "%%s:%%s" %% (os.getenv('PYTHONPATH', ''), ':'.join(python_path))) # for subprocesses''' % {'python_name' : python_name}
190
191 try:
192 templatetools.update_file_content("./bin/%s" % project_name,
193 'if (os.path.exists(os.path.join(PROJECT_ROOT_DIRECTORY',
194 " os.putenv('PYTHONPATH', PROJECT_ROOT_DIRECTORY) # for subprocesses",
195 content_to_update)
196 except templatetools.CantUpdateFile, e:
197 print _("WARNING: can't update your project to support /opt. This doesn't mind if you don't plan to submit your project to the application review board. Cause is: %s" % e)
198
199
174sys.exit(0)200sys.exit(0)
175201
=== modified file 'quickly/quicklyconfig.py'
--- quickly/quicklyconfig.py 2010-10-06 09:52:51 +0000
+++ quickly/quicklyconfig.py 2010-11-22 16:47:10 +0000
@@ -20,7 +20,7 @@
20# you're warned :)20# you're warned :)
2121
22# quickly version used for project format compatibility22# quickly version used for project format compatibility
23__version__ = '0.6.1'23__version__ = '0.7'
2424
25# where quickly will head for quickly data (for instance, templates)25# where quickly will head for quickly data (for instance, templates)
26# by default, this is ../data, relative to trunk layout26# by default, this is ../data, relative to trunk layout
2727
=== modified file 'quickly/templatetools.py'
--- quickly/templatetools.py 2010-10-15 20:26:19 +0000
+++ quickly/templatetools.py 2010-11-22 16:47:10 +0000
@@ -31,6 +31,11 @@
3131
32class bad_project_name(Exception):32class bad_project_name(Exception):
33 pass33 pass
34class CantUpdateFile(Exception):
35 def __init__(self, msg):
36 self.msg = msg
37 def __str__(self):
38 return self.msg
3439
35def handle_additional_parameters(args, help=None, shell_completion=None, usage=None):40def handle_additional_parameters(args, help=None, shell_completion=None, usage=None):
36 """Enable handling additional parameter like help or shell_completion"""41 """Enable handling additional parameter like help or shell_completion"""
@@ -88,6 +93,46 @@
88 mode = stat.S_IMODE(st.st_mode)93 mode = stat.S_IMODE(st.st_mode)
89 os.chmod(dest_file_name, mode)94 os.chmod(dest_file_name, mode)
9095
96def update_file_content(filename, start_marker, end_marker, replacing_content):
97 """Safely replace the content of a file"""
98
99 skip_until_end_found = False
100 marker_found = False
101 try:
102 filename = os.path.abspath(filename)
103 ftarget_file_name = file(filename, 'r')
104 ftarget_file_name_out = file(ftarget_file_name.name + '.new', 'w')
105 for line in ftarget_file_name:
106 # seek if we have to add something
107 if start_marker in line:
108 skip_until_end_found = True
109 marker_found = True
110 ftarget_file_name_out.write(replacing_content)
111
112 if end_marker in line:
113 skip_until_end_found = False
114
115 if not skip_until_end_found:
116 ftarget_file_name_out.write(line)
117
118 ftarget_file_name.close()
119 ftarget_file_name_out.close()
120
121 if skip_until_end_found: # that means we didn't find the end_tag, don't copy the file
122 os.remove(ftarget_file_name_out.name)
123 raise CantUpdateFile(_("%s was not found in the file %s.") % (end_marker, ftarget_file_name.name))
124
125 if not marker_found:
126 os.remove(ftarget_file_name_out.name)
127 raise CantUpdateFile(_("%s was not found in the file %s.") % (start_marker, ftarget_file_name.name))
128
129 apply_file_rights(ftarget_file_name.name, ftarget_file_name_out.name)
130 os.rename(ftarget_file_name_out.name, ftarget_file_name.name)
131
132 except (OSError, IOError), e:
133 msg = _("%s file was not found or can't update it") % ftarget_file_name
134 raise CantUpdateFile(msg)
135
91def in_verbose_mode():136def in_verbose_mode():
92 """Return true if verbose mode is on"""137 """Return true if verbose mode is on"""
93138

Subscribers

People subscribed via source and target branches