Merge lp:~johnf-inodes/autoppa/version_template into lp:autoppa
- version_template
- Merge into trunk
Status: | Merged | ||||
---|---|---|---|---|---|
Merged at revision: | not available | ||||
Proposed branch: | lp:~johnf-inodes/autoppa/version_template | ||||
Merge into: | lp:autoppa | ||||
Diff against target: |
446 lines 8 files modified
README (+25/-1) autoppa/application.py (+16/-5) autoppa/commands.py (+6/-2) autoppa/configuration.py (+4/-3) autoppa/help_topics.py (+43/-0) autoppa/target.py (+30/-13) autoppa/tests/test_configuration.py (+2/-0) autoppa/tests/test_target.py (+29/-5) |
||||
To merge this branch: | bzr merge lp:~johnf-inodes/autoppa/version_template | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Jamu Kakar | Approve | ||
John Ferlito (community) | Abstain | ||
Review via email: mp+13782@code.launchpad.net |
Commit message
Description of the change
John Ferlito (johnf-inodes) wrote : | # |
John Ferlito (johnf-inodes) wrote : | # |
Not 100% happy with the template variables but I couldn't come up with anything better.
John Ferlito (johnf-inodes) wrote : | # |
Not 100% happy with the template variables but I couldn't come up with anything better.
John Ferlito (johnf-inodes) wrote : | # |
Not 100% happy with the template variables but I couldn't come up with anything better.
Jamu Kakar (jkakar) wrote : | # |
[1]
+ file = open(filename, "r")
+ try:
+ expected = "version = 'AUTOPPA_
+ self.assertEqua
+ finally:
+ file.close()
+ self.builder.
The try/finally isn't really necessary here. If it leaks, the file
will be closed when it gets garbage collected. Also, the final line
isn't necessary since self.builder is created afresh for each test
case.
[2]
+ def _get_version(self, release_name):
+
+ version = self.version_
+ version = re.sub(
+ version = re.sub(
+ version = re.sub(
+
+ return version
The standard library provides builtin string template interpolation
functionality that will simplify this a bit:
def _get_version(self, release_name):
data = {"version": self.version, "release_name": release_name,
return version_
You'll need to add the following import:
from string import Template
[3]
What do you think about expanding the version variables to include
everything in this list:
version 'version' in the diff
revision The revision of the source branch
dist_codename 'release_name' in the diff
dist_version 'release_number' in the diff
now The current time in UTC formatted as YYYYMMDDHHMMSS
today Today's date formatted as YYYYMMDD
user The name from the USER environment variable
Is there anything else that should be included?
[4]
+version_template = ${version}
+${version} - The version passed on the command line
+${release_number} - 6.04, 6.10, etc
+${release_name} - dapper, gutsy, etc
'codename' should be 'release_name' above, in the README.
[5]
It'd be cool to add a help topic describing the functionality. If
you look at autoppa.help_topics you'll see an example of a topic.
If you implement a class following the same pattern called
topic_version_
you see when you run 'bin/autoppa help topics' and can be viewed by
running 'bin/autoppa help version-templates'.
[6]
+ build_target = self._configura
+ if "version_template" not in build_target:
+ build_target[
+ return build_target
I think this logic is a bit dangerous, because it will end up
injecting data into user configuration that wasn't actually provided
by the user. I recommend you revert this change and deal with the
default version template in autoppa.
definition of DEFAULT_
+ version_template = version_template or data["version_
Then the above line in AutoPPA.
John Ferlito (johnf-inodes) wrote : | # |
On Thu, Oct 22, 2009 at 07:03:12PM -0000, Jamu Kakar wrote:
> Review: Needs Fixing
> [1]
>
> + file = open(filename, "r")
> + try:
> + expected = "version = 'AUTOPPA_
> + self.assertEqua
> + finally:
> + file.close()
> + self.builder.
>
> The try/finally isn't really necessary here. If it leaks, the file
> will be closed when it gets garbage collected. Also, the final line
> isn't necessary since self.builder is created afresh for each test
> case.
OK. I'll fix that up. I pretty much copied this test case from the
one above which does something similar.
> [2]
>
> + def _get_version(self, release_name):
> +
> + version = self.version_
> + version = re.sub(
> + version = re.sub(
> + version = re.sub(
> +
> + return version
>
> The standard library provides builtin string template interpolation
> functionality that will simplify this a bit:
>
> def _get_version(self, release_name):
> version_template = Template(
> release_number = self._get_
> data = {"version": self.version, "release_name": release_name,
> "release_number": release_number}
> return version_
>
> You'll need to add the following import:
>
> from string import Template
Ahh that is very cool. Much more elegant. Thanks!
> [3]
>
> What do you think about expanding the version variables to include
> everything in this list:
>
> version 'version' in the diff
> revision The revision of the source branch
> dist_codename 'release_name' in the diff
> dist_version 'release_number' in the diff
> now The current time in UTC formatted as YYYYMMDDHHMMSS
> today Today's date formatted as YYYYMMDD
> user The name from the USER environment variable
>
> Is there anything else that should be included?
Can't think of anything else right now.
There are a couple of TODOs and FIXMEs regarding this change.
Testing ${revision} is painful since FakeExpect doesn't deal with
grabbing output. I'll implement it after I redo the bzrlib stuff since
then we shouldn't need expect any more.
Also I'm not sure how to stub/mock time and date so that we can test
$today so I left it out for now.
> [4]
>
> +version_template = ${version}
>
> +${version} - The version passed on the command line
> +${release_number} - 6.04, 6.10, etc
> +${release_name} - dapper, gutsy, etc
>
> 'codename' should be 'release_name' above, in the README.
Done.
> [5]
>
> It'd be cool to add a help topic describing the functionality. If
> you look at autoppa.help_topics you'll see an example of a topic.
> If you implement a class following the same pattern called
> topic_version_
> you see when you r...
- 31. By John Ferlito
-
Use string template
- 32. By John Ferlito
-
Move default version template
- 33. By John Ferlito
-
Add extra substitutions to version_template
- 34. By John Ferlito
-
Add a help topic for version templates
John Ferlito (johnf-inodes) wrote : | # |
OK. All those changes have been pushed
- 35. By John Ferlito
-
merge in trunk
Jamu Kakar (jkakar) wrote : | # |
[9]
+ def _get_revno(self):
+ # FIXME Can't use this until we move to using bzrlib
+ # directly as it causes to much hassle with FakeExpect
+ revno = self.expect.
+ logfile=file,
+ timeout=None)
+ print revno
+ return revno
I would remove this. We can add it when its necessary. Thanks for
adding the TODO about it in _get_version.
[10]
+ "now": time.strftime(
+ "today": datetime.
These should be changed to:
now = datetime.utcnow()
...
"now": now.strftime(
[11]
I have a test failure:
[FAIL]: autoppa.
Traceback (most recent call last):
File "/usr/lib/
testMethod()
File "/home/
self.
exceptions.
Looking great, +1 considering these comments. Have you had a chance
to sign the Canonical contributor agreement yet?
John Ferlito (johnf-inodes) wrote : | # |
On Wed, Oct 28, 2009 at 04:36:59AM -0000, Jamu Kakar wrote:
> Review: Approve
> [9]
>
> + def _get_revno(self):
> + # FIXME Can't use this until we move to using bzrlib
> + # directly as it causes to much hassle with FakeExpect
> + revno = self.expect.
> + logfile=file,
> + timeout=None)
> + print revno
> + return revno
>
> I would remove this. We can add it when its necessary. Thanks for
> adding the TODO about it in _get_version.
Done.
>
>
> [10]
>
> + "now": time.strftime(
> + "today": datetime.
>
> These should be changed to:
>
> now = datetime.utcnow()
> ...
> "now": now.strftime(
> "today": now.strftime(
>
>
> [11]
Done, with changes in next comment.
> I have a test failure:
>
> [FAIL]: autoppa.
>
> Traceback (most recent call last):
> File "/usr/lib/
> testMethod()
> File "/home/
> self.assertEqua
> exceptions.
Fixed. It was because it was a different day. I noticed you had some
datetime_factory code in there. I've moved that up into the
BuildTarget itself so that all date related code has access to it.
> Looking great, +1 considering these comments. Have you had a chance
> to sign the Canonical contributor agreement yet?
Yes, you should have been CC'd on the email.
- 36. By John Ferlito
-
* Remove unused _get_revision code
* Use UTC time for ${now} and ${today}
* Add a datetime_factory to BuildTarget so we can test date stuff properly.
Preview Diff
1 | === modified file 'README' | |||
2 | --- README 2009-09-21 03:13:54 +0000 | |||
3 | +++ README 2009-10-28 06:25:19 +0000 | |||
4 | @@ -105,7 +105,7 @@ | |||
5 | 105 | 105 | ||
6 | 106 | AutoPPA automatically inserts a release version into package version | 106 | AutoPPA automatically inserts a release version into package version |
7 | 107 | numbers. The conventions specified by Ubuntu's SRU [1] policy | 107 | numbers. The conventions specified by Ubuntu's SRU [1] policy |
9 | 108 | should be followed when generating version numbers. In the above | 108 | are followed by default when generating version numbers. In the above |
10 | 109 | example, the smart-0.51-landscape12 would build packages with the | 109 | example, the smart-0.51-landscape12 would build packages with the |
11 | 110 | following versions: | 110 | following versions: |
12 | 111 | 111 | ||
13 | @@ -114,6 +114,30 @@ | |||
14 | 114 | 0.51-landscape12.7.04 | 114 | 0.51-landscape12.7.04 |
15 | 115 | 0.51-landscape12.7.10 | 115 | 0.51-landscape12.7.10 |
16 | 116 | 116 | ||
17 | 117 | A version_template configuration can be set in the autoppa configuration file | ||
18 | 118 | or on the command line using the --version-template flag. For example: | ||
19 | 119 | |||
20 | 120 | [landscape-client] | ||
21 | 121 | version_template = ${version}~ppa1~${dist_codename} | ||
22 | 122 | |||
23 | 123 | would produce: | ||
24 | 124 | |||
25 | 125 | 0.51-landscape12~ppa1~dapper | ||
26 | 126 | 0.51-landscape12~ppa1~edgy | ||
27 | 127 | 0.51-landscape12~ppa1~feisty | ||
28 | 128 | 0.51-landscape12~ppa1~gutsy | ||
29 | 129 | |||
30 | 130 | The following environment variables are available: | ||
31 | 131 | |||
32 | 132 | ${version} - The version passed on the command line | ||
33 | 133 | ${revision} - The revision of the source branch | ||
34 | 134 | ${dist_codename} - dapper, gutsy, etc | ||
35 | 135 | ${dist_version} - 6.04, 6.10, etc | ||
36 | 136 | ${now} - The current time in UTC formatted as YYYYMMDDHHMMSS | ||
37 | 137 | ${today} - Today's date formatted as YYYYMMDD | ||
38 | 138 | ${user} - The name from the USER environment variable | ||
39 | 139 | |||
40 | 140 | |||
41 | 117 | [1] https://wiki.ubuntu.com/MOTU/SRU | 141 | [1] https://wiki.ubuntu.com/MOTU/SRU |
42 | 118 | 142 | ||
43 | 119 | 143 | ||
44 | 120 | 144 | ||
45 | === modified file 'autoppa/application.py' | |||
46 | --- autoppa/application.py 2009-09-21 01:35:24 +0000 | |||
47 | +++ autoppa/application.py 2009-10-28 06:25:19 +0000 | |||
48 | @@ -23,6 +23,9 @@ | |||
49 | 23 | from autoppa.errors import BuildTargetError | 23 | from autoppa.errors import BuildTargetError |
50 | 24 | from autoppa.target import BuildTarget | 24 | from autoppa.target import BuildTarget |
51 | 25 | 25 | ||
52 | 26 | from autoppa import configuration | ||
53 | 27 | |||
54 | 28 | DEFAULT_VERSION_TEMPLATE = "${version}.${dist_version}" | ||
55 | 26 | 29 | ||
56 | 27 | class AutoPPA(object): | 30 | class AutoPPA(object): |
57 | 28 | 31 | ||
58 | @@ -36,7 +39,7 @@ | |||
59 | 36 | self.log_file.write("%s\n" % (message,)) | 39 | self.log_file.write("%s\n" % (message,)) |
60 | 37 | 40 | ||
61 | 38 | def build(self, build_target, version, no_upload=None, no_merge=None, | 41 | def build(self, build_target, version, no_upload=None, no_merge=None, |
63 | 39 | no_tag=None, no_cleanup=None): | 42 | no_tag=None, no_cleanup=None, version_template=None): |
64 | 40 | """Process sources for C{built_target} using the current settings. | 43 | """Process sources for C{built_target} using the current settings. |
65 | 41 | 44 | ||
66 | 42 | @param build_target: The target to build. This should correspond to | 45 | @param build_target: The target to build. This should correspond to |
67 | @@ -44,7 +47,7 @@ | |||
68 | 44 | @param version: The version to for the new build. | 47 | @param version: The version to for the new build. |
69 | 45 | """ | 48 | """ |
70 | 46 | self._log_info("AutoPPA %s" % (VERSION,)) | 49 | self._log_info("AutoPPA %s" % (VERSION,)) |
72 | 47 | build_target = self._create_build_target(build_target, version) | 50 | build_target = self._create_build_target(build_target, version, version_template) |
73 | 48 | build_target.prepare_changelog() | 51 | build_target.prepare_changelog() |
74 | 49 | build_target.prepare_working_tree() | 52 | build_target.prepare_working_tree() |
75 | 50 | for release in build_target.releases: | 53 | for release in build_target.releases: |
76 | @@ -66,17 +69,20 @@ | |||
77 | 66 | """Switch files to use a version and Ubuntu code name.""" | 69 | """Switch files to use a version and Ubuntu code name.""" |
78 | 67 | build_target = BuildTarget("unused-name", version, "unused@email", | 70 | build_target = BuildTarget("unused-name", version, "unused@email", |
79 | 68 | "unused-branch", "unused-repository", | 71 | "unused-branch", "unused-repository", |
81 | 69 | "unused-ppa", [code_name]) | 72 | "unused-ppa", [code_name], |
82 | 73 | DEFAULT_VERSION_TEMPLATE) | ||
83 | 70 | build_target.working_tree = path | 74 | build_target.working_tree = path |
84 | 71 | build_target._prepare_custom_autoppa_files(code_name) | 75 | build_target._prepare_custom_autoppa_files(code_name) |
85 | 72 | build_target._prepare_custom_autoppa_version(code_name) | 76 | build_target._prepare_custom_autoppa_version(code_name) |
86 | 73 | 77 | ||
88 | 74 | def _create_build_target(self, build_target, version, expect=pexpect): | 78 | def _create_build_target(self, build_target, version, version_template, |
89 | 79 | expect=pexpect): | ||
90 | 75 | """Create a L{BuildTarget} instance for C{build_target}. | 80 | """Create a L{BuildTarget} instance for C{build_target}. |
91 | 76 | 81 | ||
92 | 77 | @param build_target: The target to build. This should correspond to | 82 | @param build_target: The target to build. This should correspond to |
93 | 78 | the name of the Debian source package being built. | 83 | the name of the Debian source package being built. |
94 | 79 | @param version: The version to for the new build. | 84 | @param version: The version to for the new build. |
95 | 85 | @param version_template: The template to use to create the version. | ||
96 | 80 | @param expect: Optionally, a L{pexpect} like object. Defaults to | 86 | @param expect: Optionally, a L{pexpect} like object. Defaults to |
97 | 81 | L{pexpect}. | 87 | L{pexpect}. |
98 | 82 | @raises BuildTargetError: Raised when a build target is specified that | 88 | @raises BuildTargetError: Raised when a build target is specified that |
99 | @@ -88,10 +94,15 @@ | |||
100 | 88 | if not data: | 94 | if not data: |
101 | 89 | raise BuildTargetError("'%s' is not a known build target." | 95 | raise BuildTargetError("'%s' is not a known build target." |
102 | 90 | % build_target) | 96 | % build_target) |
103 | 97 | if version_template is None: | ||
104 | 98 | version_template = data.get("version_template", | ||
105 | 99 | DEFAULT_VERSION_TEMPLATE) | ||
106 | 100 | |||
107 | 91 | builder = BuildTarget(build_target, version, data["email"], | 101 | builder = BuildTarget(build_target, version, data["email"], |
108 | 92 | data["branch"], data["repository"], | 102 | data["branch"], data["repository"], |
109 | 93 | data["ppa"], data["releases"].split(), | 103 | data["ppa"], data["releases"].split(), |
111 | 94 | expect=expect, log_file=self.log_file) | 104 | version_template, expect=expect, |
112 | 105 | log_file=self.log_file) | ||
113 | 95 | if "options" in data: | 106 | if "options" in data: |
114 | 96 | options = set(data["options"].split()) | 107 | options = set(data["options"].split()) |
115 | 97 | if "no-version-replacement" in options: | 108 | if "no-version-replacement" in options: |
116 | 98 | 109 | ||
117 | === modified file 'autoppa/commands.py' | |||
118 | --- autoppa/commands.py 2009-09-21 01:20:28 +0000 | |||
119 | +++ autoppa/commands.py 2009-10-28 06:25:19 +0000 | |||
120 | @@ -46,10 +46,13 @@ | |||
121 | 46 | Option("no-cleanup", | 46 | Option("no-cleanup", |
122 | 47 | help="Don't automatically cleanup signed sources and the " | 47 | help="Don't automatically cleanup signed sources and the " |
123 | 48 | "release branch created during a build."), | 48 | "release branch created during a build."), |
124 | 49 | Option("version-template", type=str, | ||
125 | 50 | help="The version template to use when creating the version " | ||
126 | 51 | "for each PPA."), | ||
127 | 49 | ] | 52 | ] |
128 | 50 | 53 | ||
129 | 51 | def run(self, build_target, version, config=None, log=None, no_upload=None, | 54 | def run(self, build_target, version, config=None, log=None, no_upload=None, |
131 | 52 | no_merge=None, no_tag=None, no_cleanup=None): | 55 | no_merge=None, no_tag=None, no_cleanup=None, version_template=None): |
132 | 53 | """Run command.""" | 56 | """Run command.""" |
133 | 54 | if not config: | 57 | if not config: |
134 | 55 | config = os.path.join(os.environ["HOME"], ".autoppa.conf") | 58 | config = os.path.join(os.environ["HOME"], ".autoppa.conf") |
135 | @@ -57,7 +60,8 @@ | |||
136 | 57 | log_file = get_log_file(log, self.outf) | 60 | log_file = get_log_file(log, self.outf) |
137 | 58 | autoppa = AutoPPA(configuration, log_file) | 61 | autoppa = AutoPPA(configuration, log_file) |
138 | 59 | autoppa.build(build_target, version, no_upload=no_upload, | 62 | autoppa.build(build_target, version, no_upload=no_upload, |
140 | 60 | no_merge=no_merge, no_tag=no_tag, no_cleanup=no_cleanup) | 63 | no_merge=no_merge, no_tag=no_tag, no_cleanup=no_cleanup, |
141 | 64 | version_template=version_template) | ||
142 | 61 | 65 | ||
143 | 62 | 66 | ||
144 | 63 | class cmd_switch(Command): | 67 | class cmd_switch(Command): |
145 | 64 | 68 | ||
146 | === modified file 'autoppa/configuration.py' | |||
147 | --- autoppa/configuration.py 2009-10-21 22:40:23 +0000 | |||
148 | +++ autoppa/configuration.py 2009-10-28 06:25:19 +0000 | |||
149 | @@ -21,7 +21,6 @@ | |||
150 | 21 | 21 | ||
151 | 22 | from autoppa.lib.configobj import ConfigObj | 22 | from autoppa.lib.configobj import ConfigObj |
152 | 23 | 23 | ||
153 | 24 | |||
154 | 25 | class Configuration(object): | 24 | class Configuration(object): |
155 | 26 | """Get configuration details for named build targets. | 25 | """Get configuration details for named build targets. |
156 | 27 | 26 | ||
157 | @@ -63,6 +62,7 @@ | |||
158 | 63 | repository = /home/jkakar/src/canonical/landscape-client | 62 | repository = /home/jkakar/src/canonical/landscape-client |
159 | 64 | ppa = landscape-client-ppa | 63 | ppa = landscape-client-ppa |
160 | 65 | releases = dapper edgy feisty gutsy | 64 | releases = dapper edgy feisty gutsy |
161 | 65 | version_template = ~${release_name} | ||
162 | 66 | 66 | ||
163 | 67 | [smart] | 67 | [smart] |
164 | 68 | email = Jamshed Kakar <jamshed.kakar@canonical.com> | 68 | email = Jamshed Kakar <jamshed.kakar@canonical.com> |
165 | @@ -71,7 +71,7 @@ | |||
166 | 71 | ppa = landscape-client-ppa | 71 | ppa = landscape-client-ppa |
167 | 72 | releases = dapper edgy feisty gutsy | 72 | releases = dapper edgy feisty gutsy |
168 | 73 | """ | 73 | """ |
170 | 74 | 74 | ||
171 | 75 | def __init__(self, configuration): | 75 | def __init__(self, configuration): |
172 | 76 | self._configuration = configuration | 76 | self._configuration = configuration |
173 | 77 | 77 | ||
174 | @@ -93,7 +93,8 @@ | |||
175 | 93 | def get_build_target(self, build_target): | 93 | def get_build_target(self, build_target): |
176 | 94 | """Get a C{dict}-like object with data related to C{build_target}.""" | 94 | """Get a C{dict}-like object with data related to C{build_target}.""" |
177 | 95 | try: | 95 | try: |
179 | 96 | return self._configuration[build_target] | 96 | build_target = self._configuration[build_target] |
180 | 97 | return build_target | ||
181 | 97 | except KeyError: | 98 | except KeyError: |
182 | 98 | pass | 99 | pass |
183 | 99 | return None | 100 | return None |
184 | 100 | 101 | ||
185 | === modified file 'autoppa/help_topics.py' | |||
186 | --- autoppa/help_topics.py 2009-09-21 03:13:54 +0000 | |||
187 | +++ autoppa/help_topics.py 2009-10-28 06:25:19 +0000 | |||
188 | @@ -59,3 +59,46 @@ | |||
189 | 59 | 59 | ||
190 | 60 | options = no-version-replacement | 60 | options = no-version-replacement |
191 | 61 | """ | 61 | """ |
192 | 62 | |||
193 | 63 | class topic_version_template(DocstringHelpTopic): | ||
194 | 64 | """Information about version templating functionality. | ||
195 | 65 | |||
196 | 66 | AutoPPA automatically inserts a release version into package version | ||
197 | 67 | numbers. The conventions specified by Ubuntu's SRU [1] policy | ||
198 | 68 | are followed by default when generating version numbers. For example | ||
199 | 69 | if you built a package which had a version of 0.51-landscape12, then you | ||
200 | 70 | would get the following versions for each release: | ||
201 | 71 | |||
202 | 72 | 0.51-landscape12.6.06 | ||
203 | 73 | 0.51-landscape12.6.10 | ||
204 | 74 | 0.51-landscape12.7.04 | ||
205 | 75 | 0.51-landscape12.7.10 | ||
206 | 76 | |||
207 | 77 | A version_template configuration can be set in the autoppa configuration | ||
208 | 78 | file or on the command line using the --version-template flag. For example | ||
209 | 79 | you could add the following to the configuration file for the | ||
210 | 80 | landscape-client package: | ||
211 | 81 | |||
212 | 82 | [landscape-client] | ||
213 | 83 | version_template = ${version}~ppa1~${dist_codename} | ||
214 | 84 | |||
215 | 85 | This would produce versions like: | ||
216 | 86 | |||
217 | 87 | 0.51-landscape12~ppa1~dapper | ||
218 | 88 | 0.51-landscape12~ppa1~edgy | ||
219 | 89 | 0.51-landscape12~ppa1~feisty | ||
220 | 90 | 0.51-landscape12~ppa1~gutsy | ||
221 | 91 | |||
222 | 92 | The following environment variables are available: | ||
223 | 93 | |||
224 | 94 | ${version} - The version passed on the command line | ||
225 | 95 | ${revision} - The revision of the source branch | ||
226 | 96 | ${dist_codename} - dapper, gutsy, etc | ||
227 | 97 | ${dist_version} - 6.04, 6.10, etc | ||
228 | 98 | ${now} - The current time in UTC formatted as YYYYMMDDHHMMSS | ||
229 | 99 | ${today} - Today's date formatted as YYYYMMDD | ||
230 | 100 | ${user} - The name from the USER environment variable | ||
231 | 101 | |||
232 | 102 | |||
233 | 103 | [1] https://wiki.ubuntu.com/MOTU/SRU | ||
234 | 104 | """ | ||
235 | 62 | 105 | ||
236 | === modified file 'autoppa/target.py' | |||
237 | --- autoppa/target.py 2009-10-22 18:06:19 +0000 | |||
238 | +++ autoppa/target.py 2009-10-28 06:25:19 +0000 | |||
239 | @@ -18,10 +18,12 @@ | |||
240 | 18 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | 18 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
241 | 19 | 19 | ||
242 | 20 | from datetime import datetime | 20 | from datetime import datetime |
243 | 21 | import time | ||
244 | 21 | import tempfile | 22 | import tempfile |
245 | 22 | import os | 23 | import os |
246 | 23 | 24 | ||
247 | 24 | import pexpect | 25 | import pexpect |
248 | 26 | from string import Template | ||
249 | 25 | 27 | ||
250 | 26 | from autoppa.errors import ChangelogError, EditorError | 28 | from autoppa.errors import ChangelogError, EditorError |
251 | 27 | from autoppa.file import ReleaseSpecificInclude, VersionReplacement | 29 | from autoppa.file import ReleaseSpecificInclude, VersionReplacement |
252 | @@ -41,7 +43,8 @@ | |||
253 | 41 | """ | 43 | """ |
254 | 42 | 44 | ||
255 | 43 | def __init__(self, name, version, email, branch, repository, ppa, releases, | 45 | def __init__(self, name, version, email, branch, repository, ppa, releases, |
257 | 44 | expect=pexpect, system=os.system, log_file=None): | 46 | version_template, expect=pexpect, system=os.system, |
258 | 47 | datetime_factory=None, log_file=None): | ||
259 | 45 | """ | 48 | """ |
260 | 46 | @param name: The package name. Note that multiple .deb files may be | 49 | @param name: The package name. Note that multiple .deb files may be |
261 | 47 | produced for this package. | 50 | produced for this package. |
262 | @@ -56,10 +59,14 @@ | |||
263 | 56 | @param ppa: The name of the PPA to use, as defined in C{~/.dput.cf}. | 59 | @param ppa: The name of the PPA to use, as defined in C{~/.dput.cf}. |
264 | 57 | @param releases: A list of Ubuntu releases, such as | 60 | @param releases: A list of Ubuntu releases, such as |
265 | 58 | C{['hardy', 'karmic']}. | 61 | C{['hardy', 'karmic']}. |
266 | 62 | @param version_template: A template for adding PPA sepecific version. | ||
267 | 59 | @param expect: Optionally, a L{pexpect}-like object. Defaults to | 63 | @param expect: Optionally, a L{pexpect}-like object. Defaults to |
268 | 60 | L{pexpect}. | 64 | L{pexpect}. |
269 | 61 | @param system: Optionally, an L{os.system}-like function. Defaults to | 65 | @param system: Optionally, an L{os.system}-like function. Defaults to |
270 | 62 | L{os.system}. | 66 | L{os.system}. |
271 | 67 | @param datetime_factory: Optionally, an object that yields a datetime | ||
272 | 68 | instance to use as the changelog time. Defaults to | ||
273 | 69 | C{datetime.utcnow}. | ||
274 | 63 | @param log_file: Optionally, a stream to write log output to. | 70 | @param log_file: Optionally, a stream to write log output to. |
275 | 64 | """ | 71 | """ |
276 | 65 | self.name = name | 72 | self.name = name |
277 | @@ -69,11 +76,13 @@ | |||
278 | 69 | self.repository = repository | 76 | self.repository = repository |
279 | 70 | self.ppa = ppa | 77 | self.ppa = ppa |
280 | 71 | self.releases = releases | 78 | self.releases = releases |
281 | 79 | self.version_template = version_template | ||
282 | 72 | self.working_tree = None | 80 | self.working_tree = None |
283 | 73 | self.changelog = None | 81 | self.changelog = None |
284 | 74 | self.log_file = log_file | 82 | self.log_file = log_file |
285 | 75 | self.expect = expect | 83 | self.expect = expect |
286 | 76 | self.system = system | 84 | self.system = system |
287 | 85 | self.datetime_factory = datetime_factory or datetime.utcnow() | ||
288 | 77 | self.version_replacement = True | 86 | self.version_replacement = True |
289 | 78 | self._prepared_files = set() | 87 | self._prepared_files = set() |
290 | 79 | 88 | ||
291 | @@ -166,7 +175,7 @@ | |||
292 | 166 | def _get_working_tree(self): | 175 | def _get_working_tree(self): |
293 | 167 | return "%s_%s" % (self.name, self.version) | 176 | return "%s_%s" % (self.name, self.version) |
294 | 168 | 177 | ||
296 | 169 | def prepare_custom_files(self, release, datetime_factory=None): | 178 | def prepare_custom_files(self, release): |
297 | 170 | """Prepare the release-specific files for the new release. | 179 | """Prepare the release-specific files for the new release. |
298 | 171 | 180 | ||
299 | 172 | Packages often require release-specific content for files such as the | 181 | Packages often require release-specific content for files such as the |
300 | @@ -187,17 +196,14 @@ | |||
301 | 187 | C{debian/changelog}. A new changelog file is created if necessary. | 196 | C{debian/changelog}. A new changelog file is created if necessary. |
302 | 188 | 197 | ||
303 | 189 | @param release: The name of the release to prepare package files for. | 198 | @param release: The name of the release to prepare package files for. |
304 | 190 | @param datetime_factory: Optionally, an object that yields a datetime | ||
305 | 191 | instance to use as the changelog time. Defaults to | ||
306 | 192 | C{datetime.utcnow}. | 199 | C{datetime.utcnow}. |
307 | 193 | """ | 200 | """ |
308 | 194 | self._log_info("== Preparing custom files for %s on %s ==" | 201 | self._log_info("== Preparing custom files for %s on %s ==" |
309 | 195 | % (self.name, release)) | 202 | % (self.name, release)) |
310 | 196 | datetime_factory = datetime_factory or datetime.utcnow | ||
311 | 197 | self._prepare_custom_autoppa_files(release) | 203 | self._prepare_custom_autoppa_files(release) |
312 | 198 | if self.version_replacement: | 204 | if self.version_replacement: |
313 | 199 | self._prepare_custom_autoppa_version(release) | 205 | self._prepare_custom_autoppa_version(release) |
315 | 200 | self._prepare_custom_changelog(release, datetime_factory) | 206 | self._prepare_custom_changelog(release) |
316 | 201 | 207 | ||
317 | 202 | def _prepare_custom_autoppa_files(self, release): | 208 | def _prepare_custom_autoppa_files(self, release): |
318 | 203 | include = ReleaseSpecificInclude(release) | 209 | include = ReleaseSpecificInclude(release) |
319 | @@ -245,12 +251,23 @@ | |||
320 | 245 | "lucid": "10.04"} | 251 | "lucid": "10.04"} |
321 | 246 | return numbers[release_name] | 252 | return numbers[release_name] |
322 | 247 | 253 | ||
329 | 248 | def _get_version(self, release): | 254 | def _get_version(self, release_name): |
330 | 249 | parts = self.version.split("-", 1) | 255 | version_template = Template(self.version_template) |
331 | 250 | return "%s-%s.%s" % (parts[0], parts[1], | 256 | # TODO Implement revision when we move to bzrlib |
332 | 251 | self._get_release_number(release)) | 257 | # "revision": self._get_revno(), |
333 | 252 | 258 | ||
334 | 253 | def _prepare_custom_changelog(self, release, datetime_factory): | 259 | data = { |
335 | 260 | "version": self.version, | ||
336 | 261 | "dist_codename": release_name, | ||
337 | 262 | "dist_version": self._get_release_number(release_name), | ||
338 | 263 | "now": self.datetime_factory.strftime("%Y%m%d%H%M%S"), | ||
339 | 264 | "today": self.datetime_factory.strftime("%Y%m%d"), | ||
340 | 265 | "user": os.environ["USER"] | ||
341 | 266 | } | ||
342 | 267 | |||
343 | 268 | return version_template.substitute(data) | ||
344 | 269 | |||
345 | 270 | def _prepare_custom_changelog(self, release): | ||
346 | 254 | try: | 271 | try: |
347 | 255 | path = os.path.join(self.working_tree, "debian/changelog") | 272 | path = os.path.join(self.working_tree, "debian/changelog") |
348 | 256 | file = open(path, "r") | 273 | file = open(path, "r") |
349 | @@ -262,7 +279,7 @@ | |||
350 | 262 | old_changelog = "" | 279 | old_changelog = "" |
351 | 263 | 280 | ||
352 | 264 | version = self._get_version(release) | 281 | version = self._get_version(release) |
354 | 265 | date = datetime_factory().strftime("%a, %-d %b %Y %H:%M:%S +0000") | 282 | date = self.datetime_factory.strftime("%a, %-d %b %Y %H:%M:%S +0000") |
355 | 266 | changelog = """\ | 283 | changelog = """\ |
356 | 267 | %(package)s (%(version)s) %(release)s; urgency=low | 284 | %(package)s (%(version)s) %(release)s; urgency=low |
357 | 268 | 285 | ||
358 | 269 | 286 | ||
359 | === modified file 'autoppa/tests/test_configuration.py' | |||
360 | --- autoppa/tests/test_configuration.py 2009-10-21 22:40:23 +0000 | |||
361 | +++ autoppa/tests/test_configuration.py 2009-10-28 06:25:19 +0000 | |||
362 | @@ -57,6 +57,7 @@ | |||
363 | 57 | branch = /home/john/src/supertool/production | 57 | branch = /home/john/src/supertool/production |
364 | 58 | repository = /home/john/src/supertool | 58 | repository = /home/john/src/supertool |
365 | 59 | releases = dapper edgy gutsy feisty | 59 | releases = dapper edgy gutsy feisty |
366 | 60 | version-template = ~${release_name}~ppa | ||
367 | 60 | """ | 61 | """ |
368 | 61 | path = self.fs.make_path(content=content) | 62 | path = self.fs.make_path(content=content) |
369 | 62 | configuration = Configuration.from_file(path) | 63 | configuration = Configuration.from_file(path) |
370 | @@ -65,6 +66,7 @@ | |||
371 | 65 | self.assertEquals(data["branch"], "/home/john/src/supertool/production") | 66 | self.assertEquals(data["branch"], "/home/john/src/supertool/production") |
372 | 66 | self.assertEquals(data["repository"], "/home/john/src/supertool") | 67 | self.assertEquals(data["repository"], "/home/john/src/supertool") |
373 | 67 | self.assertEquals(data["releases"], "dapper edgy gutsy feisty") | 68 | self.assertEquals(data["releases"], "dapper edgy gutsy feisty") |
374 | 69 | self.assertEquals(data["version-template"], "~${release_name}~ppa") | ||
375 | 68 | 70 | ||
376 | 69 | def test_get_missing_build_target(self): | 71 | def test_get_missing_build_target(self): |
377 | 70 | """ | 72 | """ |
378 | 71 | 73 | ||
379 | === modified file 'autoppa/tests/test_target.py' | |||
380 | --- autoppa/tests/test_target.py 2009-10-21 22:20:53 +0000 | |||
381 | +++ autoppa/tests/test_target.py 2009-10-28 06:25:19 +0000 | |||
382 | @@ -33,10 +33,12 @@ | |||
383 | 33 | self.expect = FakeExpect() | 33 | self.expect = FakeExpect() |
384 | 34 | self.fs = FilesystemPath() | 34 | self.fs = FilesystemPath() |
385 | 35 | self.branch_path = self.fs.make_dir("production") | 35 | self.branch_path = self.fs.make_dir("production") |
386 | 36 | datetime_factory = datetime(2007, 8, 2, 13, 14, 15) | ||
387 | 36 | self.builder = BuildTarget( | 37 | self.builder = BuildTarget( |
388 | 37 | "supertool", "1.3.11-upside1", "John Smith <john@upside.com>", | 38 | "supertool", "1.3.11-upside1", "John Smith <john@upside.com>", |
389 | 38 | self.branch_path, self.fs.dirname, "supertool-ppa", | 39 | self.branch_path, self.fs.dirname, "supertool-ppa", |
391 | 39 | ["dapper", "edgy", "feisty"], expect=self.expect, | 40 | ["dapper", "edgy", "feisty"], "${version}.${dist_version}", |
392 | 41 | expect=self.expect, datetime_factory=datetime_factory, | ||
393 | 40 | system=self.expect.run) | 42 | system=self.expect.run) |
394 | 41 | 43 | ||
395 | 42 | def tearDown(self): | 44 | def tearDown(self): |
396 | @@ -254,6 +256,30 @@ | |||
397 | 254 | finally: | 256 | finally: |
398 | 255 | file.close() | 257 | file.close() |
399 | 256 | 258 | ||
400 | 259 | def test_prepare_custom_files_with_custom_version_content(self): | ||
401 | 260 | """ | ||
402 | 261 | L{BuildTarget.prepare_custom_files} replaces the magic | ||
403 | 262 | C{AUTOPPA_VERSION()} symbol in lines found in processed files | ||
404 | 263 | with a custom version template. | ||
405 | 264 | """ | ||
406 | 265 | filename = self.fs.make_path(content="version = 'AUTOPPA_VERSION()'", | ||
407 | 266 | path="debian/version") | ||
408 | 267 | original_user = os.environ.get("USER") | ||
409 | 268 | os.environ["USER"] = "user_from_env" | ||
410 | 269 | try: | ||
411 | 270 | self.builder.version_template = ("${version}~${dist_codename}~" | ||
412 | 271 | "${dist_version}~${now}~${today}~${user}") | ||
413 | 272 | self.builder.working_tree = self.fs.dirname | ||
414 | 273 | self.builder.prepare_custom_files("dapper") | ||
415 | 274 | file = open(filename, "r") | ||
416 | 275 | |||
417 | 276 | expected = ("version = 'AUTOPPA_VERSION(1.3.11-upside1~dapper~" | ||
418 | 277 | "6.06~20070802131415~20070802~user_from_env)'") | ||
419 | 278 | self.assertEquals(file.read(), expected) | ||
420 | 279 | file.close() | ||
421 | 280 | finally: | ||
422 | 281 | os.environ["USER"] = original_user | ||
423 | 282 | |||
424 | 257 | def test_prepare_custom_files_with_version_replacement_suppressed(self): | 283 | def test_prepare_custom_files_with_version_replacement_suppressed(self): |
425 | 258 | """ | 284 | """ |
426 | 259 | L{BuildTarget.prepare_custom_files} replaces the magic | 285 | L{BuildTarget.prepare_custom_files} replaces the magic |
427 | @@ -298,8 +324,7 @@ | |||
428 | 298 | self.builder.changelog = " * Supertool runs 3x faster than before!" | 324 | self.builder.changelog = " * Supertool runs 3x faster than before!" |
429 | 299 | self.builder.working_tree = self.fs.dirname | 325 | self.builder.working_tree = self.fs.dirname |
430 | 300 | self.assertFalse(os.path.exists(changelog_filename)) | 326 | self.assertFalse(os.path.exists(changelog_filename)) |
433 | 301 | factory = lambda: datetime(2007, 8, 2, 13, 14, 15) | 327 | self.builder.prepare_custom_files("dapper") |
432 | 302 | self.builder.prepare_custom_files("dapper", datetime_factory=factory) | ||
434 | 303 | file = open(changelog_filename, "r") | 328 | file = open(changelog_filename, "r") |
435 | 304 | try: | 329 | try: |
436 | 305 | changelog = file.read() | 330 | changelog = file.read() |
437 | @@ -338,8 +363,7 @@ | |||
438 | 338 | 363 | ||
439 | 339 | self.builder.changelog = " * Supertool runs 3x faster than before!" | 364 | self.builder.changelog = " * Supertool runs 3x faster than before!" |
440 | 340 | self.builder.working_tree = self.fs.dirname | 365 | self.builder.working_tree = self.fs.dirname |
443 | 341 | factory = lambda: datetime(2007, 8, 2, 13, 14, 15) | 366 | self.builder.prepare_custom_files("dapper") |
442 | 342 | self.builder.prepare_custom_files("dapper", datetime_factory=factory) | ||
444 | 343 | file = open(changelog_filename, "r") | 367 | file = open(changelog_filename, "r") |
445 | 344 | try: | 368 | try: |
446 | 345 | changelog = file.read() | 369 | changelog = file.read() |
Version templates