~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/workingtree.py

 * Two new commands 'bzr checkout' and 'bzr update' allow for CVS/SVN-alike
   behaviour. They use the existing serverless-mode and store no data
   locally. As such they are not suitable for use except in high bandwidth
   low latency environments like LAN's or local disk. (Robert Collins)

Show diffs side-by-side

added added

removed removed

Lines of Context:
79
79
                            realpath,
80
80
                            relpath,
81
81
                            rename)
 
82
from bzrlib.revision import NULL_REVISION
82
83
from bzrlib.symbol_versioning import *
83
84
from bzrlib.textui import show_status
84
85
import bzrlib.tree
188
189
    """
189
190
 
190
191
    def __init__(self, basedir='.',
191
 
                 branch=None,
 
192
                 branch=DEPRECATED_PARAMETER,
192
193
                 _inventory=None,
193
194
                 _control_files=None,
194
195
                 _internal=False,
204
205
        self._format = _format
205
206
        self.bzrdir = _bzrdir
206
207
        if not _internal:
207
 
            # created via open etc.
 
208
            # not created via open etc.
 
209
            warn("WorkingTree() is deprecated as of bzr version 0.8. "
 
210
                 "Please use bzrdir.open_workingtree or WorkingTree.open().",
 
211
                 DeprecationWarning,
 
212
                 stacklevel=2)
208
213
            wt = WorkingTree.open(basedir)
209
214
            self.branch = wt.branch
210
215
            self.basedir = wt.basedir
219
224
            "base directory %r is not a string" % basedir
220
225
        basedir = safe_unicode(basedir)
221
226
        mutter("openeing working tree %r", basedir)
222
 
        if branch is None:
223
 
            branch = Branch.open(basedir)
224
 
        assert isinstance(branch, Branch), \
225
 
            "branch %r is not a Branch" % branch
226
 
        self.branch = branch
 
227
        if deprecated_passed(branch):
 
228
            if not _internal:
 
229
                warn("WorkingTree(..., branch=XXX) is deprecated as of bzr 0.8."
 
230
                     " Please use bzrdir.open_workingtree() or WorkingTree.open().",
 
231
                     DeprecationWarning,
 
232
                     stacklevel=2
 
233
                     )
 
234
            self.branch = branch
 
235
        else:
 
236
            self.branch = self.bzrdir.open_branch()
 
237
        assert isinstance(self.branch, Branch), \
 
238
            "branch %r is not a Branch" % self.branch
227
239
        self.basedir = realpath(basedir)
228
240
        # if branch is at our basedir and is a format 6 or less
229
241
        if isinstance(self._format, WorkingTreeFormat2):
779
791
        >>> from bzrlib.bzrdir import ScratchDir
780
792
        >>> d = ScratchDir(files=['foo', 'foo~'])
781
793
        >>> b = d.open_branch()
782
 
        >>> tree = WorkingTree(b.base, b)
 
794
        >>> tree = d.open_workingtree()
783
795
        >>> map(str, tree.unknowns())
784
796
        ['foo']
785
797
        >>> tree.add('foo')
919
931
    def kind(self, file_id):
920
932
        return file_kind(self.id2abspath(file_id))
921
933
 
 
934
    @needs_read_lock
922
935
    def last_revision(self):
923
936
        """Return the last revision id of this working tree.
924
937
 
949
962
    def _basis_inventory_name(self, revision_id):
950
963
        return 'basis-inventory.%s' % revision_id
951
964
 
 
965
    @needs_write_lock
952
966
    def set_last_revision(self, new_revision, old_revision=None):
953
 
        if old_revision is not None:
954
 
            try:
955
 
                path = self._basis_inventory_name(old_revision)
956
 
                path = self._control_files._escape(path)
957
 
                self._control_files._transport.delete(path)
958
 
            except NoSuchFile:
959
 
                pass
 
967
        """Change the last revision in the working tree."""
 
968
        self._remove_old_basis(old_revision)
 
969
        if self._change_last_revision(new_revision):
 
970
            self._cache_basis_inventory(new_revision)
 
971
 
 
972
    def _change_last_revision(self, new_revision):
 
973
        """Template method part of set_last_revision to perform the change."""
960
974
        if new_revision is None:
961
975
            self.branch.set_revision_history([])
962
 
            return
 
976
            return False
963
977
        # current format is locked in with the branch
964
978
        revision_history = self.branch.revision_history()
965
979
        try:
967
981
        except ValueError:
968
982
            raise errors.NoSuchRevision(self.branch, new_revision)
969
983
        self.branch.set_revision_history(revision_history[:position + 1])
 
984
        return True
 
985
 
 
986
    def _cache_basis_inventory(self, new_revision):
 
987
        """Cache new_revision as the basis inventory."""
970
988
        try:
971
989
            xml = self.branch.repository.get_inventory_xml(new_revision)
972
990
            path = self._basis_inventory_name(new_revision)
974
992
        except WeaveRevisionNotPresent:
975
993
            pass
976
994
 
 
995
    def _remove_old_basis(self, old_revision):
 
996
        """Remove the old basis inventory 'old_revision'."""
 
997
        if old_revision is not None:
 
998
            try:
 
999
                path = self._basis_inventory_name(old_revision)
 
1000
                path = self._control_files._escape(path)
 
1001
                self._control_files._transport.delete(path)
 
1002
            except NoSuchFile:
 
1003
                pass
 
1004
 
977
1005
    def read_basis_inventory(self, revision_id):
978
1006
        """Read the cached basis inventory."""
979
1007
        path = self._basis_inventory_name(revision_id)
1111
1139
            return result
1112
1140
 
1113
1141
    @needs_write_lock
 
1142
    def update(self):
 
1143
        self.branch.lock_read()
 
1144
        try:
 
1145
            if self.last_revision() == self.branch.last_revision():
 
1146
                return
 
1147
            basis = self.basis_tree()
 
1148
            to_tree = self.branch.basis_tree()
 
1149
            result = merge_inner(self.branch,
 
1150
                                 to_tree,
 
1151
                                 basis,
 
1152
                                 this_tree=self)
 
1153
            self.set_last_revision(self.branch.last_revision())
 
1154
            return result
 
1155
        finally:
 
1156
            self.branch.unlock()
 
1157
 
 
1158
    @needs_write_lock
1114
1159
    def _write_inventory(self, inv):
1115
1160
        """Write inventory as the current inventory."""
1116
1161
        sio = StringIO()
1119
1164
        self._control_files.put('inventory', sio)
1120
1165
        self._set_inventory(inv)
1121
1166
        mutter('wrote working inventory')
1122
 
            
 
1167
 
 
1168
 
 
1169
class WorkingTree3(WorkingTree):
 
1170
    """This is the Format 3 working tree.
 
1171
 
 
1172
    This differs from the base WorkingTree by:
 
1173
     - having its own file lock
 
1174
     - having its own last-revision property.
 
1175
    """
 
1176
 
 
1177
    @needs_read_lock
 
1178
    def last_revision(self):
 
1179
        """See WorkingTree.last_revision."""
 
1180
        try:
 
1181
            return self._control_files.get_utf8('last-revision').read()
 
1182
        except NoSuchFile:
 
1183
            return None
 
1184
 
 
1185
    def _change_last_revision(self, revision_id):
 
1186
        """See WorkingTree._change_last_revision."""
 
1187
        if revision_id is None or revision_id == NULL_REVISION:
 
1188
            try:
 
1189
                self._control_files._transport.delete('last-revision')
 
1190
            except errors.NoSuchFile:
 
1191
                pass
 
1192
            return False
 
1193
        else:
 
1194
            try:
 
1195
                self.branch.revision_history().index(revision_id)
 
1196
            except ValueError:
 
1197
                raise errors.NoSuchRevision(self.branch, revision_id)
 
1198
            self._control_files.put_utf8('last-revision', revision_id)
 
1199
            return True
 
1200
 
1123
1201
 
1124
1202
CONFLICT_SUFFIXES = ('.THIS', '.BASE', '.OTHER')
1125
1203
def get_conflicted_stem(path):
1173
1251
            format_string = transport.get("format").read()
1174
1252
            return klass._formats[format_string]
1175
1253
        except NoSuchFile:
1176
 
            raise errors.NotBranchError(path=transport.base)
 
1254
            raise errors.NoWorkingTree(base=transport.base)
1177
1255
        except KeyError:
1178
1256
            raise errors.UnknownFormatError(format_string)
1179
1257
 
1216
1294
    This format modified the hash cache from the format 1 hash cache.
1217
1295
    """
1218
1296
 
1219
 
    def initialize(self, a_bzrdir):
 
1297
    def initialize(self, a_bzrdir, revision_id=None):
1220
1298
        """See WorkingTreeFormat.initialize()."""
1221
1299
        if not isinstance(a_bzrdir.transport, LocalTransport):
1222
1300
            raise errors.NotLocalUrl(a_bzrdir.transport.base)
1223
1301
        branch = a_bzrdir.open_branch()
 
1302
        if revision_id is not None:
 
1303
            branch.lock_write()
 
1304
            try:
 
1305
                revision_history = branch.revision_history()
 
1306
                try:
 
1307
                    position = revision_history.index(revision_id)
 
1308
                except ValueError:
 
1309
                    raise errors.NoSuchRevision(branch, revision_id)
 
1310
                branch.set_revision_history(revision_history[:position + 1])
 
1311
            finally:
 
1312
                branch.unlock()
1224
1313
        revision = branch.last_revision()
1225
1314
        basis_tree = branch.repository.revision_tree(revision)
1226
1315
        inv = basis_tree.inventory
1268
1357
        """See WorkingTreeFormat.get_format_string()."""
1269
1358
        return "Bazaar-NG Working Tree format 3"
1270
1359
 
1271
 
    def initialize(self, a_bzrdir):
1272
 
        """See WorkingTreeFormat.initialize()."""
 
1360
    def initialize(self, a_bzrdir, revision_id=None):
 
1361
        """See WorkingTreeFormat.initialize().
 
1362
        
 
1363
        revision_id allows creating a working tree at a differnet
 
1364
        revision than the branch is at.
 
1365
        """
1273
1366
        if not isinstance(a_bzrdir.transport, LocalTransport):
1274
1367
            raise errors.NotLocalUrl(a_bzrdir.transport.base)
1275
1368
        transport = a_bzrdir.get_workingtree_transport(self)
1276
1369
        control_files = LockableFiles(transport, 'lock')
1277
1370
        control_files.put_utf8('format', self.get_format_string())
1278
1371
        branch = a_bzrdir.open_branch()
1279
 
        revision = branch.last_revision()
1280
 
        basis_tree = branch.repository.revision_tree(revision)
1281
 
        inv = basis_tree.inventory
1282
 
        wt = WorkingTree(a_bzrdir.root_transport.base,
 
1372
        if revision_id is None:
 
1373
            revision_id = branch.last_revision()
 
1374
        new_basis_tree = branch.repository.revision_tree(revision_id)
 
1375
        inv = new_basis_tree.inventory
 
1376
        wt = WorkingTree3(a_bzrdir.root_transport.base,
1283
1377
                         branch,
1284
1378
                         inv,
1285
1379
                         _internal=True,
1287
1381
                         _bzrdir=a_bzrdir)
1288
1382
        wt._write_inventory(inv)
1289
1383
        wt.set_root_id(inv.root.file_id)
1290
 
        wt.set_last_revision(revision)
 
1384
        wt.set_last_revision(revision_id)
1291
1385
        wt.set_pending_merges([])
1292
1386
        wt.revert([])
1293
1387
        return wt
1307
1401
            raise NotImplementedError
1308
1402
        if not isinstance(a_bzrdir.transport, LocalTransport):
1309
1403
            raise errors.NotLocalUrl(a_bzrdir.transport.base)
1310
 
        return WorkingTree(a_bzrdir.root_transport.base,
 
1404
        return WorkingTree3(a_bzrdir.root_transport.base,
1311
1405
                           _internal=True,
1312
1406
                           _format=self,
1313
1407
                           _bzrdir=a_bzrdir)