Merge lp:~jameinel/launchpad/lp-service into lp:launchpad

Proposed by John A Meinel
Status: Rejected
Rejected by: Martin Pool
Proposed branch: lp:~jameinel/launchpad/lp-service
Merge into: lp:launchpad
Diff against target: 10039 lines (+6605/-777)
133 files modified
Makefile (+1/-1)
bzrplugins/lpserve/__init__.py (+743/-4)
bzrplugins/lpserve/test_lpserve.py (+541/-0)
configs/development/launchpad-lazr.conf (+1/-0)
database/replication/Makefile (+15/-7)
database/replication/slon_ctl.py (+4/-2)
database/sampledata/current-dev.sql (+105/-70)
database/sampledata/current.sql (+269/-162)
database/schema/comments.sql (+45/-2)
database/schema/launchpad_session.sql (+3/-4)
database/schema/patch-2208-08-1.sql (+9/-0)
database/schema/patch-2208-08-2.sql (+8/-0)
database/schema/patch-2208-08-3.sql (+8/-0)
database/schema/patch-2208-09-0.sql (+38/-0)
database/schema/patch-2208-10-0.sql (+25/-0)
database/schema/patch-2208-11-0.sql (+30/-0)
database/schema/patch-2208-12-0.sql (+17/-0)
database/schema/patch-2208-13-0.sql (+17/-0)
database/schema/patch-2208-14-0.sql (+9/-0)
database/schema/patch-2208-15-0.sql (+7/-0)
database/schema/patch-2208-16-0.sql (+8/-0)
database/schema/patch-2208-17-0.sql (+18/-0)
database/schema/security.cfg (+57/-1)
lib/canonical/config/schema-lazr.conf (+17/-0)
lib/canonical/launchpad/icing/style-3-0.css.in (+1/-1)
lib/canonical/launchpad/interfaces/__init__.py (+2/-0)
lib/canonical/launchpad/interfaces/_schema_circular_imports.py (+10/-0)
lib/canonical/launchpad/scripts/runlaunchpad.py (+50/-0)
lib/canonical/launchpad/webapp/interfaces.py (+4/-0)
lib/canonical/launchpad/webapp/servers.py (+23/-19)
lib/canonical/launchpad/webapp/tests/test_servers.py (+14/-0)
lib/canonical/launchpad/zcml/librarian.zcml (+1/-1)
lib/lp/app/templates/base-layout-macros.pt (+2/-0)
lib/lp/bugs/browser/bugattachment.py (+11/-20)
lib/lp/bugs/browser/tests/test_bugattachment_edit_view.py (+107/-0)
lib/lp/bugs/configure.zcml (+46/-0)
lib/lp/bugs/doc/initial-bug-contacts.txt (+1/-1)
lib/lp/bugs/interfaces/bugtracker.py (+89/-0)
lib/lp/bugs/model/bugmessage.py (+2/-0)
lib/lp/bugs/model/bugsubscriptionfilter.py (+36/-0)
lib/lp/bugs/model/bugsubscriptionfilterimportance.py (+29/-0)
lib/lp/bugs/model/bugsubscriptionfilterstatus.py (+29/-0)
lib/lp/bugs/model/bugsubscriptionfiltertag.py (+29/-0)
lib/lp/bugs/model/bugtracker.py (+140/-7)
lib/lp/bugs/model/tests/test_bugsubscriptionfilter.py (+66/-0)
lib/lp/bugs/model/tests/test_bugsubscriptionfilterimportance.py (+54/-0)
lib/lp/bugs/model/tests/test_bugsubscriptionfilterstatus.py (+52/-0)
lib/lp/bugs/model/tests/test_bugsubscriptionfiltertag.py (+51/-0)
lib/lp/bugs/tests/has-bug-supervisor.txt (+1/-1)
lib/lp/bugs/tests/test_bugtracker_components.py (+176/-0)
lib/lp/buildmaster/interfaces/buildfarmjob.py (+10/-1)
lib/lp/buildmaster/interfaces/packagebuild.py (+0/-6)
lib/lp/buildmaster/model/buildfarmjob.py (+5/-2)
lib/lp/code/browser/branch.py (+14/-0)
lib/lp/code/browser/branchmergeproposal.py (+9/-2)
lib/lp/code/browser/codereviewcomment.py (+39/-35)
lib/lp/code/browser/configure.zcml (+10/-3)
lib/lp/code/browser/tests/test_branchmergeproposal.py (+21/-2)
lib/lp/code/browser/tests/test_codereviewcomment.py (+26/-9)
lib/lp/code/doc/branch.txt (+1/-0)
lib/lp/code/interfaces/branchrevision.py (+0/-2)
lib/lp/code/model/branch.py (+11/-3)
lib/lp/code/model/branchmergeproposal.py (+1/-1)
lib/lp/code/model/branchrevision.py (+1/-2)
lib/lp/code/model/tests/test_branchjob.py (+1/-3)
lib/lp/code/templates/codereviewcomment-body.pt (+2/-2)
lib/lp/code/templates/codereviewcomment-header.pt (+3/-3)
lib/lp/codehosting/sshserver/session.py (+289/-11)
lib/lp/codehosting/sshserver/tests/test_session.py (+73/-0)
lib/lp/codehosting/tests/test_lpserve.py (+11/-60)
lib/lp/registry/browser/configure.zcml (+25/-0)
lib/lp/registry/browser/distroseries.py (+9/-8)
lib/lp/registry/browser/distroseriesdifference.py (+160/-0)
lib/lp/registry/browser/tests/test_distroseriesdifference_views.py (+293/-0)
lib/lp/registry/browser/tests/test_distroseriesdifference_webservice.py (+99/-0)
lib/lp/registry/browser/tests/test_series_views.py (+35/-7)
lib/lp/registry/browser/tests/test_sourcepackage_views.py (+1/-1)
lib/lp/registry/configure.zcml (+30/-97)
lib/lp/registry/enum.py (+4/-4)
lib/lp/registry/interfaces/distroseriesdifference.py (+54/-5)
lib/lp/registry/interfaces/distroseriesdifferencecomment.py (+19/-2)
lib/lp/registry/interfaces/productseries.py (+1/-10)
lib/lp/registry/interfaces/structuralsubscription.py (+48/-30)
lib/lp/registry/javascript/distroseriesdifferences_details.js (+304/-0)
lib/lp/registry/model/distroseriesdifference.py (+102/-27)
lib/lp/registry/model/distroseriesdifferencecomment.py (+28/-3)
lib/lp/registry/model/milestone.py (+5/-3)
lib/lp/registry/model/structuralsubscription.py (+20/-31)
lib/lp/registry/stories/packaging/xx-sourcepackage-packaging.txt (+1/-1)
lib/lp/registry/templates/distroseries-localdifferences.pt (+16/-7)
lib/lp/registry/templates/distroseriesdifference-listing-extra.pt (+62/-0)
lib/lp/registry/templates/distroseriesdifferencecomment-fragment.pt (+2/-0)
lib/lp/registry/tests/test_distroseriesdifference.py (+168/-20)
lib/lp/registry/tests/test_distroseriesdifferencecomment.py (+26/-2)
lib/lp/registry/windmill/tests/test_distroseriesdifference_expander.py (+86/-0)
lib/lp/services/comments/browser/configure.zcml (+12/-4)
lib/lp/services/comments/interfaces/conversation.py (+18/-0)
lib/lp/services/comments/templates/comment-body.pt (+8/-0)
lib/lp/services/comments/templates/comment-header.pt (+9/-0)
lib/lp/soyuz/browser/configure.zcml (+0/-7)
lib/lp/soyuz/browser/distroarchseries.py (+2/-1)
lib/lp/soyuz/browser/tests/test_distroarchseries_view.py (+51/-0)
lib/lp/soyuz/configure.zcml (+12/-0)
lib/lp/soyuz/doc/distroarchseries.txt (+10/-0)
lib/lp/soyuz/doc/package-arch-specific.txt (+11/-0)
lib/lp/soyuz/interfaces/distributionjob.py (+66/-0)
lib/lp/soyuz/interfaces/distroarchseries.py (+6/-0)
lib/lp/soyuz/model/distributionjob.py (+112/-0)
lib/lp/soyuz/model/distroarchseries.py (+1/-0)
lib/lp/soyuz/model/initialisedistroseriesjob.py (+48/-0)
lib/lp/soyuz/model/publishing.py (+7/-1)
lib/lp/soyuz/model/queue.py (+18/-8)
lib/lp/soyuz/pas.py (+2/-1)
lib/lp/soyuz/scripts/initialise_distroseries.py (+2/-1)
lib/lp/soyuz/scripts/tests/test_copypackage.py (+38/-0)
lib/lp/soyuz/scripts/tests/test_initialise_distroseries.py (+21/-0)
lib/lp/soyuz/tests/test_initialisedistroseriesjob.py (+74/-0)
lib/lp/soyuz/tests/test_publishing.py (+22/-20)
lib/lp/soyuz/tests/test_publishing_top_level_api.py (+40/-1)
lib/lp/testing/__init__.py (+40/-4)
lib/lp/testing/factory.py (+58/-1)
lib/lp/testing/tests/test_testing.py (+43/-0)
lib/lp/translations/browser/configure.zcml (+17/-0)
lib/lp/translations/browser/tests/test_translationtemplatesbuild.py (+84/-0)
lib/lp/translations/browser/translationtemplatesbuild.py (+63/-0)
lib/lp/translations/configure.zcml (+17/-0)
lib/lp/translations/interfaces/translationtemplatesbuild.py (+49/-0)
lib/lp/translations/model/translationtemplatesbuild.py (+117/-0)
lib/lp/translations/model/translationtemplatesbuildbehavior.py (+4/-2)
lib/lp/translations/model/translationtemplatesbuildjob.py (+21/-14)
lib/lp/translations/stories/buildfarm/xx-build-summary.txt (+89/-4)
lib/lp/translations/templates/translationtemplatesbuild-index.pt (+133/-0)
lib/lp/translations/tests/test_translationtemplatesbuild.py (+134/-0)
To merge this branch: bzr merge lp:~jameinel/launchpad/lp-service
Reviewer Review Type Date Requested Status
John A Meinel (community) Needs Resubmitting
Andrew Bennetts (community) Needs Resubmitting
Jonathan Lange Pending
Review via email: mp+35877@code.launchpad.net

Commit message

Implement LaunchpadForkingService to speed up bzr+ssh connection times.

Description of the change

I'm pretty sure this code is based on the 'launchpad/devel' branch, but it might be db-devel.

The goal of this submission is to improve the time for "bzr+ssh" to connect and be useful. The new method must be activated by setting:
  [codehosting]
  use_forking_server = True

It is set to be enabled in "development" mode, but the default is still disabled. I can't give a recommendation for the production config, because the branch is private.

This implements a new service (LaunchpadForkingService). It sits on a socket and waits for a request to 'fork <command>'. When received, it creates a stdin/stdout/stderr fifo on disk, and forks itself, running 'run_bzr_*(command)', rather than using 'exec()' which requires bootstrapping the python process.

The benefit is seen with: time echo hello | ssh localhost bzr serve --inet ...

Without this patch, it is 2.5s to serve on the loopback. With this patch, it is 0.25s.

I'm very happy to work with someone to smooth out the finer points of this submission. I tried to be explicit about places in the code that I had a decision to make, and why I chose the method I did.

I didn't use the FeatureFlag system, because setting it up via the config file was a lot more straightforward. (globally enabling/disabling the functionality).
As near as I can tell, there should be no impact of rolling this code out on production, if use_forking_daemon: False.

(The make run_codehosting will not actually spawn the daemon, and the twisted Conch code just gets an 'if ' check to see that it should use the old code path.)

I haven't run the full test suite, but I have:
 1) Run all of the locally relevant tests "bzr selftest -s bt.lp_serve' and 'bin/test
    lp.codehosting.sshserver
 2) Manually started the sftp service and run commands through the local instance. Both with
    and without the forking service enabled. (And I have confirmed that it isn't used when
    disabled, and is used when enabled, etc.)

To post a comment you must log in.
Revision history for this message
John A Meinel (jameinel) wrote :

small update, I removed the "connect_to_lpservice.py" script. It was old prototyping code, which isn't relevant anymore.

Revision history for this message
Martin Pool (mbp) wrote :

That's a great improvement in time.

I think (per your decision 1) it would be good to change it to a unix-domain socket, for the sake of a bit more security, and better reusability as a per-user thing.

Per http://www.pathname.com/fhs/pub/fhs-2.3.html#VARRUNRUNTIMEVARIABLEDATA

> System programs that maintain transient UNIX-domain sockets must place them in this directory.

which will require sysadmins making a directory under there that's writable by this process. That can be in the config file. You should just need socket.bind((AF_UNIX, path)). Then just chmod the socket.

Having a config option to turn this on is great. We could make it active only on staging at first and see the effect.

481 + while not self._should_terminate.isSet():
482 + try:
483 + conn, client_addr = self._server_socket.accept()
484 + except self._socket_timeout:
485 + pass # run shutdown and children checks
486 + except self._socket_error, e:
487 + if e.args[0] == errno.EINTR:
488 + pass # run shutdown and children checks
489 + elif e.args[0] != errno.EBADF:
490 + # We can get EBADF here while we are shutting down
491 + # So we just ignore it for now
492 + pass

It seems like this might spin if the server socket's closed and there are no dead children.

+ fifos on the filesystem, and start running the requseted command. The

typo

We should do some kind of plan or review with LOSAs on how to deploy and support this. We should configure it to log to a file, and for that to be synced to devpad. Putting the pid in the log file would be nice.

Revision history for this message
John A Meinel (jameinel) wrote :

First off, my apologies for accidentally including some db changes in this patch.

I went for a default socket location of '/var/run/launchpad_forking_service.sock' and an lp configured '/var/tmp/launchpad_forking_service.sock', since that matched a lot of the other stuff in schema-lazr.conf. I assume we can set it wherever we want in the end.

...

> It seems like this might spin if the server socket's closed and there are no dead children.

I'm not sure how you would get the server socket closed inside this process. Regardless, children shouldn't affect whether it spins or not. We just need a way to set '_should_terminate', which can be done via SIGINT or SIGTERM.

So, yes, if self._server_socket.accept() always raises an error but the should terminate event is not set, we will spin.

I suppose I could put a "self._should_terminate.set()" inside the "EBADF" check. Would that be better for you?

I do put PID into the log file, but bzr does not for each mutter() request. So when spawning I indicate that PID started, etc. But each individual message doesn't. mutter() does its own formatting, so it is a matter of changing these lines:
=== modified file 'bzrlib/trace.py'
--- bzrlib/trace.py 2010-06-28 02:41:22 +0000
+++ bzrlib/trace.py 2010-09-22 20:15:56 +0000
@@ -183,7 +183,7 @@
     else:
         out = fmt
     now = time.time()
- timestamp = '%0.3f ' % (now - _bzr_log_start_time,)
+ timestamp = '%0.3f [%d] ' % (now - _bzr_log_start_time, os.getpid())
     out = timestamp + out + '\n'
     _trace_file.write(out)
     # there's no explicit flushing; the file is typically line buffered.

Revision history for this message
Andrew Bennetts (spiv) wrote :
Download full text (9.8 KiB)

There are many unrelated changes in this diff, which is part of why the line
count is so enormous. I guess the target branch isn't the one you branched
from? It does make the review harder than it should be, and certainly much
more intimidating at a glance than it deserves, so it'd be worth fixing :)

SIGCHLD: is this handler uninstalled in the child? If not, there's a risk of
EINTR issues if the child spawns its own subprocesses. Ah, yes, it is. Good :)

> + # [Decision #4]
> + # Exit information
> + # How do we inform the client process that the child has exited?

This section seems to describe the questions without clearly stating what the
answer was. I have to read through the wall of text fairly carefully to see
what the choice was.

> + # There is some possibility that files won't get flushed, etc. So we
> + # may want to be calling sys.exitfunc() first. Note that bzr itself

Yes, I think it would be good to call sys.exitfunc() for the reasons you give.
I'd be particularly worried about incompletely written log files... it would be
a shame to have the most interesting log content never get flushed! (The end of
the log is often the most interesting bit.)

> + # [Decision #8]
> + # env vars

This section doesn't make clear what the issue is, nor what the conclusion is.
What does “this data” refer to? Are env vars the problem, or solution to some
problem?

> + # [Decision #9]
> + # nicer errors to clients
> + # This service is meant to be run only on the local system. As such,
> + # we don't try to be extra defensive about leaking information to
> + # clients. Instead we try to be helpful, and tell them as much as we
> + # know about what went wrong.

The client is connected to a remote user though. So the information returned
here won't be repeated back to that remote client?

I'm worried about this becase we already echo more information back to the
remote client than really makes sense, e.g. random warnings on stderr are sent
to the remote client, and tend to confuse users.

> + _fork_function = os.fork

I assume this is to make unit testing easier, which is fine. Peeking ahead in
the diff I see that you test this at least in part by subclassing, which isn't
so great: I feel it violates the “Use the front door first” guideline for tests,
because this isn't a class intended for subclassing in production code, so the
tests are assuming a more intimate (and not sharply defined) interface with this
code than is ideal. I'm not sure it's worth spending effort trying to find a
better way, but hopefully you finding this interesting food for thought.

> + # XXX: Cheap hack. by this point bzrlib has opened stderr for logging
> + # (as part of starting the service process in the first place). As
> + # such, it has a stream handler that writes to stderr. logging
> + # tries to flush and close that, but the file is already closed.
> + # This just supresses that exception
> + logging.raiseExceptions = False

IIRC the Launchpad coding standard requires XXX comments to have a name and date
a...

review: Needs Resubmitting
Revision history for this message
Martin Pool (mbp) wrote :

>> === added file 'lp_service_interface.txt'
> I don't think this belongs in the root of the tree.

fwiw, my inclination is to add docstrings, not comments or text files, because they more easily show up in <http://people.canonical.com/~mwh/canonicalapi/>. I don't know what other lp devs would say.

Revision history for this message
Martin Pool (mbp) wrote :

<mwhudson> poolie: the branch has conflicts with db-devel it seems
<mwhudson> jam: can you merge db-devel, fix the conflicts and repropose it against db-devel?

Revision history for this message
John A Meinel (jameinel) wrote :

I've done the changes, but I'm rejecting this in favor of an updated merge w/ db-devel and proposing against db-devel directly.

review: Needs Resubmitting
Revision history for this message
John A Meinel (jameinel) wrote :

(note that I'm not authorized to reject my own submission, I can only delete it, but I don't want to lose the conversation)

Revision history for this message
Andrew Bennetts (spiv) wrote :
Download full text (18.0 KiB)

John Arbash Meinel wrote:
> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
>
> Unfortunately this won't get put on the MP, because Launchpad now
> rejects all my emails. But I really wanted to reply to your comments inline.

Ok. I won't trim the quoted text for other people's benefit. Warm up those
scrolling fingers!

>
>
>
> ...
>
> >> + # [Decision #4]
> >> + # Exit information
> >> + # How do we inform the client process that the child has exited?
> >
> > This section seems to describe the questions without clearly stating what the
> > answer was. I have to read through the wall of text fairly carefully to see
> > what the choice was.
>
> New summary.
>
> >
> >> + # There is some possibility that files won't get flushed, etc. So we
> >> + # may want to be calling sys.exitfunc() first. Note that bzr itself
> >
> > Yes, I think it would be good to call sys.exitfunc() for the reasons you give.
> > I'd be particularly worried about incompletely written log files... it would be
> > a shame to have the most interesting log content never get flushed! (The end of
> > the log is often the most interesting bit.)
>
> I switched to this, though I'm not really sure it is the right thing.
> (When *do* buffered files get synced to disk? It seems that it might be
> during stack unwinding, which we explicitly avoid via os._exitfunc(),
> which bzr has been doing for a long time now...)

We call os._exitfunc from the outermost frame, so we don't avoid any stack
unwinding.

We do it to avoid wasting time that would be spent garbage collecting perhaps
100000s of objects when the OS can free that memory for us more cheaply.

>
>
> >
> >> + # [Decision #8]
> >> + # env vars
> >
> > This section doesn't make clear what the issue is, nor what the conclusion is.
> > What does “this data” refer to? Are env vars the problem, or solution to some
> > problem?
>
> Removed. Passing env vars from the Twisted process to the spawned child
> is a bit tricky. I did end up going with a syntax that can be parsed
> without ambiguity, though it is limited to 8-bit without encoding
> information. (AFAIK, so are real env vars)
>
> >
> >> + # [Decision #9]
> >> + # nicer errors to clients
> >> + # This service is meant to be run only on the local system. As such,
> >> + # we don't try to be extra defensive about leaking information to
> >> + # clients. Instead we try to be helpful, and tell them as much as we
> >> + # know about what went wrong.
> >
> > The client is connected to a remote user though. So the information returned
> > here won't be repeated back to that remote client?
>
> Wrong client. The 'client' here is twisted. I clarified it with:
> nicer errors on the request socket

Ok.

>
> >
> > I'm worried about this becase we already echo more information back to the
> > remote client than really makes sense, e.g. random warnings on stderr are sent
> > to the remote client, and tend to confuse users.
>
> That is true, though often the alternative would be to tell them
> nothing, which would have been worse. (Getting Permission Error can be
> confusing when i...

Revision history for this message
Martin Pool (mbp) wrote :

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'Makefile'
--- Makefile 2010-09-07 18:15:01 +0000
+++ Makefile 2010-10-04 22:08:24 +0000
@@ -253,7 +253,7 @@
253253
254run_codehosting: check_schema inplace stop254run_codehosting: check_schema inplace stop
255 $(RM) thread*.request255 $(RM) thread*.request
256 bin/run -r librarian,sftp,codebrowse -i $(LPCONFIG)256 bin/run -r librarian,sftp,forker,codebrowse -i $(LPCONFIG)
257257
258258
259start_librarian: compile259start_librarian: compile
260260
=== added directory 'bzrplugins/lpserve'
=== renamed file 'bzrplugins/lpserve.py' => 'bzrplugins/lpserve/__init__.py'
--- bzrplugins/lpserve.py 2010-04-19 06:35:23 +0000
+++ bzrplugins/lpserve/__init__.py 2010-10-04 22:08:24 +0000
@@ -8,15 +8,33 @@
88
9__metaclass__ = type9__metaclass__ = type
1010
11__all__ = ['cmd_launchpad_server']11__all__ = ['cmd_launchpad_server',
1212 'cmd_launchpad_forking_service',
1313 ]
14
15
16import errno
17import os
14import resource18import resource
19import shlex
20import shutil
21import signal
22import socket
15import sys23import sys
24import tempfile
25import threading
26import time
1627
17from bzrlib.commands import Command, register_command28from bzrlib.commands import Command, register_command
18from bzrlib.option import Option29from bzrlib.option import Option
19from bzrlib import lockdir, ui30from bzrlib import (
31 commands,
32 errors,
33 lockdir,
34 osutils,
35 trace,
36 ui,
37 )
2038
21from bzrlib.smart import medium, server39from bzrlib.smart import medium, server
22from bzrlib.transport import get_transport40from bzrlib.transport import get_transport
@@ -110,3 +128,724 @@
110128
111129
112register_command(cmd_launchpad_server)130register_command(cmd_launchpad_server)
131
132
133class LPForkingService(object):
134 """A service that can be asked to start a new bzr subprocess via fork.
135
136 The basic idea is that python startup is very expensive. For example, the
137 original 'lp-serve' command could take 2.5s just to start up, before any
138 actual actions could be performed.
139
140 This class provides a service sitting on a socket, which can then be
141 requested to fork and run a given bzr command.
142
143 Clients connect to the socket and make a simple request, which then
144 receives a response. The possible requests are:
145
146 "hello\n": Trigger a heartbeat to report that the program is still
147 running, and write status information to the log file.
148 "quit\n": Stop the service, but do so 'nicely', waiting for children
149 to exit, etc. Once this is received the service will stop
150 taking new requests on the port.
151 "fork <command>\n": Request a new subprocess to be started.
152 <command> is the bzr command to be run, such as "rocks" or
153 "lp-serve --inet 12".
154 The immediate response will be the path-on-disk to a directory full
155 of named pipes (fifos) that will be the stdout/stderr/stdin of the
156 new process.
157 If a client holds the socket open, when the child process exits,
158 the exit status (as given by 'wait()') will be written to the
159 socket.
160
161 Note that one of the key bits is that the client will not be
162 started with exec*, we just call 'commands.run_bzr*()' directly.
163 This way, any modules that are already loaded will not need to be
164 loaded again. However, care must be taken with any global-state
165 that should be reset.
166 """
167
168 # Design decisions. These are bits where we could have chosen a different
169 # method/implementation and weren't sure what would be best. Documenting
170 # the current decision, and the alternatives.
171 #
172 # [Decision #1]
173 # Serve on a named AF_UNIX socket.
174 # 1) It doesn't make sense to serve to arbitrary hosts, we only want
175 # the local host to make requests. (Since the client needs to
176 # access the named fifos on the current filesystem.)
177 # 2) You can set security parameters on a filesystem path (g+rw,
178 # a-rw).
179 # [Decision #2]
180 # SIGCHLD
181 # We want to quickly detect that children have exited so that we can
182 # inform the client process quickly. At the moment, we register a
183 # SIGCHLD handler that doesn't do anything. However, it means that
184 # when we get the signal, if we are currently blocked in something
185 # like '.accept()', we will jump out temporarily. At that point the
186 # main loop will check if any children have exited. We could have
187 # done this work as part of the signal handler, but that felt 'racy'
188 # doing any serious work in a signal handler.
189 # If we just used socket.timeout as the indicator to go poll for
190 # children exiting, it slows the disconnect by as much as the full
191 # timeout. (So a timeout of 1.0s will cause the process to hang by
192 # that long until it determines that a child has exited, and can
193 # close the connection.)
194 # The current flow means that we'll notice exited children whenever
195 # we finish the current work.
196 # [Decision #3]
197 # Child vs Parent actions.
198 # There are several actions that are done when we get a new request.
199 # We have to create the fifos on disk, fork a new child, connect the
200 # child to those handles, and inform the client of the new path (not
201 # necessarily in that order.) It makes sense to wait to send the path
202 # message until after the fifos have been created. That way the
203 # client can just try to open them immediately, and the
204 # client-and-child will be synchronized by the open() calls.
205 # However, should the client be the one doing the mkfifo, should the
206 # server? Who should be sending the message? Should we fork after the
207 # mkfifo or before.
208 # The current thoughts:
209 # 1) Try to do work in the child when possible. This should allow
210 # for 'scaling' because the server is single-threaded.
211 # 2) We create the directory itself in the server, because that
212 # allows the server to monitor whether the client failed to
213 # clean up after itself or not.
214 # 3) Otherwise we create the fifos in the client, and then send
215 # the message back.
216 # [Decision #4]
217 # Exit information
218 # Inform the client that the child has exited on the socket they used
219 # to request the fork.
220 # 1) Arguably they could see that stdout and stderr have been closed,
221 # and thus stop reading. In testing, I wrote a client which uses
222 # select.poll() over stdin/stdout/stderr and used that to ferry
223 # the content to the appropriate local handle. However for the
224 # FIFOs, when the remote end closed, I wouldn't see any
225 # corresponding information on the local end. There obviously
226 # wasn't any data to be read, so they wouldn't show up as
227 # 'readable' (for me to try to read, and get 0 bytes, indicating
228 # it was closed). I also wasn't seeing POLLHUP, which seemed to be
229 # the correct indicator. As such, we decided to inform the client
230 # on the socket that they originally made the fork request, rather
231 # than just closing the socket immediately.
232 # 2) We could have had the forking server close the socket, and only
233 # the child hold the socket open. When the child exits, then the
234 # OS naturally closes the socket.
235 # If we want the returncode, then we should put that as bytes on
236 # the socket before we exit. Having the child do the work means
237 # that in error conditions, it could easily die before being able to
238 # write anything (think SEGFAULT, etc). The forking server is
239 # already 'wait'() ing on its children. So that we don't get
240 # zombies, and with wait3() we can get the rusage (user time,
241 # memory consumption, etc.)
242 # As such, it seems reasonable that the server can then also
243 # report back when a child is seen as exiting.
244 # [Decision #5]
245 # cleanup once connected
246 # The child process blocks during 'open()' waiting for the client to
247 # connect to its fifos. Once the client has connected, the child then
248 # deletes the temporary directory and the fifos from disk. This means
249 # that there isn't much left for diagnosis, but it also means that
250 # the client won't leave garbage around if it crashes, etc.
251 # Note that the forking service itself still monitors the paths
252 # created, and will delete garbage if it sees that a child failed to
253 # do so.
254 # [Decision #6]
255 # os._exit(retcode) in the child
256 # Calling sys.exit(retcode) raises an exception, which then bubbles
257 # up the stack and runs exit functions (and finally statements). When
258 # I tried using it originally, I would see the current child bubble
259 # all the way up the stack (through the server code that it fork()
260 # through), and then get to main() returning code 0. The process
261 # would still exit nonzero. My guess is that something in the atexit
262 # functions was failing, but that it was happening after logging, etc
263 # had been shut down.
264 # Any global state from the child process should be flushed before
265 # run_bzr_* has exited (which we *do* wait for), and any other global
266 # state is probably a remnant from the service process. Which will be
267 # cleaned up by the service itself, rather than the child.
268 # There is some concern that log files may not get flushed, so we
269 # currently call sys.exitfunc() first. The main problem is that I
270 # don't know any way to *remove* a function registered via 'atexit()'
271 # so if the forking service has some state, we my try to clean it up
272 # incorrectly.
273 # Note that the bzr script itself uses sys.exitfunc(); os._exit() in
274 # the 'bzr' main script, as the teardown time of all the python state
275 # was quite noticeable in real-world runtime. As such, bzrlib should
276 # be pretty safe, or it would have been failing for people already.
277 # [Decision #7]
278 # prefork vs max children vs ?
279 # For simplicity it seemed easiest to just fork when requested. Over
280 # time, I realized it would be easy to allow running an arbitrary
281 # command (no harder than just running one command), so it seemed
282 # reasonable to switch over. If we go the prefork route, then we'll
283 # need a way to tell the pre-forked children what command to run.
284 # This could be as easy as just adding one more fifo that they wait
285 # on in the same directory.
286 # For now, I've chosen not to limit the number of forked children. I
287 # don't know what a reasonable value is, and probably there are
288 # already limitations at play. (If Conch limits connections, then it
289 # will already be doing all the work, etc.)
290 # [Decision #8]
291 # nicer errors on the request socket
292 # This service is meant to be run only on the local system. As such,
293 # we don't try to be extra defensive about leaking information to
294 # the one connecting to the socket. (We should still watch out what
295 # we send across the per-child fifos, since those are connected to
296 # remote clients.) Instead we try to be helpful, and tell them as
297 # much as we know about what went wrong.
298
299 DEFAULT_PATH = '/var/run/launchpad_forking_service.sock'
300 DEFAULT_PERMISSIONS = 00660 # Permissions on the master socket (rw-rw----)
301 WAIT_FOR_CHILDREN_TIMEOUT = 5*60 # Wait no more than 5 min for children
302 SOCKET_TIMEOUT = 1.0
303 SLEEP_FOR_CHILDREN_TIMEOUT = 1.0
304 WAIT_FOR_REQUEST_TIMEOUT = 1.0 # No request should take longer than this to
305 # be read
306
307 _fork_function = os.fork
308
309 def __init__(self, path=DEFAULT_PATH, perms=DEFAULT_PERMISSIONS):
310 self.master_socket_path = path
311 self._perms = perms
312 self._start_time = time.time()
313 self._should_terminate = threading.Event()
314 # We address these locally, in case of shutdown socket may be gc'd
315 # before we are
316 self._socket_timeout = socket.timeout
317 self._socket_error = socket.error
318 self._socket_timeout = socket.timeout
319 self._socket_error = socket.error
320 # Map from pid => information
321 self._child_processes = {}
322 self._children_spawned = 0
323
324 def _create_master_socket(self):
325 self._server_socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
326 self._server_socket.bind(self.master_socket_path)
327 if self._perms is not None:
328 os.chmod(self.master_socket_path, self._perms)
329 self._server_socket.setsockopt(socket.SOL_SOCKET,
330 socket.SO_REUSEADDR, 1)
331 self._sockname = self._server_socket.getsockname()
332 # self.host = self._sockname[0]
333 self.port = self._sockname[1]
334 self._server_socket.listen(5)
335 self._server_socket.settimeout(self.SOCKET_TIMEOUT)
336 trace.mutter('set socket timeout to: %s' % (self.SOCKET_TIMEOUT,))
337
338 def _cleanup_master_socket(self):
339 self._server_socket.close()
340 try:
341 os.remove(self.master_socket_path)
342 except (OSError, IOError), e:
343 # If we don't delete it, then we get 'address already in
344 # use' failures
345 trace.mutter('failed to cleanup: %s'
346 % (self.master_socket_path,))
347
348 def _handle_sigchld(self, signum, frm):
349 # We don't actually do anything here, we just want an interrupt (EINTR)
350 # on socket.accept() when SIGCHLD occurs.
351 pass
352
353 def _handle_sigterm(self, signum, frm):
354 # Unregister this as the default handler, 2 SIGTERMs will exit us.
355 signal.signal(signal.SIGTERM, signal.SIG_DFL)
356 # SIGTERM should also generate EINTR on our wait loop, so this should
357 # be enough
358 self._should_terminate.set()
359
360 def _register_signals(self):
361 """Register a SIGCHILD and SIGTERM handler.
362
363 If we have a trigger for SIGCHILD then we can quickly respond to
364 clients when their process exits. The main risk is getting more EAGAIN
365 errors elsewhere.
366
367 SIGTERM allows us to cleanup nicely before we exit.
368 """
369 signal.signal(signal.SIGCHLD, self._handle_sigchld)
370 signal.signal(signal.SIGTERM, self._handle_sigterm)
371
372 def _unregister_signals(self):
373 signal.signal(signal.SIGCHLD, signal.SIG_DFL)
374 signal.signal(signal.SIGTERM, signal.SIG_DFL)
375
376 def _create_child_file_descriptors(self, base_path):
377 stdin_path = os.path.join(base_path, 'stdin')
378 stdout_path = os.path.join(base_path, 'stdout')
379 stderr_path = os.path.join(base_path, 'stderr')
380 os.mkfifo(stdin_path)
381 os.mkfifo(stdout_path)
382 os.mkfifo(stderr_path)
383
384 def _bind_child_file_descriptors(self, base_path):
385 import logging
386 from bzrlib import ui
387 stdin_path = os.path.join(base_path, 'stdin')
388 stdout_path = os.path.join(base_path, 'stdout')
389 stderr_path = os.path.join(base_path, 'stderr')
390 # Opening for writing blocks (or fails), so do those last
391 # TODO: Consider buffering, though that might interfere with reading
392 # and writing the smart protocol
393 stdin_fid = os.open(stdin_path, os.O_RDONLY)
394 stdout_fid = os.open(stdout_path, os.O_WRONLY)
395 stderr_fid = os.open(stderr_path, os.O_WRONLY)
396 # Note: by this point bzrlib has opened stderr for logging
397 # (as part of starting the service process in the first place). As
398 # such, it has a stream handler that writes to stderr. logging
399 # tries to flush and close that, but the file is already closed.
400 # This just supresses that exception
401 logging.raiseExceptions = False
402 sys.stdin.close()
403 sys.stdout.close()
404 sys.stderr.close()
405 os.dup2(stdin_fid, 0)
406 os.dup2(stdout_fid, 1)
407 os.dup2(stderr_fid, 2)
408 sys.stdin = os.fdopen(stdin_fid, 'rb')
409 sys.stdout = os.fdopen(stdout_fid, 'wb')
410 sys.stderr = os.fdopen(stderr_fid, 'wb')
411 ui.ui_factory.stdin = sys.stdin
412 ui.ui_factory.stdout = sys.stdout
413 ui.ui_factory.stderr = sys.stderr
414 # Now that we've opened the handles, delete everything so that we don't
415 # leave garbage around. Because the open() is done in blocking mode, we
416 # know that someone has already connected to them, and we don't want
417 # anyone else getting confused and connecting.
418 # See [Decision #5]
419 os.remove(stderr_path)
420 os.remove(stdout_path)
421 os.remove(stdin_path)
422 os.rmdir(base_path)
423
424 def _close_child_file_descriptons(self):
425 sys.stdin.close()
426 sys.stderr.close()
427 sys.stdout.close()
428
429 def become_child(self, command_argv, path):
430 """We are in the spawned child code, do our magic voodoo."""
431 # Stop tracking new signals
432 self._unregister_signals()
433 # Reset the start time
434 trace._bzr_log_start_time = time.time()
435 trace.mutter('%d starting %r'
436 % (os.getpid(), command_argv,))
437 self.host = None
438 self.port = None
439 self._sockname = None
440 self._bind_child_file_descriptors(path)
441 self._run_child_command(command_argv)
442
443 def _run_child_command(self, command_argv):
444 # This is the point where we would actually want to do something with
445 # our life
446 # TODO: We may want to consider special-casing the 'lp-serve' command.
447 # As that is the primary use-case for this service, it might be
448 # interesting to have an already-instantiated instance, where we
449 # can just pop on an extra argument and be ready to go. However,
450 # that would probably only really be measurable if we prefork. As
451 # it looks like ~200ms is 'fork()' time, but only 50ms is
452 # run-the-command time.
453 retcode = commands.run_bzr_catch_errors(command_argv)
454 self._close_child_file_descriptons()
455 trace.mutter('%d finished %r'
456 % (os.getpid(), command_argv,))
457 # We force os._exit() here, because we don't want to unwind the stack,
458 # which has complex results. (We can get it to unwind back to the
459 # cmd_launchpad_forking_service code, and even back to main() reporting
460 # thereturn code, but after that, suddenly the return code changes from
461 # a '0' to a '1', with no logging of info.
462 # TODO: Should we call sys.exitfunc() here? it allows atexit functions
463 # to fire, however, some of those may be still around from the
464 # parent process, which we don't really want.
465 sys.exitfunc()
466 # See [Decision #6]
467 os._exit(retcode)
468
469 @staticmethod
470 def command_to_argv(command_str):
471 """Convert a 'foo bar' style command to [u'foo', u'bar']"""
472 # command_str must be a utf-8 string
473 return [s.decode('utf-8') for s in shlex.split(command_str)]
474
475 @staticmethod
476 def parse_env(env_str):
477 """Convert the environment information into a dict.
478
479 :param env_str: A string full of environment variable declarations.
480 Each key is simple ascii "key: value\n"
481 The string must end with "end\n".
482 :return: A dict of environment variables
483 """
484 env = {}
485 if not env_str.endswith('end\n'):
486 raise ValueError('Invalid env-str: %r' % (env_str,))
487 env_str = env_str[:-5]
488 if not env_str:
489 return env
490 env_entries = env_str.split('\n')
491 for entry in env_entries:
492 key, value = entry.split(': ', 1)
493 env[key] = value
494 return env
495
496 def fork_one_request(self, conn, client_addr, command_argv, env):
497 """Fork myself and serve a request."""
498 temp_name = tempfile.mkdtemp(prefix='lp-forking-service-child-')
499 # Now that we've set everything up, send the response to the client we
500 # create them first, so the client can start trying to connect to them,
501 # while we fork and have the child do the same.
502 self._children_spawned += 1
503 pid = self._fork_function()
504 if pid == 0:
505 pid = os.getpid()
506 trace.mutter('%d spawned' % (pid,))
507 self._server_socket.close()
508 for env_var, value in env.iteritems():
509 osutils.set_or_unset_env(env_var, value)
510 # See [Decision #3]
511 self._create_child_file_descriptors(temp_name)
512 conn.sendall('ok\n%d\n%s\n' % (pid, temp_name))
513 conn.close()
514 self.become_child(command_argv, temp_name)
515 trace.warning('become_child returned!!!')
516 sys.exit(1)
517 else:
518 self._child_processes[pid] = (temp_name, conn)
519 self.log(client_addr, 'Spawned process %s for %r: %s'
520 % (pid, command_argv, temp_name))
521
522 def main_loop(self):
523 self._should_terminate.clear()
524 self._register_signals()
525 self._create_master_socket()
526 trace.note('Listening on socket: %s' % (self.master_socket_path,))
527 try:
528 try:
529 self._do_loop()
530 finally:
531 # Stop talking to others, we are shutting down
532 self._cleanup_master_socket()
533 except KeyboardInterrupt:
534 # SIGINT received, try to shutdown cleanly
535 pass
536 trace.note('Shutting down. Waiting up to %.0fs for %d child processes'
537 % (self.WAIT_FOR_CHILDREN_TIMEOUT,
538 len(self._child_processes),))
539 self._shutdown_children()
540 trace.note('Exiting')
541
542 def _do_loop(self):
543 while not self._should_terminate.isSet():
544 try:
545 conn, client_addr = self._server_socket.accept()
546 except self._socket_timeout:
547 pass # run shutdown and children checks
548 except self._socket_error, e:
549 if e.args[0] == errno.EINTR:
550 pass # run shutdown and children checks
551 elif e.args[0] != errno.EBADF:
552 # We can get EBADF here while we are shutting down
553 # So we just ignore it for now
554 pass
555 else:
556 # Log any other failure mode
557 trace.warning("listening socket error: %s", e)
558 else:
559 self.log(client_addr, 'connected')
560 # TODO: We should probably trap exceptions coming out of this
561 # and log them, so that we don't kill the service because
562 # of an unhandled error
563 # Note: settimeout is used so that a malformed request doesn't
564 # cause us to hang forever. Note that the particular
565 # implementation means that a malicious client could
566 # probably send us one byte every Xms, and we would just
567 # keep trying to read it. However, as a local service, we
568 # aren't worrying about it.
569 conn.settimeout(self.WAIT_FOR_REQUEST_TIMEOUT)
570 try:
571 self.serve_one_connection(conn, client_addr)
572 except self._socket_timeout, e:
573 trace.log_exception_quietly()
574 self.log(client_addr, 'request timeout failure: %s' % (e,))
575 conn.sendall('FAILURE\nrequest timed out\n')
576 conn.close()
577 self._poll_children()
578
579 def log(self, client_addr, message):
580 """Log a message to the trace log.
581
582 Include the information about what connection is being served.
583 """
584 if client_addr is not None:
585 # Note, we don't use conn.getpeername() because if a client
586 # disconnects before we get here, that raises an exception
587 conn_info = '[%s] ' % (client_addr,)
588 else:
589 conn_info = ''
590 trace.mutter('%s%s' % (conn_info, message))
591
592 def log_information(self):
593 """Log the status information.
594
595 This includes stuff like number of children, and ... ?
596 """
597 self._poll_children()
598 self.log(None, 'Running for %.3fs' % (time.time() - self._start_time))
599 self.log(None, '%d children currently running (spawned %d total)'
600 % (len(self._child_processes), self._children_spawned))
601 # Read the current information about memory consumption, etc.
602 self.log(None, 'Self: %s'
603 % (resource.getrusage(resource.RUSAGE_SELF),))
604 # This seems to be the sum of all rusage for all children that have
605 # been collected (not for currently running children, or ones we
606 # haven't "wait"ed on.) We may want to read /proc/PID/status, since
607 # 'live' information is probably more useful.
608 self.log(None, 'Finished children: %s'
609 % (resource.getrusage(resource.RUSAGE_CHILDREN),))
610
611 def _poll_children(self):
612 """See if children are still running, etc.
613
614 One interesting hook here would be to track memory consumption, etc.
615 """
616 while self._child_processes:
617 try:
618 c_id, exit_code, rusage = os.wait3(os.WNOHANG)
619 except OSError, e:
620 if e.errno == errno.ECHILD:
621 # TODO: We handle this right now because the test suite
622 # fakes a child, since we wanted to test some code
623 # without actually forking anything
624 trace.mutter('_poll_children() called, and'
625 ' self._child_processes indicates there are'
626 ' children, but os.wait3() says there are not.'
627 ' current_children: %s' % (self._child_processes,))
628 return
629 if c_id == 0:
630 # No more children stopped right now
631 return
632 c_path, sock = self._child_processes.pop(c_id)
633 trace.mutter('%s exited %s and usage: %s'
634 % (c_id, exit_code, rusage))
635 # See [Decision #4]
636 try:
637 sock.sendall('exited\n%s\n' % (exit_code,))
638 except (self._socket_timeout, self._socket_error), e:
639 # The client disconnected before we wanted them to,
640 # no big deal
641 trace.mutter('%s\'s socket already closed: %s' % (c_id, e))
642 else:
643 sock.close()
644 if os.path.exists(c_path):
645 # The child failed to cleanup after itself, do the work here
646 trace.warning('Had to clean up after child %d: %s\n'
647 % (c_id, c_path))
648 shutil.rmtree(c_path, ignore_errors=True)
649
650 def _wait_for_children(self, secs):
651 start = time.time()
652 end = start + secs
653 while self._child_processes:
654 self._poll_children()
655 if secs > 0 and time.time() > end:
656 break
657 time.sleep(self.SLEEP_FOR_CHILDREN_TIMEOUT)
658
659 def _shutdown_children(self):
660 self._wait_for_children(self.WAIT_FOR_CHILDREN_TIMEOUT)
661 if self._child_processes:
662 trace.warning('Failed to stop children: %s'
663 % ', '.join(map(str, self._child_processes)))
664 for c_id in self._child_processes:
665 trace.warning('sending SIGINT to %d' % (c_id,))
666 os.kill(c_id, signal.SIGINT)
667 # We sent the SIGINT signal, see if they exited
668 self._wait_for_children(self.SLEEP_FOR_CHILDREN_TIMEOUT)
669 if self._child_processes:
670 # No? Then maybe something more powerful
671 for c_id in self._child_processes:
672 trace.warning('sending SIGKILL to %d' % (c_id,))
673 os.kill(c_id, signal.SIGKILL)
674 # We sent the SIGKILL signal, see if they exited
675 self._wait_for_children(self.SLEEP_FOR_CHILDREN_TIMEOUT)
676 if self._child_processes:
677 for c_id, (c_path, sock) in self._child_processes.iteritems():
678 # TODO: We should probably put something into this message?
679 # However, the likelyhood is very small that this isn't
680 # already closed because of SIGKILL + _wait_for_children
681 # And I don't really know what to say...
682 sock.close()
683 if os.path.exists(c_path):
684 trace.warning('Cleaning up after immortal child %d: %s\n'
685 % (c_id, c_path))
686 shutil.rmtree(c_path)
687
688 def _parse_fork_request(self, conn, client_addr, request):
689 if request.startswith('fork-env '):
690 while not request.endswith('end\n'):
691 request += osutils.read_bytes_from_socket(conn)
692 request = request.replace('\r\n', '\n')
693 command, env = request[9:].split('\n', 1)
694 else:
695 command = request[5:].strip()
696 env = 'end\n' # No env set
697 try:
698 command_argv = self.command_to_argv(command)
699 env = self.parse_env(env)
700 except Exception, e:
701 # TODO: Log the traceback?
702 self.log(client_addr, 'command or env parsing failed: %r'
703 % (str(e),))
704 conn.sendall('FAILURE\ncommand or env parsing failed: %r'
705 % (str(e),))
706 else:
707 return command_argv, env
708 return None, None
709
710 def serve_one_connection(self, conn, client_addr):
711 request = ''
712 while '\n' not in request:
713 request += osutils.read_bytes_from_socket(conn)
714 # telnet likes to use '\r\n' rather than '\n', and it is nice to have
715 # an easy way to debug.
716 request = request.replace('\r\n', '\n')
717 self.log(client_addr, 'request: %r' % (request,))
718 if request == 'hello\n':
719 conn.sendall('ok\nyep, still alive\n')
720 self.log_information()
721 elif request == 'quit\n':
722 self._should_terminate.set()
723 conn.sendall('ok\nquit command requested... exiting\n')
724 elif request.startswith('fork ') or request.startswith('fork-env '):
725 command_argv, env = self._parse_fork_request(conn, client_addr,
726 request)
727 if command_argv is not None:
728 # See [Decision #7]
729 # TODO: Do we want to limit the number of children? And/or
730 # prefork additional instances? (the design will need to
731 # change if we prefork and run arbitrary commands.)
732 self.fork_one_request(conn, client_addr, command_argv, env)
733 # We don't close the conn like other code paths, since we use
734 # it again later.
735 return
736 else:
737 self.log(client_addr, 'FAILURE: unknown request: %r' % (request,))
738 # See [Decision #8]
739 conn.sendall('FAILURE\nunknown request: %r\n' % (request,))
740 conn.close()
741
742
743class cmd_launchpad_forking_service(Command):
744 """Launch a long-running process, where you can ask for new processes.
745
746 The process will block on a given --port waiting for requests to be made.
747 When a request is made, it will fork itself and redirect stdout/in/err to
748 fifos on the filesystem, and start running the requested command. The
749 caller will be informed where those file handles can be found. Thus it only
750 makes sense that the process connecting to the port must be on the same
751 system.
752 """
753
754 aliases = ['lp-service']
755
756 takes_options = [Option('path',
757 help='Listen for connections at PATH',
758 type=str),
759 Option('perms',
760 help='Set the mode bits for the socket, interpreted'
761 ' as an octal integer (same as chmod)'),
762 Option('preload',
763 help="Do/don't preload libraries before startup."),
764 Option('children-timeout', type=int,
765 help="Only wait XX seconds for children to exit"),
766 ]
767
768 def _preload_libraries(self):
769 global libraries_to_preload
770 for pyname in libraries_to_preload:
771 try:
772 __import__(pyname)
773 except ImportError, e:
774 trace.mutter('failed to preload %s: %s' % (pyname, e))
775
776 def run(self, path=None, perms=None, preload=True,
777 children_timeout=LPForkingService.WAIT_FOR_CHILDREN_TIMEOUT):
778 if path is None:
779 path = LPForkingService.DEFAULT_PATH
780 if perms is None:
781 perms = LPForkingService.DEFAULT_PERMISSIONS
782 if preload:
783 # We 'note' this because it often takes a fair amount of time.
784 trace.note('Preloading %d modules' % (len(libraries_to_preload),))
785 self._preload_libraries()
786 service = LPForkingService(path, perms)
787 service.WAIT_FOR_CHILDREN_TIMEOUT = children_timeout
788 service.main_loop()
789
790register_command(cmd_launchpad_forking_service)
791
792
793class cmd_launchpad_replay(Command):
794 """Write input from stdin back to stdout or stderr.
795
796 This is a hidden command, primarily available for testing
797 cmd_launchpad_forking_service.
798 """
799
800 hidden = True
801
802 def run(self):
803 # Just read line-by-line from stdin, and write out to stdout or stderr
804 # depending on the prefix
805 for line in sys.stdin:
806 channel, contents = line.split(' ', 1)
807 channel = int(channel)
808 if channel == 1:
809 sys.stdout.write(contents)
810 sys.stdout.flush()
811 elif channel == 2:
812 sys.stderr.write(contents)
813 sys.stderr.flush()
814 else:
815 raise RuntimeError('Invalid channel request.')
816 return 0
817
818register_command(cmd_launchpad_replay)
819
820# This list was generated by run lsprofing a spawned child, and looking for
821# <module ...> times, which indicate an import occured. Other possibilities are
822# to just run "bzr lp-serve --profile-imports" manually, and observe what was
823# expensive to import. It doesn't seem very easy to get this right
824# automatically.
825libraries_to_preload = [
826 'bzrlib.errors',
827 'bzrlib.repofmt.groupcompress_repo',
828 'bzrlib.repository',
829 'bzrlib.smart',
830 'bzrlib.smart.protocol',
831 'bzrlib.smart.request',
832 'bzrlib.smart.server',
833 'bzrlib.smart.vfs',
834 'bzrlib.transport.local',
835 'bzrlib.transport.readonly',
836 'lp.codehosting.bzrutils',
837 'lp.codehosting.vfs',
838 'lp.codehosting.vfs.branchfs',
839 'lp.codehosting.vfs.branchfsclient',
840 'lp.codehosting.vfs.hooks',
841 'lp.codehosting.vfs.transport',
842 ]
843
844
845
846def load_tests(standard_tests, module, loader):
847 standard_tests.addTests(loader.loadTestsFromModuleNames(
848 [__name__ + '.' + x for x in [
849 'test_lpserve',
850 ]]))
851 return standard_tests
113852
=== added file 'bzrplugins/lpserve/test_lpserve.py'
--- bzrplugins/lpserve/test_lpserve.py 1970-01-01 00:00:00 +0000
+++ bzrplugins/lpserve/test_lpserve.py 2010-10-04 22:08:24 +0000
@@ -0,0 +1,541 @@
1# Copyright 2010 Canonical Ltd. This software is licensed under the
2# GNU Affero General Public License version 3 (see the file LICENSE).
3
4import os
5import signal
6import socket
7import subprocess
8import tempfile
9import threading
10import time
11
12from testtools import content
13
14from bzrlib import (
15 osutils,
16 tests,
17 trace,
18 )
19from bzrlib.plugins import lpserve
20
21from canonical.config import config
22from lp.codehosting import get_bzr_path, get_BZR_PLUGIN_PATH_for_subprocess
23
24
25class TestingLPForkingServiceInAThread(lpserve.LPForkingService):
26 """Wrap starting and stopping an LPForkingService instance in a thread."""
27
28 # For testing, we set the timeouts much lower, because we want the tests to
29 # run quickly
30 WAIT_FOR_CHILDREN_TIMEOUT = 0.5
31 SOCKET_TIMEOUT = 0.01
32 SLEEP_FOR_CHILDREN_TIMEOUT = 0.01
33 WAIT_FOR_REQUEST_TIMEOUT = 0.1
34
35 _fork_function = None
36
37 def __init__(self, path, perms=None):
38 self.service_started = threading.Event()
39 self.service_stopped = threading.Event()
40 self.this_thread = None
41 self.fork_log = []
42 super(TestingLPForkingServiceInAThread, self).__init__(
43 path=path, perms=None)
44
45 def _register_signals(self):
46 pass # Don't register it for the test suite
47
48 def _unregister_signals(self):
49 pass # We don't fork, and didn't register, so don't unregister
50
51 def _create_master_socket(self):
52 super(TestingLPForkingServiceInAThread, self)._create_master_socket()
53 self.service_started.set()
54
55 def main_loop(self):
56 self.service_stopped.clear()
57 super(TestingLPForkingServiceInAThread, self).main_loop()
58 self.service_stopped.set()
59
60 def fork_one_request(self, conn, client_addr, command, env):
61 # We intentionally don't allow the test suite to request a fork, as
62 # threads + forks and everything else don't exactly play well together
63 self.fork_log.append((command, env))
64 conn.sendall('ok\nfake forking\n')
65 conn.close()
66
67 @staticmethod
68 def start_service(test):
69 """Start a new LPForkingService in a thread at a random path.
70
71 This will block until the service has created its socket, and is ready
72 to communicate.
73
74 :return: A new TestingLPForkingServiceInAThread instance
75 """
76 fd, path = tempfile.mkstemp(prefix='tmp-lp-forking-service-',
77 suffix='.sock')
78 # We don't want a temp file, we want a temp socket
79 os.close(fd)
80 os.remove(path)
81 new_service = TestingLPForkingServiceInAThread(path=path)
82 thread = threading.Thread(target=new_service.main_loop,
83 name='TestingLPForkingServiceInAThread')
84 new_service.this_thread = thread
85 # should we be doing thread.setDaemon(True) ?
86 thread.start()
87 new_service.service_started.wait(10.0)
88 if not new_service.service_started.isSet():
89 raise RuntimeError(
90 'Failed to start the TestingLPForkingServiceInAThread')
91 test.addCleanup(new_service.stop_service)
92 # what about returning new_service._sockname ?
93 return new_service
94
95 def stop_service(self):
96 """Stop the test-server thread. This can be called multiple times."""
97 if self.this_thread is None:
98 # We already stopped the process
99 return
100 self._should_terminate.set()
101 self.service_stopped.wait(10.0)
102 if not self.service_stopped.isSet():
103 raise RuntimeError(
104 'Failed to stop the TestingLPForkingServiceInAThread')
105 self.this_thread.join()
106 # Break any refcycles
107 self.this_thread = None
108
109
110class TestTestingLPForkingServiceInAThread(tests.TestCaseWithTransport):
111
112 def test_start_and_stop_service(self):
113 service = TestingLPForkingServiceInAThread.start_service(self)
114 service.stop_service()
115
116 def test_multiple_stops(self):
117 service = TestingLPForkingServiceInAThread.start_service(self)
118 service.stop_service()
119 service.stop_service()
120
121 def test_autostop(self):
122 # We shouldn't leak a thread here, as it should be part of the test
123 # case teardown.
124 service = TestingLPForkingServiceInAThread.start_service(self)
125
126
127class TestCaseWithLPForkingService(tests.TestCaseWithTransport):
128
129 def setUp(self):
130 super(TestCaseWithLPForkingService, self).setUp()
131 self.service = TestingLPForkingServiceInAThread.start_service(self)
132
133 def send_message_to_service(self, message, one_byte_at_a_time=False):
134 client_sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
135 client_sock.connect(self.service.master_socket_path)
136 if one_byte_at_a_time:
137 for byte in message:
138 client_sock.send(byte)
139 else:
140 client_sock.sendall(message)
141 response = client_sock.recv(1024)
142 return response
143
144
145class TestLPForkingServiceCommandToArgv(tests.TestCase):
146
147 def assertAsArgv(self, argv, command_str):
148 self.assertEqual(argv,
149 lpserve.LPForkingService.command_to_argv(command_str))
150
151 def test_simple(self):
152 self.assertAsArgv([u'foo'], 'foo')
153 self.assertAsArgv([u'foo', u'bar'], 'foo bar')
154
155 def test_quoted(self):
156 self.assertAsArgv([u'foo'], 'foo')
157 self.assertAsArgv([u'foo bar'], '"foo bar"')
158
159 def test_unicode(self):
160 self.assertAsArgv([u'command', u'\xe5'], 'command \xc3\xa5')
161
162
163class TestLPForkingServiceParseEnv(tests.TestCase):
164
165 def assertEnv(self, env, env_str):
166 self.assertEqual(env, lpserve.LPForkingService.parse_env(env_str))
167
168 def assertInvalid(self, env_str):
169 self.assertRaises(ValueError, lpserve.LPForkingService.parse_env,
170 env_str)
171
172 def test_no_entries(self):
173 self.assertEnv({}, 'end\n')
174
175 def test_one_entries(self):
176 self.assertEnv({'BZR_EMAIL': 'joe@foo.com'},
177 'BZR_EMAIL: joe@foo.com\n'
178 'end\n')
179
180 def test_two_entries(self):
181 self.assertEnv({'BZR_EMAIL': 'joe@foo.com', 'BAR': 'foo'},
182 'BZR_EMAIL: joe@foo.com\n'
183 'BAR: foo\n'
184 'end\n')
185
186 def test_invalid_empty(self):
187 self.assertInvalid('')
188
189 def test_invalid_end(self):
190 self.assertInvalid("BZR_EMAIL: joe@foo.com\n")
191
192 def test_invalid_entry(self):
193 self.assertInvalid("BZR_EMAIL joe@foo.com\nend\n")
194
195
196class TestLPForkingService(TestCaseWithLPForkingService):
197
198 def test_send_quit_message(self):
199 response = self.send_message_to_service('quit\n')
200 self.assertEqual('ok\nquit command requested... exiting\n', response)
201 self.service.service_stopped.wait(10.0)
202 self.assertTrue(self.service.service_stopped.isSet())
203
204 def test_send_invalid_message_fails(self):
205 response = self.send_message_to_service('unknown\n')
206 self.assertStartsWith(response, 'FAILURE')
207
208 def test_send_hello_heartbeat(self):
209 response = self.send_message_to_service('hello\n')
210 self.assertEqual('ok\nyep, still alive\n', response)
211
212 def test_hello_supports_crlf(self):
213 # telnet seems to always write in text mode. It is nice to be able to
214 # debug with simple telnet, so lets support it.
215 response = self.send_message_to_service('hello\r\n')
216 self.assertEqual('ok\nyep, still alive\n', response)
217
218 def test_send_simple_fork(self):
219 response = self.send_message_to_service('fork rocks\n')
220 self.assertEqual('ok\nfake forking\n', response)
221 self.assertEqual([(['rocks'], {})], self.service.fork_log)
222
223 def test_send_fork_env_with_empty_env(self):
224 response = self.send_message_to_service(
225 'fork-env rocks\n'
226 'end\n')
227 self.assertEqual('ok\nfake forking\n', response)
228 self.assertEqual([(['rocks'], {})], self.service.fork_log)
229
230 def test_send_fork_env_with_env(self):
231 response = self.send_message_to_service(
232 'fork-env rocks\n'
233 'BZR_EMAIL: joe@example.com\n'
234 'end\n')
235 self.assertEqual('ok\nfake forking\n', response)
236 self.assertEqual([(['rocks'], {'BZR_EMAIL': 'joe@example.com'})],
237 self.service.fork_log)
238
239 def test_send_fork_env_slowly(self):
240 response = self.send_message_to_service(
241 'fork-env rocks\n'
242 'BZR_EMAIL: joe@example.com\n'
243 'end\n', one_byte_at_a_time=True)
244 self.assertEqual('ok\nfake forking\n', response)
245 self.assertEqual([(['rocks'], {'BZR_EMAIL': 'joe@example.com'})],
246 self.service.fork_log)
247 # It should work with 'crlf' endings as well
248 response = self.send_message_to_service(
249 'fork-env rocks\r\n'
250 'BZR_EMAIL: joe@example.com\r\n'
251 'end\r\n', one_byte_at_a_time=True)
252 self.assertEqual('ok\nfake forking\n', response)
253 self.assertEqual([(['rocks'], {'BZR_EMAIL': 'joe@example.com'}),
254 (['rocks'], {'BZR_EMAIL': 'joe@example.com'})],
255 self.service.fork_log)
256
257 def test_send_incomplete_fork_env_timeout(self):
258 # We should get a failure message if we can't quickly read the whole
259 # content
260 response = self.send_message_to_service(
261 'fork-env rocks\n'
262 'BZR_EMAIL: joe@example.com\n',
263 one_byte_at_a_time=True)
264 # Note that we *don't* send a final 'end\n'
265 self.assertStartsWith(response, 'FAILURE\n')
266
267 def test_send_incomplete_request_timeout(self):
268 # Requests end with '\n', send one without it
269 response = self.send_message_to_service('hello',
270 one_byte_at_a_time=True)
271 self.assertStartsWith(response, 'FAILURE\n')
272
273
274class TestCaseWithSubprocess(tests.TestCaseWithTransport):
275 """Override the bzr start_bzr_subprocess command.
276
277 The launchpad infrastructure requires a fair amount of configuration to get
278 paths, etc correct. So this provides that work.
279 """
280
281 def get_python_path(self):
282 """Return the path to the Python interpreter."""
283 return '%s/bin/py' % config.root
284
285 def start_bzr_subprocess(self, process_args, env_changes=None,
286 working_dir=None):
287 """Start bzr in a subprocess for testing.
288
289 Copied and modified from `bzrlib.tests.TestCase.start_bzr_subprocess`.
290 This version removes some of the skipping stuff, some of the
291 irrelevant comments (e.g. about win32) and uses Launchpad's own
292 mechanisms for getting the path to 'bzr'.
293
294 Comments starting with 'LAUNCHPAD' are comments about our
295 modifications.
296 """
297 if env_changes is None:
298 env_changes = {}
299 env_changes['BZR_PLUGIN_PATH'] = get_BZR_PLUGIN_PATH_for_subprocess()
300 old_env = {}
301
302 def cleanup_environment():
303 for env_var, value in env_changes.iteritems():
304 old_env[env_var] = osutils.set_or_unset_env(env_var, value)
305
306 def restore_environment():
307 for env_var, value in old_env.iteritems():
308 osutils.set_or_unset_env(env_var, value)
309
310 cwd = None
311 if working_dir is not None:
312 cwd = osutils.getcwd()
313 os.chdir(working_dir)
314
315 # LAUNCHPAD: Because of buildout, we need to get a custom Python
316 # binary, not sys.executable.
317 python_path = self.get_python_path()
318 # LAUNCHPAD: We can't use self.get_bzr_path(), since it'll find
319 # lib/bzrlib, rather than the path to sourcecode/bzr/bzr.
320 bzr_path = get_bzr_path()
321 try:
322 cleanup_environment()
323 command = [python_path, bzr_path]
324 command.extend(process_args)
325 process = self._popen(
326 command, stdin=subprocess.PIPE, stdout=subprocess.PIPE,
327 stderr=subprocess.PIPE)
328 finally:
329 restore_environment()
330 if cwd is not None:
331 os.chdir(cwd)
332
333 return process
334
335
336class TestCaseWithLPForkingServiceSubprocess(TestCaseWithSubprocess):
337 """Tests will get a separate process to communicate to.
338
339 The number of these tests should be small, because it is expensive to start
340 and stop the daemon.
341
342 TODO: This should probably use testresources, or layers somehow...
343 """
344
345 def setUp(self):
346 super(TestCaseWithLPForkingServiceSubprocess, self).setUp()
347 self.service_process, self.service_path = self.start_service_subprocess()
348 self.addCleanup(self.stop_service)
349
350 def start_conversation(self, message, one_byte_at_a_time=False):
351 """Start talking to the service, and get the initial response."""
352 client_sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
353 trace.mutter('sending %r to socket %s' % (message, self.service_path))
354 client_sock.connect(self.service_path)
355 if one_byte_at_a_time:
356 for byte in message:
357 client_sock.send(byte)
358 else:
359 client_sock.sendall(message)
360 response = client_sock.recv(1024)
361 trace.mutter('response: %r' % (response,))
362 if response.startswith("FAILURE"):
363 raise RuntimeError('Failed to send message: %r' % (response,))
364 return response, client_sock
365
366 def send_message_to_service(self, message, one_byte_at_a_time=False):
367 response, client_sock = self.start_conversation(message,
368 one_byte_at_a_time=one_byte_at_a_time)
369 client_sock.close()
370 return response
371
372 def send_fork_request(self, command, env=None):
373 if env is not None:
374 request_lines = ['fork-env %s\n' % (command,)]
375 for key, value in env.iteritems():
376 request_lines.append('%s: %s\n' % (key, value))
377 request_lines.append('end\n')
378 request = ''.join(request_lines)
379 else:
380 request = 'fork %s\n' % (command,)
381 response, sock = self.start_conversation(request)
382 ok, pid, path, tail = response.split('\n')
383 self.assertEqual('ok', ok)
384 self.assertEqual('', tail)
385 # Don't really care what it is, but should be an integer
386 pid = int(pid)
387 path = path.strip()
388 self.assertContainsRe(path, '/lp-forking-service-child-')
389 return path, pid, sock
390
391 def start_service_subprocess(self):
392 # Make sure this plugin is exposed to the subprocess
393 # SLOOWWW (~2 seconds, which is why we are doing the work anyway)
394 fd, tempname = tempfile.mkstemp(prefix='tmp-log-bzr-lp-forking-')
395 # I'm not 100% sure about when cleanup runs versus addDetail, but I
396 # think this will work.
397 self.addCleanup(os.remove, tempname)
398 def read_log():
399 f = os.fdopen(fd)
400 f.seek(0)
401 content = f.read()
402 f.close()
403 return [content]
404 self.addDetail('server-log', content.Content(
405 content.ContentType('text', 'plain', {"charset": "utf8"}),
406 read_log))
407 service_fd, path = tempfile.mkstemp(prefix='tmp-lp-service-',
408 suffix='.sock')
409 os.close(service_fd)
410 os.remove(path) # service wants create it as a socket
411 env_changes = {'BZR_PLUGIN_PATH': lpserve.__path__[0],
412 'BZR_LOG': tempname}
413 proc = self.start_bzr_subprocess(
414 ['lp-service', '--path', path, '--no-preload',
415 '--children-timeout=1'],
416 env_changes=env_changes)
417 trace.mutter('started lp-service subprocess')
418 # preload_line = proc.stderr.readline()
419 # self.assertStartsWith(preload_line, 'Preloading')
420 expected = 'Listening on socket: %s\n' % (path,)
421 path_line = proc.stderr.readline()
422 trace.mutter(path_line)
423 self.assertEqual(expected, path_line)
424 # The process won't delete it, so we do
425 return proc, path
426
427 def stop_service(self):
428 if self.service_process is None:
429 # Already stopped
430 return
431 # First, try to stop the service gracefully, by sending a 'quit'
432 # message
433 try:
434 response = self.send_message_to_service('quit\n')
435 except socket.error, e:
436 # Ignore a failure to connect, the service must be stopping/stopped
437 # already
438 response = None
439 tend = time.time() + 10.0
440 while self.service_process.poll() is None:
441 if time.time() > tend:
442 self.finish_bzr_subprocess(process=self.service_process,
443 send_signal=signal.SIGINT, retcode=3)
444 self.fail('Failed to quit gracefully after 10.0 seconds')
445 time.sleep(0.1)
446 if response is not None:
447 self.assertEqual('ok\nquit command requested... exiting\n',
448 response)
449
450 def _get_fork_handles(self, path):
451 trace.mutter('getting handles for: %s' % (path,))
452 stdin_path = os.path.join(path, 'stdin')
453 stdout_path = os.path.join(path, 'stdout')
454 stderr_path = os.path.join(path, 'stderr')
455 # Consider the ordering, the other side should open 'stdin' first, but
456 # we want it to block until we open the last one, or we race and it can
457 # delete the other handles before we get to open them.
458 child_stdin = open(stdin_path, 'wb')
459 child_stdout = open(stdout_path, 'rb')
460 child_stderr = open(stderr_path, 'rb')
461 return child_stdin, child_stdout, child_stderr
462
463 def communicate_with_fork(self, path, stdin=None):
464 child_stdin, child_stdout, child_stderr = self._get_fork_handles(path)
465 if stdin is not None:
466 child_stdin.write(stdin)
467 child_stdin.close()
468 stdout_content = child_stdout.read()
469 stderr_content = child_stderr.read()
470 return stdout_content, stderr_content
471
472 def assertReturnCode(self, expected_code, sock):
473 """Assert that we get the expected return code as a message."""
474 response = sock.recv(1024)
475 self.assertStartsWith(response, 'exited\n')
476 code = int(response.split('\n', 1)[1])
477 self.assertEqual(expected_code, code)
478
479 def test_fork_lp_serve_hello(self):
480 path, _, sock = self.send_fork_request('lp-serve --inet 2')
481 stdout_content, stderr_content = self.communicate_with_fork(path,
482 'hello\n')
483 self.assertEqual('ok\x012\n', stdout_content)
484 self.assertEqual('', stderr_content)
485 self.assertReturnCode(0, sock)
486
487 def test_fork_replay(self):
488 path, _, sock = self.send_fork_request('launchpad-replay')
489 stdout_content, stderr_content = self.communicate_with_fork(path,
490 '1 hello\n2 goodbye\n1 maybe\n')
491 self.assertEqualDiff('hello\nmaybe\n', stdout_content)
492 self.assertEqualDiff('goodbye\n', stderr_content)
493 self.assertReturnCode(0, sock)
494
495 def test_just_run_service(self):
496 # Start and stop are defined in setUp()
497 pass
498
499 def test_fork_multiple_children(self):
500 paths = []
501 for idx in range(4):
502 paths.append(self.send_fork_request('launchpad-replay'))
503 # Do them out of order, as order shouldn't matter.
504 for idx in [3, 2, 0, 1]:
505 p, pid, sock = paths[idx]
506 stdout_msg = 'hello %d\n' % (idx,)
507 stderr_msg = 'goodbye %d\n' % (idx+1,)
508 stdout, stderr = self.communicate_with_fork(p,
509 '1 %s2 %s' % (stdout_msg, stderr_msg))
510 self.assertEqualDiff(stdout_msg, stdout)
511 self.assertEqualDiff(stderr_msg, stderr)
512 self.assertReturnCode(0, sock)
513
514 def test_fork_respects_env_vars(self):
515 path, pid, sock = self.send_fork_request('whoami',
516 env={'BZR_EMAIL': 'this_test@example.com'})
517 stdout_content, stderr_content = self.communicate_with_fork(path)
518 self.assertEqual('', stderr_content)
519 self.assertEqual('this_test@example.com\n', stdout_content)
520
521 def _check_exits_nicely(self, sig_id):
522 path, _, sock = self.send_fork_request('rocks')
523 self.assertEqual(None, self.service_process.poll())
524 # Now when we send SIGTERM, it should wait for the child to exit,
525 # before it tries to exit itself.
526 # In python2.6+ we could use self.service_process.terminate()
527 os.kill(self.service_process.pid, sig_id)
528 self.assertEqual(None, self.service_process.poll())
529 # Now talk to the child, so the service can close
530 stdout_content, stderr_content = self.communicate_with_fork(path)
531 self.assertEqual('It sure does!\n', stdout_content)
532 self.assertEqual('', stderr_content)
533 self.assertReturnCode(0, sock)
534 # And the process should exit cleanly
535 self.assertEqual(0, self.service_process.wait())
536
537 def test_sigterm_exits_nicely(self):
538 self._check_exits_nicely(signal.SIGTERM)
539
540 def test_sigint_exits_nicely(self):
541 self._check_exits_nicely(signal.SIGINT)
0542
=== modified file 'configs/development/launchpad-lazr.conf'
--- configs/development/launchpad-lazr.conf 2010-09-20 21:35:21 +0000
+++ configs/development/launchpad-lazr.conf 2010-10-04 22:08:24 +0000
@@ -76,6 +76,7 @@
76lp_url_hosts: dev76lp_url_hosts: dev
77access_log: /var/tmp/bazaar.launchpad.dev/codehosting-access.log77access_log: /var/tmp/bazaar.launchpad.dev/codehosting-access.log
78blacklisted_hostnames:78blacklisted_hostnames:
79use_forking_daemon: True
7980
80[codeimport]81[codeimport]
81bazaar_branch_store: file:///tmp/bazaar-branches82bazaar_branch_store: file:///tmp/bazaar-branches
8283
=== modified file 'database/replication/Makefile'
--- database/replication/Makefile 2010-07-26 08:12:20 +0000
+++ database/replication/Makefile 2010-10-04 22:08:24 +0000
@@ -14,8 +14,9 @@
14# To test the staging rebuild script:14# To test the staging rebuild script:
15#15#
16# $ cd database/replication16# $ cd database/replication
17# $ pg_dump --format=c launchpad_dev > launchpad.dump17# $ pg_dump --format=c launchpad_dev | bzip2 -c > launchpad.dump.bz2
18# $ make stagingsetup STAGING_CONFIG=dev-staging STAGING_DUMP=launchpad.dump18# $ make stagingsetup \
19# STAGING_CONFIG=dev-staging STAGING_DUMP=launchpad.dump.bz2
19# $ make stagingswitch STAGING_CONFIG=dev-staging20# $ make stagingswitch STAGING_CONFIG=dev-staging
20#21#
21# To restore a dogfood database:22# To restore a dogfood database:
@@ -46,7 +47,12 @@
4647
47CREATEDB_83=createdb --encoding=UTF848CREATEDB_83=createdb --encoding=UTF8
48CREATEDB_84=createdb --encoding=UTF8 --locale=C --template=template049CREATEDB_84=createdb --encoding=UTF8 --locale=C --template=template0
49CREATEDB=${CREATEDB_83}50CREATEDB=${CREATEDB_84}
51
52# Set this to --exit-on-error once our dumps are coming from a PG 8.4
53# source. Currently, the PG 8.3 dumps generate some spurious errors
54# when being restored into a PG 8.4 database.
55EXIT_ON_ERROR=
5056
51# Turn off output silencing so we can see details of staging deployments.57# Turn off output silencing so we can see details of staging deployments.
52# Without the timestamps, we are unable to estimate production deployment58# Without the timestamps, we are unable to estimate production deployment
@@ -102,8 +108,9 @@
102 # Restore the database. We need to restore permissions, despite108 # Restore the database. We need to restore permissions, despite
103 # later running security.py, to pull in permissions granted on109 # later running security.py, to pull in permissions granted on
104 # production to users not maintained by security.py.110 # production to users not maintained by security.py.
105 bunzip2 --stdout ${STAGING_DUMP} | \111 # Stop ignoring error code after dumps come from an 8.4 system.
106 pg_restore --dbname=lpmain_staging_new --no-owner --exit-on-error112 -bunzip2 --stdout ${STAGING_DUMP} | \
113 pg_restore --dbname=lpmain_staging_new --no-owner ${EXIT_ON_ERROR}
107 # Uninstall Slony-I if it is installed - a pg_dump of a DB with114 # Uninstall Slony-I if it is installed - a pg_dump of a DB with
108 # Slony-I installed isn't usable without this step.115 # Slony-I installed isn't usable without this step.
109 LPCONFIG=${NEW_STAGING_CONFIG} ./repair-restored-db.py116 LPCONFIG=${NEW_STAGING_CONFIG} ./repair-restored-db.py
@@ -136,8 +143,9 @@
136143
137dogfood:144dogfood:
138 ${CREATEDB} ${DOGFOOD_DBNAME}145 ${CREATEDB} ${DOGFOOD_DBNAME}
139 pg_restore --dbname=${DOGFOOD_DBNAME} --no-acl --no-owner \146 # Stop ignoring error code after are dumps come from an 8.4 system.
140 --exit-on-error ${DOGFOOD_DUMP}147 -pg_restore --dbname=${DOGFOOD_DBNAME} --no-acl --no-owner \
148 ${EXIT_ON_ERROR} ${DOGFOOD_DUMP}
141 ./repair-restored-db.py -d ${DOGFOOD_DBNAME}149 ./repair-restored-db.py -d ${DOGFOOD_DBNAME}
142 ../schema/upgrade.py -d ${DOGFOOD_DBNAME}150 ../schema/upgrade.py -d ${DOGFOOD_DBNAME}
143 ../schema/fti.py -d ${DOGFOOD_DBNAME}151 ../schema/fti.py -d ${DOGFOOD_DBNAME}
144152
=== modified file 'database/replication/slon_ctl.py'
--- database/replication/slon_ctl.py 2010-05-19 18:07:56 +0000
+++ database/replication/slon_ctl.py 2010-10-04 22:08:24 +0000
@@ -88,9 +88,11 @@
8888
8989
90def get_logfile(nickname):90def get_logfile(nickname):
91 logdir = config.database.replication_logdir
92 if not os.path.isabs(logdir):
93 logdir = os.path.normpath(os.path.join(config.root, logdir))
91 return os.path.join(94 return os.path.join(
92 config.root, 'database', 'replication',95 logdir, 'lpslon_%s_%s.log' % (nickname, config.instance_name))
93 'lpslon_%s_%s.log' % (nickname, config.instance_name))
9496
9597
96def start(log, nodes, lag=None):98def start(log, nodes, lag=None):
9799
=== modified file 'database/sampledata/current-dev.sql'
--- database/sampledata/current-dev.sql 2010-09-23 19:10:34 +0000
+++ database/sampledata/current-dev.sql 2010-10-04 22:08:24 +0000
@@ -1837,14 +1837,14 @@
18371837
1838ALTER TABLE distroarchseries DISABLE TRIGGER ALL;1838ALTER TABLE distroarchseries DISABLE TRIGGER ALL;
18391839
1840INSERT INTO distroarchseries (id, distroseries, processorfamily, architecturetag, owner, official, package_count, date_created, supports_virtualized) VALUES (1, 1, 1, 'i386', 1, true, 5, '2006-10-16 18:31:43.454475', true);1840INSERT INTO distroarchseries (id, distroseries, processorfamily, architecturetag, owner, official, package_count, date_created, supports_virtualized, enabled) VALUES (1, 1, 1, 'i386', 1, true, 5, '2006-10-16 18:31:43.454475', true, true);
1841INSERT INTO distroarchseries (id, distroseries, processorfamily, architecturetag, owner, official, package_count, date_created, supports_virtualized) VALUES (6, 3, 1, 'i386', 1, true, 1, '2006-10-16 18:31:43.456532', true);1841INSERT INTO distroarchseries (id, distroseries, processorfamily, architecturetag, owner, official, package_count, date_created, supports_virtualized, enabled) VALUES (6, 3, 1, 'i386', 1, true, 1, '2006-10-16 18:31:43.456532', true, true);
1842INSERT INTO distroarchseries (id, distroseries, processorfamily, architecturetag, owner, official, package_count, date_created, supports_virtualized) VALUES (7, 6, 1, 'i386', 1, true, 0, '2006-10-16 18:31:43.457028', true);1842INSERT INTO distroarchseries (id, distroseries, processorfamily, architecturetag, owner, official, package_count, date_created, supports_virtualized, enabled) VALUES (7, 6, 1, 'i386', 1, true, 0, '2006-10-16 18:31:43.457028', true, true);
1843INSERT INTO distroarchseries (id, distroseries, processorfamily, architecturetag, owner, official, package_count, date_created, supports_virtualized) VALUES (8, 10, 1, 'i386', 1, true, 0, '2006-10-16 18:31:43.457484', true);1843INSERT INTO distroarchseries (id, distroseries, processorfamily, architecturetag, owner, official, package_count, date_created, supports_virtualized, enabled) VALUES (8, 10, 1, 'i386', 1, true, 0, '2006-10-16 18:31:43.457484', true, true);
1844INSERT INTO distroarchseries (id, distroseries, processorfamily, architecturetag, owner, official, package_count, date_created, supports_virtualized) VALUES (9, 13, 1, 'i386', 1, true, 0, '2006-10-16 18:31:43.457938', true);1844INSERT INTO distroarchseries (id, distroseries, processorfamily, architecturetag, owner, official, package_count, date_created, supports_virtualized, enabled) VALUES (9, 13, 1, 'i386', 1, true, 0, '2006-10-16 18:31:43.457938', true, true);
1845INSERT INTO distroarchseries (id, distroseries, processorfamily, architecturetag, owner, official, package_count, date_created, supports_virtualized) VALUES (10, 13, 3, 'amd64', 1, true, 0, '2006-10-16 18:31:43.458434', true);1845INSERT INTO distroarchseries (id, distroseries, processorfamily, architecturetag, owner, official, package_count, date_created, supports_virtualized, enabled) VALUES (10, 13, 3, 'amd64', 1, true, 0, '2006-10-16 18:31:43.458434', true, true);
1846INSERT INTO distroarchseries (id, distroseries, processorfamily, architecturetag, owner, official, package_count, date_created, supports_virtualized) VALUES (11, 3, 4, 'hppa', 1, false, 0, '2006-10-16 18:31:43.458892', false);1846INSERT INTO distroarchseries (id, distroseries, processorfamily, architecturetag, owner, official, package_count, date_created, supports_virtualized, enabled) VALUES (11, 3, 4, 'hppa', 1, false, 0, '2006-10-16 18:31:43.458892', false, true);
1847INSERT INTO distroarchseries (id, distroseries, processorfamily, architecturetag, owner, official, package_count, date_created, supports_virtualized) VALUES (12, 1, 4, 'hppa', 1, false, 0, '2006-10-16 18:31:43.459349', false);1847INSERT INTO distroarchseries (id, distroseries, processorfamily, architecturetag, owner, official, package_count, date_created, supports_virtualized, enabled) VALUES (12, 1, 4, 'hppa', 1, false, 0, '2006-10-16 18:31:43.459349', false, true);
18481848
18491849
1850ALTER TABLE distroarchseries ENABLE TRIGGER ALL;1850ALTER TABLE distroarchseries ENABLE TRIGGER ALL;
@@ -3092,25 +3092,25 @@
30923092
3093ALTER TABLE branchrevision DISABLE TRIGGER ALL;3093ALTER TABLE branchrevision DISABLE TRIGGER ALL;
30943094
3095INSERT INTO branchrevision (id, sequence, branch, revision) VALUES (1, 1, 10, 1);3095INSERT INTO branchrevision (sequence, branch, revision) VALUES (1, 10, 1);
3096INSERT INTO branchrevision (id, sequence, branch, revision) VALUES (2, 1, 11, 2);3096INSERT INTO branchrevision (sequence, branch, revision) VALUES (1, 11, 2);
3097INSERT INTO branchrevision (id, sequence, branch, revision) VALUES (3, 1, 12, 3);3097INSERT INTO branchrevision (sequence, branch, revision) VALUES (1, 12, 3);
3098INSERT INTO branchrevision (id, sequence, branch, revision) VALUES (4, 1, 20, 4);3098INSERT INTO branchrevision (sequence, branch, revision) VALUES (1, 20, 4);
3099INSERT INTO branchrevision (id, sequence, branch, revision) VALUES (5, 2, 20, 5);3099INSERT INTO branchrevision (sequence, branch, revision) VALUES (1, 21, 4);
3100INSERT INTO branchrevision (id, sequence, branch, revision) VALUES (6, 3, 20, 6);3100INSERT INTO branchrevision (sequence, branch, revision) VALUES (2, 20, 5);
3101INSERT INTO branchrevision (id, sequence, branch, revision) VALUES (7, 4, 20, 7);3101INSERT INTO branchrevision (sequence, branch, revision) VALUES (2, 21, 5);
3102INSERT INTO branchrevision (id, sequence, branch, revision) VALUES (8, 5, 20, 8);3102INSERT INTO branchrevision (sequence, branch, revision) VALUES (3, 20, 6);
3103INSERT INTO branchrevision (id, sequence, branch, revision) VALUES (9, 6, 20, 9);3103INSERT INTO branchrevision (sequence, branch, revision) VALUES (3, 21, 10);
3104INSERT INTO branchrevision (id, sequence, branch, revision) VALUES (10, 1, 21, 4);3104INSERT INTO branchrevision (sequence, branch, revision) VALUES (4, 20, 7);
3105INSERT INTO branchrevision (id, sequence, branch, revision) VALUES (11, 2, 21, 5);3105INSERT INTO branchrevision (sequence, branch, revision) VALUES (4, 21, 11);
3106INSERT INTO branchrevision (id, sequence, branch, revision) VALUES (12, 3, 21, 10);3106INSERT INTO branchrevision (sequence, branch, revision) VALUES (5, 20, 8);
3107INSERT INTO branchrevision (id, sequence, branch, revision) VALUES (13, 4, 21, 11);3107INSERT INTO branchrevision (sequence, branch, revision) VALUES (5, 21, 8);
3108INSERT INTO branchrevision (id, sequence, branch, revision) VALUES (14, 5, 21, 8);3108INSERT INTO branchrevision (sequence, branch, revision) VALUES (6, 20, 9);
3109INSERT INTO branchrevision (id, sequence, branch, revision) VALUES (15, 6, 21, 9);3109INSERT INTO branchrevision (sequence, branch, revision) VALUES (6, 21, 9);
3110INSERT INTO branchrevision (id, sequence, branch, revision) VALUES (16, NULL, 20, 10);3110INSERT INTO branchrevision (sequence, branch, revision) VALUES (NULL, 20, 10);
3111INSERT INTO branchrevision (id, sequence, branch, revision) VALUES (17, NULL, 20, 11);3111INSERT INTO branchrevision (sequence, branch, revision) VALUES (NULL, 20, 11);
3112INSERT INTO branchrevision (id, sequence, branch, revision) VALUES (18, NULL, 21, 6);3112INSERT INTO branchrevision (sequence, branch, revision) VALUES (NULL, 21, 6);
3113INSERT INTO branchrevision (id, sequence, branch, revision) VALUES (19, NULL, 21, 7);3113INSERT INTO branchrevision (sequence, branch, revision) VALUES (NULL, 21, 7);
31143114
31153115
3116ALTER TABLE branchrevision ENABLE TRIGGER ALL;3116ALTER TABLE branchrevision ENABLE TRIGGER ALL;
@@ -3333,42 +3333,42 @@
33333333
3334ALTER TABLE bugmessage DISABLE TRIGGER ALL;3334ALTER TABLE bugmessage DISABLE TRIGGER ALL;
33353335
3336INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible) VALUES (1, 2, 1, NULL, NULL, true);3336INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible, index) VALUES (1, 2, 1, NULL, NULL, true, NULL);
3337INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible) VALUES (2, 1, 3, NULL, NULL, true);3337INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible, index) VALUES (2, 1, 3, NULL, NULL, true, NULL);
3338INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible) VALUES (3, 1, 4, NULL, NULL, true);3338INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible, index) VALUES (3, 1, 4, NULL, NULL, true, NULL);
3339INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible) VALUES (4, 2, 5, NULL, NULL, true);3339INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible, index) VALUES (4, 2, 5, NULL, NULL, true, NULL);
3340INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible) VALUES (5, 2, 6, NULL, NULL, true);3340INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible, index) VALUES (5, 2, 6, NULL, NULL, true, NULL);
3341INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible) VALUES (6, 4, 7, NULL, NULL, true);3341INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible, index) VALUES (6, 4, 7, NULL, NULL, true, NULL);
3342INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible) VALUES (7, 5, 8, NULL, NULL, true);3342INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible, index) VALUES (7, 5, 8, NULL, NULL, true, NULL);
3343INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible) VALUES (8, 6, 9, NULL, NULL, true);3343INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible, index) VALUES (8, 6, 9, NULL, NULL, true, NULL);
3344INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible) VALUES (9, 3, 10, NULL, NULL, true);3344INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible, index) VALUES (9, 3, 10, NULL, NULL, true, NULL);
3345INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible) VALUES (10, 7, 11, NULL, NULL, true);3345INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible, index) VALUES (10, 7, 11, NULL, NULL, true, NULL);
3346INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible) VALUES (11, 8, 14, NULL, NULL, true);3346INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible, index) VALUES (11, 8, 14, NULL, NULL, true, NULL);
3347INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible) VALUES (12, 9, 15, NULL, NULL, true);3347INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible, index) VALUES (12, 9, 15, NULL, NULL, true, NULL);
3348INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible) VALUES (13, 10, 17, NULL, NULL, true);3348INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible, index) VALUES (13, 10, 17, NULL, NULL, true, NULL);
3349INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible) VALUES (14, 10, 16, NULL, NULL, true);3349INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible, index) VALUES (14, 10, 16, NULL, NULL, true, NULL);
3350INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible) VALUES (15, 11, 24, NULL, NULL, true);3350INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible, index) VALUES (15, 11, 24, NULL, NULL, true, NULL);
3351INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible) VALUES (16, 11, 25, NULL, NULL, true);3351INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible, index) VALUES (16, 11, 25, NULL, NULL, true, NULL);
3352INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible) VALUES (17, 11, 26, NULL, NULL, true);3352INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible, index) VALUES (17, 11, 26, NULL, NULL, true, NULL);
3353INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible) VALUES (18, 11, 27, NULL, NULL, true);3353INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible, index) VALUES (18, 11, 27, NULL, NULL, true, NULL);
3354INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible) VALUES (19, 11, 28, NULL, NULL, true);3354INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible, index) VALUES (19, 11, 28, NULL, NULL, true, NULL);
3355INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible) VALUES (20, 11, 29, NULL, NULL, true);3355INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible, index) VALUES (20, 11, 29, NULL, NULL, true, NULL);
3356INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible) VALUES (21, 11, 30, NULL, NULL, true);3356INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible, index) VALUES (21, 11, 30, NULL, NULL, true, NULL);
3357INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible) VALUES (22, 12, 31, NULL, NULL, true);3357INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible, index) VALUES (22, 12, 31, NULL, NULL, true, NULL);
3358INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible) VALUES (23, 12, 33, NULL, NULL, true);3358INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible, index) VALUES (23, 12, 33, NULL, NULL, true, NULL);
3359INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible) VALUES (24, 12, 34, NULL, NULL, true);3359INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible, index) VALUES (24, 12, 34, NULL, NULL, true, NULL);
3360INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible) VALUES (25, 12, 35, NULL, NULL, true);3360INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible, index) VALUES (25, 12, 35, NULL, NULL, true, NULL);
3361INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible) VALUES (26, 12, 36, NULL, NULL, true);3361INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible, index) VALUES (26, 12, 36, NULL, NULL, true, NULL);
3362INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible) VALUES (27, 13, 37, NULL, NULL, true);3362INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible, index) VALUES (27, 13, 37, NULL, NULL, true, NULL);
3363INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible) VALUES (28, 13, 38, NULL, NULL, true);3363INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible, index) VALUES (28, 13, 38, NULL, NULL, true, NULL);
3364INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible) VALUES (29, 14, 39, NULL, NULL, true);3364INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible, index) VALUES (29, 14, 39, NULL, NULL, true, NULL);
3365INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible) VALUES (30, 15, 40, NULL, NULL, true);3365INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible, index) VALUES (30, 15, 40, NULL, NULL, true, NULL);
3366INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible) VALUES (31, 15, 44, 11, '<4284D7D1.6010208@gmx.de>', true);3366INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible, index) VALUES (31, 15, 44, 11, '<4284D7D1.6010208@gmx.de>', true, NULL);
3367INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible) VALUES (32, 15, 45, 11, '<20050517185429.GB20786@spring.luon.net>', true);3367INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible, index) VALUES (32, 15, 45, 11, '<20050517185429.GB20786@spring.luon.net>', true, NULL);
3368INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible) VALUES (33, 15, 46, 11, '<428A44E9.6090802@gmx.de>', true);3368INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible, index) VALUES (33, 15, 46, 11, '<428A44E9.6090802@gmx.de>', true, NULL);
3369INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible) VALUES (34, 15, 47, 11, '<20050517202044.GA23231@spring.luon.net>', true);3369INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible, index) VALUES (34, 15, 47, 11, '<20050517202044.GA23231@spring.luon.net>', true, NULL);
3370INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible) VALUES (35, 15, 48, 11, '<20050617140011.GA15638@piware.de>', true);3370INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible, index) VALUES (35, 15, 48, 11, '<20050617140011.GA15638@piware.de>', true, NULL);
3371INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible) VALUES (36, 15, 49, 11, '<42BD2E36.9090809@gmx.de>', true);3371INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible, index) VALUES (36, 15, 49, 11, '<42BD2E36.9090809@gmx.de>', true, NULL);
33723372
33733373
3374ALTER TABLE bugmessage ENABLE TRIGGER ALL;3374ALTER TABLE bugmessage ENABLE TRIGGER ALL;
@@ -3792,6 +3792,27 @@
3792ALTER TABLE bugtrackeralias ENABLE TRIGGER ALL;3792ALTER TABLE bugtrackeralias ENABLE TRIGGER ALL;
37933793
37943794
3795ALTER TABLE bugtrackercomponentgroup DISABLE TRIGGER ALL;
3796
3797
3798
3799ALTER TABLE bugtrackercomponentgroup ENABLE TRIGGER ALL;
3800
3801
3802ALTER TABLE distributionsourcepackage DISABLE TRIGGER ALL;
3803
3804
3805
3806ALTER TABLE distributionsourcepackage ENABLE TRIGGER ALL;
3807
3808
3809ALTER TABLE bugtrackercomponent DISABLE TRIGGER ALL;
3810
3811
3812
3813ALTER TABLE bugtrackercomponent ENABLE TRIGGER ALL;
3814
3815
3795ALTER TABLE bugtrackerperson DISABLE TRIGGER ALL;3816ALTER TABLE bugtrackerperson DISABLE TRIGGER ALL;
37963817
37973818
@@ -3993,6 +4014,13 @@
3993ALTER TABLE distributionbounty ENABLE TRIGGER ALL;4014ALTER TABLE distributionbounty ENABLE TRIGGER ALL;
39944015
39954016
4017ALTER TABLE distributionjob DISABLE TRIGGER ALL;
4018
4019
4020
4021ALTER TABLE distributionjob ENABLE TRIGGER ALL;
4022
4023
3996ALTER TABLE distributionmirror DISABLE TRIGGER ALL;4024ALTER TABLE distributionmirror DISABLE TRIGGER ALL;
39974025
3998INSERT INTO distributionmirror (id, distribution, name, http_base_url, ftp_base_url, rsync_base_url, displayname, description, owner, speed, country, content, official_candidate, enabled, date_created, whiteboard, status, date_reviewed, reviewer, country_dns_mirror) VALUES (1, 1, 'archive-mirror', 'http://localhost:11375/valid-mirror/', NULL, NULL, NULL, NULL, 1, 10, 75, 1, true, true, '2006-10-16 18:31:43.434567', NULL, 30, NULL, NULL, false);4026INSERT INTO distributionmirror (id, distribution, name, http_base_url, ftp_base_url, rsync_base_url, displayname, description, owner, speed, country, content, official_candidate, enabled, date_created, whiteboard, status, date_reviewed, reviewer, country_dns_mirror) VALUES (1, 1, 'archive-mirror', 'http://localhost:11375/valid-mirror/', NULL, NULL, NULL, NULL, 1, 10, 75, 1, true, true, '2006-10-16 18:31:43.434567', NULL, 30, NULL, NULL, false);
@@ -4010,13 +4038,6 @@
4010ALTER TABLE distributionmirror ENABLE TRIGGER ALL;4038ALTER TABLE distributionmirror ENABLE TRIGGER ALL;
40114039
40124040
4013ALTER TABLE distributionsourcepackage DISABLE TRIGGER ALL;
4014
4015
4016
4017ALTER TABLE distributionsourcepackage ENABLE TRIGGER ALL;
4018
4019
4020ALTER TABLE distributionsourcepackagecache DISABLE TRIGGER ALL;4041ALTER TABLE distributionsourcepackagecache DISABLE TRIGGER ALL;
40214042
4022INSERT INTO distributionsourcepackagecache (id, distribution, sourcepackagename, name, binpkgnames, binpkgsummaries, binpkgdescriptions, fti, changelog, archive) VALUES (1, 3, 19, 'alsa-utils', '', '', '', NULL, NULL, 1);4043INSERT INTO distributionsourcepackagecache (id, distribution, sourcepackagename, name, binpkgnames, binpkgsummaries, binpkgdescriptions, fti, changelog, archive) VALUES (1, 3, 19, 'alsa-utils', '', '', '', NULL, NULL, 1);
@@ -4567,6 +4588,13 @@
4567ALTER TABLE hwtestanswerdevice ENABLE TRIGGER ALL;4588ALTER TABLE hwtestanswerdevice ENABLE TRIGGER ALL;
45684589
45694590
4591ALTER TABLE incrementaldiff DISABLE TRIGGER ALL;
4592
4593
4594
4595ALTER TABLE incrementaldiff ENABLE TRIGGER ALL;
4596
4597
4570ALTER TABLE ircid DISABLE TRIGGER ALL;4598ALTER TABLE ircid DISABLE TRIGGER ALL;
45714599
4572INSERT INTO ircid (id, person, network, nickname) VALUES (1, 1, 'irc.freenode.net', 'mark');4600INSERT INTO ircid (id, person, network, nickname) VALUES (1, 1, 'irc.freenode.net', 'mark');
@@ -11141,6 +11169,13 @@
11141ALTER TABLE translationtemplateitem ENABLE TRIGGER ALL;11169ALTER TABLE translationtemplateitem ENABLE TRIGGER ALL;
1114211170
1114311171
11172ALTER TABLE translationtemplatesbuild DISABLE TRIGGER ALL;
11173
11174
11175
11176ALTER TABLE translationtemplatesbuild ENABLE TRIGGER ALL;
11177
11178
11144ALTER TABLE translator DISABLE TRIGGER ALL;11179ALTER TABLE translator DISABLE TRIGGER ALL;
1114511180
11146INSERT INTO translator (id, translationgroup, language, translator, datecreated, style_guide_url) VALUES (1, 1, 387, 53, '2005-07-13 13:14:19.748396', NULL);11181INSERT INTO translator (id, translationgroup, language, translator, datecreated, style_guide_url) VALUES (1, 1, 387, 53, '2005-07-13 13:14:19.748396', NULL);
1114711182
=== modified file 'database/sampledata/current.sql'
--- database/sampledata/current.sql 2010-09-04 20:38:35 +0000
+++ database/sampledata/current.sql 2010-10-04 22:08:24 +0000
@@ -792,6 +792,36 @@
792792
793793
794794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
795SET SESSION AUTHORIZATION DEFAULT;825SET SESSION AUTHORIZATION DEFAULT;
796826
797ALTER TABLE account DISABLE TRIGGER ALL;827ALTER TABLE account DISABLE TRIGGER ALL;
@@ -1819,14 +1849,14 @@
18191849
1820ALTER TABLE distroarchseries DISABLE TRIGGER ALL;1850ALTER TABLE distroarchseries DISABLE TRIGGER ALL;
18211851
1822INSERT INTO distroarchseries (id, distroseries, processorfamily, architecturetag, owner, official, package_count, date_created, supports_virtualized) VALUES (1, 1, 1, 'i386', 1, true, 5, '2006-10-16 18:31:43.454475', true);1852INSERT INTO distroarchseries (id, distroseries, processorfamily, architecturetag, owner, official, package_count, date_created, supports_virtualized, enabled) VALUES (1, 1, 1, 'i386', 1, true, 5, '2006-10-16 18:31:43.454475', true, true);
1823INSERT INTO distroarchseries (id, distroseries, processorfamily, architecturetag, owner, official, package_count, date_created, supports_virtualized) VALUES (6, 3, 1, 'i386', 1, true, 1, '2006-10-16 18:31:43.456532', true);1853INSERT INTO distroarchseries (id, distroseries, processorfamily, architecturetag, owner, official, package_count, date_created, supports_virtualized, enabled) VALUES (6, 3, 1, 'i386', 1, true, 1, '2006-10-16 18:31:43.456532', true, true);
1824INSERT INTO distroarchseries (id, distroseries, processorfamily, architecturetag, owner, official, package_count, date_created, supports_virtualized) VALUES (7, 6, 1, 'i386', 1, true, 0, '2006-10-16 18:31:43.457028', true);1854INSERT INTO distroarchseries (id, distroseries, processorfamily, architecturetag, owner, official, package_count, date_created, supports_virtualized, enabled) VALUES (7, 6, 1, 'i386', 1, true, 0, '2006-10-16 18:31:43.457028', true, true);
1825INSERT INTO distroarchseries (id, distroseries, processorfamily, architecturetag, owner, official, package_count, date_created, supports_virtualized) VALUES (8, 10, 1, 'i386', 1, true, 0, '2006-10-16 18:31:43.457484', true);1855INSERT INTO distroarchseries (id, distroseries, processorfamily, architecturetag, owner, official, package_count, date_created, supports_virtualized, enabled) VALUES (8, 10, 1, 'i386', 1, true, 0, '2006-10-16 18:31:43.457484', true, true);
1826INSERT INTO distroarchseries (id, distroseries, processorfamily, architecturetag, owner, official, package_count, date_created, supports_virtualized) VALUES (9, 13, 1, 'i386', 1, true, 0, '2006-10-16 18:31:43.457938', true);1856INSERT INTO distroarchseries (id, distroseries, processorfamily, architecturetag, owner, official, package_count, date_created, supports_virtualized, enabled) VALUES (9, 13, 1, 'i386', 1, true, 0, '2006-10-16 18:31:43.457938', true, true);
1827INSERT INTO distroarchseries (id, distroseries, processorfamily, architecturetag, owner, official, package_count, date_created, supports_virtualized) VALUES (10, 13, 3, 'amd64', 1, true, 0, '2006-10-16 18:31:43.458434', true);1857INSERT INTO distroarchseries (id, distroseries, processorfamily, architecturetag, owner, official, package_count, date_created, supports_virtualized, enabled) VALUES (10, 13, 3, 'amd64', 1, true, 0, '2006-10-16 18:31:43.458434', true, true);
1828INSERT INTO distroarchseries (id, distroseries, processorfamily, architecturetag, owner, official, package_count, date_created, supports_virtualized) VALUES (11, 3, 4, 'hppa', 1, false, 0, '2006-10-16 18:31:43.458892', false);1858INSERT INTO distroarchseries (id, distroseries, processorfamily, architecturetag, owner, official, package_count, date_created, supports_virtualized, enabled) VALUES (11, 3, 4, 'hppa', 1, false, 0, '2006-10-16 18:31:43.458892', false, true);
1829INSERT INTO distroarchseries (id, distroseries, processorfamily, architecturetag, owner, official, package_count, date_created, supports_virtualized) VALUES (12, 1, 4, 'hppa', 1, false, 0, '2006-10-16 18:31:43.459349', false);1859INSERT INTO distroarchseries (id, distroseries, processorfamily, architecturetag, owner, official, package_count, date_created, supports_virtualized, enabled) VALUES (12, 1, 4, 'hppa', 1, false, 0, '2006-10-16 18:31:43.459349', false, true);
18301860
18311861
1832ALTER TABLE distroarchseries ENABLE TRIGGER ALL;1862ALTER TABLE distroarchseries ENABLE TRIGGER ALL;
@@ -2238,8 +2268,8 @@
22382268
2239ALTER TABLE builder DISABLE TRIGGER ALL;2269ALTER TABLE builder DISABLE TRIGGER ALL;
22402270
2241INSERT INTO builder (id, processor, name, title, description, owner, speedindex, builderok, failnotes, virtualized, url, manual, date_created, vm_host, active) VALUES (1, 1, 'bob', 'Bob The Builder', 'The default build-slave', 61, NULL, true, NULL, false, 'http://localhost:8221/', false, '2006-10-16 18:31:43.226724', NULL, true);2271INSERT INTO builder (id, processor, name, title, description, owner, speedindex, builderok, failnotes, virtualized, url, manual, date_created, vm_host, active, failure_count) VALUES (1, 1, 'bob', 'Bob The Builder', 'The default build-slave', 61, NULL, true, NULL, false, 'http://localhost:8221/', false, '2006-10-16 18:31:43.226724', NULL, true, 0);
2242INSERT INTO builder (id, processor, name, title, description, owner, speedindex, builderok, failnotes, virtualized, url, manual, date_created, vm_host, active) VALUES (2, 1, 'frog', 'The frog builder', 'The untrusted build-slave', 61, NULL, false, NULL, true, 'http://localhost:9221/', false, '2006-10-31 18:31:43.226724', 'localhost-host.ppa', true);2272INSERT INTO builder (id, processor, name, title, description, owner, speedindex, builderok, failnotes, virtualized, url, manual, date_created, vm_host, active, failure_count) VALUES (2, 1, 'frog', 'The frog builder', 'The untrusted build-slave', 61, NULL, false, NULL, true, 'http://localhost:9221/', false, '2006-10-31 18:31:43.226724', 'localhost-host.ppa', true, 0);
22432273
22442274
2245ALTER TABLE builder ENABLE TRIGGER ALL;2275ALTER TABLE builder ENABLE TRIGGER ALL;
@@ -2247,30 +2277,30 @@
22472277
2248ALTER TABLE buildfarmjob DISABLE TRIGGER ALL;2278ALTER TABLE buildfarmjob DISABLE TRIGGER ALL;
22492279
2250INSERT INTO buildfarmjob (id, processor, virtualized, date_created, date_started, date_finished, date_first_dispatched, builder, status, log, job_type) VALUES (2, 1, false, '2004-09-27 11:57:13', '2004-09-27 11:55:13', '2004-09-27 11:57:14', NULL, 1, 1, 1, 1);2280INSERT INTO buildfarmjob (id, processor, virtualized, date_created, date_started, date_finished, date_first_dispatched, builder, status, log, job_type, failure_count) VALUES (2, 1, false, '2004-09-27 11:57:13', '2004-09-27 11:55:13', '2004-09-27 11:57:14', NULL, 1, 1, 1, 1, 0);
2251INSERT INTO buildfarmjob (id, processor, virtualized, date_created, date_started, date_finished, date_first_dispatched, builder, status, log, job_type) VALUES (6, 1, false, '2006-12-01 00:00:00', '2006-12-01 00:00:00', '2006-12-01 00:00:01', NULL, 1, 2, 1, 1);2281INSERT INTO buildfarmjob (id, processor, virtualized, date_created, date_started, date_finished, date_first_dispatched, builder, status, log, job_type, failure_count) VALUES (6, 1, false, '2006-12-01 00:00:00', '2006-12-01 00:00:00', '2006-12-01 00:00:01', NULL, 1, 2, 1, 1, 0);
2252INSERT INTO buildfarmjob (id, processor, virtualized, date_created, date_started, date_finished, date_first_dispatched, builder, status, log, job_type) VALUES (7, 1, false, '2005-03-24 00:00:00', '2005-03-24 23:58:43', '2005-03-25 00:00:03', NULL, 1, 1, 1, 1);2282INSERT INTO buildfarmjob (id, processor, virtualized, date_created, date_started, date_finished, date_first_dispatched, builder, status, log, job_type, failure_count) VALUES (7, 1, false, '2005-03-24 00:00:00', '2005-03-24 23:58:43', '2005-03-25 00:00:03', NULL, 1, 1, 1, 1, 0);
2253INSERT INTO buildfarmjob (id, processor, virtualized, date_created, date_started, date_finished, date_first_dispatched, builder, status, log, job_type) VALUES (8, 1, false, '2005-09-30 00:00:00', NULL, NULL, NULL, NULL, 6, NULL, 1);2283INSERT INTO buildfarmjob (id, processor, virtualized, date_created, date_started, date_finished, date_first_dispatched, builder, status, log, job_type, failure_count) VALUES (8, 1, false, '2005-09-30 00:00:00', NULL, NULL, NULL, NULL, 6, NULL, 1, 0);
2254INSERT INTO buildfarmjob (id, processor, virtualized, date_created, date_started, date_finished, date_first_dispatched, builder, status, log, job_type) VALUES (9, 1, false, '2005-10-01 00:00:00', '2005-10-01 23:56:41', '2005-10-02 00:00:01', NULL, 1, 2, 1, 1);2284INSERT INTO buildfarmjob (id, processor, virtualized, date_created, date_started, date_finished, date_first_dispatched, builder, status, log, job_type, failure_count) VALUES (9, 1, false, '2005-10-01 00:00:00', '2005-10-01 23:56:41', '2005-10-02 00:00:01', NULL, 1, 2, 1, 1, 0);
2255INSERT INTO buildfarmjob (id, processor, virtualized, date_created, date_started, date_finished, date_first_dispatched, builder, status, log, job_type) VALUES (10, 1, false, '2006-01-27 00:00:00', NULL, NULL, NULL, NULL, 1, NULL, 1);2285INSERT INTO buildfarmjob (id, processor, virtualized, date_created, date_started, date_finished, date_first_dispatched, builder, status, log, job_type, failure_count) VALUES (10, 1, false, '2006-01-27 00:00:00', NULL, NULL, NULL, NULL, 1, NULL, 1, 0);
2256INSERT INTO buildfarmjob (id, processor, virtualized, date_created, date_started, date_finished, date_first_dispatched, builder, status, log, job_type) VALUES (11, 1, false, '2006-02-14 00:00:00', NULL, NULL, NULL, NULL, 0, NULL, 1);2286INSERT INTO buildfarmjob (id, processor, virtualized, date_created, date_started, date_finished, date_first_dispatched, builder, status, log, job_type, failure_count) VALUES (11, 1, false, '2006-02-14 00:00:00', NULL, NULL, NULL, NULL, 0, NULL, 1, 0);
2257INSERT INTO buildfarmjob (id, processor, virtualized, date_created, date_started, date_finished, date_first_dispatched, builder, status, log, job_type) VALUES (12, 1, false, '2006-02-28 00:00:00', '2006-02-27 23:53:59', '2006-02-28 00:00:01', NULL, 1, 3, 1, 1);2287INSERT INTO buildfarmjob (id, processor, virtualized, date_created, date_started, date_finished, date_first_dispatched, builder, status, log, job_type, failure_count) VALUES (12, 1, false, '2006-02-28 00:00:00', '2006-02-27 23:53:59', '2006-02-28 00:00:01', NULL, 1, 3, 1, 1, 0);
2258INSERT INTO buildfarmjob (id, processor, virtualized, date_created, date_started, date_finished, date_first_dispatched, builder, status, log, job_type) VALUES (13, 1, false, '2006-03-21 00:00:00', '2006-03-21 00:58:33', '2006-03-21 01:00:03', NULL, 1, 5, 1, 1);2288INSERT INTO buildfarmjob (id, processor, virtualized, date_created, date_started, date_finished, date_first_dispatched, builder, status, log, job_type, failure_count) VALUES (13, 1, false, '2006-03-21 00:00:00', '2006-03-21 00:58:33', '2006-03-21 01:00:03', NULL, 1, 5, 1, 1, 0);
2259INSERT INTO buildfarmjob (id, processor, virtualized, date_created, date_started, date_finished, date_first_dispatched, builder, status, log, job_type) VALUES (14, 1, false, '2006-03-22 00:00:00', '2006-03-21 00:58:32', '2006-03-21 01:00:02', NULL, 1, 5, 1, 1);2289INSERT INTO buildfarmjob (id, processor, virtualized, date_created, date_started, date_finished, date_first_dispatched, builder, status, log, job_type, failure_count) VALUES (14, 1, false, '2006-03-22 00:00:00', '2006-03-21 00:58:32', '2006-03-21 01:00:02', NULL, 1, 5, 1, 1, 0);
2260INSERT INTO buildfarmjob (id, processor, virtualized, date_created, date_started, date_finished, date_first_dispatched, builder, status, log, job_type) VALUES (15, 1, false, '2006-03-22 00:00:01', '2006-03-21 00:58:30', '2006-03-21 01:00:00', NULL, 1, 5, 1, 1);2290INSERT INTO buildfarmjob (id, processor, virtualized, date_created, date_started, date_finished, date_first_dispatched, builder, status, log, job_type, failure_count) VALUES (15, 1, false, '2006-03-22 00:00:01', '2006-03-21 00:58:30', '2006-03-21 01:00:00', NULL, 1, 5, 1, 1, 0);
2261INSERT INTO buildfarmjob (id, processor, virtualized, date_created, date_started, date_finished, date_first_dispatched, builder, status, log, job_type) VALUES (16, 1, false, '2005-03-24 00:00:01', '2005-03-24 23:58:42', '2005-03-25 00:00:02', NULL, 1, 1, 1, 1);2291INSERT INTO buildfarmjob (id, processor, virtualized, date_created, date_started, date_finished, date_first_dispatched, builder, status, log, job_type, failure_count) VALUES (16, 1, false, '2005-03-24 00:00:01', '2005-03-24 23:58:42', '2005-03-25 00:00:02', NULL, 1, 1, 1, 1, 0);
2262INSERT INTO buildfarmjob (id, processor, virtualized, date_created, date_started, date_finished, date_first_dispatched, builder, status, log, job_type) VALUES (18, 1, false, '2004-09-27 11:57:14', '2004-09-27 11:55:12', '2004-09-27 11:57:13', NULL, 1, 1, 1, 1);2292INSERT INTO buildfarmjob (id, processor, virtualized, date_created, date_started, date_finished, date_first_dispatched, builder, status, log, job_type, failure_count) VALUES (18, 1, false, '2004-09-27 11:57:14', '2004-09-27 11:55:12', '2004-09-27 11:57:13', NULL, 1, 1, 1, 1, 0);
2263INSERT INTO buildfarmjob (id, processor, virtualized, date_created, date_started, date_finished, date_first_dispatched, builder, status, log, job_type) VALUES (19, 1, false, '2005-03-24 00:00:02', '2005-03-24 23:58:41', '2005-03-25 00:00:01', NULL, 1, 1, 1, 1);2293INSERT INTO buildfarmjob (id, processor, virtualized, date_created, date_started, date_finished, date_first_dispatched, builder, status, log, job_type, failure_count) VALUES (19, 1, false, '2005-03-24 00:00:02', '2005-03-24 23:58:41', '2005-03-25 00:00:01', NULL, 1, 1, 1, 1, 0);
2264INSERT INTO buildfarmjob (id, processor, virtualized, date_created, date_started, date_finished, date_first_dispatched, builder, status, log, job_type) VALUES (21, 1, false, '2006-12-01 00:00:01', NULL, NULL, NULL, NULL, 2, NULL, 1);2294INSERT INTO buildfarmjob (id, processor, virtualized, date_created, date_started, date_finished, date_first_dispatched, builder, status, log, job_type, failure_count) VALUES (21, 1, false, '2006-12-01 00:00:01', NULL, NULL, NULL, NULL, 2, NULL, 1, 0);
2265INSERT INTO buildfarmjob (id, processor, virtualized, date_created, date_started, date_finished, date_first_dispatched, builder, status, log, job_type) VALUES (22, 1, false, '2007-04-20 00:00:00', '2007-04-19 23:58:41', '2007-04-20 00:00:01', NULL, 1, 7, 1, 1);2295INSERT INTO buildfarmjob (id, processor, virtualized, date_created, date_started, date_finished, date_first_dispatched, builder, status, log, job_type, failure_count) VALUES (22, 1, false, '2007-04-20 00:00:00', '2007-04-19 23:58:41', '2007-04-20 00:00:01', NULL, 1, 7, 1, 1, 0);
2266INSERT INTO buildfarmjob (id, processor, virtualized, date_created, date_started, date_finished, date_first_dispatched, builder, status, log, job_type) VALUES (23, 1, false, '2006-04-11 12:00:00', NULL, NULL, NULL, NULL, 1, NULL, 1);2296INSERT INTO buildfarmjob (id, processor, virtualized, date_created, date_started, date_finished, date_first_dispatched, builder, status, log, job_type, failure_count) VALUES (23, 1, false, '2006-04-11 12:00:00', NULL, NULL, NULL, NULL, 1, NULL, 1, 0);
2267INSERT INTO buildfarmjob (id, processor, virtualized, date_created, date_started, date_finished, date_first_dispatched, builder, status, log, job_type) VALUES (24, 1, true, '2007-05-30 00:00:00', '2007-05-29 23:58:41', '2007-05-30 00:00:01', NULL, 1, 2, 1, 1);2297INSERT INTO buildfarmjob (id, processor, virtualized, date_created, date_started, date_finished, date_first_dispatched, builder, status, log, job_type, failure_count) VALUES (24, 1, true, '2007-05-30 00:00:00', '2007-05-29 23:58:41', '2007-05-30 00:00:01', NULL, 1, 2, 1, 1, 0);
2268INSERT INTO buildfarmjob (id, processor, virtualized, date_created, date_started, date_finished, date_first_dispatched, builder, status, log, job_type) VALUES (25, 1, true, '2007-07-08 12:00:00', NULL, NULL, NULL, NULL, 1, NULL, 1);2298INSERT INTO buildfarmjob (id, processor, virtualized, date_created, date_started, date_finished, date_first_dispatched, builder, status, log, job_type, failure_count) VALUES (25, 1, true, '2007-07-08 12:00:00', NULL, NULL, NULL, NULL, 1, NULL, 1, 0);
2269INSERT INTO buildfarmjob (id, processor, virtualized, date_created, date_started, date_finished, date_first_dispatched, builder, status, log, job_type) VALUES (26, 1, true, '2007-07-08 00:00:00', '2007-07-07 23:58:41', '2007-07-08 00:00:01', NULL, 1, 2, 1, 1);2299INSERT INTO buildfarmjob (id, processor, virtualized, date_created, date_started, date_finished, date_first_dispatched, builder, status, log, job_type, failure_count) VALUES (26, 1, true, '2007-07-08 00:00:00', '2007-07-07 23:58:41', '2007-07-08 00:00:01', NULL, 1, 2, 1, 1, 0);
2270INSERT INTO buildfarmjob (id, processor, virtualized, date_created, date_started, date_finished, date_first_dispatched, builder, status, log, job_type) VALUES (27, 1, true, '2007-07-24 00:00:00', '2007-07-23 23:58:41', '2007-07-24 00:00:01', NULL, 1, 1, 1, 1);2300INSERT INTO buildfarmjob (id, processor, virtualized, date_created, date_started, date_finished, date_first_dispatched, builder, status, log, job_type, failure_count) VALUES (27, 1, true, '2007-07-24 00:00:00', '2007-07-23 23:58:41', '2007-07-24 00:00:01', NULL, 1, 1, 1, 1, 0);
2271INSERT INTO buildfarmjob (id, processor, virtualized, date_created, date_started, date_finished, date_first_dispatched, builder, status, log, job_type) VALUES (28, 3, true, '2007-08-10 00:00:00', '2007-08-10 00:00:00', '2007-08-10 00:00:13', NULL, 1, 1, 1, 1);2301INSERT INTO buildfarmjob (id, processor, virtualized, date_created, date_started, date_finished, date_first_dispatched, builder, status, log, job_type, failure_count) VALUES (28, 3, true, '2007-08-10 00:00:00', '2007-08-10 00:00:00', '2007-08-10 00:00:13', NULL, 1, 1, 1, 1, 0);
2272INSERT INTO buildfarmjob (id, processor, virtualized, date_created, date_started, date_finished, date_first_dispatched, builder, status, log, job_type) VALUES (29, 1, false, '2007-08-09 21:54:18.553132', '2007-08-09 23:49:59', '2007-08-09 23:59:59', NULL, NULL, 1, NULL, 1);2302INSERT INTO buildfarmjob (id, processor, virtualized, date_created, date_started, date_finished, date_first_dispatched, builder, status, log, job_type, failure_count) VALUES (29, 1, false, '2007-08-09 21:54:18.553132', '2007-08-09 23:49:59', '2007-08-09 23:59:59', NULL, NULL, 1, NULL, 1, 0);
2273INSERT INTO buildfarmjob (id, processor, virtualized, date_created, date_started, date_finished, date_first_dispatched, builder, status, log, job_type) VALUES (30, 3, false, '2007-08-10 00:00:01', '2007-08-10 00:00:01', '2007-08-10 00:00:14', NULL, 1, 1, 1, 1);2303INSERT INTO buildfarmjob (id, processor, virtualized, date_created, date_started, date_finished, date_first_dispatched, builder, status, log, job_type, failure_count) VALUES (30, 3, false, '2007-08-10 00:00:01', '2007-08-10 00:00:01', '2007-08-10 00:00:14', NULL, 1, 1, 1, 1, 0);
22742304
22752305
2276ALTER TABLE buildfarmjob ENABLE TRIGGER ALL;2306ALTER TABLE buildfarmjob ENABLE TRIGGER ALL;
@@ -2365,29 +2395,29 @@
23652395
2366ALTER TABLE sourcepackagerelease DISABLE TRIGGER ALL;2396ALTER TABLE sourcepackagerelease DISABLE TRIGGER ALL;
23672397
2368INSERT INTO sourcepackagerelease (id, creator, version, dateuploaded, urgency, dscsigningkey, component, changelog_entry, builddepends, builddependsindep, architecturehintlist, dsc, section, maintainer, sourcepackagename, upload_distroseries, format, dsc_maintainer_rfc822, dsc_standards_version, dsc_format, dsc_binaries, upload_archive, copyright, build_conflicts, build_conflicts_indep, sourcepackage_recipe_build, changelog, user_defined_fields) VALUES (14, 1, '0.9', '2004-09-27 11:57:13', 1, NULL, 1, 'Mozilla dummy Changelog......', 'gcc-3.4-base, libc6 (>= 2.3.2.ds1-4), gcc-3.4 (>= 3.4.1-4sarge1), gcc-3.4 (<< 3.4.2), libstdc++6-dev (>= 3.4.1-4sarge1), pmount', 'bacula-common (= 1.34.6-2), bacula-director-common (= 1.34.6-2), postgresql-client (>= 7.4), pmount', 'any', NULL, 1, 1, 1, 1, 1, 'Mark Shuttleworth <mark@canonical.com>', '3.6.2', '1.0', 'mozilla-firefox', 1, NULL, 'gcc-4.0, pmount', 'gcc-4.0-base, pmount', NULL, NULL, NULL);2398INSERT INTO sourcepackagerelease (id, creator, version, dateuploaded, urgency, dscsigningkey, component, changelog_entry, builddepends, builddependsindep, architecturehintlist, dsc, section, maintainer, sourcepackagename, upload_distroseries, format, dsc_maintainer_rfc822, dsc_standards_version, dsc_format, dsc_binaries, upload_archive, copyright, build_conflicts, build_conflicts_indep, sourcepackage_recipe_build, changelog, user_defined_fields, homepage) VALUES (14, 1, '0.9', '2004-09-27 11:57:13', 1, NULL, 1, 'Mozilla dummy Changelog......', 'gcc-3.4-base, libc6 (>= 2.3.2.ds1-4), gcc-3.4 (>= 3.4.1-4sarge1), gcc-3.4 (<< 3.4.2), libstdc++6-dev (>= 3.4.1-4sarge1), pmount', 'bacula-common (= 1.34.6-2), bacula-director-common (= 1.34.6-2), postgresql-client (>= 7.4), pmount', 'any', NULL, 1, 1, 1, 1, 1, 'Mark Shuttleworth <mark@canonical.com>', '3.6.2', '1.0', 'mozilla-firefox', 1, NULL, 'gcc-4.0, pmount', 'gcc-4.0-base, pmount', NULL, NULL, NULL, NULL);
2369INSERT INTO sourcepackagerelease (id, creator, version, dateuploaded, urgency, dscsigningkey, component, changelog_entry, builddepends, builddependsindep, architecturehintlist, dsc, section, maintainer, sourcepackagename, upload_distroseries, format, dsc_maintainer_rfc822, dsc_standards_version, dsc_format, dsc_binaries, upload_archive, copyright, build_conflicts, build_conflicts_indep, sourcepackage_recipe_build, changelog, user_defined_fields) VALUES (15, 1, '1.0', '2004-09-27 11:57:13', 1, NULL, 1, NULL, NULL, NULL, 'all', NULL, 2, 1, 9, 3, 1, NULL, NULL, '1.0', NULL, 1, NULL, NULL, NULL, NULL, NULL, NULL);2399INSERT INTO sourcepackagerelease (id, creator, version, dateuploaded, urgency, dscsigningkey, component, changelog_entry, builddepends, builddependsindep, architecturehintlist, dsc, section, maintainer, sourcepackagename, upload_distroseries, format, dsc_maintainer_rfc822, dsc_standards_version, dsc_format, dsc_binaries, upload_archive, copyright, build_conflicts, build_conflicts_indep, sourcepackage_recipe_build, changelog, user_defined_fields, homepage) VALUES (15, 1, '1.0', '2004-09-27 11:57:13', 1, NULL, 1, NULL, NULL, NULL, 'all', NULL, 2, 1, 9, 3, 1, NULL, NULL, '1.0', NULL, 1, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
2370INSERT INTO sourcepackagerelease (id, creator, version, dateuploaded, urgency, dscsigningkey, component, changelog_entry, builddepends, builddependsindep, architecturehintlist, dsc, section, maintainer, sourcepackagename, upload_distroseries, format, dsc_maintainer_rfc822, dsc_standards_version, dsc_format, dsc_binaries, upload_archive, copyright, build_conflicts, build_conflicts_indep, sourcepackage_recipe_build, changelog, user_defined_fields) VALUES (16, 1, '1.0-1', '2005-03-10 16:30:00', 1, NULL, 1, NULL, NULL, NULL, 'any', NULL, 3, 1, 10, 3, 1, NULL, NULL, '1.0', NULL, 1, NULL, NULL, NULL, NULL, NULL, NULL);2400INSERT INTO sourcepackagerelease (id, creator, version, dateuploaded, urgency, dscsigningkey, component, changelog_entry, builddepends, builddependsindep, architecturehintlist, dsc, section, maintainer, sourcepackagename, upload_distroseries, format, dsc_maintainer_rfc822, dsc_standards_version, dsc_format, dsc_binaries, upload_archive, copyright, build_conflicts, build_conflicts_indep, sourcepackage_recipe_build, changelog, user_defined_fields, homepage) VALUES (16, 1, '1.0-1', '2005-03-10 16:30:00', 1, NULL, 1, NULL, NULL, NULL, 'any', NULL, 3, 1, 10, 3, 1, NULL, NULL, '1.0', NULL, 1, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
2371INSERT INTO sourcepackagerelease (id, creator, version, dateuploaded, urgency, dscsigningkey, component, changelog_entry, builddepends, builddependsindep, architecturehintlist, dsc, section, maintainer, sourcepackagename, upload_distroseries, format, dsc_maintainer_rfc822, dsc_standards_version, dsc_format, dsc_binaries, upload_archive, copyright, build_conflicts, build_conflicts_indep, sourcepackage_recipe_build, changelog, user_defined_fields) VALUES (17, 1, '0.99.6-1', '2005-03-14 18:00:00', 1, NULL, 1, NULL, NULL, NULL, 'i386', NULL, 2, 1, 10, 1, 1, NULL, NULL, '1.0', NULL, 1, NULL, NULL, NULL, NULL, NULL, NULL);2401INSERT INTO sourcepackagerelease (id, creator, version, dateuploaded, urgency, dscsigningkey, component, changelog_entry, builddepends, builddependsindep, architecturehintlist, dsc, section, maintainer, sourcepackagename, upload_distroseries, format, dsc_maintainer_rfc822, dsc_standards_version, dsc_format, dsc_binaries, upload_archive, copyright, build_conflicts, build_conflicts_indep, sourcepackage_recipe_build, changelog, user_defined_fields, homepage) VALUES (17, 1, '0.99.6-1', '2005-03-14 18:00:00', 1, NULL, 1, NULL, NULL, NULL, 'i386', NULL, 2, 1, 10, 1, 1, NULL, NULL, '1.0', NULL, 1, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
2372INSERT INTO sourcepackagerelease (id, creator, version, dateuploaded, urgency, dscsigningkey, component, changelog_entry, builddepends, builddependsindep, architecturehintlist, dsc, section, maintainer, sourcepackagename, upload_distroseries, format, dsc_maintainer_rfc822, dsc_standards_version, dsc_format, dsc_binaries, upload_archive, copyright, build_conflicts, build_conflicts_indep, sourcepackage_recipe_build, changelog, user_defined_fields) VALUES (20, 1, '0.1-1', '2005-03-24 20:59:31.439579', 1, NULL, 1, 'pmount (0.1-1) hoary; urgency=low2402INSERT INTO sourcepackagerelease (id, creator, version, dateuploaded, urgency, dscsigningkey, component, changelog_entry, builddepends, builddependsindep, architecturehintlist, dsc, section, maintainer, sourcepackagename, upload_distroseries, format, dsc_maintainer_rfc822, dsc_standards_version, dsc_format, dsc_binaries, upload_archive, copyright, build_conflicts, build_conflicts_indep, sourcepackage_recipe_build, changelog, user_defined_fields, homepage) VALUES (20, 1, '0.1-1', '2005-03-24 20:59:31.439579', 1, NULL, 1, 'pmount (0.1-1) hoary; urgency=low
23732403
2374 * Fix description (Malone #1)2404 * Fix description (Malone #1)
2375 * Fix debian (Debian #2000)2405 * Fix debian (Debian #2000)
2376 * Fix warty (Warty Ubuntu #1)2406 * Fix warty (Warty Ubuntu #1)
23772407
2378 -- Sample Person <test@canonical.com> Tue, 7 Feb 2006 12:10:08 +0300', NULL, NULL, 'all', NULL, 2, 1, 14, 3, 1, NULL, NULL, '1.0', NULL, 1, NULL, NULL, NULL, NULL, NULL, NULL);2408 -- Sample Person <test@canonical.com> Tue, 7 Feb 2006 12:10:08 +0300', NULL, NULL, 'all', NULL, 2, 1, 14, 3, 1, NULL, NULL, '1.0', NULL, 1, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
2379INSERT INTO sourcepackagerelease (id, creator, version, dateuploaded, urgency, dscsigningkey, component, changelog_entry, builddepends, builddependsindep, architecturehintlist, dsc, section, maintainer, sourcepackagename, upload_distroseries, format, dsc_maintainer_rfc822, dsc_standards_version, dsc_format, dsc_binaries, upload_archive, copyright, build_conflicts, build_conflicts_indep, sourcepackage_recipe_build, changelog, user_defined_fields) VALUES (21, 1, '0.1-2', '2005-06-24 20:59:31.439579', 1, NULL, 1, 'This is a placeholder changelog for pmount 0.1-2', NULL, NULL, 'powerpc', NULL, 1, 1, 14, 3, 1, NULL, NULL, '1.0', NULL, 1, NULL, NULL, NULL, NULL, NULL, NULL);2409INSERT INTO sourcepackagerelease (id, creator, version, dateuploaded, urgency, dscsigningkey, component, changelog_entry, builddepends, builddependsindep, architecturehintlist, dsc, section, maintainer, sourcepackagename, upload_distroseries, format, dsc_maintainer_rfc822, dsc_standards_version, dsc_format, dsc_binaries, upload_archive, copyright, build_conflicts, build_conflicts_indep, sourcepackage_recipe_build, changelog, user_defined_fields, homepage) VALUES (21, 1, '0.1-2', '2005-06-24 20:59:31.439579', 1, NULL, 1, 'This is a placeholder changelog for pmount 0.1-2', NULL, NULL, 'powerpc', NULL, 1, 1, 14, 3, 1, NULL, NULL, '1.0', NULL, 1, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
2380INSERT INTO sourcepackagerelease (id, creator, version, dateuploaded, urgency, dscsigningkey, component, changelog_entry, builddepends, builddependsindep, architecturehintlist, dsc, section, maintainer, sourcepackagename, upload_distroseries, format, dsc_maintainer_rfc822, dsc_standards_version, dsc_format, dsc_binaries, upload_archive, copyright, build_conflicts, build_conflicts_indep, sourcepackage_recipe_build, changelog, user_defined_fields) VALUES (23, 1, '1.0.8-1ubuntu1', '2005-02-03 08:50:00', 1, NULL, 1, 'alsa-utils (1.0.8-1ubuntu1) warty; urgency=low2410INSERT INTO sourcepackagerelease (id, creator, version, dateuploaded, urgency, dscsigningkey, component, changelog_entry, builddepends, builddependsindep, architecturehintlist, dsc, section, maintainer, sourcepackagename, upload_distroseries, format, dsc_maintainer_rfc822, dsc_standards_version, dsc_format, dsc_binaries, upload_archive, copyright, build_conflicts, build_conflicts_indep, sourcepackage_recipe_build, changelog, user_defined_fields, homepage) VALUES (23, 1, '1.0.8-1ubuntu1', '2005-02-03 08:50:00', 1, NULL, 1, 'alsa-utils (1.0.8-1ubuntu1) warty; urgency=low
23812411
2382 * Placeholder2412 * Placeholder
23832413
2384 -- Sample Person <test@canonical.com> Tue, 7 Feb 2006 12:10:08 +0300', NULL, NULL, 'all', NULL, 1, 1, 19, 1, 1, 'Mark Shuttleworth <mark@example.com>', '3.6.2', '1.0', 'alsa-mixer', 1, NULL, NULL, NULL, NULL, NULL, NULL);2414 -- Sample Person <test@canonical.com> Tue, 7 Feb 2006 12:10:08 +0300', NULL, NULL, 'all', NULL, 1, 1, 19, 1, 1, 'Mark Shuttleworth <mark@example.com>', '3.6.2', '1.0', 'alsa-mixer', 1, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
2385INSERT INTO sourcepackagerelease (id, creator, version, dateuploaded, urgency, dscsigningkey, component, changelog_entry, builddepends, builddependsindep, architecturehintlist, dsc, section, maintainer, sourcepackagename, upload_distroseries, format, dsc_maintainer_rfc822, dsc_standards_version, dsc_format, dsc_binaries, upload_archive, copyright, build_conflicts, build_conflicts_indep, sourcepackage_recipe_build, changelog, user_defined_fields) VALUES (24, 1, '1.0.9a-4', '2005-07-01 22:47:00', 1, NULL, 1, 'alsa-utils (1.0.9a-4) warty; urgency=low2415INSERT INTO sourcepackagerelease (id, creator, version, dateuploaded, urgency, dscsigningkey, component, changelog_entry, builddepends, builddependsindep, architecturehintlist, dsc, section, maintainer, sourcepackagename, upload_distroseries, format, dsc_maintainer_rfc822, dsc_standards_version, dsc_format, dsc_binaries, upload_archive, copyright, build_conflicts, build_conflicts_indep, sourcepackage_recipe_build, changelog, user_defined_fields, homepage) VALUES (24, 1, '1.0.9a-4', '2005-07-01 22:47:00', 1, NULL, 1, 'alsa-utils (1.0.9a-4) warty; urgency=low
23862416
2387 * Placeholder2417 * Placeholder
23882418
2389 -- Sample Person <test@canonical.com> Tue, 7 Feb 2006 12:10:08 +0300', NULL, NULL, 'any', NULL, 2, 1, 19, 8, 1, NULL, NULL, '1.0', NULL, 1, NULL, NULL, NULL, NULL, NULL, NULL);2419 -- Sample Person <test@canonical.com> Tue, 7 Feb 2006 12:10:08 +0300', NULL, NULL, 'any', NULL, 2, 1, 19, 8, 1, NULL, NULL, '1.0', NULL, 1, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
2390INSERT INTO sourcepackagerelease (id, creator, version, dateuploaded, urgency, dscsigningkey, component, changelog_entry, builddepends, builddependsindep, architecturehintlist, dsc, section, maintainer, sourcepackagename, upload_distroseries, format, dsc_maintainer_rfc822, dsc_standards_version, dsc_format, dsc_binaries, upload_archive, copyright, build_conflicts, build_conflicts_indep, sourcepackage_recipe_build, changelog, user_defined_fields) VALUES (25, 1, '1.0.9a-4ubuntu1', '2005-08-01 14:10:00', 1, NULL, 1, 'alsa-utils (1.0.9a-4ubuntu1) hoary; urgency=low2420INSERT INTO sourcepackagerelease (id, creator, version, dateuploaded, urgency, dscsigningkey, component, changelog_entry, builddepends, builddependsindep, architecturehintlist, dsc, section, maintainer, sourcepackagename, upload_distroseries, format, dsc_maintainer_rfc822, dsc_standards_version, dsc_format, dsc_binaries, upload_archive, copyright, build_conflicts, build_conflicts_indep, sourcepackage_recipe_build, changelog, user_defined_fields, homepage) VALUES (25, 1, '1.0.9a-4ubuntu1', '2005-08-01 14:10:00', 1, NULL, 1, 'alsa-utils (1.0.9a-4ubuntu1) hoary; urgency=low
23912421
2392 * Placeholder2422 * Placeholder
2393 LP: #102423 LP: #10
@@ -2396,22 +2426,22 @@
2396 LP: #7, #8,2426 LP: #7, #8,
2397 #112427 #11
23982428
2399 -- Sample Person <test@canonical.com> Tue, 7 Feb 2006 12:10:08 +0300', NULL, NULL, 'all', NULL, 1, 16, 19, 3, 1, NULL, NULL, '1.0', NULL, 1, NULL, NULL, NULL, NULL, NULL, NULL);2429 -- Sample Person <test@canonical.com> Tue, 7 Feb 2006 12:10:08 +0300', NULL, NULL, 'all', NULL, 1, 16, 19, 3, 1, NULL, NULL, '1.0', NULL, 1, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
2400INSERT INTO sourcepackagerelease (id, creator, version, dateuploaded, urgency, dscsigningkey, component, changelog_entry, builddepends, builddependsindep, architecturehintlist, dsc, section, maintainer, sourcepackagename, upload_distroseries, format, dsc_maintainer_rfc822, dsc_standards_version, dsc_format, dsc_binaries, upload_archive, copyright, build_conflicts, build_conflicts_indep, sourcepackage_recipe_build, changelog, user_defined_fields) VALUES (26, 1, 'cr.g7-37', '2005-12-22 18:19:00', 1, NULL, 1, NULL, NULL, NULL, 'i386', NULL, 1, 16, 20, 3, 1, NULL, NULL, '1.0', NULL, 1, NULL, NULL, NULL, NULL, NULL, NULL);2430INSERT INTO sourcepackagerelease (id, creator, version, dateuploaded, urgency, dscsigningkey, component, changelog_entry, builddepends, builddependsindep, architecturehintlist, dsc, section, maintainer, sourcepackagename, upload_distroseries, format, dsc_maintainer_rfc822, dsc_standards_version, dsc_format, dsc_binaries, upload_archive, copyright, build_conflicts, build_conflicts_indep, sourcepackage_recipe_build, changelog, user_defined_fields, homepage) VALUES (26, 1, 'cr.g7-37', '2005-12-22 18:19:00', 1, NULL, 1, NULL, NULL, NULL, 'i386', NULL, 1, 16, 20, 3, 1, NULL, NULL, '1.0', NULL, 1, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
2401INSERT INTO sourcepackagerelease (id, creator, version, dateuploaded, urgency, dscsigningkey, component, changelog_entry, builddepends, builddependsindep, architecturehintlist, dsc, section, maintainer, sourcepackagename, upload_distroseries, format, dsc_maintainer_rfc822, dsc_standards_version, dsc_format, dsc_binaries, upload_archive, copyright, build_conflicts, build_conflicts_indep, sourcepackage_recipe_build, changelog, user_defined_fields) VALUES (27, 1, 'b8p', '2006-02-10 11:19:00', 1, NULL, 1, 'libstdc++ (9.9-1) hoary; urgency=high2431INSERT INTO sourcepackagerelease (id, creator, version, dateuploaded, urgency, dscsigningkey, component, changelog_entry, builddepends, builddependsindep, architecturehintlist, dsc, section, maintainer, sourcepackagename, upload_distroseries, format, dsc_maintainer_rfc822, dsc_standards_version, dsc_format, dsc_binaries, upload_archive, copyright, build_conflicts, build_conflicts_indep, sourcepackage_recipe_build, changelog, user_defined_fields, homepage) VALUES (27, 1, 'b8p', '2006-02-10 11:19:00', 1, NULL, 1, 'libstdc++ (9.9-1) hoary; urgency=high
24022432
2403 * Placeholder2433 * Placeholder
24042434
2405 -- Sample Person <test@canonical.com> Tue, 10 Feb 2006 10:10:08 +0300', NULL, NULL, 'powerpc i386', NULL, 1, 16, 21, 3, 1, NULL, NULL, '1.0', NULL, 1, NULL, NULL, NULL, NULL, NULL, NULL);2435 -- Sample Person <test@canonical.com> Tue, 10 Feb 2006 10:10:08 +0300', NULL, NULL, 'powerpc i386', NULL, 1, 16, 21, 3, 1, NULL, NULL, '1.0', NULL, 1, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
2406INSERT INTO sourcepackagerelease (id, creator, version, dateuploaded, urgency, dscsigningkey, component, changelog_entry, builddepends, builddependsindep, architecturehintlist, dsc, section, maintainer, sourcepackagename, upload_distroseries, format, dsc_maintainer_rfc822, dsc_standards_version, dsc_format, dsc_binaries, upload_archive, copyright, build_conflicts, build_conflicts_indep, sourcepackage_recipe_build, changelog, user_defined_fields) VALUES (28, 1, '2.6.15.3', '2005-12-22 18:19:00', 1, NULL, 1, NULL, NULL, NULL, 'any', NULL, 1, 16, 22, 3, 1, NULL, NULL, '1.0', NULL, 1, NULL, NULL, NULL, NULL, NULL, NULL);2436INSERT INTO sourcepackagerelease (id, creator, version, dateuploaded, urgency, dscsigningkey, component, changelog_entry, builddepends, builddependsindep, architecturehintlist, dsc, section, maintainer, sourcepackagename, upload_distroseries, format, dsc_maintainer_rfc822, dsc_standards_version, dsc_format, dsc_binaries, upload_archive, copyright, build_conflicts, build_conflicts_indep, sourcepackage_recipe_build, changelog, user_defined_fields, homepage) VALUES (28, 1, '2.6.15.3', '2005-12-22 18:19:00', 1, NULL, 1, NULL, NULL, NULL, 'any', NULL, 1, 16, 22, 3, 1, NULL, NULL, '1.0', NULL, 1, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
2407INSERT INTO sourcepackagerelease (id, creator, version, dateuploaded, urgency, dscsigningkey, component, changelog_entry, builddepends, builddependsindep, architecturehintlist, dsc, section, maintainer, sourcepackagename, upload_distroseries, format, dsc_maintainer_rfc822, dsc_standards_version, dsc_format, dsc_binaries, upload_archive, copyright, build_conflicts, build_conflicts_indep, sourcepackage_recipe_build, changelog, user_defined_fields) VALUES (29, 1, '0.00', '2005-12-22 18:19:00', 1, NULL, 1, NULL, NULL, NULL, 'all', NULL, 1, 16, 17, 3, 1, NULL, NULL, '1.0', NULL, 1, NULL, NULL, NULL, NULL, NULL, NULL);2437INSERT INTO sourcepackagerelease (id, creator, version, dateuploaded, urgency, dscsigningkey, component, changelog_entry, builddepends, builddependsindep, architecturehintlist, dsc, section, maintainer, sourcepackagename, upload_distroseries, format, dsc_maintainer_rfc822, dsc_standards_version, dsc_format, dsc_binaries, upload_archive, copyright, build_conflicts, build_conflicts_indep, sourcepackage_recipe_build, changelog, user_defined_fields, homepage) VALUES (29, 1, '0.00', '2005-12-22 18:19:00', 1, NULL, 1, NULL, NULL, NULL, 'all', NULL, 1, 16, 17, 3, 1, NULL, NULL, '1.0', NULL, 1, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
2408INSERT INTO sourcepackagerelease (id, creator, version, dateuploaded, urgency, dscsigningkey, component, changelog_entry, builddepends, builddependsindep, architecturehintlist, dsc, section, maintainer, sourcepackagename, upload_distroseries, format, dsc_maintainer_rfc822, dsc_standards_version, dsc_format, dsc_binaries, upload_archive, copyright, build_conflicts, build_conflicts_indep, sourcepackage_recipe_build, changelog, user_defined_fields) VALUES (30, 1, '1.0', '2006-09-28 18:19:00', 1, NULL, 1, NULL, NULL, NULL, 'all', NULL, 1, 16, 20, 10, 1, NULL, NULL, '1.0', NULL, 1, NULL, NULL, NULL, NULL, NULL, NULL);2438INSERT INTO sourcepackagerelease (id, creator, version, dateuploaded, urgency, dscsigningkey, component, changelog_entry, builddepends, builddependsindep, architecturehintlist, dsc, section, maintainer, sourcepackagename, upload_distroseries, format, dsc_maintainer_rfc822, dsc_standards_version, dsc_format, dsc_binaries, upload_archive, copyright, build_conflicts, build_conflicts_indep, sourcepackage_recipe_build, changelog, user_defined_fields, homepage) VALUES (30, 1, '1.0', '2006-09-28 18:19:00', 1, NULL, 1, NULL, NULL, NULL, 'all', NULL, 1, 16, 20, 10, 1, NULL, NULL, '1.0', NULL, 1, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
2409INSERT INTO sourcepackagerelease (id, creator, version, dateuploaded, urgency, dscsigningkey, component, changelog_entry, builddepends, builddependsindep, architecturehintlist, dsc, section, maintainer, sourcepackagename, upload_distroseries, format, dsc_maintainer_rfc822, dsc_standards_version, dsc_format, dsc_binaries, upload_archive, copyright, build_conflicts, build_conflicts_indep, sourcepackage_recipe_build, changelog, user_defined_fields) VALUES (31, 1, '1.0', '2006-09-28 18:19:01', 1, NULL, 1, NULL, NULL, NULL, 'all', NULL, 1, 16, 20, 10, 1, NULL, NULL, '1.0', NULL, 1, NULL, NULL, NULL, NULL, NULL, NULL);2439INSERT INTO sourcepackagerelease (id, creator, version, dateuploaded, urgency, dscsigningkey, component, changelog_entry, builddepends, builddependsindep, architecturehintlist, dsc, section, maintainer, sourcepackagename, upload_distroseries, format, dsc_maintainer_rfc822, dsc_standards_version, dsc_format, dsc_binaries, upload_archive, copyright, build_conflicts, build_conflicts_indep, sourcepackage_recipe_build, changelog, user_defined_fields, homepage) VALUES (31, 1, '1.0', '2006-09-28 18:19:01', 1, NULL, 1, NULL, NULL, NULL, 'all', NULL, 1, 16, 20, 10, 1, NULL, NULL, '1.0', NULL, 1, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
2410INSERT INTO sourcepackagerelease (id, creator, version, dateuploaded, urgency, dscsigningkey, component, changelog_entry, builddepends, builddependsindep, architecturehintlist, dsc, section, maintainer, sourcepackagename, upload_distroseries, format, dsc_maintainer_rfc822, dsc_standards_version, dsc_format, dsc_binaries, upload_archive, copyright, build_conflicts, build_conflicts_indep, sourcepackage_recipe_build, changelog, user_defined_fields) VALUES (32, 1, '1.0', '2006-12-01 13:19:01', 1, NULL, 1, NULL, NULL, NULL, 'all', NULL, 1, 16, 23, 10, 1, NULL, NULL, '1.0', NULL, 1, NULL, NULL, NULL, NULL, NULL, NULL);2440INSERT INTO sourcepackagerelease (id, creator, version, dateuploaded, urgency, dscsigningkey, component, changelog_entry, builddepends, builddependsindep, architecturehintlist, dsc, section, maintainer, sourcepackagename, upload_distroseries, format, dsc_maintainer_rfc822, dsc_standards_version, dsc_format, dsc_binaries, upload_archive, copyright, build_conflicts, build_conflicts_indep, sourcepackage_recipe_build, changelog, user_defined_fields, homepage) VALUES (32, 1, '1.0', '2006-12-01 13:19:01', 1, NULL, 1, NULL, NULL, NULL, 'all', NULL, 1, 16, 23, 10, 1, NULL, NULL, '1.0', NULL, 1, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
2411INSERT INTO sourcepackagerelease (id, creator, version, dateuploaded, urgency, dscsigningkey, component, changelog_entry, builddepends, builddependsindep, architecturehintlist, dsc, section, maintainer, sourcepackagename, upload_distroseries, format, dsc_maintainer_rfc822, dsc_standards_version, dsc_format, dsc_binaries, upload_archive, copyright, build_conflicts, build_conflicts_indep, sourcepackage_recipe_build, changelog, user_defined_fields) VALUES (33, 1, '1.0', '2006-12-01 13:19:01', 1, NULL, 1, NULL, NULL, NULL, 'all', NULL, 1, 16, 24, 10, 1, NULL, NULL, '1.0', NULL, 1, NULL, NULL, NULL, NULL, NULL, NULL);2441INSERT INTO sourcepackagerelease (id, creator, version, dateuploaded, urgency, dscsigningkey, component, changelog_entry, builddepends, builddependsindep, architecturehintlist, dsc, section, maintainer, sourcepackagename, upload_distroseries, format, dsc_maintainer_rfc822, dsc_standards_version, dsc_format, dsc_binaries, upload_archive, copyright, build_conflicts, build_conflicts_indep, sourcepackage_recipe_build, changelog, user_defined_fields, homepage) VALUES (33, 1, '1.0', '2006-12-01 13:19:01', 1, NULL, 1, NULL, NULL, NULL, 'all', NULL, 1, 16, 24, 10, 1, NULL, NULL, '1.0', NULL, 1, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
2412INSERT INTO sourcepackagerelease (id, creator, version, dateuploaded, urgency, dscsigningkey, component, changelog_entry, builddepends, builddependsindep, architecturehintlist, dsc, section, maintainer, sourcepackagename, upload_distroseries, format, dsc_maintainer_rfc822, dsc_standards_version, dsc_format, dsc_binaries, upload_archive, copyright, build_conflicts, build_conflicts_indep, sourcepackage_recipe_build, changelog, user_defined_fields) VALUES (34, 1, '1.0', '2007-02-15 14:19:01', 1, NULL, 1, NULL, NULL, NULL, 'i386', NULL, 29, 16, 25, 10, 1, NULL, NULL, '1.0', NULL, 1, NULL, NULL, NULL, NULL, NULL, NULL);2442INSERT INTO sourcepackagerelease (id, creator, version, dateuploaded, urgency, dscsigningkey, component, changelog_entry, builddepends, builddependsindep, architecturehintlist, dsc, section, maintainer, sourcepackagename, upload_distroseries, format, dsc_maintainer_rfc822, dsc_standards_version, dsc_format, dsc_binaries, upload_archive, copyright, build_conflicts, build_conflicts_indep, sourcepackage_recipe_build, changelog, user_defined_fields, homepage) VALUES (34, 1, '1.0', '2007-02-15 14:19:01', 1, NULL, 1, NULL, NULL, NULL, 'i386', NULL, 29, 16, 25, 10, 1, NULL, NULL, '1.0', NULL, 1, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
2413INSERT INTO sourcepackagerelease (id, creator, version, dateuploaded, urgency, dscsigningkey, component, changelog_entry, builddepends, builddependsindep, architecturehintlist, dsc, section, maintainer, sourcepackagename, upload_distroseries, format, dsc_maintainer_rfc822, dsc_standards_version, dsc_format, dsc_binaries, upload_archive, copyright, build_conflicts, build_conflicts_indep, sourcepackage_recipe_build, changelog, user_defined_fields) VALUES (35, 1, '1.0', '2006-04-11 11:19:01', 1, NULL, 1, NULL, NULL, NULL, 'any', NULL, 1, 16, 26, 1, 1, NULL, NULL, '1.0', NULL, 10, NULL, NULL, NULL, NULL, NULL, NULL);2443INSERT INTO sourcepackagerelease (id, creator, version, dateuploaded, urgency, dscsigningkey, component, changelog_entry, builddepends, builddependsindep, architecturehintlist, dsc, section, maintainer, sourcepackagename, upload_distroseries, format, dsc_maintainer_rfc822, dsc_standards_version, dsc_format, dsc_binaries, upload_archive, copyright, build_conflicts, build_conflicts_indep, sourcepackage_recipe_build, changelog, user_defined_fields, homepage) VALUES (35, 1, '1.0', '2006-04-11 11:19:01', 1, NULL, 1, NULL, NULL, NULL, 'any', NULL, 1, 16, 26, 1, 1, NULL, NULL, '1.0', NULL, 10, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
2414INSERT INTO sourcepackagerelease (id, creator, version, dateuploaded, urgency, dscsigningkey, component, changelog_entry, builddepends, builddependsindep, architecturehintlist, dsc, section, maintainer, sourcepackagename, upload_distroseries, format, dsc_maintainer_rfc822, dsc_standards_version, dsc_format, dsc_binaries, upload_archive, copyright, build_conflicts, build_conflicts_indep, sourcepackage_recipe_build, changelog, user_defined_fields) VALUES (36, 243606, '1.0-1', '2007-08-09 21:25:37.832976', 1, NULL, 5, 'commercialpackage (1.0-1) breezy; urgency=low2444INSERT INTO sourcepackagerelease (id, creator, version, dateuploaded, urgency, dscsigningkey, component, changelog_entry, builddepends, builddependsindep, architecturehintlist, dsc, section, maintainer, sourcepackagename, upload_distroseries, format, dsc_maintainer_rfc822, dsc_standards_version, dsc_format, dsc_binaries, upload_archive, copyright, build_conflicts, build_conflicts_indep, sourcepackage_recipe_build, changelog, user_defined_fields, homepage) VALUES (36, 243606, '1.0-1', '2007-08-09 21:25:37.832976', 1, NULL, 5, 'commercialpackage (1.0-1) breezy; urgency=low
24152445
2416 * Initial version2446 * Initial version
2417 Address for testing linkification: Foo Bar <foo.bar@canonical.com>2447 Address for testing linkification: Foo Bar <foo.bar@canonical.com>
@@ -2435,8 +2465,8 @@
2435iD8DBQFGtzTjWhGlTF8G/HcRAtFsAJ4hHyKhOnsUOQDI+SAk000DmFAnUgCcC84J2465iD8DBQFGtzTjWhGlTF8G/HcRAtFsAJ4hHyKhOnsUOQDI+SAk000DmFAnUgCcC84J
24363F4bEPeRcnUjCFI/hjR0kxg=24663F4bEPeRcnUjCFI/hjR0kxg=
2437=Tjln2467=Tjln
2438', 7, 243606, 27, 10, 1, 'Julian Edwards <launchpad@julian-edwards.com>', '3.6.2', '1.0', 'commercialpackage', 12, NULL, NULL, NULL, NULL, NULL, NULL);2468', 7, 243606, 27, 10, 1, 'Julian Edwards <launchpad@julian-edwards.com>', '3.6.2', '1.0', 'commercialpackage', 12, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
2439INSERT INTO sourcepackagerelease (id, creator, version, dateuploaded, urgency, dscsigningkey, component, changelog_entry, builddepends, builddependsindep, architecturehintlist, dsc, section, maintainer, sourcepackagename, upload_distroseries, format, dsc_maintainer_rfc822, dsc_standards_version, dsc_format, dsc_binaries, upload_archive, copyright, build_conflicts, build_conflicts_indep, sourcepackage_recipe_build, changelog, user_defined_fields) VALUES (37, 1, '1.0', '2006-04-11 11:19:01', 1, NULL, 1, NULL, NULL, NULL, 'i386', NULL, 1, 16, 26, 1, 1, NULL, NULL, '1.0', NULL, 11, NULL, NULL, NULL, NULL, NULL, NULL);2469INSERT INTO sourcepackagerelease (id, creator, version, dateuploaded, urgency, dscsigningkey, component, changelog_entry, builddepends, builddependsindep, architecturehintlist, dsc, section, maintainer, sourcepackagename, upload_distroseries, format, dsc_maintainer_rfc822, dsc_standards_version, dsc_format, dsc_binaries, upload_archive, copyright, build_conflicts, build_conflicts_indep, sourcepackage_recipe_build, changelog, user_defined_fields, homepage) VALUES (37, 1, '1.0', '2006-04-11 11:19:01', 1, NULL, 1, NULL, NULL, NULL, 'i386', NULL, 1, 16, 26, 1, 1, NULL, NULL, '1.0', NULL, 11, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
24402470
24412471
2442ALTER TABLE sourcepackagerelease ENABLE TRIGGER ALL;2472ALTER TABLE sourcepackagerelease ENABLE TRIGGER ALL;
@@ -2490,21 +2520,21 @@
24902520
2491ALTER TABLE binarypackagerelease DISABLE TRIGGER ALL;2521ALTER TABLE binarypackagerelease DISABLE TRIGGER ALL;
24922522
2493INSERT INTO binarypackagerelease (id, binarypackagename, version, summary, description, build, binpackageformat, component, section, priority, shlibdeps, depends, recommends, suggests, conflicts, replaces, provides, essential, installedsize, architecturespecific, fti, datecreated, pre_depends, enhances, breaks, debug_package, user_defined_fields) VALUES (6, 6, '1.0', 'foobar is bad', 'foobar should be removed', 6, 1, 1, 1, 40, NULL, NULL, NULL, NULL, NULL, NULL, NULL, false, NULL, false, NULL, '2006-12-01 17:50:10.878712', NULL, NULL, NULL, NULL, NULL);2523INSERT INTO binarypackagerelease (id, binarypackagename, version, summary, description, build, binpackageformat, component, section, priority, shlibdeps, depends, recommends, suggests, conflicts, replaces, provides, essential, installedsize, architecturespecific, fti, datecreated, pre_depends, enhances, breaks, debug_package, user_defined_fields, homepage) VALUES (6, 6, '1.0', 'foobar is bad', 'foobar should be removed', 6, 1, 1, 1, 40, NULL, NULL, NULL, NULL, NULL, NULL, NULL, false, NULL, false, NULL, '2006-12-01 17:50:10.878712', NULL, NULL, NULL, NULL, NULL, NULL);
2494INSERT INTO binarypackagerelease (id, binarypackagename, version, summary, description, build, binpackageformat, component, section, priority, shlibdeps, depends, recommends, suggests, conflicts, replaces, provides, essential, installedsize, architecturespecific, fti, datecreated, pre_depends, enhances, breaks, debug_package, user_defined_fields) VALUES (12, 8, '0.9', 'Mozilla Firefox Web Browser', 'Mozilla Firefox Web Browser is .....', 2, 1, 1, 1, 10, NULL, 'gcc-3.4-base, libc6 (>= 2.3.2.ds1-4), gcc-3.4 (>= 3.4.1-4sarge1), gcc-3.4 (<< 3.4.2), libstdc++6-dev (>= 3.4.1-4sarge1)', 'gcc-3.4-base, libc6 (>= 2.3.2.ds1-4), gcc-3.4 (>= 3.4.1-4sarge1), gcc-3.4 (<< 3.4.2), libstdc++6-dev (>= 3.4.1-4sarge1)', 'firefox-gnome-support (= 1.0.7-0ubuntu20), latex-xft-fonts, xprint', 'firefox, mozilla-web-browser', 'gnome-mozilla-browser', 'mozilla-firefox', false, NULL, true, NULL, '2005-10-19 17:50:10.874189', 'pmount, foo', 'pmount, bar', 'pmount, baz', NULL, NULL);2524INSERT INTO binarypackagerelease (id, binarypackagename, version, summary, description, build, binpackageformat, component, section, priority, shlibdeps, depends, recommends, suggests, conflicts, replaces, provides, essential, installedsize, architecturespecific, fti, datecreated, pre_depends, enhances, breaks, debug_package, user_defined_fields, homepage) VALUES (12, 8, '0.9', 'Mozilla Firefox Web Browser', 'Mozilla Firefox Web Browser is .....', 2, 1, 1, 1, 10, NULL, 'gcc-3.4-base, libc6 (>= 2.3.2.ds1-4), gcc-3.4 (>= 3.4.1-4sarge1), gcc-3.4 (<< 3.4.2), libstdc++6-dev (>= 3.4.1-4sarge1)', 'gcc-3.4-base, libc6 (>= 2.3.2.ds1-4), gcc-3.4 (>= 3.4.1-4sarge1), gcc-3.4 (<< 3.4.2), libstdc++6-dev (>= 3.4.1-4sarge1)', 'firefox-gnome-support (= 1.0.7-0ubuntu20), latex-xft-fonts, xprint', 'firefox, mozilla-web-browser', 'gnome-mozilla-browser', 'mozilla-firefox', false, NULL, true, NULL, '2005-10-19 17:50:10.874189', 'pmount, foo', 'pmount, bar', 'pmount, baz', NULL, NULL, NULL);
2495INSERT INTO binarypackagerelease (id, binarypackagename, version, summary, description, build, binpackageformat, component, section, priority, shlibdeps, depends, recommends, suggests, conflicts, replaces, provides, essential, installedsize, architecturespecific, fti, datecreated, pre_depends, enhances, breaks, debug_package, user_defined_fields) VALUES (15, 13, '0.1-1', 'pmount shortdesc', 'pmount description', 7, 1, 1, 1, 40, NULL, 'at (>= 3.14156), linux-2.6.12, tramp-package', NULL, NULL, NULL, NULL, NULL, false, NULL, false, NULL, '2005-10-19 17:50:10.878712', NULL, NULL, NULL, NULL, NULL);2525INSERT INTO binarypackagerelease (id, binarypackagename, version, summary, description, build, binpackageformat, component, section, priority, shlibdeps, depends, recommends, suggests, conflicts, replaces, provides, essential, installedsize, architecturespecific, fti, datecreated, pre_depends, enhances, breaks, debug_package, user_defined_fields, homepage) VALUES (15, 13, '0.1-1', 'pmount shortdesc', 'pmount description', 7, 1, 1, 1, 40, NULL, 'at (>= 3.14156), linux-2.6.12, tramp-package', NULL, NULL, NULL, NULL, NULL, false, NULL, false, NULL, '2005-10-19 17:50:10.878712', NULL, NULL, NULL, NULL, NULL, NULL);
2496INSERT INTO binarypackagerelease (id, binarypackagename, version, summary, description, build, binpackageformat, component, section, priority, shlibdeps, depends, recommends, suggests, conflicts, replaces, provides, essential, installedsize, architecturespecific, fti, datecreated, pre_depends, enhances, breaks, debug_package, user_defined_fields) VALUES (16, 14, '2.6.12.20', 'the kernel of boom', 'this kernel is like the crystal method: a temple of boom', 14, 1, 1, 1, 40, NULL, NULL, NULL, NULL, NULL, NULL, NULL, false, NULL, false, NULL, '2005-10-19 17:50:10.878712', NULL, NULL, NULL, NULL, NULL);2526INSERT INTO binarypackagerelease (id, binarypackagename, version, summary, description, build, binpackageformat, component, section, priority, shlibdeps, depends, recommends, suggests, conflicts, replaces, provides, essential, installedsize, architecturespecific, fti, datecreated, pre_depends, enhances, breaks, debug_package, user_defined_fields, homepage) VALUES (16, 14, '2.6.12.20', 'the kernel of boom', 'this kernel is like the crystal method: a temple of boom', 14, 1, 1, 1, 40, NULL, NULL, NULL, NULL, NULL, NULL, NULL, false, NULL, false, NULL, '2005-10-19 17:50:10.878712', NULL, NULL, NULL, NULL, NULL, NULL);
2497INSERT INTO binarypackagerelease (id, binarypackagename, version, summary, description, build, binpackageformat, component, section, priority, shlibdeps, depends, recommends, suggests, conflicts, replaces, provides, essential, installedsize, architecturespecific, fti, datecreated, pre_depends, enhances, breaks, debug_package, user_defined_fields) VALUES (17, 15, '3.14156', 'at the mountains of madness', 'lovecraft long before enunciated that the mountains were not safe, but you did not believe him', 15, 1, 1, 1, 40, NULL, NULL, NULL, NULL, NULL, NULL, NULL, false, NULL, false, NULL, '2005-10-19 17:50:10.878712', NULL, NULL, NULL, NULL, NULL);2527INSERT INTO binarypackagerelease (id, binarypackagename, version, summary, description, build, binpackageformat, component, section, priority, shlibdeps, depends, recommends, suggests, conflicts, replaces, provides, essential, installedsize, architecturespecific, fti, datecreated, pre_depends, enhances, breaks, debug_package, user_defined_fields, homepage) VALUES (17, 15, '3.14156', 'at the mountains of madness', 'lovecraft long before enunciated that the mountains were not safe, but you did not believe him', 15, 1, 1, 1, 40, NULL, NULL, NULL, NULL, NULL, NULL, NULL, false, NULL, false, NULL, '2005-10-19 17:50:10.878712', NULL, NULL, NULL, NULL, NULL, NULL);
2498INSERT INTO binarypackagerelease (id, binarypackagename, version, summary, description, build, binpackageformat, component, section, priority, shlibdeps, depends, recommends, suggests, conflicts, replaces, provides, essential, installedsize, architecturespecific, fti, datecreated, pre_depends, enhances, breaks, debug_package, user_defined_fields) VALUES (18, 13, '2:1.9-1', 'pmount shortdesc', 'pmount description', 16, 1, 1, 1, 40, NULL, NULL, NULL, NULL, NULL, NULL, NULL, false, NULL, true, NULL, '2005-10-19 17:50:10.878712', NULL, NULL, NULL, NULL, NULL);2528INSERT INTO binarypackagerelease (id, binarypackagename, version, summary, description, build, binpackageformat, component, section, priority, shlibdeps, depends, recommends, suggests, conflicts, replaces, provides, essential, installedsize, architecturespecific, fti, datecreated, pre_depends, enhances, breaks, debug_package, user_defined_fields, homepage) VALUES (18, 13, '2:1.9-1', 'pmount shortdesc', 'pmount description', 16, 1, 1, 1, 40, NULL, NULL, NULL, NULL, NULL, NULL, NULL, false, NULL, true, NULL, '2005-10-19 17:50:10.878712', NULL, NULL, NULL, NULL, NULL, NULL);
2499INSERT INTO binarypackagerelease (id, binarypackagename, version, summary, description, build, binpackageformat, component, section, priority, shlibdeps, depends, recommends, suggests, conflicts, replaces, provides, essential, installedsize, architecturespecific, fti, datecreated, pre_depends, enhances, breaks, debug_package, user_defined_fields) VALUES (19, 8, '0.9', 'Mozilla Firefox Web Browser', 'Mozilla Firefox Web Browser is .....', 18, 1, 1, 1, 10, NULL, 'gcc-3.4-base, libc6 (>= 2.3.2.ds1-4), gcc-3.4 (>= 3.4.1-4sarge1), gcc-3.4 (<< 3.4.2), libstdc++6-dev (>= 3.4.1-4sarge1)', 'gcc-3.4-base, libc6 (>= 2.3.2.ds1-4), gcc-3.4 (>= 3.4.1-4sarge1), gcc-3.4 (<< 3.4.2), libstdc++6-dev (>= 3.4.1-4sarge1)', 'firefox-gnome-support (= 1.0.7-0ubuntu20), latex-xft-fonts, xprint', 'firefox, mozilla-web-browser', 'gnome-mozilla-browser', 'mozilla-firefox', false, NULL, true, NULL, '2005-10-19 17:50:10.874189', NULL, NULL, NULL, NULL, NULL);2529INSERT INTO binarypackagerelease (id, binarypackagename, version, summary, description, build, binpackageformat, component, section, priority, shlibdeps, depends, recommends, suggests, conflicts, replaces, provides, essential, installedsize, architecturespecific, fti, datecreated, pre_depends, enhances, breaks, debug_package, user_defined_fields, homepage) VALUES (19, 8, '0.9', 'Mozilla Firefox Web Browser', 'Mozilla Firefox Web Browser is .....', 18, 1, 1, 1, 10, NULL, 'gcc-3.4-base, libc6 (>= 2.3.2.ds1-4), gcc-3.4 (>= 3.4.1-4sarge1), gcc-3.4 (<< 3.4.2), libstdc++6-dev (>= 3.4.1-4sarge1)', 'gcc-3.4-base, libc6 (>= 2.3.2.ds1-4), gcc-3.4 (>= 3.4.1-4sarge1), gcc-3.4 (<< 3.4.2), libstdc++6-dev (>= 3.4.1-4sarge1)', 'firefox-gnome-support (= 1.0.7-0ubuntu20), latex-xft-fonts, xprint', 'firefox, mozilla-web-browser', 'gnome-mozilla-browser', 'mozilla-firefox', false, NULL, true, NULL, '2005-10-19 17:50:10.874189', NULL, NULL, NULL, NULL, NULL, NULL);
2500INSERT INTO binarypackagerelease (id, binarypackagename, version, summary, description, build, binpackageformat, component, section, priority, shlibdeps, depends, recommends, suggests, conflicts, replaces, provides, essential, installedsize, architecturespecific, fti, datecreated, pre_depends, enhances, breaks, debug_package, user_defined_fields) VALUES (20, 13, '0.1-1', 'pmount shortdesc', 'pmount description', 19, 1, 1, 1, 40, NULL, NULL, NULL, NULL, NULL, NULL, NULL, false, NULL, false, NULL, '2005-10-19 17:50:10.878712', NULL, NULL, NULL, NULL, NULL);2530INSERT INTO binarypackagerelease (id, binarypackagename, version, summary, description, build, binpackageformat, component, section, priority, shlibdeps, depends, recommends, suggests, conflicts, replaces, provides, essential, installedsize, architecturespecific, fti, datecreated, pre_depends, enhances, breaks, debug_package, user_defined_fields, homepage) VALUES (20, 13, '0.1-1', 'pmount shortdesc', 'pmount description', 19, 1, 1, 1, 40, NULL, NULL, NULL, NULL, NULL, NULL, NULL, false, NULL, false, NULL, '2005-10-19 17:50:10.878712', NULL, NULL, NULL, NULL, NULL, NULL);
2501INSERT INTO binarypackagerelease (id, binarypackagename, version, summary, description, build, binpackageformat, component, section, priority, shlibdeps, depends, recommends, suggests, conflicts, replaces, provides, essential, installedsize, architecturespecific, fti, datecreated, pre_depends, enhances, breaks, debug_package, user_defined_fields) VALUES (21, 16, '1.0', 'cdrkit is nice', 'cdrkit should be kept', 21, 1, 1, 1, 40, NULL, NULL, NULL, NULL, NULL, NULL, NULL, false, NULL, false, NULL, '2006-12-01 17:50:10.878712', NULL, NULL, NULL, NULL, NULL);2531INSERT INTO binarypackagerelease (id, binarypackagename, version, summary, description, build, binpackageformat, component, section, priority, shlibdeps, depends, recommends, suggests, conflicts, replaces, provides, essential, installedsize, architecturespecific, fti, datecreated, pre_depends, enhances, breaks, debug_package, user_defined_fields, homepage) VALUES (21, 16, '1.0', 'cdrkit is nice', 'cdrkit should be kept', 21, 1, 1, 1, 40, NULL, NULL, NULL, NULL, NULL, NULL, NULL, false, NULL, false, NULL, '2006-12-01 17:50:10.878712', NULL, NULL, NULL, NULL, NULL, NULL);
2502INSERT INTO binarypackagerelease (id, binarypackagename, version, summary, description, build, binpackageformat, component, section, priority, shlibdeps, depends, recommends, suggests, conflicts, replaces, provides, essential, installedsize, architecturespecific, fti, datecreated, pre_depends, enhances, breaks, debug_package, user_defined_fields) VALUES (22, 8, '1.0', 'ff from iceweasel', 'iceweasel huh ?', 23, 1, 1, 1, 40, NULL, NULL, NULL, NULL, NULL, NULL, NULL, false, NULL, true, NULL, '2006-04-11 12:50:10.878712', NULL, NULL, NULL, NULL, NULL);2532INSERT INTO binarypackagerelease (id, binarypackagename, version, summary, description, build, binpackageformat, component, section, priority, shlibdeps, depends, recommends, suggests, conflicts, replaces, provides, essential, installedsize, architecturespecific, fti, datecreated, pre_depends, enhances, breaks, debug_package, user_defined_fields, homepage) VALUES (22, 8, '1.0', 'ff from iceweasel', 'iceweasel huh ?', 23, 1, 1, 1, 40, NULL, NULL, NULL, NULL, NULL, NULL, NULL, false, NULL, true, NULL, '2006-04-11 12:50:10.878712', NULL, NULL, NULL, NULL, NULL, NULL);
2503INSERT INTO binarypackagerelease (id, binarypackagename, version, summary, description, build, binpackageformat, component, section, priority, shlibdeps, depends, recommends, suggests, conflicts, replaces, provides, essential, installedsize, architecturespecific, fti, datecreated, pre_depends, enhances, breaks, debug_package, user_defined_fields) VALUES (23, 13, '0.1-1', 'pmount shortdesc', 'pmount description', 27, 1, 1, 1, 40, NULL, NULL, NULL, NULL, NULL, NULL, NULL, false, NULL, false, NULL, '2007-07-24 17:50:10.878712', NULL, NULL, NULL, NULL, NULL);2533INSERT INTO binarypackagerelease (id, binarypackagename, version, summary, description, build, binpackageformat, component, section, priority, shlibdeps, depends, recommends, suggests, conflicts, replaces, provides, essential, installedsize, architecturespecific, fti, datecreated, pre_depends, enhances, breaks, debug_package, user_defined_fields, homepage) VALUES (23, 13, '0.1-1', 'pmount shortdesc', 'pmount description', 27, 1, 1, 1, 40, NULL, NULL, NULL, NULL, NULL, NULL, NULL, false, NULL, false, NULL, '2007-07-24 17:50:10.878712', NULL, NULL, NULL, NULL, NULL, NULL);
2504INSERT INTO binarypackagerelease (id, binarypackagename, version, summary, description, build, binpackageformat, component, section, priority, shlibdeps, depends, recommends, suggests, conflicts, replaces, provides, essential, installedsize, architecturespecific, fti, datecreated, pre_depends, enhances, breaks, debug_package, user_defined_fields) VALUES (24, 8, '1.0', 'ff from iceweasel', 'iceweasel huh ?', 28, 1, 1, 1, 40, NULL, NULL, NULL, NULL, NULL, NULL, NULL, false, NULL, true, NULL, '2006-08-10 12:50:10.878712', NULL, NULL, NULL, NULL, NULL);2534INSERT INTO binarypackagerelease (id, binarypackagename, version, summary, description, build, binpackageformat, component, section, priority, shlibdeps, depends, recommends, suggests, conflicts, replaces, provides, essential, installedsize, architecturespecific, fti, datecreated, pre_depends, enhances, breaks, debug_package, user_defined_fields, homepage) VALUES (24, 8, '1.0', 'ff from iceweasel', 'iceweasel huh ?', 28, 1, 1, 1, 40, NULL, NULL, NULL, NULL, NULL, NULL, NULL, false, NULL, true, NULL, '2006-08-10 12:50:10.878712', NULL, NULL, NULL, NULL, NULL, NULL);
2505INSERT INTO binarypackagerelease (id, binarypackagename, version, summary, description, build, binpackageformat, component, section, priority, shlibdeps, depends, recommends, suggests, conflicts, replaces, provides, essential, installedsize, architecturespecific, fti, datecreated, pre_depends, enhances, breaks, debug_package, user_defined_fields) VALUES (25, 17, '1.0-1', 'Stuff for testing', ' This package is simply used for testing soyuz', 29, 1, 5, 7, 20, '', '', '', '', '', '', '', false, 8, true, NULL, '2007-08-09 21:54:18.456616', NULL, NULL, NULL, NULL, NULL);2535INSERT INTO binarypackagerelease (id, binarypackagename, version, summary, description, build, binpackageformat, component, section, priority, shlibdeps, depends, recommends, suggests, conflicts, replaces, provides, essential, installedsize, architecturespecific, fti, datecreated, pre_depends, enhances, breaks, debug_package, user_defined_fields, homepage) VALUES (25, 17, '1.0-1', 'Stuff for testing', ' This package is simply used for testing soyuz', 29, 1, 5, 7, 20, '', '', '', '', '', '', '', false, 8, true, NULL, '2007-08-09 21:54:18.456616', NULL, NULL, NULL, NULL, NULL, NULL);
2506INSERT INTO binarypackagerelease (id, binarypackagename, version, summary, description, build, binpackageformat, component, section, priority, shlibdeps, depends, recommends, suggests, conflicts, replaces, provides, essential, installedsize, architecturespecific, fti, datecreated, pre_depends, enhances, breaks, debug_package, user_defined_fields) VALUES (26, 8, '0.9', 'Mozilla Firefox Web Browser', 'Mozilla Firefox Web Browser is .....', 30, 1, 1, 1, 10, '', '', '', '', '', '', '', false, NULL, true, NULL, '2005-10-19 17:50:10.874189', NULL, NULL, NULL, NULL, NULL);2536INSERT INTO binarypackagerelease (id, binarypackagename, version, summary, description, build, binpackageformat, component, section, priority, shlibdeps, depends, recommends, suggests, conflicts, replaces, provides, essential, installedsize, architecturespecific, fti, datecreated, pre_depends, enhances, breaks, debug_package, user_defined_fields, homepage) VALUES (26, 8, '0.9', 'Mozilla Firefox Web Browser', 'Mozilla Firefox Web Browser is .....', 30, 1, 1, 1, 10, '', '', '', '', '', '', '', false, NULL, true, NULL, '2005-10-19 17:50:10.874189', NULL, NULL, NULL, NULL, NULL, NULL);
2507INSERT INTO binarypackagerelease (id, binarypackagename, version, summary, description, build, binpackageformat, component, section, priority, shlibdeps, depends, recommends, suggests, conflicts, replaces, provides, essential, installedsize, architecturespecific, fti, datecreated, pre_depends, enhances, breaks, debug_package, user_defined_fields) VALUES (27, 18, '0.9', 'Mozilla Firefox Data', 'Mozilla Firefox Data is .....', 2, 1, 1, 1, 10, '', '', '', '', '', '', '', false, NULL, false, NULL, '2005-10-19 17:50:10.874189', NULL, NULL, NULL, NULL, NULL);2537INSERT INTO binarypackagerelease (id, binarypackagename, version, summary, description, build, binpackageformat, component, section, priority, shlibdeps, depends, recommends, suggests, conflicts, replaces, provides, essential, installedsize, architecturespecific, fti, datecreated, pre_depends, enhances, breaks, debug_package, user_defined_fields, homepage) VALUES (27, 18, '0.9', 'Mozilla Firefox Data', 'Mozilla Firefox Data is .....', 2, 1, 1, 1, 10, '', '', '', '', '', '', '', false, NULL, false, NULL, '2005-10-19 17:50:10.874189', NULL, NULL, NULL, NULL, NULL, NULL);
25082538
25092539
2510ALTER TABLE binarypackagerelease ENABLE TRIGGER ALL;2540ALTER TABLE binarypackagerelease ENABLE TRIGGER ALL;
@@ -3074,25 +3104,25 @@
30743104
3075ALTER TABLE branchrevision DISABLE TRIGGER ALL;3105ALTER TABLE branchrevision DISABLE TRIGGER ALL;
30763106
3077INSERT INTO branchrevision (id, sequence, branch, revision) VALUES (1, 1, 10, 1);3107INSERT INTO branchrevision (sequence, branch, revision) VALUES (1, 10, 1);
3078INSERT INTO branchrevision (id, sequence, branch, revision) VALUES (2, 1, 11, 2);3108INSERT INTO branchrevision (sequence, branch, revision) VALUES (1, 11, 2);
3079INSERT INTO branchrevision (id, sequence, branch, revision) VALUES (3, 1, 12, 3);3109INSERT INTO branchrevision (sequence, branch, revision) VALUES (1, 12, 3);
3080INSERT INTO branchrevision (id, sequence, branch, revision) VALUES (4, 1, 20, 4);3110INSERT INTO branchrevision (sequence, branch, revision) VALUES (1, 20, 4);
3081INSERT INTO branchrevision (id, sequence, branch, revision) VALUES (5, 2, 20, 5);3111INSERT INTO branchrevision (sequence, branch, revision) VALUES (1, 21, 4);
3082INSERT INTO branchrevision (id, sequence, branch, revision) VALUES (6, 3, 20, 6);3112INSERT INTO branchrevision (sequence, branch, revision) VALUES (2, 20, 5);
3083INSERT INTO branchrevision (id, sequence, branch, revision) VALUES (7, 4, 20, 7);3113INSERT INTO branchrevision (sequence, branch, revision) VALUES (2, 21, 5);
3084INSERT INTO branchrevision (id, sequence, branch, revision) VALUES (8, 5, 20, 8);3114INSERT INTO branchrevision (sequence, branch, revision) VALUES (3, 20, 6);
3085INSERT INTO branchrevision (id, sequence, branch, revision) VALUES (9, 6, 20, 9);3115INSERT INTO branchrevision (sequence, branch, revision) VALUES (3, 21, 10);
3086INSERT INTO branchrevision (id, sequence, branch, revision) VALUES (10, 1, 21, 4);3116INSERT INTO branchrevision (sequence, branch, revision) VALUES (4, 20, 7);
3087INSERT INTO branchrevision (id, sequence, branch, revision) VALUES (11, 2, 21, 5);3117INSERT INTO branchrevision (sequence, branch, revision) VALUES (4, 21, 11);
3088INSERT INTO branchrevision (id, sequence, branch, revision) VALUES (12, 3, 21, 10);3118INSERT INTO branchrevision (sequence, branch, revision) VALUES (5, 20, 8);
3089INSERT INTO branchrevision (id, sequence, branch, revision) VALUES (13, 4, 21, 11);3119INSERT INTO branchrevision (sequence, branch, revision) VALUES (5, 21, 8);
3090INSERT INTO branchrevision (id, sequence, branch, revision) VALUES (14, 5, 21, 8);3120INSERT INTO branchrevision (sequence, branch, revision) VALUES (6, 20, 9);
3091INSERT INTO branchrevision (id, sequence, branch, revision) VALUES (15, 6, 21, 9);3121INSERT INTO branchrevision (sequence, branch, revision) VALUES (6, 21, 9);
3092INSERT INTO branchrevision (id, sequence, branch, revision) VALUES (16, NULL, 20, 10);3122INSERT INTO branchrevision (sequence, branch, revision) VALUES (NULL, 20, 10);
3093INSERT INTO branchrevision (id, sequence, branch, revision) VALUES (17, NULL, 20, 11);3123INSERT INTO branchrevision (sequence, branch, revision) VALUES (NULL, 20, 11);
3094INSERT INTO branchrevision (id, sequence, branch, revision) VALUES (18, NULL, 21, 6);3124INSERT INTO branchrevision (sequence, branch, revision) VALUES (NULL, 21, 6);
3095INSERT INTO branchrevision (id, sequence, branch, revision) VALUES (19, NULL, 21, 7);3125INSERT INTO branchrevision (sequence, branch, revision) VALUES (NULL, 21, 7);
30963126
30973127
3098ALTER TABLE branchrevision ENABLE TRIGGER ALL;3128ALTER TABLE branchrevision ENABLE TRIGGER ALL;
@@ -3315,42 +3345,42 @@
33153345
3316ALTER TABLE bugmessage DISABLE TRIGGER ALL;3346ALTER TABLE bugmessage DISABLE TRIGGER ALL;
33173347
3318INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible) VALUES (1, 2, 1, NULL, NULL, true);3348INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible, index) VALUES (1, 2, 1, NULL, NULL, true, NULL);
3319INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible) VALUES (2, 1, 3, NULL, NULL, true);3349INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible, index) VALUES (2, 1, 3, NULL, NULL, true, NULL);
3320INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible) VALUES (3, 1, 4, NULL, NULL, true);3350INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible, index) VALUES (3, 1, 4, NULL, NULL, true, NULL);
3321INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible) VALUES (4, 2, 5, NULL, NULL, true);3351INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible, index) VALUES (4, 2, 5, NULL, NULL, true, NULL);
3322INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible) VALUES (5, 2, 6, NULL, NULL, true);3352INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible, index) VALUES (5, 2, 6, NULL, NULL, true, NULL);
3323INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible) VALUES (6, 4, 7, NULL, NULL, true);3353INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible, index) VALUES (6, 4, 7, NULL, NULL, true, NULL);
3324INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible) VALUES (7, 5, 8, NULL, NULL, true);3354INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible, index) VALUES (7, 5, 8, NULL, NULL, true, NULL);
3325INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible) VALUES (8, 6, 9, NULL, NULL, true);3355INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible, index) VALUES (8, 6, 9, NULL, NULL, true, NULL);
3326INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible) VALUES (9, 3, 10, NULL, NULL, true);3356INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible, index) VALUES (9, 3, 10, NULL, NULL, true, NULL);
3327INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible) VALUES (10, 7, 11, NULL, NULL, true);3357INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible, index) VALUES (10, 7, 11, NULL, NULL, true, NULL);
3328INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible) VALUES (11, 8, 14, NULL, NULL, true);3358INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible, index) VALUES (11, 8, 14, NULL, NULL, true, NULL);
3329INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible) VALUES (12, 9, 15, NULL, NULL, true);3359INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible, index) VALUES (12, 9, 15, NULL, NULL, true, NULL);
3330INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible) VALUES (13, 10, 17, NULL, NULL, true);3360INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible, index) VALUES (13, 10, 17, NULL, NULL, true, NULL);
3331INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible) VALUES (14, 10, 16, NULL, NULL, true);3361INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible, index) VALUES (14, 10, 16, NULL, NULL, true, NULL);
3332INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible) VALUES (15, 11, 24, NULL, NULL, true);3362INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible, index) VALUES (15, 11, 24, NULL, NULL, true, NULL);
3333INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible) VALUES (16, 11, 25, NULL, NULL, true);3363INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible, index) VALUES (16, 11, 25, NULL, NULL, true, NULL);
3334INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible) VALUES (17, 11, 26, NULL, NULL, true);3364INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible, index) VALUES (17, 11, 26, NULL, NULL, true, NULL);
3335INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible) VALUES (18, 11, 27, NULL, NULL, true);3365INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible, index) VALUES (18, 11, 27, NULL, NULL, true, NULL);
3336INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible) VALUES (19, 11, 28, NULL, NULL, true);3366INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible, index) VALUES (19, 11, 28, NULL, NULL, true, NULL);
3337INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible) VALUES (20, 11, 29, NULL, NULL, true);3367INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible, index) VALUES (20, 11, 29, NULL, NULL, true, NULL);
3338INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible) VALUES (21, 11, 30, NULL, NULL, true);3368INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible, index) VALUES (21, 11, 30, NULL, NULL, true, NULL);
3339INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible) VALUES (22, 12, 31, NULL, NULL, true);3369INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible, index) VALUES (22, 12, 31, NULL, NULL, true, NULL);
3340INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible) VALUES (23, 12, 33, NULL, NULL, true);3370INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible, index) VALUES (23, 12, 33, NULL, NULL, true, NULL);
3341INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible) VALUES (24, 12, 34, NULL, NULL, true);3371INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible, index) VALUES (24, 12, 34, NULL, NULL, true, NULL);
3342INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible) VALUES (25, 12, 35, NULL, NULL, true);3372INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible, index) VALUES (25, 12, 35, NULL, NULL, true, NULL);
3343INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible) VALUES (26, 12, 36, NULL, NULL, true);3373INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible, index) VALUES (26, 12, 36, NULL, NULL, true, NULL);
3344INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible) VALUES (27, 13, 37, NULL, NULL, true);3374INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible, index) VALUES (27, 13, 37, NULL, NULL, true, NULL);
3345INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible) VALUES (28, 13, 38, NULL, NULL, true);3375INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible, index) VALUES (28, 13, 38, NULL, NULL, true, NULL);
3346INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible) VALUES (29, 14, 39, NULL, NULL, true);3376INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible, index) VALUES (29, 14, 39, NULL, NULL, true, NULL);
3347INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible) VALUES (30, 15, 40, NULL, NULL, true);3377INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible, index) VALUES (30, 15, 40, NULL, NULL, true, NULL);
3348INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible) VALUES (31, 15, 44, 11, '<4284D7D1.6010208@gmx.de>', true);3378INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible, index) VALUES (31, 15, 44, 11, '<4284D7D1.6010208@gmx.de>', true, NULL);
3349INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible) VALUES (32, 15, 45, 11, '<20050517185429.GB20786@spring.luon.net>', true);3379INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible, index) VALUES (32, 15, 45, 11, '<20050517185429.GB20786@spring.luon.net>', true, NULL);
3350INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible) VALUES (33, 15, 46, 11, '<428A44E9.6090802@gmx.de>', true);3380INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible, index) VALUES (33, 15, 46, 11, '<428A44E9.6090802@gmx.de>', true, NULL);
3351INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible) VALUES (34, 15, 47, 11, '<20050517202044.GA23231@spring.luon.net>', true);3381INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible, index) VALUES (34, 15, 47, 11, '<20050517202044.GA23231@spring.luon.net>', true, NULL);
3352INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible) VALUES (35, 15, 48, 11, '<20050617140011.GA15638@piware.de>', true);3382INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible, index) VALUES (35, 15, 48, 11, '<20050617140011.GA15638@piware.de>', true, NULL);
3353INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible) VALUES (36, 15, 49, 11, '<42BD2E36.9090809@gmx.de>', true);3383INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible, index) VALUES (36, 15, 49, 11, '<42BD2E36.9090809@gmx.de>', true, NULL);
33543384
33553385
3356ALTER TABLE bugmessage ENABLE TRIGGER ALL;3386ALTER TABLE bugmessage ENABLE TRIGGER ALL;
@@ -3674,6 +3704,45 @@
3674ALTER TABLE bugsubscription ENABLE TRIGGER ALL;3704ALTER TABLE bugsubscription ENABLE TRIGGER ALL;
36753705
36763706
3707ALTER TABLE structuralsubscription DISABLE TRIGGER ALL;
3708
3709INSERT INTO structuralsubscription (id, product, productseries, project, milestone, distribution, distroseries, sourcepackagename, subscriber, subscribed_by, bug_notification_level, blueprint_notification_level, date_created, date_last_updated) VALUES (1, NULL, NULL, NULL, NULL, 1, NULL, 1, 16, 16, 40, 10, '2008-01-29 15:12:34.581468', '2008-01-29 15:12:34.581468');
3710INSERT INTO structuralsubscription (id, product, productseries, project, milestone, distribution, distroseries, sourcepackagename, subscriber, subscribed_by, bug_notification_level, blueprint_notification_level, date_created, date_last_updated) VALUES (2, NULL, NULL, NULL, NULL, 1, NULL, 14, 16, 16, 40, 10, '2008-01-29 15:12:34.581468', '2008-01-29 15:12:34.581468');
3711INSERT INTO structuralsubscription (id, product, productseries, project, milestone, distribution, distroseries, sourcepackagename, subscriber, subscribed_by, bug_notification_level, blueprint_notification_level, date_created, date_last_updated) VALUES (3, 22, NULL, NULL, NULL, NULL, NULL, NULL, 64, 64, 40, 10, '2008-02-06 12:17:13.030376', '2008-02-06 12:17:13.030376');
3712INSERT INTO structuralsubscription (id, product, productseries, project, milestone, distribution, distroseries, sourcepackagename, subscriber, subscribed_by, bug_notification_level, blueprint_notification_level, date_created, date_last_updated) VALUES (4, 16, NULL, NULL, NULL, NULL, NULL, NULL, 64, 64, 40, 10, '2008-02-06 12:17:13.030376', '2008-02-06 12:17:13.030376');
3713
3714
3715ALTER TABLE structuralsubscription ENABLE TRIGGER ALL;
3716
3717
3718ALTER TABLE bugsubscriptionfilter DISABLE TRIGGER ALL;
3719
3720
3721
3722ALTER TABLE bugsubscriptionfilter ENABLE TRIGGER ALL;
3723
3724
3725ALTER TABLE bugsubscriptionfilterimportance DISABLE TRIGGER ALL;
3726
3727
3728
3729ALTER TABLE bugsubscriptionfilterimportance ENABLE TRIGGER ALL;
3730
3731
3732ALTER TABLE bugsubscriptionfilterstatus DISABLE TRIGGER ALL;
3733
3734
3735
3736ALTER TABLE bugsubscriptionfilterstatus ENABLE TRIGGER ALL;
3737
3738
3739ALTER TABLE bugsubscriptionfiltertag DISABLE TRIGGER ALL;
3740
3741
3742
3743ALTER TABLE bugsubscriptionfiltertag ENABLE TRIGGER ALL;
3744
3745
3677ALTER TABLE bugtag DISABLE TRIGGER ALL;3746ALTER TABLE bugtag DISABLE TRIGGER ALL;
36783747
3679INSERT INTO bugtag (id, bug, tag) VALUES (1, 9, 'crash');3748INSERT INTO bugtag (id, bug, tag) VALUES (1, 9, 'crash');
@@ -3735,6 +3804,27 @@
3735ALTER TABLE bugtrackeralias ENABLE TRIGGER ALL;3804ALTER TABLE bugtrackeralias ENABLE TRIGGER ALL;
37363805
37373806
3807ALTER TABLE bugtrackercomponentgroup DISABLE TRIGGER ALL;
3808
3809
3810
3811ALTER TABLE bugtrackercomponentgroup ENABLE TRIGGER ALL;
3812
3813
3814ALTER TABLE distributionsourcepackage DISABLE TRIGGER ALL;
3815
3816
3817
3818ALTER TABLE distributionsourcepackage ENABLE TRIGGER ALL;
3819
3820
3821ALTER TABLE bugtrackercomponent DISABLE TRIGGER ALL;
3822
3823
3824
3825ALTER TABLE bugtrackercomponent ENABLE TRIGGER ALL;
3826
3827
3738ALTER TABLE bugtrackerperson DISABLE TRIGGER ALL;3828ALTER TABLE bugtrackerperson DISABLE TRIGGER ALL;
37393829
37403830
@@ -3936,6 +4026,13 @@
3936ALTER TABLE distributionbounty ENABLE TRIGGER ALL;4026ALTER TABLE distributionbounty ENABLE TRIGGER ALL;
39374027
39384028
4029ALTER TABLE distributionjob DISABLE TRIGGER ALL;
4030
4031
4032
4033ALTER TABLE distributionjob ENABLE TRIGGER ALL;
4034
4035
3939ALTER TABLE distributionmirror DISABLE TRIGGER ALL;4036ALTER TABLE distributionmirror DISABLE TRIGGER ALL;
39404037
3941INSERT INTO distributionmirror (id, distribution, name, http_base_url, ftp_base_url, rsync_base_url, displayname, description, owner, speed, country, content, official_candidate, enabled, date_created, whiteboard, status, date_reviewed, reviewer, country_dns_mirror) VALUES (1, 1, 'archive-mirror', 'http://localhost:11375/valid-mirror/', NULL, NULL, NULL, NULL, 1, 10, 75, 1, true, true, '2006-10-16 18:31:43.434567', NULL, 30, NULL, NULL, false);4038INSERT INTO distributionmirror (id, distribution, name, http_base_url, ftp_base_url, rsync_base_url, displayname, description, owner, speed, country, content, official_candidate, enabled, date_created, whiteboard, status, date_reviewed, reviewer, country_dns_mirror) VALUES (1, 1, 'archive-mirror', 'http://localhost:11375/valid-mirror/', NULL, NULL, NULL, NULL, 1, 10, 75, 1, true, true, '2006-10-16 18:31:43.434567', NULL, 30, NULL, NULL, false);
@@ -3953,13 +4050,6 @@
3953ALTER TABLE distributionmirror ENABLE TRIGGER ALL;4050ALTER TABLE distributionmirror ENABLE TRIGGER ALL;
39544051
39554052
3956ALTER TABLE distributionsourcepackage DISABLE TRIGGER ALL;
3957
3958
3959
3960ALTER TABLE distributionsourcepackage ENABLE TRIGGER ALL;
3961
3962
3963ALTER TABLE distributionsourcepackagecache DISABLE TRIGGER ALL;4053ALTER TABLE distributionsourcepackagecache DISABLE TRIGGER ALL;
39644054
3965INSERT INTO distributionsourcepackagecache (id, distribution, sourcepackagename, name, binpkgnames, binpkgsummaries, binpkgdescriptions, fti, changelog, archive) VALUES (1, 3, 19, 'alsa-utils', '', '', '', NULL, NULL, 1);4055INSERT INTO distributionsourcepackagecache (id, distribution, sourcepackagename, name, binpkgnames, binpkgsummaries, binpkgdescriptions, fti, changelog, archive) VALUES (1, 3, 19, 'alsa-utils', '', '', '', NULL, NULL, 1);
@@ -4000,6 +4090,27 @@
4000ALTER TABLE distrocomponentuploader ENABLE TRIGGER ALL;4090ALTER TABLE distrocomponentuploader ENABLE TRIGGER ALL;
40014091
40024092
4093ALTER TABLE packagediff DISABLE TRIGGER ALL;
4094
4095
4096
4097ALTER TABLE packagediff ENABLE TRIGGER ALL;
4098
4099
4100ALTER TABLE distroseriesdifference DISABLE TRIGGER ALL;
4101
4102
4103
4104ALTER TABLE distroseriesdifference ENABLE TRIGGER ALL;
4105
4106
4107ALTER TABLE distroseriesdifferencemessage DISABLE TRIGGER ALL;
4108
4109
4110
4111ALTER TABLE distroseriesdifferencemessage ENABLE TRIGGER ALL;
4112
4113
4003ALTER TABLE distroserieslanguage DISABLE TRIGGER ALL;4114ALTER TABLE distroserieslanguage DISABLE TRIGGER ALL;
40044115
4005INSERT INTO distroserieslanguage (id, distroseries, language, currentcount, updatescount, rosettacount, contributorcount, dateupdated, unreviewed_count) VALUES (1, 3, 68, 62, 0, 0, 1, '2007-01-15 17:58:40.839938', 0);4116INSERT INTO distroserieslanguage (id, distroseries, language, currentcount, updatescount, rosettacount, contributorcount, dateupdated, unreviewed_count) VALUES (1, 3, 68, 62, 0, 0, 1, '2007-01-15 17:58:40.839938', 0);
@@ -4489,6 +4600,13 @@
4489ALTER TABLE hwtestanswerdevice ENABLE TRIGGER ALL;4600ALTER TABLE hwtestanswerdevice ENABLE TRIGGER ALL;
44904601
44914602
4603ALTER TABLE incrementaldiff DISABLE TRIGGER ALL;
4604
4605
4606
4607ALTER TABLE incrementaldiff ENABLE TRIGGER ALL;
4608
4609
4492ALTER TABLE ircid DISABLE TRIGGER ALL;4610ALTER TABLE ircid DISABLE TRIGGER ALL;
44934611
4494INSERT INTO ircid (id, person, network, nickname) VALUES (1, 1, 'irc.freenode.net', 'mark');4612INSERT INTO ircid (id, person, network, nickname) VALUES (1, 1, 'irc.freenode.net', 'mark');
@@ -5986,13 +6104,6 @@
5986ALTER TABLE packagecopyrequest ENABLE TRIGGER ALL;6104ALTER TABLE packagecopyrequest ENABLE TRIGGER ALL;
59876105
59886106
5989ALTER TABLE packagediff DISABLE TRIGGER ALL;
5990
5991
5992
5993ALTER TABLE packagediff ENABLE TRIGGER ALL;
5994
5995
5996ALTER TABLE packageselection DISABLE TRIGGER ALL;6107ALTER TABLE packageselection DISABLE TRIGGER ALL;
59976108
59986109
@@ -10462,17 +10573,6 @@
10462ALTER TABLE standardshipitrequest ENABLE TRIGGER ALL;10573ALTER TABLE standardshipitrequest ENABLE TRIGGER ALL;
1046310574
1046410575
10465ALTER TABLE structuralsubscription DISABLE TRIGGER ALL;
10466
10467INSERT INTO structuralsubscription (id, product, productseries, project, milestone, distribution, distroseries, sourcepackagename, subscriber, subscribed_by, bug_notification_level, blueprint_notification_level, date_created, date_last_updated) VALUES (1, NULL, NULL, NULL, NULL, 1, NULL, 1, 16, 16, 40, 10, '2008-01-29 15:12:34.581468', '2008-01-29 15:12:34.581468');
10468INSERT INTO structuralsubscription (id, product, productseries, project, milestone, distribution, distroseries, sourcepackagename, subscriber, subscribed_by, bug_notification_level, blueprint_notification_level, date_created, date_last_updated) VALUES (2, NULL, NULL, NULL, NULL, 1, NULL, 14, 16, 16, 40, 10, '2008-01-29 15:12:34.581468', '2008-01-29 15:12:34.581468');
10469INSERT INTO structuralsubscription (id, product, productseries, project, milestone, distribution, distroseries, sourcepackagename, subscriber, subscribed_by, bug_notification_level, blueprint_notification_level, date_created, date_last_updated) VALUES (3, 22, NULL, NULL, NULL, NULL, NULL, NULL, 64, 64, 40, 10, '2008-02-06 12:17:13.030376', '2008-02-06 12:17:13.030376');
10470INSERT INTO structuralsubscription (id, product, productseries, project, milestone, distribution, distroseries, sourcepackagename, subscriber, subscribed_by, bug_notification_level, blueprint_notification_level, date_created, date_last_updated) VALUES (4, 16, NULL, NULL, NULL, NULL, NULL, NULL, 64, 64, 40, 10, '2008-02-06 12:17:13.030376', '2008-02-06 12:17:13.030376');
10471
10472
10473ALTER TABLE structuralsubscription ENABLE TRIGGER ALL;
10474
10475
10476ALTER TABLE suggestivepotemplate DISABLE TRIGGER ALL;10576ALTER TABLE suggestivepotemplate DISABLE TRIGGER ALL;
1047710577
1047810578
@@ -11081,6 +11181,13 @@
11081ALTER TABLE translationtemplateitem ENABLE TRIGGER ALL;11181ALTER TABLE translationtemplateitem ENABLE TRIGGER ALL;
1108211182
1108311183
11184ALTER TABLE translationtemplatesbuild DISABLE TRIGGER ALL;
11185
11186
11187
11188ALTER TABLE translationtemplatesbuild ENABLE TRIGGER ALL;
11189
11190
11084ALTER TABLE translator DISABLE TRIGGER ALL;11191ALTER TABLE translator DISABLE TRIGGER ALL;
1108511192
11086INSERT INTO translator (id, translationgroup, language, translator, datecreated, style_guide_url) VALUES (1, 1, 387, 53, '2005-07-13 13:14:19.748396', NULL);11193INSERT INTO translator (id, translationgroup, language, translator, datecreated, style_guide_url) VALUES (1, 1, 387, 53, '2005-07-13 13:14:19.748396', NULL);
1108711194
=== modified file 'database/schema/comments.sql'
--- database/schema/comments.sql 2010-09-03 16:43:11 +0000
+++ database/schema/comments.sql 2010-10-04 22:08:24 +0000
@@ -346,6 +346,21 @@
346COMMENT ON COLUMN BugTrackerPerson.name IS 'The (within the bug tracker) unique username in the external bug tracker.';346COMMENT ON COLUMN BugTrackerPerson.name IS 'The (within the bug tracker) unique username in the external bug tracker.';
347COMMENT ON COLUMN BugTrackerPerson.person IS 'The Person record in Launchpad this user corresponds to.';347COMMENT ON COLUMN BugTrackerPerson.person IS 'The Person record in Launchpad this user corresponds to.';
348348
349-- BugTrackerComponent
350
351COMMENT ON TABLE BugTrackerComponent IS 'A software component in a remote bug tracker, which can be linked to the corresponding source package in a distribution using this table.';
352COMMENT ON COLUMN BugTrackerComponent.name IS 'The name of the component as registered in the remote bug tracker.';
353COMMENT ON COLUMN BugTrackerComponent.is_visible IS 'Whether to display or hide the item in the Launchpad user interface.';
354COMMENT ON COLUMN BugTrackerComponent.is_custom IS 'Whether the item was added by a user in Launchpad or is kept in sync with the remote bug tracker.';
355COMMENT ON COLUMN BugTrackerComponent.component_group IS 'The product or other higher level category used by the remote bug tracker to group projects, if any.';
356COMMENT ON COLUMN BugTrackerComponent.distro_source_package IS 'A link to the source package in a distribution that corresponds to this component. This can be undefined if no link has been established yet.';
357
358-- BugTrackerComponentGroup
359
360COMMENT ON TABLE BugTrackerComponentGroup IS 'A collection of components as modeled in a remote bug tracker, often referred to as a product. Some bug trackers do not categorize software components this way, so they will have a single default component group that all components belong to.';
361COMMENT ON COLUMN BugTrackerComponentGroup.name IS 'The product or category name used in the remote bug tracker for grouping components.';
362COMMENT ON COLUMN BugTrackerComponentGroup.bug_tracker IS 'The external bug tracker this component group belongs to.';
363
349-- BugCve364-- BugCve
350365
351COMMENT ON TABLE BugCve IS 'A table that records the link between a given malone bug number, and a CVE entry.';366COMMENT ON TABLE BugCve IS 'A table that records the link between a given malone bug number, and a CVE entry.';
@@ -532,9 +547,12 @@
532COMMENT ON TABLE DistroSeriesDifference IS 'A difference of versions for a package in a derived distroseries and its parent distroseries.';547COMMENT ON TABLE DistroSeriesDifference IS 'A difference of versions for a package in a derived distroseries and its parent distroseries.';
533COMMENT ON COLUMN DistroSeriesDifference.derived_series IS 'The derived distroseries with the difference from its parent.';548COMMENT ON COLUMN DistroSeriesDifference.derived_series IS 'The derived distroseries with the difference from its parent.';
534COMMENT ON COLUMN DistroSeriesDifference.source_package_name IS 'The name of the source package which is different in the two series.';549COMMENT ON COLUMN DistroSeriesDifference.source_package_name IS 'The name of the source package which is different in the two series.';
535COMMENT ON COLUMN DistroSeriesDifference.package_diff IS 'The most recent package diff that was created for this difference.';550COMMENT ON COLUMN DistroSeriesDifference.package_diff IS 'The most recent package diff that was created for the base version to derived version.';
551COMMENT ON COLUMN DistroSeriesDifference.parent_package_diff IS 'The most recent package diff that was created for the base version to the parent version.';
536COMMENT ON COLUMN DistroSeriesDifference.status IS 'A distroseries difference can be needing attention, ignored or resolved.';552COMMENT ON COLUMN DistroSeriesDifference.status IS 'A distroseries difference can be needing attention, ignored or resolved.';
537COMMENT ON COLUMN DistroSeriesDifference.difference_type IS 'The type of difference that this record represents - a package unique to the derived series, or missing, or in both.';553COMMENT ON COLUMN DistroSeriesDifference.difference_type IS 'The type of difference that this record represents - a package unique to the derived series, or missing, or in both.';
554COMMENT ON COLUMN DistroSeriesDifference.source_version IS 'The version of the package in the derived series.';
555COMMENT ON COLUMN DistroSeriesDifference.parent_source_version IS 'The version of the package in the parent series.';
538556
539-- DistroSeriesDifferenceMessage557-- DistroSeriesDifferenceMessage
540COMMENT ON TABLE DistroSeriesDifferenceMessage IS 'A message/comment on a distro series difference.';558COMMENT ON TABLE DistroSeriesDifferenceMessage IS 'A message/comment on a distro series difference.';
@@ -839,6 +857,11 @@
839COMMENT ON COLUMN TranslationRelicensingAgreement.allow_relicensing IS 'Does this person want their translations relicensed under BSD.';857COMMENT ON COLUMN TranslationRelicensingAgreement.allow_relicensing IS 'Does this person want their translations relicensed under BSD.';
840COMMENT ON COLUMN TranslationRelicensingAgreement.date_decided IS 'Date when the last change of opinion was registered.';858COMMENT ON COLUMN TranslationRelicensingAgreement.date_decided IS 'Date when the last change of opinion was registered.';
841859
860-- TranslationTemplatesBuild
861COMMENT ON TABLE TranslationTemplatesBuild IS 'Build-farm record of a translation templates build.';
862COMMENT ON COLUMN TranslationTemplatesBuild.build_farm_job IS 'Associated BuildFarmJob.';
863COMMENT ON COLUMN TranslationTemplatesBuild.branch IS 'Branch to build templates out of.';
864
842-- RevisionAuthor865-- RevisionAuthor
843COMMENT ON TABLE RevisionAuthor IS 'All distinct authors for revisions.';866COMMENT ON TABLE RevisionAuthor IS 'All distinct authors for revisions.';
844COMMENT ON COLUMN RevisionAuthor.name IS 'The exact text extracted from the branch revision.';867COMMENT ON COLUMN RevisionAuthor.name IS 'The exact text extracted from the branch revision.';
@@ -1171,6 +1194,7 @@
1171COMMENT ON COLUMN DistroArchSeries.package_count IS 'A cache of the number of binary packages published in this distro arch release. The count only includes packages published in the release pocket.';1194COMMENT ON COLUMN DistroArchSeries.package_count IS 'A cache of the number of binary packages published in this distro arch release. The count only includes packages published in the release pocket.';
1172COMMENT ON COLUMN DistroArchSeries.supports_virtualized IS 'Whether or not1195COMMENT ON COLUMN DistroArchSeries.supports_virtualized IS 'Whether or not
1173virtualized build support should be provided by this specific distroarchseries';1196virtualized build support should be provided by this specific distroarchseries';
1197COMMENT ON COLUMN DistroArchSeries.enabled IS 'Whether to allow build creation and publishing for this DistroArchSeries.';
11741198
1175-- LauncpadDatabaseRevision1199-- LauncpadDatabaseRevision
1176COMMENT ON TABLE LaunchpadDatabaseRevision IS 'This table contains a list of the database patches that have been successfully applied to this database.';1200COMMENT ON TABLE LaunchpadDatabaseRevision IS 'This table contains a list of the database patches that have been successfully applied to this database.';
@@ -1288,11 +1312,14 @@
12881312
1289COMMENT ON TABLE ProjectBounty IS 'This table records a simple link between a bounty and a project. This bounty will be listed on the project web page, and the project will be mentioned on the bounty web page.';1313COMMENT ON TABLE ProjectBounty IS 'This table records a simple link between a bounty and a project. This bounty will be listed on the project web page, and the project will be mentioned on the bounty web page.';
12901314
1291-- Messaging subsytem1315-- BugMessages
1292COMMENT ON TABLE BugMessage IS 'This table maps a message to a bug. In other words, it shows that a particular message is associated with a particular bug.';1316COMMENT ON TABLE BugMessage IS 'This table maps a message to a bug. In other words, it shows that a particular message is associated with a particular bug.';
1293COMMENT ON COLUMN BugMessage.bugwatch IS 'The external bug this bug comment was imported from.';1317COMMENT ON COLUMN BugMessage.bugwatch IS 'The external bug this bug comment was imported from.';
1294COMMENT ON COLUMN BugMessage.remote_comment_id IS 'The id this bug comment has in the external bug tracker, if it is an imported comment. If it is NULL while having a bugwatch set, this comment was added in Launchpad and needs to be pushed to the external bug tracker.';1318COMMENT ON COLUMN BugMessage.remote_comment_id IS 'The id this bug comment has in the external bug tracker, if it is an imported comment. If it is NULL while having a bugwatch set, this comment was added in Launchpad and needs to be pushed to the external bug tracker.';
1295COMMENT ON COLUMN BugMessage.visible IS 'If false, the bug comment is hidden and should not be shown in any UI.';1319COMMENT ON COLUMN BugMessage.visible IS 'If false, the bug comment is hidden and should not be shown in any UI.';
1320COMMENT ON COLUMN BugMessage.index IS 'The index (used in urls) of the message in a particular bug.';
1321
1322-- Messaging subsytem
1296COMMENT ON TABLE Message IS 'This table stores a single RFC822-style message. Messages can be threaded (using the parent field). These messages can then be referenced from elsewhere in the system, such as the BugMessage table, integrating messageboard facilities with the rest of The Launchpad.';1323COMMENT ON TABLE Message IS 'This table stores a single RFC822-style message. Messages can be threaded (using the parent field). These messages can then be referenced from elsewhere in the system, such as the BugMessage table, integrating messageboard facilities with the rest of The Launchpad.';
1297COMMENT ON COLUMN Message.parent IS 'A "parent message". This allows for some level of threading in Messages.';1324COMMENT ON COLUMN Message.parent IS 'A "parent message". This allows for some level of threading in Messages.';
1298COMMENT ON COLUMN Message.subject IS 'The title text of the message, or the subject if it was an email.';1325COMMENT ON COLUMN Message.subject IS 'The title text of the message, or the subject if it was an email.';
@@ -1932,6 +1959,14 @@
1932COMMENT ON COLUMN Continent.code IS 'A two-letter code for a continent.';1959COMMENT ON COLUMN Continent.code IS 'A two-letter code for a continent.';
1933COMMENT ON COLUMN Continent.name IS 'The name of the continent.';1960COMMENT ON COLUMN Continent.name IS 'The name of the continent.';
19341961
1962-- DistributionJob
1963
1964COMMENT ON TABLE DistributionJob IS 'Contains references to jobs to be run on distributions.';
1965COMMENT ON COLUMN DistributionJob.distribution IS 'The distribution to be acted on.';
1966COMMENT ON COLUMN DistributionJob.distroseries IS 'The distroseries to be acted on.';
1967COMMENT ON COLUMN DistributionJob.job_type IS 'The type of job';
1968COMMENT ON COLUMN DistributionJob.json_data IS 'A JSON struct containing data for the job.';
1969
1935-- DistributionMirror1970-- DistributionMirror
1936COMMENT ON TABLE DistributionMirror IS 'A mirror of a given distribution.';1971COMMENT ON TABLE DistributionMirror IS 'A mirror of a given distribution.';
1937COMMENT ON COLUMN DistributionMirror.distribution IS 'The distribution to which the mirror refers to.';1972COMMENT ON COLUMN DistributionMirror.distribution IS 'The distribution to which the mirror refers to.';
@@ -2303,6 +2338,14 @@
2303COMMENT ON COLUMN HWDMIValue.value IS 'The value';2338COMMENT ON COLUMN HWDMIValue.value IS 'The value';
2304COMMENT ON COLUMN HWDMIValue.handle IS 'The handle to which this key/value pair belongs.';2339COMMENT ON COLUMN HWDMIValue.handle IS 'The handle to which this key/value pair belongs.';
23052340
2341-- IncrementalDiff
2342COMMENT ON TABLE IncrementalDiff IS 'Incremental diffs for merge proposals.';
2343COMMENT ON COLUMN IncrementalDiff.diff IS 'The contents of the diff.';
2344COMMENT ON COLUMN IncrementalDiff.branch_merge_proposal IS 'The merge proposal the diff is for.';
2345COMMENT ON COLUMN IncrementalDiff.old_revision IS 'The revision the diff is from.';
2346COMMENT ON COLUMN IncrementalDiff.new_revision IS 'The revision the diff is to.';
2347
2348
2306-- Job2349-- Job
23072350
2308COMMENT ON TABLE Job IS 'Common info about a job.';2351COMMENT ON TABLE Job IS 'Common info about a job.';
23092352
=== modified file 'database/schema/launchpad_session.sql'
--- database/schema/launchpad_session.sql 2010-09-06 09:48:41 +0000
+++ database/schema/launchpad_session.sql 2010-10-04 22:08:24 +0000
@@ -17,14 +17,13 @@
17CREATE TABLE TimeLimitedToken (17CREATE TABLE TimeLimitedToken (
18 path text NOT NULL,18 path text NOT NULL,
19 token text NOT NULL,19 token text NOT NULL,
20 created timestamp without time zone NOT NULL DEFAULT CURRENT_TIMESTAMP,20 created timestamp without time zone
21 constraint timelimitedtoken_pky primary key (path, token)21 NOT NULL DEFAULT (CURRENT_TIMESTAMP AT TIME ZONE 'UTC'),
22 constraint timelimitedtoken_pkey primary key (path, token)
22 ) WITHOUT OIDS;23 ) WITHOUT OIDS;
23COMMENT ON TABLE TimeLimitedToken IS 'stores tokens for granting access to a single path in the librarian for a short while. The garbo takes care of cleanups, and we should only have a few thousand at a time. Tokens are handed out just-in-time on the appserver, when a client attempts to dereference a private thing which we do not want to deliver in-line. OAuth tokens cannot be used for the launchpadlibrarian content because they would then be attackable. See lib.canonical.database.librarian for the python class.';24COMMENT ON TABLE TimeLimitedToken IS 'stores tokens for granting access to a single path in the librarian for a short while. The garbo takes care of cleanups, and we should only have a few thousand at a time. Tokens are handed out just-in-time on the appserver, when a client attempts to dereference a private thing which we do not want to deliver in-line. OAuth tokens cannot be used for the launchpadlibrarian content because they would then be attackable. See lib.canonical.database.librarian for the python class.';
24-- Give the garbo an efficient selection to cleanup25-- Give the garbo an efficient selection to cleanup
25CREATE INDEX timelimitedtoken_created ON TimeLimitedToken(created);26CREATE INDEX timelimitedtoken_created ON TimeLimitedToken(created);
26-- Give the librarian an efficient lookup
27CREATE INDEX timelimitedtoken_path_token ON TimeLimitedToken(path, token);
2827
29-- Let the session user access file access tokens.28-- Let the session user access file access tokens.
30GRANT SELECT, INSERT, UPDATE, DELETE ON TimeLimitedToken TO session;29GRANT SELECT, INSERT, UPDATE, DELETE ON TimeLimitedToken TO session;
3130
=== added file 'database/schema/patch-2208-08-1.sql'
--- database/schema/patch-2208-08-1.sql 1970-01-01 00:00:00 +0000
+++ database/schema/patch-2208-08-1.sql 2010-10-04 22:08:24 +0000
@@ -0,0 +1,9 @@
1-- Copyright 2010 Canonical Ltd. This software is licensed under the
2-- GNU Affero General Public License version 3 (see the file LICENSE).
3
4SET client_min_messages=ERROR;
5
6ALTER TABLE distroarchseries
7 ADD COLUMN enabled bool NOT NULL DEFAULT TRUE;
8
9INSERT INTO LaunchpadDatabaseRevision VALUES (2208, 08, 1);
010
=== added file 'database/schema/patch-2208-08-2.sql'
--- database/schema/patch-2208-08-2.sql 1970-01-01 00:00:00 +0000
+++ database/schema/patch-2208-08-2.sql 2010-10-04 22:08:24 +0000
@@ -0,0 +1,8 @@
1SET client_min_messages=ERROR;
2
3-- Permit bug searches ordered by 'importance' - the default - to serve from
4-- index rather than doing the full search and sorting.
5
6CREATE INDEX bugtask_importance_idx ON BugTask (importance, id desc nulls first);
7
8INSERT INTO LaunchpadDatabaseRevision VALUES (2208, 8, 2);
09
=== added file 'database/schema/patch-2208-08-3.sql'
--- database/schema/patch-2208-08-3.sql 1970-01-01 00:00:00 +0000
+++ database/schema/patch-2208-08-3.sql 2010-10-04 22:08:24 +0000
@@ -0,0 +1,8 @@
1SET client_min_messages=ERROR;
2
3-- Permit bug searches ordered by 'date_closed desc, id' to serve from
4-- index rather than doing the full search and sorting.
5
6CREATE INDEX bugtask__date_closed__id__idx2 ON BugTask (date_closed, id desc nulls first);
7
8INSERT INTO LaunchpadDatabaseRevision VALUES (2208, 8, 3);
09
=== added file 'database/schema/patch-2208-09-0.sql'
--- database/schema/patch-2208-09-0.sql 1970-01-01 00:00:00 +0000
+++ database/schema/patch-2208-09-0.sql 2010-10-04 22:08:24 +0000
@@ -0,0 +1,38 @@
1-- Copyright 2010 Canonical Ltd. This software is licensed under the
2-- GNU Affero General Public License version 3 (see the file LICENSE).
3
4SET client_min_messages=ERROR;
5
6CREATE TABLE BugTrackerComponentGroup (
7 id serial PRIMARY KEY,
8 name text NOT NULL,
9 bug_tracker integer NOT NULL REFERENCES BugTracker,
10
11 CONSTRAINT valid_name CHECK (valid_name(name))
12);
13
14ALTER TABLE BugTrackerComponentGroup
15 ADD CONSTRAINT bugtrackercomponentgroup__bug_tracker__name__key
16 UNIQUE (bug_tracker, name);
17
18
19CREATE TABLE BugTrackerComponent (
20 id serial PRIMARY KEY,
21 name text NOT NULL,
22 is_visible boolean NOT NULL DEFAULT True,
23 is_custom boolean NOT NULL DEFAULT True,
24 component_group integer NOT NULL REFERENCES BugTrackerComponentGroup,
25 distro_source_package integer REFERENCES DistributionSourcePackage,
26
27 CONSTRAINT valid_name CHECK (valid_name(name))
28);
29
30ALTER TABLE BugTrackerComponent
31 ADD CONSTRAINT bugtrackercomponent__component_group__name__key
32 UNIQUE (component_group, name);
33
34ALTER TABLE BugTrackerComponent
35 ADD CONSTRAINT bugtrackercomponent__distro_source_package__key
36 UNIQUE (distro_source_package);
37
38INSERT INTO LaunchpadDatabaseRevision VALUES(2208, 09, 0);
039
=== added file 'database/schema/patch-2208-10-0.sql'
--- database/schema/patch-2208-10-0.sql 1970-01-01 00:00:00 +0000
+++ database/schema/patch-2208-10-0.sql 2010-10-04 22:08:24 +0000
@@ -0,0 +1,25 @@
1-- Copyright 2009 Canonical Ltd. This software is licensed under the
2-- GNU Affero General Public License version 3 (see the file LICENSE).
3
4SET client_min_messages=ERROR;
5
6-- The `InitialiseDistroSeriesJob` table captures the data required for an ifp job.
7
8CREATE TABLE DistributionJob (
9 id serial PRIMARY KEY,
10 -- FK to the `Job` record with the "generic" data about this archive
11 -- job.
12 job integer NOT NULL CONSTRAINT distributionjob__job__fk REFERENCES job,
13 -- FK to the associated `Distribution` record.
14 distribution integer NOT NULL REFERENCES Distribution,
15 distroseries integer REFERENCES DistroSeries,
16 -- The particular type of foo job
17 job_type integer NOT NULL,
18 -- JSON data for use by the job
19 json_data text
20);
21
22ALTER TABLE DistributionJob ADD CONSTRAINT distributionjob__job__key UNIQUE (job);
23CREATE UNIQUE INDEX distribution_job__initialise_series__distroseries ON DistributionJob (distroseries) WHERE job_type = 1;
24INSERT INTO LaunchpadDatabaseRevision VALUES (2208, 10, 0);
25
026
=== added file 'database/schema/patch-2208-11-0.sql'
--- database/schema/patch-2208-11-0.sql 1970-01-01 00:00:00 +0000
+++ database/schema/patch-2208-11-0.sql 2010-10-04 22:08:24 +0000
@@ -0,0 +1,30 @@
1-- Copyright 2010 Canonical Ltd. This software is licensed under the
2-- GNU Affero General Public License version 3 (see the file LICENSE).
3
4SET client_min_messages=ERROR;
5
6-- This constraint is useless given the current PK
7ALTER TABLE BranchRevision
8DROP CONSTRAINT revisionnumber_branch_id_unique;
9
10-- This constraint is no longer needed as it will be the new PK
11ALTER TABLE BranchRevision
12DROP CONSTRAINT revision__branch__revision__key ;
13
14-- Kill the old PK
15ALTER TABLE BranchRevision
16DROP CONSTRAINT revisionnumber_pkey ;
17
18-- Create the new PK
19ALTER TABLE BranchRevision
20ADD CONSTRAINT revisionnumber_pkey PRIMARY KEY (branch, revision);
21
22-- What was this used for? Not used now.
23DROP VIEW RevisionNumber;
24
25-- Kill the old id.
26ALTER TABLE BranchRevision
27DROP COLUMN id;
28
29
30INSERT INTO LaunchpadDatabaseRevision VALUES (2208, 11, 0);
031
=== added file 'database/schema/patch-2208-12-0.sql'
--- database/schema/patch-2208-12-0.sql 1970-01-01 00:00:00 +0000
+++ database/schema/patch-2208-12-0.sql 2010-10-04 22:08:24 +0000
@@ -0,0 +1,17 @@
1SET client_min_messages=ERROR;
2
3-- Allow for package diffs against both derived and parent versions.
4ALTER TABLE DistroSeriesDifference ADD COLUMN parent_package_diff integer CONSTRAINT distroseriesdifference__parent_package_diff__fk REFERENCES packagediff;
5CREATE INDEX distroseriesdifference__parent_package_diff__idx ON distroseriesdifference(parent_package_diff);
6
7-- Add columns for source_version and parent_source_version
8ALTER TABLE DistroSeriesDifference ADD COLUMN source_version text;
9ALTER TABLE DistroSeriesDifference ADD CONSTRAINT valid_source_version CHECK(valid_debian_version(source_version));
10ALTER TABLE DistroSeriesDifference ADD COLUMN parent_source_version text;
11ALTER TABLE DistroSeriesDifference ADD CONSTRAINT valid_parent_source_version CHECK(valid_debian_version(parent_source_version));
12
13-- Add a unique constraint/index for the source_package_name/derived series combo and drop the previous index.
14ALTER TABLE DistroSeriesDifference ADD CONSTRAINT distroseriesdifference__derived_series__source_package_name__key UNIQUE (derived_series, source_package_name);
15DROP INDEX distroseriesdifference__derived_series__idx;
16
17INSERT INTO LaunchpadDatabaseRevision VALUES (2208, 12, 0);
018
=== added file 'database/schema/patch-2208-13-0.sql'
--- database/schema/patch-2208-13-0.sql 1970-01-01 00:00:00 +0000
+++ database/schema/patch-2208-13-0.sql 2010-10-04 22:08:24 +0000
@@ -0,0 +1,17 @@
1-- Copyright 2010 Canonical Ltd. This software is licensed under the
2-- GNU Affero General Public License version 3 (see the file LICENSE).
3
4SET client_min_messages=ERROR;
5
6CREATE TABLE TranslationTemplatesBuild (
7 id SERIAL PRIMARY KEY,
8 build_farm_job integer NOT NULL REFERENCES BuildFarmJob(id),
9 branch integer NOT NULL REFERENCES Branch(id));
10
11CREATE INDEX translationtemplatesbuild__build_farm_job__idx ON
12 TranslationTemplatesBuild(build_farm_job);
13
14CREATE INDEX translationtemplatesbuild__branch__idx ON
15 TranslationTemplatesBuild(branch);
16
17INSERT INTO LaunchpadDatabaseRevision VALUES (2208, 13, 0);
018
=== added file 'database/schema/patch-2208-14-0.sql'
--- database/schema/patch-2208-14-0.sql 1970-01-01 00:00:00 +0000
+++ database/schema/patch-2208-14-0.sql 2010-10-04 22:08:24 +0000
@@ -0,0 +1,9 @@
1SET client_min_messages=ERROR;
2
3-- Store the row index of bug messages so we don't have to calculate it all the time.
4ALTER TABLE BugMessage ADD COLUMN index integer;
5
6-- BugMessage.indexes must be unique per bug.
7ALTER TABLE BugMessage ADD CONSTRAINT bugmessage__bug__index__key UNIQUE (bug, index);
8
9INSERT INTO LaunchpadDatabaseRevision VALUES (2208, 14, 0);
010
=== added file 'database/schema/patch-2208-15-0.sql'
--- database/schema/patch-2208-15-0.sql 1970-01-01 00:00:00 +0000
+++ database/schema/patch-2208-15-0.sql 2010-10-04 22:08:24 +0000
@@ -0,0 +1,7 @@
1SET client_min_messages=ERROR;
2
3-- Delete index obsoleted by bugtask__date_closed__id__idx2
4
5DROP INDEX bugtask__date_closed__id__idx;
6
7INSERT INTO LaunchpadDatabaseRevision VALUES (2208, 15, 0);
08
=== added file 'database/schema/patch-2208-16-0.sql'
--- database/schema/patch-2208-16-0.sql 1970-01-01 00:00:00 +0000
+++ database/schema/patch-2208-16-0.sql 2010-10-04 22:08:24 +0000
@@ -0,0 +1,8 @@
1-- Copyright 2010 Canonical Ltd. This software is licensed under the
2-- GNU Affero General Public License version 3 (see the file LICENSE).
3SET client_min_messages=ERROR;
4
5ALTER TABLE SourcePackageRecipeBuildJob
6 ALTER COLUMN sourcepackage_recipe_build SET NOT NULL;
7
8INSERT INTO LaunchpadDatabaseRevision VALUES (2208, 16, 0);
09
=== added file 'database/schema/patch-2208-17-0.sql'
--- database/schema/patch-2208-17-0.sql 1970-01-01 00:00:00 +0000
+++ database/schema/patch-2208-17-0.sql 2010-10-04 22:08:24 +0000
@@ -0,0 +1,18 @@
1-- Copyright 2010 Canonical Ltd. This software is licensed under the
2-- GNU Affero General Public License version 3 (see the file LICENSE).
3
4SET client_min_messages=ERROR;
5
6CREATE TABLE IncrementalDiff(
7 id serial PRIMARY KEY,
8 diff integer NOT NULL CONSTRAINT diff_fk REFERENCES Diff ON DELETE CASCADE,
9 branch_merge_proposal integer NOT NULL CONSTRAINT branch_merge_proposal_fk REFERENCES BranchMergeProposal ON DELETE CASCADE,
10 old_revision integer NOT NULL CONSTRAINT old_revision_fk REFERENCES Revision ON DELETE CASCADE,
11 new_revision integer NOT NULL CONSTRAINT new_revision_fk REFERENCES Revision ON DELETE CASCADE);
12
13CREATE INDEX incrementaldiff__diff__idx ON IncrementalDiff(diff);
14CREATE INDEX incrementaldiff__branch_merge_proposal__idx ON IncrementalDiff(branch_merge_proposal);
15CREATE INDEX incrementaldiff__old_revision__idx ON IncrementalDiff(old_revision);
16CREATE INDEX incrementaldiff__new_revision__idx ON IncrementalDiff(new_revision);
17
18INSERT INTO LaunchpadDatabaseRevision VALUES (2208, 17, 0);
019
=== modified file 'database/schema/security.cfg'
--- database/schema/security.cfg 2010-09-21 23:09:59 +0000
+++ database/schema/security.cfg 2010-10-04 22:08:24 +0000
@@ -121,6 +121,8 @@
121public.bugnotificationrecipientarchive = SELECT, UPDATE121public.bugnotificationrecipientarchive = SELECT, UPDATE
122public.bugtag = SELECT, INSERT, DELETE122public.bugtag = SELECT, INSERT, DELETE
123public.bugtrackerperson = SELECT, UPDATE123public.bugtrackerperson = SELECT, UPDATE
124public.bugtrackercomponent = SELECT, INSERT, UPDATE
125public.bugtrackercomponentgroup = SELECT, INSERT, UPDATE
124public.bugwatchactivity = SELECT, INSERT, UPDATE126public.bugwatchactivity = SELECT, INSERT, UPDATE
125public.codeimport = SELECT, INSERT, UPDATE, DELETE127public.codeimport = SELECT, INSERT, UPDATE, DELETE
126public.codeimportevent = SELECT, INSERT, UPDATE128public.codeimportevent = SELECT, INSERT, UPDATE
@@ -138,6 +140,7 @@
138public.databasereplicationlag = SELECT140public.databasereplicationlag = SELECT
139public.diff = SELECT, INSERT, UPDATE141public.diff = SELECT, INSERT, UPDATE
140public.distributionbounty = SELECT, INSERT, UPDATE142public.distributionbounty = SELECT, INSERT, UPDATE
143public.distributionjob = SELECT, INSERT
141public.distributionmirror = SELECT, INSERT, UPDATE, DELETE144public.distributionmirror = SELECT, INSERT, UPDATE, DELETE
142public.distributionsourcepackage = SELECT, INSERT, UPDATE, DELETE145public.distributionsourcepackage = SELECT, INSERT, UPDATE, DELETE
143public.distributionsourcepackagecache = SELECT146public.distributionsourcepackagecache = SELECT
@@ -169,6 +172,7 @@
169public.hwtest = SELECT172public.hwtest = SELECT
170public.hwvendorid = SELECT173public.hwvendorid = SELECT
171public.hwvendorname = SELECT174public.hwvendorname = SELECT
175public.incrementaldiff = SELECT, INSERT, UPDATE, DELETE
172public.job = SELECT, INSERT, UPDATE, DELETE176public.job = SELECT, INSERT, UPDATE, DELETE
173public.karmacache = SELECT177public.karmacache = SELECT
174public.karmacategory = SELECT178public.karmacategory = SELECT
@@ -237,7 +241,6 @@
237public.revision = SELECT, INSERT, UPDATE241public.revision = SELECT, INSERT, UPDATE
238public.revisionauthor = SELECT, INSERT, UPDATE242public.revisionauthor = SELECT, INSERT, UPDATE
239public.revisioncache = SELECT, INSERT, UPDATE, DELETE243public.revisioncache = SELECT, INSERT, UPDATE, DELETE
240public.revisionnumber = SELECT, INSERT
241public.revisionparent = SELECT, INSERT244public.revisionparent = SELECT, INSERT
242public.scriptactivity = SELECT245public.scriptactivity = SELECT
243public.shipitreport = SELECT, INSERT246public.shipitreport = SELECT, INSERT
@@ -276,6 +279,7 @@
276public.translationgroup = SELECT, INSERT, UPDATE279public.translationgroup = SELECT, INSERT, UPDATE
277public.translationimportqueueentry = SELECT, INSERT, UPDATE, DELETE280public.translationimportqueueentry = SELECT, INSERT, UPDATE, DELETE
278public.translationmessage = SELECT, INSERT, UPDATE281public.translationmessage = SELECT, INSERT, UPDATE
282public.translationtemplatesbuild = SELECT, INSERT, UPDATE, DELETE
279public.translator = SELECT, INSERT, UPDATE, DELETE283public.translator = SELECT, INSERT, UPDATE, DELETE
280public.usertouseremail = SELECT, UPDATE284public.usertouseremail = SELECT, UPDATE
281public.validpersoncache = SELECT285public.validpersoncache = SELECT
@@ -538,8 +542,14 @@
538public.bugnotification = SELECT, INSERT542public.bugnotification = SELECT, INSERT
539public.bugnotificationrecipient = SELECT, INSERT543public.bugnotificationrecipient = SELECT, INSERT
540public.bugsubscription = SELECT544public.bugsubscription = SELECT
545public.bugsubscriptionfilter = SELECT
546public.bugsubscriptionfilterstatus = SELECT
547public.bugsubscriptionfilterimportance = SELECT
548public.bugsubscriptionfiltertag = SELECT
541public.bugtask = SELECT, INSERT, UPDATE549public.bugtask = SELECT, INSERT, UPDATE
542public.bugtracker = SELECT, INSERT550public.bugtracker = SELECT, INSERT
551public.bugtrackercomponent = SELECT, INSERT, UPDATE, DELETE
552public.bugtrackercomponentgroup = SELECT, INSERT, UPDATE, DELETE
543public.bugtrackeralias = SELECT553public.bugtrackeralias = SELECT
544public.bugtrackerperson = SELECT, INSERT554public.bugtrackerperson = SELECT, INSERT
545public.bugwatch = SELECT, INSERT, UPDATE555public.bugwatch = SELECT, INSERT, UPDATE
@@ -595,7 +605,9 @@
595public.distribution = SELECT605public.distribution = SELECT
596public.distributionsourcepackage = SELECT, UPDATE606public.distributionsourcepackage = SELECT, UPDATE
597public.emailaddress = SELECT607public.emailaddress = SELECT
608public.incrementaldiff = SELECT
598public.job = SELECT, INSERT, UPDATE, DELETE609public.job = SELECT, INSERT, UPDATE, DELETE
610public.translationtemplatesbuild = SELECT, INSERT
599# Karma611# Karma
600public.karma = SELECT, INSERT612public.karma = SELECT, INSERT
601public.karmaaction = SELECT613public.karmaaction = SELECT
@@ -617,6 +629,10 @@
617public.bugactivity = SELECT, INSERT629public.bugactivity = SELECT, INSERT
618public.bugaffectsperson = SELECT, INSERT, UPDATE, DELETE630public.bugaffectsperson = SELECT, INSERT, UPDATE, DELETE
619public.bugsubscription = SELECT631public.bugsubscription = SELECT
632public.bugsubscriptionfilter = SELECT
633public.bugsubscriptionfilterstatus = SELECT
634public.bugsubscriptionfilterimportance = SELECT
635public.bugsubscriptionfiltertag = SELECT
620public.bugnotification = SELECT, INSERT636public.bugnotification = SELECT, INSERT
621public.bugnotificationrecipient = SELECT, INSERT637public.bugnotificationrecipient = SELECT, INSERT
622public.structuralsubscription = SELECT638public.structuralsubscription = SELECT
@@ -805,6 +821,10 @@
805public.bugactivity = SELECT, INSERT821public.bugactivity = SELECT, INSERT
806public.bugaffectsperson = SELECT, INSERT, UPDATE, DELETE822public.bugaffectsperson = SELECT, INSERT, UPDATE, DELETE
807public.bugsubscription = SELECT823public.bugsubscription = SELECT
824public.bugsubscriptionfilter = SELECT
825public.bugsubscriptionfilterstatus = SELECT
826public.bugsubscriptionfilterimportance = SELECT
827public.bugsubscriptionfiltertag = SELECT
808public.bugnotification = SELECT, INSERT828public.bugnotification = SELECT, INSERT
809public.bugnotificationrecipient = SELECT, INSERT829public.bugnotificationrecipient = SELECT, INSERT
810public.bugnomination = SELECT830public.bugnomination = SELECT
@@ -889,6 +909,7 @@
889public.flatpackagesetinclusion = SELECT909public.flatpackagesetinclusion = SELECT
890public.teamparticipation = SELECT910public.teamparticipation = SELECT
891public.translationimportqueueentry = SELECT, INSERT, UPDATE911public.translationimportqueueentry = SELECT, INSERT, UPDATE
912public.translationtemplatesbuild = SELECT, INSERT
892913
893[ppa-apache-log-parser]914[ppa-apache-log-parser]
894type=user915type=user
@@ -929,6 +950,10 @@
929public.bugpackageinfestation = SELECT, INSERT, UPDATE950public.bugpackageinfestation = SELECT, INSERT, UPDATE
930public.bugproductinfestation = SELECT, INSERT, UPDATE951public.bugproductinfestation = SELECT, INSERT, UPDATE
931public.bugsubscription = SELECT, INSERT, UPDATE, DELETE952public.bugsubscription = SELECT, INSERT, UPDATE, DELETE
953public.bugsubscriptionfilter = SELECT, INSERT, UPDATE, DELETE
954public.bugsubscriptionfilterstatus = SELECT, INSERT, UPDATE, DELETE
955public.bugsubscriptionfilterimportance = SELECT, INSERT, UPDATE, DELETE
956public.bugsubscriptionfiltertag = SELECT, INSERT, UPDATE, DELETE
932public.bugtask = SELECT, INSERT, UPDATE, DELETE957public.bugtask = SELECT, INSERT, UPDATE, DELETE
933public.bugtracker = SELECT, INSERT, UPDATE, DELETE958public.bugtracker = SELECT, INSERT, UPDATE, DELETE
934public.bugtrackeralias = SELECT, INSERT, UPDATE, DELETE959public.bugtrackeralias = SELECT, INSERT, UPDATE, DELETE
@@ -1157,6 +1182,10 @@
1157public.bugaffectsperson = SELECT, INSERT, UPDATE, DELETE1182public.bugaffectsperson = SELECT, INSERT, UPDATE, DELETE
1158public.bugjob = SELECT, INSERT1183public.bugjob = SELECT, INSERT
1159public.bugsubscription = SELECT1184public.bugsubscription = SELECT
1185public.bugsubscriptionfilter = SELECT
1186public.bugsubscriptionfilterstatus = SELECT
1187public.bugsubscriptionfilterimportance = SELECT
1188public.bugsubscriptionfiltertag = SELECT
1160public.bugnotification = SELECT, INSERT1189public.bugnotification = SELECT, INSERT
1161public.bugnotificationrecipient = SELECT, INSERT1190public.bugnotificationrecipient = SELECT, INSERT
1162public.bugnomination = SELECT1191public.bugnomination = SELECT
@@ -1259,6 +1288,10 @@
1259public.bugaffectsperson = SELECT, INSERT, UPDATE, DELETE1288public.bugaffectsperson = SELECT, INSERT, UPDATE, DELETE
1260public.bugjob = SELECT, INSERT1289public.bugjob = SELECT, INSERT
1261public.bugsubscription = SELECT1290public.bugsubscription = SELECT
1291public.bugsubscriptionfilter = SELECT
1292public.bugsubscriptionfilterstatus = SELECT
1293public.bugsubscriptionfilterimportance = SELECT
1294public.bugsubscriptionfiltertag = SELECT
1262public.bugnotification = SELECT, INSERT1295public.bugnotification = SELECT, INSERT
1263public.bugnotificationrecipient = SELECT, INSERT1296public.bugnotificationrecipient = SELECT, INSERT
1264public.bugnomination = SELECT1297public.bugnomination = SELECT
@@ -1326,6 +1359,10 @@
1326public.bugnotification = SELECT, INSERT, UPDATE1359public.bugnotification = SELECT, INSERT, UPDATE
1327public.bugnotificationrecipient = SELECT, INSERT, UPDATE1360public.bugnotificationrecipient = SELECT, INSERT, UPDATE
1328public.bugsubscription = SELECT, INSERT1361public.bugsubscription = SELECT, INSERT
1362public.bugsubscriptionfilter = SELECT, INSERT
1363public.bugsubscriptionfilterstatus = SELECT, INSERT
1364public.bugsubscriptionfilterimportance = SELECT, INSERT
1365public.bugsubscriptionfiltertag = SELECT, INSERT
1329public.bugnomination = SELECT1366public.bugnomination = SELECT
1330public.bug = SELECT, INSERT, UPDATE1367public.bug = SELECT, INSERT, UPDATE
1331public.bugactivity = SELECT, INSERT1368public.bugactivity = SELECT, INSERT
@@ -1440,6 +1477,7 @@
1440[translationsbranchscanner]1477[translationsbranchscanner]
1441type=user1478type=user
1442groups=branchscanner,translations_approval1479groups=branchscanner,translations_approval
1480public.translationtemplatesbuild = SELECT, INSERT
14431481
1444[translationstobranch]1482[translationstobranch]
1445type=user1483type=user
@@ -1545,6 +1583,10 @@
1545public.bugaffectsperson = SELECT, INSERT, UPDATE, DELETE1583public.bugaffectsperson = SELECT, INSERT, UPDATE, DELETE
1546public.bugjob = SELECT, INSERT1584public.bugjob = SELECT, INSERT
1547public.bugsubscription = SELECT, INSERT1585public.bugsubscription = SELECT, INSERT
1586public.bugsubscriptionfilter = SELECT, INSERT
1587public.bugsubscriptionfilterstatus = SELECT, INSERT
1588public.bugsubscriptionfilterimportance = SELECT, INSERT
1589public.bugsubscriptionfiltertag = SELECT, INSERT
1548public.bugnotification = SELECT, INSERT1590public.bugnotification = SELECT, INSERT
1549public.bugnotificationattachment = SELECT1591public.bugnotificationattachment = SELECT
1550public.bugnotificationrecipient = SELECT, INSERT1592public.bugnotificationrecipient = SELECT, INSERT
@@ -1553,6 +1595,10 @@
1553public.bugtask = SELECT, INSERT, UPDATE1595public.bugtask = SELECT, INSERT, UPDATE
1554public.bugmessage = SELECT, INSERT1596public.bugmessage = SELECT, INSERT
1555public.bugsubscription = SELECT, INSERT, UPDATE, DELETE1597public.bugsubscription = SELECT, INSERT, UPDATE, DELETE
1598public.bugsubscriptionfilter = SELECT, INSERT, UPDATE, DELETE
1599public.bugsubscriptionfilterstatus = SELECT, INSERT, UPDATE, DELETE
1600public.bugsubscriptionfilterimportance = SELECT, INSERT, UPDATE, DELETE
1601public.bugsubscriptionfiltertag = SELECT, INSERT, UPDATE, DELETE
1556public.bugtracker = SELECT, INSERT1602public.bugtracker = SELECT, INSERT
1557public.bugtrackeralias = SELECT, INSERT1603public.bugtrackeralias = SELECT, INSERT
1558public.bugwatch = SELECT, INSERT1604public.bugwatch = SELECT, INSERT
@@ -1719,6 +1765,7 @@
1719public.distribution = SELECT1765public.distribution = SELECT
1720public.distroseries = SELECT1766public.distroseries = SELECT
1721public.emailaddress = SELECT1767public.emailaddress = SELECT
1768public.incrementaldiff = SELECT, INSERT
1722public.job = SELECT, INSERT, UPDATE1769public.job = SELECT, INSERT, UPDATE
1723public.karmaaction = SELECT1770public.karmaaction = SELECT
1724public.karma = SELECT, INSERT1771public.karma = SELECT, INSERT
@@ -1731,6 +1778,7 @@
1731public.previewdiff = SELECT, INSERT1778public.previewdiff = SELECT, INSERT
1732public.product = SELECT1779public.product = SELECT
1733public.productseries = SELECT1780public.productseries = SELECT
1781public.revision = SELECT
1734public.seriessourcepackagebranch = SELECT1782public.seriessourcepackagebranch = SELECT
1735public.sourcepackagename = SELECT1783public.sourcepackagename = SELECT
1736public.staticdiff = SELECT, INSERT1784public.staticdiff = SELECT, INSERT
@@ -1812,6 +1860,10 @@
1812public.message = SELECT, INSERT1860public.message = SELECT, INSERT
1813public.messagechunk = SELECT, INSERT1861public.messagechunk = SELECT, INSERT
1814public.bugsubscription = SELECT, INSERT1862public.bugsubscription = SELECT, INSERT
1863public.bugsubscriptionfilter = SELECT, INSERT
1864public.bugsubscriptionfilterstatus = SELECT, INSERT
1865public.bugsubscriptionfilterimportance = SELECT, INSERT
1866public.bugsubscriptionfiltertag = SELECT, INSERT
1815public.bugmessage = SELECT, INSERT1867public.bugmessage = SELECT, INSERT
1816public.sourcepackagename = SELECT1868public.sourcepackagename = SELECT
1817public.job = SELECT, INSERT, UPDATE1869public.job = SELECT, INSERT, UPDATE
@@ -1839,6 +1891,10 @@
1839public.bug = SELECT, UPDATE1891public.bug = SELECT, UPDATE
1840public.bugattachment = SELECT, DELETE1892public.bugattachment = SELECT, DELETE
1841public.bugsubscription = SELECT1893public.bugsubscription = SELECT
1894public.bugsubscriptionfilter = SELECT
1895public.bugsubscriptionfilterstatus = SELECT
1896public.bugsubscriptionfilterimportance = SELECT
1897public.bugsubscriptionfiltertag = SELECT
1842public.bugaffectsperson = SELECT1898public.bugaffectsperson = SELECT
1843public.bugnotification = SELECT, DELETE1899public.bugnotification = SELECT, DELETE
1844public.bugnotificationrecipientarchive = SELECT1900public.bugnotificationrecipientarchive = SELECT
18451901
=== modified file 'lib/canonical/config/schema-lazr.conf'
--- lib/canonical/config/schema-lazr.conf 2010-09-24 14:24:06 +0000
+++ lib/canonical/config/schema-lazr.conf 2010-10-04 22:08:24 +0000
@@ -301,6 +301,18 @@
301# datatype: string301# datatype: string
302logfile: -302logfile: -
303303
304# The location of the log file used by the LaunchpadForkingService
305# datatype: string
306forker_logfile: -
307
308# Should we be using the forking daemon? Or should we be calling spawnProcess
309# instead?
310# datatype: boolean
311use_forking_daemon: False
312# What disk path will the daemon listen on
313# datatype: string
314forking_daemon_socket: /var/tmp/launchpad_forking_service.sock
315
304# The prefix of the web URL for all public branches. This should end with a316# The prefix of the web URL for all public branches. This should end with a
305# slash.317# slash.
306#318#
@@ -644,6 +656,11 @@
644# datatype: integer656# datatype: integer
645storm_cache_size: 500657storm_cache_size: 500
646658
659# Where database/replication/slon_ctl.py dumps its logs. Used for the
660# staging replication environment.
661# datatype: existing_directory
662replication_logdir: database/replication
663
647664
648[diff]665[diff]
649# The maximum size in bytes to read from the librarian to make available in666# The maximum size in bytes to read from the librarian to make available in
650667
=== modified file 'lib/canonical/launchpad/icing/style-3-0.css.in'
--- lib/canonical/launchpad/icing/style-3-0.css.in 2010-09-10 17:32:29 +0000
+++ lib/canonical/launchpad/icing/style-3-0.css.in 2010-10-04 22:08:24 +0000
@@ -2419,7 +2419,7 @@
2419 background-repeat: no-repeat;2419 background-repeat: no-repeat;
2420 background-position:right center;2420 background-position:right center;
2421 }2421 }
2422table#packages_list tr.superseded {2422table#packages_list tr.superseded, tr.blacklisted {
2423 background-color: #eee;2423 background-color: #eee;
2424 }2424 }
2425ul.latest-ppa-updates li:nth-child(odd) {2425ul.latest-ppa-updates li:nth-child(odd) {
24262426
=== modified file 'lib/canonical/launchpad/interfaces/__init__.py'
--- lib/canonical/launchpad/interfaces/__init__.py 2010-09-30 17:08:50 +0000
+++ lib/canonical/launchpad/interfaces/__init__.py 2010-10-04 22:08:24 +0000
@@ -55,6 +55,8 @@
55from lp.registry.interfaces.distribution import *55from lp.registry.interfaces.distribution import *
56from lp.registry.interfaces.distributionmirror import *56from lp.registry.interfaces.distributionmirror import *
57from lp.registry.interfaces.distributionsourcepackage import *57from lp.registry.interfaces.distributionsourcepackage import *
58from lp.registry.interfaces.distroseriesdifference import *
59from lp.registry.interfaces.distroseriesdifferencecomment import *
58from lp.soyuz.interfaces.distributionsourcepackagecache import *60from lp.soyuz.interfaces.distributionsourcepackagecache import *
59from lp.soyuz.interfaces.distributionsourcepackagerelease import *61from lp.soyuz.interfaces.distributionsourcepackagerelease import *
60from lp.registry.interfaces.series import *62from lp.registry.interfaces.series import *
6163
=== modified file 'lib/canonical/launchpad/interfaces/_schema_circular_imports.py'
--- lib/canonical/launchpad/interfaces/_schema_circular_imports.py 2010-08-27 11:19:54 +0000
+++ lib/canonical/launchpad/interfaces/_schema_circular_imports.py 2010-10-04 22:08:24 +0000
@@ -77,6 +77,9 @@
77 IDistributionSourcePackage,77 IDistributionSourcePackage,
78 )78 )
79from lp.registry.interfaces.distroseries import IDistroSeries79from lp.registry.interfaces.distroseries import IDistroSeries
80from lp.registry.interfaces.distroseriesdifferencecomment import (
81 IDistroSeriesDifferenceComment,
82 )
80from lp.registry.interfaces.person import (83from lp.registry.interfaces.person import (
81 IPerson,84 IPerson,
82 IPersonPublic,85 IPersonPublic,
@@ -89,6 +92,7 @@
89 IStructuralSubscription,92 IStructuralSubscription,
90 IStructuralSubscriptionTarget,93 IStructuralSubscriptionTarget,
91 )94 )
95from lp.services.comments.interfaces.conversation import IComment
92from lp.soyuz.enums import (96from lp.soyuz.enums import (
93 PackagePublishingStatus,97 PackagePublishingStatus,
94 PackageUploadCustomFormat,98 PackageUploadCustomFormat,
@@ -321,6 +325,9 @@
321IBuildFarmJob['status'].vocabulary = BuildStatus325IBuildFarmJob['status'].vocabulary = BuildStatus
322IBuildFarmJob['buildqueue_record'].schema = IBuildQueue326IBuildFarmJob['buildqueue_record'].schema = IBuildQueue
323327
328# IComment
329IComment['comment_author'].schema = IPerson
330
324# IDistribution331# IDistribution
325IDistribution['series'].value_type.schema = IDistroSeries332IDistribution['series'].value_type.schema = IDistroSeries
326patch_reference_property(333patch_reference_property(
@@ -366,6 +373,9 @@
366 IDistroSeries, 'getPackageUploads', IPackageUpload)373 IDistroSeries, 'getPackageUploads', IPackageUpload)
367patch_reference_property(IDistroSeries, 'parent_series', IDistroSeries)374patch_reference_property(IDistroSeries, 'parent_series', IDistroSeries)
368375
376# IDistroSeriesDifferenceComment
377IDistroSeriesDifferenceComment['comment_author'].schema = IPerson
378
369# IDistroArchSeries379# IDistroArchSeries
370patch_reference_property(IDistroArchSeries, 'main_archive', IArchive)380patch_reference_property(IDistroArchSeries, 'main_archive', IArchive)
371381
372382
=== modified file 'lib/canonical/launchpad/scripts/runlaunchpad.py'
--- lib/canonical/launchpad/scripts/runlaunchpad.py 2010-09-17 20:46:58 +0000
+++ lib/canonical/launchpad/scripts/runlaunchpad.py 2010-10-04 22:08:24 +0000
@@ -184,6 +184,53 @@
184 stop_at_exit(process)184 stop_at_exit(process)
185185
186186
187class ForkingSessionService(Service):
188 """A lp-forking-service for handling ssh access."""
189
190 # TODO: The SFTP (and bzr+ssh) server depends fairly heavily on this
191 # service. It would seem reasonable to make one always start if the
192 # other one is started. Though this might be a way to "FeatureFlag"
193 # whether this is active or not.
194
195 @property
196 def should_launch(self):
197 return (config.codehosting.launch and
198 config.codehosting.use_forking_daemon)
199
200 @property
201 def logfile(self):
202 """Return the log file to use.
203
204 Default to the value of the configuration key logfile.
205 """
206 return config.codehosting.forker_logfile
207
208 def launch(self):
209 # Following the logic in TacFile. Specifically, if you configure sftp
210 # to not run (and thus bzr+ssh) then we don't want to run the forking
211 # service.
212 if not self.should_launch:
213 return
214 from lp.codehosting import get_bzr_path
215 command = [config.root + '/bin/py', get_bzr_path(),
216 'launchpad-forking-service',
217 '--path', config.codehosting.forking_daemon_socket,
218 ]
219 env = dict(os.environ)
220 env['BZR_PLUGIN_PATH'] = config.root + '/bzrplugins'
221 logfile = self.logfile
222 if logfile == '-':
223 # This process uses a different logging infrastructure from the
224 # rest of the Launchpad code. As such, it cannot trivially use '-'
225 # as the logfile. So we just ignore this setting.
226 pass
227 else:
228 env['BZR_LOG'] = logfile
229 process = subprocess.Popen(command, env=env, stdin=subprocess.PIPE)
230 process.stdin.close()
231 stop_at_exit(process)
232
233
187def stop_at_exit(process):234def stop_at_exit(process):
188 """Create and register an atexit hook for killing a process.235 """Create and register an atexit hook for killing a process.
189236
@@ -208,6 +255,9 @@
208 'librarian': TacFile('librarian', 'daemons/librarian.tac',255 'librarian': TacFile('librarian', 'daemons/librarian.tac',
209 'librarian_server', prepare_for_librarian),256 'librarian_server', prepare_for_librarian),
210 'sftp': TacFile('sftp', 'daemons/sftp.tac', 'codehosting'),257 'sftp': TacFile('sftp', 'daemons/sftp.tac', 'codehosting'),
258 # TODO, we probably need to run the forking service whenever somebody
259 # requests the sftp service...
260 'forker': ForkingSessionService(),
211 'mailman': MailmanService(),261 'mailman': MailmanService(),
212 'codebrowse': CodebrowseService(),262 'codebrowse': CodebrowseService(),
213 'google-webservice': GoogleWebService(),263 'google-webservice': GoogleWebService(),
214264
=== modified file 'lib/canonical/launchpad/webapp/interfaces.py'
--- lib/canonical/launchpad/webapp/interfaces.py 2010-09-12 11:43:36 +0000
+++ lib/canonical/launchpad/webapp/interfaces.py 2010-10-04 22:08:24 +0000
@@ -335,6 +335,10 @@
335 query_string_params = Attribute(335 query_string_params = Attribute(
336 'A dictionary of the query string parameters.')336 'A dictionary of the query string parameters.')
337337
338 is_ajax = Bool(
339 title=_('Is ajax'), required=False, readonly=True,
340 description=_("Indicates whether the request is an XMLHttpRequest."))
341
338 def getRootURL(rootsite):342 def getRootURL(rootsite):
339 """Return this request's root URL.343 """Return this request's root URL.
340344
341345
=== modified file 'lib/canonical/launchpad/webapp/servers.py'
--- lib/canonical/launchpad/webapp/servers.py 2010-09-22 15:17:39 +0000
+++ lib/canonical/launchpad/webapp/servers.py 2010-10-04 22:08:24 +0000
@@ -526,7 +526,27 @@
526 return decoded_qs526 return decoded_qs
527527
528528
529class BasicLaunchpadRequest:529class LaunchpadBrowserRequestMixin:
530 """Provides methods used for both API and web browser requests."""
531
532 def getRootURL(self, rootsite):
533 """See IBasicLaunchpadRequest."""
534 if rootsite is not None:
535 assert rootsite in allvhosts.configs, (
536 "rootsite is %s. Must be in %r." % (
537 rootsite, sorted(allvhosts.configs.keys())))
538 root_url = allvhosts.configs[rootsite].rooturl
539 else:
540 root_url = self.getApplicationURL() + '/'
541 return root_url
542
543 @property
544 def is_ajax(self):
545 """See `IBasicLaunchpadRequest`."""
546 return 'XMLHttpRequest' == self.getHeader('HTTP_X_REQUESTED_WITH')
547
548
549class BasicLaunchpadRequest(LaunchpadBrowserRequestMixin):
530 """Mixin request class to provide stepstogo."""550 """Mixin request class to provide stepstogo."""
531551
532 implements(IBasicLaunchpadRequest)552 implements(IBasicLaunchpadRequest)
@@ -581,24 +601,8 @@
581 return get_query_string_params(self)601 return get_query_string_params(self)
582602
583603
584class LaunchpadBrowserRequestMixin:
585 """A mixin for classes that share some method implementations."""
586
587 def getRootURL(self, rootsite):
588 """See IBasicLaunchpadRequest."""
589 if rootsite is not None:
590 assert rootsite in allvhosts.configs, (
591 "rootsite is %s. Must be in %r." % (
592 rootsite, sorted(allvhosts.configs.keys())))
593 root_url = allvhosts.configs[rootsite].rooturl
594 else:
595 root_url = self.getApplicationURL() + '/'
596 return root_url
597
598
599class LaunchpadBrowserRequest(BasicLaunchpadRequest, BrowserRequest,604class LaunchpadBrowserRequest(BasicLaunchpadRequest, BrowserRequest,
600 NotificationRequest, ErrorReportRequest,605 NotificationRequest, ErrorReportRequest):
601 LaunchpadBrowserRequestMixin):
602 """Integration of launchpad mixin request classes to make an uber606 """Integration of launchpad mixin request classes to make an uber
603 launchpad request class.607 launchpad request class.
604 """608 """
@@ -1370,7 +1374,7 @@
13701374
13711375
1372class PublicXMLRPCRequest(BasicLaunchpadRequest, XMLRPCRequest,1376class PublicXMLRPCRequest(BasicLaunchpadRequest, XMLRPCRequest,
1373 ErrorReportRequest, LaunchpadBrowserRequestMixin):1377 ErrorReportRequest):
1374 """Request type for doing public XML-RPC in Launchpad."""1378 """Request type for doing public XML-RPC in Launchpad."""
13751379
1376 def _createResponse(self):1380 def _createResponse(self):
13771381
=== modified file 'lib/canonical/launchpad/webapp/tests/test_servers.py'
--- lib/canonical/launchpad/webapp/tests/test_servers.py 2010-08-20 20:31:18 +0000
+++ lib/canonical/launchpad/webapp/tests/test_servers.py 2010-10-04 22:08:24 +0000
@@ -358,6 +358,20 @@
358 retried_request.response.getHeader('Vary'),358 retried_request.response.getHeader('Vary'),
359 'Cookie, Authorization')359 'Cookie, Authorization')
360360
361 def test_is_ajax_false(self):
362 """Normal requests do not define HTTP_X_REQUESTED_WITH."""
363 request = LaunchpadBrowserRequest(StringIO.StringIO(''), {})
364
365 self.assertFalse(request.is_ajax)
366
367 def test_is_ajax_true(self):
368 """Requests with HTTP_X_REQUESTED_WITH set are ajax requests."""
369 request = LaunchpadBrowserRequest(StringIO.StringIO(''), {
370 'HTTP_X_REQUESTED_WITH': 'XMLHttpRequest',
371 })
372
373 self.assertTrue(request.is_ajax)
374
361375
362class IThingSet(Interface):376class IThingSet(Interface):
363 """Marker interface for a set of things."""377 """Marker interface for a set of things."""
364378
=== modified file 'lib/canonical/launchpad/zcml/librarian.zcml'
--- lib/canonical/launchpad/zcml/librarian.zcml 2010-09-30 02:52:07 +0000
+++ lib/canonical/launchpad/zcml/librarian.zcml 2010-10-04 22:08:24 +0000
@@ -16,7 +16,7 @@
16 <allow interface="canonical.launchpad.interfaces.librarian.ILibraryFileAliasWithParent" />16 <allow interface="canonical.launchpad.interfaces.librarian.ILibraryFileAliasWithParent" />
17 <require17 <require
18 permission="launchpad.Edit"18 permission="launchpad.Edit"
19 set_attributes="restricted" />19 set_attributes="mimetype restricted" />
20 </class>20 </class>
2121
22 <class class="canonical.launchpad.database.librarian.LibraryFileContent">22 <class class="canonical.launchpad.database.librarian.LibraryFileContent">
2323
=== modified file 'lib/lp/app/templates/base-layout-macros.pt'
--- lib/lp/app/templates/base-layout-macros.pt 2010-09-29 03:26:01 +0000
+++ lib/lp/app/templates/base-layout-macros.pt 2010-10-04 22:08:24 +0000
@@ -181,6 +181,8 @@
181 <script type="text/javascript"181 <script type="text/javascript"
182 tal:attributes="src string:${lp_js}/bugs/bugtracker_overlay.js"></script>182 tal:attributes="src string:${lp_js}/bugs/bugtracker_overlay.js"></script>
183 <script type="text/javascript"183 <script type="text/javascript"
184 tal:attributes="src string:${lp_js}/registry/distroseriesdifferences_details.js"></script>
185 <script type="text/javascript"
184 tal:attributes="src string:${lp_js}/registry/milestoneoverlay.js"></script>186 tal:attributes="src string:${lp_js}/registry/milestoneoverlay.js"></script>
185 <script type="text/javascript"187 <script type="text/javascript"
186 tal:attributes="src string:${lp_js}/registry/milestonetable.js"></script>188 tal:attributes="src string:${lp_js}/registry/milestonetable.js"></script>
187189
=== modified file 'lib/lp/bugs/browser/bugattachment.py'
--- lib/lp/bugs/browser/bugattachment.py 2010-09-06 07:44:21 +0000
+++ lib/lp/bugs/browser/bugattachment.py 2010-10-04 22:08:24 +0000
@@ -12,19 +12,21 @@
12 'BugAttachmentURL',12 'BugAttachmentURL',
13 ]13 ]
1414
15from cStringIO import StringIO15from zope.component import (
1616 getMultiAdapter,
17from zope.component import getUtility17 getUtility,
18 )
18from zope.contenttype import guess_content_type19from zope.contenttype import guess_content_type
19from zope.interface import implements20from zope.interface import implements
2021
21from canonical.launchpad.browser.librarian import (22from canonical.launchpad.browser.librarian import (
22 FileNavigationMixin,23 FileNavigationMixin,
23 ProxiedLibraryFileAlias,24 ProxiedLibraryFileAlias,
24 StreamOrRedirectLibraryFileAliasView,
25 SafeStreamOrRedirectLibraryFileAliasView,25 SafeStreamOrRedirectLibraryFileAliasView,
26 )26 )
27from canonical.launchpad.interfaces.librarian import ILibraryFileAliasSet27from canonical.launchpad.interfaces.librarian import (
28 ILibraryFileAliasWithParent,
29 )
28from canonical.launchpad.webapp import (30from canonical.launchpad.webapp import (
29 canonical_url,31 canonical_url,
30 custom_widget,32 custom_widget,
@@ -163,7 +165,10 @@
163 self.context.title = data['title']165 self.context.title = data['title']
164166
165 if self.context.libraryfile.mimetype != data['contenttype']:167 if self.context.libraryfile.mimetype != data['contenttype']:
166 self.updateContentType(data['contenttype'])168 lfa_with_parent = getMultiAdapter(
169 (self.context.libraryfile, self.context),
170 ILibraryFileAliasWithParent)
171 lfa_with_parent.mimetype = data['contenttype']
167172
168 @action('Delete Attachment', name='delete')173 @action('Delete Attachment', name='delete')
169 def delete_action(self, action, data):174 def delete_action(self, action, data):
@@ -174,20 +179,6 @@
174 url=libraryfile_url, name=self.context.title))179 url=libraryfile_url, name=self.context.title))
175 self.context.removeFromBug(user=self.user)180 self.context.removeFromBug(user=self.user)
176181
177 def updateContentType(self, new_content_type):
178 """Update the attachment content type."""
179 filealiasset = getUtility(ILibraryFileAliasSet)
180 old_filealias = self.context.libraryfile
181 # Download the file and upload it again with the new content
182 # type.
183 # XXX: Bjorn Tillenius 2005-06-30:
184 # It should be possible to simply create a new filealias
185 # with the same content as the old one.
186 old_content = old_filealias.read()
187 self.context.libraryfile = filealiasset.create(
188 name=old_filealias.filename, size=len(old_content),
189 file=StringIO(old_content), contentType=new_content_type)
190
191 @property182 @property
192 def label(self):183 def label(self):
193 return smartquote('Bug #%d - Edit attachment "%s"') % (184 return smartquote('Bug #%d - Edit attachment "%s"') % (
194185
=== added file 'lib/lp/bugs/browser/tests/test_bugattachment_edit_view.py'
--- lib/lp/bugs/browser/tests/test_bugattachment_edit_view.py 1970-01-01 00:00:00 +0000
+++ lib/lp/bugs/browser/tests/test_bugattachment_edit_view.py 2010-10-04 22:08:24 +0000
@@ -0,0 +1,107 @@
1# Copyright 2010 Canonical Ltd. This software is licensed under the
2# GNU Affero General Public License version 3 (see the file LICENSE).
3
4__metaclass__ = type
5
6import transaction
7from zope.security.interfaces import Unauthorized
8
9from canonical.testing import LaunchpadFunctionalLayer
10from lp.testing import (
11 login_person,
12 TestCaseWithFactory,
13 )
14from lp.testing.views import create_initialized_view
15
16
17class TestBugAttachmentEditView(TestCaseWithFactory):
18 """Tests of traversal to and access of files of bug attachments."""
19
20 layer = LaunchpadFunctionalLayer
21
22 CHANGE_FORM_DATA = {
23 'field.title': 'new description',
24 'field.patch': 'on',
25 'field.contenttype': 'application/whatever',
26 'field.actions.change': 'Change',
27 }
28
29 def setUp(self):
30 super(TestBugAttachmentEditView, self).setUp()
31 self.bug_owner = self.factory.makePerson()
32 login_person(self.bug_owner)
33 self.bug = self.factory.makeBug(owner=self.bug_owner)
34 self.bugattachment = self.factory.makeBugAttachment(
35 bug=self.bug, filename='foo.diff', data='file content',
36 description='attachment description', content_type='text/plain',
37 is_patch=False)
38 # The Librarian server should know about the new file before
39 # we start the tests.
40 transaction.commit()
41
42 def test_change_action_public_bug(self):
43 # Properties of attachments for public bugs can be
44 # changed by every user.
45 user = self.factory.makePerson()
46 login_person(user)
47 create_initialized_view(
48 self.bugattachment, name='+edit', form=self.CHANGE_FORM_DATA)
49 self.assertEqual('new description', self.bugattachment.title)
50 self.assertTrue(self.bugattachment.is_patch)
51 self.assertEqual(
52 'application/whatever', self.bugattachment.libraryfile.mimetype)
53
54 def test_change_action_private_bug(self):
55 # Subscribers of a private bug can edit attachments.
56 user = self.factory.makePerson()
57 self.bug.subscribe(user, self.bug_owner)
58 self.bug.setPrivate(True, self.bug_owner)
59 transaction.commit()
60 login_person(user)
61 create_initialized_view(
62 self.bugattachment, name='+edit', form=self.CHANGE_FORM_DATA)
63 self.assertEqual('new description', self.bugattachment.title)
64 self.assertTrue(self.bugattachment.is_patch)
65 self.assertEqual(
66 'application/whatever', self.bugattachment.libraryfile.mimetype)
67
68 def test_change_action_private_bug_unauthorized(self):
69 # Other users cannot edit attachments of private bugs.
70 user = self.factory.makePerson()
71 self.bug.setPrivate(True, self.bug_owner)
72 transaction.commit()
73 login_person(user)
74 self.assertRaises(
75 Unauthorized, create_initialized_view, self.bugattachment,
76 name='+edit', form=self.CHANGE_FORM_DATA)
77
78 DELETE_FORM_DATA = {
79 'field.actions.delete': 'Delete Attachment',
80 }
81
82 def test_delete_action_public_bug(self):
83 # Bug attachments can be removed from a bug.
84 user = self.factory.makePerson()
85 login_person(user)
86 create_initialized_view(
87 self.bugattachment, name='+edit', form=self.DELETE_FORM_DATA)
88 self.assertEqual(0, self.bug.attachments.count())
89
90 def test_delete_action_private_bug(self):
91 # Subscribers of a private bug can delete attachments.
92 user = self.factory.makePerson()
93 self.bug.subscribe(user, self.bug_owner)
94 self.bug.setPrivate(True, self.bug_owner)
95 login_person(user)
96 create_initialized_view(
97 self.bugattachment, name='+edit', form=self.DELETE_FORM_DATA)
98 self.assertEqual(0, self.bug.attachments.count())
99
100 def test_delete_action_private_bug_unautorized(self):
101 # Other users cannot delete private bug attachments.
102 user = self.factory.makePerson()
103 self.bug.setPrivate(True, self.bug_owner)
104 login_person(user)
105 self.assertRaises(
106 Unauthorized, create_initialized_view, self.bugattachment,
107 name='+edit', form=self.DELETE_FORM_DATA)
0108
=== modified file 'lib/lp/bugs/configure.zcml'
--- lib/lp/bugs/configure.zcml 2010-09-28 14:59:25 +0000
+++ lib/lp/bugs/configure.zcml 2010-10-04 22:08:24 +0000
@@ -368,10 +368,14 @@
368 aliases368 aliases
369 baseurl369 baseurl
370 bugtrackertype370 bugtrackertype
371 componentForDistroSourcePackage
372 component_groups
371 contactdetails373 contactdetails
374 getAllRemoteComponentGroups
372 getBugFilingAndSearchLinks375 getBugFilingAndSearchLinks
373 getBugsWatching376 getBugsWatching
374 getLinkedPersonByName377 getLinkedPersonByName
378 getRemoteComponentGroup
375 has_lp_plugin379 has_lp_plugin
376 id380 id
377 imported_bug_messages381 imported_bug_messages
@@ -394,6 +398,7 @@
394 destroySelf398 destroySelf
395 ensurePersonForSelf399 ensurePersonForSelf
396 linkPersonToSelf400 linkPersonToSelf
401 addRemoteComponentGroup
397 "402 "
398 set_attributes="403 set_attributes="
399 aliases404 aliases
@@ -461,6 +466,47 @@
461 interface="lp.bugs.interfaces.bugtracker.IBugTrackerAliasSet"/>466 interface="lp.bugs.interfaces.bugtracker.IBugTrackerAliasSet"/>
462 </securedutility>467 </securedutility>
463468
469 <!--BugTrackerComponent -->
470
471 <class
472 class="lp.bugs.model.bugtracker.BugTrackerComponent">
473 <require
474 permission="zope.Public"
475 attributes="
476 id
477 name
478 is_visible
479 is_custom
480 "/>
481 <require
482 permission="launchpad.AnyPerson"
483 set_attributes="
484 is_visible
485 is_custom
486 "/>
487 <implements
488 interface="lp.bugs.interfaces.bugtracker.IBugTrackerComponent"/>
489 </class>
490
491 <!--BugTrackerComponentGroup -->
492
493 <class
494 class="lp.bugs.model.bugtracker.BugTrackerComponentGroup">
495 <require
496 permission="zope.Public"
497 attributes="
498 id
499 name
500 bug_tracker
501 components
502 getComponent
503 addComponent
504 addCustomComponent
505 "/>
506 <implements
507 interface="lp.bugs.interfaces.bugtracker.IBugTrackerComponentGroup"/>
508 </class>
509
464 <!-- RemoteBug -->510 <!-- RemoteBug -->
465511
466 <class512 <class
467513
=== modified file 'lib/lp/bugs/doc/initial-bug-contacts.txt'
--- lib/lp/bugs/doc/initial-bug-contacts.txt 2010-08-20 01:29:08 +0000
+++ lib/lp/bugs/doc/initial-bug-contacts.txt 2010-10-04 22:08:24 +0000
@@ -16,7 +16,7 @@
16 >>> debian = getUtility(IDistributionSet).getByName("debian")16 >>> debian = getUtility(IDistributionSet).getByName("debian")
17 >>> debian_firefox = debian.getSourcePackage("mozilla-firefox")17 >>> debian_firefox = debian.getSourcePackage("mozilla-firefox")
1818
19 >>> debian_firefox.bug_subscriptions19 >>> list(debian_firefox.bug_subscriptions)
20 []20 []
2121
22Adding a package subscription is done with the22Adding a package subscription is done with the
2323
=== modified file 'lib/lp/bugs/interfaces/bugtracker.py'
--- lib/lp/bugs/interfaces/bugtracker.py 2010-09-19 23:52:49 +0000
+++ lib/lp/bugs/interfaces/bugtracker.py 2010-10-04 22:08:24 +0000
@@ -12,6 +12,8 @@
12 'IBugTracker',12 'IBugTracker',
13 'IBugTrackerAlias',13 'IBugTrackerAlias',
14 'IBugTrackerAliasSet',14 'IBugTrackerAliasSet',
15 'IBugTrackerComponent',
16 'IBugTrackerComponentGroup',
15 'IBugTrackerSet',17 'IBugTrackerSet',
16 'IRemoteBug',18 'IRemoteBug',
17 'SINGLE_PRODUCT_BUGTRACKERTYPES',19 'SINGLE_PRODUCT_BUGTRACKERTYPES',
@@ -29,6 +31,7 @@
29 export_as_webservice_entry,31 export_as_webservice_entry,
30 export_factory_operation,32 export_factory_operation,
31 export_read_operation,33 export_read_operation,
34 export_write_operation,
32 exported,35 exported,
33 operation_parameters,36 operation_parameters,
34 operation_returns_entry,37 operation_returns_entry,
@@ -353,6 +356,26 @@
353 point between now and 24 hours hence.356 point between now and 24 hours hence.
354 """357 """
355358
359 @operation_parameters(
360 component_group_name=TextLine(
361 title=u"The name of the remote component group", required=True))
362 @export_write_operation()
363 def addRemoteComponentGroup(component_group_name):
364 """Adds a new component group to the bug tracker"""
365
366 def getAllRemoteComponentGroups():
367 """Return collection of all component groups for this bug tracker"""
368
369 @operation_parameters(
370 component_group_name=TextLine(
371 title=u"The name of the remote component group", required=True))
372 @export_read_operation()
373 def getRemoteComponentGroup(component_group_name):
374 """Retrieve a given component group registered with the bug tracker.
375
376 :param component_group_name: Name of the component group to retrieve.
377 """
378
356379
357class IBugTrackerSet(Interface):380class IBugTrackerSet(Interface):
358 """A set of IBugTracker's.381 """A set of IBugTracker's.
@@ -465,6 +488,72 @@
465 """Query IBugTrackerAliases by BugTracker."""488 """Query IBugTrackerAliases by BugTracker."""
466489
467490
491class IBugTrackerComponent(Interface):
492 """The software component in the remote bug tracker.
493
494 Most bug trackers organize bug reports by the software 'component'
495 they affect. This class provides a mapping of this upstream component
496 to the corresponding source package in the distro.
497 """
498 export_as_webservice_entry()
499
500 id = Int(title=_('ID'), required=True, readonly=True)
501 is_visible = Bool(
502 title=_('Is Visible?'),
503 description=_("Should the component be shown in "
504 "the Launchpad web interface?"),
505 readonly=True)
506 is_custom = Bool(
507 title=_('Is Custom?'),
508 description=_("Was the component added locally in "
509 "Launchpad? If it was, we must retain "
510 "it across updates of bugtracker data."),
511 readonly=True)
512
513 name = exported(
514 Text(
515 title=_('Name'),
516 constraint=name_validator,
517 description=_('The name of a software component'
518 'in a remote bug tracker')))
519
520# XXX: Bug 644794 will implement this link
521# distro_source_package = exported(
522# Reference(
523# title=_('Distribution Source Package'),
524# schema=Interface,
525# description=_('The distribution source package for this '
526# 'component, if one has been defined.')))
527
528
529class IBugTrackerComponentGroup(Interface):
530 """A collection of components in a remote bug tracker.
531
532 Some bug trackers organize sets of components into higher level groups,
533 such as Bugzilla's 'product'.
534 """
535 export_as_webservice_entry()
536
537 id = Int(title=_('ID'))
538 name = exported(
539 Text(
540 title=_('Name'),
541 constraint=name_validator,
542 description=_('The name of the bug tracker product.')))
543 components = exported(
544 Reference(title=_('Components'), schema=IBugTrackerComponent))
545 bug_tracker = exported(
546 Reference(title=_('BugTracker'), schema=IBugTracker))
547
548 @operation_parameters(
549 component_name=TextLine(
550 title=u"The name of the remote software component to be added",
551 required=True))
552 @export_write_operation()
553 def addComponent(component_name):
554 """Adds a component to be tracked as part of this component group"""
555
556
468class IRemoteBug(Interface):557class IRemoteBug(Interface):
469 """A remote bug for a given bug tracker."""558 """A remote bug for a given bug tracker."""
470559
471560
=== modified file 'lib/lp/bugs/model/bugmessage.py'
--- lib/lp/bugs/model/bugmessage.py 2010-08-20 20:31:18 +0000
+++ lib/lp/bugs/model/bugmessage.py 2010-10-04 22:08:24 +0000
@@ -44,6 +44,8 @@
44 notNull=False, default=None)44 notNull=False, default=None)
45 remote_comment_id = StringCol(notNull=False, default=None)45 remote_comment_id = StringCol(notNull=False, default=None)
46 visible = BoolCol(notNull=True, default=True)46 visible = BoolCol(notNull=True, default=True)
47 # -- Uncomment when deployed.
48 # index = IntCol()
4749
4850
49class BugMessageSet:51class BugMessageSet:
5052
=== added file 'lib/lp/bugs/model/bugsubscriptionfilter.py'
--- lib/lp/bugs/model/bugsubscriptionfilter.py 1970-01-01 00:00:00 +0000
+++ lib/lp/bugs/model/bugsubscriptionfilter.py 2010-10-04 22:08:24 +0000
@@ -0,0 +1,36 @@
1# Copyright 2009 Canonical Ltd. This software is licensed under the
2# GNU Affero General Public License version 3 (see the file LICENSE).
3
4# pylint: disable-msg=E0611,W0212
5
6__metaclass__ = type
7__all__ = ['BugSubscriptionFilter']
8
9from storm.base import Storm
10from storm.locals import (
11 Bool,
12 Int,
13 Reference,
14 Unicode,
15 )
16
17
18class BugSubscriptionFilter(Storm):
19 """A filter to specialize a *structural* subscription."""
20
21 __storm_table__ = "BugSubscriptionFilter"
22
23 id = Int(primary=True)
24
25 structural_subscription_id = Int(
26 "structuralsubscription", allow_none=False)
27 structural_subscription = Reference(
28 structural_subscription_id, "StructuralSubscription.id")
29
30 find_all_tags = Bool(allow_none=False, default=False)
31 include_any_tags = Bool(allow_none=False, default=False)
32 exclude_any_tags = Bool(allow_none=False, default=False)
33
34 other_parameters = Unicode()
35
36 description = Unicode()
037
=== added file 'lib/lp/bugs/model/bugsubscriptionfilterimportance.py'
--- lib/lp/bugs/model/bugsubscriptionfilterimportance.py 1970-01-01 00:00:00 +0000
+++ lib/lp/bugs/model/bugsubscriptionfilterimportance.py 2010-10-04 22:08:24 +0000
@@ -0,0 +1,29 @@
1# Copyright 2009 Canonical Ltd. This software is licensed under the
2# GNU Affero General Public License version 3 (see the file LICENSE).
3
4# pylint: disable-msg=E0611,W0212
5
6__metaclass__ = type
7__all__ = ['BugSubscriptionFilterImportance']
8
9from storm.base import Storm
10from storm.locals import (
11 Int,
12 Reference,
13 )
14
15from canonical.database.enumcol import DBEnum
16from lp.bugs.interfaces.bugtask import BugTaskImportance
17
18
19class BugSubscriptionFilterImportance(Storm):
20 """Importances to filter."""
21
22 __storm_table__ = "BugSubscriptionFilterImportance"
23
24 id = Int(primary=True)
25
26 filter_id = Int("filter", allow_none=False)
27 filter = Reference(filter_id, "BugSubscriptionFilter.id")
28
29 importance = DBEnum(enum=BugTaskImportance, allow_none=False)
030
=== added file 'lib/lp/bugs/model/bugsubscriptionfilterstatus.py'
--- lib/lp/bugs/model/bugsubscriptionfilterstatus.py 1970-01-01 00:00:00 +0000
+++ lib/lp/bugs/model/bugsubscriptionfilterstatus.py 2010-10-04 22:08:24 +0000
@@ -0,0 +1,29 @@
1# Copyright 2009 Canonical Ltd. This software is licensed under the
2# GNU Affero General Public License version 3 (see the file LICENSE).
3
4# pylint: disable-msg=E0611,W0212
5
6__metaclass__ = type
7__all__ = ['BugSubscriptionFilterStatus']
8
9from storm.base import Storm
10from storm.locals import (
11 Int,
12 Reference,
13 )
14
15from canonical.database.enumcol import DBEnum
16from lp.bugs.interfaces.bugtask import BugTaskStatus
17
18
19class BugSubscriptionFilterStatus(Storm):
20 """Statuses to filter."""
21
22 __storm_table__ = "BugSubscriptionFilterStatus"
23
24 id = Int(primary=True)
25
26 filter_id = Int("filter", allow_none=False)
27 filter = Reference(filter_id, "BugSubscriptionFilter.id")
28
29 status = DBEnum(enum=BugTaskStatus, allow_none=False)
030
=== added file 'lib/lp/bugs/model/bugsubscriptionfiltertag.py'
--- lib/lp/bugs/model/bugsubscriptionfiltertag.py 1970-01-01 00:00:00 +0000
+++ lib/lp/bugs/model/bugsubscriptionfiltertag.py 2010-10-04 22:08:24 +0000
@@ -0,0 +1,29 @@
1# Copyright 2009 Canonical Ltd. This software is licensed under the
2# GNU Affero General Public License version 3 (see the file LICENSE).
3
4# pylint: disable-msg=E0611,W0212
5
6__metaclass__ = type
7__all__ = ['BugSubscriptionFilterTag']
8
9from storm.base import Storm
10from storm.locals import (
11 Bool,
12 Int,
13 Reference,
14 Unicode,
15 )
16
17
18class BugSubscriptionFilterTag(Storm):
19 """Tags to filter."""
20
21 __storm_table__ = "BugSubscriptionFilterTag"
22
23 id = Int(primary=True)
24
25 filter_id = Int("filter", allow_none=False)
26 filter = Reference(filter_id, "BugSubscriptionFilter.id")
27
28 include = Bool(allow_none=False)
29 tag = Unicode(allow_none=False)
030
=== modified file 'lib/lp/bugs/model/bugtracker.py'
--- lib/lp/bugs/model/bugtracker.py 2010-09-19 00:35:22 +0000
+++ lib/lp/bugs/model/bugtracker.py 2010-10-04 22:08:24 +0000
@@ -6,12 +6,14 @@
6__metaclass__ = type6__metaclass__ = type
7__all__ = [7__all__ = [
8 'BugTracker',8 'BugTracker',
9 'BugTrackerSet',
9 'BugTrackerAlias',10 'BugTrackerAlias',
10 'BugTrackerAliasSet',11 'BugTrackerAliasSet',
12 'BugTrackerComponent',
13 'BugTrackerComponentGroup',
11 'BugTrackerSet',14 'BugTrackerSet',
12 ]15 ]
1316
14
15from datetime import datetime17from datetime import datetime
16from itertools import chain18from itertools import chain
17# splittype is not formally documented, but is in urllib.__all__, is19# splittype is not formally documented, but is in urllib.__all__, is
@@ -22,9 +24,15 @@
22 splittype,24 splittype,
23 )25 )
2426
27from storm.base import Storm
28from storm.locals import (
29 Int,
30 Reference,
31 ReferenceSet,
32 Unicode,
33 )
25from zope.component import getUtility34from zope.component import getUtility
26from zope.interface import implements35from zope.interface import implements
27from zope.security.interfaces import Unauthorized
2836
29from lazr.uri import URI37from lazr.uri import URI
30from pytz import timezone38from pytz import timezone
@@ -45,8 +53,6 @@
45 )53 )
46from storm.locals import Bool54from storm.locals import Bool
47from storm.store import Store55from storm.store import Store
48from zope.component import getUtility
49from zope.interface import implements
5056
51from canonical.database.enumcol import EnumCol57from canonical.database.enumcol import EnumCol
52from canonical.database.sqlbase import (58from canonical.database.sqlbase import (
@@ -64,6 +70,8 @@
64 IBugTracker,70 IBugTracker,
65 IBugTrackerAlias,71 IBugTrackerAlias,
66 IBugTrackerAliasSet,72 IBugTrackerAliasSet,
73 IBugTrackerComponent,
74 IBugTrackerComponentGroup,
67 IBugTrackerSet,75 IBugTrackerSet,
68 SINGLE_PRODUCT_BUGTRACKERTYPES,76 SINGLE_PRODUCT_BUGTRACKERTYPES,
69 )77 )
@@ -518,6 +526,41 @@
518 next_check=new_next_check, lastchecked=None,526 next_check=new_next_check, lastchecked=None,
519 last_error_type=None)527 last_error_type=None)
520528
529 def addRemoteComponentGroup(self, component_group_name):
530 """See `IBugTracker`."""
531
532 if component_group_name is None:
533 component_group_name = "default"
534 component_group = BugTrackerComponentGroup()
535 component_group.name = component_group_name
536 component_group.bug_tracker = self
537
538 store = IStore(BugTrackerComponentGroup)
539 store.add(component_group)
540 store.commit()
541
542 return component_group
543
544 def getAllRemoteComponentGroups(self):
545 """See `IBugTracker`."""
546 component_groups = []
547
548 component_groups = Store.of(self).find(
549 BugTrackerComponentGroup,
550 BugTrackerComponentGroup.bug_tracker == self.id)
551 component_groups = component_groups.order_by(
552 BugTrackerComponentGroup.name)
553 return component_groups
554
555 def getRemoteComponentGroup(self, component_group_name):
556 """See `IBugTracker`."""
557 component_group = None
558 store = IStore(BugTrackerComponentGroup)
559 component_group = store.find(
560 BugTrackerComponentGroup,
561 name = component_group_name).one()
562 return component_group
563
521564
522class BugTrackerSet:565class BugTrackerSet:
523 """Implements IBugTrackerSet for a container or set of BugTrackers,566 """Implements IBugTrackerSet for a container or set of BugTrackers,
@@ -627,9 +670,11 @@
627670
628 def getMostActiveBugTrackers(self, limit=None):671 def getMostActiveBugTrackers(self, limit=None):
629 """See `IBugTrackerSet`."""672 """See `IBugTrackerSet`."""
630 store = IStore(self.table)673 store = IStore(BugTracker)
631 result = store.find(self.table, self.table.id == BugWatch.bugtrackerID)674 result = store.find(
632 result = result.group_by(self.table)675 BugTracker,
676 BugTracker.id == BugWatch.bugtrackerID)
677 result = result.group_by(BugTracker)
633 result = result.order_by(Desc(Count(BugWatch)))678 result = result.order_by(Desc(Count(BugWatch)))
634 if limit is not None:679 if limit is not None:
635 return result[:limit]680 return result[:limit]
@@ -671,3 +716,91 @@
671 def queryByBugTracker(self, bugtracker):716 def queryByBugTracker(self, bugtracker):
672 """See IBugTrackerSet."""717 """See IBugTrackerSet."""
673 return self.table.selectBy(bugtracker=bugtracker.id)718 return self.table.selectBy(bugtracker=bugtracker.id)
719
720
721class BugTrackerComponent(Storm):
722 """The software component in the remote bug tracker.
723
724 Most bug trackers organize bug reports by the software 'component'
725 they affect. This class provides a mapping of this upstream component
726 to the corresponding source package in the distro.
727 """
728 implements(IBugTrackerComponent)
729 __storm_table__ = 'BugTrackerComponent'
730
731 id = Int(primary=True)
732 name = Unicode(allow_none=False)
733
734 component_group_id = Int('component_group')
735 component_group = Reference(
736 component_group_id,
737 'BugTrackerComponentGroup.id')
738
739 is_visible = Bool(allow_none=False)
740 is_custom = Bool(allow_none=False)
741
742 distro_source_package_id = Int('distro_source_package')
743 distro_source_package = Reference(
744 distro_source_package_id,
745 'DistributionSourcePackageInDatabase.id')
746
747
748class BugTrackerComponentGroup(Storm):
749 """A collection of components in a remote bug tracker.
750
751 Some bug trackers organize sets of components into higher level groups,
752 such as Bugzilla's 'product'.
753 """
754 implements(IBugTrackerComponentGroup)
755 __storm_table__ = 'BugTrackerComponentGroup'
756
757 id = Int(primary=True)
758 name = Unicode(allow_none=False)
759 bug_tracker_id = Int('bug_tracker')
760 bug_tracker = Reference(bug_tracker_id, 'BugTracker.id')
761 components = ReferenceSet(
762 id,
763 BugTrackerComponent.component_group_id,
764 order_by=BugTrackerComponent.name)
765
766 def addComponent(self, component_name):
767 """Adds a component that is synced from a remote bug tracker"""
768
769 component = BugTrackerComponent()
770 component.name = component_name
771 component.component_group = self
772
773 store = IStore(BugTrackerComponent)
774 store.add(component)
775 store.flush()
776
777 return component
778
779 def getComponent(self, component_name):
780 """Retrieves a component by the given name.
781
782 None is returned if there is no component by that name in the
783 group.
784 """
785
786 if component_name is None:
787 return None
788 else:
789 return Store.of(self).find(
790 BugTrackerComponent,
791 (BugTrackerComponent.name == component_name)).one()
792
793 def addCustomComponent(self, component_name):
794 """Adds a component locally that isn't synced from a remote tracker
795 """
796
797 component = BugTrackerComponent()
798 component.name = component_name
799 component.component_group = self
800 component.is_custom = True
801
802 store = IStore(BugTrackerComponent)
803 store.add(component)
804 store.flush()
805
806 return component
674807
=== added directory 'lib/lp/bugs/model/tests'
=== added file 'lib/lp/bugs/model/tests/__init__.py'
=== added file 'lib/lp/bugs/model/tests/test_bugsubscriptionfilter.py'
--- lib/lp/bugs/model/tests/test_bugsubscriptionfilter.py 1970-01-01 00:00:00 +0000
+++ lib/lp/bugs/model/tests/test_bugsubscriptionfilter.py 2010-10-04 22:08:24 +0000
@@ -0,0 +1,66 @@
1# Copyright 2010 Canonical Ltd. This software is licensed under the
2# GNU Affero General Public License version 3 (see the file LICENSE).
3
4"""Tests for the bugsubscription module."""
5
6__metaclass__ = type
7
8from canonical.launchpad.interfaces.lpstorm import IStore
9from canonical.testing import DatabaseFunctionalLayer
10from lp.bugs.model.bugsubscriptionfilter import BugSubscriptionFilter
11from lp.testing import (
12 login_person,
13 TestCaseWithFactory,
14 )
15
16
17class TestBugSubscriptionFilter(TestCaseWithFactory):
18
19 layer = DatabaseFunctionalLayer
20
21 def setUp(self):
22 super(TestBugSubscriptionFilter, self).setUp()
23 self.target = self.factory.makeProduct()
24 self.subscriber = self.target.owner
25 login_person(self.subscriber)
26 self.subscription = self.target.addBugSubscription(
27 self.subscriber, self.subscriber)
28
29 def test_basics(self):
30 """Test the basic operation of `BugSubscriptionFilter` objects."""
31 # Create.
32 bug_subscription_filter = BugSubscriptionFilter()
33 bug_subscription_filter.structural_subscription = self.subscription
34 bug_subscription_filter.find_all_tags = True
35 bug_subscription_filter.include_any_tags = True
36 bug_subscription_filter.exclude_any_tags = True
37 bug_subscription_filter.other_parameters = u"foo"
38 bug_subscription_filter.description = u"bar"
39 # Flush and reload.
40 IStore(bug_subscription_filter).flush()
41 IStore(bug_subscription_filter).reload(bug_subscription_filter)
42 # Check.
43 self.assertIsNot(None, bug_subscription_filter.id)
44 self.assertEqual(
45 self.subscription.id,
46 bug_subscription_filter.structural_subscription_id)
47 self.assertEqual(
48 self.subscription,
49 bug_subscription_filter.structural_subscription)
50 self.assertIs(True, bug_subscription_filter.find_all_tags)
51 self.assertIs(True, bug_subscription_filter.include_any_tags)
52 self.assertIs(True, bug_subscription_filter.exclude_any_tags)
53 self.assertEqual(u"foo", bug_subscription_filter.other_parameters)
54 self.assertEqual(u"bar", bug_subscription_filter.description)
55
56 def test_defaults(self):
57 """Test the default values of `BugSubscriptionFilter` objects."""
58 # Create.
59 bug_subscription_filter = BugSubscriptionFilter()
60 bug_subscription_filter.structural_subscription = self.subscription
61 # Check.
62 self.assertIs(False, bug_subscription_filter.find_all_tags)
63 self.assertIs(False, bug_subscription_filter.include_any_tags)
64 self.assertIs(False, bug_subscription_filter.exclude_any_tags)
65 self.assertIs(None, bug_subscription_filter.other_parameters)
66 self.assertIs(None, bug_subscription_filter.description)
067
=== added file 'lib/lp/bugs/model/tests/test_bugsubscriptionfilterimportance.py'
--- lib/lp/bugs/model/tests/test_bugsubscriptionfilterimportance.py 1970-01-01 00:00:00 +0000
+++ lib/lp/bugs/model/tests/test_bugsubscriptionfilterimportance.py 2010-10-04 22:08:24 +0000
@@ -0,0 +1,54 @@
1# Copyright 2010 Canonical Ltd. This software is licensed under the
2# GNU Affero General Public License version 3 (see the file LICENSE).
3
4"""Tests for the bugsubscription module."""
5
6__metaclass__ = type
7
8from canonical.launchpad.interfaces.lpstorm import IStore
9from canonical.testing import DatabaseFunctionalLayer
10from lp.bugs.interfaces.bugtask import BugTaskImportance
11from lp.bugs.model.bugsubscriptionfilter import BugSubscriptionFilter
12from lp.bugs.model.bugsubscriptionfilterimportance import (
13 BugSubscriptionFilterImportance,
14 )
15from lp.testing import (
16 login_person,
17 TestCaseWithFactory,
18 )
19
20
21class TestBugSubscriptionFilterImportance(TestCaseWithFactory):
22
23 layer = DatabaseFunctionalLayer
24
25 def setUp(self):
26 super(TestBugSubscriptionFilterImportance, self).setUp()
27 self.target = self.factory.makeProduct()
28 self.subscriber = self.target.owner
29 login_person(self.subscriber)
30 self.subscription = self.target.addBugSubscription(
31 self.subscriber, self.subscriber)
32 self.subscription_filter = BugSubscriptionFilter()
33 self.subscription_filter.structural_subscription = self.subscription
34
35 def test_basics(self):
36 """Test the basics of `BugSubscriptionFilterImportance` objects."""
37 # Create.
38 bug_sub_filter_importance = BugSubscriptionFilterImportance()
39 bug_sub_filter_importance.filter = self.subscription_filter
40 bug_sub_filter_importance.importance = BugTaskImportance.HIGH
41 # Flush and reload.
42 IStore(bug_sub_filter_importance).flush()
43 IStore(bug_sub_filter_importance).reload(bug_sub_filter_importance)
44 # Check.
45 self.assertIsNot(None, bug_sub_filter_importance.id)
46 self.assertEqual(
47 self.subscription_filter.id,
48 bug_sub_filter_importance.filter_id)
49 self.assertEqual(
50 self.subscription_filter,
51 bug_sub_filter_importance.filter)
52 self.assertEqual(
53 BugTaskImportance.HIGH,
54 bug_sub_filter_importance.importance)
055
=== added file 'lib/lp/bugs/model/tests/test_bugsubscriptionfilterstatus.py'
--- lib/lp/bugs/model/tests/test_bugsubscriptionfilterstatus.py 1970-01-01 00:00:00 +0000
+++ lib/lp/bugs/model/tests/test_bugsubscriptionfilterstatus.py 2010-10-04 22:08:24 +0000
@@ -0,0 +1,52 @@
1# Copyright 2010 Canonical Ltd. This software is licensed under the
2# GNU Affero General Public License version 3 (see the file LICENSE).
3
4"""Tests for the bugsubscription module."""
5
6__metaclass__ = type
7
8from canonical.launchpad.interfaces.lpstorm import IStore
9from canonical.testing import DatabaseFunctionalLayer
10from lp.bugs.interfaces.bugtask import BugTaskStatus
11from lp.bugs.model.bugsubscriptionfilter import BugSubscriptionFilter
12from lp.bugs.model.bugsubscriptionfilterstatus import (
13 BugSubscriptionFilterStatus,
14 )
15from lp.testing import (
16 login_person,
17 TestCaseWithFactory,
18 )
19
20
21class TestBugSubscriptionFilterStatus(TestCaseWithFactory):
22
23 layer = DatabaseFunctionalLayer
24
25 def setUp(self):
26 super(TestBugSubscriptionFilterStatus, self).setUp()
27 self.target = self.factory.makeProduct()
28 self.subscriber = self.target.owner
29 login_person(self.subscriber)
30 self.subscription = self.target.addBugSubscription(
31 self.subscriber, self.subscriber)
32 self.subscription_filter = BugSubscriptionFilter()
33 self.subscription_filter.structural_subscription = self.subscription
34
35 def test_basics(self):
36 """Test the basics of `BugSubscriptionFilterStatus` objects."""
37 # Create.
38 bug_sub_filter_status = BugSubscriptionFilterStatus()
39 bug_sub_filter_status.filter = self.subscription_filter
40 bug_sub_filter_status.status = BugTaskStatus.NEW
41 # Flush and reload.
42 IStore(bug_sub_filter_status).flush()
43 IStore(bug_sub_filter_status).reload(bug_sub_filter_status)
44 # Check.
45 self.assertIsNot(None, bug_sub_filter_status.id)
46 self.assertEqual(
47 self.subscription_filter.id,
48 bug_sub_filter_status.filter_id)
49 self.assertEqual(
50 self.subscription_filter,
51 bug_sub_filter_status.filter)
52 self.assertEqual(BugTaskStatus.NEW, bug_sub_filter_status.status)
053
=== added file 'lib/lp/bugs/model/tests/test_bugsubscriptionfiltertag.py'
--- lib/lp/bugs/model/tests/test_bugsubscriptionfiltertag.py 1970-01-01 00:00:00 +0000
+++ lib/lp/bugs/model/tests/test_bugsubscriptionfiltertag.py 2010-10-04 22:08:24 +0000
@@ -0,0 +1,51 @@
1# Copyright 2010 Canonical Ltd. This software is licensed under the
2# GNU Affero General Public License version 3 (see the file LICENSE).
3
4"""Tests for the bugsubscription module."""
5
6__metaclass__ = type
7
8from canonical.launchpad.interfaces.lpstorm import IStore
9from canonical.testing import DatabaseFunctionalLayer
10from lp.bugs.model.bugsubscriptionfilter import BugSubscriptionFilter
11from lp.bugs.model.bugsubscriptionfiltertag import BugSubscriptionFilterTag
12from lp.testing import (
13 login_person,
14 TestCaseWithFactory,
15 )
16
17
18class TestBugSubscriptionFilterTag(TestCaseWithFactory):
19
20 layer = DatabaseFunctionalLayer
21
22 def setUp(self):
23 super(TestBugSubscriptionFilterTag, self).setUp()
24 self.target = self.factory.makeProduct()
25 self.subscriber = self.target.owner
26 login_person(self.subscriber)
27 self.subscription = self.target.addBugSubscription(
28 self.subscriber, self.subscriber)
29 self.subscription_filter = BugSubscriptionFilter()
30 self.subscription_filter.structural_subscription = self.subscription
31
32 def test_basics(self):
33 """Test the basics of `BugSubscriptionFilterTag` objects."""
34 # Create.
35 bug_sub_filter_tag = BugSubscriptionFilterTag()
36 bug_sub_filter_tag.filter = self.subscription_filter
37 bug_sub_filter_tag.include = True
38 bug_sub_filter_tag.tag = u"foo"
39 # Flush and reload.
40 IStore(bug_sub_filter_tag).flush()
41 IStore(bug_sub_filter_tag).reload(bug_sub_filter_tag)
42 # Check.
43 self.assertIsNot(None, bug_sub_filter_tag.id)
44 self.assertEqual(
45 self.subscription_filter.id,
46 bug_sub_filter_tag.filter_id)
47 self.assertEqual(
48 self.subscription_filter,
49 bug_sub_filter_tag.filter)
50 self.assertIs(True, bug_sub_filter_tag.include)
51 self.assertEqual(u"foo", bug_sub_filter_tag.tag)
052
=== modified file 'lib/lp/bugs/tests/has-bug-supervisor.txt'
--- lib/lp/bugs/tests/has-bug-supervisor.txt 2009-08-25 11:21:05 +0000
+++ lib/lp/bugs/tests/has-bug-supervisor.txt 2010-10-04 22:08:24 +0000
@@ -5,7 +5,7 @@
5structural subscription targets. When the bug supervisor for such an object5structural subscription targets. When the bug supervisor for such an object
6is set, a new bug subscription is created as well.6is set, a new bug subscription is created as well.
77
8 >>> target.bug_subscriptions8 >>> list(target.bug_subscriptions)
9 []9 []
1010
11 >>> print target.bug_supervisor11 >>> print target.bug_supervisor
1212
=== added file 'lib/lp/bugs/tests/test_bugtracker_components.py'
--- lib/lp/bugs/tests/test_bugtracker_components.py 1970-01-01 00:00:00 +0000
+++ lib/lp/bugs/tests/test_bugtracker_components.py 2010-10-04 22:08:24 +0000
@@ -0,0 +1,176 @@
1# Copyright 2010 Canonical Ltd. This software is licensed under the
2# GNU Affero General Public License version 3 (see the file LICENSE).
3
4"""Test for components and component groups (products) in bug trackers."""
5
6__metaclass__ = type
7
8__all__ = []
9
10import unittest
11
12from canonical.launchpad.ftests import login_person
13from canonical.testing import DatabaseFunctionalLayer
14from lp.testing import TestCaseWithFactory
15
16class TestBugTrackerComponent(TestCaseWithFactory):
17
18 layer = DatabaseFunctionalLayer
19
20 def setUp(self):
21 super(TestBugTrackerComponent, self).setUp()
22
23 regular_user = self.factory.makePerson()
24 login_person(regular_user)
25
26 self.bug_tracker = self.factory.makeBugTracker()
27
28 self.comp_group = self.factory.makeBugTrackerComponentGroup(
29 u'alpha',
30 self.bug_tracker)
31
32 def test_component_creation(self):
33 """Verify a component can be created"""
34 component = self.factory.makeBugTrackerComponent(
35 u'example', self.comp_group)
36 self.assertTrue(component is not None)
37 self.assertEqual(component.name, u'example')
38
39 def test_set_visibility(self):
40 """Users can delete components
41
42 In case invalid components get imported from a remote bug
43 tracker, users can hide them so they don't show up in the UI.
44 We do this rather than delete them outright so that they won't
45 show up again when we re-sync from the remote bug tracker.
46 """
47 component = self.factory.makeBugTrackerComponent(
48 u'example', self.comp_group)
49 self.assertEqual(component.is_visible, True)
50
51 component.is_visible = False
52 self.assertEqual(component.is_visible, False)
53
54 component.is_visible = True
55 self.assertEqual(component.is_visible, True)
56
57 def test_custom_component(self):
58 """Users can also add components
59
60 For whatever reason, it may be that we can't import a component
61 from the remote bug tracker. This gives users a way to correct
62 the omissions."""
63 custom_component = self.factory.makeBugTrackerComponent(
64 u'example', self.comp_group, custom=True)
65 self.assertTrue(custom_component != None)
66 self.assertEqual(custom_component.is_custom, True)
67
68 def test_multiple_component_creation(self):
69 """Verify several components can be created at once"""
70 comp_a = self.factory.makeBugTrackerComponent(
71 u'example-a', self.comp_group)
72 comp_b = self.factory.makeBugTrackerComponent(
73 u'example-b', self.comp_group)
74 comp_c = self.factory.makeBugTrackerComponent(
75 u'example-c', self.comp_group, True)
76
77 self.assertTrue(comp_a is not None)
78 self.assertTrue(comp_b is not None)
79 self.assertTrue(comp_c is not None)
80
81
82class TestBugTrackerWithComponents(TestCaseWithFactory):
83
84 layer = DatabaseFunctionalLayer
85
86 def setUp(self):
87 super(TestBugTrackerWithComponents, self).setUp()
88
89 regular_user = self.factory.makePerson()
90 login_person(regular_user)
91
92 self.bug_tracker = self.factory.makeBugTracker()
93
94 def test_empty_bugtracker(self):
95 """Trivial case of bugtracker with no products or components"""
96 self.assertTrue(self.bug_tracker is not None)
97
98 # Empty bugtrackers shouldn't return component groups
99 comp_group = self.bug_tracker.getRemoteComponentGroup(u'non-existant')
100 self.assertEqual(comp_group, None)
101
102 # Verify it contains no component groups
103 comp_groups = self.bug_tracker.getAllRemoteComponentGroups()
104 self.assertEqual(len(list(comp_groups)), 0)
105
106 def test_single_product_bugtracker(self):
107 """Bug tracker with a single (default) product and several components
108 """
109 # Add a component group and fill it with some components
110 default_comp_group = self.bug_tracker.addRemoteComponentGroup(
111 u'alpha')
112 default_comp_group.addComponent(u'example-a')
113 default_comp_group.addComponent(u'example-b')
114 default_comp_group.addComponent(u'example-c')
115
116 # Verify that retrieving an invalid component group returns nothing
117 comp_group = self.bug_tracker.getRemoteComponentGroup(u'non-existant')
118 self.assertEqual(comp_group, None)
119
120 # Now retrieve the component group we added
121 comp_group = self.bug_tracker.getRemoteComponentGroup(u'alpha')
122 self.assertEqual(comp_group, default_comp_group)
123 self.assertEqual(comp_group.name, u'alpha')
124
125 # Verify there is only the one component group in the tracker
126 comp_groups = self.bug_tracker.getAllRemoteComponentGroups()
127 self.assertEqual(len(list(comp_groups)), 1)
128
129 def test_multiple_product_bugtracker(self):
130 """Bug tracker with multiple products and components"""
131 # Create several component groups with varying numbers of components
132 comp_group_i = self.bug_tracker.addRemoteComponentGroup(u'alpha')
133
134 comp_group_ii = self.bug_tracker.addRemoteComponentGroup(u'beta')
135 comp_group_ii.addComponent(u'example-beta-1')
136
137 comp_group_iii = self.bug_tracker.addRemoteComponentGroup(u'gamma')
138 comp_group_iii.addComponent(u'example-gamma-1')
139 comp_group_iii.addComponent(u'example-gamma-2')
140 comp_group_iii.addComponent(u'example-gamma-3')
141
142 # Retrieving a non-existant component group returns nothing
143 comp_group = self.bug_tracker.getRemoteComponentGroup(u'non-existant')
144 self.assertEqual(comp_group, None)
145
146 # Now retrieve one of the real component groups
147 comp_group = self.bug_tracker.getRemoteComponentGroup(u'beta')
148 self.assertEqual(comp_group, comp_group_ii)
149
150 # Check the correct number of component groups are in the bug tracker
151 comp_groups = self.bug_tracker.getAllRemoteComponentGroups()
152 self.assertEqual(len(list(comp_groups)), 3)
153
154 def test_get_components_for_component_group(self):
155 """Retrieve a set of components from a given product"""
156 # Create a component group with some components
157 default_comp_group = self.bug_tracker.addRemoteComponentGroup(
158 u'alpha')
159 default_comp_group.addComponent(u'example-a')
160 default_comp_group.addComponent(u'example-b')
161 default_comp_group.addComponent(u'example-c')
162
163 # Verify group has the correct number of components
164 comp_group = self.bug_tracker.getRemoteComponentGroup(u'alpha')
165 self.assertEqual(len(list(comp_group.components)), 3)
166
167 # Check one of the components, that it is what we expect
168 comp = comp_group.getComponent(u'example-b')
169 self.assertEqual(comp.name, u'example-b')
170
171
172def test_suite():
173 suite = unittest.TestSuite()
174 suite.addTest(unittest.TestLoader().loadTestsFromName(__name__))
175
176 return suite
0177
=== modified file 'lib/lp/buildmaster/interfaces/buildfarmjob.py'
--- lib/lp/buildmaster/interfaces/buildfarmjob.py 2010-09-16 12:27:46 +0000
+++ lib/lp/buildmaster/interfaces/buildfarmjob.py 2010-10-04 22:08:24 +0000
@@ -1,4 +1,4 @@
1# Copyright 2009 Canonical Ltd. This software is licensed under the1# Copyright 2009-2010 Canonical Ltd. This software is licensed under the
2# GNU Affero General Public License version 3 (see the file LICENSE).2# GNU Affero General Public License version 3 (see the file LICENSE).
33
4# pylint: disable-msg=E0211,E02134# pylint: disable-msg=E0211,E0213
@@ -256,6 +256,15 @@
256256
257 was_built = Attribute("Whether or not modified by the builddfarm.")257 was_built = Attribute("Whether or not modified by the builddfarm.")
258258
259 # This doesn't belong here. It really belongs in IPackageBuild, but
260 # the TAL assumes it can read this directly.
261 dependencies = exported(
262 TextLine(
263 title=_('Dependencies'), required=False,
264 description=_(
265 'Debian-like dependency line that must be satisfied before '
266 'attempting to build this request.')))
267
259268
260class ISpecificBuildFarmJob(IBuildFarmJob):269class ISpecificBuildFarmJob(IBuildFarmJob):
261 """A marker interface with which to define adapters for IBuildFarmJob.270 """A marker interface with which to define adapters for IBuildFarmJob.
262271
=== modified file 'lib/lp/buildmaster/interfaces/packagebuild.py'
--- lib/lp/buildmaster/interfaces/packagebuild.py 2010-09-10 12:29:36 +0000
+++ lib/lp/buildmaster/interfaces/packagebuild.py 2010-10-04 22:08:24 +0000
@@ -61,12 +61,6 @@
61 description=_("A URL for failed upload logs."61 description=_("A URL for failed upload logs."
62 "Will be None if there was no failure.")))62 "Will be None if there was no failure.")))
6363
64 dependencies = exported(
65 TextLine(
66 title=_('Dependencies'), required=False,
67 description=_('Debian-like dependency line that must be satisfied'
68 ' before attempting to build this request.')))
69
70 build_farm_job = Reference(64 build_farm_job = Reference(
71 title=_('Build farm job'), schema=IBuildFarmJob, required=True,65 title=_('Build farm job'), schema=IBuildFarmJob, required=True,
72 readonly=True, description=_('The base build farm job.'))66 readonly=True, description=_('The base build farm job.'))
7367
=== modified file 'lib/lp/buildmaster/model/buildfarmjob.py'
--- lib/lp/buildmaster/model/buildfarmjob.py 2010-09-16 12:27:46 +0000
+++ lib/lp/buildmaster/model/buildfarmjob.py 2010-10-04 22:08:24 +0000
@@ -237,6 +237,8 @@
237237
238 failure_count = Int(name='failure_count', allow_none=False)238 failure_count = Int(name='failure_count', allow_none=False)
239239
240 dependencies = None
241
240 def __init__(self, job_type, status=BuildStatus.NEEDSBUILD,242 def __init__(self, job_type, status=BuildStatus.NEEDSBUILD,
241 processor=None, virtualized=None, date_created=None):243 processor=None, virtualized=None, date_created=None):
242 super(BuildFarmJob, self).__init__()244 super(BuildFarmJob, self).__init__()
@@ -273,7 +275,7 @@
273 return self.date_finished - self.date_started275 return self.date_finished - self.date_started
274276
275 def makeJob(self):277 def makeJob(self):
276 """See `IBuildFarmJob`."""278 """See `IBuildFarmJobOld`."""
277 raise NotImplementedError279 raise NotImplementedError
278280
279 def jobStarted(self):281 def jobStarted(self):
@@ -420,7 +422,8 @@
420 # specific private builds to which they have access.422 # specific private builds to which they have access.
421 origin.extend(left_join_archive)423 origin.extend(left_join_archive)
422 origin.append(LeftJoin(424 origin.append(LeftJoin(
423 TeamParticipation, TeamParticipation.teamID == Archive.ownerID))425 TeamParticipation,
426 TeamParticipation.teamID == Archive.ownerID))
424 extra_clauses.append(427 extra_clauses.append(
425 Or(Coalesce(Archive.private, False) == False,428 Or(Coalesce(Archive.private, False) == False,
426 TeamParticipation.person == user))429 TeamParticipation.person == user))
427430
=== modified file 'lib/lp/code/browser/branch.py'
--- lib/lp/code/browser/branch.py 2010-09-22 18:54:36 +0000
+++ lib/lp/code/browser/branch.py 2010-10-04 22:08:24 +0000
@@ -105,6 +105,7 @@
105from canonical.widgets.branch import TargetBranchWidget105from canonical.widgets.branch import TargetBranchWidget
106from canonical.widgets.itemswidgets import LaunchpadRadioWidgetWithDescription106from canonical.widgets.itemswidgets import LaunchpadRadioWidgetWithDescription
107from canonical.widgets.lazrjs import vocabulary_to_choice_edit_items107from canonical.widgets.lazrjs import vocabulary_to_choice_edit_items
108from lp.app.errors import NotFoundError
108from lp.blueprints.interfaces.specificationbranch import ISpecificationBranch109from lp.blueprints.interfaces.specificationbranch import ISpecificationBranch
109from lp.bugs.interfaces.bug import IBugSet110from lp.bugs.interfaces.bug import IBugSet
110from lp.bugs.interfaces.bugbranch import IBugBranch111from lp.bugs.interfaces.bugbranch import IBugBranch
@@ -146,6 +147,9 @@
146from lp.registry.interfaces.productseries import IProductSeries147from lp.registry.interfaces.productseries import IProductSeries
147from lp.registry.vocabularies import UserTeamsParticipationPlusSelfVocabulary148from lp.registry.vocabularies import UserTeamsParticipationPlusSelfVocabulary
148from lp.services.propertycache import cachedproperty149from lp.services.propertycache import cachedproperty
150from lp.translations.interfaces.translationtemplatesbuild import (
151 ITranslationTemplatesBuildSource,
152 )
149153
150154
151def quote(text):155def quote(text):
@@ -238,6 +242,16 @@
238 """Traverses to the `ICodeImport` for the branch."""242 """Traverses to the `ICodeImport` for the branch."""
239 return self.context.code_import243 return self.context.code_import
240244
245 @stepthrough("+translation-templates-build")
246 def traverse_translation_templates_build(self, id_string):
247 """Traverses to a `TranslationTemplatesBuild`."""
248 try:
249 buildfarmjob_id = int(id_string)
250 except ValueError:
251 raise NotFoundError(id_string)
252 source = getUtility(ITranslationTemplatesBuildSource)
253 return source.getByBuildFarmJob(buildfarmjob_id)
254
241255
242class BranchEditMenu(NavigationMenu):256class BranchEditMenu(NavigationMenu):
243 """Edit menu for IBranch."""257 """Edit menu for IBranch."""
244258
=== modified file 'lib/lp/code/browser/branchmergeproposal.py'
--- lib/lp/code/browser/branchmergeproposal.py 2010-09-27 20:47:58 +0000
+++ lib/lp/code/browser/branchmergeproposal.py 2010-10-04 22:08:24 +0000
@@ -547,7 +547,7 @@
547 return diff_text.count('\n') >= config.diff.max_format_lines547 return diff_text.count('\n') >= config.diff.max_format_lines
548548
549549
550class ICodeReviewNewRevisions(Interface):550class ICodeReviewNewRevisions(IComment):
551 """Marker interface used to register views for CodeReviewNewRevisions."""551 """Marker interface used to register views for CodeReviewNewRevisions."""
552552
553553
@@ -557,7 +557,7 @@
557 Each object instance represents a number of revisions scanned at a557 Each object instance represents a number of revisions scanned at a
558 particular time.558 particular time.
559 """559 """
560 implements(IComment, ICodeReviewNewRevisions)560 implements(ICodeReviewNewRevisions)
561561
562 def __init__(self, revisions, date, branch):562 def __init__(self, revisions, date, branch):
563 self.revisions = revisions563 self.revisions = revisions
@@ -567,6 +567,13 @@
567 # The date attribute is used to sort the comments in the conversation.567 # The date attribute is used to sort the comments in the conversation.
568 self.date = date568 self.date = date
569569
570 # Other standard IComment attributes are not used.
571 self.extra_css_class = None
572 self.comment_author = None
573 self.body_text = None
574 self.comment_date = None
575 self.display_attachments = False
576
570577
571class CodeReviewNewRevisionsView(LaunchpadView):578class CodeReviewNewRevisionsView(LaunchpadView):
572 """The view for rendering the new revisions."""579 """The view for rendering the new revisions."""
573580
=== modified file 'lib/lp/code/browser/codereviewcomment.py'
--- lib/lp/code/browser/codereviewcomment.py 2010-10-01 14:14:04 +0000
+++ lib/lp/code/browser/codereviewcomment.py 2010-10-04 22:08:24 +0000
@@ -43,6 +43,10 @@
43from lp.services.propertycache import cachedproperty43from lp.services.propertycache import cachedproperty
4444
4545
46class ICodeReviewDisplayComment(IComment, ICodeReviewComment):
47 """Marker interface for displaying code review comments."""
48
49
46class CodeReviewDisplayComment:50class CodeReviewDisplayComment:
47 """A code review comment or activity or both.51 """A code review comment or activity or both.
4852
@@ -51,7 +55,7 @@
51 only code in the model itself.55 only code in the model itself.
52 """56 """
5357
54 implements(IComment)58 implements(ICodeReviewDisplayComment)
5559
56 delegates(ICodeReviewComment, 'comment')60 delegates(ICodeReviewComment, 'comment')
5761
@@ -70,6 +74,40 @@
70 else:74 else:
71 return ''75 return ''
7276
77 @cachedproperty
78 def comment_author(self):
79 """The author of the comment."""
80 return self.comment.message.owner
81
82 @cachedproperty
83 def has_body(self):
84 """Is there body text?"""
85 return bool(self.body_text)
86
87 @cachedproperty
88 def body_text(self):
89 """Get the body text for the message."""
90 return self.comment.message_body
91
92 @cachedproperty
93 def comment_date(self):
94 """The date of the comment."""
95 return self.comment.message.datecreated
96
97 @cachedproperty
98 def all_attachments(self):
99 return self.comment.getAttachments()
100
101 @cachedproperty
102 def display_attachments(self):
103 # Attachments to show.
104 return [DiffAttachment(alias) for alias in self.all_attachments[0]]
105
106 @cachedproperty
107 def other_attachments(self):
108 # Attachments to not show.
109 return self.all_attachments[1]
110
73111
74class CodeReviewCommentPrimaryContext:112class CodeReviewCommentPrimaryContext:
75 """The primary context is the comment is that of the source branch."""113 """The primary context is the comment is that of the source branch."""
@@ -132,45 +170,11 @@
132 """The decorated code review comment."""170 """The decorated code review comment."""
133 return CodeReviewDisplayComment(self.context)171 return CodeReviewDisplayComment(self.context)
134172
135 @cachedproperty
136 def comment_author(self):
137 """The author of the comment."""
138 return self.context.message.owner
139
140 @cachedproperty
141 def has_body(self):
142 """Is there body text?"""
143 return bool(self.body_text)
144
145 @cachedproperty
146 def body_text(self):
147 """Get the body text for the message."""
148 return self.context.message_body
149
150 @cachedproperty
151 def comment_date(self):
152 """The date of the comment."""
153 return self.context.message.datecreated
154
155 # Should the comment be shown in full?173 # Should the comment be shown in full?
156 full_comment = True174 full_comment = True
157 # Show comment expanders?175 # Show comment expanders?
158 show_expanders = False176 show_expanders = False
159177
160 @cachedproperty
161 def all_attachments(self):
162 return self.context.getAttachments()
163
164 @cachedproperty
165 def display_attachments(self):
166 # Attachments to show.
167 return [DiffAttachment(alias) for alias in self.all_attachments[0]]
168
169 @cachedproperty
170 def other_attachments(self):
171 # Attachments to not show.
172 return self.all_attachments[1]
173
174178
175class CodeReviewCommentSummary(CodeReviewCommentView):179class CodeReviewCommentSummary(CodeReviewCommentView):
176 """Summary view of a CodeReviewComment"""180 """Summary view of a CodeReviewComment"""
177181
=== modified file 'lib/lp/code/browser/configure.zcml'
--- lib/lp/code/browser/configure.zcml 2010-09-30 22:26:08 +0000
+++ lib/lp/code/browser/configure.zcml 2010-10-04 22:08:24 +0000
@@ -691,6 +691,16 @@
691 name="+index"691 name="+index"
692 template="../templates/codereviewcomment-index.pt"/>692 template="../templates/codereviewcomment-index.pt"/>
693 <browser:page693 <browser:page
694 name="+fragment"
695 template="../templates/codereviewcomment-fragment.pt"/>
696 </browser:pages>
697 <browser:pages
698 facet="branches"
699 for="lp.code.browser.codereviewcomment.ICodeReviewDisplayComment"
700 layer="lp.code.publisher.CodeLayer"
701 class="lp.code.browser.codereviewcomment.CodeReviewCommentView"
702 permission="zope.Public">
703 <browser:page
694 name="+comment-header"704 name="+comment-header"
695 template="../templates/codereviewcomment-header.pt"/>705 template="../templates/codereviewcomment-header.pt"/>
696 <browser:page706 <browser:page
@@ -699,9 +709,6 @@
699 <browser:page709 <browser:page
700 name="+comment-footer"710 name="+comment-footer"
701 template="../templates/codereviewcomment-footer.pt"/>711 template="../templates/codereviewcomment-footer.pt"/>
702 <browser:page
703 name="+fragment"
704 template="../templates/codereviewcomment-fragment.pt"/>
705 </browser:pages>712 </browser:pages>
706 <browser:pages713 <browser:pages
707 facet="branches"714 facet="branches"
708715
=== modified file 'lib/lp/code/browser/tests/test_branchmergeproposal.py'
--- lib/lp/code/browser/tests/test_branchmergeproposal.py 2010-09-15 20:41:46 +0000
+++ lib/lp/code/browser/tests/test_branchmergeproposal.py 2010-10-04 22:08:24 +0000
@@ -23,6 +23,7 @@
23from canonical.launchpad.database.message import MessageSet23from canonical.launchpad.database.message import MessageSet
24from canonical.launchpad.webapp.interfaces import IPrimaryContext24from canonical.launchpad.webapp.interfaces import IPrimaryContext
25from canonical.launchpad.webapp.servers import LaunchpadTestRequest25from canonical.launchpad.webapp.servers import LaunchpadTestRequest
26from canonical.launchpad.webapp.testing import verifyObject
26from canonical.testing import (27from canonical.testing import (
27 DatabaseFunctionalLayer,28 DatabaseFunctionalLayer,
28 LaunchpadFunctionalLayer,29 LaunchpadFunctionalLayer,
@@ -35,8 +36,10 @@
35 BranchMergeProposalMergedView,36 BranchMergeProposalMergedView,
36 BranchMergeProposalVoteView,37 BranchMergeProposalVoteView,
37 DecoratedCodeReviewVoteReference,38 DecoratedCodeReviewVoteReference,
39 ICodeReviewNewRevisions,
38 latest_proposals_for_each_branch,40 latest_proposals_for_each_branch,
39 )41 )
42from lp.code.browser.codereviewcomment import CodeReviewDisplayComment
40from lp.code.enums import (43from lp.code.enums import (
41 BranchMergeProposalStatus,44 BranchMergeProposalStatus,
42 CodeReviewVote,45 CodeReviewVote,
@@ -45,6 +48,7 @@
45 PreviewDiff,48 PreviewDiff,
46 StaticDiff,49 StaticDiff,
47 )50 )
51from lp.code.tests.helpers import add_revision_to_branch
48from lp.testing import (52from lp.testing import (
49 login_person,53 login_person,
50 TestCaseWithFactory,54 TestCaseWithFactory,
@@ -575,6 +579,20 @@
575 view = create_initialized_view(self.bmp, '+index')579 view = create_initialized_view(self.bmp, '+index')
576 self.assertEqual([], view.linked_bugs)580 self.assertEqual([], view.linked_bugs)
577581
582 def test_CodeReviewNewRevisions_implements_ICodeReviewNewRevisions(self):
583 # The browser helper class implements its interface.
584 review_date = datetime(2009, 9, 10, tzinfo=pytz.UTC)
585 revision_date = review_date + timedelta(days=1)
586 bmp = self.factory.makeBranchMergeProposal(
587 date_created=review_date)
588 revision = add_revision_to_branch(
589 self.factory, bmp.source_branch, revision_date)
590
591 view = create_initialized_view(bmp, '+index')
592 new_revisions = view.conversation.comments[0]
593
594 self.assertTrue(verifyObject(ICodeReviewNewRevisions, new_revisions))
595
578 def test_include_superseded_comments(self):596 def test_include_superseded_comments(self):
579 for x, time in zip(range(3), time_counter()):597 for x, time in zip(range(3), time_counter()):
580 if x != 0:598 if x != 0:
@@ -707,7 +725,8 @@
707 body='testing',725 body='testing',
708 attachments=[('test.diff', 'text/plain', attachment_body)])726 attachments=[('test.diff', 'text/plain', attachment_body)])
709 message = MessageSet().fromEmail(msg.as_string())727 message = MessageSet().fromEmail(msg.as_string())
710 return bmp.createCommentFromMessage(message, None, None, msg)728 return CodeReviewDisplayComment(
729 bmp.createCommentFromMessage(message, None, None, msg))
711730
712 def test_nonascii_in_attachment_renders(self):731 def test_nonascii_in_attachment_renders(self):
713 # The view should render without errors.732 # The view should render without errors.
@@ -723,7 +742,7 @@
723 # Need to commit in order to read the diff out of the librarian.742 # Need to commit in order to read the diff out of the librarian.
724 transaction.commit()743 transaction.commit()
725 view = create_initialized_view(comment, '+comment-body')744 view = create_initialized_view(comment, '+comment-body')
726 [diff_attachment] = view.display_attachments745 [diff_attachment] = view.comment.display_attachments
727 self.assertEqual(u'\u2615', diff_attachment.diff_text)746 self.assertEqual(u'\u2615', diff_attachment.diff_text)
728747
729748
730749
=== modified file 'lib/lp/code/browser/tests/test_codereviewcomment.py'
--- lib/lp/code/browser/tests/test_codereviewcomment.py 2010-08-20 20:31:18 +0000
+++ lib/lp/code/browser/tests/test_codereviewcomment.py 2010-10-04 22:08:24 +0000
@@ -3,35 +3,52 @@
33
4"""Unit tests for CodeReviewComments."""4"""Unit tests for CodeReviewComments."""
55
6from __future__ import with_statement
7
6__metaclass__ = type8__metaclass__ = type
79
8import unittest10import unittest
911
10from canonical.launchpad.webapp.interfaces import IPrimaryContext12from canonical.launchpad.webapp.interfaces import IPrimaryContext
13from canonical.launchpad.webapp.testing import verifyObject
11from canonical.testing import DatabaseFunctionalLayer14from canonical.testing import DatabaseFunctionalLayer
15from lp.code.browser.codereviewcomment import (
16 CodeReviewDisplayComment,
17 ICodeReviewDisplayComment,
18 )
12from lp.testing import (19from lp.testing import (
13 login_person,20 person_logged_in,
14 TestCaseWithFactory,21 TestCaseWithFactory,
15 )22 )
1623
1724
18class TestCodeReviewCommentPrimaryContext(TestCaseWithFactory):25class TestCodeReviewComments(TestCaseWithFactory):
19 # Tests the adaptation of a code review comment into a primary context.
2026
21 layer = DatabaseFunctionalLayer27 layer = DatabaseFunctionalLayer
2228
23 def testPrimaryContext(self):29 def testPrimaryContext(self):
30 # Tests the adaptation of a code review comment into a primary
31 # context.
24 # We need a person to make a comment.32 # We need a person to make a comment.
25 commenter = self.factory.makePerson()33 with person_logged_in(self.factory.makePerson()):
26 login_person(commenter)34 # The primary context of a code review comment is the same
27 # The primary context of a code review comment is the same as the35 # as the primary context for the branch merge proposal that
28 # primary context for the branch merge proposal that the comment is36 # the comment is for.
29 # for.37 comment = self.factory.makeCodeReviewComment()
30 comment = self.factory.makeCodeReviewComment()38
31 self.assertEqual(39 self.assertEqual(
32 IPrimaryContext(comment).context,40 IPrimaryContext(comment).context,
33 IPrimaryContext(comment.branch_merge_proposal).context)41 IPrimaryContext(comment.branch_merge_proposal).context)
3442
43 def test_display_comment_provides_icodereviewdisplaycomment(self):
44 # The CodeReviewDisplayComment class provides IComment.
45 with person_logged_in(self.factory.makePerson()):
46 comment = self.factory.makeCodeReviewComment()
47
48 display_comment = CodeReviewDisplayComment(comment)
49
50 verifyObject(ICodeReviewDisplayComment, display_comment)
51
3552
36def test_suite():53def test_suite():
37 return unittest.TestLoader().loadTestsFromName(__name__)54 return unittest.TestLoader().loadTestsFromName(__name__)
3855
=== modified file 'lib/lp/code/doc/branch.txt'
--- lib/lp/code/doc/branch.txt 2010-10-01 14:14:04 +0000
+++ lib/lp/code/doc/branch.txt 2010-10-04 22:08:24 +0000
@@ -405,6 +405,7 @@
405 sourcepackagerecipedata.base_branch405 sourcepackagerecipedata.base_branch
406 sourcepackagerecipedatainstruction.branch406 sourcepackagerecipedatainstruction.branch
407 specificationbranch.branch407 specificationbranch.branch
408 translationtemplatesbuild.branch
408409
409(Unfortunately, references can form a cycle-- note that410(Unfortunately, references can form a cycle-- note that
410codereviewcomments411codereviewcomments
411412
=== modified file 'lib/lp/code/interfaces/branchrevision.py'
--- lib/lp/code/interfaces/branchrevision.py 2010-09-09 01:04:26 +0000
+++ lib/lp/code/interfaces/branchrevision.py 2010-10-04 22:08:24 +0000
@@ -26,8 +26,6 @@
26 ancestry of a branch. History revisions have an integer sequence, merged26 ancestry of a branch. History revisions have an integer sequence, merged
27 revisions have sequence set to None.27 revisions have sequence set to None.
28 """28 """
29 id = Int(title=_('The database revision ID'))
30
31 sequence = Int(29 sequence = Int(
32 title=_("Revision number"), required=True,30 title=_("Revision number"), required=True,
33 description=_("The index of the revision within the branch's history."31 description=_("The index of the revision within the branch's history."
3432
=== modified file 'lib/lp/code/model/branch.py'
--- lib/lp/code/model/branch.py 2010-09-21 02:46:02 +0000
+++ lib/lp/code/model/branch.py 2010-10-04 22:08:24 +0000
@@ -919,7 +919,7 @@
919 def getScannerData(self):919 def getScannerData(self):
920 """See `IBranch`."""920 """See `IBranch`."""
921 columns = (921 columns = (
922 BranchRevision.id, BranchRevision.sequence, Revision.revision_id)922 BranchRevision.sequence, Revision.revision_id)
923 rows = Store.of(self).using(Revision, BranchRevision).find(923 rows = Store.of(self).using(Revision, BranchRevision).find(
924 columns,924 columns,
925 Revision.id == BranchRevision.revision_id,925 Revision.id == BranchRevision.revision_id,
@@ -927,7 +927,7 @@
927 rows = rows.order_by(BranchRevision.sequence)927 rows = rows.order_by(BranchRevision.sequence)
928 ancestry = set()928 ancestry = set()
929 history = []929 history = []
930 for branch_revision_id, sequence, revision_id in rows:930 for sequence, revision_id in rows:
931 ancestry.add(revision_id)931 ancestry.add(revision_id)
932 if sequence is not None:932 if sequence is not None:
933 history.append(revision_id)933 history.append(revision_id)
@@ -1027,10 +1027,14 @@
1027 """Delete jobs for this branch prior to deleting branch.1027 """Delete jobs for this branch prior to deleting branch.
10281028
1029 This deletion includes `BranchJob`s associated with the branch,1029 This deletion includes `BranchJob`s associated with the branch,
1030 as well as `BuildQueue` entries for `TranslationTemplateBuildJob`s.1030 as well as `BuildQueue` entries for `TranslationTemplateBuildJob`s
1031 and `TranslationTemplateBuild`s.
1031 """1032 """
1032 # Avoid circular imports.1033 # Avoid circular imports.
1033 from lp.code.model.branchjob import BranchJob1034 from lp.code.model.branchjob import BranchJob
1035 from lp.translations.model.translationtemplatesbuild import (
1036 TranslationTemplatesBuild,
1037 )
10341038
1035 store = Store.of(self)1039 store = Store.of(self)
1036 affected_jobs = Select(1040 affected_jobs = Select(
@@ -1044,6 +1048,10 @@
1044 # Delete Jobs. Their BranchJobs cascade along in the database.1048 # Delete Jobs. Their BranchJobs cascade along in the database.
1045 store.find(Job, Job.id.is_in(affected_jobs)).remove()1049 store.find(Job, Job.id.is_in(affected_jobs)).remove()
10461050
1051 store.find(
1052 TranslationTemplatesBuild,
1053 TranslationTemplatesBuild.branch == self).remove()
1054
1047 def destroySelf(self, break_references=False):1055 def destroySelf(self, break_references=False):
1048 """See `IBranch`."""1056 """See `IBranch`."""
1049 from lp.code.interfaces.branchjob import IReclaimBranchSpaceJobSource1057 from lp.code.interfaces.branchjob import IReclaimBranchSpaceJobSource
10501058
=== modified file 'lib/lp/code/model/branchmergeproposal.py'
--- lib/lp/code/model/branchmergeproposal.py 2010-09-22 18:55:25 +0000
+++ lib/lp/code/model/branchmergeproposal.py 2010-10-04 22:08:24 +0000
@@ -633,7 +633,7 @@
633 SourceRevision,633 SourceRevision,
634 SourceRevision.branch_id == self.source_branch.id,634 SourceRevision.branch_id == self.source_branch.id,
635 SourceRevision.sequence != None,635 SourceRevision.sequence != None,
636 TargetRevision.id == None)636 TargetRevision.branch_id == None)
637 return result.order_by(Desc(SourceRevision.sequence)).config(limit=10)637 return result.order_by(Desc(SourceRevision.sequence)).config(limit=10)
638638
639 def createComment(self, owner, subject, content=None, vote=None,639 def createComment(self, owner, subject, content=None, vote=None,
640640
=== modified file 'lib/lp/code/model/branchrevision.py'
--- lib/lp/code/model/branchrevision.py 2010-09-09 01:04:26 +0000
+++ lib/lp/code/model/branchrevision.py 2010-10-04 22:08:24 +0000
@@ -21,8 +21,7 @@
21class BranchRevision(Storm):21class BranchRevision(Storm):
22 """See `IBranchRevision`."""22 """See `IBranchRevision`."""
23 __storm_table__ = 'BranchRevision'23 __storm_table__ = 'BranchRevision'
2424 __storm_primary__ = "branch_id", "revision_id"
25 id = Int(primary=True)
2625
27 implements(IBranchRevision)26 implements(IBranchRevision)
2827
2928
=== modified file 'lib/lp/code/model/tests/test_branchjob.py'
--- lib/lp/code/model/tests/test_branchjob.py 2010-08-20 20:31:18 +0000
+++ lib/lp/code/model/tests/test_branchjob.py 2010-10-04 22:08:24 +0000
@@ -518,9 +518,7 @@
518 except bzr_errors.NoSuchRevision:518 except bzr_errors.NoSuchRevision:
519 revno = None519 revno = None
520 if existing is not None:520 if existing is not None:
521 branchrevision = IMasterStore(branch).find(521 branch.removeBranchRevisions([existing.revision.revision_id])
522 BranchRevision, BranchRevision.id == existing.id)
523 branchrevision.remove()
524 branch.createBranchRevision(revno, revision)522 branch.createBranchRevision(revno, revision)
525523
526 def create3CommitsBranch(self):524 def create3CommitsBranch(self):
527525
=== modified file 'lib/lp/code/templates/codereviewcomment-body.pt'
--- lib/lp/code/templates/codereviewcomment-body.pt 2010-04-16 04:20:43 +0000
+++ lib/lp/code/templates/codereviewcomment-body.pt 2010-10-04 22:08:24 +0000
@@ -3,9 +3,9 @@
3 xmlns:metal="http://xml.zope.org/namespaces/metal"3 xmlns:metal="http://xml.zope.org/namespaces/metal"
4 omit-tag="">4 omit-tag="">
55
6 <tal:message replace="structure view/body_text/fmt:obfuscate-email/fmt:nice_pre" />6 <tal:message replace="structure view/comment/body_text/fmt:obfuscate-email/fmt:nice_pre" />
77
8 <tal:good-attachments repeat="attachment view/display_attachments">8 <tal:good-attachments repeat="attachment view/comment/display_attachments">
9 <div class="boardComment attachment">9 <div class="boardComment attachment">
10 <div class="boardCommentDetails filename"><a tal:content="attachment/filename" tal:attributes="href attachment/getURL"/></div>10 <div class="boardCommentDetails filename"><a tal:content="attachment/filename" tal:attributes="href attachment/getURL"/></div>
11 <div class="boardCommentBody attachmentBody" tal:content="structure attachment/diff_text/fmt:diff"/>11 <div class="boardCommentBody attachmentBody" tal:content="structure attachment/diff_text/fmt:diff"/>
1212
=== modified file 'lib/lp/code/templates/codereviewcomment-header.pt'
--- lib/lp/code/templates/codereviewcomment-header.pt 2010-02-18 16:40:09 +0000
+++ lib/lp/code/templates/codereviewcomment-header.pt 2010-10-04 22:08:24 +0000
@@ -3,9 +3,9 @@
3 xmlns:metal="http://xml.zope.org/namespaces/metal"3 xmlns:metal="http://xml.zope.org/namespaces/metal"
4 omit-tag="">4 omit-tag="">
55
6 <tal:author replace="structure view/comment_author/fmt:link:mainsite"/>6 <tal:author replace="structure context/comment_author/fmt:link:mainsite"/>
7 <tal:has-body condition="view/has_body">wrote</tal:has-body>7 <tal:has-body condition="context/has_body">wrote</tal:has-body>
8 <tal:date replace="view/comment_date/fmt:displaydate" />8 <tal:date replace="context/comment_date/fmt:displaydate" />
9 <span tal:condition="context/from_superseded" class="sprite warning-icon"9 <span tal:condition="context/from_superseded" class="sprite warning-icon"
10 style="float: right">Posted in <a10 style="float: right">Posted in <a
11 tal:attributes="href context/branch_merge_proposal/fmt:url">a11 tal:attributes="href context/branch_merge_proposal/fmt:url">a
1212
=== modified file 'lib/lp/codehosting/sshserver/session.py'
--- lib/lp/codehosting/sshserver/session.py 2010-08-20 20:31:18 +0000
+++ lib/lp/codehosting/sshserver/session.py 2010-10-04 22:08:24 +0000
@@ -9,9 +9,20 @@
9 ]9 ]
1010
11import os11import os
12import signal
13import socket
12import urlparse14import urlparse
1315
14from twisted.internet.process import ProcessExitedAlready16from zope.event import notify
17from zope.interface import implements
18
19from twisted.internet import (
20 error,
21 fdesc,
22 interfaces,
23 main,
24 process,
25 )
15from twisted.python import log26from twisted.python import log
16from zope.event import notify27from zope.event import notify
1728
@@ -35,6 +46,229 @@
35 """Raised when a session is asked to execute a forbidden command."""46 """Raised when a session is asked to execute a forbidden command."""
3647
3748
49class _WaitForExit(process.ProcessReader):
50 """Wait on a socket for the exit status."""
51
52 def __init__(self, reactor, proc, sock):
53 super(_WaitForExit, self).__init__(reactor, proc, 'exit',
54 sock.fileno())
55 self._sock = sock
56 self.connected = 1
57
58 def close(self):
59 self._sock.close()
60
61 def dataReceived(self, data):
62 # TODO: how do we handle getting only *some* of the content?, Maybe we
63 # need to read more bytes first...
64
65 # This is the only thing we do differently from the standard
66 # ProcessReader. When we get data on this socket, we need to treat it
67 # as a return code, or a failure.
68 if not data.startswith('exited'):
69 # Bad data, we want to signal that we are closing the connection
70 # TODO: How?
71 # self.proc.?
72 self.close()
73 # I don't know what to put here if we get bogus data, but I *do*
74 # want to say that the process is now considered dead to me
75 log.err('Got invalid exit information: %r' % (data,))
76 exit_status = (255 << 8)
77 else:
78 exit_status = int(data.split('\n')[1])
79 self.proc.processEnded(exit_status)
80
81
82class ForkedProcessTransport(process.BaseProcess):
83 """Wrap the forked process in a ProcessTransport so we can talk to it.
84
85 Note that instantiating the class creates the fork and sets it up in the
86 reactor.
87 """
88
89 implements(interfaces.IProcessTransport)
90
91 # Design decisions
92 # [Decision #a]
93 # Inherit from process.BaseProcess
94 # This seems slightly risky, as process.BaseProcess is actually
95 # imported from twisted.internet._baseprocess.BaseProcess. The
96 # real-world Process then actually inherits from process._BaseProcess
97 # I've also had to copy a fair amount from the actual Process
98 # command.
99 # One option would be to inherit from process.Process, and just
100 # override stuff like __init__ and reapProcess which I don't want to
101 # do in the same way. (Is it ok not to call your Base classes
102 # __init__ if you don't want to do that exact work?)
103
104 def __init__(self, reactor, executable, args, environment, proto):
105 process.BaseProcess.__init__(self, proto)
106 # Map from standard file descriptor to the associated pipe
107 self.pipes = {}
108 pid, path, sock = self._spawn(executable, args, environment)
109 self._fifo_path = path
110 self.pid = pid
111 self.process_sock = sock
112 self._fifo_path = path
113 self._connectSpawnToReactor(reactor)
114 if self.proto is not None:
115 self.proto.makeConnection(self)
116
117 def _sendMessageToService(self, message):
118 """Send a message to the Forking service and get the response"""
119 path = config.codehosting.forking_daemon_socket
120 client_sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
121 log.msg('Connecting to Forking Service @ socket: %s for %r'
122 % (path, message))
123 try:
124 client_sock.connect(path)
125 client_sock.sendall(message)
126 # We define the requests to be no bigger than 1kB. (For now)
127 response = client_sock.recv(1024)
128 except socket.error, e:
129 # TODO: What exceptions should be raised?
130 # Raising the raw exception seems to kill the twisted reactor
131 # Note that if the connection is refused, we *could* just
132 # fall back on a regular 'spawnProcess' call.
133 log.err('Connection failed: %s' % (e,))
134 raise
135 if response.startswith("FAILURE"):
136 raise RuntimeError('Failed to send message: %r' % (response,))
The diff has been truncated for viewing.