Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitf96ee74

Browse files
committed
index: added move method including test
test.helpers: temporary rw repository creators now set the working dir of the program, easing working with relative paths a lot
1 parent76fd1d4 commitf96ee74

File tree

3 files changed

+132
-13
lines changed

3 files changed

+132
-13
lines changed

‎lib/git/index.py

Lines changed: 88 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -986,6 +986,20 @@ def add(self, items, force=True, fprogress=lambda *args: None):
986986

987987
returnentries_added
988988

989+
def_items_to_rela_paths(self,items):
990+
"""Returns a list of repo-relative paths from the given items which
991+
may be absolute or relative paths, entries or blobs"""
992+
paths=list()
993+
foriteminitems:
994+
ifisinstance(item, (BaseIndexEntry,Blob)):
995+
paths.append(self._to_relative_path(item.path))
996+
elifisinstance(item,basestring):
997+
paths.append(self._to_relative_path(item))
998+
else:
999+
raiseTypeError("Invalid item type: %r"%item)
1000+
# END for each item
1001+
returnpaths
1002+
9891003
@clear_cache
9901004
@default_index
9911005
defremove(self,items,working_tree=False,**kwargs):
@@ -1021,7 +1035,8 @@ def remove(self, items, working_tree=False, **kwargs):
10211035
as 'r' to allow recurive removal of
10221036
10231037
Returns
1024-
List(path_string, ...) list of paths that have been removed effectively.
1038+
List(path_string, ...) list of repository relative paths that have
1039+
been removed effectively.
10251040
This is interesting to know in case you have provided a directory or
10261041
globs. Paths are relative to the repository.
10271042
"""
@@ -1031,22 +1046,84 @@ def remove(self, items, working_tree=False, **kwargs):
10311046
args.append("--")
10321047

10331048
# preprocess paths
1034-
paths=list()
1035-
foriteminitems:
1036-
ifisinstance(item, (BaseIndexEntry,Blob)):
1037-
paths.append(self._to_relative_path(item.path))
1038-
elifisinstance(item,basestring):
1039-
paths.append(self._to_relative_path(item))
1040-
else:
1041-
raiseTypeError("Invalid item type: %r"%item)
1042-
# END for each item
1043-
1049+
paths=self._items_to_rela_paths(items)
10441050
removed_paths=self.repo.git.rm(args,paths,**kwargs).splitlines()
10451051

10461052
# process output to gain proper paths
10471053
# rm 'path'
10481054
return [p[4:-1]forpinremoved_paths ]
1055+
1056+
@clear_cache
1057+
@default_index
1058+
defmove(self,items,skip_errors=False,**kwargs):
1059+
"""
1060+
Rename/move the items, whereas the last item is considered the destination of
1061+
the move operation. If the destination is a file, the first item ( of two )
1062+
must be a file as well. If the destination is a directory, it may be preceeded
1063+
by one or more directories or files.
1064+
1065+
The working tree will be affected in non-bare repositories.
1066+
1067+
``items``
1068+
Multiple types of items are supported, please see the 'remove' method
1069+
for reference.
1070+
``skip_errors``
1071+
If True, errors such as ones resulting from missing source files will
1072+
be skpped.
1073+
``**kwargs``
1074+
Additional arguments you would like to pass to git-mv, such as dry_run
1075+
or force.
1076+
1077+
Returns
1078+
List(tuple(source_path_string, destination_path_string), ...)
1079+
A list of pairs, containing the source file moved as well as its
1080+
actual destination. Relative to the repository root.
1081+
1082+
Raises
1083+
ValueErorr: If only one item was given
1084+
GitCommandError: If git could not handle your request
1085+
"""
1086+
args=list()
1087+
ifskip_errors:
1088+
args.append('-k')
1089+
1090+
paths=self._items_to_rela_paths(items)
1091+
iflen(paths)<2:
1092+
raiseValueError("Please provide at least one source and one destination of the move operation")
1093+
1094+
was_dry_run=kwargs.pop('dry_run',kwargs.pop('n',None))
1095+
kwargs['dry_run']=True
1096+
1097+
# first execute rename in dryrun so the command tells us what it actually does
1098+
# ( for later output )
1099+
out=list()
1100+
mvlines=self.repo.git.mv(args,paths,**kwargs).splitlines()
1101+
1102+
# parse result - first 0:n/2 lines are 'checking ', the remaining ones
1103+
# are the 'renaming' ones which we parse
1104+
forlninxrange(len(mvlines)/2,len(mvlines)):
1105+
tokens=mvlines[ln].split(' to ')
1106+
assertlen(tokens)==2,"Too many tokens in %s"%mvlines[ln]
1107+
1108+
# [0] = Renaming x
1109+
# [1] = y
1110+
out.append((tokens[0][9:],tokens[1]))
1111+
# END for each line to parse
1112+
1113+
# either prepare for the real run, or output the dry-run result
1114+
ifwas_dry_run:
1115+
returnout
1116+
# END handle dryrun
10491117

1118+
1119+
# now apply the actual operation
1120+
kwargs.pop('dry_run')
1121+
self.repo.git.mv(args,paths,**kwargs)
1122+
1123+
returnout
1124+
1125+
1126+
10501127
@default_index
10511128
defcommit(self,message,parent_commits=None,head=True):
10521129
"""

‎test/git/test_index.py

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,10 @@
1414
importshutil
1515
fromstatimport*
1616

17-
classTestTree(TestBase):
17+
classTestIndex(TestBase):
1818

1919
def__init__(self,*args):
20-
super(TestTree,self).__init__(*args)
20+
super(TestIndex,self).__init__(*args)
2121
self._reset_progress()
2222

2323
def_assert_fprogress(self,entries):
@@ -498,3 +498,32 @@ def mixed_iterator():
498498
open(fake_symlink_path,'rb').read()==link_target
499499
else:
500500
assertS_ISLNK(os.lstat(fake_symlink_path)[ST_MODE])
501+
502+
# TEST RENAMING
503+
defassert_mv_rval(rval):
504+
forsource,destinrval:
505+
assertnotos.path.exists(source)andos.path.exists(dest)
506+
# END for each renamed item
507+
# END move assertion utility
508+
509+
self.failUnlessRaises(ValueError,index.move, ['just_one_path'])
510+
# file onto existing file
511+
files= ['AUTHORS','LICENSE']
512+
self.failUnlessRaises(GitCommandError,index.move,files)
513+
514+
# again, with force
515+
assert_mv_rval(index.move(files,force=True))
516+
517+
# files into directory - dry run
518+
paths= ['LICENSE','VERSION','doc']
519+
rval=index.move(paths,dry_run=True)
520+
assertlen(rval)==2
521+
assertos.path.exists(paths[0])
522+
523+
# again, no dry run
524+
rval=index.move(paths)
525+
assert_mv_rval(rval)
526+
527+
# dir into dir
528+
rval=index.move(['doc','test'])
529+
assert_mv_rval(rval)

‎test/testlib/helper.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ def case(self, rw_repo)
9090
defbare_repo_creator(self):
9191
repo_dir=tempfile.mktemp("bare_repo")
9292
rw_repo=self.rorepo.clone(repo_dir,shared=True,bare=True)
93+
prev_cwd=os.getcwd()
9394
try:
9495
returnfunc(self,rw_repo)
9596
finally:
@@ -106,6 +107,9 @@ def with_rw_repo(working_tree_ref):
106107
out the working tree at the given working_tree_ref.
107108
108109
This repository type is more costly due to the working copy checkout.
110+
111+
To make working with relative paths easier, the cwd will be set to the working
112+
dir of the repository.
109113
"""
110114
assertisinstance(working_tree_ref,basestring),"Decorator requires ref name for working tree checkout"
111115
defargument_passer(func):
@@ -116,9 +120,12 @@ def repo_creator(self):
116120
rw_repo.head.commit=working_tree_ref
117121
rw_repo.head.reference.checkout()
118122

123+
prev_cwd=os.getcwd()
124+
os.chdir(rw_repo.working_dir)
119125
try:
120126
returnfunc(self,rw_repo)
121127
finally:
128+
os.chdir(prev_cwd)
122129
rw_repo.git.clear_cache()
123130
shutil.rmtree(repo_dir,onerror=_rmtree_onerror)
124131
# END cleanup
@@ -148,6 +155,8 @@ def with_rw_and_rw_remote_repo(working_tree_ref):
148155
def case(self, rw_repo, rw_remote_repo)
149156
150157
This setup allows you to test push and pull scenarios and hooks nicely.
158+
159+
See working dir info in with_rw_repo
151160
"""
152161
assertisinstance(working_tree_ref,basestring),"Decorator requires ref name for working tree checkout"
153162
defargument_passer(func):
@@ -192,9 +201,13 @@ def remote_repo_creator(self):
192201
else:
193202
raiseAssertionError('Please start a git-daemon to run this test, execute: git-daemon "%s"'%tempfile.gettempdir())
194203

204+
# adjust working dir
205+
prev_cwd=os.getcwd()
206+
os.chdir(rw_repo.working_dir)
195207
try:
196208
returnfunc(self,rw_repo,rw_remote_repo)
197209
finally:
210+
os.chdir(prev_cwd)
198211
rw_repo.git.clear_cache()
199212
rw_remote_repo.git.clear_cache()
200213
shutil.rmtree(repo_dir,onerror=_rmtree_onerror)

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp