~launchpad-pqm/launchpad/devel

10637.3.1 by Guilherme Salgado
Use the default python version instead of a hard-coded version
1
#!/usr/bin/python -S
10373.3.1 by Jeroen Vermeulen
Import make-ubuntu-sane.py into the LP tree, with cleanups.
2
# pylint: disable-msg=W0403
3
10373.3.2 by Jeroen Vermeulen
Integrate cleanup of playground sample data for Soyuz testing.
4
# Copyright 2010 Canonical Ltd.  This software is licensed under the
5
# GNU Affero General Public License version 3 (see the file LICENSE).
6
#
7
# This code is based on William Grant's make-ubuntu-sane.py script, but
8
# reorganized to fit Launchpad coding guidelines, and extended.  The
9
# code is included under Canonical copyright with his permission
10
# (2010-02-24).
11
10373.3.1 by Jeroen Vermeulen
Import make-ubuntu-sane.py into the LP tree, with cleanups.
12
"""Clean up sample data so it will allow Soyuz to run locally.
13
14
DO NOT RUN ON PRODUCTION SYSTEMS.  This script deletes lots of
15
Ubuntu-related data.
10373.3.3 by Jeroen Vermeulen
Make the script take over much more of the manual work.
16
17
This script creates a user "ppa-user" (email ppa-user@example.com,
18
password test) who is able to create PPAs.
10373.3.1 by Jeroen Vermeulen
Import make-ubuntu-sane.py into the LP tree, with cleanups.
19
"""
20
21
__metaclass__ = type
22
23
import _pythonpath
24
25
import re
10373.3.5 by Jeroen Vermeulen
Automating lots of manual steps for getting Soyuz to work.
26
import os
27
import subprocess
10373.3.1 by Jeroen Vermeulen
Import make-ubuntu-sane.py into the LP tree, with cleanups.
28
import sys
10373.3.4 by Jeroen Vermeulen
Make soyuz sampledata script do more of the work.
29
from textwrap import dedent
10373.3.3 by Jeroen Vermeulen
Make the script take over much more of the manual work.
30
import transaction
10373.3.1 by Jeroen Vermeulen
Import make-ubuntu-sane.py into the LP tree, with cleanups.
31
32
from zope.component import getUtility
33
from zope.event import notify
34
from zope.lifecycleevent import ObjectCreatedEvent
35
from zope.security.proxy import removeSecurityProxy
36
37
from storm.store import Store
38
13130.1.21 by Curtis Hovey
Fixed cronscript imports.
39
from lp.app.interfaces.launchpad import ILaunchpadCelebrities
14600.2.2 by Curtis Hovey
Moved webapp to lp.services.
40
from lp.services.webapp.interfaces import (
10373.3.3 by Jeroen Vermeulen
Make the script take over much more of the manual work.
41
    IStoreSelector, MAIN_STORE, MASTER_FLAVOR, SLAVE_FLAVOR)
10373.3.1 by Jeroen Vermeulen
Import make-ubuntu-sane.py into the LP tree, with cleanups.
42
10373.3.3 by Jeroen Vermeulen
Make the script take over much more of the manual work.
43
from lp.registry.interfaces.codeofconduct import ISignedCodeOfConductSet
10427.4.6 by Jeroen Vermeulen
Final polish. I hope.
44
from lp.registry.interfaces.person import IPersonSet
10373.3.1 by Jeroen Vermeulen
Import make-ubuntu-sane.py into the LP tree, with cleanups.
45
from lp.registry.interfaces.series import SeriesStatus
10373.3.3 by Jeroen Vermeulen
Make the script take over much more of the manual work.
46
from lp.registry.model.codeofconduct import SignedCodeOfConduct
13970.7.6 by William Grant
SoyuzSampledataSetup is now a LaunchpadScript.
47
from lp.services.scripts.base import LaunchpadScript
11411.6.11 by Julian Edwards
Move SourcePackageFormat
48
from lp.soyuz.enums import SourcePackageFormat
10373.3.1 by Jeroen Vermeulen
Import make-ubuntu-sane.py into the LP tree, with cleanups.
49
from lp.soyuz.interfaces.component import IComponentSet
10373.3.3 by Jeroen Vermeulen
Make the script take over much more of the manual work.
50
from lp.soyuz.interfaces.processor import IProcessorFamilySet
10373.3.1 by Jeroen Vermeulen
Import make-ubuntu-sane.py into the LP tree, with cleanups.
51
from lp.soyuz.interfaces.section import ISectionSet
10373.3.2 by Jeroen Vermeulen
Integrate cleanup of playground sample data for Soyuz testing.
52
from lp.soyuz.interfaces.sourcepackageformat import (
11411.6.11 by Julian Edwards
Move SourcePackageFormat
53
    ISourcePackageFormatSelectionSet,
54
    )
10373.3.1 by Jeroen Vermeulen
Import make-ubuntu-sane.py into the LP tree, with cleanups.
55
from lp.soyuz.model.section import SectionSelection
56
from lp.soyuz.model.component import ComponentSelection
13194.2.1 by Gavin Panella
Change all uses of 'initialise' to 'initialize'.
57
from lp.soyuz.scripts.initialize_distroseries import InitializeDistroSeries
10373.3.3 by Jeroen Vermeulen
Make the script take over much more of the manual work.
58
from lp.testing.factory import LaunchpadObjectFactory
10373.3.1 by Jeroen Vermeulen
Import make-ubuntu-sane.py into the LP tree, with cleanups.
59
60
10373.3.5 by Jeroen Vermeulen
Automating lots of manual steps for getting Soyuz to work.
61
user_name = 'ppa-user'
62
default_email = '%s@example.com' % user_name
63
64
10373.3.1 by Jeroen Vermeulen
Import make-ubuntu-sane.py into the LP tree, with cleanups.
65
class DoNotRunOnProduction(Exception):
66
    """Error: do not run this script on production (-like) systems."""
67
68
69
def get_max_id(store, table_name):
70
    """Find highest assigned id in given table."""
71
    max_id = store.execute("SELECT max(id) FROM %s" % table_name).get_one()
72
    if max_id is None:
73
        return None
74
    else:
75
        return max_id[0]
76
77
10373.3.11 by Jeroen Vermeulen
Merge devel
78
def get_store(flavor=MASTER_FLAVOR):
79
    """Obtain an ORM store."""
80
    return getUtility(IStoreSelector).get(MAIN_STORE, flavor)
81
82
10373.3.1 by Jeroen Vermeulen
Import make-ubuntu-sane.py into the LP tree, with cleanups.
83
def check_preconditions(options):
10373.3.2 by Jeroen Vermeulen
Integrate cleanup of playground sample data for Soyuz testing.
84
    """Try to ensure that it's safe to run.
10373.3.1 by Jeroen Vermeulen
Import make-ubuntu-sane.py into the LP tree, with cleanups.
85
86
    This script must not run on a production server, or anything
87
    remotely like it.
88
    """
10373.3.11 by Jeroen Vermeulen
Merge devel
89
    store = get_store(SLAVE_FLAVOR)
10373.3.1 by Jeroen Vermeulen
Import make-ubuntu-sane.py into the LP tree, with cleanups.
90
91
    # Just a guess, but dev systems aren't likely to have ids this high
92
    # in this table.  Production data does.
93
    real_data = (get_max_id(store, "TranslationMessage") >= 1000000)
94
    if real_data and not options.force:
95
        raise DoNotRunOnProduction(
96
            "Refusing to delete Ubuntu data unless you --force me.")
97
98
    # For some configs it's just absolutely clear this script shouldn't
99
    # run.  Don't even accept --force there.
100
    forbidden_configs = re.compile('(edge|lpnet|production)')
10373.3.5 by Jeroen Vermeulen
Automating lots of manual steps for getting Soyuz to work.
101
    current_config = os.getenv('LPCONFIG', 'an unknown config')
10373.3.1 by Jeroen Vermeulen
Import make-ubuntu-sane.py into the LP tree, with cleanups.
102
    if forbidden_configs.match(current_config):
103
        raise DoNotRunOnProduction(
104
            "I won't delete Ubuntu data on %s and you can't --force me."
105
            % current_config)
106
107
10373.3.3 by Jeroen Vermeulen
Make the script take over much more of the manual work.
108
def get_person_set():
10373.3.1 by Jeroen Vermeulen
Import make-ubuntu-sane.py into the LP tree, with cleanups.
109
    """Return `IPersonSet` utility."""
10373.3.3 by Jeroen Vermeulen
Make the script take over much more of the manual work.
110
    return getUtility(IPersonSet)
10373.3.1 by Jeroen Vermeulen
Import make-ubuntu-sane.py into the LP tree, with cleanups.
111
112
113
def retire_series(distribution):
114
    """Mark all `DistroSeries` for `distribution` as obsolete."""
115
    for series in distribution.series:
116
        series.status = SeriesStatus.OBSOLETE
117
118
119
def retire_active_publishing_histories(histories, requester):
120
    """Retire all active publishing histories in the given collection."""
121
    # Avoid circular import.
122
    from lp.soyuz.interfaces.publishing import active_publishing_status
123
    for history in histories(status=active_publishing_status):
124
        history.requestDeletion(
125
            requester, "Cleaned up because of missing Librarian files.")
126
127
128
def retire_distro_archives(distribution, culprit):
129
    """Retire all items in `distribution`'s archives."""
130
    for archive in distribution.all_distro_archives:
131
        retire_active_publishing_histories(
132
            archive.getPublishedSources, culprit)
133
        retire_active_publishing_histories(
134
            archive.getAllPublishedBinaries, culprit)
135
136
137
def retire_ppas(distribution):
138
    """Disable all PPAs for `distribution`."""
139
    for ppa in distribution.getAllPPAs():
140
        removeSecurityProxy(ppa).publish = False
141
142
10373.3.3 by Jeroen Vermeulen
Make the script take over much more of the manual work.
143
def add_architecture(distroseries, architecture_name):
144
    """Add a DistroArchSeries for the given architecture to `distroseries`."""
145
    # Avoid circular import.
146
    from lp.soyuz.model.distroarchseries import DistroArchSeries
147
10373.3.11 by Jeroen Vermeulen
Merge devel
148
    store = get_store(MASTER_FLAVOR)
10373.3.3 by Jeroen Vermeulen
Make the script take over much more of the manual work.
149
    family = getUtility(IProcessorFamilySet).getByName(architecture_name)
150
    archseries = DistroArchSeries(
151
        distroseries=distroseries, processorfamily=family,
152
        owner=distroseries.owner, official=True,
153
        architecturetag=architecture_name)
154
    store.add(archseries)
155
156
10373.3.1 by Jeroen Vermeulen
Import make-ubuntu-sane.py into the LP tree, with cleanups.
157
def create_sections(distroseries):
158
    """Set up some sections for `distroseries`."""
159
    section_names = (
160
        'admin', 'cli-mono', 'comm', 'database', 'devel', 'debug', 'doc',
161
        'editors', 'electronics', 'embedded', 'fonts', 'games', 'gnome',
162
        'graphics', 'gnu-r', 'gnustep', 'hamradio', 'haskell', 'httpd',
163
        'interpreters', 'java', 'kde', 'kernel', 'libs', 'libdevel', 'lisp',
164
        'localization', 'mail', 'math', 'misc', 'net', 'news', 'ocaml',
165
        'oldlibs', 'otherosfs', 'perl', 'php', 'python', 'ruby', 'science',
166
        'shells', 'sound', 'tex', 'text', 'utils', 'vcs', 'video', 'web',
167
        'x11', 'xfce', 'zope')
168
    store = Store.of(distroseries)
169
    for section_name in section_names:
170
        section = getUtility(ISectionSet).ensure(section_name)
171
        if section not in distroseries.sections:
172
            store.add(
173
                SectionSelection(distroseries=distroseries, section=section))
174
175
176
def create_components(distroseries, uploader):
177
    """Set up some components for `distroseries`."""
178
    component_names = ('main', 'restricted', 'universe', 'multiverse')
179
    store = Store.of(distroseries)
180
    main_archive = distroseries.distribution.main_archive
181
    for component_name in component_names:
182
        component = getUtility(IComponentSet).ensure(component_name)
183
        if component not in distroseries.components:
184
            store.add(
185
                ComponentSelection(
186
                    distroseries=distroseries, component=component))
187
        main_archive.newComponentUploader(uploader, component)
188
        main_archive.newQueueAdmin(uploader, component)
189
190
191
def create_series(parent, full_name, version, status):
192
    """Set up a `DistroSeries`."""
193
    distribution = parent.distribution
7675.1070.6 by Raphael Badin
Fixed tests.
194
    registrant = parent.owner
10373.3.1 by Jeroen Vermeulen
Import make-ubuntu-sane.py into the LP tree, with cleanups.
195
    name = full_name.split()[0].lower()
196
    title = "The " + full_name
197
    displayname = full_name.split()[0]
198
    new_series = distribution.newSeries(name=name, title=title,
199
        displayname=displayname, summary='Ubuntu %s is good.' % version,
200
        description='%s is awesome.' % version, version=version,
13045.14.3 by Gavin Panella
Change many more sites from using parent_series to previous_series.
201
        previous_series=None, registrant=registrant)
10373.3.1 by Jeroen Vermeulen
Import make-ubuntu-sane.py into the LP tree, with cleanups.
202
    new_series.status = status
203
    notify(ObjectCreatedEvent(new_series))
204
13168.13.30 by Raphael Badin
Setup previous_series properly in tests.
205
    new_series.previous_series = parent
13194.2.1 by Gavin Panella
Change all uses of 'initialise' to 'initialize'.
206
    ids = InitializeDistroSeries(new_series, [parent.id])
207
    ids.initialize()
10373.3.1 by Jeroen Vermeulen
Import make-ubuntu-sane.py into the LP tree, with cleanups.
208
    return new_series
209
210
211
def create_sample_series(original_series, log):
212
    """Set up sample `DistroSeries`.
213
214
    :param original_series: The parent for the first new series to be
215
        created.  The second new series will have the first as a parent,
216
        and so on.
217
    """
218
    series_descriptions = [
219
        ('Dapper Drake', SeriesStatus.SUPPORTED, '6.06'),
220
        ('Edgy Eft', SeriesStatus.OBSOLETE, '6.10'),
221
        ('Feisty Fawn', SeriesStatus.OBSOLETE, '7.04'),
222
        ('Gutsy Gibbon', SeriesStatus.OBSOLETE, '7.10'),
223
        ('Hardy Heron', SeriesStatus.SUPPORTED, '8.04'),
12473.2.2 by William Grant
Add Natty and Onerous, and allow 3.0 formats in Karmic and later.
224
        ('Intrepid Ibex', SeriesStatus.OBSOLETE, '8.10'),
225
        ('Jaunty Jackalope', SeriesStatus.OBSOLETE, '9.04'),
11091.5.2 by Aaron Bentley
Update soyuz sample data
226
        ('Karmic Koala', SeriesStatus.SUPPORTED, '9.10'),
12473.2.2 by William Grant
Add Natty and Onerous, and allow 3.0 formats in Karmic and later.
227
        ('Lucid Lynx', SeriesStatus.SUPPORTED, '10.04'),
228
        ('Maverick Meerkat', SeriesStatus.CURRENT, '10.10'),
229
        ('Natty Narwhal', SeriesStatus.DEVELOPMENT, '11.04'),
230
        ('Onerous Ocelot', SeriesStatus.FUTURE, '11.10'),
10373.3.1 by Jeroen Vermeulen
Import make-ubuntu-sane.py into the LP tree, with cleanups.
231
        ]
232
233
    parent = original_series
234
    for full_name, status, version in series_descriptions:
235
        log.info('Creating %s...' % full_name)
236
        parent = create_series(parent, full_name, version, status)
12473.2.2 by William Grant
Add Natty and Onerous, and allow 3.0 formats in Karmic and later.
237
        # Karmic is the first series in which the 3.0 formats are
238
        # allowed. Subsequent series will inherit them.
239
        if version == '9.10':
240
            spfss = getUtility(ISourcePackageFormatSelectionSet)
241
            spfss.add(parent, SourcePackageFormat.FORMAT_3_0_QUILT)
242
            spfss.add(parent, SourcePackageFormat.FORMAT_3_0_NATIVE)
10373.3.1 by Jeroen Vermeulen
Import make-ubuntu-sane.py into the LP tree, with cleanups.
243
244
12473.2.3 by William Grant
Add a component to grumpy to placate the publisher.
245
def add_series_component(series):
246
    """Permit a component in the given series."""
247
    component = getUtility(IComponentSet)['main']
248
    get_store(MASTER_FLAVOR).add(
249
        ComponentSelection(
250
            distroseries=series, component=component))
251
252
10373.3.1 by Jeroen Vermeulen
Import make-ubuntu-sane.py into the LP tree, with cleanups.
253
def clean_up(distribution, log):
254
    # First we eliminate all active publishings in the Ubuntu main archives.
255
    # None of the librarian files exist, so it kills the publisher.
256
257
    # Could use IPublishingSet.requestDeletion() on the published sources to
258
    # get rid of the binaries too, but I don't trust that there aren't
259
    # published binaries without corresponding sources.
260
261
    log.info("Deleting all items in official archives...")
10373.3.3 by Jeroen Vermeulen
Make the script take over much more of the manual work.
262
    retire_distro_archives(distribution, get_person_set().getByName('name16'))
10373.3.1 by Jeroen Vermeulen
Import make-ubuntu-sane.py into the LP tree, with cleanups.
263
264
    # Disable publishing of all PPAs, as they probably have broken
265
    # publishings too.
266
    log.info("Disabling all PPAs...")
267
    retire_ppas(distribution)
268
269
    retire_series(distribution)
270
12473.2.3 by William Grant
Add a component to grumpy to placate the publisher.
271
    # grumpy has no components, which upsets the publisher.
272
    add_series_component(distribution['grumpy'])
273
10373.3.1 by Jeroen Vermeulen
Import make-ubuntu-sane.py into the LP tree, with cleanups.
274
10373.3.2 by Jeroen Vermeulen
Integrate cleanup of playground sample data for Soyuz testing.
275
def set_source_package_format(distroseries):
276
    """Register a series' source package format selection."""
277
    utility = getUtility(ISourcePackageFormatSelectionSet)
278
    format = SourcePackageFormat.FORMAT_1_0
279
    if utility.getBySeriesAndFormat(distroseries, format) is None:
280
        utility.add(distroseries, format)
281
282
13045.14.3 by Gavin Panella
Change many more sites from using parent_series to previous_series.
283
def populate(distribution, previous_series_name, uploader_name, options, log):
10373.3.1 by Jeroen Vermeulen
Import make-ubuntu-sane.py into the LP tree, with cleanups.
284
    """Set up sample data on `distribution`."""
13045.14.3 by Gavin Panella
Change many more sites from using parent_series to previous_series.
285
    previous_series = distribution.getSeries(previous_series_name)
10373.3.1 by Jeroen Vermeulen
Import make-ubuntu-sane.py into the LP tree, with cleanups.
286
287
    log.info("Configuring sections...")
13045.14.3 by Gavin Panella
Change many more sites from using parent_series to previous_series.
288
    create_sections(previous_series)
289
    add_architecture(previous_series, 'amd64')
10373.3.1 by Jeroen Vermeulen
Import make-ubuntu-sane.py into the LP tree, with cleanups.
290
291
    log.info("Configuring components and permissions...")
10373.3.3 by Jeroen Vermeulen
Make the script take over much more of the manual work.
292
    uploader = get_person_set().getByName(uploader_name)
13045.14.3 by Gavin Panella
Change many more sites from using parent_series to previous_series.
293
    create_components(previous_series, uploader)
294
295
    set_source_package_format(previous_series)
296
297
    create_sample_series(previous_series, log)
10373.3.1 by Jeroen Vermeulen
Import make-ubuntu-sane.py into the LP tree, with cleanups.
298
299
10373.3.4 by Jeroen Vermeulen
Make soyuz sampledata script do more of the work.
300
def sign_code_of_conduct(person, log):
301
    """Sign Ubuntu Code of Conduct for `person`, if necessary."""
302
    if person.is_ubuntu_coc_signer:
303
        # Already signed.
304
        return
305
306
    log.info("Signing Ubuntu code of conduct.")
307
    signedcocset = getUtility(ISignedCodeOfConductSet)
308
    person_id = person.id
309
    if signedcocset.searchByUser(person_id).count() == 0:
310
        fake_gpg_key = LaunchpadObjectFactory().makeGPGKey(person)
311
        Store.of(person).add(SignedCodeOfConduct(
312
            owner=person, signingkey=fake_gpg_key,
313
            signedcode="Normally a signed CoC would go here.", active=True))
314
315
316
def create_ppa_user(username, options, approver, log):
10373.3.3 by Jeroen Vermeulen
Make the script take over much more of the manual work.
317
    """Create new user, with password "test," and sign code of conduct."""
318
    person = get_person_set().getByName(username)
319
    if person is None:
10427.4.2 by Jeroen Vermeulen
Moved user/gpg creation into make-lp-user.
320
        have_email = (options.email != default_email)
321
        command_line = [
12494.1.98 by Gavin Panella
Fix almost all test failures. Most were due to the extra required argument to the InitialiseDistroSeries constructor.
322
            'utilities/make-lp-user', username, 'ubuntu-team']
10427.4.2 by Jeroen Vermeulen
Moved user/gpg creation into make-lp-user.
323
        if have_email:
324
            command_line += ['--email', options.email]
325
326
        pipe = subprocess.Popen(command_line, stderr=subprocess.PIPE)
327
        stdout, stderr = pipe.communicate()
328
        if stderr != '':
329
            print stderr
330
        if pipe.returncode != 0:
331
            sys.exit(2)
332
333
    transaction.commit()
10373.3.3 by Jeroen Vermeulen
Make the script take over much more of the manual work.
334
10427.4.6 by Jeroen Vermeulen
Final polish. I hope.
335
    person = getUtility(IPersonSet).getByName(username)
10373.3.4 by Jeroen Vermeulen
Make soyuz sampledata script do more of the work.
336
    sign_code_of_conduct(person, log)
10373.3.3 by Jeroen Vermeulen
Make the script take over much more of the manual work.
337
10373.3.5 by Jeroen Vermeulen
Automating lots of manual steps for getting Soyuz to work.
338
    return person
339
340
10373.3.10 by Jeroen Vermeulen
Creating PPA as well.
341
def create_ppa(distribution, person, name):
342
    """Create a PPA for `person`."""
10373.3.12 by Jeroen Vermeulen
Set external dependencies.
343
    ppa = LaunchpadObjectFactory().makeArchive(
10373.3.10 by Jeroen Vermeulen
Creating PPA as well.
344
        distribution=distribution, owner=person, name=name, virtualized=False,
345
        description="Automatically created test PPA.")
10373.3.12 by Jeroen Vermeulen
Set external dependencies.
346
    ppa.external_dependencies = (
12473.2.1 by William Grant
An archive's external dependencies can have a series variable. Use it.
347
        "deb http://archive.ubuntu.com/ubuntu %(series)s "
348
        "main restricted universe multiverse\n")
10373.3.12 by Jeroen Vermeulen
Set external dependencies.
349
10373.3.10 by Jeroen Vermeulen
Creating PPA as well.
350
13970.7.6 by William Grant
SoyuzSampledataSetup is now a LaunchpadScript.
351
class SoyuzSampledataSetup(LaunchpadScript):
352
353
    description = "Set up fresh Ubuntu series and %s identity." % user_name
354
355
    def add_my_options(self):
356
        self.parser.add_option(
357
            '-f', '--force', action='store_true', dest='force',
358
            help="DANGEROUS: run even if the database looks production-like.")
359
        self.parser.add_option(
360
            '-e', '--email', action='store', dest='email',
361
            default=default_email,
362
            help=(
363
                "Email address to use for %s.  Should match your GPG key."
364
                % user_name))
365
366
    def main(self):
367
        check_preconditions(self.options.force)
368
369
        ubuntu = getUtility(ILaunchpadCelebrities).ubuntu
370
        clean_up(ubuntu, self.logger)
371
372
        # Use Hoary as the root, as Breezy and Grumpy are broken.
373
        populate(ubuntu, 'hoary', 'ubuntu-team', self.options, self.logger)
374
375
        admin = get_person_set().getByName('name16')
376
        person = create_ppa_user(user_name, self.options, admin, self.logger)
377
378
        create_ppa(ubuntu, person, 'test-ppa')
379
380
        transaction.commit()
381
        self.logger.info("Done.")
382
383
        print dedent("""
384
            Now start your local Launchpad with "make run_codehosting" and log
385
            into https://launchpad.dev/ as "%(email)s" with "test" as the
386
            password.
387
            Your user name will be %(user_name)s."""
388
            % {
389
                'email': self.options.email,
390
                'user_name': user_name,
391
                })
10373.3.5 by Jeroen Vermeulen
Automating lots of manual steps for getting Soyuz to work.
392
10373.3.2 by Jeroen Vermeulen
Integrate cleanup of playground sample data for Soyuz testing.
393
10373.3.1 by Jeroen Vermeulen
Import make-ubuntu-sane.py into the LP tree, with cleanups.
394
if __name__ == "__main__":
13970.7.6 by William Grant
SoyuzSampledataSetup is now a LaunchpadScript.
395
    SoyuzSampledataSetup('soyuz-sampledata-setup').lock_and_run()