~xnox/bzr-pipeline/bump-bzr

200 by Aaron Bentley
bzr-reconfigure uses .bzr/branches instead of .bzr/pipes.
1
# Copyright (C) 2009-2011 Aaron Bentley
6 by Aaron Bentley
Add copyright and GPL notices.
2
#
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
7
#
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
12
#
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
17
132.1.14 by Aaron Bentley
Clean up output from sync-pipeline.
18
from bzrlib import (
19
    builtins,
20
    errors,
21
    merge,
22
    revision as _mod_revision, trace,
23
    ui,
24
)
2 by Aaron Bentley
Add add-block command
25
from bzrlib.branch import Branch
28 by Aaron Bentley
Allow remove-pipe to operate directly on branches.
26
from bzrlib.bzrdir import BzrDir
2 by Aaron Bentley
Add add-block command
27
from bzrlib.commands import Command
165 by Aaron Bentley
Lint fix
28
from bzrlib.option import Option, RegistryOption
124 by Aaron Bentley
Accept directories for pipe-patches
29
from bzrlib.osutils import pathjoin
15 by Aaron Bentley
Implement switch-pipe.
30
from bzrlib.switch import switch
31
from bzrlib.workingtree import WorkingTree
66 by Aaron Bentley
Introduce reconfigure-pipeline.
32
from bzrlib.plugins.pipeline.pipeline import (
58.4.9 by Aaron Bentley
Add dwim pipe selection to to --uncommitted.
33
    dwim_pipe,
197 by Aaron Bentley
Extract PipeManager.remove_pipe.
34
    is_light_checkout,
188 by Aaron Bentley
bzr pump supports --show-base.
35
    MergeConfig,
66 by Aaron Bentley
Introduce reconfigure-pipeline.
36
    NoSuchPipe,
37
    PipeManager,
157.1.12 by Aaron Bentley
Move find_pipe to PipeStorage
38
    PipeStorage,
66 by Aaron Bentley
Introduce reconfigure-pipeline.
39
    tree_to_pipeline,
40
)
5 by Aaron Bentley
Rename to pipeline
41
42
30 by Aaron Bentley
Check for lightweight checkouts before switching.
43
def require_light_checkout(tree):
44
    if not is_light_checkout(tree):
45
        raise errors.BzrCommandError('Directory is not a lightweight'
46
                                     ' checkout.')
47
48
71 by Aaron Bentley
Allow show-pipeline in a subdirectory.
49
class PipeCommand(Command):
50
89 by Aaron Bentley
Provide -d option or similar for all commands.
51
    def _get_manager(self, location, after, before):
52
        tree, manager = self._get_checkout_manager(location, allow_tree=True)
71 by Aaron Bentley
Allow show-pipeline in a subdirectory.
53
        if after is not None:
54
            if before is not None:
55
                raise errors.BzrCommandError('Cannot specify --before and'
56
                                             ' --after.')
157.1.13 by Aaron Bentley
Make PipeManager take a checkout parameter.
57
            manager = PipeManager(manager.storage.find_pipe(after), tree)
71 by Aaron Bentley
Allow show-pipeline in a subdirectory.
58
        if before is not None:
157.1.13 by Aaron Bentley
Make PipeManager take a checkout parameter.
59
            manager = PipeManager(manager.storage.find_pipe(before), tree)
89 by Aaron Bentley
Provide -d option or similar for all commands.
60
        return tree, manager
71 by Aaron Bentley
Allow show-pipeline in a subdirectory.
61
62
    def _get_location_manager(self, location='.'):
63
        branch = Branch.open_containing(location)[0]
157.1.13 by Aaron Bentley
Make PipeManager take a checkout parameter.
64
        return PipeManager(branch, None)
71 by Aaron Bentley
Allow show-pipeline in a subdirectory.
65
74 by Aaron Bentley
Unify input handling.
66
    @staticmethod
89 by Aaron Bentley
Provide -d option or similar for all commands.
67
    def _get_tree_and_branch(location, tree_optional):
68
        if tree_optional:
73 by Aaron Bentley
Unify input handling.
69
            tree, branch = BzrDir.open_containing_tree_or_branch(location)[:2]
70
        else:
71
            tree = WorkingTree.open_containing(location)[0]
72
            branch = tree.branch
89 by Aaron Bentley
Provide -d option or similar for all commands.
73
        return tree, branch
74
75
    @classmethod
76
    def _get_checkout_manager(klass, location='.', checkout_optional=False,
77
                              pipe=None, allow_tree=False):
78
        try:
79
            tree, branch = klass._get_tree_and_branch('.', checkout_optional)
157.1.12 by Aaron Bentley
Move find_pipe to PipeStorage
80
            branch = PipeStorage(branch).find_pipe(location)
89 by Aaron Bentley
Provide -d option or similar for all commands.
81
        except (errors.NotBranchError, NoSuchPipe):
82
            tree, branch = klass._get_tree_and_branch(location,
83
                                                      checkout_optional)
73 by Aaron Bentley
Unify input handling.
84
        if tree is not None and not allow_tree:
85
            require_light_checkout(tree)
157.1.13 by Aaron Bentley
Make PipeManager take a checkout parameter.
86
        manager = PipeManager(branch, tree)
73 by Aaron Bentley
Unify input handling.
87
        if pipe is not None:
157.1.13 by Aaron Bentley
Make PipeManager take a checkout parameter.
88
            manager = PipeManager(manager.storage.find_pipe(pipe), tree)
73 by Aaron Bentley
Unify input handling.
89
        return tree, manager
72 by Aaron Bentley
Move switch logic to PipeManager.
90
132 by Aaron Bentley
add-pipe uses previous revision-id where possible.
91
    def _get_revision_id(self, branch, revision, manager, insert_before):
71 by Aaron Bentley
Allow show-pipeline in a subdirectory.
92
        if revision is None:
132 by Aaron Bentley
add-pipe uses previous revision-id where possible.
93
            if not insert_before:
94
                return None
95
            prev_revision_id = manager.get_prev_revision_id()
96
            if prev_revision_id is not None:
97
                return prev_revision_id
98
            else:
99
                return branch.last_revision()
71 by Aaron Bentley
Allow show-pipeline in a subdirectory.
100
        if len(revision) > 1:
101
            raise errors.BzrCommandError('Only one revision may be supplied.')
102
        return revision[0].as_revision_id(branch)
103
104
105
class cmd_add_pipe(PipeCommand):
11 by Aaron Bentley
Make add-pipe more flexible.
106
    """Add a pipe to the pipeline.
107
108
    By default, the pipe is added after the current active pipe, at the
109
    current revision.
110
111
    This command can be used to start a new pipeline.
112
    """
5 by Aaron Bentley
Rename to pipeline
113
104 by Aaron Bentley
add-pipe --before now works.
114
    takes_args = ['pipe', 'neighbour?']
115
    takes_options = [RegistryOption.from_kwargs('position',
116
                     'Position to insert the new pipe at.',
117
                     after='Insert after the selected pipe.',
118
                     before='Insert before the selected pipe.',
119
                     value_switches=True, enum_switch=False),
32 by Aaron Bentley
Add interactive mode to add-pipe.
120
                     Option('interactive', short_name='i',
121
                             help='Interactively decide which changes to place'
122
                             ' in the new pipe.'),
85 by Aaron Bentley
Switch to newly-added pipes.
123
                     Option('no-switch', help="Do not switch to new pipe."),
89 by Aaron Bentley
Provide -d option or similar for all commands.
124
                     Option('directory', short_name='d', type=unicode,
125
                            help='Directory of the pipe to add to, rather than'
126
                            ' the one for the working directory.'),
11 by Aaron Bentley
Make add-pipe more flexible.
127
                     'revision',]
128
104 by Aaron Bentley
add-pipe --before now works.
129
    def run(self, pipe, neighbour=None, revision=None, interactive=False,
130
            no_switch=False, directory=None, position='after'):
131
        tree, manager = self._get_checkout_manager(directory, pipe=neighbour,
132
            allow_tree=True)
63 by Aaron Bentley
Require lightweight checkouts for add-pipe.
133
        if not is_light_checkout(tree):
134
            raise errors.BzrCommandError('add-pipe should be run in a '
135
                'lightweight checkout.  See bzr help pipeline for details.')
104 by Aaron Bentley
add-pipe --before now works.
136
        insert_before = (position == 'before')
132.1.6 by Aaron Bentley
Fix determining LCA
137
        tree.branch.lock_read()
138
        try:
139
            revision_id = self._get_revision_id(tree.branch, revision,
140
                                                manager, insert_before)
141
        finally:
142
            tree.branch.unlock()
97 by Aaron Bentley
Allow adding branches to pipelines.
143
        try:
144
            new_br = Branch.open(pipe)
145
        except errors.NotBranchError:
157.1.11 by Aaron Bentley
Move methods to PipeStorage
146
            new_br = manager.storage.insert_pipe(pipe, revision_id,
147
                                                 before=insert_before)
97 by Aaron Bentley
Allow adding branches to pipelines.
148
        else:
157.1.11 by Aaron Bentley
Move methods to PipeStorage
149
            manager.storage.insert_branch(new_br, insert_before)
85 by Aaron Bentley
Switch to newly-added pipes.
150
        if revision_id is None and no_switch:
157.1.15 by Aaron Bentley
store_uncommitted doesn't take a tree parameter.
151
            PipeManager(new_br, tree).store_uncommitted(interactive)
85 by Aaron Bentley
Switch to newly-added pipes.
152
        if no_switch:
153
            trace.note('Created pipe "%s".' % pipe)
154
        if not no_switch:
155
            switch(tree.bzrdir, new_br)
156
            trace.note('Created and switched to pipe "%s".' % pipe)
15 by Aaron Bentley
Implement switch-pipe.
157
158
132.1.16 by Aaron Bentley
Allow pipes to be renamed
159
class cmd_rename_pipe(PipeCommand):
132.1.17 by Aaron Bentley
Update docstring
160
    """Rename a pipe to a different name.
161
162
    This will rename the branch directory and update the pipeline metadata.
163
    It is not connected to the branch nick.
164
    """
132.1.16 by Aaron Bentley
Allow pipes to be renamed
165
166
    takes_args = ['new_name']
167
168
    def run(self, new_name):
169
        tree, manager = self._get_checkout_manager('.')
157.1.14 by Aaron Bentley
Remove tree from sync_pipeline parameters.
170
        manager.rename_pipe(new_name)
132.1.16 by Aaron Bentley
Allow pipes to be renamed
171
35 by Aaron Bentley
Support merge --uncommitted PIPE.
172
class cmd_merge(builtins.cmd_merge):
173
    #Support merge --uncommitted PIPE
53 by Aaron Bentley
Update user doc
174
    __doc__ = builtins.cmd_merge.__doc__
35 by Aaron Bentley
Support merge --uncommitted PIPE.
175
153 by Aaron Bentley
Fix merge --uncommitted with bzr 2.1rc1
176
    def get_merger_from_uncommitted(self, tree, location, pb):
60.1.1 by Aaron Bentley
Override merge --uncommitted a cleaner way.
177
        try:
157.1.13 by Aaron Bentley
Make PipeManager take a checkout parameter.
178
            pipe = PipeManager(dwim_pipe(PipeManager(tree.branch, tree),
179
                                         location), tree)
60.1.1 by Aaron Bentley
Override merge --uncommitted a cleaner way.
180
        except NoSuchPipe:
58.1.19 by Aaron Bentley
Fix normal merge --uncommitted
181
            return builtins.cmd_merge.get_merger_from_uncommitted(
153 by Aaron Bentley
Fix merge --uncommitted with bzr 2.1rc1
182
                self, tree, location, pb)
157.1.16 by Aaron Bentley
Use PipeManager.checkout where possible.
183
        merger = pipe.make_uncommitted_merger(self)
60.1.1 by Aaron Bentley
Override merge --uncommitted a cleaner way.
184
        if merger is None:
185
            # Have to return a merger of some kind, so we don't try another
186
            # code path.
187
            merger = merge.Merger.from_revision_ids(None, tree,
188
                _mod_revision.NULL_REVISION, _mod_revision.NULL_REVISION)
189
        return merger
35 by Aaron Bentley
Support merge --uncommitted PIPE.
190
191
132.1.4 by Aaron Bentley
Improve docs.
192
class cmd_reconfigure_pipeline(PipeCommand):
193
    """Reconfigure a tree with branch into a lightweight checkout of a pipe.
194
200 by Aaron Bentley
bzr-reconfigure uses .bzr/branches instead of .bzr/pipes.
195
    The pipeline will be stored in a new "branches" subdirectory of .bzr.
196
    This is compatible with the bzr-colo plugin.
132.1.4 by Aaron Bentley
Improve docs.
197
198
    This is suitable if you have a standalone tree, but if you have a
199
    shared repository with its own organization scheme already, it's probably
200
    better to just create a lightweight checkout.
201
    """
66 by Aaron Bentley
Introduce reconfigure-pipeline.
202
203
    def run(self):
204
        tree = WorkingTree.open_containing('.')[0]
205
        tree_to_pipeline(tree)
206
207
73 by Aaron Bentley
Unify input handling.
208
class cmd_remove_pipe(PipeCommand):
33 by Aaron Bentley
Allow specifying a pipe to remove-pipe, add docs.
209
    """Remove a pipe from the pipeline.
210
211
    By default, the current pipe is removed, but a pipe may be specified as
84 by Aaron Bentley
Add remove-pipe --branch.
212
    the first parameter.  By default, only the association of the pipe with
213
    its pipeline is removed, but if --branch is specified, the branch is
214
    also deleted.
33 by Aaron Bentley
Allow specifying a pipe to remove-pipe, add docs.
215
    """
216
217
    takes_args = ['pipe?']
84 by Aaron Bentley
Add remove-pipe --branch.
218
    takes_options = [Option('branch', help="Remove pipe's branch.")]
33 by Aaron Bentley
Allow specifying a pipe to remove-pipe, add docs.
219
84 by Aaron Bentley
Add remove-pipe --branch.
220
    def run(self, pipe=None, branch=False):
89 by Aaron Bentley
Provide -d option or similar for all commands.
221
        tree, manager = self._get_checkout_manager(location=pipe,
73 by Aaron Bentley
Unify input handling.
222
                                                   checkout_optional=True,
223
                                                   allow_tree=True)
197 by Aaron Bentley
Extract PipeManager.remove_pipe.
224
        target_branch = manager.get_nearest_pipe()
52 by Aaron Bentley
Separate PipeStorage from PipeManager.
225
        if target_branch is None:
27 by Aaron Bentley
Implement remove-pipe.
226
            raise errors.BzrCommandError('Branch is not connected to a'
227
                                         ' pipeline.')
197 by Aaron Bentley
Extract PipeManager.remove_pipe.
228
        manager.remove_pipe(target_branch, delete_branch=branch)
27 by Aaron Bentley
Implement remove-pipe.
229
230
72 by Aaron Bentley
Move switch logic to PipeManager.
231
class cmd_switch_pipe(PipeCommand):
15 by Aaron Bentley
Implement switch-pipe.
232
    """Switch from one pipe to another.
233
234
    Any uncommitted changes are stored.  Any stored changes in the target
235
    pipe are restored.
236
    """
132.1.5 by Aaron Bentley
Add swp alias, fix pipes alias.
237
    
238
    aliases = ['swp']
53 by Aaron Bentley
Update user doc
239
15 by Aaron Bentley
Implement switch-pipe.
240
    takes_args = ['pipe']
89 by Aaron Bentley
Provide -d option or similar for all commands.
241
    takes_options = [
242
        Option('directory', type=unicode, short_name='d',
243
               help='Directory of the checkout to switch, rather than the'
244
                    ' current directory.')]
15 by Aaron Bentley
Implement switch-pipe.
245
89 by Aaron Bentley
Provide -d option or similar for all commands.
246
    def run(self, pipe, directory=None):
247
        checkout, manager = self._get_checkout_manager(directory)
130 by Aaron Bentley
switch-pipe reports which pipe it switched from and to.
248
        old = checkout.branch.nick
58.4.9 by Aaron Bentley
Add dwim pipe selection to to --uncommitted.
249
        target = dwim_pipe(manager, pipe)
157.1.16 by Aaron Bentley
Use PipeManager.checkout where possible.
250
        manager.switch_to_pipe(target)
130 by Aaron Bentley
switch-pipe reports which pipe it switched from and to.
251
        trace.note('Switched from "%s" to "%s".' % (old, target.nick))
5 by Aaron Bentley
Rename to pipeline
252
253
161 by Aaron Bentley
Add hidden store command.
254
class cmd_store(PipeCommand):
255
178 by Aaron Bentley
Fix docs
256
    """Store uncommitted changes in the pipe."""
257
161 by Aaron Bentley
Add hidden store command.
258
    hidden = True
259
260
    def run(self):
261
        checkout, manager = self._get_checkout_manager('.')
192.1.7 by Aaron Bentley
Fix store to not prompt.
262
        manager.store_uncommitted()
161 by Aaron Bentley
Add hidden store command.
263
264
71 by Aaron Bentley
Allow show-pipeline in a subdirectory.
265
class cmd_show_pipeline(PipeCommand):
31 by Aaron Bentley
Document the show-pipeline command.
266
    """Show the current pipeline.
267
268
    All pipes are listed with the beginning of the pipeline at the top and the
132.1.3 by Aaron Bentley
Cherrypick ian's doc fixes.
269
    end of the pipeline at the bottom. These indicators are used::
31 by Aaron Bentley
Document the show-pipeline command.
270
132.1.3 by Aaron Bentley
Cherrypick ian's doc fixes.
271
      * - The current pipe.
272
      U - A pipe holding uncommitted changes.
31 by Aaron Bentley
Document the show-pipeline command.
273
274
    Uncommitted changes are automatically restored by the 'switch-pipe'
275
    command.
276
    """
3 by Aaron Bentley
Add list-blocks command.
277
60 by Aaron Bentley
Allow specifying a location to show-pipeline.
278
    takes_args = ['location?']
58.4.10 by Aaron Bentley
Make 'pipes' an alias for show-pipeline
279
    aliases = ['pipes']
196 by Aaron Bentley
Mention 'nick' in show-pipeline docs.
280
    _see_also = ['nick']
60 by Aaron Bentley
Allow specifying a location to show-pipeline.
281
282
    def run(self, location='.'):
71 by Aaron Bentley
Allow show-pipeline in a subdirectory.
283
        manager = self._get_location_manager(location)
284
        for pipe in manager.list_pipes():
285
            if pipe is manager.storage.branch:
24 by Aaron Bentley
Add display of uncommitted changes to 'show-pipeline'
286
                selected = '*'
287
            else:
288
                selected = ' '
157.1.13 by Aaron Bentley
Make PipeManager take a checkout parameter.
289
            if PipeStorage(pipe).has_stored_changes():
24 by Aaron Bentley
Add display of uncommitted changes to 'show-pipeline'
290
                uncommitted = 'U'
291
            else:
292
                uncommitted = ' '
293
            self.outf.write('%s%s %s\n' % (selected, uncommitted, pipe.nick))
22 by Aaron Bentley
Add pump command.
294
295
74 by Aaron Bentley
Unify input handling.
296
class cmd_pump(PipeCommand):
22 by Aaron Bentley
Add pump command.
297
    """From this pipe onward, merge all pipes into their next pipe and commit.
298
299
    If the merge is successful, the changes are automatically committed, and
300
    the process repeats for the next pipe.  Eventually, the last pipe will
301
    have all the changes from all of the affected pipes.  On success, the
302
    checkout's initial state is restored.
303
304
    If the merge produces conflicts, the process aborts and no commit is
305
    performed.  You should resolve the conflicts, commit, and re-run pump.
185 by Aaron Bentley
Make --from work with pipes.
306
307
    --from may be a pipe, in which case the pumping starts at the specified
308
    pipe, or it may be a branch, in which case the branch will be pumped into
309
    the first pipe.
22 by Aaron Bentley
Add pump command.
310
    """
311
89 by Aaron Bentley
Provide -d option or similar for all commands.
312
    takes_options = [
313
        Option('directory', short_name='d', type=unicode,
91 by Aaron Bentley
Add pump --from-submit.
314
               help='Directory in the pipeline to pump from.'),
315
        Option('from-submit', help="Start from the first pipe's submit"
316
               " branch."),
185 by Aaron Bentley
Make --from work with pipes.
317
        Option('from',
318
               help="Pump start.  May be a pipe or a non-pipe.",
184 by Aaron Bentley
Support pump --from-branch
319
               type=unicode),
189 by Aaron Bentley
Implement pump --reprocess.
320
        Option('show-base', help='Show base revision text in conflicts.'),
190 by Aaron Bentley
Support --merge-type
321
        'reprocess', 'merge-type',
89 by Aaron Bentley
Provide -d option or similar for all commands.
322
    ]
323
188 by Aaron Bentley
bzr pump supports --show-base.
324
    def run(self, directory=None, from_submit=False, show_base=False,
190 by Aaron Bentley
Support --merge-type
325
            reprocess=False, merge_type=None, **kwargs):
188 by Aaron Bentley
bzr pump supports --show-base.
326
        """Run the command.  kwargs are needed to accept --from."""
89 by Aaron Bentley
Provide -d option or similar for all commands.
327
        tree, manager = self._get_checkout_manager(directory)
188 by Aaron Bentley
bzr pump supports --show-base.
328
        unexpected = set(kwargs.keys()).difference(set(['from']))
329
        if len(unexpected) != 0:
330
            raise TypeError("run() got an unexpected keyword argument '%s'" %
331
                            list(unexpected)[0])
185 by Aaron Bentley
Make --from work with pipes.
332
        from_ = kwargs.get('from')
186 by Aaron Bentley
Do pipe handling based on name.
333
        from_branch = None
185 by Aaron Bentley
Make --from work with pipes.
334
        if from_submit or from_:
184 by Aaron Bentley
Support pump --from-branch
335
            first_pipe = manager.get_first_pipe()
336
            manager = PipeManager(first_pipe, tree)
91 by Aaron Bentley
Add pump --from-submit.
337
        if from_submit:
185 by Aaron Bentley
Make --from work with pipes.
338
            from_ = first_pipe.get_submit_branch()
339
        if from_ is not None:
186 by Aaron Bentley
Do pipe handling based on name.
340
            try:
341
                from_pipe = dwim_pipe(manager, from_)
342
                manager = PipeManager(from_pipe, tree)
343
            except NoSuchPipe:
344
                from_branch = Branch.open(from_)
185 by Aaron Bentley
Make --from work with pipes.
345
        else:
346
            from_branch = None
184 by Aaron Bentley
Support pump --from-branch
347
190 by Aaron Bentley
Support --merge-type
348
        merge_config = MergeConfig(merge_type, show_base, reprocess)
188 by Aaron Bentley
bzr pump supports --show-base.
349
        if not manager.pipeline_merge(from_branch, merge_config):
22 by Aaron Bentley
Add pump command.
350
            trace.note('Please resolve conflicts, commit, and re-run pump.')
46 by Aaron Bentley
Implement sync-pipeline command.
351
352
123 by Aaron Bentley
Implement pipe-patches command.
353
class cmd_pipe_patches(PipeCommand):
125 by Aaron Bentley
Add help
354
    """Export the pipeline as a collection of patches, one per pipe.
355
356
    The patch name begins with a sequence number, and ends with the pipe
357
    name.
358
    """
124 by Aaron Bentley
Accept directories for pipe-patches
359
    takes_args = ['patch_location?']
360
    takes_options = [Option('directory', short_name='d', type=unicode,
361
               help='Directory of the pipeline.'),
362
    ]
363
    def run(self, patch_location='.', directory=None):
364
        checkout, manager = self._get_checkout_manager(directory,
365
                                                       checkout_optional=True,
123 by Aaron Bentley
Implement pipe-patches command.
366
                                                       allow_tree=True)
367
        for num, pipe in enumerate(manager.list_pipes()):
368
            pipe.lock_read()
369
            try:
157.1.13 by Aaron Bentley
Make PipeManager take a checkout parameter.
370
                patch = PipeManager(pipe, checkout).get_patch()
123 by Aaron Bentley
Implement pipe-patches command.
371
            finally:
372
                pipe.unlock()
373
            if patch is None:
374
                continue
124 by Aaron Bentley
Accept directories for pipe-patches
375
            filename = pathjoin(patch_location,
376
                                '%.2d-%s.patch' % (num, pipe.nick))
123 by Aaron Bentley
Implement pipe-patches command.
377
            my_file = open(filename, 'wb')
378
            try:
379
                my_file.write(patch)
380
            finally:
381
                my_file.close()
382
383
74 by Aaron Bentley
Unify input handling.
384
class cmd_sync_pipeline(PipeCommand):
53 by Aaron Bentley
Update user doc
385
    """Synchronise the contents of this pipeline with another copy.
386
387
    The first argument is the location of one of the pipes in the remote
388
    pipeline.  It defaults to the push location.  If it does not exist, the
389
    whole remote pipeline will be created.  If any remote pipes are missing,
390
    they will be created.
391
392
    The pipelines are then synchronized by pulling and pushing between
393
    pipes, depending on which is newer.
394
395
    If pipes have diverged, the process will abort.  You should then merge the
396
    remote pipe into the local pipe and re-run sync-pipeline.
397
    """
46 by Aaron Bentley
Implement sync-pipeline command.
398
90 by Aaron Bentley
Clean up variable names.
399
    takes_args = ['location?']
53 by Aaron Bentley
Update user doc
400
90 by Aaron Bentley
Clean up variable names.
401
    def run(self, location=None):
74 by Aaron Bentley
Unify input handling.
402
        checkout, manager = self._get_checkout_manager(checkout_optional=True,
403
                                                       allow_tree=True)
98 by Aaron Bentley
sync-pipeline handles new previous branches with push locations.
404
        remote = None
90 by Aaron Bentley
Clean up variable names.
405
        if location is None:
98 by Aaron Bentley
sync-pipeline handles new previous branches with push locations.
406
            branchless_location = None
90 by Aaron Bentley
Clean up variable names.
407
            for pipe in manager.list_pipes():
408
                location = pipe.get_push_location()
409
                if location is not None:
98 by Aaron Bentley
sync-pipeline handles new previous branches with push locations.
410
                    try:
411
                        remote = Branch.open(location)
412
                    except errors.NotBranchError:
413
                        if branchless_location is None:
414
                            branchless_location = location
415
                        continue
157.1.13 by Aaron Bentley
Make PipeManager take a checkout parameter.
416
                    manager = PipeManager(pipe, checkout)
88 by Aaron Bentley
Make sync-pipeline use closest-to-first push location.
417
                    break
418
            else:
98 by Aaron Bentley
sync-pipeline handles new previous branches with push locations.
419
                if branchless_location is not None:
420
                    location = branchless_location
421
                else:
422
                    raise errors.BzrCommandError(
423
                        'No location specified and none remembered.')
132.1.14 by Aaron Bentley
Clean up output from sync-pipeline.
424
        try:
157.1.14 by Aaron Bentley
Remove tree from sync_pipeline parameters.
425
            manager.sync_pipeline(location, remote)
132.1.14 by Aaron Bentley
Clean up output from sync-pipeline.
426
        finally:
427
            ui.ui_factory.clear_term()