Merge lp:~mvo/launchpad/support-timeframe-fix-660433 into lp:launchpad/db-devel
- support-timeframe-fix-660433
- Merge into db-devel
Status: | Merged |
---|---|
Merge reported by: | Gavin Panella |
Merged at revision: | not available |
Proposed branch: | lp:~mvo/launchpad/support-timeframe-fix-660433 |
Merge into: | lp:launchpad/db-devel |
Diff against target: |
767 lines (+399/-67) 6 files modified
cronscripts/publishing/cron.germinate (+25/-9) cronscripts/publishing/maintenance-check.py (+104/-58) lib/lp/soyuz/scripts/tests/germinate-test-data/mock-bin/germinate (+5/-0) lib/lp/soyuz/scripts/tests/germinate-test-data/mock-bin/lockfile (+8/-0) lib/lp/soyuz/scripts/tests/germinate-test-data/mock-lp-root/scripts/ftpmaster-tools/lp-query-distro.py (+27/-0) lib/lp/soyuz/scripts/tests/test_cron_germinate.py (+230/-0) |
To merge this branch: | bzr merge lp:~mvo/launchpad/support-timeframe-fix-660433 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Michael Vogt (community) | Needs Resubmitting | ||
Jeroen T. Vermeulen (community) | code | Approve | |
Colin Watson | Pending | ||
Review via email: mp+38503@code.launchpad.net |
Commit message
Update support-timeframe info for NEW packages.
Description of the change
Hello,
this branch fixes the soyuz bug #660433. It will re-generate the support-timeframe information (Supported tag in more-extras.
I added a simple test for the functionality. I'm not sure it follows the guidelines, there was no tests/ directory under cronscripts/
Its also prepares mock-data (./mock-
Someone with soyuz experience (and knowledge about e.g. the content of "crontab -l") needs to review this carefully as it will affect the extra-overrides file from stable distros and therefore modify stuff in $distro-updates.
Cheers,
Michael
Michael Vogt (mvo) wrote : | # |
Robert Collins (lifeless) wrote : | # |
That sample data will add to the tree size and isn't necessary or
desirable - could you please uncommit back to before you added it and
resubmit? Thanks.
Binary files in bzr is a bad idea, and anytime it seems like a good
one... its not :)
-Rob
Michael Vogt (mvo) wrote : | # |
Hey Robert, thanks for your review. I'm happy to remove the data. Please note that its empty gz files currently, so the data added to bzr should be small. But I'm fine with removing it as its currently not required (something small binray (one or two stanzas will be required when we test the germinate output though, so advise is welcome how to handle this).
Robert Collins (lifeless) wrote : | # |
On Fri, Oct 15, 2010 at 8:57 PM, Michael Vogt <email address hidden> wrote:
> Hey Robert, thanks for your review. I'm happy to remove the data. Please note that its empty gz files currently, so the data added to bzr should be small. But I'm fine with removing it as its currently not required (something small binray (one or two stanzas will be required when we test the germinate output though, so advise is welcome how to handle this).
We already have such data elsewhere in the tree, or we can generate it
on demand.
We're currently working on parallel testing too, which means that
tests *cannot* depend on mutating data in the tree.
(and yes, you'll need to have it be a python unittest).
-Rob
- 9888. By Michael Vogt
-
remove all binary data from the tree and generate it on the fly
- 9889. By Michael Vogt
-
cronscripts/
publishing/ tests/test_ cron.germinate. py: convert test to python - 9890. By Michael Vogt
-
cronscripts/
publishing/ tests/test_ cron.germinate: remove shell script test
Michael Vogt (mvo) wrote : | # |
I generate the data on the fly now and converted the shell to proper unittest. Please have another look.
- 9891. By Michael Vogt
-
clear mock ubuntu/dists data too
Jeroen T. Vermeulen (jtv) wrote : | # |
Hi Michael,
Thanks for the branch. I'm ecstatic to see someone work on these scripts, especially with tests attached; but a bit uncomfortable reviewing the changes. Most of the existing code seems absolutely ancient and ill-matched to today's source tree. I'll resist the temptation to say "while you're here, could you also clean up this bit of other code" a lot. :-)
Julian is still looking at the testing and design sides, but I'll review the code on the assumption that that will come out okay. Lots of notes though. I hope you won't be put off by them!
=== modified file 'cronscripts/
--- cronscripts/
+++ cronscripts/
@@ -126,10 +125,19 @@
done
echo " done."
-# now generate the Supported extra overrides
-$MAINTAINCE_CHECK $suite > "$MISCROOT/
-if [ $? -eq 0 ]; then
- cat "$MISCROOT/
-fi
-
mv -f "$MISCROOT/
+
+# now generate the Supported extra overrides for all supported distros
+for supported_suite in `$LAUNCHPADROOT
The lines in this script get pretty long. Could you place the "do" on a separate line?
for supported_suite in `$LAUNCHPADROOT
do
# ...
done
+ echo -n "Running maintenance-check for $supported_suite... "
+ if $MAINTAINCE_CHECK $supported_suite > "$MISCROOT/
And this one is now definitely too long! It'd help if these enormous filenames were in sensibly-named variables. Makes it easier to get an overview of what's happening.
+ # make sure the more-extra.override file exists
+ touch "$MISCROOT/
This comment just re-words the code. Instead, could you make it say very briefly _why_ it does this?
(Also, contrary to what you see in these scripts, please start your sentences with capital letters and punctuate them!).
+ # remove old "Supporte" info from extra overrides
Typo: missing "d." Also, please capitalize & punctuate.
+ sed /"^.* Supported"/d "$MISCROOT/
+ cat "$MISCROOT/
+ mv "$MISCROOT/
+ fi
+ echo " done"
+done
Does this piece of the script want to live in its own function?
=== modified file 'cronscripts/
--- cronscripts/
+++ cronscripts/
@@ -297,7 +297,11 @@
...
- 9892. By Michael Vogt
-
cronscripts/
publishing/ cron.germinate: address merge review issues raised by jtv - 9893. By Michael Vogt
-
cronscripts/
publishing/ maintenance- check.py: fix missing capitalization and punctation and kill off whitespace - 9894. By Michael Vogt
-
cronscripts/
publishing/ tests/mock- data/mock- bin/germinate: add comment in the script header - 9895. By Michael Vogt
-
cronscripts/
publishing/ tests/mock- data/mock- lp-root/ scripts/ ftpmaster- tools/lp- query-distro. py: update to include comment and error checking and a else claue - 9896. By Michael Vogt
-
cronscripts/
publishing/ tests/test_ cron.germinate. py: address a lot of the review points, punctation, test template, variable naming, comments and docstrings (more to come)
Martin Pool (mbp) wrote : | # |
Thanks for reviewing it, Jeroen. I want to contribute a meta-review.
First off, thanks for reviewing this quickly and expressing enthusiasm for what mvo did. Those two things make a big difference to the speed at which anyone can contribute and they're especially important for new contributors.
> + gz = gzip.GzipFile(
> + gz.close()
>
> Here too it would be nice to have a helper: "create gzip file."
>
>
> + # binaries
>
> Cap & Punct.
>
>
> + for arch in self.ARCHES:
> + for p in ["", "debian-
>
> Please replace "p" with a full variable name.
>
>
> + d = os.path.join(
>
> Same for "d."
This kind of review comment I think is not so good, for a couple of reasons.
It's bad scaling behaviour to manually comment on all N instances of a problem, when a single comment would cover all of them. It seems to me that, like in my recent contribution, the problem is not that mvo made some particular mistakes, but that he just didn't know of some Launchpad conventions. I think it would be better to have a shorter review with the coding standard URL and pointing out the particular bits that are relevant. It will be quicker for you too.
I don't know how much mvo has participated in lp development before but I'm guessing not that much. So he probably won't know he ought to run 'make lint', or the quirk that it only covers currently uncommitted code.
However when somebody is putting up an early patch that violates these pretty minor rules, I wonder how much it is worth getting them to go back and eg remove whitespace. istm it is better to build up more knowledge of conventions in their head, and more enthusiasm for the project. Again, probably better scaling behaviour.
Saying "I don't understand this, please add a comment" or "you don't need this" is of course fine.
my 2c.
Jeroen T. Vermeulen (jtv) wrote : | # |
Martin, you make a good point. I was actually just trying to be helpful: since I'm "proof-reading" the entire diff anyway, there's no need for Michael to go over the whole thing to find each individual instance that needs changing. I just noted them consistently, as is common practice in Launchpad reviews.
I'm used to this practice and don't feel in any way accused when a reviewer does it for me (or accusatory when I do it for someone else). But now that you mention it, I suppose it does need an explanation for new contributors.
Jeroen T. Vermeulen (jtv) wrote : | # |
The starting point for the ins and outs of writing Launchpad branches, by the way, is here: https:/
Unfortunately there's rather a lot of it. The actual coding rules is in pages linked from there, notably the Python style guide.
Michael Vogt (mvo) wrote : | # |
Thanks for the review Jeroen and thanks for the meta-review from Martin as well!
I update the code to adress a lot of the points, but there is more to be done. I'm happy
about the detailed review as it means I can just go over it point by point. The result
is that the code is now better and more readable. Martin is right, I don't usually do LP
development and I'm not familiar with the processes. I just want to fix this bug as it
affects the distro (badly) :)
I do not nessecarily agree with all of the points in the review (e.g. I think short variable
like "d" are fine if they are just used in a two lines or a short function). But that is fine, its more important that its consistent with the rest of the codebase.
The only "grief" I have is the testing template. To test a small part of LP like this
that does not need the database or other fancy part using the template drags in a huge
set of python dependencies, including psycopg2, storm, transactions, windmill
(that appears to be not packaged in ubuntu maverick) and more. It would be great to be
able to use the test template without all this if its not actually needed for the test
at hand.
Martin Pool (mbp) wrote : | # |
On 21 October 2010 15:28, Jeroen T. Vermeulen <email address hidden> wrote:
> Martin, you make a good point. Â I was actually just trying to be helpful: since I'm "proof-reading" the entire diff anyway, there's no need for Michael to go over the whole thing to find each individual instance that needs changing. Â I just noted them consistently, as is common practice in Launchpad reviews.
>
> I'm used to this practice and don't feel in any way accused when a reviewer does it for me (or accusatory when I do it for someone else). Â But now that you mention it, I suppose it does need an explanation for new contributors.
I don't take it as accusatory at all. There are probably some things
we could do in lp reviews to help with this - it would be neat if your
editor could jump through a list of review comments with the lines
they correspond to, or perhaps if a reviewer could more easily get in
and edit the branch...
--
Martin
- 9897. By Michael Vogt
-
cronscripts/
publishing/ tests/test_ cron.germinate. py: refactor to create fake ubuntu archive root as a tempdir and add new helper create_ directory_ if_missing - 9898. By Michael Vogt
-
cronscripts/
publishing/ tests/test_ cron.germinate. py: move creating the germinate process environment into its own function, add gzip helper, add directory lists helper - 9899. By Michael Vogt
-
cronscripts/
publishing/ tests/test_ cron.germinate. py: add helper create_file()
Michael Vogt (mvo) wrote : | # |
Beside the following two open issues I think I fixed all of the things mentioned.
Open is:
I don't use from lp.testing import TestCase because I could not make it work on my machine.
Adding the launchpad PPA and installing the launchpad-
I either get:
ImportError: No module named windmill.
or
ImportError: No module named fixtures (when importing from lp.testing import TestCase only)
I guess I do something wrong but I don't know what.
The other one is that I did not change the directory layout yet (where the tests lives).
Colin Watson (cjwatson) wrote : | # |
I don't expect problems here from a deployment point of view; obviously (say) dists/lucid/ won't be changed, as opposed to dists/lucid-
One thing that jumped out at me, although I realise it was in the pre-existing code too:
- if distro[0] < 'h':
- print "ERROR: only hardy or later is supported"
+ if distro[0] < 'l':
+ logging.error("only lucid or later is supported")
We're only six years or so away from wrapping around the end of the alphabet. Perhaps this needs to be more explicit somehow? Of course, having to list all historical release names here isn't particularly great either ...
Michael Vogt (mvo) wrote : | # |
Hello Colin, thanks for this feedback. The generated Suported fields will indeed be only be updated for changed or added Packages. But that is ok, before lucid-final we reviewed the data to made sure that it is sane. The open issue is that newly published kernels to not get the right Supported field currently and that makes ubuntu-
The wrapping is a good point, I just added the relevant historic names to make it explicit.
- 9900. By Michael Vogt
-
cronscripts/
publishing/ tests/mock- data/mock- lp-root/ scripts/ ftpmaster- tools/lp- query-distro. py: return more supported distros to test filter in maintenance- check.py - 9901. By Michael Vogt
-
cronscripts/
publishing/ maintenance- check.py: make unsupported release names explicit to avoid future problems when the codenames wrap around (thanks to Colin!)
Julian Edwards (julian-edwards) wrote : | # |
167 +# mvo: I would love to use this, but it appears doing this import
168 +# requires python-psycopg2, python-storm, python-transaction,
169 +# python-lazr.restful and now "windmill" that is not packaged
170 +# at this point I give up and let someone else with a proper
171 +# LP environment fix this
172 +#from canonical.
In an ideal world every test would not use any layers because it's massively quicker to run the tests. However, I can't see any reason that your tests need layers so I think it's fine to remove this commented block entirely.
- 9902. By Michael Vogt
-
cronscripts/
publishing/ tests/test_ cron.germinate. py: remove (commented out) import for canonical. testing. layers, use abspath() for BASEPATH to ensure it works correctly when run from different dirs
Michael Vogt (mvo) wrote : | # |
Thanks Julian, I removed that part of the diff now. I still can not use from lp.testing import TestCase for some reason.
Julian Edwards (julian-edwards) wrote : | # |
I'd personally be happy with you using the unittest one if it means you can run your own tests.
Jeroen T. Vermeulen (jtv) wrote : | # |
With apologies for the delays—holiday and crisis, yin and yang—I'm just coming back to this branch. I hope I can help with this problem:
> Beside the following two open issues I think I fixed all of the things
> mentioned.
> Open is:
>
> I don't use from lp.testing import TestCase because I could not make it work
> on my machine.
> Adding the launchpad PPA and installing the launchpad-
> help.
>
> I either get:
> ImportError: No module named windmill.
> canonical.
> or
> ImportError: No module named fixtures (when importing from lp.testing import
> TestCase only)
> I guess I do something wrong but I don't know what.
These are external modules that have recently been updated. Try running rocketfuel-get (or if that doesn't do the trick, rocketfuel-setup). Then, in your branch, run
{{{
. ~/.rocketfuel-
utilities/
make
}}}
That should update your branch to use the latest external modules. You need to re-run rocketfuel-get from time to time to keep them updated. Sometimes you also need to merge in newer versions of your parent branch.
Jeroen T. Vermeulen (jtv) wrote : | # |
Thanks for all the work you did on this! Is it just me or does the diff look a lot shorter now, despite having the new bits code? It certainly seems easier to read.
=== modified file 'cronscripts/
--- cronscripts/
+++ cronscripts/
+# Now generate the Supported extra overrides for all supported distros.
+SUITES=
+for supported_suite in $SUITES; do
+ echo -n "Running maintenance-check for $supported_suite... "
+ # The support timeframe information is stored here
+ SUPPORTED=
+ # This is the target override file that contains germinate plus support info
+ TARGET=
+ # Debug/Log information
+ LOG="_maintenan
+ if $MAINTAINCE_CHECK $supported_suite > $SUPPORTED 2> $LOG; then
+ # The target file may be missing on the server and the script should
+ # not fail if that is the case.
+ touch $TARGET
+ # Remove old "Supported" info from extra-overrides as it may be
+ # stale now and we replace it with fresh content below.
+ sed /"^.* Supported"/d $TARGET > ${TARGET}.new
+ cat $SUPPORTED >> ${TARGET}.new
+ mv ${TARGET}.new $TARGET
+ fi
+ echo " done"
+done
This looks nice and clear.
=== modified file 'cronscripts/
--- cronscripts/
+++ cronscripts/
+# Names of the distribution releases that are not supported by this
+# tool. All later versions are supported.
+UNSUPPORTED_
+ "intrepid", "jaunty", "karmic"]
A small thing: our coding standards say this should be formatted as
UNSUPPORTED_
"dapper",
"edgy",
"feisty",
"gutsy",
"hardy",
"intrepid",
"jaunty",
"karmic",
]
(Notice the trailing comma even on the last line.)
@@ -275,8 +282,8 @@
- if distro[0] < 'h':
- print "ERROR: only hardy or later is supported"
+ if distro in UNSUPPORTED_
+ logging.error("only lucid or later is supported")
Much nicer, yes!
=== added directory 'cronscripts/
=== added directory 'cronscripts/
=== added directory 'cronscripts/
=== added file 'cronscripts/
--- cronscripts/
+++ cronscripts/
@@ -0,0 +1,5 @@
+#!/bin/sh
+#
+# This is a mock germinate script that just produces enough (empty)
+# files so that the cron.germinate shell script can run.
+touch structure all all.sources minimal standard
Perfect. This tells me exactly what I'm looki...
Jeroen T. Vermeulen (jtv) wrote : | # |
(Setting review type to "code," because the ec2 landing script requires an Approved vote of that type.)
- 9903. By Michael Vogt
-
cronscripts/
publishing/ tests/mock- data/mock- lp-root/ scripts/ ftpmaster- tools/lp- query-distro. py: fix pocketlint errors (indent, spacing) - 9904. By Michael Vogt
-
cronscripts/
publishing/ maintenance- check.py: fix pocketlint errors (spacing, indent, linewrap) - 9905. By Michael Vogt
-
cronscripts/
publishing/ tests/test_ cron.germinate. py: fix pocketlint errors (spacing, indent, linewrap) - 9906. By Michael Vogt
-
cronscripts/
publishing/ tests/test_ cron.germinate. py: updated to follow LP coding standards - 9907. By Michael Vogt
-
cronscripts/
publishing/ tests/test_ cron.germinate. py, cronscripts/ publishing/ maintenance- check.py: add SPACE around "=" to follow LP coding standard - 9908. By Michael Vogt
-
cronscripts/
publishing/ tests/test_ cron.germinate. py: adress formating issues and assert messages
Michael Vogt (mvo) wrote : | # |
On Wed, Oct 27, 2010 at 10:46:02AM -0000, Jeroen T. Vermeulen wrote:
> Thanks for all the work you did on this! Is it just me or does the
> diff look a lot shorter now, despite having the new bits code? It
> certainly seems easier to read.
Thanks for the detailed review and sorry for the slow reply, the UDS
was taking all my attention. Its indeed much nicer now.
[..]
> === modified file 'cronscripts/
> --- cronscripts/
> +++ cronscripts/
>
> +# Names of the distribution releases that are not supported by this
> +# tool. All later versions are supported.
> +UNSUPPORTED_
> + "intrepid", "jaunty", "karmic"]
>
> A small thing: our coding standards say this should be formatted as
>
> UNSUPPORTED_
> "dapper",
> "edgy",
> "feisty",
> "gutsy",
> "hardy",
> "intrepid",
> "jaunty",
> "karmic",
> ]
> (Notice the trailing comma even on the last line.)
Thanks, updated in my branch.
[..]
> --- cronscripts/
> +++ cronscripts/
> @@ -0,0 +1,24 @@
> +#!/usr/bin/python
> +#
> +# This is a mock version of the lp-query-distro.py script that
> +# returns static data so that the cron.germinate shell script
> +# can be tested.
> +
> +import sys
> +
> +def error_and_exit():
>
> Another small thing from our coding standards: each top-level (i.e. unindented) class or function definition in a file should have two blank lines above it.
>
> Running "make lint" should tell you about these things. With such old code though, it's possible that your changes drown among warnings for code you didn't even touch.
[..]
Thanks, I fixed that in my branch now as well. I can not run make lint
apparently without setting up a proper LP dev environment. It
complains about missing external dependencies, if I run the suggested
script it will fails with a non-obvious error. But checking lint.sh.in
shows that pocketlint is used and that makes it trivial to run it.
I went over the pocketlint errors and fixed all of them (except for
one in line 88 that I'm not sure what the correct style to use is).
[..]
> +# mvo: I would love to use this, but it complains about a missing
> +# import for "fixtures" and I can not find a package that
> +# provides this module
> +#from lp.testing import TestCase # or TestCaseWithFactory
>
> The disadvantage of having a very active hands-on architect is that things change so fast. :-) When in doubt, I generally go through these steps:
[..]
Thanks for these tips. For this particular piece of code I do not need
a full launchpad environment so I haven't setup one. But I will keep
this in my tomboy notes for when I need it :)
> + self.ubuntu_
> + self.ubuntu_ger...
Jeroen T. Vermeulen (jtv) wrote : | # |
Hi Michael,
This sure isn't an easy review. My compliments on your tenacity—it'll be really good to have this landed. The code as such is good as far as I'm concerned.
To be honest, developing a branch without a full LP environment set up is probably not a good idea. It messes with your system setup and drops any postgres clusters you may have, but on the bright side, it is fully automated (including easy updates and faster bzr interaction with future branches) and gives you access to "make lint" and the test runner. It may be worth setting up a virtual machine for.
I set up a copy of your branch locally. It turns out that on the one hand, the test suite does run your script test. On the other, it's not run in the right way somehow and it breaks. As it turns out, moving the test and the mock-data directory into lib/lp/
Unfortunately it's still not quite working. The cron.germinate script seems to run a command "lockfile" that it can't find. If this is from a package that needs to be installed on the system, it should be included in either the dependencies for Launchpad or the zc.buildout packages. Otherwise the test suite will not pass on the EC2 and buildbot machines, which start out with clean base systems.
Jeroen
- 9909. By Michael Vogt
-
merged with db-devel
- 9910. By Michael Vogt
-
merged from jtv (many thanks)
- 9911. By Michael Vogt
-
lib/lp/
soyuz/scripts/ tests/germinate -test-data/ mock-bin/ lockfile: add mock lockfile command to ensure cron.germinate finds this command when it needs it - 9912. By Michael Vogt
-
lib/lp/
soyuz/scripts/ tests/germinate -test-data/ mock-bin/ lockfile: return 1 instead of 0 (this is what cron.germinate expects)
Michael Vogt (mvo) wrote : | # |
Thanks for your branch. I merged it into my branch and I have a LP setup now (that took a while to setup). I created a mock lockfile command, however the test is still failing in my lucid VM. Probably some problem with the path shuffling. I look into this tomorrow.
- 9913. By Michael Vogt
-
lib/lp/
soyuz/scripts/ tests/germinate -test-data/ mock-lp- root/cronscript s/publishing/ maintenance- check.py: fix symlink target now that the tests moved to a different directory
Michael Vogt (mvo) wrote : | # |
The branch should be ready now, the tests pass in a LP dev environment for me now.
Jeroen T. Vermeulen (jtv) wrote : | # |
Argh! The test gets stuck when I run it:
Running germinate... .......
Running maintenance-check for hardy... done
Running maintenance-check for jaunty... done
Running maintenance-check for karmic... done
Running maintenance-check for lucid...
At that point maintenance-
What I suspect happens is that the script tries to access the URLs that it has hard-coded into it:
{{{
# germinate output base directory
BASE_URL = "http://
# hints dir url, hints file is "$distro.hints" by default
# (e.g. lucid.hints)
HINTS_DIR_URL = "http://
# we need the archive root to parse the Sources file to support
# by-source hints
ARCHIVE_ROOT = "http://
}}}
The test suite should not make any network connections outside of the test system. I'm afraid that to get this working, we may have to inject test doubles for these URLs as well.
(Also, on a very minor note, the current branch still adds cronscripts/
Michael Vogt (mvo) wrote : | # |
Thanks Jeroen for running this inside the test evnironment. I look into adding test doubles next, that is going to be a bit of work. And I removed the empty dir now :)
- 9914. By Michael Vogt
-
cronscripts/
publishing/ tests: removed, empty now - 9915. By Michael Vogt
-
cronscripts/
publishing/ maintenance- check.py: support url overrides in the environment for {MAINTENANCE_ CHECK_BASE_ URL, MAINTENANCE_ CHECK_HINTS_ DIR_URL, MAINTENANCE_ CHECK_ARCHIVE_ ROOT}
Gavin Panella (allenap) wrote : | # |
Michael, this is a long-lived branch into which you and the reviewers have put a lot of work. Is there something I can do to help you get this landed?
Michael Vogt (mvo) wrote : | # |
Thanks Gavin! I did look into this one again yesterday. I need to create the test dummies, that is tedious work. But the bugfix is important, so I will give it another go.
- 9916. By Michael Vogt
-
lib/lp/
soyuz/scripts/ tests/test_ cron_germinate. py: create mock environment for get-maintenance -check. py because it can not use the network to fetch the real data when the testsuite runs
Michael Vogt (mvo) wrote : | # |
This update should create all the needed files locally now without the need to touch the network. Please note that I added a "class PoorMvosTestCas
Gavin Panella (allenap) wrote : | # |
Michael, I've merged devel into your branch, cleaned up your last revision and put it in lp:~allenap/launchpad/support-timeframe-fix-660433. Please can you merge my branch into yours and push back to Launchpad?
Gavin Panella (allenap) wrote : | # |
Don't worry, I'll land this directly from my branch.
Gavin Panella (allenap) wrote : | # |
I've merged this into *devel* via lp:~allenap/launchpad/support-timeframe-fix-660433.
Michael Vogt (mvo) wrote : | # |
On Thu, Jan 20, 2011 at 07:01:55PM -0000, Gavin Panella wrote:
> Michael, I've merged devel into your branch, cleaned up your last revision and put it in lp:~allenap/launchpad/support-timeframe-fix-660433. Please can you merge my branch into yours and push back to Launchpad?
Thanks a lot for this! And sorry for my late reply, I was away for a
cross distro meeting a couple of days and just returned. Merged and
pushed.
I just read that you will land it from your branch, thats great. I
hope you did not had too much trouble with merge conflicts and all?
Cheers,
Michael
Gavin Panella (allenap) wrote : | # |
Michael, it landed without a hitch, perfect. Thank you for all the work you've done on this :)
Preview Diff
1 | === modified file 'cronscripts/publishing/cron.germinate' |
2 | --- cronscripts/publishing/cron.germinate 2010-11-02 15:54:52 +0000 |
3 | +++ cronscripts/publishing/cron.germinate 2011-01-07 13:50:46 +0000 |
4 | @@ -6,12 +6,12 @@ |
5 | set -e |
6 | set -u |
7 | |
8 | -ARCHIVEROOT=/srv/launchpad.net/ubuntu-archive/ubuntu |
9 | +ARCHIVEROOT=${TEST_ARCHIVEROOT:-/srv/launchpad.net/ubuntu-archive/ubuntu} |
10 | MISCROOT=$ARCHIVEROOT/../ubuntu-misc |
11 | LOCKROOT=$ARCHIVEROOT/.. |
12 | GERMINATEROOT=$ARCHIVEROOT/../ubuntu-germinate |
13 | |
14 | -LAUNCHPADROOT=/srv/launchpad.net/codelines/current |
15 | +LAUNCHPADROOT=${TEST_LAUNCHPADROOT:-/srv/launchpad.net/codelines/current} |
16 | MAINTAINCE_CHECK=$LAUNCHPADROOT/cronscripts/publishing/maintenance-check.py |
17 | |
18 | ## Check to see if another germinate run is in progress |
19 | @@ -28,7 +28,6 @@ |
20 | |
21 | trap cleanup EXIT |
22 | |
23 | -LAUNCHPADROOT=/srv/launchpad.net/codelines/current |
24 | suite=`$LAUNCHPADROOT/scripts/ftpmaster-tools/lp-query-distro.py development` |
25 | |
26 | echo -n "Running germinate... " |
27 | @@ -131,10 +130,27 @@ |
28 | done |
29 | echo " done." |
30 | |
31 | -# now generate the Supported extra overrides |
32 | -$MAINTAINCE_CHECK $suite > "$MISCROOT/more-extra.override.$suite.main.supported" 2> _maintenance-check.stderr |
33 | -if [ $? -eq 0 ]; then |
34 | - cat "$MISCROOT/more-extra.override.$suite.main.supported" >> "$MISCROOT/more-extra.override.$suite.main.new" |
35 | -fi |
36 | - |
37 | mv -f "$MISCROOT/more-extra.override.$suite.main.new" "$MISCROOT/more-extra.override.$suite.main" |
38 | + |
39 | +# Now generate the Supported extra overrides for all supported distros. |
40 | +SUITES=`$LAUNCHPADROOT/scripts/ftpmaster-tools/lp-query-distro.py supported` |
41 | +for supported_suite in $SUITES; do |
42 | + echo -n "Running maintenance-check for $supported_suite... " |
43 | + # The support timeframe information is stored here |
44 | + SUPPORTED="$MISCROOT/more-extra.override.$supported_suite.main.supported" |
45 | + # This is the target override file that contains germinate plus support info |
46 | + TARGET="$MISCROOT/more-extra.override.$supported_suite.main" |
47 | + # Debug/Log information |
48 | + LOG="_maintenance-check.$supported_suite.stderr" |
49 | + if $MAINTAINCE_CHECK $supported_suite > $SUPPORTED 2> $LOG; then |
50 | + # The target file may be missing on the server and the script should |
51 | + # not fail if that is the case. |
52 | + touch $TARGET |
53 | + # Remove old "Supported" info from extra-overrides as it may be |
54 | + # stale now and we replace it with fresh content below. |
55 | + sed /"^.* Supported"/d $TARGET > ${TARGET}.new |
56 | + cat $SUPPORTED >> ${TARGET}.new |
57 | + mv ${TARGET}.new $TARGET |
58 | + fi |
59 | + echo " done" |
60 | +done |
61 | |
62 | === modified file 'cronscripts/publishing/maintenance-check.py' |
63 | --- cronscripts/publishing/maintenance-check.py 2010-05-28 16:17:51 +0000 |
64 | +++ cronscripts/publishing/maintenance-check.py 2011-01-07 13:50:46 +0000 |
65 | @@ -1,7 +1,7 @@ |
66 | #!/usr/bin/python |
67 | # |
68 | # python port of the nice maintainace-check script by Nick Barcet |
69 | -# |
70 | +# |
71 | # taken from: |
72 | # https://code.edge.launchpad.net/~mvo/ubuntu-maintenance-check/python-port |
73 | # (where it will vanish once taken here) |
74 | @@ -9,7 +9,7 @@ |
75 | # this warning filter is only needed on older versions of python-apt, |
76 | # once the machine runs lucid it can be removed |
77 | import warnings |
78 | -warnings.filterwarnings("ignore","apt API not stable yet") |
79 | +warnings.filterwarnings("ignore", "apt API not stable yet") |
80 | import apt |
81 | warnings.resetwarnings() |
82 | |
83 | @@ -29,21 +29,21 @@ |
84 | # - distros "kubuntu", "edubuntu" and "netbook" need to be |
85 | # considered *but* only follow SUPPORT_TIMEFRAME |
86 | # - anything that is in armel follows SUPPORT_TIMEFRAME |
87 | -# |
88 | +# |
89 | |
90 | # codename of the lts releases |
91 | -LTS_RELEASES = [ "dapper", "hardy", "lucid" ] |
92 | +LTS_RELEASES = ["dapper", "hardy", "lucid"] |
93 | |
94 | # architectures that are full supported (including LTS time) |
95 | -PRIMARY_ARCHES = ["i386", "amd64"] |
96 | +PRIMARY_ARCHES = ["i386", "amd64"] |
97 | |
98 | # architectures we support (but not for LTS time) |
99 | SUPPORTED_ARCHES = PRIMARY_ARCHES + ["armel"] |
100 | |
101 | # what defines the seeds is documented in wiki.ubuntu.com/SeedManagement |
102 | -SERVER_SEEDS = [ "supported-server", "server-ship"] |
103 | +SERVER_SEEDS = ["supported-server", "server-ship"] |
104 | DESKTOP_SEEDS = ["ship", "supported-desktop", "supported-desktop-extra"] |
105 | -SUPPORTED_SEEDS = [ "all" ] |
106 | +SUPPORTED_SEEDS = ["all"] |
107 | |
108 | # normal support timeframe |
109 | # time, seeds, arches |
110 | @@ -60,25 +60,46 @@ |
111 | ] |
112 | |
113 | # distro names and if they get LTS support (order is important) |
114 | -DISTRO_NAMES_AND_LTS_SUPPORT = [ ("ubuntu", True), |
115 | - ("kubuntu", True), |
116 | - ("netbook", False), |
117 | - ] |
118 | +DISTRO_NAMES_AND_LTS_SUPPORT = [ |
119 | + ("ubuntu", True), |
120 | + ("kubuntu", True), |
121 | + ("netbook", False), |
122 | + ] |
123 | + |
124 | +# Names of the distribution releases that are not supported by this |
125 | +# tool. All later versions are supported. |
126 | +UNSUPPORTED_DISTRO_RELEASED = [ |
127 | + "dapper", |
128 | + "edgy", |
129 | + "feisty", |
130 | + "gutsy", |
131 | + "hardy", |
132 | + "intrepid", |
133 | + "jaunty", |
134 | + "karmic", |
135 | + ] |
136 | + |
137 | |
138 | # germinate output base directory |
139 | -BASE_URL = "http://people.canonical.com/~ubuntu-archive/germinate-output/" |
140 | +BASE_URL = os.environ.get( |
141 | + "MAINTENANCE_CHECK_BASE_URL", |
142 | + "http://people.canonical.com/~ubuntu-archive/germinate-output/") |
143 | |
144 | # hints dir url, hints file is "$distro.hints" by default |
145 | # (e.g. lucid.hints) |
146 | -HINTS_DIR_URL = "http://people.canonical.com/~ubuntu-archive/seeds/platform.%s/SUPPORTED_HINTS" |
147 | +HINTS_DIR_URL = os.environ.get( |
148 | + "MAINTENANCE_CHECK_HINTS_DIR_URL", |
149 | + "http://people.canonical.com/~ubuntu-archive/seeds/platform.%s/SUPPORTED_HINTS") |
150 | |
151 | # we need the archive root to parse the Sources file to support |
152 | # by-source hints |
153 | -ARCHIVE_ROOT = "http://archive.ubuntu.com/ubuntu" |
154 | +ARCHIVE_ROOT = os.environ.get( |
155 | + "MAINTENANCE_CHECK_ARCHIVE_ROOT", "http://archive.ubuntu.com/ubuntu") |
156 | |
157 | # support timeframe tag used in the Packages file |
158 | SUPPORT_TAG = "Supported" |
159 | |
160 | + |
161 | def get_binaries_for_source_pkg(srcname): |
162 | """ Return all binary package names for the given source package name. |
163 | |
164 | @@ -92,38 +113,41 @@ |
165 | pkgnames.add(binary) |
166 | return pkgnames |
167 | |
168 | + |
169 | def expand_src_pkgname(pkgname): |
170 | """ Expand a package name if it is prefixed with src. |
171 | |
172 | If the package name is prefixed with src it will be expanded |
173 | to a list of binary package names. Otherwise the original |
174 | package name will be returned. |
175 | - |
176 | + |
177 | :param pkgname: The package name (that may include src:prefix). |
178 | - :return: A list of binary package names (the list may be one element long). |
179 | + :return: A list of binary package names (the list may be one element |
180 | + long). |
181 | """ |
182 | if not pkgname.startswith("src:"): |
183 | return [pkgname] |
184 | return get_binaries_for_source_pkg(pkgname.split("src:")[1]) |
185 | |
186 | + |
187 | def create_and_update_deb_src_source_list(distroseries): |
188 | """ Create sources.list and update cache. |
189 | |
190 | - This creates a sources.list file with deb-src entries for a given |
191 | + This creates a sources.list file with deb-src entries for a given |
192 | distroseries and apt.Cache.update() to make sure the data is up-to-date. |
193 | :param distro: The code name of the distribution series (e.g. lucid). |
194 | :return: None |
195 | :raises: IOError: When cache update fails. |
196 | """ |
197 | # apt root dir |
198 | - rootdir="./aptroot.%s" % distroseries |
199 | - sources_list_dir = os.path.join(rootdir, "etc","apt") |
200 | + rootdir = "./aptroot.%s" % distroseries |
201 | + sources_list_dir = os.path.join(rootdir, "etc", "apt") |
202 | if not os.path.exists(sources_list_dir): |
203 | os.makedirs(sources_list_dir) |
204 | - sources_list = open(os.path.join(sources_list_dir, "sources.list"),"w") |
205 | + sources_list = open(os.path.join(sources_list_dir, "sources.list"), "w") |
206 | for pocket in [ |
207 | - "%s" % distroseries, |
208 | - "%s-updates" % distroseries, |
209 | + "%s" % distroseries, |
210 | + "%s-updates" % distroseries, |
211 | "%s-security" % distroseries]: |
212 | sources_list.write( |
213 | "deb-src %s %s main restricted\n" % ( |
214 | @@ -134,13 +158,13 @@ |
215 | sources_list.close() |
216 | # create required dirs/files for apt.Cache(rootdir) to work on older |
217 | # versions of python-apt. once lucid is used it can be removed |
218 | - for d in ["var/lib/dpkg", |
219 | - "var/cache/apt/archives/partial", |
220 | - "var/lib/apt/lists/partial"]: |
221 | - if not os.path.exists(os.path.join(rootdir,d)): |
222 | - os.makedirs(os.path.join(rootdir,d)) |
223 | - if not os.path.exists(os.path.join(rootdir,"var/lib/dpkg/status")): |
224 | - open(os.path.join(rootdir,"var/lib/dpkg/status"),"w") |
225 | + for d in ["var/lib/dpkg", |
226 | + "var/cache/apt/archives/partial", |
227 | + "var/lib/apt/lists/partial"]: |
228 | + if not os.path.exists(os.path.join(rootdir, d)): |
229 | + os.makedirs(os.path.join(rootdir, d)) |
230 | + if not os.path.exists(os.path.join(rootdir, "var/lib/dpkg/status")): |
231 | + open(os.path.join(rootdir, "var/lib/dpkg/status"), "w") |
232 | # open cache with our just prepared rootdir |
233 | cache = apt.Cache(rootdir=rootdir) |
234 | try: |
235 | @@ -148,24 +172,28 @@ |
236 | except SystemError: |
237 | logging.exception("cache.update() failed") |
238 | |
239 | + |
240 | def get_structure(distroname, version): |
241 | """ Get structure file conent for named distro and distro version. |
242 | - |
243 | + |
244 | :param name: Name of the distribution (e.g. kubuntu, ubuntu, xubuntu). |
245 | :param version: Code name of the distribution version (e.g. lucid). |
246 | :return: List of strings with the structure file content |
247 | """ |
248 | - f = urllib2.urlopen("%s/%s.%s/structure" % (BASE_URL, distroname, version)) |
249 | + f = urllib2.urlopen("%s/%s.%s/structure" % ( |
250 | + BASE_URL, distroname, version)) |
251 | structure = f.readlines() |
252 | f.close() |
253 | return structure |
254 | |
255 | + |
256 | def expand_seeds(structure, seedname): |
257 | """ Expand seed by its dependencies using the strucure file. |
258 | |
259 | :param structure: The content of the STRUCTURE file as string list. |
260 | :param seedname: The name of the seed as string that needs to be expanded. |
261 | - :return: a set() for the seed dependencies (excluding the original seedname) |
262 | + :return: a set() for the seed dependencies (excluding the original |
263 | + seedname) |
264 | """ |
265 | seeds = [] |
266 | for line in structure: |
267 | @@ -175,9 +203,10 @@ |
268 | seeds += expand_seeds(structure, seed) |
269 | return set(seeds) |
270 | |
271 | + |
272 | def get_packages_for_seeds(name, distro, seeds): |
273 | """ |
274 | - get packages for the given name (e.g. ubuntu) and distro release |
275 | + get packages for the given name (e.g. ubuntu) and distro release |
276 | (e.g. lucid) that are in the given list of seeds |
277 | returns a set() of package names |
278 | """ |
279 | @@ -185,7 +214,7 @@ |
280 | for bseed in seeds: |
281 | for seed in [bseed]: #, bseed+".build-depends", bseed+".seed"]: |
282 | pkgs_in_seeds[seed] = set() |
283 | - seedurl = "%s/%s.%s/%s" % (BASE_URL,name, distro, seed) |
284 | + seedurl = "%s/%s.%s/%s" % (BASE_URL, name, distro, seed) |
285 | logging.debug("looking for '%s'" % seedurl) |
286 | try: |
287 | f = urllib2.urlopen(seedurl) |
288 | @@ -204,6 +233,7 @@ |
289 | logging.error("seed %s failed (%s)" % (seedurl, e)) |
290 | return pkgs_in_seeds |
291 | |
292 | + |
293 | def what_seeds(pkgname, seeds): |
294 | in_seeds = set() |
295 | for s in seeds: |
296 | @@ -211,6 +241,7 @@ |
297 | in_seeds.add(s) |
298 | return in_seeds |
299 | |
300 | + |
301 | def compare_support_level(x, y): |
302 | """ |
303 | compare two support level strings of the form 18m, 3y etc |
304 | @@ -218,9 +249,10 @@ |
305 | :parm y: the second support level |
306 | :return: negative if x < y, zero if x==y, positive if x > y |
307 | """ |
308 | + |
309 | def support_to_int(support_time): |
310 | """ |
311 | - helper that takes a support time string and converts it to |
312 | + helper that takes a support time string and converts it to |
313 | a integer for cmp() |
314 | """ |
315 | # allow strings like "5y (kubuntu-common) |
316 | @@ -233,7 +265,9 @@ |
317 | raise ValueError("support time '%s' has to end with y or m" % x) |
318 | return cmp(support_to_int(x), support_to_int(y)) |
319 | |
320 | -def get_packages_support_time(structure, name, pkg_support_time, support_timeframe_list): |
321 | + |
322 | +def get_packages_support_time(structure, name, pkg_support_time, |
323 | + support_timeframe_list): |
324 | """ |
325 | input a structure file and a list of pair<timeframe, seedlist> |
326 | return a dict of pkgnames -> support timeframe string |
327 | @@ -255,18 +289,21 @@ |
328 | pkg, old_timeframe, timeframe)) |
329 | pkg_support_time[pkg] = timeframe |
330 | if options.with_seeds: |
331 | - pkg_support_time[pkg] += " (%s)" % ", ".join(what_seeds(pkg, pkgs_in_seeds)) |
332 | + pkg_support_time[pkg] += " (%s)" % ", ".join( |
333 | + what_seeds(pkg, pkgs_in_seeds)) |
334 | |
335 | |
336 | return pkg_support_time |
337 | |
338 | + |
339 | if __name__ == "__main__": |
340 | parser = OptionParser() |
341 | parser.add_option("--with-seeds", "", default=False, |
342 | - action="store_true", |
343 | - help="add seed(s) of the package that are responsible for the maintaince time") |
344 | + action="store_true", |
345 | + help="add seed(s) of the package that are responsible " |
346 | + "for the maintaince time") |
347 | parser.add_option("--source-packages", "", default=False, |
348 | - action="store_true", |
349 | + action="store_true", |
350 | help="show as source pkgs") |
351 | parser.add_option("--hints-file", "", default=None, |
352 | help="use diffenrt use hints file location") |
353 | @@ -275,8 +312,8 @@ |
354 | # init |
355 | if len(args) > 0: |
356 | distro = args[0] |
357 | - if distro[0] < 'h': |
358 | - print "ERROR: only hardy or later is supported" |
359 | + if distro in UNSUPPORTED_DISTRO_RELEASED: |
360 | + logging.error("only lucid or later is supported") |
361 | sys.exit(1) |
362 | else: |
363 | distro = "lucid" |
364 | @@ -286,26 +323,32 @@ |
365 | |
366 | if options.hints_file: |
367 | hints_file = options.hints_file |
368 | - (schema, netloc, path, query, fragment) = urlparse.urlsplit(hints_file) |
369 | + (schema, netloc, path, query, fragment) = urlparse.urlsplit( |
370 | + hints_file) |
371 | if not schema: |
372 | hints_file = "file:%s" % path |
373 | else: |
374 | hints_file = HINTS_DIR_URL % distro |
375 | - |
376 | + |
377 | # go over the distros we need to check |
378 | pkg_support_time = {} |
379 | for (name, lts_supported) in DISTRO_NAMES_AND_LTS_SUPPORT: |
380 | |
381 | # get basic structure file |
382 | - structure = get_structure(name, distro) |
383 | - |
384 | + try: |
385 | + structure = get_structure(name, distro) |
386 | + except urllib2.HTTPError: |
387 | + logging.error("Can not get structure for '%s'." % name) |
388 | + continue |
389 | + |
390 | # get dicts of pkgname -> support timeframe string |
391 | support_timeframe = SUPPORT_TIMEFRAME |
392 | if lts_supported and distro in LTS_RELEASES: |
393 | - support_timeframe = SUPPORT_TIMEFRAME_LTS |
394 | + support_timeframe = SUPPORT_TIMEFRAME_LTS |
395 | else: |
396 | support_timeframe = SUPPORT_TIMEFRAME |
397 | - get_packages_support_time(structure, name, pkg_support_time, support_timeframe) |
398 | + get_packages_support_time( |
399 | + structure, name, pkg_support_time, support_timeframe) |
400 | |
401 | # now go over the bits in main that we have not seen (because |
402 | # they are not in any seed and got added manually into "main" |
403 | @@ -321,10 +364,11 @@ |
404 | for pkg in cache: |
405 | if not pkg.name in pkg_support_time: |
406 | pkg_support_time[pkg.name] = support_timeframe[-1][0] |
407 | - logging.warn("add package in main but not in seeds %s with %s" % |
408 | - (pkg.name, pkg_support_time[pkg.name])) |
409 | + logging.warn( |
410 | + "add package in main but not in seeds %s with %s" % ( |
411 | + pkg.name, pkg_support_time[pkg.name])) |
412 | |
413 | - # now check the hints file that is used to overwrite |
414 | + # now check the hints file that is used to overwrite |
415 | # the default seeds |
416 | try: |
417 | for line in urllib2.urlopen(hints_file): |
418 | @@ -337,14 +381,15 @@ |
419 | if support_time == 'unsupported': |
420 | try: |
421 | del pkg_support_time[pkgname] |
422 | - sys.stderr.write("hints-file: marking %s unsupported\n" % pkgname) |
423 | + sys.stderr.write("hints-file: marking %s " |
424 | + "unsupported\n" % pkgname) |
425 | except KeyError: |
426 | pass |
427 | else: |
428 | if pkg_support_time.get(pkgname) != support_time: |
429 | sys.stderr.write( |
430 | "hints-file: changing %s from %s to %s\n" % ( |
431 | - pkgname, pkg_support_time.get(pkgname), |
432 | + pkgname, pkg_support_time.get(pkgname), |
433 | support_time)) |
434 | pkg_support_time[pkgname] = support_time |
435 | except: |
436 | @@ -353,7 +398,7 @@ |
437 | if e.code != 404: |
438 | raise |
439 | sys.stderr.write("hints-file: %s gave 404 error\n" % hints_file) |
440 | - |
441 | + |
442 | # output suitable for the extra-override file |
443 | for pkgname in sorted(pkg_support_time.keys()): |
444 | # special case, the hints file may contain overrides that |
445 | @@ -362,7 +407,7 @@ |
446 | print "%s %s %s" % ( |
447 | pkgname, SUPPORT_TAG, pkg_support_time[pkgname]) |
448 | else: |
449 | - # go over the supported arches, they are divided in |
450 | + # go over the supported arches, they are divided in |
451 | # first-class (PRIMARY) and second-class with different |
452 | # support levels |
453 | for arch in SUPPORTED_ARCHES: |
454 | @@ -373,10 +418,11 @@ |
455 | if arch in PRIMARY_ARCHES: |
456 | # arch with full LTS support |
457 | print "%s %s %s" % ( |
458 | - pkgname_and_arch, SUPPORT_TAG, pkg_support_time[pkgname]) |
459 | + pkgname_and_arch, SUPPORT_TAG, |
460 | + pkg_support_time[pkgname]) |
461 | else: |
462 | # not a LTS supported architecture, gets only regular |
463 | # support_timeframe |
464 | print "%s %s %s" % ( |
465 | - pkgname_and_arch, SUPPORT_TAG, SUPPORT_TIMEFRAME[0][0]) |
466 | - |
467 | + pkgname_and_arch, SUPPORT_TAG, |
468 | + SUPPORT_TIMEFRAME[0][0]) |
469 | |
470 | === added directory 'lib/lp/soyuz/scripts/tests/germinate-test-data' |
471 | === added directory 'lib/lp/soyuz/scripts/tests/germinate-test-data/mock-bin' |
472 | === added file 'lib/lp/soyuz/scripts/tests/germinate-test-data/mock-bin/germinate' |
473 | --- lib/lp/soyuz/scripts/tests/germinate-test-data/mock-bin/germinate 1970-01-01 00:00:00 +0000 |
474 | +++ lib/lp/soyuz/scripts/tests/germinate-test-data/mock-bin/germinate 2011-01-07 13:50:46 +0000 |
475 | @@ -0,0 +1,5 @@ |
476 | +#!/bin/sh |
477 | +# |
478 | +# This is a mock germinate script that just produces enough (empty) |
479 | +# files so that the cron.germinate shell script can run. |
480 | +touch structure all all.sources minimal standard |
481 | |
482 | === added file 'lib/lp/soyuz/scripts/tests/germinate-test-data/mock-bin/lockfile' |
483 | --- lib/lp/soyuz/scripts/tests/germinate-test-data/mock-bin/lockfile 1970-01-01 00:00:00 +0000 |
484 | +++ lib/lp/soyuz/scripts/tests/germinate-test-data/mock-bin/lockfile 2011-01-07 13:50:46 +0000 |
485 | @@ -0,0 +1,8 @@ |
486 | +#!/bin/sh |
487 | + |
488 | +# This is a mock "lockfile" command that is used during the test |
489 | +# There is no need to have the real lockfile installed (its part |
490 | +# of procmail) because there can be no multiple germinate instances |
491 | +# while we run the tests |
492 | + |
493 | +exit 1 |
494 | |
495 | === added directory 'lib/lp/soyuz/scripts/tests/germinate-test-data/mock-lp-root' |
496 | === added directory 'lib/lp/soyuz/scripts/tests/germinate-test-data/mock-lp-root/cronscripts' |
497 | === added directory 'lib/lp/soyuz/scripts/tests/germinate-test-data/mock-lp-root/cronscripts/publishing' |
498 | === added symlink 'lib/lp/soyuz/scripts/tests/germinate-test-data/mock-lp-root/cronscripts/publishing/maintenance-check.py' |
499 | === target is u'../../../../../../../../../cronscripts/publishing/maintenance-check.py' |
500 | === added directory 'lib/lp/soyuz/scripts/tests/germinate-test-data/mock-lp-root/scripts' |
501 | === added directory 'lib/lp/soyuz/scripts/tests/germinate-test-data/mock-lp-root/scripts/ftpmaster-tools' |
502 | === added file 'lib/lp/soyuz/scripts/tests/germinate-test-data/mock-lp-root/scripts/ftpmaster-tools/lp-query-distro.py' |
503 | --- lib/lp/soyuz/scripts/tests/germinate-test-data/mock-lp-root/scripts/ftpmaster-tools/lp-query-distro.py 1970-01-01 00:00:00 +0000 |
504 | +++ lib/lp/soyuz/scripts/tests/germinate-test-data/mock-lp-root/scripts/ftpmaster-tools/lp-query-distro.py 2011-01-07 13:50:46 +0000 |
505 | @@ -0,0 +1,27 @@ |
506 | +#!/usr/bin/python |
507 | +# |
508 | +# This is a mock version of the lp-query-distro.py script that |
509 | +# returns static data so that the cron.germinate shell script |
510 | +# can be tested. |
511 | + |
512 | +import sys |
513 | + |
514 | + |
515 | +def error_and_exit(): |
516 | + sys.stderr.write("ERROR: I'm a mock, I only support 'development' " |
517 | + "and 'supported' as argument\n") |
518 | + sys.exit(1) |
519 | + |
520 | + |
521 | +if __name__ == "__main__": |
522 | + # There is only a very limited subset of arguments that we support, |
523 | + # test for it and error if it looks wrong |
524 | + if len(sys.argv) != 2: |
525 | + error_and_exit() |
526 | + distro = sys.argv[1] |
527 | + if distro == "development": |
528 | + print "natty" |
529 | + elif distro == "supported": |
530 | + print "hardy jaunty karmic lucid maverick" |
531 | + else: |
532 | + error_and_exit() |
533 | |
534 | === added file 'lib/lp/soyuz/scripts/tests/test_cron_germinate.py' |
535 | --- lib/lp/soyuz/scripts/tests/test_cron_germinate.py 1970-01-01 00:00:00 +0000 |
536 | +++ lib/lp/soyuz/scripts/tests/test_cron_germinate.py 2011-01-07 13:50:46 +0000 |
537 | @@ -0,0 +1,230 @@ |
538 | +#!/usr/bin/python |
539 | +# Copyright 2010 Canonical Ltd. This software is licensed under the |
540 | +# GNU Affero General Public License version 3 (see the file LICENSE). |
541 | + |
542 | +"""This is a test for the soyuz cron.germinate script.""" |
543 | + |
544 | +__metaclass__ = type |
545 | + |
546 | +import copy |
547 | +import gzip |
548 | +import os |
549 | +import subprocess |
550 | +import unittest |
551 | + |
552 | +try: |
553 | + from lp.testing import TestCase |
554 | +except ImportError: |
555 | + # mvo: *cough* poor mans version if no full LP environment is installed |
556 | + class PoorMvosTestCase(unittest.TestCase): |
557 | + def makeTemporaryDirectory(self): |
558 | + import tempfile |
559 | + return tempfile.mkdtemp(prefix="test_cron_germinate_") |
560 | + TestCase = PoorMvosTestCase |
561 | + |
562 | +class TestCronGerminate(TestCase): |
563 | + |
564 | + DISTRO_NAMES = [ "platform", "ubuntu", "kubuntu", "netbook" ] |
565 | + DISTS = ["hardy", "lucid", "maverick"] |
566 | + DEVELOPMENT_DIST = "natty" |
567 | + COMPONENTS = ["main", "restricted", "universe", "multiverse"] |
568 | + ARCHES = ["i386", "amd64", "armel", "powerpc"] |
569 | + BASEPATH = os.path.abspath(os.path.dirname(__file__)) |
570 | + source_root = os.path.normpath( |
571 | + os.path.join(BASEPATH, "..", "..", "..", "..", "..")) |
572 | + |
573 | + def setUp(self): |
574 | + super(TestCronGerminate, self).setUp() |
575 | + |
576 | + # Setup a temp archive directory and populate it with the right |
577 | + # sub-directories. |
578 | + self.tmpdir = self.makeTemporaryDirectory() |
579 | + self.archive_dir = self.setup_mock_archive_environment() |
580 | + self.ubuntu_misc_dir = os.path.join(self.archive_dir, "ubuntu-misc") |
581 | + self.ubuntu_germinate_dir = os.path.join( |
582 | + self.archive_dir, "ubuntu-germinate") |
583 | + # create a mock archive environment for all the distros we |
584 | + # support and also include "updates" and "security" |
585 | + for dist in self.DISTS + [self.DEVELOPMENT_DIST]: |
586 | + self.populate_mock_archive_environment( |
587 | + self.archive_dir, self.COMPONENTS, self.ARCHES, dist) |
588 | + for component in ["security", "updates"]: |
589 | + self.populate_mock_archive_environment( |
590 | + self.archive_dir, self.COMPONENTS, self.ARCHES, |
591 | + "%s-%s" % (dist, component)) |
592 | + # generate test dummies for maintenance-time.py, if this is |
593 | + # set to "None" instead it will use the network to test against |
594 | + # the real data |
595 | + self.germinate_output_dir = self.setup_mock_germinate_output() |
596 | + |
597 | + def create_directory_if_missing(self, directory): |
598 | + """Create the given directory if it does not exist.""" |
599 | + if not os.path.exists(directory): |
600 | + os.makedirs(directory) |
601 | + |
602 | + def create_directory_list_if_missing(self, directory_list): |
603 | + """Create the given directories from the list if they don't exist.""" |
604 | + for directory in directory_list: |
605 | + self.create_directory_if_missing(directory) |
606 | + |
607 | + def create_gzip_file(self, filepath, content=""): |
608 | + """Create a gziped file in the given path with the given content. |
609 | + If not content is given a empty file is created. |
610 | + """ |
611 | + gz = gzip.GzipFile(filepath, "w") |
612 | + gz.write(content) |
613 | + gz.close() |
614 | + |
615 | + def create_file(self, filepath, content=""): |
616 | + """Create a file in the given path with the given content. |
617 | + If not content is given a empty file is created. |
618 | + """ |
619 | + f = open(filepath, "w") |
620 | + f.write(content) |
621 | + f.close() |
622 | + |
623 | + def setup_mock_germinate_output(self): |
624 | + # empty structure files |
625 | + germinate_output_dir = os.path.join( |
626 | + self.tmpdir, "germinate-test-data", "germinate-output") |
627 | + dirs = [] |
628 | + for distro_name in self.DISTRO_NAMES: |
629 | + for distro_series in self.DISTS: |
630 | + dirs.append(os.path.join(germinate_output_dir, "%s.%s" % (distro_name, distro_series))) |
631 | + self.create_directory_list_if_missing(dirs) |
632 | + for dir in dirs: |
633 | + self.create_file(os.path.join(dir, "structure")) |
634 | + return germinate_output_dir |
635 | + |
636 | + def setup_mock_archive_environment(self): |
637 | + """Creates a mock archive environment and populate |
638 | + it with the subdirectories that germinate will expect. |
639 | + """ |
640 | + archive_dir = os.path.join( |
641 | + self.tmpdir, "germinate-test-data", "ubuntu-archive") |
642 | + ubuntu_misc_dir = os.path.join(archive_dir, "ubuntu-misc") |
643 | + ubuntu_germinate_dir = os.path.join(archive_dir, "ubuntu-germinate") |
644 | + ubuntu_dists_dir = os.path.join(archive_dir, "ubuntu", "dists") |
645 | + self.create_directory_list_if_missing([ |
646 | + archive_dir, |
647 | + ubuntu_misc_dir, |
648 | + ubuntu_germinate_dir, |
649 | + ubuntu_dists_dir]) |
650 | + return archive_dir |
651 | + |
652 | + def populate_mock_archive_environment(self, archive_dir, components_list, |
653 | + arches_list, current_devel_distro): |
654 | + """Populates a mock archive environment with empty source packages |
655 | + and empty binary packages. |
656 | + """ |
657 | + for component in components_list: |
658 | + # Create the environment for the source packages. |
659 | + targetdir = os.path.join( |
660 | + archive_dir, |
661 | + "ubuntu/dists/%s/%s/source" % ( |
662 | + current_devel_distro, component)) |
663 | + self.create_directory_if_missing(targetdir) |
664 | + self.create_gzip_file(os.path.join(targetdir, "Sources.gz")) |
665 | + |
666 | + # Create the environment for the binary packages. |
667 | + for arch in arches_list: |
668 | + for subpath in ["", "debian-installer"]: |
669 | + targetdir = os.path.join( |
670 | + self.archive_dir, |
671 | + "ubuntu/dists/%s/%s/%s/binary-%s" % ( |
672 | + current_devel_distro, component, subpath, arch)) |
673 | + self.create_directory_if_missing(targetdir) |
674 | + self.create_gzip_file(os.path.join( |
675 | + targetdir, "Packages.gz")) |
676 | + |
677 | + def create_fake_environment(self, basepath, archive_dir, |
678 | + germinate_output_dir): |
679 | + """Create a fake process envirionment based on os.environ that |
680 | + sets TEST_ARCHIVEROOT, TEST_LAUNCHPADROOT and modifies PATH |
681 | + to point to the mock lp-bin directory. |
682 | + """ |
683 | + fake_environ = copy.copy(os.environ) |
684 | + fake_environ["TEST_ARCHIVEROOT"] = os.path.abspath( |
685 | + os.path.join(archive_dir, "ubuntu")) |
686 | + fake_environ["TEST_LAUNCHPADROOT"] = os.path.abspath( |
687 | + os.path.join(basepath, "germinate-test-data/mock-lp-root")) |
688 | + # Set the PATH in the fake environment so that our mock germinate |
689 | + # is used. We could use the real germinate as well, but that will |
690 | + # slow down the tests a lot and its also not interessting for this |
691 | + # test as we do not use any of the germinate information. |
692 | + fake_environ["PATH"] = "%s:%s" % ( |
693 | + os.path.abspath(os.path.join( |
694 | + basepath, "germinate-test-data/mock-bin")), |
695 | + os.environ["PATH"]) |
696 | + # test dummies for get-support-timeframe.py, they need to be |
697 | + # in URI format |
698 | + if germinate_output_dir: |
699 | + # redirect base url to the mock environment |
700 | + fake_environ["MAINTENANCE_CHECK_BASE_URL"] = "file://%s" % \ |
701 | + germinate_output_dir |
702 | + # point to mock archive root |
703 | + archive_root_url = "file://%s" % os.path.abspath( |
704 | + os.path.join(archive_dir, "ubuntu")) |
705 | + fake_environ["MAINTENANCE_CHECK_ARCHIVE_ROOT"] = archive_root_url |
706 | + # maintenance-check.py expects a format string |
707 | + hints_file_url = germinate_output_dir + "/platform.%s/SUPPORTED_HINTS" |
708 | + for distro in self.DISTS: |
709 | + open(hints_file_url % distro, "w") |
710 | + fake_environ["MAINTENANCE_CHECK_HINTS_DIR_URL"] = "file://%s" % \ |
711 | + os.path.abspath(hints_file_url) |
712 | + # add hints override to test that feature |
713 | + f=open(hints_file_url % "lucid", "a") |
714 | + f.write("linux-image-2.6.32-25-server 5y\n") |
715 | + f.close() |
716 | + return fake_environ |
717 | + |
718 | + def test_maintenance_update(self): |
719 | + """Test the maintenance-check.py porition of the soyuz cron.germinate |
720 | + shell script by running it inside a fake environment and ensure |
721 | + that it did update the "Support" override information for |
722 | + apt-ftparchive without destroying/modifying the information |
723 | + that the "germinate" script added to it earlier. |
724 | + """ |
725 | + # Write into more-extras.overrides to ensure it is alive after we |
726 | + # mucked around. |
727 | + canary = "abrowser Task mock\n" |
728 | + # Build fake environment based on the real one. |
729 | + fake_environ = self.create_fake_environment( |
730 | + self.BASEPATH, self.archive_dir, self.germinate_output_dir) |
731 | + # Create mock override data files that include the canary string |
732 | + # so that we can test later if it is still there. |
733 | + for dist in self.DISTS: |
734 | + self.create_file( |
735 | + os.path.join(self.ubuntu_misc_dir, |
736 | + "more-extra.override.%s.main" % dist), |
737 | + canary) |
738 | + |
739 | + # Run cron.germinate in the fake environment. |
740 | + cron_germinate_path = os.path.join( |
741 | + self.source_root, "cronscripts", "publishing", "cron.germinate") |
742 | + subprocess.call( |
743 | + [cron_germinate_path], env=fake_environ, cwd=self.BASEPATH) |
744 | + |
745 | + # And check the output it generated for correctness. |
746 | + for dist in self.DISTS: |
747 | + supported_override_file = os.path.join( |
748 | + self.ubuntu_misc_dir, |
749 | + "more-extra.override.%s.main.supported" % dist) |
750 | + self.assertTrue(os.path.exists(supported_override_file), |
751 | + "no override file created for '%s'" % dist) |
752 | + main_override_file = os.path.join( |
753 | + self.ubuntu_misc_dir, |
754 | + "more-extra.override.%s.main" % dist) |
755 | + self.assertIn(canary, open(main_override_file).read(), |
756 | + "canary no longer there for '%s'" % dist) |
757 | + |
758 | + # Check here if we got the data from maintenance-check.py that |
759 | + # we expected. This is a kernel name from lucid-updates and it |
760 | + # will be valid for 5 years. |
761 | + needle = "linux-image-2.6.32-25-server/i386 Supported 5y" |
762 | + lucid_supported_override_file = os.path.join( |
763 | + self.ubuntu_misc_dir, "more-extra.override.lucid.main") |
764 | + self.assertIn(needle, open(lucid_supported_override_file).read()) |
765 | + |
766 | +if __name__ == "__main__": |
767 | + unittest.main() |
It also modifies maintenance- check.py to put information only for lucid and later. While the script will work for hardy as well it does not make sense to generate "Supported" info in hardy-updates for it when there is none for the main archive.