14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20
from osutils import quotefn, appendpath
21
from errors import bailout
22
from trace import mutter, note
24
def smart_add(file_list, verbose=False, recurse=True):
25
"""Add files to version, optionall recursing into directories.
27
This is designed more towards DWIM for humans than API simplicity.
28
For the specific behaviour see the help for cmd_add().
31
assert not isinstance(file_list, basestring)
32
b = bzrlib.branch.Branch(file_list[0], find_root=True)
33
inv = b.read_working_inventory()
34
tree = b.working_tree()
18
from os.path import dirname
20
import bzrlib.errors as errors
21
from bzrlib.inventory import InventoryEntry
22
from bzrlib.trace import mutter, note, warning
23
from bzrlib.errors import NotBranchError
24
from bzrlib.workingtree import is_control_file
26
from bzrlib.workingtree import WorkingTree
28
def glob_expand_for_win32(file_list):
32
expanded_file_list = []
33
for possible_glob in file_list:
34
glob_files = glob.glob(possible_glob)
37
# special case to let the normal code path handle
38
# files that do not exists
39
expanded_file_list.append(possible_glob)
41
expanded_file_list += glob_files
42
return expanded_file_list
45
def _prepare_file_list(file_list):
46
"""Prepare a file list for use by smart_add_*."""
47
if sys.platform == 'win32':
48
file_list = glob_expand_for_win32(file_list)
51
file_list = list(file_list)
55
class AddAction(object):
56
"""A class which defines what action to take when adding a file."""
61
def __init__(self, to_file=None, should_add=None, should_print=None):
62
self._to_file = to_file
64
self._to_file = sys.stdout
65
if should_add is not None:
66
self.should_add = should_add
67
if should_print is not None:
68
self.should_print = should_print
70
def __call__(self, inv, path, kind):
71
"""Add path to inventory.
73
The default action does nothing.
75
:param inv: The inventory we are working with.
76
:param path: The path being added
77
:param kind: The kind of the object being added.
80
self._add_to_inv(inv, path, kind)
82
self._print(inv, path, kind)
84
def _print(self, inv, path, kind):
85
self._to_file.write('added ')
86
self._to_file.write(bzrlib.osutils.quotefn(path))
87
self._to_file.write('\n')
89
def _add_to_inv(self, inv, path, kind):
90
entry = inv.add_path(path, kind=kind)
91
mutter("added %r kind %r file_id={%s}", path, kind, entry.file_id)
94
# TODO: jam 20050105 These could be used for compatibility
95
# however, they bind against the current stdout, not the
96
# one which exists at the time they are called, so they
97
# don't work for the test suite.
99
add_action_null = AddAction()
100
add_action_add = AddAction(should_add=True)
101
add_action_print = AddAction(should_print=True)
102
add_action_add_and_print = AddAction(should_add=True, should_print=True)
105
def smart_add(file_list, recurse=True, action=None):
106
"""Add files to version, optionally recursing into directories.
108
This is designed more towards DWIM for humans than API simplicity.
109
For the specific behaviour see the help for cmd_add().
111
Returns the number of files added.
114
file_list = _prepare_file_list(file_list)
115
tree = WorkingTree.open_containing(file_list[0])[0]
116
return smart_add_tree(tree, file_list, recurse, action=action)
119
def smart_add_tree(tree, file_list, recurse=True, action=None):
120
"""Add files to version, optionally recursing into directories.
122
This is designed more towards DWIM for humans than API simplicity.
123
For the specific behaviour see the help for cmd_add().
125
This calls reporter with each (path, kind, file_id) of added files.
127
Returns the number of files added.
130
from bzrlib.errors import BadFileKindError, ForbiddenFileError
131
assert isinstance(recurse, bool)
133
action = AddAction(should_add=True)
135
file_list = _prepare_file_list(file_list)
136
user_list = file_list[:]
137
inv = tree.read_working_inventory()
37
141
for f in file_list:
41
## TODO: It's OK to add root but only in recursive mode
43
bzrlib.mutter("smart add of %r" % f)
143
af = tree.abspath(rf)
146
kind = bzrlib.osutils.file_kind(af)
148
if hasattr(e, 'errno') and e.errno == errno.ENOENT:
149
raise errors.NoSuchFile(rf)
152
if not InventoryEntry.versionable_kind(kind):
154
raise BadFileKindError("cannot add %s of type %s" % (f, kind))
156
warning("skipping %s (can't add file of kind '%s')", f, kind)
159
mutter("smart add of %r, abs=%r", f, af)
45
if bzrlib.branch.is_control_file(af):
46
bailout("cannot add control file %r" % af)
48
kind = bzrlib.osutils.file_kind(f)
50
if kind != 'file' and kind != 'directory':
51
bailout("can't add file of kind %r" % kind)
161
if tree.is_control_filename(af):
162
raise ForbiddenFileError('cannot add control file %s' % f)
53
164
versioned = (inv.path2id(rf) != None)
166
if kind == 'directory':
168
sub_branch = WorkingTree.open(af)
170
except NotBranchError:
172
except errors.UnsupportedFormatError:
56
mutter("branch root doesn't need to be added")
178
mutter("tree root doesn't need to be added")
58
mutter("%r is already versioned" % f)
181
mutter("%r is already versioned", f)
183
mutter("%r is a bzr tree", f)
60
file_id = bzrlib.branch.gen_file_id(rf)
61
inv.add_path(rf, kind=kind, file_id=file_id)
62
bzrlib.mutter("added %r kind %r file_id={%s}" % (rf, kind, file_id))
65
bzrlib.textui.show_status('A', kind, quotefn(f))
185
added.extend(__add_one(tree, inv, rf, kind, action))
67
if kind == 'directory' and recurse:
187
if kind == 'directory' and recurse and not sub_tree:
68
188
for subf in os.listdir(af):
69
subp = appendpath(rf, subf)
70
if subf == bzrlib.BZRDIR:
71
mutter("skip control directory %r" % subp)
72
elif tree.is_ignored(subp):
73
mutter("skip ignored sub-file %r" % subp)
189
subp = bzrlib.osutils.pathjoin(rf, subf)
190
if tree.is_control_filename(subp):
191
mutter("skip control directory %r", subp)
75
mutter("queue to add sub-file %r" % (subp))
76
file_list.append(subp)
80
note('added %d' % count)
81
b._write_inventory(inv)
193
ignore_glob = tree.is_ignored(subp)
194
if ignore_glob is not None:
195
mutter("skip ignored sub-file %r", subp)
196
if ignore_glob not in ignored:
197
ignored[ignore_glob] = []
198
ignored[ignore_glob].append(subp)
200
mutter("queue to add sub-file %r", subp)
201
file_list.append(tree.abspath(subp))
204
mutter('added %d entries', len(added))
207
tree._write_inventory(inv)
209
return added, ignored
212
def __add_one(tree, inv, path, kind, action):
213
"""Add a file or directory, automatically add unversioned parents."""
215
# Nothing to do if path is already versioned.
216
# This is safe from infinite recursion because the tree root is
218
if inv.path2id(path) != None:
222
added = __add_one(tree, inv, dirname(path), 'directory', action)
223
action(inv, path, kind)
225
return added + [path]