/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/transform.py

  • Committer: Jelmer Vernooij
  • Date: 2009-03-22 00:24:37 UTC
  • mfrom: (4180 +trunk)
  • mto: (3920.2.35 dpush)
  • mto: This revision was merged to the branch mainline in revision 4281.
  • Revision ID: jelmer@samba.org-20090322002437-0vlyqnz29isqeozo
Merge bzr.dev.

Show diffs side-by-side

added added

removed removed

Lines of Context:
36
36
                           ReusingTransform, NotVersionedError, CantMoveRoot,
37
37
                           ExistingLimbo, ImmortalLimbo, NoFinalPath,
38
38
                           UnableCreateSymlink)
 
39
from bzrlib.filters import filtered_output_bytes, ContentFilterContext
39
40
from bzrlib.inventory import InventoryEntry
40
41
from bzrlib.osutils import (
41
42
    delete_any,
121
122
        self._non_present_ids = {}
122
123
        # Mapping of new file_id -> trans_id
123
124
        self._r_new_id = {}
124
 
        # Set of file_ids that will be removed
 
125
        # Set of trans_ids that will be removed
125
126
        self._removed_id = set()
126
127
        # Mapping of path in old tree -> trans_id
127
128
        self._tree_path_ids = {}
233
234
 
234
235
    def adjust_root_path(self, name, parent):
235
236
        """Emulate moving the root by moving all children, instead.
236
 
        
 
237
 
237
238
        We do this by undoing the association of root's transaction id with the
238
239
        current tree.  This allows us to create a new directory with that
239
 
        transaction id.  We unversion the root directory and version the 
 
240
        transaction id.  We unversion the root directory and version the
240
241
        physically new directory, and hope someone versions the tree root
241
242
        later.
242
243
        """
245
246
        # force moving all children of root
246
247
        for child_id in self.iter_tree_children(old_root):
247
248
            if child_id != parent:
248
 
                self.adjust_path(self.final_name(child_id), 
 
249
                self.adjust_path(self.final_name(child_id),
249
250
                                 self.final_parent(child_id), child_id)
250
251
            file_id = self.final_file_id(child_id)
251
252
            if file_id is not None:
252
253
                self.unversion_file(child_id)
253
254
            self.version_file(file_id, child_id)
254
 
        
 
255
 
255
256
        # the physical root needs a new transaction id
256
257
        self._tree_path_ids.pop("")
257
258
        self._tree_id_paths.pop(old_root)
265
266
 
266
267
    def trans_id_tree_file_id(self, inventory_id):
267
268
        """Determine the transaction id of a working tree file.
268
 
        
 
269
 
269
270
        This reflects only files that already exist, not ones that will be
270
271
        added by transactions.
271
272
        """
335
336
        """Schedule creation of a new file.
336
337
 
337
338
        See also new_file.
338
 
        
 
339
 
339
340
        Contents is an iterator of strings, all of which will be written
340
341
        to the target destination.
341
342
 
404
405
 
405
406
    def create_directory(self, trans_id):
406
407
        """Schedule creation of a new directory.
407
 
        
 
408
 
408
409
        See also new_directory.
409
410
        """
410
411
        os.mkdir(self._limbo_name(trans_id))
535
536
 
536
537
    def final_kind(self, trans_id):
537
538
        """Determine the final file kind, after any changes applied.
538
 
        
 
539
 
539
540
        Raises NoSuchFile if the file does not exist/has no contents.
540
541
        (It is conceivable that a path would be created without the
541
542
        corresponding contents insertion command)
561
562
 
562
563
    def final_file_id(self, trans_id):
563
564
        """Determine the file id after any changes are applied, or None.
564
 
        
 
565
 
565
566
        None indicates that the file will not be versioned after changes are
566
567
        applied.
567
568
        """
606
607
 
607
608
    def by_parent(self):
608
609
        """Return a map of parent: children for known parents.
609
 
        
 
610
 
610
611
        Only new paths and parents of tree files with assigned ids are used.
611
612
        """
612
613
        by_parent = {}
613
614
        items = list(self._new_parent.iteritems())
614
 
        items.extend((t, self.final_parent(t)) for t in 
 
615
        items.extend((t, self.final_parent(t)) for t in
615
616
                      self._tree_id_paths.keys())
616
617
        for trans_id, parent_id in items:
617
618
            if parent_id not in by_parent:
652
653
        removed.  This is a necessary first step in detecting conflicts.
653
654
        """
654
655
        parents = self.by_parent().keys()
655
 
        parents.extend([t for t in self._removed_contents if 
 
656
        parents.extend([t for t in self._removed_contents if
656
657
                        self.tree_kind(t) == 'directory'])
657
658
        for trans_id in self._removed_id:
658
659
            file_id = self.tree_file_id(trans_id)
745
746
 
746
747
    def _improper_versioning(self):
747
748
        """Cannot version a file with no contents, or a bad type.
748
 
        
 
749
 
749
750
        However, existing entries with no contents are okay.
750
751
        """
751
752
        conflicts = []
761
762
 
762
763
    def _executability_conflicts(self):
763
764
        """Check for bad executability changes.
764
 
        
 
765
 
765
766
        Only versioned files may have their executability set, because
766
767
        1. only versioned entries can have executability under windows
767
768
        2. only files can be executable.  (The execute bit on a directory
936
937
            self.version_file(file_id, trans_id)
937
938
        return trans_id
938
939
 
939
 
    def new_file(self, name, parent_id, contents, file_id=None, 
 
940
    def new_file(self, name, parent_id, contents, file_id=None,
940
941
                 executable=None):
941
942
        """Convenience method to create files.
942
 
        
 
943
 
943
944
        name is the name of the file to create.
944
945
        parent_id is the transaction id of the parent directory of the file.
945
946
        contents is an iterator of bytestrings, which will be used to produce
965
966
        """
966
967
        trans_id = self._new_entry(name, parent_id, file_id)
967
968
        self.create_directory(trans_id)
968
 
        return trans_id 
 
969
        return trans_id
969
970
 
970
971
    def new_symlink(self, name, parent_id, target, file_id=None):
971
972
        """Convenience method to create symbolic link.
972
 
        
 
973
 
973
974
        name is the name of the symlink to create.
974
975
        parent_id is the transaction id of the parent directory of the symlink.
975
976
        target is a bytestring of the target of the symlink.
1649
1650
    def has_id(self, file_id):
1650
1651
        if file_id in self._transform._r_new_id:
1651
1652
            return True
1652
 
        elif file_id in self._transform._removed_id:
 
1653
        elif file_id in set([self._transform.tree_file_id(trans_id) for
 
1654
            trans_id in self._transform._removed_id]):
1653
1655
            return False
1654
1656
        else:
1655
1657
            return self._transform._tree.has_id(file_id)
1844
1846
                size = None
1845
1847
                executable = None
1846
1848
            if kind == 'symlink':
1847
 
                link_or_sha1 = os.readlink(limbo_name)
 
1849
                link_or_sha1 = os.readlink(limbo_name).decode(osutils._fs_enc)
1848
1850
        if supports_executable():
1849
1851
            executable = tt._new_executability.get(trans_id, executable)
1850
1852
        return kind, size, executable, link_or_sha1
1999
2001
def build_tree(tree, wt, accelerator_tree=None, hardlink=False,
2000
2002
               delta_from_tree=False):
2001
2003
    """Create working tree for a branch, using a TreeTransform.
2002
 
    
 
2004
 
2003
2005
    This function should be used on empty trees, having a tree root at most.
2004
2006
    (see merge and revert functionality for working with existing trees)
2005
2007
 
2006
2008
    Existing files are handled like so:
2007
 
    
 
2009
 
2008
2010
    - Existing bzrdirs take precedence over creating new items.  They are
2009
2011
      created as '%s.diverted' % name.
2010
2012
    - Otherwise, if the content on disk matches the content we are building,
2112
2114
                    executable = tree.is_executable(file_id, tree_path)
2113
2115
                    if executable:
2114
2116
                        tt.set_executability(executable, trans_id)
2115
 
                    deferred_contents.append((file_id, trans_id))
 
2117
                    trans_data = (trans_id, tree_path)
 
2118
                    deferred_contents.append((file_id, trans_data))
2116
2119
                else:
2117
2120
                    file_trans_id[file_id] = new_by_entry(tt, entry, parent_id,
2118
2121
                                                          tree)
2157
2160
                         in iter if not (c or e[0] != e[1]))
2158
2161
        new_desired_files = []
2159
2162
        count = 0
2160
 
        for file_id, trans_id in desired_files:
 
2163
        for file_id, (trans_id, tree_path) in desired_files:
2161
2164
            accelerator_path = unchanged.get(file_id)
2162
2165
            if accelerator_path is None:
2163
 
                new_desired_files.append((file_id, trans_id))
 
2166
                new_desired_files.append((file_id, (trans_id, tree_path)))
2164
2167
                continue
2165
2168
            pb.update('Adding file contents', count + offset, total)
2166
2169
            if hardlink:
2168
2171
                                   trans_id)
2169
2172
            else:
2170
2173
                contents = accelerator_tree.get_file(file_id, accelerator_path)
 
2174
                if tree.supports_content_filtering():
 
2175
                    filters = tree._content_filter_stack(tree_path)
 
2176
                    contents = filtered_output_bytes(contents, filters,
 
2177
                        ContentFilterContext(tree_path, tree))
2171
2178
                try:
2172
2179
                    tt.create_file(contents, trans_id)
2173
2180
                finally:
2174
 
                    contents.close()
 
2181
                    try:
 
2182
                        contents.close()
 
2183
                    except AttributeError:
 
2184
                        # after filtering, contents may no longer be file-like
 
2185
                        pass
2175
2186
            count += 1
2176
2187
        offset += count
2177
 
    for count, (trans_id, contents) in enumerate(tree.iter_files_bytes(
2178
 
                                                 new_desired_files)):
 
2188
    for count, ((trans_id, tree_path), contents) in enumerate(
 
2189
            tree.iter_files_bytes(new_desired_files)):
 
2190
        if tree.supports_content_filtering():
 
2191
            filters = tree._content_filter_stack(tree_path)
 
2192
            contents = filtered_output_bytes(contents, filters,
 
2193
                ContentFilterContext(tree_path, tree))
2179
2194
        tt.create_file(contents, trans_id)
2180
2195
        pb.update('Adding file contents', count + offset, total)
2181
2196
 
2241
2256
    if kind == 'file':
2242
2257
        contents = tree.get_file(entry.file_id).readlines()
2243
2258
        executable = tree.is_executable(entry.file_id)
2244
 
        return tt.new_file(name, parent_id, contents, entry.file_id, 
 
2259
        return tt.new_file(name, parent_id, contents, entry.file_id,
2245
2260
                           executable)
2246
2261
    elif kind in ('directory', 'tree-reference'):
2247
2262
        trans_id = tt.new_directory(name, parent_id, entry.file_id)
2248
2263
        if kind == 'tree-reference':
2249
2264
            tt.set_tree_reference(entry.reference_revision, trans_id)
2250
 
        return trans_id 
 
2265
        return trans_id
2251
2266
    elif kind == 'symlink':
2252
2267
        target = tree.get_symlink_target(entry.file_id)
2253
2268
        return tt.new_symlink(name, parent_id, target, entry.file_id)
2332
2347
        if entry.kind != working_kind:
2333
2348
            contents_mod, meta_mod = True, False
2334
2349
        else:
2335
 
            cur_entry._read_tree_state(working_tree.id2path(file_id), 
 
2350
            cur_entry._read_tree_state(working_tree.id2path(file_id),
2336
2351
                                       working_tree)
2337
2352
            contents_mod, meta_mod = entry.detect_changes(cur_entry)
2338
2353
            cur_entry._forget_tree_state()
2527
2542
                existing_file, new_file = conflict[1], conflict[2]
2528
2543
            new_name = tt.final_name(existing_file)+'.moved'
2529
2544
            tt.adjust_path(new_name, final_parent, existing_file)
2530
 
            new_conflicts.add((c_type, 'Moved existing file to', 
 
2545
            new_conflicts.add((c_type, 'Moved existing file to',
2531
2546
                               existing_file, new_file))
2532
2547
        elif c_type == 'parent loop':
2533
2548
            # break the loop by undoing one of the ops that caused the loop
2537
2552
            new_conflicts.add((c_type, 'Cancelled move', cur,
2538
2553
                               tt.final_parent(cur),))
2539
2554
            tt.adjust_path(tt.final_name(cur), tt.get_tree_parent(cur), cur)
2540
 
            
 
2555
 
2541
2556
        elif c_type == 'missing parent':
2542
2557
            trans_id = conflict[1]
2543
2558
            try:
2544
2559
                tt.cancel_deletion(trans_id)
2545
 
                new_conflicts.add(('deleting parent', 'Not deleting', 
 
2560
                new_conflicts.add(('deleting parent', 'Not deleting',
2546
2561
                                   trans_id))
2547
2562
            except KeyError:
2548
2563
                create = True
2613
2628
        if len(conflict) == 3:
2614
2629
            yield Conflict.factory(c_type, action=action, path=modified_path,
2615
2630
                                     file_id=modified_id)
2616
 
             
 
2631
 
2617
2632
        else:
2618
2633
            conflicting_path = fp.get_path(conflict[3])
2619
2634
            conflicting_id = tt.final_file_id(conflict[3])
2620
2635
            yield Conflict.factory(c_type, action=action, path=modified_path,
2621
 
                                   file_id=modified_id, 
 
2636
                                   file_id=modified_id,
2622
2637
                                   conflict_path=conflicting_path,
2623
2638
                                   conflict_file_id=conflicting_id)
2624
2639