Merge lp:~allenap/maas/repackage into lp:maas/trunk

Proposed by Gavin Panella
Status: Rejected
Rejected by: MAAS Lander
Proposed branch: lp:~allenap/maas/repackage
Merge into: lp:maas/trunk
Prerequisite: lp:~allenap/maas/repackage-prep
Diff against target: 5403 lines (+3060/-1035)
94 files modified
.bzrignore (+12/-1)
HACKING.txt (+5/-52)
MANIFEST.in (+0/-10)
Makefile (+111/-131)
buildout.cfg (+0/-232)
etc/maas_local_celeryconfig_cluster.py (+0/-4)
pkg/Makefile (+49/-0)
pkg/common/Makefile (+57/-0)
pkg/common/__init__.py (+194/-0)
pkg/common/checkarchive.py (+96/-0)
pkg/common/tox.ini (+11/-0)
pkg/maas-apiclient/Makefile (+9/-0)
pkg/maas-apiclient/README.rst (+5/-0)
pkg/maas-apiclient/apiclient/testing/settings.py (+18/-0)
pkg/maas-apiclient/configure.py (+19/-0)
pkg/maas-apiclient/packages.txt (+4/-0)
pkg/maas-apiclient/setup.py (+197/-0)
pkg/maas-client/Makefile (+3/-0)
pkg/maas-client/README.rst (+5/-0)
pkg/maas-client/configure.py (+26/-0)
pkg/maas-client/maascli/tests/test_integration.py (+16/-15)
pkg/maas-client/packages.txt (+7/-0)
pkg/maas-client/setup.py (+197/-0)
pkg/maas-cluster/MANIFEST.in (+4/-0)
pkg/maas-cluster/Makefile (+12/-0)
pkg/maas-cluster/README.rst (+6/-0)
pkg/maas-cluster/configure.py (+51/-0)
pkg/maas-cluster/maascluster/entrypoints.py (+61/-0)
pkg/maas-cluster/maascluster/worker/config.py (+2/-2)
pkg/maas-cluster/packages.txt (+36/-0)
pkg/maas-cluster/provisioningserver/dhcp/tests/test_writer.py (+8/-10)
pkg/maas-cluster/provisioningserver/testing/bindfixture.py (+5/-1)
pkg/maas-cluster/provisioningserver/testing/celeryconfig.py (+49/-0)
pkg/maas-cluster/provisioningserver/testing/djangosettings.py (+18/-0)
pkg/maas-cluster/provisioningserver/tests/test_config.py (+6/-1)
pkg/maas-cluster/provisioningserver/utils/tests/test_utils.py (+7/-5)
pkg/maas-cluster/setup.py (+197/-0)
pkg/maas-develop/MANIFEST.in (+2/-0)
pkg/maas-develop/Makefile (+6/-0)
pkg/maas-develop/README.rst (+5/-0)
pkg/maas-develop/configure.py (+47/-0)
pkg/maas-develop/maasdevelop/cluster/celeryconfig_demo.py (+7/-10)
pkg/maas-develop/maasdevelop/cluster/entrypoints.py (+61/-0)
pkg/maas-develop/maasdevelop/common/celeryconfig_demo.py (+8/-13)
pkg/maas-develop/maasdevelop/region/celeryconfig_demo.py (+6/-9)
pkg/maas-develop/maasdevelop/region/demo.py (+8/-6)
pkg/maas-develop/maasdevelop/region/development.py (+17/-23)
pkg/maas-develop/maasdevelop/region/entrypoints.py (+64/-0)
pkg/maas-develop/maasdevelop/region/maas_cluster.demo.conf (+8/-0)
pkg/maas-develop/maasdevelop/testing/entrypoints.py (+82/-0)
pkg/maas-develop/packages.txt (+17/-0)
pkg/maas-develop/setup.py (+197/-0)
pkg/maas-region/MANIFEST.in (+6/-0)
pkg/maas-region/Makefile (+38/-0)
pkg/maas-region/README.rst (+5/-0)
pkg/maas-region/configure.py (+70/-0)
pkg/maas-region/maas/entrypoints.py (+57/-0)
pkg/maas-region/maas/testing/celeryconfig.py (+45/-0)
pkg/maas-region/maas/testing/djangosettings.py (+112/-0)
pkg/maas-region/maasserver/components.py (+4/-1)
pkg/maas-region/maasserver/testing/testcase.py (+30/-28)
pkg/maas-region/maasserver/tests/test_js.py (+7/-9)
pkg/maas-region/maasserver/views/tests/test_nodes.py (+4/-0)
pkg/maas-region/maasserver/worker/config.py (+2/-2)
pkg/maas-region/metadataserver/commissioning/etctest/__init__.py (+15/-0)
pkg/maas-region/metadataserver/commissioning/etctest/test_maas_ipmi_autodetect.py (+3/-2)
pkg/maas-region/packages.txt (+48/-0)
pkg/maas-region/setup.py (+197/-0)
pkg/maas-testing/Makefile (+1/-0)
pkg/maas-testing/README.rst (+5/-0)
pkg/maas-testing/configure.py (+27/-0)
pkg/maas-testing/maastesting/__init__.py (+22/-9)
pkg/maas-testing/maastesting/djangoloader.py (+12/-46)
pkg/maas-testing/maastesting/fixtures.py (+37/-0)
pkg/maas-testing/maastesting/loader.py (+4/-0)
pkg/maas-testing/maastesting/testcase.py (+22/-0)
pkg/maas-testing/maastesting/tests/test_httpd.py (+6/-3)
pkg/maas-testing/packages.txt (+21/-0)
pkg/maas-testing/setup.py (+197/-0)
required-packages/base (+0/-56)
required-packages/build (+0/-3)
required-packages/dev (+0/-12)
required-packages/doc (+0/-3)
required-packages/forbidden (+0/-1)
required-packages/optional (+0/-1)
services/cluster-worker/run (+2/-5)
services/dns/run (+5/-3)
services/pserv/run (+4/-4)
services/region-worker/run (+2/-5)
services/txlongpoll/run (+2/-2)
services/web/run (+6/-2)
services/webapp/run (+4/-1)
setup.py (+0/-168)
versions.cfg (+0/-144)
To merge this branch: bzr merge lp:~allenap/maas/repackage
Reviewer Review Type Date Requested Status
MAAS Maintainers Pending
Review via email: mp+200935@code.launchpad.net

Description of the change

This changes a lot of stuff. It creates actually separate Python distribution packages for each subcomponent of MAAS, then unifies them into a single development environment. There's simply way more in this branch than I can hope to efficiently convey here, so I think this would be best reviewed as a pair. However, here it is anyway.

To post a comment you must log in.
lp:~allenap/maas/repackage updated
1924. By Gavin Panella

Merged repackage-prep into repackage, resolving a few conflicts.

1925. By Gavin Panella

Merged repackage-prep into repackage.

1926. By Gavin Panella

Merged trunk into repackage.

1927. By Gavin Panella

Remove required-packages; it's not used any more.

1928. By Gavin Panella

Merged trunk into repackage.

Revision history for this message
Jeroen T. Vermeulen (jtv) wrote :

The Makefile still has a bunch of “Move to maas-develop?” comments. Maybe just add TODO markers for the time being?

lp:~allenap/maas/repackage updated
1929. By Gavin Panella

Change some comments to TODOs.

1930. By Gavin Panella

Correct test_loader setting.

1931. By Gavin Panella

Merged trunk into repackage.

Revision history for this message
Gavin Panella (allenap) wrote :

> The Makefile still has a bunch of “Move to maas-develop?” comments. Maybe
> just add TODO markers for the time being?

Good idea, done.

lp:~allenap/maas/repackage updated
1932. By Gavin Panella

Merged trunk into repackage.

Revision history for this message
Jeroen T. Vermeulen (jtv) wrote :

Reading a bit further. Getting a bit lost with all the repetition! Is there really no way to share common definitions of __version__, envvar, check_settings, and so on? It's a lot of stuff to have both duplicated and untested, even if it is "meta" code.

.

I can see how it could be useful in the future for envvar to yield the environment variable's original value. But it's also a potential source of misunderstanding: "with environment variable set to X, its value is Y." I would just leave that feature out until we actually need it.

.

Much of the duplicated code needs documentation, and I can't help feeling that the duplication is the reason for not documenting it — which would be a poor state of affairs. I'm thinking of check_settings in particular: which settings does this check, for whose benefit, to serve what need?

.

Why doesn't install_deps follow our naming conventions?

.

I think the linter needs an update to check the pkg directory. The setup() calls are on insanely long lines.

.

Does pkg/common/checkarchive.py really compare contents of a tarball to a directory? Or only the file and directory names?

.

In pkg/maas-cluster/provisioningserver/testing/__init__.py you define "here" and "root" as global variables. Better upper-case them, as we have mostly been doing. Moreover "root" needs a more descriptive name and a bit of documentation. Root of what? And in a branch, in a package installation, or both?

Revision history for this message
Jeroen T. Vermeulen (jtv) wrote :

Plowing right on! Looking forward to getting this in.

In pkg/maas-region/maasserver/components.py, line 42 or so, you have a docstring, then a function call, and *then* an import that's there to avoid an import cycle. Would be more regular and obvious to have the import right below the docstring:

3328 :param error_message: Human-readable error text.
3329 """
3330 discard_persistent_error(component)
3331 + from maasserver.models import ComponentError # Avoid circular imports.
3332 ComponentError.objects.create(component=component, error=error_message)

.

The comment in MAASServerTestCase.setUp really doesn't need to have a TODO marker as far as I'm concerned. It's a great comment, but it does not instill a great sense of urgency. :-)

.

In pkg/maas-region/maasserver/tests/test_views_nodes.py, why does test_node_list_sorts_by_zone newly skip with an XXX message from gmb? It looks as if you were just porting over a previous skip() to a better format, but I don't see anything that would have made that test skip before.

.

The documentation for ClassSetup relies on knowledge of MAASTestCaseType in a different module. Can you explain it in such a way that people who aren't aware of MAASTestCaseType's relevance have a chance of understanding it? Can you also explain in docstrings *why* MAASTestCaseType forbids setUpClass if we then need ClassSetup to un-forbid it again?

Revision history for this message
Jeroen T. Vermeulen (jtv) wrote :

Here's one thing I really don't like: I ran a plain "make" just now and found it went and sudo'ed on me. I don't expect a build to mess with my global system configuration!

Revision history for this message
Jeroen T. Vermeulen (jtv) wrote :

Ran the test suite. Five maasserver tests failing, plus one error (but I'm not sure that counts — it's the old "Can't load the profile" error in test_YUI3_unit_tests).

lp:~allenap/maas/repackage updated
1933. By Gavin Panella

Merged trunk into repackage.

Revision history for this message
Gavin Panella (allenap) wrote :

> Reading a bit further. Getting a bit lost with all the repetition! Is there
> really no way to share common definitions of __version__, envvar,
> check_settings, and so on? It's a lot of stuff to have both duplicated and
> untested, even if it is "meta" code.

Bugger, I didn't mention that in the description. That's one of the
reasons I wanted to do an interactive review. The setup.py files are all
auto-generated from the call to common.configure().

I tried using pprint to make the call to setup() format better, but that
has its own problems. Ideally I'd like to get rid of that hack, but I
did try several other ways to do it. I was trying to make it so that
each package would be installable from PyPI, for example, where the
common package would no longer be available, hence the need for bundling
things into setup.py.

>
> .
>
> I can see how it could be useful in the future for envvar to yield the
> environment variable's original value. But it's also a potential source of
> misunderstanding: "with environment variable set to X, its value is Y." I
> would just leave that feature out until we actually need it.

Done.

>
> .
>
> Much of the duplicated code needs documentation, and I can't help feeling that
> the duplication is the reason for not documenting it — which would be a poor
> state of affairs. I'm thinking of check_settings in particular: which
> settings does this check, for whose benefit, to serve what need?

I've added docstrings to pkg/common/__init__.py, which now means that
all the setup.pys are also documented.

>
> .
>
> Why doesn't install_deps follow our naming conventions?

It follows the distutils/setuptools naming convention for commands. I
don't know why it's that way :-/

>
> .
>
> I think the linter needs an update to check the pkg directory. The setup()
> calls are on insanely long lines.

pkg/common/__init__.py is lint-free, and there's not much I can do about
those setup() calls right now.

>
> .
>
> Does pkg/common/checkarchive.py really compare contents of a tarball to a
> directory? Or only the file and directory names?

Just names. It was useful when figuring out why data_files and
include_package_data were not doing as I expected (see check_settings).
I've updated its docstring.

>
> .
>
> In pkg/maas-cluster/provisioningserver/testing/__init__.py you define "here"
> and "root" as global variables. Better upper-case them, as we have mostly
> been doing. Moreover "root" needs a more descriptive name and a bit of
> documentation. Root of what? And in a branch, in a package installation, or
> both?

I totally want to get rid of those! I'll see if I can.

Revision history for this message
Gavin Panella (allenap) wrote :

> Plowing right on!  Looking forward to getting this in.

Cheers, thank you for persisting :)

>
> In pkg/maas-region/maasserver/components.py, line 42 or so, you have a
> docstring, then a function call, and *then* an import that's there to avoid an
> import cycle.  Would be more regular and obvious to have the import right
> below the docstring:
>
> 3328         :param error_message: Human-readable error text.
> 3329         """
> 3330         discard_persistent_error(component)
> 3331    +    from maasserver.models import ComponentError  # Avoid circular
> imports.
> 3332         ComponentError.objects.create(component=component,
> error=error_message)

I've changed it.

>
> .
>
> The comment in MAASServerTestCase.setUp really doesn't need to have a TODO
> marker as far as I'm concerned.  It's a great comment, but it does not instill
> a great sense of urgency.  :-)

Fixed :)

>
> .
>
> In pkg/maas-region/maasserver/tests/test_views_nodes.py, why does
> test_node_list_sorts_by_zone newly skip with an XXX message from gmb?  It
> looks as if you were just porting over a previous skip() to a better format,
> but I don't see anything that would have made that test skip before.

Ah, I think you're right. I think I changed it from using `raise
SkipTest(...)` to using `self.skip(...)` thus avoiding the import of
SkipTest. Then Raffolo fixed it, I merged trunk, but no conflict (or
easily overlooked conflict) arose.

>
> .
>
> The documentation for ClassSetup relies on knowledge of MAASTestCaseType in a
> different module.  Can you explain it in such a way that people who aren't
> aware of MAASTestCaseType's relevance have a chance of understanding it?  Can
> you also explain in docstrings *why* MAASTestCaseType forbids setUpClass if we
> then need ClassSetup to un-forbid it again?

Docstring updated with:

    `MAASTestCaseType` forbids `setUpClass` and `tearDownClass` in new
    test classes, but sometimes they must be called in existing super
    classes, one example being :class:`django.test.LiveServerTestCase`.

lp:~allenap/maas/repackage updated
1934. By Gavin Panella

Docstrings for all functions in module common.

1935. By Gavin Panella

Don't yield the previous environment variable's value in envvar().

1936. By Gavin Panella

Make it clear that checkarchive.py only checks *names* in archives.

1937. By Gavin Panella

Remove obsolete XXX.

1938. By Gavin Panella

Couple of review fixes.

1939. By Gavin Panella

Explain the need for ClassSetup.

Revision history for this message
Gavin Panella (allenap) wrote :

> Here's one thing I really don't like: I ran a plain "make" just now and found
> it went and sudo'ed on me.  I don't expect a build to mess with my global
> system configuration!

Something it could do, without needing root privileges, is to check if
all the dependencies are installed. If not, it can bail with a message
like:

    The following system dependencies are missing:
        ...
    To install them, run the following command:
        sudo apt-get install ...

Would that be better?

Fwiw, I like the automatic installation, but I can see that it's not
going to be to everyone's tastes.

Revision history for this message
Gavin Panella (allenap) wrote :

> Ran the test suite. Five maasserver tests failing, plus one error (but I'm
> not sure that counts — it's the old "Can't load the profile" error in
> test_YUI3_unit_tests).

Those tests drive me nuts. I'm not sure wtf is going on with those;
they're failing in trunk for me too.

lp:~allenap/maas/repackage updated
1940. By Gavin Panella

Import the name required only; I think South is doing something 'clever' with the models package and subpackages.

1941. By Gavin Panella

Update some configs such that make harness works again.

1942. By Gavin Panella

Ignore .db.lock files.

1943. By Gavin Panella

Don't get the default zone at module import time.

1944. By Gavin Panella

Replace most uses of 'root' variables with pkg_resources.

1945. By Gavin Panella

Merge trunk, resolving lots of conflicts.

1946. By Gavin Panella

Merge trunk, resolving some conflicts, and migrating version requirements to the new layout.

1947. By Gavin Panella

ContainsAll is in testtools 0.9.32, and that's what's packaged in Ubuntu, so only require that.

1948. By Gavin Panella

Merge trunk.

1949. By Gavin Panella

Merge trunk.

1950. By Gavin Panella

Use load_entry_point() for celeryd so that it works on saucy and trusty.

1951. By Gavin Panella

Trusty's development Apache config is the same as saucy's.

1952. By Gavin Panella

bin/pip is no longer guaranteed to be made.

1953. By Gavin Panella

Merge trunk r1838. Discarded all changes, but reworked them into the New Way.

1954. By Gavin Panella

Merge trunk.

1955. By Gavin Panella

Merge trunk.

1956. By Gavin Panella

Merge trunk.

1957. By Gavin Panella

Merge trunk.

Revision history for this message
Raphaël Badin (rvb) wrote :

Running `make` was failing with "Error: pg_config executable not found." until I ran "sudo apt-get install libpq-dev python-dev".

Revision history for this message
Raphaël Badin (rvb) wrote :

`make test` fails with 'KeyError: "The cache has no package named u'python-selenium'"'
(http://paste.ubuntu.com/6825198/)

Revision history for this message
Gavin Panella (allenap) wrote :

> Running `make` was failing with "Error: pg_config executable not found." until
> I ran "sudo apt-get install libpq-dev python-dev".

One of the things missing in this branch is the division between
production and development package dependencies: the Python packages
themselves (see pkg/*/package.txt and pkg/*/configure.py) arrange for
installation of package dependencies, but I've not added code to
distinguish between run-time and test-time.

I'll see what I can do.

Revision history for this message
Gavin Panella (allenap) wrote :

> `make test` fails with 'KeyError: "The cache has no package named u'python-
> selenium'"'
> (http://paste.ubuntu.com/6825198/)

Ah, that'll be because python-selenium is in multiverse :-/

lp:~allenap/maas/repackage updated
1958. By Gavin Panella

Merge trunk, resolving a few small conflicts.

1959. By Gavin Panella

Merged trunk into repackage.

1960. By Gavin Panella

Merge trunk, resolving 1 minor conflict.

1961. By Gavin Panella

Merge trunk.

1962. By Gavin Panella

Merge trunk.

Revision history for this message
Graham Binns (gmb) wrote :

It would be lovely if we could prevent this from bitrotting... what still needs to happen?

Revision history for this message
Gavin Panella (allenap) wrote :

> It would be lovely if we could prevent this from bitrotting... what still
> needs to happen?

It needs to land :)

I need to find time to split out some bits that can be merged separately, but I'm not sure what exactly that might be.

Also, when this lands it's going to break packaging and probably QA. It might be worth setting up a parallel PPA with new packages, and perhaps also a parallel QA process. However, it might be less work to land this, accept the breakage, then everyone fixes stuff.

lp:~allenap/maas/repackage updated
1963. By Gavin Panella

Merge trunk, resolving several small conflicts.

Revision history for this message
Andres Rodriguez (andreserl) wrote :

Gavin,

As previously discussed please check with doko and/or Barry about the
multiple setup.py's before you move forward with this.

And keep in mind that feature freeze is around the corner. I won't be
releasing these changes until after doko (on the packaging side) and Barry
(on the python side) sign this of. If this doesn't happen before feature
freeze i'll be hesitant on releasing this change at all.

Cheers
On Feb 10, 2014 8:58 AM, "Gavin Panella" <email address hidden>
wrote:

> > It would be lovely if we could prevent this from bitrotting... what still
> > needs to happen?
>
> It needs to land :)
>
> I need to find time to split out some bits that can be merged separately,
> but I'm not sure what exactly that might be.
>
> Also, when this lands it's going to break packaging and probably QA. It
> might be worth setting up a parallel PPA with new packages, and perhaps
> also a parallel QA process. However, it might be less work to land this,
> accept the breakage, then everyone fixes stuff.
>
> --
> https://code.launchpad.net/~allenap/maas/repackage/+merge/200935
> You are subscribed to branch lp:maas.
>

Revision history for this message
Gavin Panella (allenap) wrote :

Okay, I've emailed doko and Barry (and maas-devel) to get their advice.

lp:~allenap/maas/repackage updated
1964. By Gavin Panella

Forgot to regenerate a setup.py.

Revision history for this message
Julian Edwards (julian-edwards) wrote :

I'm almost convinced that this should wait until after 14.04.

Revision history for this message
Andres Rodriguez (andreserl) wrote :

I agree with Julian!
On Feb 10, 2014 8:06 PM, "Julian Edwards" <email address hidden>
wrote:

> I'm almost convinced that this should wait until after 14.04.
>
> --
> https://code.launchpad.net/~allenap/maas/repackage/+merge/200935
> You are subscribed to branch lp:maas.
>

Revision history for this message
Gavin Panella (allenap) wrote :

> I'm almost convinced that this should wait until after 14.04.

Sadly, I'm of that opinion too. There was a window shortly after it was done that it could have merged, but that's gone now. I understand the reluctance to swallow such a big change, but it's not an easy change to break up into pieces. Assuming this is an acceptable change, I think the best way to approach it is to JFDI and then fix whatever it breaks. We can do that early in the next cycle. The downside is that it'll make it harder to back-port changes to Trusty.

Revision history for this message
Julian Edwards (julian-edwards) wrote :

On Tuesday 11 Feb 2014 09:28:00 Gavin Panella wrote:
> > I'm almost convinced that this should wait until after 14.04.
>
> Sadly, I'm of that opinion too. There was a window shortly after it was done
> that it could have merged, but that's gone now. I understand the reluctance
> to swallow such a big change, but it's not an easy change to break up into
> pieces. Assuming this is an acceptable change, I think the best way to
> approach it is to JFDI and then fix whatever it breaks. We can do that
> early in the next cycle. The downside is that it'll make it harder to
> back-port changes to Trusty.

So a couple of things:

1. I think we should not backport anything to trusty, instead reply on the
cloud archive for up-to-date packages based on trunk. We have more leeway in
there to make this sort of change.

2. +1 to a huge land-and-fixorama post 14.04.

lp:~allenap/maas/repackage updated
1965. By Gavin Panella

Merge trunk, resolving many conflicts.

1966. By Gavin Panella

Add python-crochet as a dependency.

1967. By Gavin Panella

Some more maascli/maas-cli fixes.

1968. By Gavin Panella

Merge trunk.

1969. By Gavin Panella

Merge trunk r1944.

1970. By Gavin Panella

Merge trunk r1945.

1971. By Gavin Panella

Merge trunk r1946.

1972. By Gavin Panella

Merge trunk r1947.

1973. By Gavin Panella

Merge trunk r1948.

1974. By Gavin Panella

Merge trunk r1949.

1975. By Gavin Panella

Merge trunk r1950.

1976. By Gavin Panella

Merge trunk r1951.

1977. By Gavin Panella

Merge trunk r1952.

1978. By Gavin Panella

Merge trunk r1953, resolving minor conflicts.

1979. By Gavin Panella

Merge trunk r1954.

1980. By Gavin Panella

Merge trunk r1955, resolving minor conflicts.

1981. By Gavin Panella

Merge trunk r1956.

1982. By Gavin Panella

Merge trunk r1957.

1983. By Gavin Panella

Merge trunk r1958.

1984. By Gavin Panella

Merge trunk r1959.

1985. By Gavin Panella

Merge trunk r1960.

1986. By Gavin Panella

Merge trunk r1961.

1987. By Gavin Panella

Merge trunk r1962.

1988. By Gavin Panella

Merge trunk r1963.

1989. By Gavin Panella

Merge trunk r1964.

1990. By Gavin Panella

Merge trunk r1965.

1991. By Gavin Panella

Merge trunk r1966.

1992. By Gavin Panella

Merge trunk r1967.

1993. By Gavin Panella

Merge trunk r1968.

1994. By Gavin Panella

Merge trunk r1969.

1995. By Gavin Panella

Merge trunk r1970, resolving minor conflicts.

1996. By Gavin Panella

Merge trunk r1971.

1997. By Gavin Panella

Merge trunk r1972.

1998. By Gavin Panella

Merge trunk r1973.

1999. By Gavin Panella

Merge trunk r1974.

2000. By Gavin Panella

Merge trunk r1975.

2001. By Gavin Panella

Merge trunk r1976.

2002. By Gavin Panella

Merge trunk r1977, resolving minor conflicts.

2003. By Gavin Panella

Merge trunk r1978.

2004. By Gavin Panella

Merge trunk r1979.

2005. By Gavin Panella

Merge trunk r1980.

2006. By Gavin Panella

Merge trunk r1981.

2007. By Gavin Panella

Merge trunk r1982.

2008. By Gavin Panella

Merge trunk r1983.

2009. By Gavin Panella

Merge trunk r1984.

2010. By Gavin Panella

Merge trunk r1985.

2011. By Gavin Panella

Merge trunk r1986.

2012. By Gavin Panella

Merge trunk r1987.

2013. By Gavin Panella

Merge trunk r1988.

2014. By Gavin Panella

Merge trunk r1989.

2015. By Gavin Panella

Merge trunk r1990.

2016. By Gavin Panella

Merge trunk r1991.

2017. By Gavin Panella

Merge trunk r1992.

2018. By Gavin Panella

Merge trunk r1993.

2019. By Gavin Panella

Merge trunk r1994.

2020. By Gavin Panella

Merge trunk r1995.

2021. By Gavin Panella

Merge trunk r1996.

2022. By Gavin Panella

Merge trunk r1997.

2023. By Gavin Panella

Merge trunk r1998.

2024. By Gavin Panella

Merge trunk r1999.

2025. By Gavin Panella

Merge trunk r2000.

2026. By Gavin Panella

Merge trunk r2001, resolving minor conflicts.

2027. By Gavin Panella

Merge trunk r2002.

2028. By Gavin Panella

Merge trunk r2003.

2029. By Gavin Panella

Merge trunk r2004.

2030. By Gavin Panella

Merge trunk r2005.

2031. By Gavin Panella

Merge trunk r2006.

2032. By Gavin Panella

Merge trunk r2007.

2033. By Gavin Panella

Merge trunk r2008.

2034. By Gavin Panella

Merge trunk r2009.

2035. By Gavin Panella

Merge trunk r2010.

2036. By Gavin Panella

Merge trunk r2011, resolving minor conflicts.

2037. By Gavin Panella

Merge trunk r2012.

2038. By Gavin Panella

Merge trunk r2013.

2039. By Gavin Panella

Merge trunk r2014, resolving minor conflicts.

2040. By Gavin Panella

Merge trunk r2015.

2041. By Gavin Panella

Merge trunk r2016.

2042. By Gavin Panella

Merge trunk r2017.

2043. By Gavin Panella

Merge trunk r2018.

2044. By Gavin Panella

Merge trunk r2019.

2045. By Gavin Panella

Merge trunk r2020.

2046. By Gavin Panella

Merge trunk r2021, resolving minor conflicts.

2047. By Gavin Panella

Merge trunk r2022.

2048. By Gavin Panella

Merge trunk r2023.

2049. By Gavin Panella

Merge trunk r2024.

2050. By Gavin Panella

Merge trunk r2025.

2051. By Gavin Panella

Merge trunk r2026.

2052. By Gavin Panella

Merge trunk r2027.

2053. By Gavin Panella

Merge trunk r2028.

2054. By Gavin Panella

Merge trunk r2029.

2055. By Gavin Panella

Merge trunk r2030.

2056. By Gavin Panella

Merge trunk r2031.

2057. By Gavin Panella

Merge trunk r2032.

2058. By Gavin Panella

Merge trunk r2033.

2059. By Gavin Panella

Merge trunk r2034.

2060. By Gavin Panella

Merge trunk r2035.

2061. By Gavin Panella

Merge trunk r2036.

2062. By Gavin Panella

Merge trunk r2037.

2063. By Gavin Panella

Merge trunk r2038.

2064. By Gavin Panella

Merge trunk r2039.

2065. By Gavin Panella

Merge trunk r2040.

2066. By Gavin Panella

Merge trunk r2041.

2067. By Gavin Panella

Merge trunk r2042.

2068. By Gavin Panella

Merge trunk r2043.

2069. By Gavin Panella

Merge trunk r2044.

2070. By Gavin Panella

Merge trunk r2045.

2071. By Gavin Panella

Merge trunk r2046, resolving minor conflicts.

2072. By Gavin Panella

Merge trunk r2047.

2073. By Gavin Panella

Merge trunk r2048.

2074. By Gavin Panella

Merge trunk r2049.

2075. By Gavin Panella

Merge trunk r2050.

2076. By Gavin Panella

Merge trunk r2051.

2077. By Gavin Panella

Merge trunk r2052.

2078. By Gavin Panella

Merge trunk r2053.

2079. By Gavin Panella

Merge trunk r2054.

2080. By Gavin Panella

Merge trunk r2055.

2081. By Gavin Panella

Merge trunk r2056.

2082. By Gavin Panella

Merge trunk r2057.

2083. By Gavin Panella

Merge trunk r2058.

2084. By Gavin Panella

Merge trunk r2059.

2085. By Gavin Panella

Merge trunk r2060.

2086. By Gavin Panella

Merge trunk r2061.

2087. By Gavin Panella

Merge trunk r2062, resolving minor conflicts.

2088. By Gavin Panella

Merge trunk r2063.

2089. By Gavin Panella

Merge trunk r2064.

2090. By Gavin Panella

Merge trunk r2065.

2091. By Gavin Panella

Merge trunk r2066.

2092. By Gavin Panella

Merge trunk r2067.

2093. By Gavin Panella

Merge trunk r2068.

2094. By Gavin Panella

Merge trunk r2069.

2095. By Gavin Panella

Merge trunk r2070.

2096. By Gavin Panella

Merge trunk r2071.

2097. By Gavin Panella

Merge trunk r2072.

2098. By Gavin Panella

Merge trunk r2073.

2099. By Gavin Panella

Merge trunk r2074.

2100. By Gavin Panella

Merge trunk r2075.

2101. By Gavin Panella

Merge trunk r2076.

2102. By Gavin Panella

Merge trunk r2077.

2103. By Gavin Panella

Merge trunk r2078.

2104. By Gavin Panella

Merge trunk r2079.

2105. By Gavin Panella

Merge trunk r2080.

2106. By Gavin Panella

Merge trunk r2081.

2107. By Gavin Panella

Merge trunk r2082.

2108. By Gavin Panella

Merge trunk r2083, resolving minor conflicts.

2109. By Gavin Panella

Merge trunk r2084.

2110. By Gavin Panella

Merge trunk r2085.

2111. By Gavin Panella

Merge trunk r2086.

2112. By Gavin Panella

Merge trunk r2087.

2113. By Gavin Panella

Merge trunk r2088.

2114. By Gavin Panella

Merge trunk r2089.

2115. By Gavin Panella

Merge trunk r2090.

2116. By Gavin Panella

Merge trunk r2091.

2117. By Gavin Panella

Merge trunk r2092.

2118. By Gavin Panella

Merge trunk r2093.

2119. By Gavin Panella

Merge trunk r2094.

2120. By Gavin Panella

Merge trunk r2095.

2121. By Gavin Panella

Merge trunk r2096.

2122. By Gavin Panella

Merge trunk r2097.

2123. By Gavin Panella

Merge trunk r2098.

2124. By Gavin Panella

Merge trunk r2099.

2125. By Gavin Panella

Merge trunk r2100.

2126. By Gavin Panella

Merge trunk r2101.

2127. By Gavin Panella

Merge trunk r2102.

2128. By Gavin Panella

Merge trunk r2103.

2129. By Gavin Panella

Merge trunk r2104.

2130. By Gavin Panella

Merge trunk r2105.

2131. By Gavin Panella

Merge trunk r2106.

2132. By Gavin Panella

Merge trunk r2107.

2133. By Gavin Panella

Merge trunk r2108.

2134. By Gavin Panella

Merge trunk r2109.

2135. By Gavin Panella

Merge trunk r2110.

2136. By Gavin Panella

Merge trunk r2111.

2137. By Gavin Panella

Merge trunk r2112.

2138. By Gavin Panella

Merge trunk r2113.

2139. By Gavin Panella

Merge trunk r2114.

2140. By Gavin Panella

Merge trunk r2115.

2141. By Gavin Panella

Merge trunk r2116.

2142. By Gavin Panella

Merge trunk r2117.

2143. By Gavin Panella

Merge trunk r2118.

2144. By Gavin Panella

Merge trunk r2119.

2145. By Gavin Panella

Merge trunk r2120.

2146. By Gavin Panella

Merge trunk r2121.

2147. By Gavin Panella

Merge trunk r2122.

2148. By Gavin Panella

Merge trunk r2123.

2149. By Gavin Panella

Merge trunk r2124.

2150. By Gavin Panella

Merge trunk r2125.

2151. By Gavin Panella

Merge trunk r2126.

2152. By Gavin Panella

Merge trunk r2127.

2153. By Gavin Panella

Merge trunk r2128.

2154. By Gavin Panella

Merge trunk r2129.

2155. By Gavin Panella

Merge trunk r2130.

2156. By Gavin Panella

Merge trunk r2131.

2157. By Gavin Panella

Merge trunk r2132.

2158. By Gavin Panella

Merge trunk r2133.

2159. By Gavin Panella

Merge trunk r2134.

2160. By Gavin Panella

Merge trunk r2135.

2161. By Gavin Panella

Merge trunk r2136.

2162. By Gavin Panella

Merge trunk r2137.

2163. By Gavin Panella

Merge trunk r2138.

2164. By Gavin Panella

Merge trunk r2139.

2165. By Gavin Panella

Merge trunk r2140, resolving minor conflicts.

2166. By Gavin Panella

Missing dependency, subunit.

2167. By Gavin Panella

Merge r2141, changing things quite a lot.

2168. By Gavin Panella

Merge trunk r2142.

2169. By Gavin Panella

Merge trunk r2143.

2170. By Gavin Panella

Merge trunk r2144.

2171. By Gavin Panella

Merge trunk r2145.

2172. By Gavin Panella

Merge r2146, resolving conflicts.

2173. By Gavin Panella

Merge trunk r2147.

2174. By Gavin Panella

Merge trunk r2148.

2175. By Gavin Panella

Merge trunk r2149.

2176. By Gavin Panella

Merge r2150, resolving minor conflicts.

2177. By Gavin Panella

Merge r2151, resolving minor conflicts.

2178. By Gavin Panella

Merge trunk r2152.

2179. By Gavin Panella

Merge trunk r2153, resolving several conflicts.

2180. By Gavin Panella

Merge trunk r2154, discarding all changes.

2181. By Gavin Panella

Work with - and + suffixes in packages.txt.

2182. By Gavin Panella

Purge python-librabbitmq; it breaks stuff.

2183. By Gavin Panella

Update setup.pys.

2184. By Gavin Panella

Merge r2155, discarding all changes.

2185. By Gavin Panella

Merge trunk r2156.

2186. By Gavin Panella

Merge trunk r2157, resolving minor conflicts.

2187. By Gavin Panella

Merge trunk r2158, discarding most changes.

2188. By Gavin Panella

Merge trunk r2159.

2189. By Gavin Panella

Merge trunk r2160.

2190. By Gavin Panella

Merge trunk r2161.

2191. By Gavin Panella

Merge trunk r2162.

2192. By Gavin Panella

Merge trunk r2163.

2193. By Gavin Panella

Merge trunk r2164.

2194. By Gavin Panella

Merge trunk r2165.

2195. By Gavin Panella

Merge trunk r2166.

2196. By Gavin Panella

Merge trunk r2167.

2197. By Gavin Panella

Merge trunk r2168.

2198. By Gavin Panella

Merge trunk r2169.

2199. By Gavin Panella

Merge trunk r2170, resolving conflicts.

2200. By Gavin Panella

Merge trunk r2171.

2201. By Gavin Panella

Merge trunk r2172, resolving minor conflicts.

2202. By Gavin Panella

Merge trunk r2173.

2203. By Gavin Panella

Merge trunk r2174.

2204. By Gavin Panella

Merge trunk r2175.

2205. By Gavin Panella

Merge trunk r2176.

2206. By Gavin Panella

Merge trunk r2177.

2207. By Gavin Panella

Merge trunk r2178.

2208. By Gavin Panella

Merge trunk r2179.

2209. By Gavin Panella

Merge trunk r2180, resolving minor conflicts.

2210. By Gavin Panella

Merge trunk r2181, resolving minor conflicts.

2211. By Gavin Panella

Merge trunk r2182.

2212. By Gavin Panella

Merge trunk r2183.

2213. By Gavin Panella

Merge trunk r2184.

2214. By Gavin Panella

Merge trunk r2185, resolving minor conflicts.

2215. By Gavin Panella

Merge trunk r2186.

2216. By Gavin Panella

Merge trunk r2187.

2217. By Gavin Panella

Merge trunk r2188.

2218. By Gavin Panella

Merge trunk r2189.

2219. By Gavin Panella

Merge trunk r2190.

2220. By Gavin Panella

Merge trunk r2191.

2221. By Gavin Panella

Merge trunk r2192, resolving minor conflicts.

2222. By Gavin Panella

Merge trunk r2193.

2223. By Gavin Panella

Merge trunk r2194.

2224. By Gavin Panella

Merge trunk r2195.

2225. By Gavin Panella

Merge trunk r2196.

2226. By Gavin Panella

Merge trunk r2197, resolving minor conflicts.

2227. By Gavin Panella

Merge trunk r2198.

2228. By Gavin Panella

Merge trunk r2199.

2229. By Gavin Panella

Merge trunk r2200.

2230. By Gavin Panella

Merge trunk r2201.

2231. By Gavin Panella

Merge trunk r2202.

2232. By Gavin Panella

Merge trunk r2203, discarding all changes.

2233. By Gavin Panella

Merge trunk r2204.

2234. By Gavin Panella

Merge trunk r2205.

2235. By Gavin Panella

Merge trunk r2206.

2236. By Gavin Panella

Merge trunk r2207.

2237. By Gavin Panella

Merge trunk r2208.

2238. By Gavin Panella

Merge trunk r2209.

2239. By Gavin Panella

Merge trunk r2210.

2240. By Gavin Panella

Merge trunk r2211.

2241. By Gavin Panella

Merge trunk r2212.

2242. By Gavin Panella

Merge trunk r2213, resolving minor conflicts.

2243. By Gavin Panella

Merge trunk r2214.

2244. By Gavin Panella

Merge trunk r2215.

2245. By Gavin Panella

Merge trunk r2216.

2246. By Gavin Panella

Merge trunk r2217.

2247. By Gavin Panella

Merge trunk r2218.

2248. By Gavin Panella

Merge trunk r2219.

2249. By Gavin Panella

Merge trunk r2220.

2250. By Gavin Panella

Merge trunk r2221.

2251. By Gavin Panella

Merge trunk r2222.

2252. By Gavin Panella

Merge trunk r2223.

2253. By Gavin Panella

Merge trunk r2224.

2254. By Gavin Panella

Merge trunk r2225.

2255. By Gavin Panella

Merge trunk r2226.

2256. By Gavin Panella

Merge trunk r2227.

2257. By Gavin Panella

Merge trunk r2228.

2258. By Gavin Panella

Merge trunk r2229.

2259. By Gavin Panella

Merge trunk r2230.

2260. By Gavin Panella

Merge trunk r2231.

2261. By Gavin Panella

Merge trunk r2232.

2262. By Gavin Panella

Merge trunk r2233.

2263. By Gavin Panella

Merge trunk r2234.

2264. By Gavin Panella

Merge trunk r2235.

2265. By Gavin Panella

Merge trunk r2236.

2266. By Gavin Panella

Merge trunk r2237.

2267. By Gavin Panella

Merge trunk r2238, resolving 1 minor conflict.

2268. By Gavin Panella

Merge trunk r2239.

2269. By Gavin Panella

Merge trunk r2240.

2270. By Gavin Panella

Merge trunk r2241.

2271. By Gavin Panella

Merge trunk r2242.

2272. By Gavin Panella

Merge trunk r2243.

2273. By Gavin Panella

Merge trunk r2244.

2274. By Gavin Panella

Merge trunk r2245.

2275. By Gavin Panella

Merge trunk r2246.

2276. By Gavin Panella

Merge trunk r2247.

2277. By Gavin Panella

Merge trunk r2248.

2278. By Gavin Panella

Merge trunk r2249.

2279. By Gavin Panella

Merge trunk r2250.

2280. By Gavin Panella

Merge trunk r2251.

2281. By Gavin Panella

Merge trunk r2252.

2282. By Gavin Panella

Merge trunk r2253, resolving conflicts.

2283. By Gavin Panella

Merge trunk r2254.

2284. By Gavin Panella

Merge trunk r2255.

2285. By Gavin Panella

Merge trunk r2256.

2286. By Gavin Panella

Merge trunk r2257.

2287. By Gavin Panella

Merge trunk r2258.

2288. By Gavin Panella

Merge trunk r2259.

2289. By Gavin Panella

Merge trunk r2260.

2290. By Gavin Panella

Merge trunk r2261.

2291. By Gavin Panella

Merge trunk r2262.

2292. By Gavin Panella

Merge trunk r2263.

2293. By Gavin Panella

Merge trunk r2264.

2294. By Gavin Panella

Merge trunk r2265.

2295. By Gavin Panella

Merge trunk r2266.

2296. By Gavin Panella

Merge trunk r2267.

2297. By Gavin Panella

Merge trunk r2268, resolving 1 minor conflict.

2298. By Gavin Panella

Merge trunk r2269.

2299. By Gavin Panella

Merge trunk r2270.

2300. By Gavin Panella

Merge trunk r2271.

2301. By Gavin Panella

Merge trunk r2272.

2302. By Gavin Panella

Merge trunk r2273.

2303. By Gavin Panella

Merge trunk r2274.

2304. By Gavin Panella

Merge trunk r2275.

2305. By Gavin Panella

Merge trunk r2276.

2306. By Gavin Panella

Merge trunk r2277.

2307. By Gavin Panella

Merge trunk r2278.

2308. By Gavin Panella

Merge trunk r2279.

2309. By Gavin Panella

Merge trunk r2280.

2310. By Gavin Panella

Merge trunk r2281.

2311. By Gavin Panella

Merge trunk r2282.

2312. By Gavin Panella

Merge trunk r2283.

2313. By Gavin Panella

Merge trunk r2284.

2314. By Gavin Panella

Merge trunk r2285.

2315. By Gavin Panella

Merge trunk r2286.

2316. By Gavin Panella

Merge trunk r2287, resolving 1 minor conflict.

2317. By Gavin Panella

Merge trunk r2288.

2318. By Gavin Panella

Merge trunk r2289.

2319. By Gavin Panella

Merge trunk r2290.

2320. By Gavin Panella

Merge trunk r2291.

2321. By Gavin Panella

Merge trunk r2292.

2322. By Gavin Panella

Merge trunk r2293.

2323. By Gavin Panella

Merge trunk r2294.

2324. By Gavin Panella

Merge trunk r2295.

2325. By Gavin Panella

Merge trunk r2296.

2326. By Gavin Panella

Merge trunk r2297.

2327. By Gavin Panella

Merge trunk r2298.

2328. By Gavin Panella

Merge trunk r2299.

2329. By Gavin Panella

Merge trunk r2300.

2330. By Gavin Panella

Merge trunk r2301.

2331. By Gavin Panella

Merge trunk r2302.

2332. By Gavin Panella

Merge trunk r2303.

2333. By Gavin Panella

Merge trunk r2304.

2334. By Gavin Panella

Merge trunk r2305.

2335. By Gavin Panella

Merge trunk r2306.

2336. By Gavin Panella

Merge trunk r2307.

2337. By Gavin Panella

Merge trunk r2308.

2338. By Gavin Panella

Merge trunk r2309.

2339. By Gavin Panella

Merge trunk r2310.

2340. By Gavin Panella

Merge trunk r2311.

2341. By Gavin Panella

Merge trunk r2312.

2342. By Gavin Panella

Merge trunk r2313.

2343. By Gavin Panella

Merge trunk r2314.

2344. By Gavin Panella

Merge trunk r2315.

2345. By Gavin Panella

Merge trunk r2316.

2346. By Gavin Panella

Merge trunk r2317.

2347. By Gavin Panella

Merge trunk r2318.

2348. By Gavin Panella

Merge trunk r2319.

2349. By Gavin Panella

Merge trunk r2320.

2350. By Gavin Panella

Merge trunk r2321.

2351. By Gavin Panella

Merge trunk r2322.

2352. By Gavin Panella

Merge trunk r2323.

2353. By Gavin Panella

Merge trunk r2324.

2354. By Gavin Panella

Merge trunk r2325.

2355. By Gavin Panella

Merge trunk r2326.

2356. By Gavin Panella

Merge trunk r2327.

2357. By Gavin Panella

Merge trunk r2328.

2358. By Gavin Panella

Merge trunk r2329.

2359. By Gavin Panella

Merge trunk r2330.

2360. By Gavin Panella

Merge trunk r2331.

2361. By Gavin Panella

Merge trunk r2332.

2362. By Gavin Panella

Merge trunk r2333.

2363. By Gavin Panella

Merge trunk r2334.

2364. By Gavin Panella

Merge trunk r2335.

2365. By Gavin Panella

Merge trunk r2336.

2366. By Gavin Panella

Merge trunk r2337.

2367. By Gavin Panella

Merge trunk r2338.

2368. By Gavin Panella

Merge trunk r2339.

2369. By Gavin Panella

Merge trunk r2340.

2370. By Gavin Panella

Merge trunk r2341.

2371. By Gavin Panella

Merge trunk r2342.

2372. By Gavin Panella

Merge trunk r2343.

2373. By Gavin Panella

Merge trunk r2344, resolving 1 minor conflict.

2374. By Gavin Panella

Merge trunk r2345.

2375. By Gavin Panella

Merge trunk r2346.

2376. By Gavin Panella

Merge trunk r2347.

2377. By Gavin Panella

Merge trunk r2348.

2378. By Gavin Panella

Merge trunk r2349.

2379. By Gavin Panella

Merge trunk r2350.

2380. By Gavin Panella

Merge trunk r2351.

2381. By Gavin Panella

Merge trunk r2352.

2382. By Gavin Panella

Merge trunk r2353, resolving minor conflicts.

2383. By Gavin Panella

Merge trunk r2354.

2384. By Gavin Panella

Merge trunk r2355.

2385. By Gavin Panella

Merge trunk r2356.

2386. By Gavin Panella

Merge trunk r2357.

2387. By Gavin Panella

Merge trunk r2358.

2388. By Gavin Panella

Merge trunk r2359.

2389. By Gavin Panella

Merge trunk r2360.

2390. By Gavin Panella

Merge trunk r2361.

2391. By Gavin Panella

Merge trunk r2362.

2392. By Gavin Panella

Merge trunk r2363.

2393. By Gavin Panella

Merge trunk r2364.

2394. By Gavin Panella

Merge trunk r2365.

2395. By Gavin Panella

Merge trunk r2366.

2396. By Gavin Panella

Merge trunk r2367.

2397. By Gavin Panella

Merge trunk r2368.

2398. By Gavin Panella

Merge trunk r2369.

2399. By Gavin Panella

Merge trunk r2370.

2400. By Gavin Panella

Merge trunk r2371.

2401. By Gavin Panella

Merge trunk r2372.

2402. By Gavin Panella

Merge trunk r2373.

2403. By Gavin Panella

Merge trunk r2374.

2404. By Gavin Panella

Merge trunk r2375.

2405. By Gavin Panella

Merge trunk r2376.

2406. By Gavin Panella

Merge trunk r2377, resolving minor conflicts.

2407. By Gavin Panella

Merge trunk r2378.

2408. By Gavin Panella

Merge trunk r2379.

2409. By Gavin Panella

Merge trunk r2380.

2410. By Gavin Panella

Merge trunk r2381.

2411. By Gavin Panella

Merge trunk r2382.

2412. By Gavin Panella

Merge trunk r2383.

2413. By Gavin Panella

Merge trunk r2384.

2414. By Gavin Panella

Merge trunk r2385.

2415. By Gavin Panella

Merge trunk r2386.

2416. By Gavin Panella

Merge trunk r2387.

2417. By Gavin Panella

Merge trunk r2388.

2418. By Gavin Panella

Merge trunk r2389.

2419. By Gavin Panella

Merge trunk r2390.

2420. By Gavin Panella

Merge trunk r2391.

2421. By Gavin Panella

Merge trunk r2392.

2422. By Gavin Panella

Merge trunk r2393.

2423. By Gavin Panella

Merge trunk r2394.

2424. By Gavin Panella

Merge trunk r2395.

2425. By Gavin Panella

Merge trunk r2396, resolving minor conflicts.

2426. By Gavin Panella

Merge trunk r2397.

2427. By Gavin Panella

Merge trunk r2398.

2428. By Gavin Panella

Merge trunk r2399.

2429. By Gavin Panella

Merge trunk r2400.

2430. By Gavin Panella

Merge trunk r2401.

2431. By Gavin Panella

Merge trunk r2402.

2432. By Gavin Panella

Merge trunk r2403.

2433. By Gavin Panella

Merge trunk r2404.

2434. By Gavin Panella

Merge trunk r2405.

2435. By Gavin Panella

Merge trunk r2406, resolving minor conflicts.

2436. By Gavin Panella

Merge trunk r2407.

2437. By Gavin Panella

Merge trunk r2408.

2438. By Gavin Panella

Merge trunk r2409.

2439. By Gavin Panella

Merge trunk r2410.

2440. By Gavin Panella

Merge trunk r2411.

2441. By Gavin Panella

Merge trunk r2412, resolving minor conflicts.

2442. By Gavin Panella

Merge trunk r2413.

2443. By Gavin Panella

Merge trunk r2414.

2444. By Gavin Panella

Merge trunk r2415.

2445. By Gavin Panella

Merge trunk r2416.

2446. By Gavin Panella

Merge trunk r2417.

2447. By Gavin Panella

Merge trunk r2418.

2448. By Gavin Panella

Merge trunk r2419.

2449. By Gavin Panella

Merge trunk r2420.

2450. By Gavin Panella

Merge trunk r2421.

2451. By Gavin Panella

Merge trunk r2422.

2452. By Gavin Panella

Merge trunk r2423.

2453. By Gavin Panella

Merge trunk r2424.

2454. By Gavin Panella

Merge trunk r2425.

2455. By Gavin Panella

Merge trunk r2426.

2456. By Gavin Panella

Merge trunk r2427.

2457. By Gavin Panella

Merge trunk r2428.

2458. By Gavin Panella

Merge trunk r2429.

2459. By Gavin Panella

Merge trunk r2430, resolving minor conflicts.

2460. By Gavin Panella

Merge trunk r2431.

2461. By Gavin Panella

Merge trunk r2432.

2462. By Gavin Panella

Merge trunk r2433.

2463. By Gavin Panella

Merge trunk r2434.

2464. By Gavin Panella

Merge trunk r2435.

2465. By Gavin Panella

Merge trunk r2436.

2466. By Gavin Panella

Merge trunk r2437.

2467. By Gavin Panella

Merge trunk r2438.

2468. By Gavin Panella

Merge trunk r2439.

2469. By Gavin Panella

Merge trunk r2440.

2470. By Gavin Panella

Merge trunk r2441.

2471. By Gavin Panella

Merge trunk r2442.

2472. By Gavin Panella

Merge trunk r2443.

2473. By Gavin Panella

Merge trunk r2444.

2474. By Gavin Panella

Merge trunk r2445.

2475. By Gavin Panella

Merge trunk r2446.

2476. By Gavin Panella

Merge trunk r2447.

2477. By Gavin Panella

Merge trunk r2448, resolving minor conflicts.

2478. By Gavin Panella

Merge trunk r2449, resolving minor conflicts.

2479. By Gavin Panella

Merge trunk r2450, resolving minor conflicts.

2480. By Gavin Panella

Merge trunk r2451.

2481. By Gavin Panella

Merge trunk r2452.

2482. By Gavin Panella

Merge trunk r2453.

2483. By Gavin Panella

Merge trunk r2454.

2484. By Gavin Panella

Merge trunk r2455.

2485. By Gavin Panella

Merge trunk r2456.

2486. By Gavin Panella

Merge trunk r2457.

2487. By Gavin Panella

Merge trunk r2458.

2488. By Gavin Panella

Merge trunk r2459.

2489. By Gavin Panella

Merge trunk r2460.

2490. By Gavin Panella

Merge trunk r2461.

2491. By Gavin Panella

Merge trunk r2462, resolving minor conflicts.

2492. By Gavin Panella

Merge trunk r2463.

2493. By Gavin Panella

Merge trunk r2464.

2494. By Gavin Panella

Merge trunk r2465, resolving minor conflicts.

2495. By Gavin Panella

Merge trunk r2466.

2496. By Gavin Panella

Merge trunk r2467.

2497. By Gavin Panella

Merge trunk r2468.

2498. By Gavin Panella

Merge trunk r2469.

2499. By Gavin Panella

Merge trunk r2470.

2500. By Gavin Panella

Merge trunk r2471.

2501. By Gavin Panella

Merge trunk r2472.

2502. By Gavin Panella

Merge trunk r2473, resolving minor conflicts.

2503. By Gavin Panella

Merge trunk r2474.

2504. By Gavin Panella

Merge trunk r2475.

2505. By Gavin Panella

Merge trunk r2476.

2506. By Gavin Panella

Merge trunk r2477.

2507. By Gavin Panella

Merge trunk r2478.

2508. By Gavin Panella

Merge trunk r2479.

2509. By Gavin Panella

Merge trunk r2480.

2510. By Gavin Panella

Merge trunk r2481.

2511. By Gavin Panella

Merge trunk r2482.

2512. By Gavin Panella

Merge trunk r2483.

2513. By Gavin Panella

Merge trunk r2484.

2514. By Gavin Panella

Merge trunk r2485.

2515. By Gavin Panella

Merge trunk r2486.

2516. By Gavin Panella

Merge trunk r2487.

2517. By Gavin Panella

Merge trunk r2488.

2518. By Gavin Panella

Merge trunk r2489.

2519. By Gavin Panella

Merge trunk r2490.

2520. By Gavin Panella

Merge trunk r2491.

2521. By Gavin Panella

Merge trunk r2492.

2522. By Gavin Panella

Merge trunk r2493.

2523. By Gavin Panella

Merge trunk r2494.

2524. By Gavin Panella

Merge trunk r2495.

2525. By Gavin Panella

Merge trunk r2496.

2526. By Gavin Panella

Merge trunk r2497.

2527. By Gavin Panella

Merge trunk r2498.

2528. By Gavin Panella

Merge trunk r2499.

2529. By Gavin Panella

Merge trunk r2500.

2530. By Gavin Panella

Merge trunk r2501.

2531. By Gavin Panella

Merge trunk r2502.

2532. By Gavin Panella

Merge trunk r2503.

2533. By Gavin Panella

Merge trunk r2504.

2534. By Gavin Panella

Merge trunk r2505.

2535. By Gavin Panella

Merge trunk r2506.

2536. By Gavin Panella

Merge trunk r2507.

2537. By Gavin Panella

Merge trunk r2508.

2538. By Gavin Panella

Merge trunk r2509.

2539. By Gavin Panella

Merge trunk r2510.

2540. By Gavin Panella

Merge trunk r2511.

2541. By Gavin Panella

Merge trunk r2512.

2542. By Gavin Panella

Merge trunk r2513.

2543. By Gavin Panella

Merge trunk r2514.

2544. By Gavin Panella

Merge trunk r2515.

2545. By Gavin Panella

Merge trunk r2516.

2546. By Gavin Panella

Merge trunk r2517.

2547. By Gavin Panella

Merge trunk r2518.

2548. By Gavin Panella

Merge trunk r2519.

2549. By Gavin Panella

Merge trunk r2520.

2550. By Gavin Panella

Merge trunk r2521.

2551. By Gavin Panella

Merge trunk r2522.

2552. By Gavin Panella

Merge trunk r2523.

2553. By Gavin Panella

Merge trunk r2524.

2554. By Gavin Panella

Merge trunk r2525.

2555. By Gavin Panella

Merge trunk r2526.

2556. By Gavin Panella

Merge trunk r2527.

2557. By Gavin Panella

Merge trunk r2528.

2558. By Gavin Panella

Merge trunk r2529.

2559. By Gavin Panella

Merge trunk r2530.

2560. By Gavin Panella

Merge trunk r2531.

2561. By Gavin Panella

Merge trunk r2532.

2562. By Gavin Panella

Merge trunk r2533.

2563. By Gavin Panella

Merge trunk r2534.

2564. By Gavin Panella

Merge trunk r2535.

2565. By Gavin Panella

Merge trunk r2536.

2566. By Gavin Panella

Merge trunk r2537.

2567. By Gavin Panella

Merge trunk r2538.

2568. By Gavin Panella

Merge trunk r2539.

2569. By Gavin Panella

Merge trunk r2540.

2570. By Gavin Panella

Merge trunk r2541.

2571. By Gavin Panella

Merge trunk r2542.

2572. By Gavin Panella

Merge trunk r2543.

2573. By Gavin Panella

Merge trunk r2544.

2574. By Gavin Panella

Merge trunk r2545.

2575. By Gavin Panella

Merge trunk r2546.

2576. By Gavin Panella

Merge trunk r2547.

2577. By Gavin Panella

Merge trunk r2548.

2578. By Gavin Panella

Merge trunk r2549.

2579. By Gavin Panella

Merge trunk r2550.

2580. By Gavin Panella

Merge trunk r2551.

2581. By Gavin Panella

Merge trunk r2552.

2582. By Gavin Panella

Merge trunk r2553.

2583. By Gavin Panella

Merge trunk r2554.

2584. By Gavin Panella

Merge trunk r2555.

2585. By Gavin Panella

Merge trunk r2556.

2586. By Gavin Panella

Merge trunk r2557.

2587. By Gavin Panella

Merge trunk r2558.

2588. By Gavin Panella

Merge trunk r2559.

2589. By Gavin Panella

Merge trunk r2560.

2590. By Gavin Panella

Merge trunk r2561.

2591. By Gavin Panella

Merge trunk r2562.

2592. By Gavin Panella

call_capture_and_check was removed a while back.

2593. By Gavin Panella

Merge trunk r2563.

2594. By Gavin Panella

Merge trunk r2564.

2595. By Gavin Panella

Merge trunk r2565.

2596. By Gavin Panella

Merge trunk r2566.

2597. By Gavin Panella

Merge trunk r2567.

2598. By Gavin Panella

Merge trunk r2568.

2599. By Gavin Panella

Merge trunk r2569.

2600. By Gavin Panella

Merge trunk r2570.

2601. By Gavin Panella

Merge trunk r2571.

2602. By Gavin Panella

Merge trunk r2572.

2603. By Gavin Panella

Merge trunk r2573.

2604. By Gavin Panella

Merge trunk r2574.

2605. By Gavin Panella

Merge trunk r2575.

2606. By Gavin Panella

Merge trunk r2576.

2607. By Gavin Panella

Merge trunk r2577.

2608. By Gavin Panella

Merge trunk r2578.

2609. By Gavin Panella

Merge trunk r2579.

2610. By Gavin Panella

Merge trunk r2580.

2611. By Gavin Panella

Merge trunk r2581.

2612. By Gavin Panella

Merge trunk r2582.

2613. By Gavin Panella

Merge trunk r2583.

2614. By Gavin Panella

Merge trunk r2584.

2615. By Gavin Panella

Merge trunk r2585.

2616. By Gavin Panella

Merge trunk r2586.

2617. By Gavin Panella

Merge trunk r2587.

2618. By Gavin Panella

Merge trunk r2588.

2619. By Gavin Panella

Merge trunk r2589.

2620. By Gavin Panella

Merge trunk r2590.

2621. By Gavin Panella

Merge trunk r2591.

2622. By Gavin Panella

Merge trunk r2592.

2623. By Gavin Panella

Merge trunk r2593.

2624. By Gavin Panella

Merge trunk r2594.

2625. By Gavin Panella

Merge trunk r2595.

2626. By Gavin Panella

Merge trunk r2596.

2627. By Gavin Panella

Merge trunk r2597.

2628. By Gavin Panella

Merge trunk r2598.

2629. By Gavin Panella

Merge trunk r2599.

2630. By Gavin Panella

Merge trunk r2600.

Revision history for this message
MAAS Lander (maas-lander) wrote :

Transitioned to Git.

lp:maas has now moved from Bzr to Git.
Please propose your branches with Launchpad using Git.

git clone https://git.launchpad.net/maas

Unmerged revisions

2630. By Gavin Panella

Merge trunk r2600.

2629. By Gavin Panella

Merge trunk r2599.

2628. By Gavin Panella

Merge trunk r2598.

2627. By Gavin Panella

Merge trunk r2597.

2626. By Gavin Panella

Merge trunk r2596.

2625. By Gavin Panella

Merge trunk r2595.

2624. By Gavin Panella

Merge trunk r2594.

2623. By Gavin Panella

Merge trunk r2593.

2622. By Gavin Panella

Merge trunk r2592.

2621. By Gavin Panella

Merge trunk r2591.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file '.bzrignore'
2--- .bzrignore 2014-01-17 18:19:37 +0000
3+++ .bzrignore 2014-07-28 15:42:36 +0000
4@@ -27,9 +27,20 @@
5 ./media/demo/*
6 ./media/development
7 ./parts
8+./pkg/*/.db.lock
9+./pkg/*/.tox
10+./pkg/*/bin
11+./pkg/*/db
12+./pkg/*/dist
13+./pkg/*/include
14+./pkg/*/lib
15+./pkg/*/local
16+./pkg/*/man
17+./pkg/*/share
18+./pkg/dist
19+./pkg/maas-region/maasserver/static/js/enums.js
20 ./run/*
21 ./services/*/supervise
22-./src/maasserver/static/js/enums.js
23 ./TAGS
24 ./tags
25 dropin.cache
26
27=== added file '.root'
28=== modified file 'HACKING.txt'
29--- HACKING.txt 2014-05-05 16:20:18 +0000
30+++ HACKING.txt 2014-07-28 15:42:36 +0000
31@@ -38,6 +38,8 @@
32
33 $ bzr branch lp:maas maas && cd maas
34
35+TODO: Some of the following is obsolete or has changed.
36+
37 MAAS depends on Postgres 9.1, RabbitMQ, Apache 2, daemontools,
38 pyinotify, and many other packages. To install everything that's needed
39 for running and developing MAAS, run::
40@@ -58,54 +60,16 @@
41 suite.
42
43 All other development dependencies are pulled automatically from
44-`PyPI`_ when ``buildout`` runs. See `First time using buildout?`_ and
45-`Running tests`_.
46+`PyPI`_.
47
48 .. _PyPI:
49 http://pypi.python.org/
50
51
52-First time using buildout?
53-==========================
54-
55-Buildout_ is used to develop MAAS. Buildout, if configured so, can
56-cache downloaded files and built eggs. If you've not already done
57-something similar, the following snippet will massively improve build
58-times::
59-
60- [buildout]
61- download-cache = /home/<your-user-name>/.buildout/cache
62- eggs-directory = /home/<your-user-name>/.buildout/eggs
63-
64-Put this in ``~/.buildout/default.cfg`` and create the ``cache``
65-directory::
66-
67- $ mkdir /home/<your-user-name>/.buildout/cache
68-
69-The ``eggs`` directory will be created automatically.
70-
71-.. _Buildout:
72- http://www.buildout.org/
73-
74-
75 Running tests
76 =============
77
78-To run the whole suite::
79-
80- $ make test
81-
82-To run tests at a lower level of granularity::
83-
84- $ ./bin/test.maas test src/maasserver/tests/test_api.py
85- $ ./bin/test.maas test src/maasserver/tests/test_api.py:AnonymousEnlistmentAPITest
86-
87-The test runner is `nose`_, so you can pass in options like
88-``--with-coverage`` and ``--nocapture`` (short option: ``-s``). The
89-latter is essential when using ``pdb`` so that stdout is not
90-adulterated.
91-
92-.. _nose: http://readthedocs.org/docs/nose/en/latest/
93+TODO: Describe how to run tests in a post-``buildout`` world.
94
95
96 Running JavaScript tests
97@@ -395,18 +359,7 @@
98 Adding new dependencies
99 =======================
100
101-Since MAAS is distributed mainly as an Ubuntu package, all runtime
102-dependencies should be packaged, and we should develop with the
103-packaged version if possible. All dependencies, from a package or not,
104-need to be added to ``setup.py`` and ``buildout.cfg``, and the version
105-specified in ``versions.cfg`` (``allowed-picked-version`` is disabled,
106-hence ``buildout`` must be given precise version information).
107-
108-If it is a development-only dependency (i.e. only needed for the test suite, or
109-for developers' convenience), simply running ``buildout`` like this will make
110-the necessary updates to ``versions.cfg``::
111-
112- $ ./bin/buildout -v buildout:allow-picked-versions=true
113+TODO: Describe how to add new dependencies in a post-``buildout`` world.
114
115
116 Adding new source files
117
118=== removed file 'MANIFEST.in'
119--- MANIFEST.in 2013-06-05 10:44:25 +0000
120+++ MANIFEST.in 1970-01-01 00:00:00 +0000
121@@ -1,10 +0,0 @@
122-graft src/*/static
123-graft src/*/templates
124-graft src/*/fixtures
125-graft src/*/specs
126-graft src/provisioningserver/*
127-graft src/metadataserver/commissioning
128-prune src/*/testing
129-prune src/*/tests
130-prune src/maastesting
131-prune src/provisioningserver/*/tests
132
133=== modified file 'Makefile'
134--- Makefile 2014-06-10 14:45:14 +0000
135+++ Makefile 2014-07-28 15:42:36 +0000
136@@ -3,10 +3,8 @@
137 # Network activity can be suppressed by setting offline=true (or any
138 # non-empty string) at the command-line.
139 ifeq ($(offline),)
140-buildout := bin/buildout
141 virtualenv := virtualenv
142 else
143-buildout := bin/buildout buildout:offline=true
144 virtualenv := virtualenv --never-download
145 endif
146
147@@ -17,11 +15,6 @@
148 export https_proxy := broken
149 endif
150
151-# Python enum modules.
152-py_enums := $(wildcard src/*/enum.py)
153-# JavaScript enum module (not modules).
154-js_enums := src/maasserver/static/js/enums.js
155-
156 # Prefix commands with this when they need access to the database.
157 # Remember to add a dependency on bin/database from the targets in
158 # which those commands appear.
159@@ -31,100 +24,56 @@
160 # use the "maas" databases.
161 export PGDATABASE := maas
162
163-build: \
164- bin/buildout \
165- bin/database \
166- bin/maas-region-admin bin/test.maas \
167- bin/maas bin/test.maascli \
168- bin/test.maastesting \
169- bin/twistd.pserv bin/test.pserv \
170- bin/test.config \
171- bin/maas-probe-dhcp \
172- bin/twistd.txlongpoll \
173- bin/celeryd.cluster bin/celeryd.region \
174- bin/py bin/ipy \
175- $(js_enums)
176+# Executables that are usual for a development environment.
177+define executables
178+ bin/database
179+ bin/flake8
180+ bin/ipython
181+ bin/sphinx
182+
183+ bin/maas-dns-server
184+ bin/maas-region-admin
185+ bin/maas-region-twistd
186+ bin/maas-region-worker
187+
188+ bin/maas-cluster-twistd
189+ bin/maas-cluster-worker
190+ bin/maas-probe-dhcp
191+ bin/maas-provision
192+
193+ bin/maas
194+endef
195+executables := $(strip $(executables))
196+
197+# The Python packages that form MAAS, in order of installation (pip is
198+# not great at resolving dependencies in the correct order).
199+define python-packages
200+ maas-apiclient
201+ maas-client
202+ maas-cluster
203+ maas-region
204+ maas-testing
205+ maas-develop
206+endef
207+python-packages := $(strip $(python-packages))
208+
209+build: $(executables) enums
210
211 all: build doc
212
213-# Install all packages required for MAAS development & operation on
214-# the system. This may prompt for a password.
215-install-dependencies:
216- sudo DEBIAN_FRONTEND=noninteractive apt-get -y \
217- --no-install-recommends install $(shell sort -u \
218- $(addprefix required-packages/,base build dev doc))
219- sudo DEBIAN_FRONTEND=noninteractive apt-get -y \
220- purge $(shell sort -u required-packages/forbidden)
221-
222 bin/python:
223 $(virtualenv) --python=$(python) --system-site-packages $(CURDIR)
224
225-bin/buildout: bin/python bootstrap/zc.buildout-1.5.2.tar.gz
226- bin/python -m pip --quiet install --ignore-installed \
227- --no-dependencies bootstrap/zc.buildout-1.5.2.tar.gz
228- $(RM) -f README.txt # zc.buildout installs an annoying README.txt.
229- @touch --no-create $@ # Ensure it's newer than its dependencies.
230-
231-bin/database: bin/buildout buildout.cfg versions.cfg setup.py
232- $(buildout) install database
233- @touch --no-create $@
234-
235-bin/maas-region-admin bin/celeryd.region: \
236- bin/buildout buildout.cfg versions.cfg setup.py $(js_enums)
237- $(buildout) install maas
238- @touch --no-create $@
239-
240-bin/test.maas: bin/buildout buildout.cfg versions.cfg setup.py $(js_enums)
241- $(buildout) install maas-test
242- @touch --no-create $@
243-
244-bin/maas: bin/buildout buildout.cfg versions.cfg setup.py
245- $(buildout) install maascli
246- @touch --no-create $@
247-
248-bin/test.maascli: bin/buildout buildout.cfg versions.cfg setup.py
249- $(buildout) install maascli-test
250- @touch --no-create $@
251-
252-bin/test.maastesting: bin/buildout buildout.cfg versions.cfg setup.py
253- $(buildout) install maastesting-test
254- @touch --no-create $@
255-
256-bin/maas-provision bin/twistd.pserv bin/celeryd.cluster: \
257- bin/buildout buildout.cfg versions.cfg setup.py
258- $(buildout) install pserv
259- @touch --no-create $@
260-
261-bin/test.pserv: bin/buildout buildout.cfg versions.cfg setup.py
262- $(buildout) install pserv-test
263- @touch --no-create $@
264-
265-bin/test.config: bin/buildout buildout.cfg versions.cfg setup.py
266- $(buildout) install config-test
267- @touch --no-create $@
268-
269-bin/maas-probe-dhcp: bin/buildout buildout.cfg versions.cfg setup.py
270- $(buildout) install maas-probe-dhcp
271- @touch --no-create $@
272-
273-bin/twistd.txlongpoll: bin/buildout buildout.cfg versions.cfg setup.py
274- $(buildout) install txlongpoll
275- @touch --no-create $@
276-
277-bin/flake8: bin/buildout buildout.cfg versions.cfg setup.py
278- $(buildout) install flake8
279- @touch --no-create $@
280-
281-bin/sphinx bin/sphinx-build: bin/buildout buildout.cfg versions.cfg setup.py
282- $(buildout) install sphinx
283- @touch --no-create $@
284-
285-bin/py bin/ipy: bin/buildout buildout.cfg versions.cfg setup.py
286- $(buildout) install repl
287- @touch --no-create bin/py bin/ipy
288-
289-test: build
290- echo $(wildcard bin/test.*) | xargs -n1 env
291+$(executables): bin/python
292+ $(MAKE) -C pkg
293+ @for dep in $(python-packages); do \
294+ (cd pkg/$${dep} && python setup.py install_deps); done
295+ bin/python -m pip install \
296+ $(addprefix --editable pkg/,$(python-packages))
297+ @touch --no-create $@
298+
299+test:
300+ $(MAKE) -C pkg test
301
302 lint: lint-py lint-js lint-doc
303
304@@ -133,57 +82,69 @@
305 # XXX jtv 2014-02-25: Clean up this lint, then make it part of "make lint".
306 lint-css: sources = src/maasserver/static/css
307 lint-css:
308- @find $(sources) -type f \
309- -print0 | xargs -r0 $(pocketlint) --max-length=120
310+ @find . -type f -name '*.css' -print0 | \
311+ xargs -r0 $(pocketlint) --max-length=120
312
313-lint-py: sources = $(wildcard *.py contrib/*.py) src templates twisted utilities etc
314+lint-py: sources = src/*/ templates utilities pkg/common
315+lint-py: sources += pkg/*/contrib pkg/*/etc pkg/*/*.py pkg/*/twisted
316 lint-py: bin/flake8
317- @find $(sources) -name '*.py' ! -path '*/migrations/*' \
318- -print0 | xargs -r0 bin/flake8 --ignore=E123 --config=/dev/null
319+ @find $(sources) -type f -name '*.py' \
320+ ! -path '*/migrations/*' ! -path '*/setup.py' -print0 | \
321+ xargs -r0 bin/flake8 --ignore=E123 --config=/dev/null
322
323 lint-doc:
324- @./utilities/doc-lint
325+ @utilities/doc-lint
326
327 lint-js: sources = src/maasserver/static/js
328 lint-js:
329- @find $(sources) -type f -print0 '(' -name '*.html' -o -name '*.js' ')' | xargs -r0 $(pocketlint)
330+ @find $(sources) -type f -print0 \
331+ '(' -name '*.html' -o -name '*.js' ')' | \
332+ xargs -r0 $(pocketlint) --max-length=120
333
334 # Apply automated formatting to all Python files.
335-format: sources = $(wildcard *.py contrib/*.py) src templates twisted utilities etc
336+format: sources = src/*/ templates utilities pkg/common
337+format: sources += pkg/*/contrib pkg/*/etc pkg/*/*.py pkg/*/twisted
338 format:
339- @find $(sources) -name '*.py' -print0 | xargs -r0 ./utilities/format-imports
340+ @find $(sources) -name '*.py' -print0 | \
341+ xargs -r0 utilities/format-imports
342
343 check: clean test
344
345+# TODO: Move to maas-develop? Or maas-region. Generating documentation
346+# may even be better contained in a separate subproject.
347 docs/api.rst: bin/maas-region-admin src/maasserver/api.py syncdb
348 bin/maas-region-admin generate_api_doc > $@
349
350-sampledata: bin/maas-region-admin bin/database syncdb
351- $(dbrun) bin/maas-region-admin loaddata src/maasserver/fixtures/dev_fixture.yaml
352-
353+# TODO: Move to maas-develop? Or maas-region. Generating documentation
354+# may even be better contained in a separate subproject.
355 doc: bin/sphinx docs/api.rst
356- bin/sphinx
357+ bin/sphinx docs docs/_build/html
358
359+# TODO: Move to maas-develop? Or maas-region. Generating documentation
360+# may even be better contained in a separate subproject.
361 doc-with-versions: bin/sphinx docs/api.rst
362 cd docs/_build; make SPHINXOPTS="-A add_version_switcher=true" html
363
364+# TODO: Move to maas-develop? Or maas-region. Generating documentation
365+# may even be better contained in a separate subproject.
366 man: $(patsubst docs/man/%.rst,man/%,$(wildcard docs/man/*.rst))
367
368-man/%: docs/man/%.rst | bin/sphinx-build
369- bin/sphinx-build -b man docs man $^
370-
371-enums: $(js_enums)
372-
373-$(js_enums): bin/py src/maasserver/utils/jsenums.py $(py_enums)
374- bin/py -m src/maasserver/utils/jsenums $(py_enums) > $@
375+# TODO: Move to maas-develop? Or maas-region. Generating documentation
376+# may even be better contained in a separate subproject.
377+man/%: docs/man/%.rst | bin/sphinx
378+ bin/sphinx -b man docs man $^
379+
380+# TODO: Dynamically serve enums JavaScript to clients. This build step
381+# complicates packaging, and introduces some fragility.
382+enums:
383+ $(MAKE) -C pkg/maas-region enums
384
385 clean:
386 $(MAKE) -C acceptance $@
387+ $(MAKE) -C pkg $@
388 find . -type f -name '*.py[co]' -print0 | xargs -r0 $(RM)
389 find . -type f -name '*~' -print0 | xargs -r0 $(RM)
390 find . -type f -name dropin.cache -print0 | xargs -r0 $(RM)
391- $(RM) -r media/demo/* media/development
392- $(RM) $(js_enums)
393 $(RM) *.log
394 $(RM) docs/api.rst
395 $(RM) -r docs/_autosummary docs/_build
396@@ -191,23 +152,31 @@
397
398 distclean: clean stop
399 $(RM) -r bin include lib local
400- $(RM) -r eggs develop-eggs
401- $(RM) -r build dist logs/* parts
402- $(RM) tags TAGS .installed.cfg
403- $(RM) -r *.egg *.egg-info src/*.egg-info
404+ $(RM) -r build dist logs/*
405+ $(RM) tags TAGS
406+ $(RM) -r *.egg *.egg-info
407 $(RM) -r run/* services/*/supervise
408
409+# TODO: Move to maas-develop? This is a development-only target.
410 harness: bin/maas-region-admin bin/database
411- $(dbrun) bin/maas-region-admin shell --settings=maas.demo
412+ $(dbrun) bin/maas-region-admin shell
413
414+# TODO: Move to maas-develop? This is a development-only target.
415 dbharness: bin/database
416 bin/database --preserve shell
417
418+# TODO: Move to maas-develop? This is a development-only target.
419 syncdb: bin/maas-region-admin bin/database
420 $(dbrun) bin/maas-region-admin syncdb --noinput
421 $(dbrun) bin/maas-region-admin migrate maasserver --noinput
422 $(dbrun) bin/maas-region-admin migrate metadataserver --noinput
423
424+# TODO: Move to maas-develop, along with dev_fixture.yaml? This is a
425+# development-only target.
426+sampledata: bin/maas-region-admin bin/database syncdb
427+ $(dbrun) bin/maas-region-admin loaddata \
428+ src/maasserver/fixtures/dev_fixture.yaml
429+
430 define phony_targets
431 build
432 check
433@@ -218,7 +187,6 @@
434 enums
435 format
436 harness
437- install-dependencies
438 lint
439 lint-css
440 lint-doc
441@@ -262,12 +230,19 @@
442 $(eval $(call service_template,stop))
443 $(eval $(call service_template,supervise))
444
445-# The `run` targets do not fit into the mould of the others.
446+# The `run` targets do not fit into the mould of the others. Note: logs
447+# directories shouldn't be needed for `run` targets, but some config
448+# seems to still require it, so we create them. Ideally the configs used
449+# for running services should log to stdout/stderr, then we could get
450+# rid of these.
451 run-region:
452+ @mkdir -p $(addprefix logs/,$(service_names_region))
453 @services/run $(service_names_region)
454 run-cluster:
455+ @mkdir -p $(addprefix logs/,$(service_names_cluster))
456 @services/run $(service_names_cluster)
457 run:
458+ @mkdir -p $(addprefix logs/,$(service_names_all))
459 @services/run $(service_names_all)
460
461 phony_services_targets += run-region run-cluster run
462@@ -290,7 +265,12 @@
463
464 # Pseudo-magic targets for controlling individual services.
465
466+# Note: log directories shouldn't be needed for `@run` targets, but some
467+# config seems to still require it, so we create them. Ideally the
468+# configs used for running services should log to stdout/stderr, then we
469+# could get rid of this.
470 services/%/@run: services/%/@stop services/%/@deps
471+ @mkdir -p logs/$*
472 @$(call service_lock, $*) services/$*/run
473
474 services/%/@start: services/%/@supervise
475@@ -319,19 +299,19 @@
476
477 # Dependencies for individual services.
478
479-services/dns/@deps: bin/py
480-
481-services/cluster-worker/@deps: bin/celeryd.cluster
482-
483-services/region-worker/@deps: bin/celeryd.region
484+services/dns/@deps: bin/maas-dns-server
485+
486+services/cluster-worker/@deps: bin/maas-cluster-worker
487+
488+services/region-worker/@deps: bin/maas-region-worker
489
490 services/database/@deps: bin/database
491
492-services/pserv/@deps: bin/twistd.pserv
493+services/pserv/@deps: bin/maas-cluster-twistd
494
495 services/reloader/@deps:
496
497-services/txlongpoll/@deps: bin/twistd.txlongpoll
498+services/txlongpoll/@deps: bin/maas-region-twistd
499
500 services/web/@deps:
501
502
503=== removed directory 'bootstrap'
504=== removed file 'bootstrap/zc.buildout-1.5.2.tar.gz'
505Binary files bootstrap/zc.buildout-1.5.2.tar.gz 2012-06-14 11:21:10 +0000 and bootstrap/zc.buildout-1.5.2.tar.gz 1970-01-01 00:00:00 +0000 differ
506=== removed file 'buildout.cfg'
507--- buildout.cfg 2014-03-18 14:35:22 +0000
508+++ buildout.cfg 1970-01-01 00:00:00 +0000
509@@ -1,232 +0,0 @@
510-[buildout]
511-parts =
512- flake8
513- maas
514- maas-test
515- maascli
516- maascli-test
517- maas-probe-dhcp
518- maastesting-test
519- pserv
520- pserv-test
521- config-test
522- repl
523- sphinx
524- txlongpoll
525-extensions = buildout-versions
526-buildout_versions_file = versions.cfg
527-versions = versions
528-extends = versions.cfg
529-offline = false
530-newest = false
531-
532-# Since MAAS's main deployment target is Ubuntu, all runtime
533-# dependencies should come from python packages. However, it's okay
534-# for development-time dependencies to come from eggs.
535-include-site-packages = true
536-
537-prefer-final = true
538-allow-picked-versions = false
539-
540-[common]
541-extra-paths =
542- ${buildout:directory}/etc
543- ${buildout:directory}/src
544- ${buildout:directory}
545-test-eggs =
546- coverage
547- fixtures
548- mock
549- nose
550- nose-subunit
551- postgresfixture
552- python-subunit
553- rabbitfixture
554- saucelabsfixture
555- sst
556- testresources
557- testscenarios
558- testtools
559-initialization =
560- from os import environ
561- environ.setdefault("MAAS_CONFIG_DIR", "${buildout:directory}/etc/maas")
562-
563-[database]
564-recipe = z3c.recipe.scripts
565-eggs = postgresfixture
566-extra-paths = ${common:extra-paths}
567-interpreter =
568-entry-points = database=postgresfixture.main:main
569-scripts = database
570-
571-[maas]
572-recipe = zc.recipe.egg
573-dev-eggs =
574- django-debug-toolbar
575-test-eggs =
576- ${common:test-eggs}
577- django-nose
578-eggs =
579- ${maas:dev-eggs}
580- ${maas:test-eggs}
581- djorm-ext-pgarray
582- docutils
583- crochet
584- iscpy
585-entry-points =
586- celeryd.region=celery.bin.worker:main
587- maas-region-admin=django.core.management:execute_from_command_line
588-initialization =
589- ${common:initialization}
590- environ.setdefault("DJANGO_SETTINGS_MODULE", "maas.development")
591-scripts =
592- celeryd.region
593- maas-region-admin
594-extra-paths =
595- ${common:extra-paths}
596-
597-[maas-test]
598-recipe = zc.recipe.egg
599-eggs =
600- ${maas:eggs}
601-entry-points =
602- test.maas=django.core.management:execute_from_command_line
603-initialization =
604- ${maas:initialization}
605- sys.argv[1:1] = [
606- "test", "--noinput", "--exclude=provisioningserver",
607- "--exclude=maastesting", "--exclude=maascli"]
608-scripts = test.maas
609-extra-paths =
610- ${maas:extra-paths}
611-
612-[maas-probe-dhcp]
613-recipe = zc.recipe.egg
614-eggs =
615- ${maas:eggs}
616-entry-points =
617- maas-probe-dhcp=provisioningserver.dhcp.probe:main
618-scripts =
619- maas-probe-dhcp
620-extra-paths =
621- ${maas:extra-paths}
622-initialization =
623- ${common:initialization}
624-
625-[maascli]
626-recipe = zc.recipe.egg
627-eggs =
628-entry-points =
629- maas=maascli:main
630-extra-paths =
631- ${common:extra-paths}
632-scripts =
633- maas
634-
635-[maascli-test]
636-recipe = zc.recipe.egg
637-eggs =
638- ${maascli:eggs}
639- ${common:test-eggs}
640-entry-points =
641- test.maascli=nose.core:TestProgram
642-initialization =
643- sys.argv[1:1] = ["--where=src/maascli"]
644-extra-paths = ${maascli:extra-paths}
645-scripts =
646- test.maascli
647-
648-[maastesting-test]
649-recipe = zc.recipe.egg
650-eggs =
651- ${common:test-eggs}
652-entry-points =
653- test.maastesting=nose.core:TestProgram
654-initialization =
655- sys.argv[1:1] = ["--where=src/maastesting"]
656-extra-paths = ${common:extra-paths}
657-scripts =
658- test.maastesting
659-scripts = test.maastesting
660-extra-paths =
661- ${maas:extra-paths}
662-
663-[pserv]
664-recipe = zc.recipe.egg
665-eggs =
666- crochet
667-entry-points =
668- celeryd.cluster=celery.bin.worker:main
669- maas-provision=provisioningserver.__main__:main
670- twistd.pserv=twisted.scripts.twistd:run
671-extra-paths =
672- ${common:extra-paths}
673-scripts =
674- celeryd.cluster
675- maas-provision
676- twistd.pserv
677-initialization =
678- ${common:initialization}
679-
680-[pserv-test]
681-recipe = zc.recipe.egg
682-eggs =
683- ${pserv:eggs}
684- ${common:test-eggs}
685-entry-points =
686- test.pserv=nose.core:TestProgram
687-initialization =
688- ${pserv:initialization}
689- sys.argv[1:1] = ["--where=src/provisioningserver"]
690-extra-paths = ${pserv:extra-paths}
691-scripts =
692- test.pserv
693-
694-[config-test]
695-recipe = zc.recipe.egg
696-eggs =
697- ${common:test-eggs}
698-entry-points =
699- test.config=nose.core:TestProgram
700-initialization =
701- ${pserv:initialization}
702- sys.argv[1:1] = ["--where=etc/maas/templates/commissioning-user-data"]
703-extra-paths = ${common:extra-paths}
704-scripts =
705- test.config
706-
707-[flake8]
708-recipe = zc.recipe.egg
709-eggs =
710- flake8
711-entry-points =
712- flake8=flake8.run:main
713-
714-[sphinx]
715-recipe = collective.recipe.sphinxbuilder
716-source = ${buildout:directory}/docs
717-build = ${buildout:directory}/docs/_build
718-extra-paths = ${common:extra-paths}
719-eggs =
720- ${maas:eggs}
721- ${pserv:eggs}
722-
723-# Convenient REPLs with all eggs available.
724-[repl]
725-recipe = z3c.recipe.scripts
726-eggs =
727- ${maas:eggs}
728- ${pserv:eggs}
729- ${common:test-eggs}
730-extra-paths = ${common:extra-paths}
731-interpreter = py
732-scripts = ipy
733-entry-points =
734- ipy=IPython.frontend.terminal.ipapp:launch_new_instance
735-
736-[txlongpoll]
737-recipe = z3c.recipe.scripts
738-eggs =
739-extra-paths = /buildout/creates/an/invalid/list/literal/without/this
740-entry-points = twistd.txlongpoll=twisted.scripts.twistd:run
741-scripts = twistd.txlongpoll
742
743=== removed directory 'contrib'
744=== removed directory 'etc'
745=== removed symlink 'etc/apache.trusty.conf'
746=== target was u'apache.saucy.conf'
747=== removed directory 'etc/maas'
748=== removed directory 'etc/maas/templates'
749=== removed file 'etc/maas_local_celeryconfig_cluster.py'
750--- etc/maas_local_celeryconfig_cluster.py 2013-12-03 13:06:17 +0000
751+++ etc/maas_local_celeryconfig_cluster.py 1970-01-01 00:00:00 +0000
752@@ -1,4 +0,0 @@
753-# This is the version of maas_local_celeryconfig_cluster.py that's used
754-# when running from a branch. The master cluster controller (running on
755-# the same development machine) has a fixed UUID.
756-CLUSTER_UUID = "adfd3977-f251-4f2c-8d61-745dbd690bf2"
757
758=== added directory 'pkg'
759=== added file 'pkg/Makefile'
760--- pkg/Makefile 1970-01-01 00:00:00 +0000
761+++ pkg/Makefile 2014-07-28 15:42:36 +0000
762@@ -0,0 +1,49 @@
763+# Copyright 2013 Canonical Ltd. This software is licensed under the
764+# GNU Affero General Public License version 3 (see the file LICENSE).
765+
766+PYTHON := python
767+
768+define sdist
769+$(PYTHON) setup.py --quiet \
770+ egg_info sdist --dist-dir $(CURDIR)/dist
771+endef
772+
773+define make-dist-for
774+cd $(1) && $(sdist)
775+endef
776+
777+setups := $(patsubst %/configure.py,%/setup.py,$(wildcard */configure.py))
778+
779+# ---
780+
781+all: $(setups)
782+
783+dists: $(setups)
784+ $(call make-dist-for,maas-apiclient)
785+ $(call make-dist-for,maas-client)
786+ $(call make-dist-for,maas-cluster)
787+ $(call make-dist-for,maas-develop)
788+ $(call make-dist-for,maas-region)
789+ $(call make-dist-for,maas-testing)
790+
791+test: $(setups)
792+ @ls -1d maas-* | xargs --verbose -I {} make -C {} $@
793+
794+clean:
795+ @ls -1d common maas-* | xargs --verbose -I {} make -C {} $@
796+ find . -name '*~' -print0 | xargs -r0 $(RM)
797+ $(RM) -r dist
798+
799+%/setup.py: %/configure.py common/*.py
800+ $(MAKE) -C $(@D) $(@F)
801+
802+# ---
803+
804+define phony
805+ all
806+ clean
807+ dists
808+ test
809+endef
810+
811+.PHONY: $(strip $(phony))
812
813=== added directory 'pkg/common'
814=== added file 'pkg/common/Makefile'
815--- pkg/common/Makefile 1970-01-01 00:00:00 +0000
816+++ pkg/common/Makefile 2014-07-28 15:42:36 +0000
817@@ -0,0 +1,57 @@
818+# Copyright 2013, 2014 Canonical Ltd. This software is licensed under
819+# the GNU Affero General Public License version 3 (see the file LICENSE).
820+
821+PYTHON := python
822+
823+define virtualenv
824+virtualenv --python=$(PYTHON) --quiet
825+endef
826+
827+# ---
828+
829+all: build
830+
831+ifneq ($(localdeps),)
832+build:: bin/python
833+ @for dep in $(localdeps); do \
834+ (cd ../$${dep} && python setup.py install_deps); done
835+ bin/python -m pip install $(addprefix --editable ../,$(localdeps))
836+endif
837+
838+build:: bin/python setup.py
839+ bin/python setup.py --quiet install_deps develop
840+
841+dist:: bin/python setup.py
842+ bin/python setup.py --quiet egg_info sdist
843+
844+test:: build bin/python setup.py
845+ PATH="$$PWD/bin:$$PATH" bin/python setup.py install_deps test
846+
847+clean::
848+ $(RM) -r bin build dist include lib local man share
849+ find . -name '*.py[co]' -print0 | xargs -r0 $(RM) -r
850+ find . -name '__pycache__' -print0 | xargs -r0 $(RM) -r
851+ find . -name '*.egg' -print0 | xargs -r0 $(RM) -r
852+ find . -name '*.egg-info' -print0 | xargs -r0 $(RM) -r
853+ find . -name '*~' -print0 | xargs -r0 $(RM)
854+ $(RM) -r .tox TAGS tags
855+
856+# ---
857+
858+bin/python:
859+ $(virtualenv) --system-site-packages $(CURDIR)
860+
861+setup.py: configure.py common/*.py
862+ $(PYTHON) $<
863+
864+# ---
865+
866+define phony
867+ all
868+ build
869+ clean
870+ dist
871+ test
872+endef
873+
874+.PHONY: $(strip $(phony))
875
876=== added file 'pkg/common/__init__.py'
877--- pkg/common/__init__.py 1970-01-01 00:00:00 +0000
878+++ pkg/common/__init__.py 2014-07-28 15:42:36 +0000
879@@ -0,0 +1,194 @@
880+#!/usr/bin/env python
881+# Copyright 2013 Canonical Ltd. This software is licensed under the
882+# GNU Affero General Public License version 3 (see the file LICENSE).
883+
884+"""Distutils installer for MAAS."""
885+
886+# unicode_literals is *not* included here to *better* support setup
887+# scripts that work on both Python 2 and 3. Both expect their default
888+# string type, and are fussy about it.
889+from __future__ import (
890+ absolute_import,
891+ print_function,
892+ )
893+
894+__version__ = "1.4"
895+__metaclass__ = type
896+
897+
898+from codecs import open
899+from contextlib import contextmanager
900+from distutils import (
901+ errors,
902+ log,
903+ )
904+from inspect import getsourcefile
905+from operator import methodcaller
906+from os import environ
907+
908+import setuptools
909+
910+
911+@contextmanager
912+def envvar(name, value):
913+ """Context manager for temporarily setting an environment variable."""
914+ original = environ.get(name)
915+ environ[name] = value
916+ try:
917+ yield
918+ finally:
919+ if original is None:
920+ environ.pop(name, None)
921+ else:
922+ environ[name] = original
923+
924+
925+class install_deps(setuptools.Command):
926+ """Distutils/setuptools command to install package dependencies."""
927+
928+ user_options = [
929+ ('list-from=', None,
930+ "file from which to read packages to install"),
931+ ]
932+
933+ def initialize_options(self):
934+ self.list_from = "packages.txt"
935+
936+ def gen_package_ops(self, package_lines):
937+ install = methodcaller("mark_install")
938+ delete = methodcaller("mark_delete", purge=True)
939+ for line in package_lines:
940+ if len(line) == 0:
941+ pass # Ignore blank lines.
942+ elif line.startswith("#"):
943+ pass # Ignore whole-line comments.
944+ elif line.endswith("-"):
945+ package_name = line.rstrip("-")
946+ yield package_name, delete
947+ else:
948+ package_name = line.rstrip("+")
949+ yield package_name, install
950+
951+ def finalize_options(self):
952+ self.ensure_filename("list_from")
953+ self.packages = set()
954+ with open(self.list_from, "r", encoding="utf-8") as fd:
955+ lines = (line.strip() for line in fd)
956+ self.package_ops = dict(self.gen_package_ops(lines))
957+ self.packages = set(self.package_ops)
958+
959+ def run(self):
960+ self.calculate_changes()
961+ if len(self.changes) > 0:
962+ self.apply_changes()
963+
964+ def calculate_changes(self):
965+ from apt import Cache
966+ cache = Cache()
967+ for package_name, op in self.package_ops.iteritems():
968+ op(cache[package_name])
969+ self.changes = cache.get_changes()
970+
971+ def get_packages_to_install(self):
972+ return self.packages.intersection(
973+ package.name for package in self.changes
974+ if package.marked_install or package.marked_upgrade)
975+
976+ def get_packages_to_delete(self):
977+ return self.packages.intersection(
978+ package.name for package in self.changes
979+ if package.marked_delete)
980+
981+ def apply_changes(self):
982+ """Use ``apt`` to check for package installs.
983+
984+ Spawns ``apt-get`` if necessary.
985+ """
986+ to_install = {
987+ "%s+" % package
988+ for package in self.get_packages_to_install()
989+ }
990+ if len(to_install) == 0:
991+ log.info("system dependencies are all in place")
992+
993+ to_delete = {
994+ "%s-" % package
995+ for package in self.get_packages_to_delete()
996+ }
997+ if len(to_delete) == 0:
998+ log.info("no forbidden system dependencies are installed")
999+
1000+ to_do = sorted(to_install | to_delete)
1001+ if len(to_do) > 0:
1002+ install = [
1003+ "sudo", "apt-get", "--assume-yes",
1004+ "--no-install-recommends", "--purge",
1005+ "install",
1006+ ]
1007+ with envvar("DEBIAN_FRONTEND", "noninteractive"):
1008+ self.spawn(install + to_do)
1009+
1010+
1011+def check_settings(settings):
1012+ """Check setup settings for obvious issues.
1013+
1014+ - ``data_files`` should not be specified; setuptools ignores it.
1015+
1016+ - ``include_package_data`` should not be specified; it has weird
1017+ behaviour in setuptools.
1018+ """
1019+ if "data_files" in settings:
1020+ raise errors.DistutilsOptionError(
1021+ "data_files is ignored by setuptools")
1022+ if "include_package_data" in settings:
1023+ raise errors.DistutilsOptionError(
1024+ "include_package_data does not work as you "
1025+ "might expect with setuptools")
1026+
1027+
1028+def setup(**kwargs):
1029+ """MAAS-specific setup function.
1030+
1031+ Determines sensible defaults for many parameters.
1032+ """
1033+ command_classes = {}
1034+
1035+ try:
1036+ import apt
1037+ except ImportError:
1038+ log.warn("apt not available (install 'python-apt'?)")
1039+ else:
1040+ command_classes["install_deps"] = install_deps
1041+ apt # Silence lint.
1042+
1043+ settings = {
1044+ "cmdclass": command_classes,
1045+ "packages": setuptools.find_packages(".", exclude={"common"}),
1046+ "version": __version__,
1047+ "maintainer": "Canonical",
1048+ "maintainer_email": "maas-devel@lists.launchpad.net",
1049+ "url": "https://launchpad.net/maas",
1050+ "license": "AGPLv3",
1051+ "test_loader": "maastesting.loader:MAASTestLoader",
1052+ "test_suite": ".",
1053+ "tests_require": {"maas-testing >= %s" % __version__},
1054+ }
1055+ settings.update(kwargs)
1056+ check_settings(settings)
1057+
1058+ return setuptools.setup(**settings)
1059+
1060+
1061+def configure(**settings):
1062+ """Create a new ``setup.py`` file in the currnet directory.
1063+
1064+ Uses the file in which this function is originally defined as a
1065+ template, adding on a call to ``setup`` with the given ``settings``.
1066+ """
1067+ check_settings(settings)
1068+ thisfile = getsourcefile(configure)
1069+ with open(thisfile, "r", encoding="utf-8") as fin:
1070+ template = fin.read()
1071+ with open("setup.py", "w", encoding="utf-8") as fout:
1072+ fout.write(template)
1073+ fout.write(b"\n\nsetup(**%r)\n" % settings)
1074
1075=== added file 'pkg/common/checkarchive.py'
1076--- pkg/common/checkarchive.py 1970-01-01 00:00:00 +0000
1077+++ pkg/common/checkarchive.py 2014-07-28 15:42:36 +0000
1078@@ -0,0 +1,96 @@
1079+#!/usr/bin/env python2.7
1080+# Copyright 2013 Canonical Ltd. This software is licensed under the
1081+# GNU Affero General Public License version 3 (see the file LICENSE).
1082+
1083+"""Helper to compare the names in an archive with the filesystem.
1084+
1085+More specifically, the names of - and contained within - one or more
1086+directories. Typically these would be top-level Python package
1087+directories, and the archive would be a source distribution of the
1088+aforementioned archive.
1089+
1090+"""
1091+
1092+from __future__ import (
1093+ absolute_import,
1094+ print_function,
1095+ unicode_literals,
1096+ )
1097+
1098+str = None
1099+
1100+__metaclass__ = type
1101+
1102+import argparse
1103+from fnmatch import fnmatchcase
1104+from itertools import (
1105+ chain,
1106+ imap,
1107+ )
1108+import os
1109+from os.path import join
1110+import tarfile
1111+
1112+
1113+ignore = [
1114+ "*.egg-info",
1115+ "*.egg-info/*",
1116+ "*.py[co]",
1117+ "MANIFEST.in",
1118+ "PKG-INFO",
1119+ "README.*",
1120+ "setup.cfg",
1121+ "setup.py",
1122+]
1123+
1124+
1125+# See http://docs.python.org/release/2.7/library/argparse.html.
1126+argument_parser = argparse.ArgumentParser(description=__doc__)
1127+argument_parser.add_argument(
1128+ "archive", type=bytes, help="The archive to compare.")
1129+argument_parser.add_argument(
1130+ "directories", metavar="directory", nargs="+", type=bytes,
1131+ help="Directories to compare.")
1132+argument_parser.add_argument(
1133+ "--ignore", action="append", type=bytes, default=ignore,
1134+ help="Full-path patterns to ignore (default: %s)." % ", ".join(ignore))
1135+
1136+
1137+def walk_tarball(filename):
1138+ for name in tarfile.open(args.archive, "r").getnames():
1139+ parts = name.split(b"/")
1140+ if len(parts) > 1:
1141+ yield b"/".join(parts[1:])
1142+
1143+
1144+def walk_directory(directory):
1145+ yield directory
1146+ for root, dirnames, filenames in os.walk(directory):
1147+ for dirname in dirnames:
1148+ yield join(root, dirname)
1149+ for filename in filenames:
1150+ yield join(root, filename)
1151+
1152+
1153+def filter_matching_paths(paths, ignore):
1154+ for path in paths:
1155+ for pattern in ignore:
1156+ if fnmatchcase(path, pattern):
1157+ break
1158+ else:
1159+ yield path
1160+
1161+
1162+if __name__ == "__main__":
1163+ args = argument_parser.parse_args()
1164+ names_from_dist = walk_tarball(args.archive)
1165+ names_from_dist = filter_matching_paths(names_from_dist, args.ignore)
1166+ names_from_dist = set(names_from_dist)
1167+ names_from_fs = imap(walk_directory, args.directories)
1168+ names_from_fs = chain.from_iterable(names_from_fs)
1169+ names_from_fs = filter_matching_paths(names_from_fs, args.ignore)
1170+ names_from_fs = set(names_from_fs)
1171+ for name in sorted(names_from_dist - names_from_fs):
1172+ print("+", name)
1173+ for name in sorted(names_from_fs - names_from_dist):
1174+ print("-", name)
1175
1176=== added file 'pkg/common/tox.ini'
1177--- pkg/common/tox.ini 1970-01-01 00:00:00 +0000
1178+++ pkg/common/tox.ini 2014-07-28 15:42:36 +0000
1179@@ -0,0 +1,11 @@
1180+[tox]
1181+minversion = 1.6
1182+# envlist = py27, py33
1183+envlist = py27
1184+
1185+[testenv]
1186+commands = {envpython} setup.py test
1187+install_command = pip install --find-links ../dist {opts} {packages}
1188+sitepackages = True
1189+usedevelop = True
1190+deps =
1191
1192=== added directory 'pkg/maas-apiclient'
1193=== added file 'pkg/maas-apiclient/Makefile'
1194--- pkg/maas-apiclient/Makefile 1970-01-01 00:00:00 +0000
1195+++ pkg/maas-apiclient/Makefile 2014-07-28 15:42:36 +0000
1196@@ -0,0 +1,9 @@
1197+localdeps := maas-testing
1198+
1199+# TODO: This duplicates what's in maas-develop.testing.entrypoints. The
1200+# latter is a better approach to ensuring that environment variables are
1201+# set for the test suite as a whole, but there's probably a better way
1202+# than either.
1203+test:: export DJANGO_SETTINGS_MODULE := apiclient.testing.settings
1204+
1205+include ../common/Makefile
1206
1207=== added file 'pkg/maas-apiclient/README.rst'
1208--- pkg/maas-apiclient/README.rst 1970-01-01 00:00:00 +0000
1209+++ pkg/maas-apiclient/README.rst 2014-07-28 15:42:36 +0000
1210@@ -0,0 +1,5 @@
1211+--------------
1212+maas-apiclient
1213+--------------
1214+
1215+API client library for MAAS.
1216
1217=== renamed directory 'src/apiclient' => 'pkg/maas-apiclient/apiclient'
1218=== added file 'pkg/maas-apiclient/apiclient/testing/settings.py'
1219--- pkg/maas-apiclient/apiclient/testing/settings.py 1970-01-01 00:00:00 +0000
1220+++ pkg/maas-apiclient/apiclient/testing/settings.py 2014-07-28 15:42:36 +0000
1221@@ -0,0 +1,18 @@
1222+# Copyright 2012-2013 Canonical Ltd. This software is licensed under the
1223+# GNU Affero General Public License version 3 (see the file LICENSE).
1224+
1225+"""Django settings for testing apiclient."""
1226+
1227+from __future__ import (
1228+ absolute_import,
1229+ print_function,
1230+ unicode_literals,
1231+ )
1232+
1233+str = None
1234+
1235+__metaclass__ = type
1236+
1237+
1238+SECRET_KEY = 'bogus secret key'
1239+DEBUG = True
1240
1241=== added symlink 'pkg/maas-apiclient/common'
1242=== target is u'../common'
1243=== added file 'pkg/maas-apiclient/configure.py'
1244--- pkg/maas-apiclient/configure.py 1970-01-01 00:00:00 +0000
1245+++ pkg/maas-apiclient/configure.py 2014-07-28 15:42:36 +0000
1246@@ -0,0 +1,19 @@
1247+from common import (
1248+ __version__,
1249+ configure,
1250+ )
1251+
1252+
1253+configure(
1254+ name='maas-apiclient',
1255+ description="MAAS API client library.",
1256+ install_requires=[
1257+ "oauth >= 1.0.1",
1258+ ],
1259+ tests_require=[
1260+ "django >= 1.5.4",
1261+ "django-piston >= 0.2.3",
1262+ "maas-testing >= %s" % __version__,
1263+ "testtools >= 0.9.32",
1264+ ],
1265+)
1266
1267=== added file 'pkg/maas-apiclient/packages.txt'
1268--- pkg/maas-apiclient/packages.txt 1970-01-01 00:00:00 +0000
1269+++ pkg/maas-apiclient/packages.txt 2014-07-28 15:42:36 +0000
1270@@ -0,0 +1,4 @@
1271+python-django
1272+python-django-piston
1273+python-oauth
1274+python-testtools
1275
1276=== added file 'pkg/maas-apiclient/setup.py'
1277--- pkg/maas-apiclient/setup.py 1970-01-01 00:00:00 +0000
1278+++ pkg/maas-apiclient/setup.py 2014-07-28 15:42:36 +0000
1279@@ -0,0 +1,197 @@
1280+#!/usr/bin/env python
1281+# Copyright 2013 Canonical Ltd. This software is licensed under the
1282+# GNU Affero General Public License version 3 (see the file LICENSE).
1283+
1284+"""Distutils installer for MAAS."""
1285+
1286+# unicode_literals is *not* included here to *better* support setup
1287+# scripts that work on both Python 2 and 3. Both expect their default
1288+# string type, and are fussy about it.
1289+from __future__ import (
1290+ absolute_import,
1291+ print_function,
1292+ )
1293+
1294+__version__ = "1.4"
1295+__metaclass__ = type
1296+
1297+
1298+from codecs import open
1299+from contextlib import contextmanager
1300+from distutils import (
1301+ errors,
1302+ log,
1303+ )
1304+from inspect import getsourcefile
1305+from operator import methodcaller
1306+from os import environ
1307+
1308+import setuptools
1309+
1310+
1311+@contextmanager
1312+def envvar(name, value):
1313+ """Context manager for temporarily setting an environment variable."""
1314+ original = environ.get(name)
1315+ environ[name] = value
1316+ try:
1317+ yield
1318+ finally:
1319+ if original is None:
1320+ environ.pop(name, None)
1321+ else:
1322+ environ[name] = original
1323+
1324+
1325+class install_deps(setuptools.Command):
1326+ """Distutils/setuptools command to install package dependencies."""
1327+
1328+ user_options = [
1329+ ('list-from=', None,
1330+ "file from which to read packages to install"),
1331+ ]
1332+
1333+ def initialize_options(self):
1334+ self.list_from = "packages.txt"
1335+
1336+ def gen_package_ops(self, package_lines):
1337+ install = methodcaller("mark_install")
1338+ delete = methodcaller("mark_delete", purge=True)
1339+ for line in package_lines:
1340+ if len(line) == 0:
1341+ pass # Ignore blank lines.
1342+ elif line.startswith("#"):
1343+ pass # Ignore whole-line comments.
1344+ elif line.endswith("-"):
1345+ package_name = line.rstrip("-")
1346+ yield package_name, delete
1347+ else:
1348+ package_name = line.rstrip("+")
1349+ yield package_name, install
1350+
1351+ def finalize_options(self):
1352+ self.ensure_filename("list_from")
1353+ self.packages = set()
1354+ with open(self.list_from, "r", encoding="utf-8") as fd:
1355+ lines = (line.strip() for line in fd)
1356+ self.package_ops = dict(self.gen_package_ops(lines))
1357+ self.packages = set(self.package_ops)
1358+
1359+ def run(self):
1360+ self.calculate_changes()
1361+ if len(self.changes) > 0:
1362+ self.apply_changes()
1363+
1364+ def calculate_changes(self):
1365+ from apt import Cache
1366+ cache = Cache()
1367+ for package_name, op in self.package_ops.iteritems():
1368+ op(cache[package_name])
1369+ self.changes = cache.get_changes()
1370+
1371+ def get_packages_to_install(self):
1372+ return self.packages.intersection(
1373+ package.name for package in self.changes
1374+ if package.marked_install or package.marked_upgrade)
1375+
1376+ def get_packages_to_delete(self):
1377+ return self.packages.intersection(
1378+ package.name for package in self.changes
1379+ if package.marked_delete)
1380+
1381+ def apply_changes(self):
1382+ """Use ``apt`` to check for package installs.
1383+
1384+ Spawns ``apt-get`` if necessary.
1385+ """
1386+ to_install = {
1387+ "%s+" % package
1388+ for package in self.get_packages_to_install()
1389+ }
1390+ if len(to_install) == 0:
1391+ log.info("system dependencies are all in place")
1392+
1393+ to_delete = {
1394+ "%s-" % package
1395+ for package in self.get_packages_to_delete()
1396+ }
1397+ if len(to_delete) == 0:
1398+ log.info("no forbidden system dependencies are installed")
1399+
1400+ to_do = sorted(to_install | to_delete)
1401+ if len(to_do) > 0:
1402+ install = [
1403+ "sudo", "apt-get", "--assume-yes",
1404+ "--no-install-recommends", "--purge",
1405+ "install",
1406+ ]
1407+ with envvar("DEBIAN_FRONTEND", "noninteractive"):
1408+ self.spawn(install + to_do)
1409+
1410+
1411+def check_settings(settings):
1412+ """Check setup settings for obvious issues.
1413+
1414+ - ``data_files`` should not be specified; setuptools ignores it.
1415+
1416+ - ``include_package_data`` should not be specified; it has weird
1417+ behaviour in setuptools.
1418+ """
1419+ if "data_files" in settings:
1420+ raise errors.DistutilsOptionError(
1421+ "data_files is ignored by setuptools")
1422+ if "include_package_data" in settings:
1423+ raise errors.DistutilsOptionError(
1424+ "include_package_data does not work as you "
1425+ "might expect with setuptools")
1426+
1427+
1428+def setup(**kwargs):
1429+ """MAAS-specific setup function.
1430+
1431+ Determines sensible defaults for many parameters.
1432+ """
1433+ command_classes = {}
1434+
1435+ try:
1436+ import apt
1437+ except ImportError:
1438+ log.warn("apt not available (install 'python-apt'?)")
1439+ else:
1440+ command_classes["install_deps"] = install_deps
1441+ apt # Silence lint.
1442+
1443+ settings = {
1444+ "cmdclass": command_classes,
1445+ "packages": setuptools.find_packages(".", exclude={"common"}),
1446+ "version": __version__,
1447+ "maintainer": "Canonical",
1448+ "maintainer_email": "maas-devel@lists.launchpad.net",
1449+ "url": "https://launchpad.net/maas",
1450+ "license": "AGPLv3",
1451+ "test_loader": "maastesting.loader:MAASTestLoader",
1452+ "test_suite": ".",
1453+ "tests_require": {"maas-testing >= %s" % __version__},
1454+ }
1455+ settings.update(kwargs)
1456+ check_settings(settings)
1457+
1458+ return setuptools.setup(**settings)
1459+
1460+
1461+def configure(**settings):
1462+ """Create a new ``setup.py`` file in the currnet directory.
1463+
1464+ Uses the file in which this function is originally defined as a
1465+ template, adding on a call to ``setup`` with the given ``settings``.
1466+ """
1467+ check_settings(settings)
1468+ thisfile = getsourcefile(configure)
1469+ with open(thisfile, "r", encoding="utf-8") as fin:
1470+ template = fin.read()
1471+ with open("setup.py", "w", encoding="utf-8") as fout:
1472+ fout.write(template)
1473+ fout.write(b"\n\nsetup(**%r)\n" % settings)
1474+
1475+
1476+setup(**{'install_requires': ['oauth >= 1.0.1'], 'name': 'maas-apiclient', 'tests_require': ['django >= 1.5.4', 'django-piston >= 0.2.3', 'maas-testing >= 1.4', 'testtools >= 0.9.32'], 'description': 'MAAS API client library.'})
1477
1478=== added directory 'pkg/maas-client'
1479=== added file 'pkg/maas-client/Makefile'
1480--- pkg/maas-client/Makefile 1970-01-01 00:00:00 +0000
1481+++ pkg/maas-client/Makefile 2014-07-28 15:42:36 +0000
1482@@ -0,0 +1,3 @@
1483+localdeps := maas-apiclient maas-testing
1484+
1485+include ../common/Makefile
1486
1487=== added file 'pkg/maas-client/README.rst'
1488--- pkg/maas-client/README.rst 1970-01-01 00:00:00 +0000
1489+++ pkg/maas-client/README.rst 2014-07-28 15:42:36 +0000
1490@@ -0,0 +1,5 @@
1491+------------
1492+maas-testing
1493+------------
1494+
1495+Testing utilities for MAAS.
1496
1497=== added symlink 'pkg/maas-client/common'
1498=== target is u'../common'
1499=== added file 'pkg/maas-client/configure.py'
1500--- pkg/maas-client/configure.py 1970-01-01 00:00:00 +0000
1501+++ pkg/maas-client/configure.py 2014-07-28 15:42:36 +0000
1502@@ -0,0 +1,26 @@
1503+from common import (
1504+ __version__,
1505+ configure,
1506+ )
1507+
1508+
1509+configure(
1510+ name='maas-client',
1511+ description="MAAS command-line client.",
1512+ install_requires=[
1513+ "bzr >= 2.6.0",
1514+ "httplib2 >= 0.8",
1515+ "maas-apiclient >= %s" % __version__,
1516+ ],
1517+ tests_require=[
1518+ "maas-testing >= %s" % __version__,
1519+ "mock >= 1.0.1",
1520+ "testtools >= 0.9.32",
1521+ "twisted >= 13.0.0",
1522+ ],
1523+ entry_points={
1524+ "console_scripts": {
1525+ "maas = maascli:main",
1526+ },
1527+ }
1528+)
1529
1530=== renamed directory 'src/maascli' => 'pkg/maas-client/maascli'
1531=== modified file 'pkg/maas-client/maascli/tests/test_integration.py'
1532--- src/maascli/tests/test_integration.py 2014-02-12 04:50:36 +0000
1533+++ pkg/maas-client/maascli/tests/test_integration.py 2014-07-28 15:42:36 +0000
1534@@ -1,7 +1,7 @@
1535-# Copyright 2012, 2013 Canonical Ltd. This software is licensed under the
1536+# Copyright 2012-2014 Canonical Ltd. This software is licensed under the
1537 # GNU Affero General Public License version 3 (see the file LICENSE).
1538
1539-"""Integration-test the `maascli` command."""
1540+"""Integration-test the `maas` command."""
1541
1542 from __future__ import (
1543 absolute_import,
1544@@ -14,37 +14,38 @@
1545 __metaclass__ = type
1546 __all__ = []
1547
1548-import os.path
1549+from os import (
1550+ environ,
1551+ path,
1552+ )
1553 from subprocess import (
1554 CalledProcessError,
1555 check_output,
1556 STDOUT,
1557 )
1558+import sys
1559
1560-from maastesting import root
1561+import maascli
1562 from maastesting.testcase import MAASTestCase
1563
1564
1565-def locate_maascli():
1566- return os.path.join(root, 'bin', 'maas')
1567-
1568-
1569 class TestMAASCli(MAASTestCase):
1570
1571 def run_command(self, *args):
1572- check_output([locate_maascli()] + list(args), stderr=STDOUT)
1573+ command = [sys.executable, "-m", "maascli"]
1574+ command.extend(args)
1575+ check_output(command, stderr=STDOUT, env=dict(
1576+ environ, PYTHONPATH=path.pathsep.join(sys.path)))
1577
1578 def test_run_without_args_fails(self):
1579 self.assertRaises(CalledProcessError, self.run_command)
1580
1581 def test_run_without_args_shows_help_reminder(self):
1582- self.output_file = self.make_file('output')
1583- try:
1584- self.run_command()
1585- except CalledProcessError as e:
1586- pass
1587+ script = path.realpath(maascli.__file__)
1588+ e = self.assertRaises(CalledProcessError, self.run_command)
1589 self.assertIn(
1590- "Run %s --help for usage details." % locate_maascli(),
1591+ "Run %s --help for usage details." % path.join(
1592+ path.dirname(script), "__main__.py"),
1593 e.output)
1594
1595 def test_help_option_succeeds(self):
1596
1597=== added file 'pkg/maas-client/packages.txt'
1598--- pkg/maas-client/packages.txt 1970-01-01 00:00:00 +0000
1599+++ pkg/maas-client/packages.txt 2014-07-28 15:42:36 +0000
1600@@ -0,0 +1,7 @@
1601+python-bzrlib
1602+python-django
1603+python-django-piston
1604+python-httplib2
1605+python-mock
1606+python-testtools
1607+python-twisted
1608
1609=== added file 'pkg/maas-client/setup.py'
1610--- pkg/maas-client/setup.py 1970-01-01 00:00:00 +0000
1611+++ pkg/maas-client/setup.py 2014-07-28 15:42:36 +0000
1612@@ -0,0 +1,197 @@
1613+#!/usr/bin/env python
1614+# Copyright 2013 Canonical Ltd. This software is licensed under the
1615+# GNU Affero General Public License version 3 (see the file LICENSE).
1616+
1617+"""Distutils installer for MAAS."""
1618+
1619+# unicode_literals is *not* included here to *better* support setup
1620+# scripts that work on both Python 2 and 3. Both expect their default
1621+# string type, and are fussy about it.
1622+from __future__ import (
1623+ absolute_import,
1624+ print_function,
1625+ )
1626+
1627+__version__ = "1.4"
1628+__metaclass__ = type
1629+
1630+
1631+from codecs import open
1632+from contextlib import contextmanager
1633+from distutils import (
1634+ errors,
1635+ log,
1636+ )
1637+from inspect import getsourcefile
1638+from operator import methodcaller
1639+from os import environ
1640+
1641+import setuptools
1642+
1643+
1644+@contextmanager
1645+def envvar(name, value):
1646+ """Context manager for temporarily setting an environment variable."""
1647+ original = environ.get(name)
1648+ environ[name] = value
1649+ try:
1650+ yield
1651+ finally:
1652+ if original is None:
1653+ environ.pop(name, None)
1654+ else:
1655+ environ[name] = original
1656+
1657+
1658+class install_deps(setuptools.Command):
1659+ """Distutils/setuptools command to install package dependencies."""
1660+
1661+ user_options = [
1662+ ('list-from=', None,
1663+ "file from which to read packages to install"),
1664+ ]
1665+
1666+ def initialize_options(self):
1667+ self.list_from = "packages.txt"
1668+
1669+ def gen_package_ops(self, package_lines):
1670+ install = methodcaller("mark_install")
1671+ delete = methodcaller("mark_delete", purge=True)
1672+ for line in package_lines:
1673+ if len(line) == 0:
1674+ pass # Ignore blank lines.
1675+ elif line.startswith("#"):
1676+ pass # Ignore whole-line comments.
1677+ elif line.endswith("-"):
1678+ package_name = line.rstrip("-")
1679+ yield package_name, delete
1680+ else:
1681+ package_name = line.rstrip("+")
1682+ yield package_name, install
1683+
1684+ def finalize_options(self):
1685+ self.ensure_filename("list_from")
1686+ self.packages = set()
1687+ with open(self.list_from, "r", encoding="utf-8") as fd:
1688+ lines = (line.strip() for line in fd)
1689+ self.package_ops = dict(self.gen_package_ops(lines))
1690+ self.packages = set(self.package_ops)
1691+
1692+ def run(self):
1693+ self.calculate_changes()
1694+ if len(self.changes) > 0:
1695+ self.apply_changes()
1696+
1697+ def calculate_changes(self):
1698+ from apt import Cache
1699+ cache = Cache()
1700+ for package_name, op in self.package_ops.iteritems():
1701+ op(cache[package_name])
1702+ self.changes = cache.get_changes()
1703+
1704+ def get_packages_to_install(self):
1705+ return self.packages.intersection(
1706+ package.name for package in self.changes
1707+ if package.marked_install or package.marked_upgrade)
1708+
1709+ def get_packages_to_delete(self):
1710+ return self.packages.intersection(
1711+ package.name for package in self.changes
1712+ if package.marked_delete)
1713+
1714+ def apply_changes(self):
1715+ """Use ``apt`` to check for package installs.
1716+
1717+ Spawns ``apt-get`` if necessary.
1718+ """
1719+ to_install = {
1720+ "%s+" % package
1721+ for package in self.get_packages_to_install()
1722+ }
1723+ if len(to_install) == 0:
1724+ log.info("system dependencies are all in place")
1725+
1726+ to_delete = {
1727+ "%s-" % package
1728+ for package in self.get_packages_to_delete()
1729+ }
1730+ if len(to_delete) == 0:
1731+ log.info("no forbidden system dependencies are installed")
1732+
1733+ to_do = sorted(to_install | to_delete)
1734+ if len(to_do) > 0:
1735+ install = [
1736+ "sudo", "apt-get", "--assume-yes",
1737+ "--no-install-recommends", "--purge",
1738+ "install",
1739+ ]
1740+ with envvar("DEBIAN_FRONTEND", "noninteractive"):
1741+ self.spawn(install + to_do)
1742+
1743+
1744+def check_settings(settings):
1745+ """Check setup settings for obvious issues.
1746+
1747+ - ``data_files`` should not be specified; setuptools ignores it.
1748+
1749+ - ``include_package_data`` should not be specified; it has weird
1750+ behaviour in setuptools.
1751+ """
1752+ if "data_files" in settings:
1753+ raise errors.DistutilsOptionError(
1754+ "data_files is ignored by setuptools")
1755+ if "include_package_data" in settings:
1756+ raise errors.DistutilsOptionError(
1757+ "include_package_data does not work as you "
1758+ "might expect with setuptools")
1759+
1760+
1761+def setup(**kwargs):
1762+ """MAAS-specific setup function.
1763+
1764+ Determines sensible defaults for many parameters.
1765+ """
1766+ command_classes = {}
1767+
1768+ try:
1769+ import apt
1770+ except ImportError:
1771+ log.warn("apt not available (install 'python-apt'?)")
1772+ else:
1773+ command_classes["install_deps"] = install_deps
1774+ apt # Silence lint.
1775+
1776+ settings = {
1777+ "cmdclass": command_classes,
1778+ "packages": setuptools.find_packages(".", exclude={"common"}),
1779+ "version": __version__,
1780+ "maintainer": "Canonical",
1781+ "maintainer_email": "maas-devel@lists.launchpad.net",
1782+ "url": "https://launchpad.net/maas",
1783+ "license": "AGPLv3",
1784+ "test_loader": "maastesting.loader:MAASTestLoader",
1785+ "test_suite": ".",
1786+ "tests_require": {"maas-testing >= %s" % __version__},
1787+ }
1788+ settings.update(kwargs)
1789+ check_settings(settings)
1790+
1791+ return setuptools.setup(**settings)
1792+
1793+
1794+def configure(**settings):
1795+ """Create a new ``setup.py`` file in the currnet directory.
1796+
1797+ Uses the file in which this function is originally defined as a
1798+ template, adding on a call to ``setup`` with the given ``settings``.
1799+ """
1800+ check_settings(settings)
1801+ thisfile = getsourcefile(configure)
1802+ with open(thisfile, "r", encoding="utf-8") as fin:
1803+ template = fin.read()
1804+ with open("setup.py", "w", encoding="utf-8") as fout:
1805+ fout.write(template)
1806+ fout.write(b"\n\nsetup(**%r)\n" % settings)
1807+
1808+
1809+setup(**{'install_requires': ['bzr >= 2.6.0', 'httplib2 >= 0.8', 'maas-apiclient >= 1.4'], 'entry_points': {'console_scripts': set(['maas = maascli:main'])}, 'name': 'maas-client', 'tests_require': ['maas-testing >= 1.4', 'mock >= 1.0.1', 'testtools >= 0.9.32', 'twisted >= 13.0.0'], 'description': 'MAAS command-line client.'})
1810
1811=== added directory 'pkg/maas-cluster'
1812=== added file 'pkg/maas-cluster/MANIFEST.in'
1813--- pkg/maas-cluster/MANIFEST.in 1970-01-01 00:00:00 +0000
1814+++ pkg/maas-cluster/MANIFEST.in 2014-07-28 15:42:36 +0000
1815@@ -0,0 +1,4 @@
1816+graft etc
1817+graft provisioningserver/specs
1818+graft scripts
1819+graft twisted
1820
1821=== added file 'pkg/maas-cluster/Makefile'
1822--- pkg/maas-cluster/Makefile 1970-01-01 00:00:00 +0000
1823+++ pkg/maas-cluster/Makefile 2014-07-28 15:42:36 +0000
1824@@ -0,0 +1,12 @@
1825+localdeps := maas-apiclient maas-testing
1826+
1827+# TODO: This duplicates what's in maas-develop.testing.entrypoints. The
1828+# latter is a better approach to ensuring that environment variables are
1829+# set for the test suite as a whole, but there's probably a better way
1830+# than either.
1831+test:: export DJANGO_SETTINGS_MODULE := provisioningserver.testing.djangosettings
1832+test:: export CELERY_CONFIG_MODULE := provisioningserver.testing.celeryconfig
1833+test:: export MAAS_CONFIG_DIR := $(abspath etc/maas)
1834+test:: export PYTHONPATH := $(MAAS_CONFIG_DIR):$(PYTHONPATH)
1835+
1836+include ../common/Makefile
1837
1838=== added file 'pkg/maas-cluster/README.rst'
1839--- pkg/maas-cluster/README.rst 1970-01-01 00:00:00 +0000
1840+++ pkg/maas-cluster/README.rst 2014-07-28 15:42:36 +0000
1841@@ -0,0 +1,6 @@
1842+-----------------------
1843+maas-cluster
1844+-----------------------
1845+
1846+Provisioning Server for MAAS Cluster Controllers, incorportating a TFTP
1847+server.
1848
1849=== added symlink 'pkg/maas-cluster/common'
1850=== target is u'../common'
1851=== added file 'pkg/maas-cluster/configure.py'
1852--- pkg/maas-cluster/configure.py 1970-01-01 00:00:00 +0000
1853+++ pkg/maas-cluster/configure.py 2014-07-28 15:42:36 +0000
1854@@ -0,0 +1,51 @@
1855+from common import (
1856+ __version__,
1857+ configure,
1858+ )
1859+
1860+
1861+configure(
1862+ name='maas-cluster',
1863+ description="MAAS Provisioning Server (part of a Cluster Controller).",
1864+ install_requires=[
1865+ "celery >= 2.5.3",
1866+ "crochet >= 1.0.0",
1867+ "formencode >= 1.2.4",
1868+ # "hivex >= 1.3.9", # Needs distutils packaging.
1869+ "lxml >= 3.2.0",
1870+ "maas-apiclient >= %s" % __version__,
1871+ "netaddr >= 0.7.7",
1872+ "netifaces >= 0.8",
1873+ "oops >= 0.0.10",
1874+ "oops-datedir-repo >= 0.0.15",
1875+ "oops-twisted >= 0.0.6",
1876+ "paramiko >= 1.10.1",
1877+ "pexpect >= 3.1",
1878+ # "pkg_resources >= 0.6.37", # Implicit.
1879+ # "pymongo >= 2.6", # Or bson >= 2.6 ???
1880+ "python-seamicroclient >= 0.1",
1881+ # "python-tx-tftp >= 0.1", # Needs distutils packaging.
1882+ "PyYAML >= 3.1.0",
1883+ "simplejson >= 3.3.0",
1884+ # "simplestreams >= 0.1.0", # Needs distutils packaging.
1885+ "tempita >= 0.5.1",
1886+ "twisted >= 13.0.0",
1887+ "txamqp >= 0.6.1",
1888+ "zope.interface >= 4.0.5",
1889+ ],
1890+ tests_require=[
1891+ "fixtures >= 0.3.8",
1892+ "maas-testing >= %s" % __version__,
1893+ "mock >= 1.0b1",
1894+ "rabbitfixture >= 0.3.5",
1895+ "testtools >= 0.9.32",
1896+ ],
1897+ entry_points={
1898+ "console_scripts": {
1899+ "maas-cluster-twistd = maascluster.entrypoints:twistd",
1900+ "maas-cluster-worker = maascluster.entrypoints:celeryd",
1901+ "maas-probe-dhcp = maascluster.entrypoints:probe_dhcp",
1902+ "maas-provision = maascluster.entrypoints:provision",
1903+ },
1904+ },
1905+)
1906
1907=== added directory 'pkg/maas-cluster/etc'
1908=== added directory 'pkg/maas-cluster/etc/maas'
1909=== renamed file 'contrib/maas-cluster-http.conf' => 'pkg/maas-cluster/etc/maas/maas-cluster-http.conf'
1910=== renamed file 'etc/maas_cluster.conf' => 'pkg/maas-cluster/etc/maas/maas_cluster.conf'
1911=== renamed file 'contrib/maas_local_celeryconfig_cluster.py' => 'pkg/maas-cluster/etc/maas/maas_local_celeryconfig_cluster.py'
1912=== renamed file 'etc/maas/pserv.yaml' => 'pkg/maas-cluster/etc/maas/pserv.yaml'
1913=== added directory 'pkg/maas-cluster/etc/maas/templates'
1914=== renamed directory 'etc/maas/templates/dhcp' => 'pkg/maas-cluster/etc/maas/templates/dhcp'
1915=== renamed directory 'etc/maas/templates/dns' => 'pkg/maas-cluster/etc/maas/templates/dns'
1916=== renamed directory 'etc/maas/templates/power' => 'pkg/maas-cluster/etc/maas/templates/power'
1917=== renamed directory 'etc/maas/templates/pxe' => 'pkg/maas-cluster/etc/maas/templates/pxe'
1918=== renamed directory 'etc/maas/templates/uefi' => 'pkg/maas-cluster/etc/maas/templates/uefi'
1919=== renamed directory 'etc/maas/templates/windows' => 'pkg/maas-cluster/etc/maas/templates/windows'
1920=== added directory 'pkg/maas-cluster/maascluster'
1921=== added file 'pkg/maas-cluster/maascluster/__init__.py'
1922=== added file 'pkg/maas-cluster/maascluster/entrypoints.py'
1923--- pkg/maas-cluster/maascluster/entrypoints.py 1970-01-01 00:00:00 +0000
1924+++ pkg/maas-cluster/maascluster/entrypoints.py 2014-07-28 15:42:36 +0000
1925@@ -0,0 +1,61 @@
1926+# Copyright 2014 Canonical Ltd. This software is licensed under the
1927+# GNU Affero General Public License version 3 (see the file LICENSE).
1928+
1929+"""Entry-points for the MAAS Cluster."""
1930+
1931+from __future__ import (
1932+ absolute_import,
1933+ print_function,
1934+ unicode_literals,
1935+ )
1936+
1937+str = None
1938+
1939+__metaclass__ = type
1940+__all__ = [
1941+ "celeryd",
1942+ "probe_dhcp",
1943+ "provision",
1944+ "twistd",
1945+]
1946+
1947+from os import environ
1948+
1949+from pkg_resources import (
1950+ load_entry_point,
1951+ Requirement,
1952+ resource_filename,
1953+ )
1954+
1955+
1956+def set_environment():
1957+ environ.setdefault(
1958+ "CELERY_CONFIG_MODULE",
1959+ "maascluster.worker.config")
1960+ environ.setdefault(
1961+ "MAAS_CONFIG_DIR", resource_filename(
1962+ Requirement.parse("maas-cluster"), "etc/maas"))
1963+
1964+
1965+def celeryd():
1966+ set_environment()
1967+ main = load_entry_point("celery", "console_scripts", "celeryd")
1968+ return main()
1969+
1970+
1971+def probe_dhcp():
1972+ set_environment()
1973+ from provisioningserver.dhcp.probe import main
1974+ return main()
1975+
1976+
1977+def provision():
1978+ set_environment()
1979+ from provisioningserver.__main__ import main
1980+ return main()
1981+
1982+
1983+def twistd():
1984+ set_environment()
1985+ from twisted.scripts.twistd import run
1986+ return run()
1987
1988=== added directory 'pkg/maas-cluster/maascluster/worker'
1989=== added file 'pkg/maas-cluster/maascluster/worker/__init__.py'
1990=== renamed file 'etc/celeryconfig_cluster.py' => 'pkg/maas-cluster/maascluster/worker/config.py'
1991--- etc/celeryconfig_cluster.py 2014-02-25 13:38:27 +0000
1992+++ pkg/maas-cluster/maascluster/worker/config.py 2014-07-28 15:42:36 +0000
1993@@ -19,14 +19,14 @@
1994
1995 from datetime import timedelta
1996
1997-import celeryconfig_common
1998+import maascluster.worker.config_base
1999 from provisioningserver.utils import import_settings
2000
2001 # Cluster UUID. Will be overridden by the customized setting in the
2002 # local MAAS Celery config.
2003 CLUSTER_UUID = None
2004
2005-import_settings(celeryconfig_common)
2006+import_settings(maascluster.worker.config_base)
2007
2008 try:
2009 import maas_local_celeryconfig_cluster
2010
2011=== renamed file 'etc/celeryconfig_common.py' => 'pkg/maas-cluster/maascluster/worker/config_base.py'
2012=== added file 'pkg/maas-cluster/packages.txt'
2013--- pkg/maas-cluster/packages.txt 1970-01-01 00:00:00 +0000
2014+++ pkg/maas-cluster/packages.txt 2014-07-28 15:42:36 +0000
2015@@ -0,0 +1,36 @@
2016+distro-info
2017+dnsutils
2018+freeipmi-tools
2019+isc-dhcp-common
2020+isc-dhcp-server
2021+python-bson
2022+python-celery
2023+python-crochet
2024+python-fixtures
2025+python-formencode
2026+python-hivex
2027+python-librabbitmq-
2028+python-lxml
2029+python-mock
2030+python-netaddr
2031+python-netifaces
2032+python-oops
2033+python-oops-datedir-repo
2034+python-oops-twisted
2035+python-paramiko
2036+python-pexpect
2037+python-pkg-resources
2038+python-seamicroclient
2039+python-simplejson
2040+python-simplestreams
2041+python-tempita
2042+python-testtools
2043+python-twisted
2044+python-txamqp
2045+python-txtftp
2046+python-yaml
2047+python-zope.interface
2048+syslinux-common
2049+tgt
2050+ubuntu-cloudimage-keyring
2051+wget
2052
2053=== renamed directory 'src/provisioningserver' => 'pkg/maas-cluster/provisioningserver'
2054=== modified file 'pkg/maas-cluster/provisioningserver/dhcp/tests/test_writer.py'
2055--- src/provisioningserver/dhcp/tests/test_writer.py 2014-03-28 04:36:31 +0000
2056+++ pkg/maas-cluster/provisioningserver/dhcp/tests/test_writer.py 2014-07-28 15:42:36 +0000
2057@@ -17,15 +17,12 @@
2058 from argparse import ArgumentParser
2059 from io import BytesIO
2060 import os
2061-from subprocess import (
2062- PIPE,
2063- Popen,
2064- )
2065+from subprocess import STDOUT
2066 import sys
2067
2068-from maastesting import root
2069 from maastesting.testcase import MAASTestCase
2070 from provisioningserver.dhcp import writer
2071+from provisioningserver.utils import call_and_check
2072 from testtools.matchers import (
2073 ContainsAll,
2074 MatchesStructure,
2075@@ -50,12 +47,13 @@
2076 )
2077
2078 def test_script_executable(self):
2079- script = ["%s/bin/maas-provision" % root, "generate-dhcp-config"]
2080+ script = [
2081+ sys.executable, "-m", "provisioningserver",
2082+ "generate-dhcp-config",
2083+ ]
2084 script.extend(self.test_args)
2085- cmd = Popen(
2086- script, stdout=PIPE, env=dict(PYTHONPATH=":".join(sys.path)))
2087- output, err = cmd.communicate()
2088- self.assertEqual(0, cmd.returncode, err)
2089+ output = call_and_check(script, env=dict(
2090+ os.environ, PYTHONPATH=os.path.pathsep.join(sys.path)))
2091 contains_all_params = ContainsAll(
2092 ['subnet', 'subnet-mask', 'broadcast-ip',
2093 'omapi-key', 'dns-servers', 'ntp-server', 'domain-name',
2094
2095=== modified file 'pkg/maas-cluster/provisioningserver/testing/bindfixture.py'
2096--- src/provisioningserver/testing/bindfixture.py 2014-06-30 14:08:34 +0000
2097+++ pkg/maas-cluster/provisioningserver/testing/bindfixture.py 2014-07-28 15:42:36 +0000
2098@@ -298,7 +298,7 @@
2099 self.useFixture(self.runner)
2100
2101
2102-if __name__ == "__main__":
2103+def main():
2104 parser = argparse.ArgumentParser(description='Run a BIND server.')
2105 parser.add_argument(
2106 '--homedir',
2107@@ -338,3 +338,7 @@
2108 os.execlp(
2109 resources.named_file, resources.named_file, "-g", "-c",
2110 resources.conf_file)
2111+
2112+
2113+if __name__ == "__main__":
2114+ main()
2115
2116=== added file 'pkg/maas-cluster/provisioningserver/testing/celeryconfig.py'
2117--- pkg/maas-cluster/provisioningserver/testing/celeryconfig.py 1970-01-01 00:00:00 +0000
2118+++ pkg/maas-cluster/provisioningserver/testing/celeryconfig.py 2014-07-28 15:42:36 +0000
2119@@ -0,0 +1,49 @@
2120+# Copyright 2012 Canonical Ltd. This software is licensed under the
2121+# GNU Affero General Public License version 3 (see the file LICENSE).
2122+
2123+"""Celery demo settings for the maas project: cluster settings."""
2124+
2125+from __future__ import (
2126+ absolute_import,
2127+ print_function,
2128+ unicode_literals,
2129+)
2130+
2131+str = None
2132+
2133+__metaclass__ = type
2134+
2135+
2136+import os
2137+
2138+import maascluster.worker.config
2139+from maastesting import root
2140+from pkg_resources import (
2141+ Requirement,
2142+ resource_filename,
2143+ )
2144+from provisioningserver.utils import import_settings
2145+
2146+# Extend base settings.
2147+import_settings(maascluster.worker.config)
2148+
2149+DNS_CONFIG_DIR = resource_filename(
2150+ Requirement.parse("maas-cluster"), "run/named")
2151+
2152+DNS_RNDC_PORT = 9154
2153+
2154+# In configuring RNDC, do not include the default "controls" statement that,
2155+# on a production system, would allow the init scripts to control the DNS
2156+# daemon. It would try to listen on port 953, which causes conflicts. (The
2157+# similar "controls" statement for the benefit of MAAS itself, on port 954,
2158+# will still be there).
2159+DNS_DEFAULT_CONTROLS = False
2160+
2161+DHCP_CONFIG_FILE = os.path.join(root, 'run/dhcpd.conf')
2162+
2163+DHCP_LEASES_FILE = os.path.join(root, 'run/dhcpd.leases')
2164+
2165+CELERYD_LOG_FILE = os.path.join(root, 'logs/cluster-worker/current')
2166+
2167+CELERYBEAT_SCHEDULE_FILENAME = os.path.join(
2168+ root, 'run/celerybeat-cluster-schedule')
2169
2170=== added file 'pkg/maas-cluster/provisioningserver/testing/djangosettings.py'
2171--- pkg/maas-cluster/provisioningserver/testing/djangosettings.py 1970-01-01 00:00:00 +0000
2172+++ pkg/maas-cluster/provisioningserver/testing/djangosettings.py 2014-07-28 15:42:36 +0000
2173@@ -0,0 +1,18 @@
2174+# Copyright 2012-2013 Canonical Ltd. This software is licensed under the
2175+# GNU Affero General Public License version 3 (see the file LICENSE).
2176+
2177+"""Django settings for testing provisioningserver."""
2178+
2179+from __future__ import (
2180+ absolute_import,
2181+ print_function,
2182+ unicode_literals,
2183+ )
2184+
2185+str = None
2186+
2187+__metaclass__ = type
2188+
2189+
2190+SECRET_KEY = 'bogus secret key'
2191+DEBUG = True
2192
2193=== modified file 'pkg/maas-cluster/provisioningserver/tests/test_config.py'
2194--- src/provisioningserver/tests/test_config.py 2014-07-16 14:12:13 +0000
2195+++ pkg/maas-cluster/provisioningserver/tests/test_config.py 2014-07-28 15:42:36 +0000
2196@@ -28,6 +28,10 @@
2197 from maastesting import root
2198 from maastesting.factory import factory
2199 from maastesting.testcase import MAASTestCase
2200+from pkg_resources import (
2201+ Requirement,
2202+ resource_filename,
2203+ )
2204 from provisioningserver.config import (
2205 BootSources,
2206 Config,
2207@@ -379,7 +383,8 @@
2208
2209 def test_load_example(self):
2210 # The example configuration is designed for development.
2211- filename = os.path.join(root, "etc", "maas", "pserv.yaml")
2212+ filename = resource_filename(
2213+ Requirement.parse("maas-cluster"), "etc/maas/pserv.yaml")
2214 self.assertEqual(
2215 self.default_development_config,
2216 Config.load(filename))
2217
2218=== modified file 'pkg/maas-cluster/provisioningserver/utils/tests/test_utils.py'
2219--- src/provisioningserver/utils/tests/test_utils.py 2014-07-18 15:44:55 +0000
2220+++ pkg/maas-cluster/provisioningserver/utils/tests/test_utils.py 2014-07-28 15:42:36 +0000
2221@@ -47,10 +47,7 @@
2222 FakeLogger,
2223 )
2224 from lxml import etree
2225-from maastesting import (
2226- bindir,
2227- root,
2228- )
2229+from maastesting import bindir
2230 from maastesting.factory import factory
2231 from maastesting.fakemethod import FakeMethod
2232 from maastesting.matchers import (
2233@@ -62,6 +59,10 @@
2234 Mock,
2235 sentinel,
2236 )
2237+from pkg_resources import (
2238+ Requirement,
2239+ resource_filename,
2240+ )
2241 import provisioningserver
2242 from provisioningserver.testing.testcase import PservTestCase
2243 import provisioningserver.utils
2244@@ -134,7 +135,8 @@
2245
2246 def get_branch_dir(*path):
2247 """Locate a file or directory relative to this branch."""
2248- return os.path.abspath(os.path.join(root, *path))
2249+ return resource_filename(
2250+ Requirement.parse("maas-cluster"), "/".join(path))
2251
2252
2253 class TestLocateConfig(MAASTestCase):
2254
2255=== renamed directory 'scripts' => 'pkg/maas-cluster/scripts'
2256=== added file 'pkg/maas-cluster/setup.py'
2257--- pkg/maas-cluster/setup.py 1970-01-01 00:00:00 +0000
2258+++ pkg/maas-cluster/setup.py 2014-07-28 15:42:36 +0000
2259@@ -0,0 +1,197 @@
2260+#!/usr/bin/env python
2261+# Copyright 2013 Canonical Ltd. This software is licensed under the
2262+# GNU Affero General Public License version 3 (see the file LICENSE).
2263+
2264+"""Distutils installer for MAAS."""
2265+
2266+# unicode_literals is *not* included here to *better* support setup
2267+# scripts that work on both Python 2 and 3. Both expect their default
2268+# string type, and are fussy about it.
2269+from __future__ import (
2270+ absolute_import,
2271+ print_function,
2272+ )
2273+
2274+__version__ = "1.4"
2275+__metaclass__ = type
2276+
2277+
2278+from codecs import open
2279+from contextlib import contextmanager
2280+from distutils import (
2281+ errors,
2282+ log,
2283+ )
2284+from inspect import getsourcefile
2285+from operator import methodcaller
2286+from os import environ
2287+
2288+import setuptools
2289+
2290+
2291+@contextmanager
2292+def envvar(name, value):
2293+ """Context manager for temporarily setting an environment variable."""
2294+ original = environ.get(name)
2295+ environ[name] = value
2296+ try:
2297+ yield
2298+ finally:
2299+ if original is None:
2300+ environ.pop(name, None)
2301+ else:
2302+ environ[name] = original
2303+
2304+
2305+class install_deps(setuptools.Command):
2306+ """Distutils/setuptools command to install package dependencies."""
2307+
2308+ user_options = [
2309+ ('list-from=', None,
2310+ "file from which to read packages to install"),
2311+ ]
2312+
2313+ def initialize_options(self):
2314+ self.list_from = "packages.txt"
2315+
2316+ def gen_package_ops(self, package_lines):
2317+ install = methodcaller("mark_install")
2318+ delete = methodcaller("mark_delete", purge=True)
2319+ for line in package_lines:
2320+ if len(line) == 0:
2321+ pass # Ignore blank lines.
2322+ elif line.startswith("#"):
2323+ pass # Ignore whole-line comments.
2324+ elif line.endswith("-"):
2325+ package_name = line.rstrip("-")
2326+ yield package_name, delete
2327+ else:
2328+ package_name = line.rstrip("+")
2329+ yield package_name, install
2330+
2331+ def finalize_options(self):
2332+ self.ensure_filename("list_from")
2333+ self.packages = set()
2334+ with open(self.list_from, "r", encoding="utf-8") as fd:
2335+ lines = (line.strip() for line in fd)
2336+ self.package_ops = dict(self.gen_package_ops(lines))
2337+ self.packages = set(self.package_ops)
2338+
2339+ def run(self):
2340+ self.calculate_changes()
2341+ if len(self.changes) > 0:
2342+ self.apply_changes()
2343+
2344+ def calculate_changes(self):
2345+ from apt import Cache
2346+ cache = Cache()
2347+ for package_name, op in self.package_ops.iteritems():
2348+ op(cache[package_name])
2349+ self.changes = cache.get_changes()
2350+
2351+ def get_packages_to_install(self):
2352+ return self.packages.intersection(
2353+ package.name for package in self.changes
2354+ if package.marked_install or package.marked_upgrade)
2355+
2356+ def get_packages_to_delete(self):
2357+ return self.packages.intersection(
2358+ package.name for package in self.changes
2359+ if package.marked_delete)
2360+
2361+ def apply_changes(self):
2362+ """Use ``apt`` to check for package installs.
2363+
2364+ Spawns ``apt-get`` if necessary.
2365+ """
2366+ to_install = {
2367+ "%s+" % package
2368+ for package in self.get_packages_to_install()
2369+ }
2370+ if len(to_install) == 0:
2371+ log.info("system dependencies are all in place")
2372+
2373+ to_delete = {
2374+ "%s-" % package
2375+ for package in self.get_packages_to_delete()
2376+ }
2377+ if len(to_delete) == 0:
2378+ log.info("no forbidden system dependencies are installed")
2379+
2380+ to_do = sorted(to_install | to_delete)
2381+ if len(to_do) > 0:
2382+ install = [
2383+ "sudo", "apt-get", "--assume-yes",
2384+ "--no-install-recommends", "--purge",
2385+ "install",
2386+ ]
2387+ with envvar("DEBIAN_FRONTEND", "noninteractive"):
2388+ self.spawn(install + to_do)
2389+
2390+
2391+def check_settings(settings):
2392+ """Check setup settings for obvious issues.
2393+
2394+ - ``data_files`` should not be specified; setuptools ignores it.
2395+
2396+ - ``include_package_data`` should not be specified; it has weird
2397+ behaviour in setuptools.
2398+ """
2399+ if "data_files" in settings:
2400+ raise errors.DistutilsOptionError(
2401+ "data_files is ignored by setuptools")
2402+ if "include_package_data" in settings:
2403+ raise errors.DistutilsOptionError(
2404+ "include_package_data does not work as you "
2405+ "might expect with setuptools")
2406+
2407+
2408+def setup(**kwargs):
2409+ """MAAS-specific setup function.
2410+
2411+ Determines sensible defaults for many parameters.
2412+ """
2413+ command_classes = {}
2414+
2415+ try:
2416+ import apt
2417+ except ImportError:
2418+ log.warn("apt not available (install 'python-apt'?)")
2419+ else:
2420+ command_classes["install_deps"] = install_deps
2421+ apt # Silence lint.
2422+
2423+ settings = {
2424+ "cmdclass": command_classes,
2425+ "packages": setuptools.find_packages(".", exclude={"common"}),
2426+ "version": __version__,
2427+ "maintainer": "Canonical",
2428+ "maintainer_email": "maas-devel@lists.launchpad.net",
2429+ "url": "https://launchpad.net/maas",
2430+ "license": "AGPLv3",
2431+ "test_loader": "maastesting.loader:MAASTestLoader",
2432+ "test_suite": ".",
2433+ "tests_require": {"maas-testing >= %s" % __version__},
2434+ }
2435+ settings.update(kwargs)
2436+ check_settings(settings)
2437+
2438+ return setuptools.setup(**settings)
2439+
2440+
2441+def configure(**settings):
2442+ """Create a new ``setup.py`` file in the currnet directory.
2443+
2444+ Uses the file in which this function is originally defined as a
2445+ template, adding on a call to ``setup`` with the given ``settings``.
2446+ """
2447+ check_settings(settings)
2448+ thisfile = getsourcefile(configure)
2449+ with open(thisfile, "r", encoding="utf-8") as fin:
2450+ template = fin.read()
2451+ with open("setup.py", "w", encoding="utf-8") as fout:
2452+ fout.write(template)
2453+ fout.write(b"\n\nsetup(**%r)\n" % settings)
2454+
2455+
2456+setup(**{'install_requires': ['celery >= 2.5.3', 'crochet >= 1.0.0', 'formencode >= 1.2.4', 'lxml >= 3.2.0', 'maas-apiclient >= 1.4', 'netaddr >= 0.7.7', 'netifaces >= 0.8', 'oops >= 0.0.10', 'oops-datedir-repo >= 0.0.15', 'oops-twisted >= 0.0.6', 'paramiko >= 1.10.1', 'pexpect >= 3.1', 'python-seamicroclient >= 0.1', 'PyYAML >= 3.1.0', 'simplejson >= 3.3.0', 'tempita >= 0.5.1', 'twisted >= 13.0.0', 'txamqp >= 0.6.1', 'zope.interface >= 4.0.5'], 'entry_points': {'console_scripts': set(['maas-cluster-worker = maascluster.entrypoints:celeryd', 'maas-cluster-twistd = maascluster.entrypoints:twistd', 'maas-probe-dhcp = maascluster.entrypoints:probe_dhcp', 'maas-provision = maascluster.entrypoints:provision'])}, 'name': 'maas-cluster', 'tests_require': ['fixtures >= 0.3.8', 'maas-testing >= 1.4', 'mock >= 1.0b1', 'rabbitfixture >= 0.3.5', 'testtools >= 0.9.32'], 'description': 'MAAS Provisioning Server (part of a Cluster Controller).'})
2457
2458=== renamed directory 'twisted' => 'pkg/maas-cluster/twisted'
2459=== renamed file 'twisted/plugins/maasps.py' => 'pkg/maas-cluster/twisted/plugins/maas_cluster.py'
2460=== added directory 'pkg/maas-develop'
2461=== added file 'pkg/maas-develop/MANIFEST.in'
2462--- pkg/maas-develop/MANIFEST.in 1970-01-01 00:00:00 +0000
2463+++ pkg/maas-develop/MANIFEST.in 2014-07-28 15:42:36 +0000
2464@@ -0,0 +1,2 @@
2465+graft maasdevelop
2466+graft media
2467
2468=== added file 'pkg/maas-develop/Makefile'
2469--- pkg/maas-develop/Makefile 1970-01-01 00:00:00 +0000
2470+++ pkg/maas-develop/Makefile 2014-07-28 15:42:36 +0000
2471@@ -0,0 +1,6 @@
2472+localdeps := maas-apiclient maas-client maas-cluster maas-region maas-testing
2473+
2474+include ../common/Makefile
2475+
2476+clean::
2477+ $(RM) -r media/demo/* media/development
2478
2479=== added file 'pkg/maas-develop/README.rst'
2480--- pkg/maas-develop/README.rst 1970-01-01 00:00:00 +0000
2481+++ pkg/maas-develop/README.rst 2014-07-28 15:42:36 +0000
2482@@ -0,0 +1,5 @@
2483+------------
2484+maas-develop
2485+------------
2486+
2487+Development utilities for MAAS.
2488
2489=== added symlink 'pkg/maas-develop/common'
2490=== target is u'../common'
2491=== added file 'pkg/maas-develop/configure.py'
2492--- pkg/maas-develop/configure.py 1970-01-01 00:00:00 +0000
2493+++ pkg/maas-develop/configure.py 2014-07-28 15:42:36 +0000
2494@@ -0,0 +1,47 @@
2495+from common import (
2496+ __version__,
2497+ configure,
2498+ )
2499+
2500+
2501+configure(
2502+ name='maas-develop',
2503+ description="MAAS development support.",
2504+ install_requires=[
2505+ # Bring in all the other MAAS packages.
2506+ "maas-apiclient == %s" % __version__,
2507+ "maas-client == %s" % __version__,
2508+ "maas-cluster == %s" % __version__,
2509+ "maas-region == %s" % __version__,
2510+ "maas-testing == %s" % __version__,
2511+ # Other developement dependencies.
2512+ "flake8",
2513+ "ipython",
2514+ "sphinx == 1.2.2",
2515+ ],
2516+ entry_points={
2517+ "console_scripts": {
2518+ # Development tools.
2519+ "database = postgresfixture.main:main",
2520+ "flake8 = flake8.run:main",
2521+ "ipython = IPython.frontend.terminal.ipapp:launch_new_instance",
2522+ "sphinx = sphinx:main",
2523+ # Region entry points.
2524+ "maas = maasdevelop.region.entrypoints:manage",
2525+ "maas-dns-server = maasdevelop.region.entrypoints:dns_server",
2526+ "maas-region-twistd = maasdevelop.region.entrypoints:twistd",
2527+ "maas-region-worker = maasdevelop.region.entrypoints:celeryd",
2528+ # Cluster entry points.
2529+ "maas-cluster-twistd = maasdevelop.cluster.entrypoints:twistd",
2530+ "maas-cluster-worker = maasdevelop.cluster.entrypoints:celeryd",
2531+ "maas-probe-dhcp = maasdevelop.cluster.entrypoints:probe_dhcp",
2532+ "maas-provision = maasdevelop.cluster.entrypoints:provision",
2533+ # Testing scripts for all MAAS projects.
2534+ "test.apiclient = maasdevelop.testing.entrypoints:test_apiclient",
2535+ "test.client = maasdevelop.testing.entrypoints:test_client",
2536+ "test.cluster = maasdevelop.testing.entrypoints:test_cluster",
2537+ "test.region = maasdevelop.testing.entrypoints:test_region",
2538+ "test.testing = maasdevelop.testing.entrypoints:test_testing",
2539+ },
2540+ },
2541+)
2542
2543=== added directory 'pkg/maas-develop/maasdevelop'
2544=== added file 'pkg/maas-develop/maasdevelop/__init__.py'
2545=== added directory 'pkg/maas-develop/maasdevelop/cluster'
2546=== added file 'pkg/maas-develop/maasdevelop/cluster/__init__.py'
2547=== renamed file 'etc/democeleryconfig_cluster.py' => 'pkg/maas-develop/maasdevelop/cluster/celeryconfig_demo.py'
2548--- etc/democeleryconfig_cluster.py 2013-10-07 09:12:40 +0000
2549+++ pkg/maas-develop/maasdevelop/cluster/celeryconfig_demo.py 2014-07-28 15:42:36 +0000
2550@@ -16,20 +16,17 @@
2551
2552 import os
2553
2554-import celeryconfig_cluster
2555-import democeleryconfig_common
2556+import maascluster.worker.config
2557+import maasdevelop.common.celeryconfig_demo
2558+from maastesting import root
2559 from provisioningserver.utils import import_settings
2560
2561-# Silence lint, this will be defined by democeleryconfig_common.
2562-DEV_ROOT_DIRECTORY = None
2563-
2564 # Extend base settings.
2565-import_settings(celeryconfig_cluster)
2566-
2567-import_settings(democeleryconfig_common)
2568+import_settings(maascluster.worker.config)
2569+import_settings(maasdevelop.common.celeryconfig_demo)
2570
2571 CELERYD_LOG_FILE = os.path.join(
2572- DEV_ROOT_DIRECTORY, 'logs/cluster-worker/current')
2573+ root, 'logs/cluster-worker/current')
2574
2575 CELERYBEAT_SCHEDULE_FILENAME = os.path.join(
2576- DEV_ROOT_DIRECTORY, 'run/celerybeat-cluster-schedule')
2577+ root, 'run/celerybeat-cluster-schedule')
2578
2579=== added file 'pkg/maas-develop/maasdevelop/cluster/entrypoints.py'
2580--- pkg/maas-develop/maasdevelop/cluster/entrypoints.py 1970-01-01 00:00:00 +0000
2581+++ pkg/maas-develop/maasdevelop/cluster/entrypoints.py 2014-07-28 15:42:36 +0000
2582@@ -0,0 +1,61 @@
2583+# Copyright 2014 Canonical Ltd. This software is licensed under the
2584+# GNU Affero General Public License version 3 (see the file LICENSE).
2585+
2586+"""Entry-points for the MAAS Cluster in development."""
2587+
2588+from __future__ import (
2589+ absolute_import,
2590+ print_function,
2591+ unicode_literals,
2592+ )
2593+
2594+str = None
2595+
2596+__metaclass__ = type
2597+__all__ = [
2598+ "celeryd",
2599+ "probe_dhcp",
2600+ "provision",
2601+ "twistd",
2602+]
2603+
2604+from os import environ
2605+
2606+from pkg_resources import (
2607+ load_entry_point,
2608+ Requirement,
2609+ resource_filename,
2610+ )
2611+
2612+
2613+def set_environment():
2614+ environ.setdefault(
2615+ "CELERY_CONFIG_MODULE",
2616+ "maasdevelop.cluster.celeryconfig_demo")
2617+ environ.setdefault(
2618+ "MAAS_CONFIG_DIR", resource_filename(
2619+ Requirement.parse("maas-cluster"), "etc/maas"))
2620+
2621+
2622+def celeryd():
2623+ set_environment()
2624+ main = load_entry_point("celery", "console_scripts", "celeryd")
2625+ return main()
2626+
2627+
2628+def probe_dhcp():
2629+ set_environment()
2630+ from provisioningserver.dhcp.probe import main
2631+ return main()
2632+
2633+
2634+def provision():
2635+ set_environment()
2636+ from provisioningserver.__main__ import main
2637+ return main()
2638+
2639+
2640+def twistd():
2641+ set_environment()
2642+ from twisted.scripts.twistd import run
2643+ return run()
2644
2645=== renamed file 'etc/demo_maas_cluster.conf' => 'pkg/maas-develop/maasdevelop/cluster/maas_cluster.demo.conf'
2646=== added directory 'pkg/maas-develop/maasdevelop/common'
2647=== added file 'pkg/maas-develop/maasdevelop/common/__init__.py'
2648=== renamed file 'etc/democeleryconfig_common.py' => 'pkg/maas-develop/maasdevelop/common/celeryconfig_demo.py'
2649--- etc/democeleryconfig_common.py 2013-10-07 09:12:40 +0000
2650+++ pkg/maas-develop/maasdevelop/common/celeryconfig_demo.py 2014-07-28 15:42:36 +0000
2651@@ -15,13 +15,10 @@
2652
2653 import os
2654
2655-
2656-DEV_ROOT_DIRECTORY = os.path.join(
2657- os.path.dirname(__file__), os.pardir)
2658-
2659-
2660-DNS_CONFIG_DIR = os.path.join(
2661- DEV_ROOT_DIRECTORY, 'run/named/')
2662+from maastesting import root
2663+
2664+
2665+DNS_CONFIG_DIR = os.path.join(root, 'run/named')
2666
2667
2668 DNS_RNDC_PORT = 9154
2669@@ -35,9 +32,7 @@
2670 DNS_DEFAULT_CONTROLS = False
2671
2672
2673-DHCP_CONFIG_FILE = os.path.join(
2674- DEV_ROOT_DIRECTORY, 'run/dhcpd.conf')
2675-
2676-
2677-DHCP_LEASES_FILE = os.path.join(
2678- DEV_ROOT_DIRECTORY, 'run/dhcpd.leases')
2679+DHCP_CONFIG_FILE = os.path.join(root, 'run/dhcpd.conf')
2680+
2681+
2682+DHCP_LEASES_FILE = os.path.join(root, 'run/dhcpd.leases')
2683
2684=== added directory 'pkg/maas-develop/maasdevelop/region'
2685=== added file 'pkg/maas-develop/maasdevelop/region/__init__.py'
2686=== renamed file 'etc/democeleryconfig.py' => 'pkg/maas-develop/maasdevelop/region/celeryconfig_demo.py'
2687--- etc/democeleryconfig.py 2013-10-07 09:12:40 +0000
2688+++ pkg/maas-develop/maasdevelop/region/celeryconfig_demo.py 2014-07-28 15:42:36 +0000
2689@@ -16,17 +16,14 @@
2690
2691 import os
2692
2693-import celeryconfig
2694-import democeleryconfig_common
2695 from maas import import_settings
2696-
2697-# Silence lint, this will be defined by democeleryconfig_common.
2698-DEV_ROOT_DIRECTORY = None
2699+import maasdevelop.common.celeryconfig_demo
2700+import maasserver.worker.config
2701+from maastesting import root
2702
2703 # Extend base settings.
2704-import_settings(celeryconfig)
2705-
2706-import_settings(democeleryconfig_common)
2707+import_settings(maasserver.worker.config)
2708+import_settings(maasdevelop.common.celeryconfig_demo)
2709
2710 CELERYD_LOG_FILE = os.path.join(
2711- DEV_ROOT_DIRECTORY, 'logs/region-worker/current')
2712+ root, 'logs/region-worker/current')
2713
2714=== renamed file 'src/maas/demo.py' => 'pkg/maas-develop/maasdevelop/region/demo.py'
2715--- src/maas/demo.py 2014-02-14 12:12:28 +0000
2716+++ pkg/maas-develop/maasdevelop/region/demo.py 2014-07-28 15:42:36 +0000
2717@@ -16,20 +16,26 @@
2718 from os.path import abspath
2719
2720 from maas import (
2721- development,
2722 import_settings,
2723 settings,
2724 )
2725+from maasdevelop.region import development
2726+from pkg_resources import (
2727+ Requirement,
2728+ resource_filename,
2729+ )
2730
2731 # We expect the following settings to be overridden. They are mentioned here
2732 # to silence lint warnings.
2733+INSTALLED_APPS = None
2734 MIDDLEWARE_CLASSES = None
2735
2736 # Extend base and development settings.
2737 import_settings(settings)
2738 import_settings(development)
2739
2740-MEDIA_ROOT = abspath("media/demo")
2741+MEDIA_ROOT = resource_filename(
2742+ Requirement.parse("maas-develop"), "media/demo")
2743
2744 MIDDLEWARE_CLASSES += (
2745 'debug_toolbar.middleware.DebugToolbarMiddleware',
2746@@ -82,10 +88,6 @@
2747 },
2748 }
2749
2750-# Use the in-branch development version of maas_cluster.conf.
2751-LOCAL_CLUSTER_CONFIG = abspath("etc/demo_maas_cluster.conf")
2752-
2753-
2754 # For demo purposes, give nodes unauthenticated access to their metadata
2755 # even if we can't pass boot parameters. This is not safe; do not
2756 # enable it on a production MAAS.
2757
2758=== renamed file 'src/maas/development.py' => 'pkg/maas-develop/maasdevelop/region/development.py'
2759--- src/maas/development.py 2014-06-24 11:37:01 +0000
2760+++ pkg/maas-develop/maasdevelop/region/development.py 2014-07-28 15:42:36 +0000
2761@@ -14,8 +14,11 @@
2762 __metaclass__ = type
2763
2764 import logging
2765-import os
2766-from os.path import abspath
2767+from os.path import (
2768+ abspath,
2769+ dirname,
2770+ join,
2771+ )
2772
2773 from maas import (
2774 import_local_settings,
2775@@ -23,6 +26,10 @@
2776 settings,
2777 )
2778 from metadataserver.address import guess_server_address
2779+from pkg_resources import (
2780+ Requirement,
2781+ resource_filename,
2782+ )
2783 import provisioningserver.config
2784 from provisioningserver.utils import compose_URL_on_IP
2785 from psycopg2.extensions import ISOLATION_LEVEL_SERIALIZABLE
2786@@ -37,10 +44,6 @@
2787 # In development, django can be accessed directly on port 5240.
2788 DEFAULT_MAAS_URL = compose_URL_on_IP("http://:5240/", guess_server_address())
2789
2790-# Use our custom test runner, which makes sure that a local database
2791-# cluster is running in the branch.
2792-TEST_RUNNER = 'maastesting.djangoloader.MAASDjangoTestRunner'
2793-
2794 # Don't connect to the DNS server in tests, this will be enabled on a case per
2795 # case basis.
2796 DNS_CONNECT = False
2797@@ -78,13 +81,12 @@
2798
2799 # Absolute filesystem path to the directory that will hold user-uploaded files.
2800 # Example: "/home/media/media.lawrence.com/media/"
2801-MEDIA_ROOT = abspath("media/development")
2802+MEDIA_ROOT = resource_filename(
2803+ Requirement.parse("maas-develop"), "media/development")
2804
2805 INSTALLED_APPS += (
2806 'django.contrib.admin',
2807 'maastesting',
2808- 'debug_toolbar',
2809- 'django_nose',
2810 )
2811
2812 INTERNAL_IPS = ('127.0.0.1',)
2813@@ -98,24 +100,16 @@
2814 ALLOW_UNSAFE_METADATA_ACCESS = True
2815
2816 # Use in-branch preseed templates.
2817-PRESEED_TEMPLATE_LOCATIONS = (
2818- abspath("etc/preseeds"),
2819- abspath("contrib/preseeds_v2"),
2820- )
2821-
2822-# The root directory of the MAAS project for this dev instance.
2823-DEV_ROOT_DIRECTORY = os.path.join(
2824- os.path.dirname(__file__), os.pardir, os.pardir)
2825+PRESEED_TEMPLATE_LOCATIONS = resource_filename(
2826+ Requirement.parse("maas-region"), "etc/maas/preseeds")
2827
2828 # Override the default provisioning config filename.
2829-provisioningserver.config.Config.DEFAULT_FILENAME = abspath(
2830- "etc/maas/pserv.yaml")
2831-
2832-# Set up celery to use the demo settings.
2833-os.environ['CELERY_CONFIG_MODULE'] = 'democeleryconfig'
2834+provisioningserver.config.Config.DEFAULT_FILENAME = resource_filename(
2835+ Requirement.parse("maas-region"), "etc/maas/pserv.yaml")
2836
2837 # Use the in-branch development version of maas_cluster.conf.
2838-LOCAL_CLUSTER_CONFIG = abspath("etc/demo_maas_cluster.conf")
2839+LOCAL_CLUSTER_CONFIG = abspath(
2840+ join(dirname(__file__), "maas_cluster.demo.conf"))
2841
2842 PASSWORD_HASHERS = (
2843 'django.contrib.auth.hashers.MD5PasswordHasher',
2844
2845=== added file 'pkg/maas-develop/maasdevelop/region/entrypoints.py'
2846--- pkg/maas-develop/maasdevelop/region/entrypoints.py 1970-01-01 00:00:00 +0000
2847+++ pkg/maas-develop/maasdevelop/region/entrypoints.py 2014-07-28 15:42:36 +0000
2848@@ -0,0 +1,64 @@
2849+# Copyright 2014 Canonical Ltd. This software is licensed under the
2850+# GNU Affero General Public License version 3 (see the file LICENSE).
2851+
2852+"""Entry-points for the MAAS Region in development."""
2853+
2854+from __future__ import (
2855+ absolute_import,
2856+ print_function,
2857+ unicode_literals,
2858+ )
2859+
2860+str = None
2861+
2862+__metaclass__ = type
2863+__all__ = [
2864+ "celeryd",
2865+ "dns_server",
2866+ "manage",
2867+ "twistd",
2868+]
2869+
2870+from os import environ
2871+
2872+from pkg_resources import (
2873+ load_entry_point,
2874+ Requirement,
2875+ resource_filename,
2876+ )
2877+
2878+
2879+def set_environment():
2880+ environ.setdefault(
2881+ "CELERY_CONFIG_MODULE",
2882+ "maasdevelop.region.celeryconfig_demo")
2883+ environ.setdefault(
2884+ "DJANGO_SETTINGS_MODULE",
2885+ "maasdevelop.region.demo")
2886+ environ.setdefault(
2887+ "MAAS_CONFIG_DIR", resource_filename(
2888+ Requirement.parse("maas-region"), "etc/maas"))
2889+
2890+
2891+def celeryd():
2892+ set_environment()
2893+ main = load_entry_point("celery", "console_scripts", "celeryd")
2894+ return main()
2895+
2896+
2897+def dns_server():
2898+ set_environment()
2899+ from provisioningserver.testing.bindfixture import main
2900+ return main()
2901+
2902+
2903+def manage():
2904+ set_environment()
2905+ from django.core.management import execute_from_command_line
2906+ return execute_from_command_line()
2907+
2908+
2909+def twistd():
2910+ set_environment()
2911+ from twisted.scripts.twistd import run
2912+ return run()
2913
2914=== added file 'pkg/maas-develop/maasdevelop/region/maas_cluster.demo.conf'
2915--- pkg/maas-develop/maasdevelop/region/maas_cluster.demo.conf 1970-01-01 00:00:00 +0000
2916+++ pkg/maas-develop/maasdevelop/region/maas_cluster.demo.conf 2014-07-28 15:42:36 +0000
2917@@ -0,0 +1,8 @@
2918+# This is the version of maas_cluster.conf that's used when running from a
2919+# branch. The region controller will serve HTTP on a different port from a
2920+# packaged MAAS, and the master cluster controller (running on the same
2921+# development machine) has a fixed UUID.
2922+# It is also carefully crafted so it works as both a bash script and a
2923+# Python script.
2924+MAAS_URL="http://0.0.0.0:5240/"
2925+CLUSTER_UUID="adfd3977-f251-4f2c-8d61-745dbd690bf2"
2926
2927=== added directory 'pkg/maas-develop/maasdevelop/testing'
2928=== added file 'pkg/maas-develop/maasdevelop/testing/__init__.py'
2929=== added file 'pkg/maas-develop/maasdevelop/testing/entrypoints.py'
2930--- pkg/maas-develop/maasdevelop/testing/entrypoints.py 1970-01-01 00:00:00 +0000
2931+++ pkg/maas-develop/maasdevelop/testing/entrypoints.py 2014-07-28 15:42:36 +0000
2932@@ -0,0 +1,82 @@
2933+# Copyright 2014 Canonical Ltd. This software is licensed under the
2934+# GNU Affero General Public License version 3 (see the file LICENSE).
2935+
2936+"""Entry-points for testing all of MAAS."""
2937+
2938+from __future__ import (
2939+ absolute_import,
2940+ print_function,
2941+ unicode_literals,
2942+ )
2943+
2944+str = None
2945+
2946+__metaclass__ = type
2947+__all__ = [
2948+ "test_apiclient",
2949+ "test_client",
2950+ "test_cluster",
2951+ "test_region",
2952+ "test_testing",
2953+]
2954+
2955+from os import (
2956+ chdir,
2957+ environ,
2958+ execv,
2959+ )
2960+import subprocess
2961+import sys
2962+
2963+from pkg_resources import (
2964+ Requirement,
2965+ resource_filename,
2966+ )
2967+
2968+
2969+def test(name):
2970+ chdir(resource_filename(Requirement.parse(name), None))
2971+ cmd = ["bin/python", "setup.py", "test"] + sys.argv[1:]
2972+ subprocess.check_call(("make", "--quiet"))
2973+ execv("bin/python", cmd)
2974+
2975+
2976+def test_apiclient():
2977+ environ.setdefault(
2978+ "DJANGO_SETTINGS_MODULE",
2979+ "apiclient.testing.settings")
2980+ test("maas-apiclient")
2981+
2982+
2983+def test_client():
2984+ test("maas-client")
2985+
2986+
2987+def test_cluster():
2988+ environ.setdefault(
2989+ "CELERY_CONFIG_MODULE",
2990+ "provisioningserver.testing.celeryconfig")
2991+ environ.setdefault(
2992+ "DJANGO_SETTINGS_MODULE",
2993+ "provisioningserver.testing.djangosettings")
2994+ environ.setdefault(
2995+ "MAAS_CONFIG_DIR", resource_filename(
2996+ Requirement.parse("maas-cluster"), "etc/maas"))
2997+ test("maas-cluster")
2998+
2999+
3000+def test_region():
3001+ environ.setdefault(
3002+ "CELERY_CONFIG_MODULE",
3003+ "maas.testing.celeryconfig")
3004+ environ.setdefault(
3005+ "DJANGO_SETTINGS_MODULE",
3006+ "maas.testing.djangosettings")
3007+ environ.setdefault(
3008+ "MAAS_CONFIG_DIR", resource_filename(
3009+ Requirement.parse("maas-region"), "etc/maas"))
3010+ test("maas-region")
3011+
3012+
3013+def test_testing():
3014+ test("maas-testing")
3015
3016=== renamed directory 'media' => 'pkg/maas-develop/media'
3017=== added file 'pkg/maas-develop/packages.txt'
3018--- pkg/maas-develop/packages.txt 1970-01-01 00:00:00 +0000
3019+++ pkg/maas-develop/packages.txt 2014-07-28 15:42:36 +0000
3020@@ -0,0 +1,17 @@
3021+avahi-utils
3022+build-essential
3023+bzr-builddeb
3024+curl
3025+debhelper
3026+dh-apport
3027+firefox
3028+ipython
3029+libjs-yui3-full
3030+make
3031+python-cssselect
3032+python-lxml
3033+python-pip
3034+python-pocket-lint
3035+python-sphinx
3036+python-virtualenv
3037+xvfb
3038
3039=== added file 'pkg/maas-develop/setup.py'
3040--- pkg/maas-develop/setup.py 1970-01-01 00:00:00 +0000
3041+++ pkg/maas-develop/setup.py 2014-07-28 15:42:36 +0000
3042@@ -0,0 +1,197 @@
3043+#!/usr/bin/env python
3044+# Copyright 2013 Canonical Ltd. This software is licensed under the
3045+# GNU Affero General Public License version 3 (see the file LICENSE).
3046+
3047+"""Distutils installer for MAAS."""
3048+
3049+# unicode_literals is *not* included here to *better* support setup
3050+# scripts that work on both Python 2 and 3. Both expect their default
3051+# string type, and are fussy about it.
3052+from __future__ import (
3053+ absolute_import,
3054+ print_function,
3055+ )
3056+
3057+__version__ = "1.4"
3058+__metaclass__ = type
3059+
3060+
3061+from codecs import open
3062+from contextlib import contextmanager
3063+from distutils import (
3064+ errors,
3065+ log,
3066+ )
3067+from inspect import getsourcefile
3068+from operator import methodcaller
3069+from os import environ
3070+
3071+import setuptools
3072+
3073+
3074+@contextmanager
3075+def envvar(name, value):
3076+ """Context manager for temporarily setting an environment variable."""
3077+ original = environ.get(name)
3078+ environ[name] = value
3079+ try:
3080+ yield
3081+ finally:
3082+ if original is None:
3083+ environ.pop(name, None)
3084+ else:
3085+ environ[name] = original
3086+
3087+
3088+class install_deps(setuptools.Command):
3089+ """Distutils/setuptools command to install package dependencies."""
3090+
3091+ user_options = [
3092+ ('list-from=', None,
3093+ "file from which to read packages to install"),
3094+ ]
3095+
3096+ def initialize_options(self):
3097+ self.list_from = "packages.txt"
3098+
3099+ def gen_package_ops(self, package_lines):
3100+ install = methodcaller("mark_install")
3101+ delete = methodcaller("mark_delete", purge=True)
3102+ for line in package_lines:
3103+ if len(line) == 0:
3104+ pass # Ignore blank lines.
3105+ elif line.startswith("#"):
3106+ pass # Ignore whole-line comments.
3107+ elif line.endswith("-"):
3108+ package_name = line.rstrip("-")
3109+ yield package_name, delete
3110+ else:
3111+ package_name = line.rstrip("+")
3112+ yield package_name, install
3113+
3114+ def finalize_options(self):
3115+ self.ensure_filename("list_from")
3116+ self.packages = set()
3117+ with open(self.list_from, "r", encoding="utf-8") as fd:
3118+ lines = (line.strip() for line in fd)
3119+ self.package_ops = dict(self.gen_package_ops(lines))
3120+ self.packages = set(self.package_ops)
3121+
3122+ def run(self):
3123+ self.calculate_changes()
3124+ if len(self.changes) > 0:
3125+ self.apply_changes()
3126+
3127+ def calculate_changes(self):
3128+ from apt import Cache
3129+ cache = Cache()
3130+ for package_name, op in self.package_ops.iteritems():
3131+ op(cache[package_name])
3132+ self.changes = cache.get_changes()
3133+
3134+ def get_packages_to_install(self):
3135+ return self.packages.intersection(
3136+ package.name for package in self.changes
3137+ if package.marked_install or package.marked_upgrade)
3138+
3139+ def get_packages_to_delete(self):
3140+ return self.packages.intersection(
3141+ package.name for package in self.changes
3142+ if package.marked_delete)
3143+
3144+ def apply_changes(self):
3145+ """Use ``apt`` to check for package installs.
3146+
3147+ Spawns ``apt-get`` if necessary.
3148+ """
3149+ to_install = {
3150+ "%s+" % package
3151+ for package in self.get_packages_to_install()
3152+ }
3153+ if len(to_install) == 0:
3154+ log.info("system dependencies are all in place")
3155+
3156+ to_delete = {
3157+ "%s-" % package
3158+ for package in self.get_packages_to_delete()
3159+ }
3160+ if len(to_delete) == 0:
3161+ log.info("no forbidden system dependencies are installed")
3162+
3163+ to_do = sorted(to_install | to_delete)
3164+ if len(to_do) > 0:
3165+ install = [
3166+ "sudo", "apt-get", "--assume-yes",
3167+ "--no-install-recommends", "--purge",
3168+ "install",
3169+ ]
3170+ with envvar("DEBIAN_FRONTEND", "noninteractive"):
3171+ self.spawn(install + to_do)
3172+
3173+
3174+def check_settings(settings):
3175+ """Check setup settings for obvious issues.
3176+
3177+ - ``data_files`` should not be specified; setuptools ignores it.
3178+
3179+ - ``include_package_data`` should not be specified; it has weird
3180+ behaviour in setuptools.
3181+ """
3182+ if "data_files" in settings:
3183+ raise errors.DistutilsOptionError(
3184+ "data_files is ignored by setuptools")
3185+ if "include_package_data" in settings:
3186+ raise errors.DistutilsOptionError(
3187+ "include_package_data does not work as you "
3188+ "might expect with setuptools")
3189+
3190+
3191+def setup(**kwargs):
3192+ """MAAS-specific setup function.
3193+
3194+ Determines sensible defaults for many parameters.
3195+ """
3196+ command_classes = {}
3197+
3198+ try:
3199+ import apt
3200+ except ImportError:
3201+ log.warn("apt not available (install 'python-apt'?)")
3202+ else:
3203+ command_classes["install_deps"] = install_deps
3204+ apt # Silence lint.
3205+
3206+ settings = {
3207+ "cmdclass": command_classes,
3208+ "packages": setuptools.find_packages(".", exclude={"common"}),
3209+ "version": __version__,
3210+ "maintainer": "Canonical",
3211+ "maintainer_email": "maas-devel@lists.launchpad.net",
3212+ "url": "https://launchpad.net/maas",
3213+ "license": "AGPLv3",
3214+ "test_loader": "maastesting.loader:MAASTestLoader",
3215+ "test_suite": ".",
3216+ "tests_require": {"maas-testing >= %s" % __version__},
3217+ }
3218+ settings.update(kwargs)
3219+ check_settings(settings)
3220+
3221+ return setuptools.setup(**settings)
3222+
3223+
3224+def configure(**settings):
3225+ """Create a new ``setup.py`` file in the currnet directory.
3226+
3227+ Uses the file in which this function is originally defined as a
3228+ template, adding on a call to ``setup`` with the given ``settings``.
3229+ """
3230+ check_settings(settings)
3231+ thisfile = getsourcefile(configure)
3232+ with open(thisfile, "r", encoding="utf-8") as fin:
3233+ template = fin.read()
3234+ with open("setup.py", "w", encoding="utf-8") as fout:
3235+ fout.write(template)
3236+ fout.write(b"\n\nsetup(**%r)\n" % settings)
3237+
3238+
3239+setup(**{'install_requires': ['maas-apiclient == 1.4', 'maas-client == 1.4', 'maas-cluster == 1.4', 'maas-region == 1.4', 'maas-testing == 1.4', 'flake8', 'ipython', 'sphinx == 1.2.2'], 'entry_points': {'console_scripts': set(['sphinx = sphinx:main', 'maas-provision = maasdevelop.cluster.entrypoints:provision', 'test.apiclient = maasdevelop.testing.entrypoints:test_apiclient', 'database = postgresfixture.main:main', 'test.cluster = maasdevelop.testing.entrypoints:test_cluster', 'maas-cluster-twistd = maasdevelop.cluster.entrypoints:twistd', 'ipython = IPython.frontend.terminal.ipapp:launch_new_instance', 'flake8 = flake8.run:main', 'maas-region-twistd = maasdevelop.region.entrypoints:twistd', 'maas-dns-server = maasdevelop.region.entrypoints:dns_server', 'maas-probe-dhcp = maasdevelop.cluster.entrypoints:probe_dhcp', 'test.testing = maasdevelop.testing.entrypoints:test_testing', 'test.region = maasdevelop.testing.entrypoints:test_region', 'maas-region-worker = maasdevelop.region.entrypoints:celeryd', 'maas-cluster-worker = maasdevelop.cluster.entrypoints:celeryd', 'test.client = maasdevelop.testing.entrypoints:test_client', 'maas = maasdevelop.region.entrypoints:manage'])}, 'name': 'maas-develop', 'description': 'MAAS development support.'})
3240
3241=== added directory 'pkg/maas-region'
3242=== added file 'pkg/maas-region/MANIFEST.in'
3243--- pkg/maas-region/MANIFEST.in 1970-01-01 00:00:00 +0000
3244+++ pkg/maas-region/MANIFEST.in 2014-07-28 15:42:36 +0000
3245@@ -0,0 +1,6 @@
3246+graft etc
3247+graft media
3248+graft */fixtures
3249+graft maasserver/static
3250+graft maasserver/templates
3251+graft maasserver/tests/data
3252
3253=== added file 'pkg/maas-region/Makefile'
3254--- pkg/maas-region/Makefile 1970-01-01 00:00:00 +0000
3255+++ pkg/maas-region/Makefile 2014-07-28 15:42:36 +0000
3256@@ -0,0 +1,38 @@
3257+localdeps := maas-apiclient maas-testing maas-cluster
3258+
3259+# TODO: This duplicates what's in maas-develop.testing.entrypoints. The
3260+# latter is a better approach to ensuring that environment variables are
3261+# set for the test suite as a whole, but there's probably a better way
3262+# than either.
3263+test:: export CELERY_CONFIG_MODULE := maas.testing.celeryconfig
3264+test:: export DJANGO_SETTINGS_MODULE := maas.testing.djangosettings
3265+test:: export MAAS_CONFIG_DIR := $(abspath etc/maas)
3266+test:: export PYTHONPATH := $(MAAS_CONFIG_DIR):$(PYTHONPATH)
3267+
3268+# Python enum modules.
3269+py_enums := $(wildcard */enum.py)
3270+# JavaScript enum module (not modules).
3271+js_enums := maasserver/static/js/enums.js
3272+
3273+# For things that care, postgresfixture for example, we always want to
3274+# use the "maas" databases.
3275+export PGDATABASE := maas
3276+
3277+# JavaScript enums must be built before distribution archive is created.
3278+dist:: $(js_enums)
3279+
3280+include ../common/Makefile
3281+
3282+# JavaScript enums must be built too, after everything else.
3283+build:: $(js_enums)
3284+
3285+$(js_enums): bin/python maasserver/utils/jsenums.py $(py_enums)
3286+ bin/python -m maasserver/utils/jsenums $(py_enums) > $@
3287+
3288+enums: $(js_enums)
3289+
3290+clean::
3291+ $(RM) $(js_enums)
3292+ $(RM) -r media/development
3293+
3294+.PHONY: enums
3295
3296=== added file 'pkg/maas-region/README.rst'
3297--- pkg/maas-region/README.rst 1970-01-01 00:00:00 +0000
3298+++ pkg/maas-region/README.rst 2014-07-28 15:42:36 +0000
3299@@ -0,0 +1,5 @@
3300+-----------
3301+maas-region
3302+-----------
3303+
3304+MAAS's Region Controller, incorporating the API server and UI.
3305
3306=== added symlink 'pkg/maas-region/common'
3307=== target is u'../common'
3308=== added file 'pkg/maas-region/configure.py'
3309--- pkg/maas-region/configure.py 1970-01-01 00:00:00 +0000
3310+++ pkg/maas-region/configure.py 2014-07-28 15:42:36 +0000
3311@@ -0,0 +1,70 @@
3312+from common import (
3313+ __version__,
3314+ configure,
3315+ )
3316+
3317+
3318+configure(
3319+ name='maas-region',
3320+ description="MAAS Region Controller.",
3321+ install_requires=[
3322+ "amqplib >= 1.0.2",
3323+ # "avahi >= 0.6.31", # Needs distutils packaging.
3324+ "celery >= 2.5.3",
3325+ "convoy >= 0.2.1",
3326+ "crochet >= 1.0.0",
3327+ # "curtin >= 0.1.0", # Needs distutils packaging.
3328+ # "dbus >= 1.2.0", # Needs distutils packaging.
3329+ "django >= 1.5.4",
3330+ "django-debug-toolbar >= 1.0.1",
3331+ "django-piston >= 0.2.3",
3332+ "djorm-ext-pgarray >= 0.8",
3333+ "docutils >= 0.11",
3334+ "formencode >= 1.2.4",
3335+ "iscpy >= 1.05",
3336+ "jsonschema >= 2.3.0",
3337+ "lockfile >= 0.8",
3338+ "lxml >= 3.2.0",
3339+ "maas-apiclient >= %s" % __version__,
3340+ "maas-cluster >= %s" % __version__,
3341+ "netaddr >= 0.7.7",
3342+ "oauth >= 1.0.1",
3343+ "oops >= 0.0.10",
3344+ "oops-datedir-repo >= 0.0.15",
3345+ "oops-twisted >= 0.0.6",
3346+ # "pkg_resources >= 0.6.37", # Implicit.
3347+ "psycopg2 >= 2.4.5",
3348+ # "pymongo >= 2.6", # Or bson >= 2.6 ???
3349+ "pyOpenSSL >= 0.13",
3350+ "PyYAML >= 3.1.0",
3351+ "simplejson >= 3.3.0",
3352+ "south >= 0.7.5",
3353+ "tempita >= 0.5.1",
3354+ "twisted >= 13.0.0",
3355+ "txlongpoll >= 0.3.1",
3356+ ],
3357+ tests_require=[
3358+ "fixtures >= 0.3.14",
3359+ "maas-testing >= %s" % __version__,
3360+ "mock >= 1.0.1",
3361+ "nose >= 1.1.2",
3362+ "postgresfixture >= 0.2.1",
3363+ "python-subunit >= 0.0.18",
3364+ "rabbitfixture >= 0.3.5",
3365+ "saucelabsfixture >= 0.1",
3366+ "selenium >= 2.39",
3367+ "sst >= 0.2.2",
3368+ "testresources >= 0.2.5",
3369+ "testscenarios >= 0.3",
3370+ "testtools >= 0.9.32",
3371+ ],
3372+ test_loader="maastesting.djangoloader:MAASDjangoTestLoader",
3373+ entry_points={
3374+ "console_scripts": {
3375+ "maas = maas.entrypoints:manage",
3376+ "maas-dns-server = maas.entrypoints:dns_server",
3377+ "maas-region-twistd = maas.entrypoints:twistd",
3378+ "maas-region-worker = maas.entrypoints:celeryd",
3379+ },
3380+ },
3381+)
3382
3383=== added directory 'pkg/maas-region/contrib'
3384=== renamed file 'contrib/maas-http.conf' => 'pkg/maas-region/contrib/maas-http.conf'
3385=== renamed file 'contrib/maas_local_celeryconfig.py' => 'pkg/maas-region/contrib/maas_local_celeryconfig.py'
3386=== renamed file 'contrib/maas_local_settings.py' => 'pkg/maas-region/contrib/maas_local_settings.py'
3387=== renamed file 'contrib/tgt.conf' => 'pkg/maas-region/contrib/tgt.conf'
3388=== renamed file 'contrib/wsgi.py' => 'pkg/maas-region/contrib/wsgi.py'
3389=== added directory 'pkg/maas-region/etc'
3390=== added directory 'pkg/maas-region/etc/maas'
3391=== renamed file 'etc/maas/drivers.yaml' => 'pkg/maas-region/etc/maas/drivers.yaml'
3392=== added file 'pkg/maas-region/etc/maas/maas_local_celeryconfig.py'
3393=== renamed directory 'contrib/preseeds_v2' => 'pkg/maas-region/etc/maas/preseeds'
3394=== added symlink 'pkg/maas-region/etc/maas/pserv.yaml'
3395=== target is u'../../../maas-cluster/etc/maas/pserv.yaml'
3396=== added directory 'pkg/maas-region/etc/maas/templates'
3397=== renamed directory 'etc/maas/templates/commissioning-user-data' => 'pkg/maas-region/etc/maas/templates/commissioning-user-data'
3398=== added symlink 'pkg/maas-region/etc/maas/templates/dhcp'
3399=== target is u'../../../../maas-cluster/etc/maas/templates/dhcp'
3400=== added symlink 'pkg/maas-region/etc/maas/templates/dns'
3401=== target is u'../../../../maas-cluster/etc/maas/templates/dns'
3402=== added symlink 'pkg/maas-region/etc/maas/templates/power'
3403=== target is u'../../../../maas-cluster/etc/maas/templates/power'
3404=== added symlink 'pkg/maas-region/etc/maas/templates/pxe'
3405=== target is u'../../../../maas-cluster/etc/maas/templates/pxe'
3406=== added symlink 'pkg/maas-region/etc/maas/templates/uefi'
3407=== target is u'../../../../maas-cluster/etc/maas/templates/uefi/'
3408=== renamed file 'etc/txlongpoll.yaml' => 'pkg/maas-region/etc/maas/txlongpoll.yaml'
3409=== renamed directory 'src/maas' => 'pkg/maas-region/maas'
3410=== added file 'pkg/maas-region/maas/entrypoints.py'
3411--- pkg/maas-region/maas/entrypoints.py 1970-01-01 00:00:00 +0000
3412+++ pkg/maas-region/maas/entrypoints.py 2014-07-28 15:42:36 +0000
3413@@ -0,0 +1,57 @@
3414+# Copyright 2014 Canonical Ltd. This software is licensed under the
3415+# GNU Affero General Public License version 3 (see the file LICENSE).
3416+
3417+"""Entry-points for the MAAS Region."""
3418+
3419+from __future__ import (
3420+ absolute_import,
3421+ print_function,
3422+ unicode_literals,
3423+ )
3424+
3425+str = None
3426+
3427+__metaclass__ = type
3428+__all__ = [
3429+ "celeryd",
3430+ "dns_server",
3431+ "manage",
3432+ "twistd",
3433+]
3434+
3435+from os import environ
3436+
3437+from pkg_resources import load_entry_point
3438+
3439+
3440+def set_environment():
3441+ environ.setdefault(
3442+ "CELERY_CONFIG_MODULE",
3443+ "maasserver.worker.config")
3444+ environ.setdefault(
3445+ "DJANGO_SETTINGS_MODULE",
3446+ "maas.settings")
3447+
3448+
3449+def celeryd():
3450+ set_environment()
3451+ main = load_entry_point("celery", "console_scripts", "celeryd")
3452+ return main()
3453+
3454+
3455+def dns_server():
3456+ set_environment()
3457+ from provisioningserver.testing.bindfixture import main
3458+ return main()
3459+
3460+
3461+def manage():
3462+ set_environment()
3463+ from django.core.management import execute_from_command_line
3464+ return execute_from_command_line()
3465+
3466+
3467+def twistd():
3468+ set_environment()
3469+ from twisted.scripts.twistd import run
3470+ return run()
3471
3472=== added directory 'pkg/maas-region/maas/testing'
3473=== added file 'pkg/maas-region/maas/testing/__init__.py'
3474=== added file 'pkg/maas-region/maas/testing/celeryconfig.py'
3475--- pkg/maas-region/maas/testing/celeryconfig.py 1970-01-01 00:00:00 +0000
3476+++ pkg/maas-region/maas/testing/celeryconfig.py 2014-07-28 15:42:36 +0000
3477@@ -0,0 +1,45 @@
3478+# Copyright 2014 Canonical Ltd. This software is licensed under the
3479+# GNU Affero General Public License version 3 (see the file LICENSE).
3480+
3481+"""Celery test settings for the MAAS project: region settings."""
3482+
3483+from __future__ import (
3484+ absolute_import,
3485+ print_function,
3486+ unicode_literals,
3487+)
3488+
3489+str = None
3490+
3491+__metaclass__ = type
3492+
3493+from maas import import_settings
3494+import maasserver.worker.config
3495+from pkg_resources import (
3496+ Requirement,
3497+ resource_filename,
3498+ )
3499+
3500+# Extend base settings.
3501+import_settings(maasserver.worker.config)
3502+
3503+DNS_CONFIG_DIR = resource_filename(
3504+ Requirement.parse("maas-region"), "run/named")
3505+
3506+DNS_RNDC_PORT = 9154
3507+
3508+# In configuring RNDC, do not include the default "controls" statement that,
3509+# on a production system, would allow the init scripts to control the DNS
3510+# daemon. It would try to listen on port 953, which causes conflicts. (The
3511+# similar "controls" statement for the benefit of MAAS itself, on port 954,
3512+# will still be there).
3513+DNS_DEFAULT_CONTROLS = False
3514+
3515+DHCP_CONFIG_FILE = resource_filename(
3516+ Requirement.parse("maas-region"), 'run/dhcpd.conf')
3517+
3518+DHCP_LEASES_FILE = resource_filename(
3519+ Requirement.parse("maas-region"), 'run/dhcpd.leases')
3520+
3521+CELERYD_LOG_FILE = resource_filename(
3522+ Requirement.parse("maas-region"), 'logs/region-worker/current')
3523
3524=== added file 'pkg/maas-region/maas/testing/djangosettings.py'
3525--- pkg/maas-region/maas/testing/djangosettings.py 1970-01-01 00:00:00 +0000
3526+++ pkg/maas-region/maas/testing/djangosettings.py 2014-07-28 15:42:36 +0000
3527@@ -0,0 +1,112 @@
3528+# Copyright 2012-2013 Canonical Ltd. This software is licensed under the
3529+# GNU Affero General Public License version 3 (see the file LICENSE).
3530+
3531+"""Django DEVELOPMENT settings for maas project."""
3532+
3533+from __future__ import (
3534+ absolute_import,
3535+ print_function,
3536+ unicode_literals,
3537+ )
3538+
3539+str = None
3540+
3541+__metaclass__ = type
3542+
3543+import logging
3544+import os
3545+from os.path import abspath
3546+
3547+from maas import (
3548+ import_local_settings,
3549+ import_settings,
3550+ settings,
3551+ )
3552+from metadataserver.address import guess_server_address
3553+from pkg_resources import (
3554+ Requirement,
3555+ resource_filename,
3556+ )
3557+import provisioningserver.config
3558+
3559+# We expect the following settings to be overridden. They are mentioned here
3560+# to silence lint warnings.
3561+INSTALLED_APPS = None
3562+
3563+# Extend base settings.
3564+import_settings(settings)
3565+
3566+# In development, django can be accessed directly on port 5240.
3567+DEFAULT_MAAS_URL = "http://%s:5240/" % guess_server_address()
3568+
3569+# Don't connect to the DNS server in tests, this will be enabled on a case per
3570+# case basis.
3571+DNS_CONNECT = False
3572+
3573+# Don't setup DHCP servers in tests, this will be enabled on a case per case
3574+# basis.
3575+DHCP_CONNECT = False
3576+
3577+# Invalid strings should be visible.
3578+TEMPLATE_STRING_IF_INVALID = '#### INVALID STRING ####'
3579+
3580+DEBUG = True
3581+TEMPLATE_DEBUG = DEBUG
3582+YUI_DEBUG = DEBUG
3583+STATIC_LOCAL_SERVE = True
3584+
3585+RABBITMQ_PUBLISH = False
3586+
3587+# Silent South during tests.
3588+logging.getLogger('south').setLevel(logging.WARNING)
3589+
3590+DATABASES = {
3591+ 'default': {
3592+ # 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' etc.
3593+ 'ENGINE': 'django.db.backends.postgresql_psycopg2',
3594+ 'NAME': 'maas',
3595+ # For PostgreSQL, a "hostname" starting with a slash indicates a
3596+ # Unix socket directory.
3597+ 'HOST': abspath('db'),
3598+ }
3599+}
3600+
3601+# Absolute filesystem path to the directory that will hold user-uploaded files.
3602+# Example: "/home/media/media.lawrence.com/media/"
3603+MEDIA_ROOT = resource_filename(
3604+ Requirement.parse("maas-region"), "media/testing")
3605+
3606+INSTALLED_APPS += (
3607+ 'django.contrib.admin',
3608+ 'maastesting',
3609+)
3610+
3611+INTERNAL_IPS = ('127.0.0.1',)
3612+
3613+DEBUG_TOOLBAR_CONFIG = {
3614+ 'INTERCEPT_REDIRECTS': False,
3615+ }
3616+
3617+# Make all nodes' metadata visible. This is not safe; do not enable it
3618+# on a production MAAS.
3619+ALLOW_UNSAFE_METADATA_ACCESS = True
3620+
3621+# Use in-branch preseed templates.
3622+PRESEED_TEMPLATE_LOCATIONS = (
3623+ resource_filename(
3624+ Requirement.parse("maas-region"), "etc/maas/preseeds"),
3625+)
3626+
3627+# Override the default provisioning config filename.
3628+provisioningserver.config.Config.DEFAULT_FILENAME = resource_filename(
3629+ Requirement.parse("maas-cluster"), "etc/maas/pserv.yaml")
3630+
3631+# Tests should patch in a value for this.
3632+LOCAL_CLUSTER_CONFIG = os.devnull
3633+
3634+PASSWORD_HASHERS = (
3635+ 'django.contrib.auth.hashers.MD5PasswordHasher',
3636+)
3637+
3638+# Allow the user to override settings in maas_local_settings.
3639+import_local_settings()
3640
3641=== renamed directory 'src/maasserver' => 'pkg/maas-region/maasserver'
3642=== modified file 'pkg/maas-region/maasserver/components.py'
3643--- src/maasserver/components.py 2013-10-07 09:12:40 +0000
3644+++ pkg/maas-region/maasserver/components.py 2014-07-28 15:42:36 +0000
3645@@ -20,7 +20,6 @@
3646 ]
3647
3648 from django.utils.safestring import mark_safe
3649-from maasserver.models import ComponentError
3650 from maasserver.utils.orm import get_one
3651
3652
3653@@ -29,6 +28,7 @@
3654
3655 :param component: An enum value of :class:`COMPONENT`.
3656 """
3657+ from maasserver.models import ComponentError # Avoid circular imports.
3658 ComponentError.objects.filter(component=component).delete()
3659
3660
3661@@ -38,12 +38,14 @@
3662 :param component: An enum value of :class:`COMPONENT`.
3663 :param error_message: Human-readable error text.
3664 """
3665+ from maasserver.models import ComponentError # Avoid circular imports.
3666 discard_persistent_error(component)
3667 ComponentError.objects.create(component=component, error=error_message)
3668
3669
3670 def get_persistent_error(component):
3671 """Return persistent error for `component`, or None."""
3672+ from maasserver.models import ComponentError # Avoid circular imports.
3673 err = get_one(ComponentError.objects.filter(component=component))
3674 if err is None:
3675 return None
3676@@ -53,5 +55,6 @@
3677
3678 def get_persistent_errors():
3679 """Return list of current persistent error messages."""
3680+ from maasserver.models import ComponentError # Avoid circular imports.
3681 return sorted(
3682 mark_safe(err.error) for err in ComponentError.objects.all())
3683
3684=== modified file 'pkg/maas-region/maasserver/testing/testcase.py'
3685--- src/maasserver/testing/testcase.py 2014-07-18 22:28:08 +0000
3686+++ pkg/maas-region/maasserver/testing/testcase.py 2014-07-28 15:42:36 +0000
3687@@ -45,6 +45,7 @@
3688 from mock import Mock
3689 import provisioningserver
3690 from provisioningserver.testing.worker_cache import WorkerCacheFixture
3691+from testresources import FixtureResource
3692
3693
3694 MIME_BOUNDARY = 'BoUnDaRyStRiNg'
3695@@ -57,11 +58,11 @@
3696 :ivar client: Django http test client.
3697 """
3698
3699- @classmethod
3700- def setUpClass(cls):
3701+ def setUp(self):
3702+ # register_mac_type() only needs to be called once, though
3703+ # calling it repeatedly is harmless apart from the time and
3704+ # resources it takes.
3705 register_mac_type(connection.cursor())
3706-
3707- def setUp(self):
3708 super(MAASServerTestCase, self).setUp()
3709 self.useFixture(WorkerCacheFixture())
3710 self.useFixture(TagCachedKnowledgeFixture())
3711@@ -139,6 +140,25 @@
3712 wsgiref.handlers.BaseHandler.log_exception = self.old_log_exception
3713
3714
3715+class SeleniumFixture(Fixture):
3716+ """Fixture that brings up Selenium with an off-screen display.
3717+
3718+ Also silences some logs with `LogSilencerFixture`.
3719+ """
3720+
3721+ def setUp(self):
3722+ super(SeleniumFixture, self).setUp()
3723+ self.display = DisplayFixture()
3724+ self.useFixture(self.display)
3725+ self.silencer = LogSilencerFixture()
3726+ self.useFixture(self.silencer)
3727+ self.driver = WebDriver()
3728+ self.addCleanup(self.driver.quit)
3729+
3730+ def reset(self):
3731+ pass # No reset necessary.
3732+
3733+
3734 class SeleniumTestCase(MAASTestCase, LiveServerTestCase):
3735 """Selenium-enabled test case.
3736
3737@@ -147,42 +167,24 @@
3738 in as either using `log_in`.
3739 """
3740
3741- # Load the selenium test fixture.
3742- fixtures = ['selenium_tests_fixture.yaml']
3743-
3744- @classmethod
3745- def setUpClass(cls):
3746- if not django_supports_selenium:
3747- return
3748- cls.display = DisplayFixture()
3749- cls.display.__enter__()
3750-
3751- cls.silencer = LogSilencerFixture()
3752- cls.silencer.__enter__()
3753-
3754- cls.selenium = WebDriver()
3755- super(SeleniumTestCase, cls).setUpClass()
3756+ if django_supports_selenium:
3757+ # Load the selenium test data fixture.
3758+ fixtures = ['selenium_tests_fixture.yaml']
3759+ # Arrange for a shared web driver.
3760+ resources = [("selenium", FixtureResource(SeleniumFixture()))]
3761
3762 def setUp(self):
3763 if not django_supports_selenium:
3764 raise SkipTest(
3765 "Live tests only enabled if Django.version >=1.4.")
3766 super(SeleniumTestCase, self).setUp()
3767+ self.selenium = self.selenium.driver
3768
3769 def tearDown(self):
3770 super(SeleniumTestCase, self).tearDown()
3771 cleanup_db(self)
3772 django_cache.clear()
3773
3774- @classmethod
3775- def tearDownClass(cls):
3776- if not django_supports_selenium:
3777- return
3778- cls.selenium.quit()
3779- cls.display.__exit__(None, None, None)
3780- cls.silencer.__exit__(None, None, None)
3781- super(SeleniumTestCase, cls).tearDownClass()
3782-
3783 def log_in(self, user='user', password='test'):
3784 """Log in as the given user. Defaults to non-admin user."""
3785 self.get_page('login')
3786
3787=== modified file 'pkg/maas-region/maasserver/tests/test_js.py'
3788--- src/maasserver/tests/test_js.py 2014-01-08 17:12:10 +0000
3789+++ pkg/maas-region/maasserver/tests/test_js.py 2014-07-28 15:42:36 +0000
3790@@ -22,17 +22,13 @@
3791 import json
3792 import os
3793 from os.path import (
3794- abspath,
3795+ basename,
3796 join,
3797- relpath,
3798 )
3799 import sys
3800 from urlparse import urljoin
3801
3802-from maastesting import (
3803- root,
3804- yui3,
3805- )
3806+from maastesting import yui3
3807 from maastesting.fixtures import (
3808 DisplayFixture,
3809 ProxiesDisabledFixture,
3810@@ -42,6 +38,7 @@
3811 from maastesting.testcase import MAASTestCase
3812 from maastesting.utils import extract_word_list
3813 from nose.tools import nottest
3814+from pkg_resources import resource_filename
3815 from saucelabsfixture import (
3816 SauceConnectFixture,
3817 SSTOnDemandFixture,
3818@@ -118,7 +115,8 @@
3819
3820 __metaclass__ = ABCMeta
3821
3822- test_paths = glob(join(root, "src/maasserver/static/js/tests/*.html"))
3823+ test_dir = resource_filename("maasserver", "static/js/tests")
3824+ test_paths = glob(join(test_dir, "*.html"))
3825 assert test_paths != [], "No JavaScript unit test pages found."
3826
3827 # Indicates if this test has been cloned.
3828@@ -169,7 +167,7 @@
3829 class YUIUnitTestsLocal(YUIUnitTestsBase, MAASTestCase):
3830
3831 scenarios = tuple(
3832- (relpath(path, root), {"test_url": "file://%s" % abspath(path)})
3833+ (basename(path), {"test_url": "file://%s" % path})
3834 for path in YUIUnitTestsBase.test_paths)
3835
3836 def multiply(self, result):
3837@@ -198,7 +196,7 @@
3838 # are proxied. See <https://saucelabs.com/docs/ondemand/connect>.
3839 with HTTPServerFixture(port=5555) as httpd:
3840 scenarios = tuple(
3841- (relpath(path, root), {"test_url": urljoin(httpd.url, path)})
3842+ (basename(path), {"test_url": urljoin(httpd.url, path)})
3843 for path in self.test_paths)
3844 with SauceConnectFixture() as sauce_connect:
3845 for browser_name in browser_names:
3846
3847=== modified file 'pkg/maas-region/maasserver/views/tests/test_nodes.py'
3848--- src/maasserver/views/tests/test_nodes.py 2014-07-18 15:44:55 +0000
3849+++ pkg/maas-region/maasserver/views/tests/test_nodes.py 2014-07-28 15:42:36 +0000
3850@@ -68,6 +68,7 @@
3851 from maasserver.views import nodes as nodes_views
3852 from maasserver.views.nodes import message_from_form_stats
3853 from maastesting.djangotestcase import count_queries
3854+from maastesting.fixtures import ClassSetup
3855 from metadataserver.models.commissioningscript import (
3856 LIST_MODALIASES_OUTPUT_NAME,
3857 LLDP_OUTPUT_NAME,
3858@@ -1246,6 +1247,7 @@
3859 self.normalise_whitespace(link.text_content()))
3860
3861
3862+@ClassSetup.use
3863 class NodeListingSelectionJSControls(SeleniumTestCase):
3864
3865 def test_node_list_js_control_select_all(self):
3866@@ -1279,6 +1281,7 @@
3867 self.assertTrue(master_selector.is_selected())
3868
3869
3870+@ClassSetup.use
3871 class NodeListingBulkActionSelectionTest(SeleniumTestCase):
3872 """Tests for JS event handling on the "bulk action" selection widget."""
3873
3874@@ -1307,6 +1310,7 @@
3875 self.assertFalse(zone_widget.is_displayed())
3876
3877
3878+@ClassSetup.use
3879 class NodeProbedDetailsExpanderTest(SeleniumTestCase):
3880
3881 def make_node_with_lldp_output(self):
3882
3883=== added directory 'pkg/maas-region/maasserver/worker'
3884=== added file 'pkg/maas-region/maasserver/worker/__init__.py'
3885=== renamed file 'etc/celeryconfig.py' => 'pkg/maas-region/maasserver/worker/config.py'
3886--- etc/celeryconfig.py 2014-06-18 14:41:48 +0000
3887+++ pkg/maas-region/maasserver/worker/config.py 2014-07-28 15:42:36 +0000
3888@@ -19,15 +19,15 @@
3889
3890 from datetime import timedelta
3891
3892-import celeryconfig_common
3893 from maas import import_settings
3894+from maascluster.worker import config_base
3895
3896 # Region worker queue. Will be overridden by the customized setting in the
3897 # local MAAS Celery config.
3898 WORKER_QUEUE_REGION = None
3899 CELERY_IMPORTS = None
3900
3901-import_settings(celeryconfig_common)
3902+import_settings(config_base)
3903
3904 CELERY_IMPORTS = CELERY_IMPORTS + (
3905 # Master tasks.
3906
3907=== added directory 'pkg/maas-region/media'
3908=== renamed directory 'src/metadataserver' => 'pkg/maas-region/metadataserver'
3909=== renamed directory 'etc/maas/templates/commissioning-user-data/snippets/tests' => 'pkg/maas-region/metadataserver/commissioning/etctest'
3910=== modified file 'pkg/maas-region/metadataserver/commissioning/etctest/__init__.py'
3911--- etc/maas/templates/commissioning-user-data/snippets/tests/__init__.py 2014-02-12 19:44:35 +0000
3912+++ pkg/maas-region/metadataserver/commissioning/etctest/__init__.py 2014-07-28 15:42:36 +0000
3913@@ -0,0 +1,15 @@
3914+# Copyright 2014 Canonical Ltd. This software is licensed under the
3915+# GNU Affero General Public License version 3 (see the file LICENSE).
3916+
3917+"""Tests for code and templates in ``etc`` related to commissioning."""
3918+
3919+from __future__ import (
3920+ absolute_import,
3921+ print_function,
3922+ unicode_literals,
3923+ )
3924+
3925+str = None
3926+
3927+__metaclass__ = type
3928+__all__ = []
3929
3930=== added symlink 'pkg/maas-region/metadataserver/commissioning/etctest/snippets'
3931=== target is u'../../../etc/maas/templates/commissioning-user-data/snippets'
3932=== modified file 'pkg/maas-region/metadataserver/commissioning/etctest/test_maas_ipmi_autodetect.py'
3933--- etc/maas/templates/commissioning-user-data/snippets/tests/test_maas_ipmi_autodetect.py 2014-07-16 14:12:13 +0000
3934+++ pkg/maas-region/metadataserver/commissioning/etctest/test_maas_ipmi_autodetect.py 2014-07-28 15:42:36 +0000
3935@@ -25,8 +25,9 @@
3936 )
3937 from maastesting.testcase import MAASTestCase
3938 from mock import call
3939-from snippets import maas_ipmi_autodetect
3940-from snippets.maas_ipmi_autodetect import (
3941+
3942+from .snippets import maas_ipmi_autodetect
3943+from .snippets.maas_ipmi_autodetect import (
3944 apply_ipmi_user_settings,
3945 bmc_list_sections,
3946 bmc_supports_lan2_0,
3947
3948=== added file 'pkg/maas-region/packages.txt'
3949--- pkg/maas-region/packages.txt 1970-01-01 00:00:00 +0000
3950+++ pkg/maas-region/packages.txt 2014-07-28 15:42:36 +0000
3951@@ -0,0 +1,48 @@
3952+apache2
3953+avahi-daemon
3954+bind9
3955+bind9utils
3956+firefox
3957+libjs-raphael
3958+libjs-yui3-full
3959+libjs-yui3-min
3960+python-amqplib
3961+python-apt
3962+python-avahi
3963+python-bson
3964+python-celery
3965+python-convoy
3966+python-crochet
3967+python-curtin
3968+python-dbus
3969+python-django
3970+python-django-piston
3971+python-django-south
3972+python-djorm-ext-pgarray
3973+python-docutils
3974+python-fixtures
3975+python-formencode
3976+python-iscpy
3977+python-jsonschema
3978+python-librabbitmq-
3979+python-lockfile
3980+python-lxml
3981+python-mock
3982+python-netaddr
3983+python-nose
3984+python-oops
3985+python-oops-datedir-repo
3986+python-oops-twisted
3987+python-openssl
3988+python-pkg-resources
3989+python-psycopg2
3990+python-simplejson
3991+python-subunit
3992+python-tempita
3993+python-testresources
3994+python-testscenarios
3995+python-testtools
3996+python-twisted
3997+python-txlongpoll
3998+python-yaml
3999+rabbitmq-server
4000
4001=== added file 'pkg/maas-region/setup.py'
4002--- pkg/maas-region/setup.py 1970-01-01 00:00:00 +0000
4003+++ pkg/maas-region/setup.py 2014-07-28 15:42:36 +0000
4004@@ -0,0 +1,197 @@
4005+#!/usr/bin/env python
4006+# Copyright 2013 Canonical Ltd. This software is licensed under the
4007+# GNU Affero General Public License version 3 (see the file LICENSE).
4008+
4009+"""Distutils installer for MAAS."""
4010+
4011+# unicode_literals is *not* included here to *better* support setup
4012+# scripts that work on both Python 2 and 3. Both expect their default
4013+# string type, and are fussy about it.
4014+from __future__ import (
4015+ absolute_import,
4016+ print_function,
4017+ )
4018+
4019+__version__ = "1.4"
4020+__metaclass__ = type
4021+
4022+
4023+from codecs import open
4024+from contextlib import contextmanager
4025+from distutils import (
4026+ errors,
4027+ log,
4028+ )
4029+from inspect import getsourcefile
4030+from operator import methodcaller
4031+from os import environ
4032+
4033+import setuptools
4034+
4035+
4036+@contextmanager
4037+def envvar(name, value):
4038+ """Context manager for temporarily setting an environment variable."""
4039+ original = environ.get(name)
4040+ environ[name] = value
4041+ try:
4042+ yield
4043+ finally:
4044+ if original is None:
4045+ environ.pop(name, None)
4046+ else:
4047+ environ[name] = original
4048+
4049+
4050+class install_deps(setuptools.Command):
4051+ """Distutils/setuptools command to install package dependencies."""
4052+
4053+ user_options = [
4054+ ('list-from=', None,
4055+ "file from which to read packages to install"),
4056+ ]
4057+
4058+ def initialize_options(self):
4059+ self.list_from = "packages.txt"
4060+
4061+ def gen_package_ops(self, package_lines):
4062+ install = methodcaller("mark_install")
4063+ delete = methodcaller("mark_delete", purge=True)
4064+ for line in package_lines:
4065+ if len(line) == 0:
4066+ pass # Ignore blank lines.
4067+ elif line.startswith("#"):
4068+ pass # Ignore whole-line comments.
4069+ elif line.endswith("-"):
4070+ package_name = line.rstrip("-")
4071+ yield package_name, delete
4072+ else:
4073+ package_name = line.rstrip("+")
4074+ yield package_name, install
4075+
4076+ def finalize_options(self):
4077+ self.ensure_filename("list_from")
4078+ self.packages = set()
4079+ with open(self.list_from, "r", encoding="utf-8") as fd:
4080+ lines = (line.strip() for line in fd)
4081+ self.package_ops = dict(self.gen_package_ops(lines))
4082+ self.packages = set(self.package_ops)
4083+
4084+ def run(self):
4085+ self.calculate_changes()
4086+ if len(self.changes) > 0:
4087+ self.apply_changes()
4088+
4089+ def calculate_changes(self):
4090+ from apt import Cache
4091+ cache = Cache()
4092+ for package_name, op in self.package_ops.iteritems():
4093+ op(cache[package_name])
4094+ self.changes = cache.get_changes()
4095+
4096+ def get_packages_to_install(self):
4097+ return self.packages.intersection(
4098+ package.name for package in self.changes
4099+ if package.marked_install or package.marked_upgrade)
4100+
4101+ def get_packages_to_delete(self):
4102+ return self.packages.intersection(
4103+ package.name for package in self.changes
4104+ if package.marked_delete)
4105+
4106+ def apply_changes(self):
4107+ """Use ``apt`` to check for package installs.
4108+
4109+ Spawns ``apt-get`` if necessary.
4110+ """
4111+ to_install = {
4112+ "%s+" % package
4113+ for package in self.get_packages_to_install()
4114+ }
4115+ if len(to_install) == 0:
4116+ log.info("system dependencies are all in place")
4117+
4118+ to_delete = {
4119+ "%s-" % package
4120+ for package in self.get_packages_to_delete()
4121+ }
4122+ if len(to_delete) == 0:
4123+ log.info("no forbidden system dependencies are installed")
4124+
4125+ to_do = sorted(to_install | to_delete)
4126+ if len(to_do) > 0:
4127+ install = [
4128+ "sudo", "apt-get", "--assume-yes",
4129+ "--no-install-recommends", "--purge",
4130+ "install",
4131+ ]
4132+ with envvar("DEBIAN_FRONTEND", "noninteractive"):
4133+ self.spawn(install + to_do)
4134+
4135+
4136+def check_settings(settings):
4137+ """Check setup settings for obvious issues.
4138+
4139+ - ``data_files`` should not be specified; setuptools ignores it.
4140+
4141+ - ``include_package_data`` should not be specified; it has weird
4142+ behaviour in setuptools.
4143+ """
4144+ if "data_files" in settings:
4145+ raise errors.DistutilsOptionError(
4146+ "data_files is ignored by setuptools")
4147+ if "include_package_data" in settings:
4148+ raise errors.DistutilsOptionError(
4149+ "include_package_data does not work as you "
4150+ "might expect with setuptools")
4151+
4152+
4153+def setup(**kwargs):
4154+ """MAAS-specific setup function.
4155+
4156+ Determines sensible defaults for many parameters.
4157+ """
4158+ command_classes = {}
4159+
4160+ try:
4161+ import apt
4162+ except ImportError:
4163+ log.warn("apt not available (install 'python-apt'?)")
4164+ else:
4165+ command_classes["install_deps"] = install_deps
4166+ apt # Silence lint.
4167+
4168+ settings = {
4169+ "cmdclass": command_classes,
4170+ "packages": setuptools.find_packages(".", exclude={"common"}),
4171+ "version": __version__,
4172+ "maintainer": "Canonical",
4173+ "maintainer_email": "maas-devel@lists.launchpad.net",
4174+ "url": "https://launchpad.net/maas",
4175+ "license": "AGPLv3",
4176+ "test_loader": "maastesting.loader:MAASTestLoader",
4177+ "test_suite": ".",
4178+ "tests_require": {"maas-testing >= %s" % __version__},
4179+ }
4180+ settings.update(kwargs)
4181+ check_settings(settings)
4182+
4183+ return setuptools.setup(**settings)
4184+
4185+
4186+def configure(**settings):
4187+ """Create a new ``setup.py`` file in the currnet directory.
4188+
4189+ Uses the file in which this function is originally defined as a
4190+ template, adding on a call to ``setup`` with the given ``settings``.
4191+ """
4192+ check_settings(settings)
4193+ thisfile = getsourcefile(configure)
4194+ with open(thisfile, "r", encoding="utf-8") as fin:
4195+ template = fin.read()
4196+ with open("setup.py", "w", encoding="utf-8") as fout:
4197+ fout.write(template)
4198+ fout.write(b"\n\nsetup(**%r)\n" % settings)
4199+
4200+
4201+setup(**{'test_loader': 'maastesting.djangoloader:MAASDjangoTestLoader', 'entry_points': {'console_scripts': set(['maas-region-worker = maas.entrypoints:celeryd', 'maas-region-twistd = maas.entrypoints:twistd', 'maas = maas.entrypoints:manage', 'maas-dns-server = maas.entrypoints:dns_server'])}, 'name': 'maas-region', 'install_requires': ['amqplib >= 1.0.2', 'celery >= 2.5.3', 'convoy >= 0.2.1', 'crochet >= 1.0.0', 'django >= 1.5.4', 'django-debug-toolbar >= 1.0.1', 'django-piston >= 0.2.3', 'djorm-ext-pgarray >= 0.8', 'docutils >= 0.11', 'formencode >= 1.2.4', 'iscpy >= 1.05', 'jsonschema >= 2.3.0', 'lockfile >= 0.8', 'lxml >= 3.2.0', 'maas-apiclient >= 1.4', 'maas-cluster >= 1.4', 'netaddr >= 0.7.7', 'oauth >= 1.0.1', 'oops >= 0.0.10', 'oops-datedir-repo >= 0.0.15', 'oops-twisted >= 0.0.6', 'psycopg2 >= 2.4.5', 'pyOpenSSL >= 0.13', 'PyYAML >= 3.1.0', 'simplejson >= 3.3.0', 'south >= 0.7.5', 'tempita >= 0.5.1', 'twisted >= 13.0.0', 'txlongpoll >= 0.3.1'], 'tests_require': ['fixtures >= 0.3.14', 'maas-testing >= 1.4', 'mock >= 1.0.1', 'nose >= 1.1.2', 'postgresfixture >= 0.2.1', 'python-subunit >= 0.0.18', 'rabbitfixture >= 0.3.5', 'saucelabsfixture >= 0.1', 'selenium >= 2.39', 'sst >= 0.2.2', 'testresources >= 0.2.5', 'testscenarios >= 0.3', 'testtools >= 0.9.32'], 'description': 'MAAS Region Controller.'})
4202
4203=== added directory 'pkg/maas-testing'
4204=== added file 'pkg/maas-testing/Makefile'
4205--- pkg/maas-testing/Makefile 1970-01-01 00:00:00 +0000
4206+++ pkg/maas-testing/Makefile 2014-07-28 15:42:36 +0000
4207@@ -0,0 +1,1 @@
4208+include ../common/Makefile
4209
4210=== added file 'pkg/maas-testing/README.rst'
4211--- pkg/maas-testing/README.rst 1970-01-01 00:00:00 +0000
4212+++ pkg/maas-testing/README.rst 2014-07-28 15:42:36 +0000
4213@@ -0,0 +1,5 @@
4214+------------
4215+maas-testing
4216+------------
4217+
4218+Testing utilities for MAAS.
4219
4220=== added symlink 'pkg/maas-testing/common'
4221=== target is u'../common'
4222=== added file 'pkg/maas-testing/configure.py'
4223--- pkg/maas-testing/configure.py 1970-01-01 00:00:00 +0000
4224+++ pkg/maas-testing/configure.py 2014-07-28 15:42:36 +0000
4225@@ -0,0 +1,27 @@
4226+from common import configure
4227+
4228+
4229+configure(
4230+ name='maas-testing',
4231+ description="MAAS testing infrastructure.",
4232+ install_requires=[
4233+ "bzr >= 2.6.0",
4234+ "celery >= 2.5.3",
4235+ "django >= 1.5.4",
4236+ "fixtures >= 0.3.14",
4237+ "lockfile >= 0.8",
4238+ "lxml >= 3.2.0",
4239+ "mock >= 1.0.1",
4240+ "netaddr >= 0.7.7",
4241+ "nose >= 1.1.2",
4242+ "postgresfixture >= 0.2.1",
4243+ "psycopg2 >= 2.4.5",
4244+ "rabbitfixture == 0.3.5",
4245+ "selenium >= 2.39",
4246+ "six >= 1.3.0",
4247+ "sst == 0.2.2",
4248+ "testresources >= 0.2.5",
4249+ "testscenarios >= 0.3",
4250+ "testtools >= 0.9.32",
4251+ ],
4252+)
4253
4254=== renamed directory 'src/maastesting' => 'pkg/maas-testing/maastesting'
4255=== modified file 'pkg/maas-testing/maastesting/__init__.py'
4256--- src/maastesting/__init__.py 2014-07-21 19:19:59 +0000
4257+++ pkg/maas-testing/maastesting/__init__.py 2014-07-28 15:42:36 +0000
4258@@ -17,22 +17,35 @@
4259 "root",
4260 ]
4261
4262-from os.path import (
4263- abspath,
4264- dirname,
4265- join,
4266- pardir,
4267- realpath,
4268+from os import (
4269+ getcwd,
4270+ path,
4271 )
4272 import re
4273 from sys import executable
4274 from warnings import filterwarnings
4275
4276-# The root of the source tree.
4277-root = abspath(join(dirname(realpath(__file__)), pardir, pardir))
4278+# The root of the source tree. Relies on having a symlink named ".root"
4279+# in the current working directory or above. Use of root is deprecated
4280+# now that different parts of MAAS are separately packaged (in Python
4281+# terms).
4282+root = getcwd()
4283+while root != path.sep:
4284+ rootflag = path.join(root, ".root")
4285+ if path.islink(rootflag):
4286+ root = path.realpath(rootflag)
4287+ break
4288+ elif path.isfile(rootflag):
4289+ root = path.realpath(root)
4290+ break
4291+ else:
4292+ root = path.dirname(root)
4293+else:
4294+ raise AssertionError(
4295+ "Could not find branch root starting from %s" % getcwd())
4296
4297 # The directory containing the current interpreter.
4298-bindir = abspath(dirname(executable))
4299+bindir = path.abspath(path.dirname(executable))
4300
4301 # Construct a regular expression that matches all of MAAS's core
4302 # packages, and their subpackages.
4303
4304=== modified file 'pkg/maas-testing/maastesting/djangoloader.py'
4305--- src/maastesting/djangoloader.py 2014-01-15 18:22:38 +0000
4306+++ pkg/maas-testing/maastesting/djangoloader.py 2014-07-28 15:42:36 +0000
4307@@ -12,51 +12,21 @@
4308
4309 __metaclass__ = type
4310 __all__ = [
4311- "MAASDjangoTestRunner",
4312 "MAASDjangoTestSuite",
4313 "MAASDjangoTestLoader",
4314 ]
4315
4316 import threading
4317-import unittest
4318
4319 from django.conf import settings
4320 from django.test.simple import DjangoTestSuiteRunner
4321-from django_nose import NoseTestSuiteRunner
4322 from maastesting.loader import MAASTestLoader
4323 from postgresfixture import ClusterFixture
4324 import south.management.commands
4325-from testtools import try_imports
4326-
4327-
4328-reorder_suite = try_imports((
4329- "django.test.simple.reorder_suite",
4330- "django.test.runner.reorder_suite",
4331-))
4332-
4333-
4334-class MAASDjangoTestRunner(NoseTestSuiteRunner):
4335- """Custom test runner; ensures that the test database cluster is up."""
4336-
4337- def setup_databases(self, *args, **kwargs):
4338- """Fire up the db cluster, then punt to original implementation."""
4339- self.cluster = ClusterFixture("db", preserve=True)
4340- self.cluster.setUp()
4341- # Create a database in the PostgreSQL cluster for each database
4342- # connection configured in Django's settings that points to the same
4343- # datadir.
4344- for database in settings.DATABASES.values():
4345- if database["HOST"] == self.cluster.datadir:
4346- self.cluster.createdb(database["NAME"])
4347- return super(MAASDjangoTestRunner, self).setup_databases(
4348- *args, **kwargs)
4349-
4350- def teardown_databases(self, *args, **kwargs):
4351- super(MAASDjangoTestRunner, self).teardown_databases(*args, **kwargs)
4352- self.cluster.cleanUp()
4353-
4354-
4355-class MAASDjangoTestSuite(unittest.TestSuite):
4356+import testresources
4357+
4358+
4359+class MAASDjangoTestSuite(testresources.OptimisingTestSuite):
4360 """A MAAS and Django-specific test s