Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
G
git2
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
lvzhengyang
git2
Commits
9d8f97c9
Commit
9d8f97c9
authored
Apr 19, 2013
by
Russell Belfer
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #1479 from arrbee/iterator-for-directory
Add filesystem iterator variant
parents
743048f1
1af80a67
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
452 additions
and
262 deletions
+452
-262
src/branch.c
+1
-1
src/index.c
+1
-1
src/iterator.c
+292
-229
src/iterator.h
+11
-0
src/revparse.c
+1
-1
tests-clar/refdb/inmemory.c
+2
-2
tests-clar/repo/iterator.c
+144
-28
No files found.
src/branch.c
View file @
9d8f97c9
...
...
@@ -377,7 +377,7 @@ int git_branch_remote_name(char *buffer, size_t buffer_len, git_repository *repo
if
(
buffer
)
git_buf_copy_cstr
(
buffer
,
buffer_len
,
&
buf
);
ret
=
git_buf_len
(
&
buf
)
+
1
;
ret
=
(
int
)
git_buf_len
(
&
buf
)
+
1
;
git_buf_free
(
&
buf
);
return
ret
;
...
...
src/index.c
View file @
9d8f97c9
...
...
@@ -1345,7 +1345,7 @@ static size_t read_extension(git_index *index, const char *buffer, size_t buffer
static
int
parse_index
(
git_index
*
index
,
const
char
*
buffer
,
size_t
buffer_size
)
{
unsigned
int
i
;
struct
index_header
header
;
struct
index_header
header
=
{
0
}
;
git_oid
checksum_calculated
,
checksum_expected
;
#define seek_forward(_increase) { \
...
...
src/iterator.c
View file @
9d8f97c9
...
...
@@ -26,8 +26,6 @@
(GIT_ITERATOR_IGNORE_CASE | GIT_ITERATOR_DONT_IGNORE_CASE)
#define ITERATOR_BASE_INIT(P,NAME_LC,NAME_UC,REPO) do { \
(P) = git__calloc(1, sizeof(NAME_LC ## _iterator)); \
GITERR_CHECK_ALLOC(P); \
(P)->base.type = GIT_ITERATOR_TYPE_ ## NAME_UC; \
(P)->base.cb = &(P)->cb; \
ITERATOR_SET_CB(P,NAME_LC); \
...
...
@@ -148,7 +146,8 @@ int git_iterator_for_nothing(
const
char
*
start
,
const
char
*
end
)
{
empty_iterator
*
i
;
empty_iterator
*
i
=
git__calloc
(
1
,
sizeof
(
empty_iterator
));
GITERR_CHECK_ALLOC
(
i
);
#define empty_iterator__current empty_iterator__noop
#define empty_iterator__advance empty_iterator__noop
...
...
@@ -581,6 +580,9 @@ int git_iterator_for_tree(
if
((
error
=
git_object_dup
((
git_object
**
)
&
tree
,
(
git_object
*
)
tree
))
<
0
)
return
error
;
ti
=
git__calloc
(
1
,
sizeof
(
tree_iterator
));
GITERR_CHECK_ALLOC
(
ti
);
ITERATOR_BASE_INIT
(
ti
,
tree
,
TREE
,
git_tree_owner
(
tree
));
if
((
error
=
iterator__update_ignore_case
((
git_iterator
*
)
ti
,
flags
))
<
0
)
...
...
@@ -810,7 +812,8 @@ int git_iterator_for_index(
const
char
*
start
,
const
char
*
end
)
{
index_iterator
*
ii
;
index_iterator
*
ii
=
git__calloc
(
1
,
sizeof
(
index_iterator
));
GITERR_CHECK_ALLOC
(
ii
);
ITERATOR_BASE_INIT
(
ii
,
index
,
INDEX
,
git_index_owner
(
index
));
...
...
@@ -833,237 +836,221 @@ int git_iterator_for_index(
}
#define WORKDIR_MAX_DEPTH 100
typedef
struct
workdir_iterator_frame
workdir_iterator_frame
;
struct
workdir_iterator_frame
{
workdir_iterator_frame
*
next
;
typedef
struct
fs_iterator_frame
fs_iterator_frame
;
struct
fs_iterator_frame
{
fs_iterator_frame
*
next
;
git_vector
entries
;
size_t
index
;
};
typedef
struct
{
typedef
struct
fs_iterator
fs_iterator
;
struct
fs_iterator
{
git_iterator
base
;
git_iterator_callbacks
cb
;
workdir_iterator_frame
*
stack
;
git_ignores
ignores
;
fs_iterator_frame
*
stack
;
git_index_entry
entry
;
git_buf
path
;
size_t
root_len
;
int
is_ignored
;
int
depth
;
}
workdir_iterator
;
GIT_INLINE
(
bool
)
path_is_dotgit
(
const
git_path_with_stat
*
ps
)
{
if
(
!
ps
)
return
false
;
else
{
const
char
*
path
=
ps
->
path
;
size_t
len
=
ps
->
path_len
;
if
(
len
<
4
)
return
false
;
if
(
path
[
len
-
1
]
==
'/'
)
len
--
;
if
(
tolower
(
path
[
len
-
1
])
!=
't'
||
tolower
(
path
[
len
-
2
])
!=
'i'
||
tolower
(
path
[
len
-
3
])
!=
'g'
||
tolower
(
path
[
len
-
4
])
!=
'.'
)
return
false
;
return
(
len
==
4
||
path
[
len
-
5
]
==
'/'
);
}
}
int
(
*
enter_dir_cb
)(
fs_iterator
*
self
);
int
(
*
leave_dir_cb
)(
fs_iterator
*
self
);
int
(
*
update_entry_cb
)(
fs_iterator
*
self
);
};
static
workdir_iterator_frame
*
workdir_iterator__alloc_frame
(
workdir_iterator
*
wi
)
#define FS_MAX_DEPTH 100
static
fs_iterator_frame
*
fs_iterator__alloc_frame
(
fs_iterator
*
fi
)
{
workdir_iterator_frame
*
wf
=
git__calloc
(
1
,
sizeof
(
workdir
_iterator_frame
));
fs_iterator_frame
*
ff
=
git__calloc
(
1
,
sizeof
(
fs
_iterator_frame
));
git_vector_cmp
entry_compare
=
CASESELECT
(
iterator__ignore_case
(
w
i
),
iterator__ignore_case
(
f
i
),
git_path_with_stat_cmp_icase
,
git_path_with_stat_cmp
);
if
(
wf
==
NULL
)
return
NULL
;
if
(
git_vector_init
(
&
wf
->
entries
,
0
,
entry_compare
)
!=
0
)
{
git__free
(
wf
);
return
NULL
;
if
(
ff
&&
git_vector_init
(
&
ff
->
entries
,
0
,
entry_compare
)
<
0
)
{
git__free
(
ff
);
ff
=
NULL
;
}
return
w
f
;
return
f
f
;
}
static
void
workdir_iterator__free_frame
(
workdir_iterator_frame
*
w
f
)
static
void
fs_iterator__free_frame
(
fs_iterator_frame
*
f
f
)
{
unsigned
in
t
i
;
size_
t
i
;
git_path_with_stat
*
path
;
git_vector_foreach
(
&
w
f
->
entries
,
i
,
path
)
git_vector_foreach
(
&
f
f
->
entries
,
i
,
path
)
git__free
(
path
);
git_vector_free
(
&
wf
->
entries
);
git__free
(
wf
);
git_vector_free
(
&
ff
->
entries
);
git__free
(
ff
);
}
static
void
fs_iterator__pop_frame
(
fs_iterator
*
fi
,
fs_iterator_frame
*
ff
,
bool
pop_last
)
{
if
(
fi
&&
fi
->
stack
==
ff
)
{
if
(
!
ff
->
next
&&
!
pop_last
)
{
memset
(
&
fi
->
entry
,
0
,
sizeof
(
fi
->
entry
));
return
;
}
if
(
fi
->
leave_dir_cb
)
(
void
)
fi
->
leave_dir_cb
(
fi
);
fi
->
stack
=
ff
->
next
;
fi
->
depth
--
;
}
fs_iterator__free_frame
(
ff
);
}
static
int
workdir_iterator__update_entry
(
workdir_iterator
*
w
i
);
static
int
fs_iterator__update_entry
(
fs_iterator
*
f
i
);
static
int
workdir
_iterator__entry_cmp
(
const
void
*
i
,
const
void
*
item
)
static
int
fs
_iterator__entry_cmp
(
const
void
*
i
,
const
void
*
item
)
{
const
workdir_iterator
*
wi
=
(
const
workdir
_iterator
*
)
i
;
const
fs_iterator
*
fi
=
(
const
fs
_iterator
*
)
i
;
const
git_path_with_stat
*
ps
=
item
;
return
wi
->
base
.
prefixcomp
(
w
i
->
base
.
start
,
ps
->
path
);
return
fi
->
base
.
prefixcomp
(
f
i
->
base
.
start
,
ps
->
path
);
}
static
void
workdir
_iterator__seek_frame_start
(
workdir_iterator
*
wi
,
workdir_iterator_frame
*
w
f
)
static
void
fs
_iterator__seek_frame_start
(
fs_iterator
*
fi
,
fs_iterator_frame
*
f
f
)
{
if
(
!
w
f
)
if
(
!
f
f
)
return
;
if
(
w
i
->
base
.
start
)
if
(
f
i
->
base
.
start
)
git_vector_bsearch2
(
&
wf
->
index
,
&
wf
->
entries
,
workdir_iterator__entry_cmp
,
w
i
);
&
ff
->
index
,
&
ff
->
entries
,
fs_iterator__entry_cmp
,
f
i
);
else
wf
->
index
=
0
;
if
(
path_is_dotgit
(
git_vector_get
(
&
wf
->
entries
,
wf
->
index
)))
wf
->
index
++
;
ff
->
index
=
0
;
}
static
int
workdir_iterator__expand_dir
(
workdir_iterator
*
w
i
)
static
int
fs_iterator__expand_dir
(
fs_iterator
*
f
i
)
{
int
error
;
workdir_iterator_frame
*
wf
;
fs_iterator_frame
*
ff
;
if
(
fi
->
depth
>
FS_MAX_DEPTH
)
{
giterr_set
(
GITERR_REPOSITORY
,
"Directory nesting is too deep (%d)"
,
fi
->
depth
);
return
-
1
;
}
wf
=
workdir_iterator__alloc_frame
(
w
i
);
GITERR_CHECK_ALLOC
(
w
f
);
ff
=
fs_iterator__alloc_frame
(
f
i
);
GITERR_CHECK_ALLOC
(
f
f
);
error
=
git_path_dirload_with_stat
(
wi
->
path
.
ptr
,
wi
->
root_len
,
iterator__ignore_case
(
w
i
),
wi
->
base
.
start
,
wi
->
base
.
end
,
&
w
f
->
entries
);
fi
->
path
.
ptr
,
fi
->
root_len
,
iterator__ignore_case
(
f
i
),
fi
->
base
.
start
,
fi
->
base
.
end
,
&
f
f
->
entries
);
if
(
error
<
0
||
w
f
->
entries
.
length
==
0
)
{
workdir_iterator__free_frame
(
w
f
);
if
(
error
<
0
||
f
f
->
entries
.
length
==
0
)
{
fs_iterator__free_frame
(
f
f
);
return
GIT_ENOTFOUND
;
}
if
(
++
(
wi
->
depth
)
>
WORKDIR_MAX_DEPTH
)
{
giterr_set
(
GITERR_REPOSITORY
,
"Working directory is too deep (%d)"
,
wi
->
depth
);
workdir_iterator__free_frame
(
wf
);
return
-
1
;
}
workdir_iterator__seek_frame_start
(
wi
,
wf
);
fs_iterator__seek_frame_start
(
fi
,
ff
);
/* only push new ignores if this is not top level directory */
if
(
wi
->
stack
!=
NULL
)
{
ssize_t
slash_pos
=
git_buf_rfind_next
(
&
wi
->
path
,
'/'
);
(
void
)
git_ignore__push_dir
(
&
wi
->
ignores
,
&
wi
->
path
.
ptr
[
slash_pos
+
1
]);
}
ff
->
next
=
fi
->
stack
;
fi
->
stack
=
ff
;
fi
->
depth
++
;
wf
->
next
=
wi
->
stack
;
wi
->
stack
=
wf
;
if
(
fi
->
enter_dir_cb
&&
(
error
=
fi
->
enter_dir_cb
(
fi
))
<
0
)
return
error
;
return
workdir_iterator__update_entry
(
w
i
);
return
fs_iterator__update_entry
(
f
i
);
}
static
int
workdir
_iterator__current
(
static
int
fs
_iterator__current
(
const
git_index_entry
**
entry
,
git_iterator
*
self
)
{
workdir_iterator
*
wi
=
(
workdir
_iterator
*
)
self
;
fs_iterator
*
fi
=
(
fs
_iterator
*
)
self
;
if
(
entry
)
*
entry
=
(
wi
->
entry
.
path
==
NULL
)
?
NULL
:
&
w
i
->
entry
;
*
entry
=
(
fi
->
entry
.
path
==
NULL
)
?
NULL
:
&
f
i
->
entry
;
return
0
;
}
static
int
workdir
_iterator__at_end
(
git_iterator
*
self
)
static
int
fs
_iterator__at_end
(
git_iterator
*
self
)
{
return
(((
workdir
_iterator
*
)
self
)
->
entry
.
path
==
NULL
);
return
(((
fs
_iterator
*
)
self
)
->
entry
.
path
==
NULL
);
}
static
int
workdir
_iterator__advance_into
(
static
int
fs
_iterator__advance_into
(
const
git_index_entry
**
entry
,
git_iterator
*
iter
)
{
int
error
=
0
;
workdir_iterator
*
wi
=
(
workdir
_iterator
*
)
iter
;
fs_iterator
*
fi
=
(
fs
_iterator
*
)
iter
;
iterator__clear_entry
(
entry
);
/* workdir iterator will allow you to explicitly advance into a
* commit/submodule (as well as a tree) to avoid some cases where an
* entry is mislabeled as a submodule in the working directory
/* Allow you to explicitly advance into a commit/submodule (as well as a
* tree) to avoid cases where an entry is mislabeled as a submodule in
* the working directory. The fs iterator will never have COMMMIT
* entries on it's own, but a wrapper might add them.
*/
if
(
w
i
->
entry
.
path
!=
NULL
&&
(
w
i
->
entry
.
mode
==
GIT_FILEMODE_TREE
||
w
i
->
entry
.
mode
==
GIT_FILEMODE_COMMIT
))
if
(
f
i
->
entry
.
path
!=
NULL
&&
(
f
i
->
entry
.
mode
==
GIT_FILEMODE_TREE
||
f
i
->
entry
.
mode
==
GIT_FILEMODE_COMMIT
))
/* returns GIT_ENOTFOUND if the directory is empty */
error
=
workdir_iterator__expand_dir
(
w
i
);
error
=
fs_iterator__expand_dir
(
f
i
);
if
(
!
error
&&
entry
)
error
=
workdir
_iterator__current
(
entry
,
iter
);
error
=
fs
_iterator__current
(
entry
,
iter
);
return
error
;
}
static
int
workdir_iterator__advance
(
static
int
fs_iterator__advance_over
(
const
git_index_entry
**
entry
,
git_iterator
*
self
)
{
int
error
=
0
;
workdir_iterator
*
wi
=
(
workdir
_iterator
*
)
self
;
workdir_iterator_frame
*
w
f
;
fs_iterator
*
fi
=
(
fs
_iterator
*
)
self
;
fs_iterator_frame
*
f
f
;
git_path_with_stat
*
next
;
/* given include_trees & autoexpand, we might have to go into a tree */
if
(
iterator__do_autoexpand
(
wi
)
&&
wi
->
entry
.
path
!=
NULL
&&
wi
->
entry
.
mode
==
GIT_FILEMODE_TREE
)
{
error
=
workdir_iterator__advance_into
(
entry
,
self
);
/* continue silently past empty directories if autoexpanding */
if
(
error
!=
GIT_ENOTFOUND
)
return
error
;
giterr_clear
();
error
=
0
;
}
if
(
entry
!=
NULL
)
*
entry
=
NULL
;
while
(
w
i
->
entry
.
path
!=
NULL
)
{
wf
=
w
i
->
stack
;
next
=
git_vector_get
(
&
wf
->
entries
,
++
w
f
->
index
);
while
(
f
i
->
entry
.
path
!=
NULL
)
{
ff
=
f
i
->
stack
;
next
=
git_vector_get
(
&
ff
->
entries
,
++
f
f
->
index
);
if
(
next
!=
NULL
)
{
/* match git's behavior of ignoring anything named ".git" */
if
(
path_is_dotgit
(
next
))
continue
;
/* else found a good entry */
if
(
next
!=
NULL
)
break
;
}
/* pop stack if anything is left to pop */
if
(
!
wf
->
next
)
{
memset
(
&
wi
->
entry
,
0
,
sizeof
(
wi
->
entry
));
return
0
;
}
wi
->
stack
=
wf
->
next
;
wi
->
depth
--
;
workdir_iterator__free_frame
(
wf
);
git_ignore__pop_dir
(
&
wi
->
ignores
);
fs_iterator__pop_frame
(
fi
,
ff
,
false
);
}
error
=
workdir_iterator__update_entry
(
w
i
);
error
=
fs_iterator__update_entry
(
f
i
);
if
(
!
error
&&
entry
!=
NULL
)
error
=
workdir
_iterator__current
(
entry
,
self
);
error
=
fs
_iterator__current
(
entry
,
self
);
return
error
;
}
static
int
workdir_iterator__seek
(
git_iterator
*
self
,
const
char
*
prefix
)
static
int
fs_iterator__advance
(
const
git_index_entry
**
entry
,
git_iterator
*
self
)
{
fs_iterator
*
fi
=
(
fs_iterator
*
)
self
;
/* given include_trees & autoexpand, we might have to go into a tree */
if
(
iterator__do_autoexpand
(
fi
)
&&
fi
->
entry
.
path
!=
NULL
&&
fi
->
entry
.
mode
==
GIT_FILEMODE_TREE
)
{
int
error
=
fs_iterator__advance_into
(
entry
,
self
);
if
(
error
!=
GIT_ENOTFOUND
)
return
error
;
/* continue silently past empty directories if autoexpanding */
giterr_clear
();
}
return
fs_iterator__advance_over
(
entry
,
self
);
}
static
int
fs_iterator__seek
(
git_iterator
*
self
,
const
char
*
prefix
)
{
GIT_UNUSED
(
self
);
GIT_UNUSED
(
prefix
);
...
...
@@ -1073,107 +1060,192 @@ static int workdir_iterator__seek(git_iterator *self, const char *prefix)
return
0
;
}
static
int
workdir
_iterator__reset
(
static
int
fs
_iterator__reset
(
git_iterator
*
self
,
const
char
*
start
,
const
char
*
end
)
{
workdir_iterator
*
wi
=
(
workdir
_iterator
*
)
self
;
fs_iterator
*
fi
=
(
fs
_iterator
*
)
self
;
while
(
wi
->
stack
!=
NULL
&&
wi
->
stack
->
next
!=
NULL
)
{
workdir_iterator_frame
*
wf
=
wi
->
stack
;
wi
->
stack
=
wf
->
next
;
workdir_iterator__free_frame
(
wf
);
git_ignore__pop_dir
(
&
wi
->
ignores
);
}
wi
->
depth
=
0
;
while
(
fi
->
stack
!=
NULL
&&
fi
->
stack
->
next
!=
NULL
)
fs_iterator__pop_frame
(
fi
,
fi
->
stack
,
false
);
fi
->
depth
=
0
;
if
(
iterator__reset_range
(
self
,
start
,
end
)
<
0
)
return
-
1
;
workdir_iterator__seek_frame_start
(
wi
,
w
i
->
stack
);
fs_iterator__seek_frame_start
(
fi
,
f
i
->
stack
);
return
workdir_iterator__update_entry
(
w
i
);
return
fs_iterator__update_entry
(
f
i
);
}
static
void
workdir
_iterator__free
(
git_iterator
*
self
)
static
void
fs
_iterator__free
(
git_iterator
*
self
)
{
workdir_iterator
*
wi
=
(
workdir
_iterator
*
)
self
;
fs_iterator
*
fi
=
(
fs
_iterator
*
)
self
;
while
(
wi
->
stack
!=
NULL
)
{
workdir_iterator_frame
*
wf
=
wi
->
stack
;
wi
->
stack
=
wf
->
next
;
workdir_iterator__free_frame
(
wf
);
}
while
(
fi
->
stack
!=
NULL
)
fs_iterator__pop_frame
(
fi
,
fi
->
stack
,
true
);
git_ignore__free
(
&
wi
->
ignores
);
git_buf_free
(
&
wi
->
path
);
git_buf_free
(
&
fi
->
path
);
}
static
int
workdir_iterator__update_entry
(
workdir_iterator
*
w
i
)
static
int
fs_iterator__update_entry
(
fs_iterator
*
f
i
)
{
int
error
=
0
;
git_path_with_stat
*
ps
=
git_vector_get
(
&
wi
->
stack
->
entries
,
w
i
->
stack
->
index
);
git_vector_get
(
&
fi
->
stack
->
entries
,
f
i
->
stack
->
index
);
git_buf_truncate
(
&
wi
->
path
,
w
i
->
root_len
);
memset
(
&
wi
->
entry
,
0
,
sizeof
(
w
i
->
entry
));
git_buf_truncate
(
&
fi
->
path
,
f
i
->
root_len
);
memset
(
&
fi
->
entry
,
0
,
sizeof
(
f
i
->
entry
));
if
(
!
ps
)
return
0
;
if
(
git_buf_put
(
&
fi
->
path
,
ps
->
path
,
ps
->
path_len
)
<
0
)
return
-
1
;
if
(
iterator__past_end
(
fi
,
fi
->
path
.
ptr
+
fi
->
root_len
))
return
0
;
/* skip over .git entries */
if
(
path_is_dotgit
(
ps
))
return
workdir_iterator__advance
(
NULL
,
(
git_iterator
*
)
wi
);
fi
->
entry
.
path
=
ps
->
path
;
git_index_entry__init_from_stat
(
&
fi
->
entry
,
&
ps
->
st
);
/* need different mode here to keep directories during iteration */
fi
->
entry
.
mode
=
git_futils_canonical_mode
(
ps
->
st
.
st_mode
);
/* allow wrapper to check/update the entry (can force skip) */
if
(
fi
->
update_entry_cb
&&
fi
->
update_entry_cb
(
fi
)
==
GIT_ENOTFOUND
)
return
fs_iterator__advance_over
(
NULL
,
(
git_iterator
*
)
fi
);
/* if this is a tree and trees aren't included, then skip */
if
(
fi
->
entry
.
mode
==
GIT_FILEMODE_TREE
&&
!
iterator__include_trees
(
fi
))
return
git_iterator_advance
(
NULL
,
(
git_iterator
*
)
fi
);
return
0
;
}
static
int
fs_iterator__initialize
(
git_iterator
**
out
,
fs_iterator
*
fi
,
const
char
*
root
)
{
int
error
;
if
(
git_buf_put
(
&
wi
->
path
,
ps
->
path
,
ps
->
path_len
)
<
0
)
if
(
git_buf_sets
(
&
fi
->
path
,
root
)
<
0
||
git_path_to_dir
(
&
fi
->
path
)
<
0
)
{
git__free
(
fi
);
return
-
1
;
}
fi
->
root_len
=
fi
->
path
.
size
;
if
(
iterator__past_end
(
wi
,
wi
->
path
.
ptr
+
wi
->
root_len
))
return
0
;
if
((
error
=
fs_iterator__expand_dir
(
fi
))
==
GIT_ENOTFOUND
)
{
giterr_clear
();
error
=
0
;
}
if
(
error
)
{
git_iterator_free
((
git_iterator
*
)
fi
);
fi
=
NULL
;
}
wi
->
entry
.
path
=
ps
->
path
;
*
out
=
(
git_iterator
*
)
fi
;
return
error
;
}
wi
->
is_ignored
=
-
1
;
int
git_iterator_for_filesystem
(
git_iterator
**
out
,
const
char
*
root
,
git_iterator_flag_t
flags
,
const
char
*
start
,
const
char
*
end
)
{
fs_iterator
*
fi
=
git__calloc
(
1
,
sizeof
(
fs_iterator
));
GITERR_CHECK_ALLOC
(
fi
);
git_index_entry__init_from_stat
(
&
wi
->
entry
,
&
ps
->
st
);
ITERATOR_BASE_INIT
(
fi
,
fs
,
FS
,
NULL
);
/* need different mode here to keep directories during iteration */
wi
->
entry
.
mode
=
git_futils_canonical_mode
(
ps
->
st
.
st_mode
)
;
if
((
flags
&
GIT_ITERATOR_IGNORE_CASE
)
!=
0
)
fi
->
base
.
flags
|=
GIT_ITERATOR_IGNORE_CASE
;
/* if this is a file type we don't handle, treat as ignored */
if
(
wi
->
entry
.
mode
==
0
)
{
wi
->
is_ignored
=
1
;
return
0
;
return
fs_iterator__initialize
(
out
,
fi
,
root
);
}
typedef
struct
{
fs_iterator
fi
;
git_ignores
ignores
;
int
is_ignored
;
}
workdir_iterator
;
GIT_INLINE
(
bool
)
workdir_path_is_dotgit
(
const
git_buf
*
path
)
{
size_t
len
;
if
(
!
path
||
(
len
=
path
->
size
)
<
4
)
return
false
;
if
(
path
->
ptr
[
len
-
1
]
==
'/'
)
len
--
;
if
(
tolower
(
path
->
ptr
[
len
-
1
])
!=
't'
||
tolower
(
path
->
ptr
[
len
-
2
])
!=
'i'
||
tolower
(
path
->
ptr
[
len
-
3
])
!=
'g'
||
tolower
(
path
->
ptr
[
len
-
4
])
!=
'.'
)
return
false
;
return
(
len
==
4
||
path
->
ptr
[
len
-
5
]
==
'/'
);
}
static
int
workdir_iterator__enter_dir
(
fs_iterator
*
fi
)
{
/* only push new ignores if this is not top level directory */
if
(
fi
->
stack
->
next
!=
NULL
)
{
workdir_iterator
*
wi
=
(
workdir_iterator
*
)
fi
;
ssize_t
slash_pos
=
git_buf_rfind_next
(
&
fi
->
path
,
'/'
);
(
void
)
git_ignore__push_dir
(
&
wi
->
ignores
,
&
fi
->
path
.
ptr
[
slash_pos
+
1
]);
}
/* if this isn't a tree, then we're done */
if
(
wi
->
entry
.
mode
!=
GIT_FILEMODE_TREE
)
return
0
;
return
0
;
}
/* detect submodules */
error
=
git_submodule_lookup
(
NULL
,
wi
->
base
.
repo
,
wi
->
entry
.
path
);
if
(
error
==
GIT_ENOTFOUND
)
giterr_clear
();
static
int
workdir_iterator__leave_dir
(
fs_iterator
*
fi
)
{
workdir_iterator
*
wi
=
(
workdir_iterator
*
)
fi
;
git_ignore__pop_dir
(
&
wi
->
ignores
);
return
0
;
}
if
(
error
==
GIT_EEXISTS
)
/* if contains .git, treat as untracked submod */
error
=
0
;
static
int
workdir_iterator__update_entry
(
fs_iterator
*
fi
)
{
int
error
=
0
;
workdir_iterator
*
wi
=
(
workdir_iterator
*
)
fi
;
/* skip over .git entries */
if
(
workdir_path_is_dotgit
(
&
fi
->
path
))
return
GIT_ENOTFOUND
;
/* reset is_ignored since we haven't checked yet */
wi
->
is_ignored
=
-
1
;
/* if submodule, mark as GITLINK and remove trailing slash */
if
(
!
error
)
{
size_t
len
=
strlen
(
wi
->
entry
.
path
);
assert
(
wi
->
entry
.
path
[
len
-
1
]
==
'/'
);
wi
->
entry
.
path
[
len
-
1
]
=
'\0'
;
wi
->
entry
.
mode
=
S_IFGITLINK
;
/* check if apparent tree entries are actually submodules */
if
(
fi
->
entry
.
mode
!=
GIT_FILEMODE_TREE
)
return
0
;
error
=
git_submodule_lookup
(
NULL
,
fi
->
base
.
repo
,
fi
->
entry
.
path
);
if
(
error
<
0
)
giterr_clear
();
/* mark submodule (or any dir with .git) as GITLINK and remove slash */
if
(
!
error
||
error
==
GIT_EEXISTS
)
{
fi
->
entry
.
mode
=
S_IFGITLINK
;
fi
->
entry
.
path
[
strlen
(
fi
->
entry
.
path
)
-
1
]
=
'\0'
;
}
if
(
iterator__include_trees
(
wi
))
return
0
;
return
0
;
}
return
workdir_iterator__advance
(
NULL
,
(
git_iterator
*
)
wi
);
static
void
workdir_iterator__free
(
git_iterator
*
self
)
{
workdir_iterator
*
wi
=
(
workdir_iterator
*
)
self
;
fs_iterator__free
(
self
);
git_ignore__free
(
&
wi
->
ignores
);
}
int
git_iterator_for_workdir
(
git_iterator
**
iter
,
git_iterator
**
out
,
git_repository
*
repo
,
git_iterator_flag_t
flags
,
const
char
*
start
,
...
...
@@ -1182,38 +1254,28 @@ int git_iterator_for_workdir(
int
error
;
workdir_iterator
*
wi
;
assert
(
iter
&&
repo
);
if
(
git_repository__ensure_not_bare
(
repo
,
"scan working directory"
)
<
0
)
return
GIT_EBAREREPO
;
if
((
error
=
git_repository__ensure_not_bare
(
repo
,
"scan working directory"
))
<
0
)
return
error
;
/* initialize as an fs iterator then do overrides */
wi
=
git__calloc
(
1
,
sizeof
(
workdir_iterator
));
GITERR_CHECK_ALLOC
(
wi
);
ITERATOR_BASE_INIT
((
&
wi
->
fi
),
fs
,
FS
,
repo
);
ITERATOR_BASE_INIT
(
wi
,
workdir
,
WORKDIR
,
repo
);
if
((
error
=
iterator__update_ignore_case
((
git_iterator
*
)
wi
,
flags
))
<
0
)
goto
fail
;
wi
->
fi
.
base
.
type
=
GIT_ITERATOR_TYPE_WORKDIR
;
wi
->
fi
.
cb
.
free
=
workdir_iterator__free
;
wi
->
fi
.
enter_dir_cb
=
workdir_iterator__enter_dir
;
wi
->
fi
.
leave_dir_cb
=
workdir_iterator__leave_dir
;
wi
->
fi
.
update_entry_cb
=
workdir_iterator__update_entry
;
if
(
git_buf_sets
(
&
wi
->
path
,
git_repository_workdir
(
repo
))
<
0
||
git_path_to_dir
(
&
wi
->
path
)
<
0
||
git_ignore__for_path
(
repo
,
""
,
&
wi
->
ignores
)
<
0
)
if
((
error
=
iterator__update_ignore_case
((
git_iterator
*
)
wi
,
flags
))
<
0
||
(
error
=
git_ignore__for_path
(
repo
,
""
,
&
wi
->
ignores
))
<
0
)
{
git__free
(
wi
);
return
-
1
;
}
wi
->
root_len
=
wi
->
path
.
size
;
if
((
error
=
workdir_iterator__expand_dir
(
wi
))
<
0
)
{
if
(
error
!=
GIT_ENOTFOUND
)
goto
fail
;
giterr_clear
();
git_iterator_free
((
git_iterator
*
)
wi
);
return
error
;
}
*
iter
=
(
git_iterator
*
)
wi
;
return
0
;
fail:
git_iterator_free
((
git_iterator
*
)
wi
);
return
error
;
return
fs_iterator__initialize
(
out
,
&
wi
->
fi
,
git_repository_workdir
(
repo
));
}
...
...
@@ -1315,7 +1377,8 @@ bool git_iterator_current_is_ignored(git_iterator *iter)
if
(
wi
->
is_ignored
!=
-
1
)
return
(
bool
)(
wi
->
is_ignored
!=
0
);
if
(
git_ignore__lookup
(
&
wi
->
ignores
,
wi
->
entry
.
path
,
&
wi
->
is_ignored
)
<
0
)
if
(
git_ignore__lookup
(
&
wi
->
ignores
,
wi
->
fi
.
entry
.
path
,
&
wi
->
is_ignored
)
<
0
)
wi
->
is_ignored
=
true
;
return
(
bool
)
wi
->
is_ignored
;
...
...
@@ -1340,10 +1403,10 @@ int git_iterator_current_workdir_path(git_buf **path, git_iterator *iter)
{
workdir_iterator
*
wi
=
(
workdir_iterator
*
)
iter
;
if
(
iter
->
type
!=
GIT_ITERATOR_TYPE_WORKDIR
||
!
wi
->
entry
.
path
)
if
(
iter
->
type
!=
GIT_ITERATOR_TYPE_WORKDIR
||
!
wi
->
fi
.
entry
.
path
)
*
path
=
NULL
;
else
*
path
=
&
wi
->
path
;
*
path
=
&
wi
->
fi
.
path
;
return
0
;
}
src/iterator.h
View file @
9d8f97c9
...
...
@@ -19,6 +19,7 @@ typedef enum {
GIT_ITERATOR_TYPE_TREE
=
1
,
GIT_ITERATOR_TYPE_INDEX
=
2
,
GIT_ITERATOR_TYPE_WORKDIR
=
3
,
GIT_ITERATOR_TYPE_FS
=
4
,
}
git_iterator_type_t
;
typedef
enum
{
...
...
@@ -88,6 +89,16 @@ extern int git_iterator_for_workdir(
const
char
*
start
,
const
char
*
end
);
/* for filesystem iterators, you have to explicitly pass in the ignore_case
* behavior that you desire
*/
extern
int
git_iterator_for_filesystem
(
git_iterator
**
out
,
const
char
*
root
,
git_iterator_flag_t
flags
,
const
char
*
start
,
const
char
*
end
);
extern
void
git_iterator_free
(
git_iterator
*
iter
);
/* Return a git_index_entry structure for the current value the iterator
...
...
src/revparse.c
View file @
9d8f97c9
...
...
@@ -16,7 +16,7 @@
static
int
disambiguate_refname
(
git_reference
**
out
,
git_repository
*
repo
,
const
char
*
refname
)
{
int
error
,
i
;
int
error
=
0
,
i
;
bool
fallbackmode
=
true
;
git_reference
*
ref
;
git_buf
refnamebuf
=
GIT_BUF_INIT
,
name
=
GIT_BUF_INIT
;
...
...
tests-clar/refdb/inmemory.c
View file @
9d8f97c9
...
...
@@ -160,7 +160,7 @@ void test_refdb_inmemory__foreach(void)
cl_git_pass
(
git_reference_create
(
&
write3
,
repo
,
GIT_REFS_HEADS_DIR
"test3"
,
&
oid3
,
0
));
cl_git_pass
(
git_reference_foreach
(
repo
,
GIT_REF_LISTALL
,
foreach_test
,
&
i
));
cl_assert_equal_i
(
i
,
3
);
cl_assert_equal_i
(
3
,
(
int
)
i
);
git_reference_free
(
write1
);
git_reference_free
(
write2
);
...
...
@@ -207,7 +207,7 @@ void test_refdb_inmemory__delete(void)
git_reference_free
(
write3
);
cl_git_pass
(
git_reference_foreach
(
repo
,
GIT_REF_LISTALL
,
delete_test
,
&
i
));
cl_assert_equal_i
(
i
,
1
);
cl_assert_equal_i
(
1
,
(
int
)
i
);
git_reference_free
(
write2
);
}
tests-clar/repo/iterator.c
View file @
9d8f97c9
...
...
@@ -422,7 +422,7 @@ static void build_test_tree(
git_treebuilder
*
builder
;
const
char
*
scan
=
fmt
,
*
next
;
char
type
,
delimiter
;
git_filemode_t
mode
;
git_filemode_t
mode
=
GIT_FILEMODE_BLOB
;
git_buf
name
=
GIT_BUF_INIT
;
va_list
arglist
;
...
...
@@ -755,47 +755,52 @@ void test_repo_iterator__workdir_icase(void)
git_iterator_free
(
i
);
}
void
test_repo_iterator__workdir_depth
(
void
)
static
void
build_workdir_tree
(
const
char
*
root
,
int
dirs
,
int
subs
)
{
int
i
,
j
;
git_iterator
*
iter
;
char
buf
[
64
];
g_repo
=
cl_git_sandbox_init
(
"icase"
);
for
(
i
=
0
;
i
<
10
;
++
i
)
{
p_snprintf
(
buf
,
sizeof
(
buf
),
"icase/dir%02d"
,
i
);
cl_git_pass
(
git_futils_mkdir
(
buf
,
NULL
,
0775
,
GIT_MKDIR_PATH
));
char
buf
[
64
],
sub
[
64
];
for
(
i
=
0
;
i
<
dirs
;
++
i
)
{
if
(
i
%
2
==
0
)
{
p_snprintf
(
buf
,
sizeof
(
buf
),
"icase/dir%02d/file"
,
i
);
p_snprintf
(
buf
,
sizeof
(
buf
),
"%s/dir%02d"
,
root
,
i
);
cl_git_pass
(
git_futils_mkdir
(
buf
,
NULL
,
0775
,
GIT_MKDIR_PATH
));
p_snprintf
(
buf
,
sizeof
(
buf
),
"%s/dir%02d/file"
,
root
,
i
);
cl_git_mkfile
(
buf
,
buf
);
buf
[
strlen
(
buf
)
-
5
]
=
'\0'
;
}
else
{
p_snprintf
(
buf
,
sizeof
(
buf
),
"%s/DIR%02d"
,
root
,
i
);
cl_git_pass
(
git_futils_mkdir
(
buf
,
NULL
,
0775
,
GIT_MKDIR_PATH
));
}
for
(
j
=
0
;
j
<
10
;
++
j
)
{
p_snprintf
(
buf
,
sizeof
(
buf
),
"icase/dir%02d/sub%02d"
,
i
,
j
);
cl_git_pass
(
git_futils_mkdir
(
buf
,
NULL
,
0775
,
GIT_MKDIR_PATH
));
for
(
j
=
0
;
j
<
subs
;
++
j
)
{
switch
(
j
%
4
)
{
case
0
:
p_snprintf
(
sub
,
sizeof
(
sub
),
"%s/sub%02d"
,
buf
,
j
);
break
;
case
1
:
p_snprintf
(
sub
,
sizeof
(
sub
),
"%s/sUB%02d"
,
buf
,
j
);
break
;
case
2
:
p_snprintf
(
sub
,
sizeof
(
sub
),
"%s/Sub%02d"
,
buf
,
j
);
break
;
case
3
:
p_snprintf
(
sub
,
sizeof
(
sub
),
"%s/SUB%02d"
,
buf
,
j
);
break
;
}
cl_git_pass
(
git_futils_mkdir
(
sub
,
NULL
,
0775
,
GIT_MKDIR_PATH
));
if
(
j
%
2
==
0
)
{
p_snprintf
(
buf
,
sizeof
(
buf
),
"icase/dir%02d/sub%02d/file"
,
i
,
j
);
cl_git_mkfile
(
buf
,
buf
);
size_t
sublen
=
strlen
(
sub
);
memcpy
(
&
sub
[
sublen
],
"/file"
,
sizeof
(
"/file"
));
cl_git_mkfile
(
sub
,
sub
);
sub
[
sublen
]
=
'\0'
;
}
}
}
}
for
(
i
=
1
;
i
<
3
;
++
i
)
{
for
(
j
=
0
;
j
<
50
;
++
j
)
{
p_snprintf
(
buf
,
sizeof
(
buf
),
"icase/dir%02d/sub01/moar%02d"
,
i
,
j
);
cl_git_pass
(
git_futils_mkdir
(
buf
,
NULL
,
0775
,
GIT_MKDIR_PATH
));
void
test_repo_iterator__workdir_depth
(
void
)
{
git_iterator
*
iter
;
if
(
j
%
2
==
0
)
{
p_snprintf
(
buf
,
sizeof
(
buf
),
"icase/dir%02d/sub01/moar%02d/file"
,
i
,
j
);
cl_git_mkfile
(
buf
,
buf
);
}
}
}
g_repo
=
cl_git_sandbox_init
(
"icase"
);
build_workdir_tree
(
"icase"
,
10
,
10
);
build_workdir_tree
(
"icase/DIR01/sUB01"
,
50
,
0
);
build_workdir_tree
(
"icase/dir02/sUB01"
,
50
,
0
);
/* auto expand with no tree entries */
cl_git_pass
(
git_iterator_for_workdir
(
&
iter
,
g_repo
,
0
,
NULL
,
NULL
));
...
...
@@ -808,3 +813,114 @@ void test_repo_iterator__workdir_depth(void)
expect_iterator_items
(
iter
,
337
,
NULL
,
337
,
NULL
);
git_iterator_free
(
iter
);
}
void
test_repo_iterator__fs
(
void
)
{
git_iterator
*
i
;
static
const
char
*
expect_base
[]
=
{
"DIR01/Sub02/file"
,
"DIR01/sub00/file"
,
"current_file"
,
"dir00/Sub02/file"
,
"dir00/file"
,
"dir00/sub00/file"
,
"modified_file"
,
"new_file"
,
NULL
,
};
static
const
char
*
expect_trees
[]
=
{
"DIR01/"
,
"DIR01/SUB03/"
,
"DIR01/Sub02/"
,
"DIR01/Sub02/file"
,
"DIR01/sUB01/"
,
"DIR01/sub00/"
,
"DIR01/sub00/file"
,
"current_file"
,
"dir00/"
,
"dir00/SUB03/"
,
"dir00/Sub02/"
,
"dir00/Sub02/file"
,
"dir00/file"
,
"dir00/sUB01/"
,
"dir00/sub00/"
,
"dir00/sub00/file"
,
"modified_file"
,
"new_file"
,
NULL
,
};
static
const
char
*
expect_noauto
[]
=
{
"DIR01/"
,
"current_file"
,
"dir00/"
,
"modified_file"
,
"new_file"
,
NULL
,
};
g_repo
=
cl_git_sandbox_init
(
"status"
);
build_workdir_tree
(
"status/subdir"
,
2
,
4
);
cl_git_pass
(
git_iterator_for_filesystem
(
&
i
,
"status/subdir"
,
0
,
NULL
,
NULL
));
expect_iterator_items
(
i
,
8
,
expect_base
,
8
,
expect_base
);
git_iterator_free
(
i
);
cl_git_pass
(
git_iterator_for_filesystem
(
&
i
,
"status/subdir"
,
GIT_ITERATOR_INCLUDE_TREES
,
NULL
,
NULL
));
expect_iterator_items
(
i
,
18
,
expect_trees
,
18
,
expect_trees
);
git_iterator_free
(
i
);
cl_git_pass
(
git_iterator_for_filesystem
(
&
i
,
"status/subdir"
,
GIT_ITERATOR_DONT_AUTOEXPAND
,
NULL
,
NULL
));
expect_iterator_items
(
i
,
5
,
expect_noauto
,
18
,
expect_trees
);
git_iterator_free
(
i
);
git__tsort
((
void
**
)
expect_base
,
8
,
(
git__tsort_cmp
)
git__strcasecmp
);
git__tsort
((
void
**
)
expect_trees
,
18
,
(
git__tsort_cmp
)
git__strcasecmp
);
git__tsort
((
void
**
)
expect_noauto
,
5
,
(
git__tsort_cmp
)
git__strcasecmp
);
cl_git_pass
(
git_iterator_for_filesystem
(
&
i
,
"status/subdir"
,
GIT_ITERATOR_IGNORE_CASE
,
NULL
,
NULL
));
expect_iterator_items
(
i
,
8
,
expect_base
,
8
,
expect_base
);
git_iterator_free
(
i
);
cl_git_pass
(
git_iterator_for_filesystem
(
&
i
,
"status/subdir"
,
GIT_ITERATOR_IGNORE_CASE
|
GIT_ITERATOR_INCLUDE_TREES
,
NULL
,
NULL
));
expect_iterator_items
(
i
,
18
,
expect_trees
,
18
,
expect_trees
);
git_iterator_free
(
i
);
cl_git_pass
(
git_iterator_for_filesystem
(
&
i
,
"status/subdir"
,
GIT_ITERATOR_IGNORE_CASE
|
GIT_ITERATOR_DONT_AUTOEXPAND
,
NULL
,
NULL
));
expect_iterator_items
(
i
,
5
,
expect_noauto
,
18
,
expect_trees
);
git_iterator_free
(
i
);
}
void
test_repo_iterator__fs2
(
void
)
{
git_iterator
*
i
;
static
const
char
*
expect_base
[]
=
{
"heads/br2"
,
"heads/dir"
,
"heads/master"
,
"heads/packed-test"
,
"heads/subtrees"
,
"heads/test"
,
"tags/e90810b"
,
"tags/foo/bar"
,
"tags/foo/foo/bar"
,
"tags/point_to_blob"
,
"tags/test"
,
NULL
,
};
g_repo
=
cl_git_sandbox_init
(
"testrepo"
);
cl_git_pass
(
git_iterator_for_filesystem
(
&
i
,
"testrepo/.git/refs"
,
0
,
NULL
,
NULL
));
expect_iterator_items
(
i
,
11
,
expect_base
,
11
,
expect_base
);
git_iterator_free
(
i
);
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment