rugged 0.1.2 → 0.16.0b1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (277) hide show
  1. data/README.md +25 -36
  2. data/Rakefile +20 -98
  3. data/ext/rugged/extconf.rb +44 -4
  4. data/ext/rugged/remote.c +215 -0
  5. data/ext/rugged/rugged.c +171 -0
  6. data/ext/rugged/rugged.h +126 -0
  7. data/ext/rugged/rugged_blob.c +99 -0
  8. data/ext/rugged/rugged_commit.c +224 -0
  9. data/ext/rugged/rugged_config.c +238 -0
  10. data/ext/rugged/rugged_index.c +440 -0
  11. data/ext/rugged/rugged_object.c +203 -0
  12. data/ext/rugged/rugged_reference.c +401 -0
  13. data/ext/rugged/rugged_repo.c +482 -0
  14. data/ext/rugged/rugged_revwalk.c +138 -0
  15. data/ext/rugged/rugged_signature.c +80 -0
  16. data/ext/rugged/rugged_tag.c +216 -0
  17. data/ext/rugged/rugged_tree.c +322 -0
  18. data/ext/rugged/vendor/libgit2-dist.tar.gz +0 -0
  19. data/ext/rugged/vendor/libgit2-dist/deps/http-parser/http_parser.c +1778 -0
  20. data/ext/rugged/vendor/libgit2-dist/deps/http-parser/http_parser.h +267 -0
  21. data/ext/rugged/vendor/libgit2-dist/deps/zlib/adler32.c +169 -0
  22. data/ext/rugged/vendor/libgit2-dist/deps/zlib/crc32.c +442 -0
  23. data/ext/rugged/vendor/libgit2-dist/deps/zlib/crc32.h +441 -0
  24. data/ext/rugged/vendor/libgit2-dist/deps/zlib/deflate.c +1834 -0
  25. data/ext/rugged/vendor/libgit2-dist/deps/zlib/deflate.h +342 -0
  26. data/ext/rugged/vendor/libgit2-dist/deps/zlib/inffast.c +340 -0
  27. data/ext/rugged/vendor/libgit2-dist/deps/zlib/inffast.h +11 -0
  28. data/ext/rugged/vendor/libgit2-dist/deps/zlib/inffixed.h +94 -0
  29. data/ext/rugged/vendor/libgit2-dist/deps/zlib/inflate.c +1480 -0
  30. data/ext/rugged/vendor/libgit2-dist/deps/zlib/inflate.h +122 -0
  31. data/ext/rugged/vendor/libgit2-dist/deps/zlib/inftrees.c +330 -0
  32. data/ext/rugged/vendor/libgit2-dist/deps/zlib/inftrees.h +62 -0
  33. data/ext/rugged/vendor/libgit2-dist/deps/zlib/trees.c +1244 -0
  34. data/ext/rugged/vendor/libgit2-dist/deps/zlib/trees.h +128 -0
  35. data/ext/rugged/vendor/libgit2-dist/deps/zlib/zconf.h +54 -0
  36. data/ext/rugged/vendor/libgit2-dist/deps/zlib/zlib.h +1613 -0
  37. data/ext/rugged/vendor/libgit2-dist/deps/zlib/zutil.c +318 -0
  38. data/ext/rugged/vendor/libgit2-dist/deps/zlib/zutil.h +274 -0
  39. data/ext/rugged/vendor/libgit2-dist/examples/general.c +451 -0
  40. data/ext/rugged/vendor/libgit2-dist/examples/network/common.h +14 -0
  41. data/ext/rugged/vendor/libgit2-dist/examples/network/fetch.c +97 -0
  42. data/ext/rugged/vendor/libgit2-dist/examples/network/git2.c +58 -0
  43. data/ext/rugged/vendor/libgit2-dist/examples/network/index-pack.c +47 -0
  44. data/ext/rugged/vendor/libgit2-dist/examples/network/ls-remote.c +76 -0
  45. data/ext/rugged/vendor/libgit2-dist/examples/showindex.c +43 -0
  46. data/ext/rugged/vendor/libgit2-dist/include/git2.h +44 -0
  47. data/ext/rugged/vendor/libgit2-dist/include/git2/blob.h +120 -0
  48. data/ext/rugged/vendor/libgit2-dist/include/git2/branch.h +15 -0
  49. data/ext/rugged/vendor/libgit2-dist/include/git2/commit.h +263 -0
  50. data/ext/rugged/vendor/libgit2-dist/include/git2/common.h +103 -0
  51. data/ext/rugged/vendor/libgit2-dist/include/git2/config.h +278 -0
  52. data/ext/rugged/vendor/libgit2-dist/include/git2/errors.h +144 -0
  53. data/ext/rugged/vendor/libgit2-dist/include/git2/index.h +306 -0
  54. data/ext/rugged/vendor/libgit2-dist/include/git2/indexer.h +76 -0
  55. data/ext/rugged/vendor/libgit2-dist/include/git2/inttypes.h +305 -0
  56. data/ext/rugged/vendor/libgit2-dist/include/git2/net.h +51 -0
  57. data/ext/rugged/vendor/libgit2-dist/include/git2/object.h +173 -0
  58. data/ext/rugged/vendor/libgit2-dist/include/git2/odb.h +331 -0
  59. data/ext/rugged/vendor/libgit2-dist/include/git2/odb_backend.h +100 -0
  60. data/ext/rugged/vendor/libgit2-dist/include/git2/oid.h +218 -0
  61. data/ext/rugged/vendor/libgit2-dist/include/git2/reflog.h +128 -0
  62. data/ext/rugged/vendor/libgit2-dist/include/git2/refs.h +309 -0
  63. data/ext/rugged/vendor/libgit2-dist/include/git2/refspec.h +60 -0
  64. data/ext/rugged/vendor/libgit2-dist/include/git2/remote.h +176 -0
  65. data/ext/rugged/vendor/libgit2-dist/include/git2/repository.h +290 -0
  66. data/ext/rugged/vendor/libgit2-dist/include/git2/revwalk.h +169 -0
  67. data/ext/rugged/vendor/libgit2-dist/include/git2/signature.h +65 -0
  68. data/ext/rugged/vendor/libgit2-dist/include/git2/status.h +63 -0
  69. data/ext/rugged/vendor/libgit2-dist/include/git2/stdint.h +247 -0
  70. data/ext/rugged/vendor/libgit2-dist/include/git2/tag.h +279 -0
  71. data/ext/rugged/vendor/libgit2-dist/include/git2/threads.h +48 -0
  72. data/ext/rugged/vendor/libgit2-dist/include/git2/tree.h +318 -0
  73. data/ext/rugged/vendor/libgit2-dist/include/git2/types.h +169 -0
  74. data/ext/rugged/vendor/libgit2-dist/include/git2/version.h +15 -0
  75. data/ext/rugged/vendor/libgit2-dist/include/git2/windows.h +59 -0
  76. data/ext/rugged/vendor/libgit2-dist/include/git2/zlib.h +40 -0
  77. data/ext/rugged/vendor/libgit2-dist/src/blob.c +135 -0
  78. data/ext/rugged/vendor/libgit2-dist/src/blob.h +23 -0
  79. data/ext/rugged/vendor/libgit2-dist/src/bswap.h +97 -0
  80. data/ext/rugged/vendor/libgit2-dist/src/buffer.c +113 -0
  81. data/ext/rugged/vendor/libgit2-dist/src/buffer.h +32 -0
  82. data/ext/rugged/vendor/libgit2-dist/src/cache.c +111 -0
  83. data/ext/rugged/vendor/libgit2-dist/src/cache.h +64 -0
  84. data/ext/rugged/vendor/libgit2-dist/src/cc-compat.h +67 -0
  85. data/ext/rugged/vendor/libgit2-dist/src/commit.c +299 -0
  86. data/ext/rugged/vendor/libgit2-dist/src/commit.h +34 -0
  87. data/ext/rugged/vendor/libgit2-dist/src/common.h +64 -0
  88. data/ext/rugged/vendor/libgit2-dist/src/config.c +418 -0
  89. data/ext/rugged/vendor/libgit2-dist/src/config.h +24 -0
  90. data/ext/rugged/vendor/libgit2-dist/src/config_file.c +1210 -0
  91. data/ext/rugged/vendor/libgit2-dist/src/delta-apply.c +115 -0
  92. data/ext/rugged/vendor/libgit2-dist/src/delta-apply.h +33 -0
  93. data/ext/rugged/vendor/libgit2-dist/src/dir.h +47 -0
  94. data/ext/rugged/vendor/libgit2-dist/src/errors.c +104 -0
  95. data/ext/rugged/vendor/libgit2-dist/src/fetch.c +172 -0
  96. data/ext/rugged/vendor/libgit2-dist/src/fetch.h +18 -0
  97. data/ext/rugged/vendor/libgit2-dist/src/filebuf.c +400 -0
  98. data/ext/rugged/vendor/libgit2-dist/src/filebuf.h +72 -0
  99. data/ext/rugged/vendor/libgit2-dist/src/fileops.c +358 -0
  100. data/ext/rugged/vendor/libgit2-dist/src/fileops.h +151 -0
  101. data/ext/rugged/vendor/libgit2-dist/src/global.c +134 -0
  102. data/ext/rugged/vendor/libgit2-dist/src/global.h +24 -0
  103. data/ext/rugged/vendor/libgit2-dist/src/hash.c +74 -0
  104. data/ext/rugged/vendor/libgit2-dist/src/hash.h +29 -0
  105. data/ext/rugged/vendor/libgit2-dist/src/hashtable.c +243 -0
  106. data/ext/rugged/vendor/libgit2-dist/src/hashtable.h +80 -0
  107. data/ext/rugged/vendor/libgit2-dist/src/index.c +918 -0
  108. data/ext/rugged/vendor/libgit2-dist/src/index.h +34 -0
  109. data/ext/rugged/vendor/libgit2-dist/src/indexer.c +401 -0
  110. data/ext/rugged/vendor/libgit2-dist/src/map.h +37 -0
  111. data/ext/rugged/vendor/libgit2-dist/src/mwindow.c +272 -0
  112. data/ext/rugged/vendor/libgit2-dist/src/mwindow.h +45 -0
  113. data/ext/rugged/vendor/libgit2-dist/src/netops.c +198 -0
  114. data/ext/rugged/vendor/libgit2-dist/src/netops.h +36 -0
  115. data/ext/rugged/vendor/libgit2-dist/src/object.c +295 -0
  116. data/ext/rugged/vendor/libgit2-dist/src/odb.c +672 -0
  117. data/ext/rugged/vendor/libgit2-dist/src/odb.h +43 -0
  118. data/ext/rugged/vendor/libgit2-dist/src/odb_loose.c +855 -0
  119. data/ext/rugged/vendor/libgit2-dist/src/odb_pack.c +485 -0
  120. data/ext/rugged/vendor/libgit2-dist/src/oid.c +388 -0
  121. data/ext/rugged/vendor/libgit2-dist/src/pack.c +788 -0
  122. data/ext/rugged/vendor/libgit2-dist/src/pack.h +99 -0
  123. data/ext/rugged/vendor/libgit2-dist/src/path.c +270 -0
  124. data/ext/rugged/vendor/libgit2-dist/src/path.h +84 -0
  125. data/ext/rugged/vendor/libgit2-dist/src/pkt.c +426 -0
  126. data/ext/rugged/vendor/libgit2-dist/src/pkt.h +77 -0
  127. data/ext/rugged/vendor/libgit2-dist/src/posix.c +94 -0
  128. data/ext/rugged/vendor/libgit2-dist/src/posix.h +69 -0
  129. data/ext/rugged/vendor/libgit2-dist/src/ppc/sha1.c +70 -0
  130. data/ext/rugged/vendor/libgit2-dist/src/ppc/sha1.h +26 -0
  131. data/ext/rugged/vendor/libgit2-dist/src/pqueue.c +141 -0
  132. data/ext/rugged/vendor/libgit2-dist/src/pqueue.h +81 -0
  133. data/ext/rugged/vendor/libgit2-dist/src/protocol.c +50 -0
  134. data/ext/rugged/vendor/libgit2-dist/src/protocol.h +23 -0
  135. data/ext/rugged/vendor/libgit2-dist/src/reflog.c +318 -0
  136. data/ext/rugged/vendor/libgit2-dist/src/reflog.h +34 -0
  137. data/ext/rugged/vendor/libgit2-dist/src/refs.c +1693 -0
  138. data/ext/rugged/vendor/libgit2-dist/src/refs.h +58 -0
  139. data/ext/rugged/vendor/libgit2-dist/src/refspec.c +95 -0
  140. data/ext/rugged/vendor/libgit2-dist/src/refspec.h +23 -0
  141. data/ext/rugged/vendor/libgit2-dist/src/remote.c +339 -0
  142. data/ext/rugged/vendor/libgit2-dist/src/remote.h +25 -0
  143. data/ext/rugged/vendor/libgit2-dist/src/repository.c +849 -0
  144. data/ext/rugged/vendor/libgit2-dist/src/repository.h +60 -0
  145. data/ext/rugged/vendor/libgit2-dist/src/revwalk.c +569 -0
  146. data/ext/rugged/vendor/libgit2-dist/src/sha1.c +280 -0
  147. data/ext/rugged/vendor/libgit2-dist/src/sha1.h +21 -0
  148. data/ext/rugged/vendor/libgit2-dist/src/sha1_lookup.c +177 -0
  149. data/ext/rugged/vendor/libgit2-dist/src/sha1_lookup.h +18 -0
  150. data/ext/rugged/vendor/libgit2-dist/src/signature.c +335 -0
  151. data/ext/rugged/vendor/libgit2-dist/src/signature.h +18 -0
  152. data/ext/rugged/vendor/libgit2-dist/src/status.c +696 -0
  153. data/ext/rugged/vendor/libgit2-dist/src/tag.c +446 -0
  154. data/ext/rugged/vendor/libgit2-dist/src/tag.h +28 -0
  155. data/ext/rugged/vendor/libgit2-dist/src/thread-utils.c +55 -0
  156. data/ext/rugged/vendor/libgit2-dist/src/thread-utils.h +108 -0
  157. data/ext/rugged/vendor/libgit2-dist/src/transport.c +85 -0
  158. data/ext/rugged/vendor/libgit2-dist/src/transport.h +110 -0
  159. data/ext/rugged/vendor/libgit2-dist/src/transports/git.c +502 -0
  160. data/ext/rugged/vendor/libgit2-dist/src/transports/http.c +756 -0
  161. data/ext/rugged/vendor/libgit2-dist/src/transports/local.c +235 -0
  162. data/ext/rugged/vendor/libgit2-dist/src/tree-cache.c +201 -0
  163. data/ext/rugged/vendor/libgit2-dist/src/tree-cache.h +31 -0
  164. data/ext/rugged/vendor/libgit2-dist/src/tree.c +758 -0
  165. data/ext/rugged/vendor/libgit2-dist/src/tree.h +37 -0
  166. data/ext/rugged/vendor/libgit2-dist/src/tsort.c +365 -0
  167. data/ext/rugged/vendor/libgit2-dist/src/unix/map.c +70 -0
  168. data/ext/rugged/vendor/libgit2-dist/src/unix/posix.h +25 -0
  169. data/ext/rugged/vendor/libgit2-dist/src/util.c +381 -0
  170. data/ext/rugged/vendor/libgit2-dist/src/util.h +137 -0
  171. data/ext/rugged/vendor/libgit2-dist/src/vector.c +174 -0
  172. data/ext/rugged/vendor/libgit2-dist/src/vector.h +45 -0
  173. data/ext/rugged/vendor/libgit2-dist/src/win32/dir.c +115 -0
  174. data/ext/rugged/vendor/libgit2-dist/src/win32/fnmatch.c +180 -0
  175. data/ext/rugged/vendor/libgit2-dist/src/win32/fnmatch.h +27 -0
  176. data/ext/rugged/vendor/libgit2-dist/src/win32/map.c +131 -0
  177. data/ext/rugged/vendor/libgit2-dist/src/win32/mingw-compat.h +24 -0
  178. data/ext/rugged/vendor/libgit2-dist/src/win32/msvc-compat.h +38 -0
  179. data/ext/rugged/vendor/libgit2-dist/src/win32/posix.h +53 -0
  180. data/ext/rugged/vendor/libgit2-dist/src/win32/posix_w32.c +404 -0
  181. data/ext/rugged/vendor/libgit2-dist/src/win32/pthread.c +65 -0
  182. data/ext/rugged/vendor/libgit2-dist/src/win32/pthread.h +40 -0
  183. data/ext/rugged/vendor/libgit2-dist/src/win32/utf-conv.c +88 -0
  184. data/ext/rugged/vendor/libgit2-dist/src/win32/utf-conv.h +17 -0
  185. data/ext/rugged/vendor/libgit2-dist/tests-clay/buf/basic.c +29 -0
  186. data/ext/rugged/vendor/libgit2-dist/tests-clay/clay.h +187 -0
  187. data/ext/rugged/vendor/libgit2-dist/tests-clay/clay_libgit2.h +28 -0
  188. data/ext/rugged/vendor/libgit2-dist/tests-clay/clay_main.c +1073 -0
  189. data/ext/rugged/vendor/libgit2-dist/tests-clay/config/add.c +37 -0
  190. data/ext/rugged/vendor/libgit2-dist/tests-clay/config/new.c +36 -0
  191. data/ext/rugged/vendor/libgit2-dist/tests-clay/config/read.c +209 -0
  192. data/ext/rugged/vendor/libgit2-dist/tests-clay/config/stress.c +39 -0
  193. data/ext/rugged/vendor/libgit2-dist/tests-clay/config/write.c +77 -0
  194. data/ext/rugged/vendor/libgit2-dist/tests-clay/core/dirent.c +222 -0
  195. data/ext/rugged/vendor/libgit2-dist/tests-clay/core/filebuf.c +106 -0
  196. data/ext/rugged/vendor/libgit2-dist/tests-clay/core/oid.c +18 -0
  197. data/ext/rugged/vendor/libgit2-dist/tests-clay/core/path.c +139 -0
  198. data/ext/rugged/vendor/libgit2-dist/tests-clay/core/rmdir.c +50 -0
  199. data/ext/rugged/vendor/libgit2-dist/tests-clay/core/string.c +28 -0
  200. data/ext/rugged/vendor/libgit2-dist/tests-clay/core/strtol.c +37 -0
  201. data/ext/rugged/vendor/libgit2-dist/tests-clay/core/vector.c +66 -0
  202. data/ext/rugged/vendor/libgit2-dist/tests-clay/index/rename.c +60 -0
  203. data/ext/rugged/vendor/libgit2-dist/tests-clay/network/remotes.c +50 -0
  204. data/ext/rugged/vendor/libgit2-dist/tests-clay/object/raw/chars.c +52 -0
  205. data/ext/rugged/vendor/libgit2-dist/tests-clay/object/raw/compare.c +124 -0
  206. data/ext/rugged/vendor/libgit2-dist/tests-clay/object/raw/convert.c +75 -0
  207. data/ext/rugged/vendor/libgit2-dist/tests-clay/object/raw/data.h +323 -0
  208. data/ext/rugged/vendor/libgit2-dist/tests-clay/object/raw/fromstr.c +30 -0
  209. data/ext/rugged/vendor/libgit2-dist/tests-clay/object/raw/hash.c +162 -0
  210. data/ext/rugged/vendor/libgit2-dist/tests-clay/object/raw/short.c +94 -0
  211. data/ext/rugged/vendor/libgit2-dist/tests-clay/object/raw/size.c +13 -0
  212. data/ext/rugged/vendor/libgit2-dist/tests-clay/object/raw/type2string.c +54 -0
  213. data/ext/rugged/vendor/libgit2-dist/tests-clay/object/tree/frompath.c +75 -0
  214. data/ext/rugged/vendor/libgit2-dist/tests-clay/odb/loose.c +84 -0
  215. data/ext/rugged/vendor/libgit2-dist/tests-clay/odb/loose_data.h +522 -0
  216. data/ext/rugged/vendor/libgit2-dist/tests-clay/odb/pack_data.h +151 -0
  217. data/ext/rugged/vendor/libgit2-dist/tests-clay/odb/packed.c +78 -0
  218. data/ext/rugged/vendor/libgit2-dist/tests-clay/odb/sorting.c +71 -0
  219. data/ext/rugged/vendor/libgit2-dist/tests-clay/repo/getters.c +68 -0
  220. data/ext/rugged/vendor/libgit2-dist/tests-clay/repo/init.c +104 -0
  221. data/ext/rugged/vendor/libgit2-dist/tests-clay/repo/open.c +54 -0
  222. data/ext/rugged/vendor/libgit2-dist/tests-clay/status/single.c +38 -0
  223. data/ext/rugged/vendor/libgit2-dist/tests-clay/status/status_data.h +48 -0
  224. data/ext/rugged/vendor/libgit2-dist/tests-clay/status/worktree.c +124 -0
  225. data/ext/rugged/vendor/libgit2-dist/tests/t00-core.c +628 -0
  226. data/ext/rugged/vendor/libgit2-dist/tests/t01-data.h +322 -0
  227. data/ext/rugged/vendor/libgit2-dist/tests/t01-rawobj.c +638 -0
  228. data/ext/rugged/vendor/libgit2-dist/tests/t03-data.h +344 -0
  229. data/ext/rugged/vendor/libgit2-dist/tests/t03-objwrite.c +255 -0
  230. data/ext/rugged/vendor/libgit2-dist/tests/t04-commit.c +788 -0
  231. data/ext/rugged/vendor/libgit2-dist/tests/t05-revwalk.c +140 -0
  232. data/ext/rugged/vendor/libgit2-dist/tests/t06-index.c +219 -0
  233. data/ext/rugged/vendor/libgit2-dist/tests/t07-hashtable.c +192 -0
  234. data/ext/rugged/vendor/libgit2-dist/tests/t08-tag.c +357 -0
  235. data/ext/rugged/vendor/libgit2-dist/tests/t09-tree.c +221 -0
  236. data/ext/rugged/vendor/libgit2-dist/tests/t10-refs.c +1294 -0
  237. data/ext/rugged/vendor/libgit2-dist/tests/t12-repo.c +174 -0
  238. data/ext/rugged/vendor/libgit2-dist/tests/t13-threads.c +41 -0
  239. data/ext/rugged/vendor/libgit2-dist/tests/t17-bufs.c +61 -0
  240. data/ext/rugged/vendor/libgit2-dist/tests/t18-status.c +448 -0
  241. data/ext/rugged/vendor/libgit2-dist/tests/test_helpers.c +310 -0
  242. data/ext/rugged/vendor/libgit2-dist/tests/test_helpers.h +83 -0
  243. data/ext/rugged/vendor/libgit2-dist/tests/test_lib.c +198 -0
  244. data/ext/rugged/vendor/libgit2-dist/tests/test_lib.h +54 -0
  245. data/ext/rugged/vendor/libgit2-dist/tests/test_main.c +89 -0
  246. data/lib/rugged.rb +4 -3
  247. data/lib/rugged/index.rb +0 -8
  248. data/lib/rugged/objects.rb +45 -0
  249. data/lib/rugged/repository.rb +29 -0
  250. data/lib/rugged/tree.rb +16 -6
  251. data/lib/rugged/version.rb +1 -1
  252. data/lib/rugged/walker.rb +5 -0
  253. data/test/blob_test.rb +18 -14
  254. data/test/commit_test.rb +28 -26
  255. data/test/coverage/HEAD.json +1 -0
  256. data/test/coverage/cover.rb +106 -0
  257. data/test/fixtures/testrepo.git/refs/heads/new_name +1 -0
  258. data/test/index_test.rb +101 -78
  259. data/test/lib_test.rb +4 -4
  260. data/test/object_test.rb +3 -3
  261. data/test/reference_test.rb +75 -0
  262. data/test/remote_test.rb +19 -0
  263. data/test/repo_pack_test.rb +4 -4
  264. data/test/repo_test.rb +44 -15
  265. data/test/tag_test.rb +7 -17
  266. data/test/test_helper.rb +24 -5
  267. data/test/tree_test.rb +30 -12
  268. data/test/walker_test.rb +40 -31
  269. metadata +273 -50
  270. data/lib/rugged/person.rb +0 -20
  271. data/lib/rugged/tree_entry.rb +0 -9
  272. data/test/fixtures/testrepo.git/objects/1d/83f106355e4309a293e42ad2a2c4b8bdbe77ae +0 -0
  273. data/test/fixtures/testrepo.git/objects/2f/3321418db5b2a841375b8b70880a8ab5a4148f +0 -0
  274. data/test/fixtures/testrepo.git/objects/36/9b00a7700cca3a506d79e301d6ad8bf735d9ee +0 -3
  275. data/test/fixtures/testrepo.git/objects/3d/b1b5ceace59ff65279757003763046fd4cbbe6 +0 -0
  276. data/test/fixtures/testrepo.git/objects/4c/d1604907792e2c43e03dcec1216f99d63e68c4 +0 -3
  277. data/test/fixtures/testrepo.git/objects/e0/f46d77041c149296549b01ed4a18b02c4b7400 +0 -0
@@ -0,0 +1,18 @@
1
+ /*
2
+ * Copyright (C) 2009-2011 the libgit2 contributors
3
+ *
4
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
5
+ * a Linking Exception. For full terms see the included COPYING file.
6
+ */
7
+ #ifndef INCLUDE_sha1_lookup_h__
8
+ #define INCLUDE_sha1_lookup_h__
9
+
10
+ #include <stdlib.h>
11
+
12
+ int sha1_entry_pos(const void *table,
13
+ size_t elem_size,
14
+ size_t key_offset,
15
+ unsigned lo, unsigned hi, unsigned nr,
16
+ const unsigned char *key);
17
+
18
+ #endif
@@ -0,0 +1,335 @@
1
+ /*
2
+ * Copyright (C) 2009-2011 the libgit2 contributors
3
+ *
4
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
5
+ * a Linking Exception. For full terms see the included COPYING file.
6
+ */
7
+
8
+ #include "common.h"
9
+ #include "signature.h"
10
+ #include "repository.h"
11
+ #include "git2/common.h"
12
+
13
+ void git_signature_free(git_signature *sig)
14
+ {
15
+ if (sig == NULL)
16
+ return;
17
+
18
+ git__free(sig->name);
19
+ git__free(sig->email);
20
+ git__free(sig);
21
+ }
22
+
23
+ static const char *skip_leading_spaces(const char *buffer, const char *buffer_end)
24
+ {
25
+ while (*buffer == ' ' && buffer < buffer_end)
26
+ buffer++;
27
+
28
+ return buffer;
29
+ }
30
+
31
+ static const char *skip_trailing_spaces(const char *buffer_start, const char *buffer_end)
32
+ {
33
+ while (*buffer_end == ' ' && buffer_end > buffer_start)
34
+ buffer_end--;
35
+
36
+ return buffer_end;
37
+ }
38
+
39
+ static int process_trimming(const char *input, char **storage, const char *input_end, int fail_when_empty)
40
+ {
41
+ const char *left, *right;
42
+ int trimmed_input_length;
43
+
44
+ left = skip_leading_spaces(input, input_end);
45
+ right = skip_trailing_spaces(input, input_end - 1);
46
+
47
+ if (right < left) {
48
+ if (fail_when_empty)
49
+ return git__throw(GIT_EINVALIDARGS, "Failed to trim. Input is either empty or only contains spaces");
50
+ else
51
+ right = left - 1;
52
+ }
53
+
54
+ trimmed_input_length = right - left + 1;
55
+
56
+ *storage = git__malloc(trimmed_input_length + 1);
57
+ if (*storage == NULL)
58
+ return GIT_ENOMEM;
59
+
60
+ memcpy(*storage, left, trimmed_input_length);
61
+ (*storage)[trimmed_input_length] = 0;
62
+
63
+ return GIT_SUCCESS;
64
+ }
65
+
66
+ int git_signature_new(git_signature **sig_out, const char *name, const char *email, git_time_t time, int offset)
67
+ {
68
+ int error;
69
+ git_signature *p = NULL;
70
+
71
+ assert(name && email);
72
+
73
+ *sig_out = NULL;
74
+
75
+ if ((p = git__malloc(sizeof(git_signature))) == NULL) {
76
+ error = GIT_ENOMEM;
77
+ goto cleanup;
78
+ }
79
+
80
+ memset(p, 0x0, sizeof(git_signature));
81
+
82
+ error = process_trimming(name, &p->name, name + strlen(name), 1);
83
+ if (error < GIT_SUCCESS) {
84
+ git__rethrow(GIT_EINVALIDARGS, "Failed to create signature. 'name' argument is invalid");
85
+ goto cleanup;
86
+ }
87
+
88
+ error = process_trimming(email, &p->email, email + strlen(email), 1);
89
+ if (error < GIT_SUCCESS) {
90
+ git__rethrow(GIT_EINVALIDARGS, "Failed to create signature. 'email' argument is invalid");
91
+ goto cleanup;
92
+ }
93
+
94
+ p->when.time = time;
95
+ p->when.offset = offset;
96
+
97
+ *sig_out = p;
98
+
99
+ return error;
100
+
101
+ cleanup:
102
+ git_signature_free(p);
103
+ return error;
104
+ }
105
+
106
+ git_signature *git_signature_dup(const git_signature *sig)
107
+ {
108
+ git_signature *new;
109
+ if (git_signature_new(&new, sig->name, sig->email, sig->when.time, sig->when.offset) < GIT_SUCCESS)
110
+ return NULL;
111
+ return new;
112
+ }
113
+
114
+ int git_signature_now(git_signature **sig_out, const char *name, const char *email)
115
+ {
116
+ int error;
117
+ time_t now;
118
+ time_t offset;
119
+ struct tm *utc_tm, *local_tm;
120
+ git_signature *sig;
121
+
122
+ #ifndef GIT_WIN32
123
+ struct tm _utc, _local;
124
+ #endif
125
+
126
+ *sig_out = NULL;
127
+
128
+ time(&now);
129
+
130
+ /**
131
+ * On Win32, `gmtime_r` doesn't exist but
132
+ * `gmtime` is threadsafe, so we can use that
133
+ */
134
+ #ifdef GIT_WIN32
135
+ utc_tm = gmtime(&now);
136
+ local_tm = localtime(&now);
137
+ #else
138
+ utc_tm = gmtime_r(&now, &_utc);
139
+ local_tm = localtime_r(&now, &_local);
140
+ #endif
141
+
142
+ offset = mktime(local_tm) - mktime(utc_tm);
143
+ offset /= 60;
144
+
145
+ /* mktime takes care of setting tm_isdst correctly */
146
+ if (local_tm->tm_isdst)
147
+ offset += 60;
148
+
149
+ if ((error = git_signature_new(&sig, name, email, now, (int)offset)) < GIT_SUCCESS)
150
+ return error;
151
+
152
+ *sig_out = sig;
153
+
154
+ return error;
155
+ }
156
+
157
+ static int parse_timezone_offset(const char *buffer, int *offset_out)
158
+ {
159
+ int dec_offset;
160
+ int mins, hours, offset;
161
+
162
+ const char *offset_start;
163
+ const char *offset_end;
164
+
165
+ offset_start = buffer;
166
+
167
+ if (*offset_start == '\n') {
168
+ *offset_out = 0;
169
+ return GIT_SUCCESS;
170
+ }
171
+
172
+ if (offset_start[0] != '-' && offset_start[0] != '+')
173
+ return git__throw(GIT_EOBJCORRUPTED, "Failed to parse TZ offset. It doesn't start with '+' or '-'");
174
+
175
+ if (offset_start[1] < '0' || offset_start[1] > '9')
176
+ return git__throw(GIT_EOBJCORRUPTED, "Failed to parse TZ offset.");
177
+
178
+ if (git__strtol32(&dec_offset, offset_start + 1, &offset_end, 10) < GIT_SUCCESS)
179
+ return git__throw(GIT_EOBJCORRUPTED, "Failed to parse TZ offset. It isn't a number");
180
+
181
+ if (offset_end - offset_start != 5)
182
+ return git__throw(GIT_EOBJCORRUPTED, "Failed to parse TZ offset. Invalid length");
183
+
184
+ if (dec_offset > 1400)
185
+ return git__throw(GIT_EOBJCORRUPTED, "Failed to parse TZ offset. Value too large");
186
+
187
+ hours = dec_offset / 100;
188
+ mins = dec_offset % 100;
189
+
190
+ if (hours > 14) // see http://www.worldtimezone.com/faq.html
191
+ return git__throw(GIT_EOBJCORRUPTED, "Failed to parse TZ offset. Hour value too large");
192
+
193
+ if (mins > 59)
194
+ return git__throw(GIT_EOBJCORRUPTED, "Failed to parse TZ offset. Minute value too large");
195
+
196
+ offset = (hours * 60) + mins;
197
+
198
+ if (offset_start[0] == '-')
199
+ offset *= -1;
200
+
201
+ *offset_out = offset;
202
+
203
+ return GIT_SUCCESS;
204
+ }
205
+
206
+ static int process_next_token(const char **buffer_out, char **storage,
207
+ const char *token_end, const char *right_boundary)
208
+ {
209
+ int error = process_trimming(*buffer_out, storage, token_end, 0);
210
+ if (error < GIT_SUCCESS)
211
+ return error;
212
+
213
+ *buffer_out = token_end + 1;
214
+
215
+ if (*buffer_out > right_boundary)
216
+ return git__throw(GIT_EOBJCORRUPTED, "Failed to parse signature. Signature too short");
217
+
218
+ return GIT_SUCCESS;
219
+ }
220
+
221
+ static const char *scan_for_previous_token(const char *buffer, const char *left_boundary)
222
+ {
223
+ const char *start;
224
+
225
+ if (buffer <= left_boundary)
226
+ return NULL;
227
+
228
+ start = skip_trailing_spaces(left_boundary, buffer);
229
+
230
+ /* Search for previous occurence of space */
231
+ while (start[-1] != ' ' && start > left_boundary)
232
+ start--;
233
+
234
+ return start;
235
+ }
236
+
237
+ static int parse_time(git_time_t *time_out, const char *buffer)
238
+ {
239
+ int time;
240
+ int error;
241
+
242
+ if (*buffer == '+' || *buffer == '-')
243
+ return git__throw(GIT_ERROR, "Failed while parsing time. '%s' rather look like a timezone offset.", buffer);
244
+
245
+ error = git__strtol32(&time, buffer, &buffer, 10);
246
+
247
+ if (error < GIT_SUCCESS)
248
+ return error;
249
+
250
+ *time_out = (git_time_t)time;
251
+
252
+ return GIT_SUCCESS;
253
+ }
254
+
255
+ int git_signature__parse(git_signature *sig, const char **buffer_out,
256
+ const char *buffer_end, const char *header, char ender)
257
+ {
258
+ const char *buffer = *buffer_out;
259
+ const char *line_end, *name_end, *email_end, *tz_start, *time_start;
260
+ int error = GIT_SUCCESS;
261
+
262
+ memset(sig, 0x0, sizeof(git_signature));
263
+
264
+ if ((line_end = memchr(buffer, ender, buffer_end - buffer)) == NULL)
265
+ return git__throw(GIT_EOBJCORRUPTED, "Failed to parse signature. No newline given");
266
+
267
+ if (header) {
268
+ const size_t header_len = strlen(header);
269
+
270
+ if (memcmp(buffer, header, header_len) != 0)
271
+ return git__throw(GIT_EOBJCORRUPTED, "Failed to parse signature. Expected prefix '%s' doesn't match actual", header);
272
+
273
+ buffer += header_len;
274
+ }
275
+
276
+ if (buffer > line_end)
277
+ return git__throw(GIT_EOBJCORRUPTED, "Failed to parse signature. Signature too short");
278
+
279
+ if ((name_end = strchr(buffer, '<')) == NULL)
280
+ return git__throw(GIT_EOBJCORRUPTED, "Failed to parse signature. Cannot find '<' in signature");
281
+
282
+ if ((email_end = strchr(name_end, '>')) == NULL)
283
+ return git__throw(GIT_EOBJCORRUPTED, "Failed to parse signature. Cannot find '>' in signature");
284
+
285
+ if (email_end < name_end)
286
+ return git__throw(GIT_EOBJCORRUPTED, "Failed to parse signature. Malformed e-mail");
287
+
288
+ error = process_next_token(&buffer, &sig->name, name_end, line_end);
289
+ if (error < GIT_SUCCESS)
290
+ return error;
291
+
292
+ error = process_next_token(&buffer, &sig->email, email_end, line_end);
293
+ if (error < GIT_SUCCESS)
294
+ return error;
295
+
296
+ tz_start = scan_for_previous_token(line_end - 1, buffer);
297
+
298
+ if (tz_start == NULL)
299
+ goto clean_exit; /* No timezone nor date */
300
+
301
+ time_start = scan_for_previous_token(tz_start - 1, buffer);
302
+ if (time_start == NULL || parse_time(&sig->when.time, time_start) < GIT_SUCCESS) {
303
+ /* The tz_start might point at the time */
304
+ parse_time(&sig->when.time, tz_start);
305
+ goto clean_exit;
306
+ }
307
+
308
+ if (parse_timezone_offset(tz_start, &sig->when.offset) < GIT_SUCCESS) {
309
+ sig->when.time = 0; /* Bogus timezone, we reset the time */
310
+ }
311
+
312
+ clean_exit:
313
+ *buffer_out = line_end + 1;
314
+ return GIT_SUCCESS;
315
+ }
316
+
317
+ void git_signature__writebuf(git_buf *buf, const char *header, const git_signature *sig)
318
+ {
319
+ int offset, hours, mins;
320
+ char sign;
321
+
322
+ offset = sig->when.offset;
323
+ sign = (sig->when.offset < 0) ? '-' : '+';
324
+
325
+ if (offset < 0)
326
+ offset = -offset;
327
+
328
+ hours = offset / 60;
329
+ mins = offset % 60;
330
+
331
+ git_buf_printf(buf, "%s%s <%s> %u %c%02d%02d\n",
332
+ header ? header : "", sig->name, sig->email,
333
+ (unsigned)sig->when.time, sign, hours, mins);
334
+ }
335
+
@@ -0,0 +1,18 @@
1
+ /*
2
+ * Copyright (C) 2009-2011 the libgit2 contributors
3
+ *
4
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
5
+ * a Linking Exception. For full terms see the included COPYING file.
6
+ */
7
+ #ifndef INCLUDE_signature_h__
8
+ #define INCLUDE_signature_h__
9
+
10
+ #include "git2/common.h"
11
+ #include "git2/signature.h"
12
+ #include "repository.h"
13
+ #include <time.h>
14
+
15
+ int git_signature__parse(git_signature *sig, const char **buffer_out, const char *buffer_end, const char *header, char ender);
16
+ void git_signature__writebuf(git_buf *buf, const char *header, const git_signature *sig);
17
+
18
+ #endif
@@ -0,0 +1,696 @@
1
+ /*
2
+ * Copyright (C) 2009-2011 the libgit2 contributors
3
+ *
4
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
5
+ * a Linking Exception. For full terms see the included COPYING file.
6
+ */
7
+
8
+ #include "common.h"
9
+ #include "git2.h"
10
+ #include "fileops.h"
11
+ #include "hash.h"
12
+ #include "vector.h"
13
+ #include "tree.h"
14
+ #include "git2/status.h"
15
+ #include "repository.h"
16
+
17
+ struct status_entry {
18
+ git_index_time mtime;
19
+
20
+ git_oid head_oid;
21
+ git_oid index_oid;
22
+ git_oid wt_oid;
23
+
24
+ unsigned int status_flags:6;
25
+
26
+ char path[GIT_FLEX_ARRAY]; /* more */
27
+ };
28
+
29
+ static struct status_entry *status_entry_new(git_vector *entries, const char *path)
30
+ {
31
+ struct status_entry *e = git__malloc(sizeof(*e) + strlen(path) + 1);
32
+ if (e == NULL)
33
+ return NULL;
34
+
35
+ memset(e, 0x0, sizeof(*e));
36
+
37
+ if (entries != NULL)
38
+ git_vector_insert(entries, e);
39
+
40
+ strcpy(e->path, path);
41
+
42
+ return e;
43
+ }
44
+
45
+ GIT_INLINE(void) status_entry_update_from_tree_entry(struct status_entry *e, const git_tree_entry *tree_entry)
46
+ {
47
+ assert(e && tree_entry);
48
+
49
+ git_oid_cpy(&e->head_oid, &tree_entry->oid);
50
+ }
51
+
52
+ GIT_INLINE(void) status_entry_update_from_index_entry(struct status_entry *e, const git_index_entry *index_entry)
53
+ {
54
+ assert(e && index_entry);
55
+
56
+ git_oid_cpy(&e->index_oid, &index_entry->oid);
57
+ e->mtime = index_entry->mtime;
58
+ }
59
+
60
+ static void status_entry_update_from_index(struct status_entry *e, git_index *index)
61
+ {
62
+ int idx;
63
+ git_index_entry *index_entry;
64
+
65
+ assert(e && index);
66
+
67
+ idx = git_index_find(index, e->path);
68
+ if (idx < 0)
69
+ return;
70
+
71
+ index_entry = git_index_get(index, idx);
72
+
73
+ status_entry_update_from_index_entry(e, index_entry);
74
+ }
75
+
76
+ static int status_entry_update_from_workdir(struct status_entry *e, char* full_path)
77
+ {
78
+ struct stat filest;
79
+
80
+ if (p_stat(full_path, &filest) < GIT_SUCCESS)
81
+ return git__throw(GIT_EOSERR, "Failed to determine status of file '%s'. Can't read file", full_path);
82
+
83
+ if (e->mtime.seconds == (git_time_t)filest.st_mtime)
84
+ git_oid_cpy(&e->wt_oid, &e->index_oid);
85
+ else
86
+ git_odb_hashfile(&e->wt_oid, full_path, GIT_OBJ_BLOB);
87
+
88
+ return GIT_SUCCESS;
89
+ }
90
+
91
+ static int status_entry_update_flags(struct status_entry *e)
92
+ {
93
+ git_oid zero;
94
+ int head_zero, index_zero, wt_zero;
95
+
96
+ memset(&zero, 0x0, sizeof(git_oid));
97
+
98
+ head_zero = git_oid_cmp(&zero, &e->head_oid);
99
+ index_zero = git_oid_cmp(&zero, &e->index_oid);
100
+ wt_zero = git_oid_cmp(&zero, &e->wt_oid);
101
+
102
+ if (head_zero == 0 && index_zero == 0 && wt_zero == 0)
103
+ return GIT_ENOTFOUND;
104
+
105
+ if (head_zero == 0 && index_zero != 0)
106
+ e->status_flags |= GIT_STATUS_INDEX_NEW;
107
+ else if (index_zero == 0 && head_zero != 0)
108
+ e->status_flags |= GIT_STATUS_INDEX_DELETED;
109
+ else if (git_oid_cmp(&e->head_oid, &e->index_oid) != 0)
110
+ e->status_flags |= GIT_STATUS_INDEX_MODIFIED;
111
+
112
+ if (index_zero == 0 && wt_zero != 0)
113
+ e->status_flags |= GIT_STATUS_WT_NEW;
114
+ else if (wt_zero == 0 && index_zero != 0)
115
+ e->status_flags |= GIT_STATUS_WT_DELETED;
116
+ else if (git_oid_cmp(&e->index_oid, &e->wt_oid) != 0)
117
+ e->status_flags |= GIT_STATUS_WT_MODIFIED;
118
+
119
+ return GIT_SUCCESS;
120
+ }
121
+
122
+ struct status_st {
123
+ git_vector *vector;
124
+ git_index *index;
125
+ git_tree *tree;
126
+
127
+ int workdir_path_len;
128
+ char* head_tree_relative_path;
129
+ int head_tree_relative_path_len;
130
+ unsigned int tree_position;
131
+ unsigned int index_position;
132
+ int is_dir:1;
133
+ };
134
+
135
+ static int retrieve_head_tree(git_tree **tree_out, git_repository *repo)
136
+ {
137
+ git_reference *resolved_head_ref;
138
+ git_commit *head_commit = NULL;
139
+ git_tree *tree;
140
+ int error = GIT_SUCCESS;
141
+
142
+ *tree_out = NULL;
143
+
144
+ error = git_repository_head(&resolved_head_ref, repo);
145
+ /*
146
+ * We assume that a situation where HEAD exists but can not be resolved is valid.
147
+ * A new repository fits this description for instance.
148
+ */
149
+ if (error == GIT_ENOTFOUND)
150
+ return GIT_SUCCESS;
151
+ if (error < GIT_SUCCESS)
152
+ return git__rethrow(error, "HEAD can't be resolved");
153
+
154
+ if ((error = git_commit_lookup(&head_commit, repo, git_reference_oid(resolved_head_ref))) < GIT_SUCCESS)
155
+ return git__rethrow(error, "The tip of HEAD can't be retrieved");
156
+
157
+ if ((error = git_commit_tree(&tree, head_commit)) < GIT_SUCCESS) {
158
+ error = git__rethrow(error, "The tree of HEAD can't be retrieved");
159
+ goto exit;
160
+ }
161
+
162
+ *tree_out = tree;
163
+
164
+ exit:
165
+ git_commit_free(head_commit);
166
+ return error;
167
+ }
168
+
169
+ enum path_type {
170
+ GIT_STATUS_PATH_NULL,
171
+ GIT_STATUS_PATH_IGNORE,
172
+ GIT_STATUS_PATH_FILE,
173
+ GIT_STATUS_PATH_FOLDER,
174
+ };
175
+
176
+ static int dirent_cb(void *state, char *full_path);
177
+ static int alphasorted_futils_direach(
178
+ char *path, size_t path_sz,
179
+ int (*fn)(void *, char *), void *arg);
180
+
181
+ static int process_folder(struct status_st *st, const git_tree_entry *tree_entry, char *full_path, enum path_type path_type)
182
+ {
183
+ git_object *subtree = NULL;
184
+ git_tree *pushed_tree = NULL;
185
+ int error, pushed_tree_position = 0;
186
+ git_otype tree_entry_type = GIT_OBJ_BAD;
187
+
188
+ if (tree_entry != NULL) {
189
+ tree_entry_type = git_tree_entry_type(tree_entry);
190
+
191
+ switch (tree_entry_type) {
192
+ case GIT_OBJ_TREE:
193
+ error = git_tree_entry_2object(&subtree, ((git_object *)(st->tree))->repo, tree_entry);
194
+ pushed_tree = st->tree;
195
+ pushed_tree_position = st->tree_position;
196
+ st->tree = (git_tree *)subtree;
197
+ st->tree_position = 0;
198
+ st->head_tree_relative_path_len += 1 + tree_entry->filename_len; /* path + '/' + name */
199
+ break;
200
+
201
+ case GIT_OBJ_BLOB:
202
+ /* No op */
203
+ break;
204
+
205
+ default:
206
+ error = git__throw(GIT_EINVALIDTYPE, "Unexpected tree entry type"); /* TODO: How should we deal with submodules? */
207
+ }
208
+ }
209
+
210
+ if (full_path != NULL && path_type == GIT_STATUS_PATH_FOLDER)
211
+ error = alphasorted_futils_direach(full_path, GIT_PATH_MAX, dirent_cb, st);
212
+ else {
213
+ error = dirent_cb(st, NULL);
214
+ }
215
+
216
+ if (tree_entry_type == GIT_OBJ_TREE) {
217
+ git_object_free(subtree);
218
+ st->head_tree_relative_path_len -= 1 + tree_entry->filename_len;
219
+ st->tree = pushed_tree;
220
+ st->tree_position = pushed_tree_position;
221
+ st->tree_position++;
222
+ }
223
+
224
+ return error;
225
+ }
226
+
227
+ static int store_if_changed(struct status_st *st, struct status_entry *e)
228
+ {
229
+ int error;
230
+ if ((error = status_entry_update_flags(e)) < GIT_SUCCESS)
231
+ return git__throw(error, "Failed to process the file '%s'. It doesn't exist in the workdir, in the HEAD nor in the index", e->path);
232
+
233
+ if (e->status_flags == GIT_STATUS_CURRENT) {
234
+ git__free(e);
235
+ return GIT_SUCCESS;
236
+ }
237
+
238
+ return git_vector_insert(st->vector, e);
239
+ }
240
+
241
+ static int determine_status(struct status_st *st,
242
+ int in_head, int in_index, int in_workdir,
243
+ const git_tree_entry *tree_entry,
244
+ const git_index_entry *index_entry,
245
+ char *full_path,
246
+ const char *status_path,
247
+ enum path_type path_type)
248
+ {
249
+ struct status_entry *e;
250
+ int error = GIT_SUCCESS;
251
+ git_otype tree_entry_type = GIT_OBJ_BAD;
252
+
253
+ if (tree_entry != NULL)
254
+ tree_entry_type = git_tree_entry_type(tree_entry);
255
+
256
+ /* If we're dealing with a directory in the workdir, let's recursively tackle it first */
257
+ if (path_type == GIT_STATUS_PATH_FOLDER)
258
+ return process_folder(st, tree_entry, full_path, path_type);
259
+
260
+ /* Are we dealing with a file somewhere? */
261
+ if (in_workdir || in_index || (in_head && tree_entry_type == GIT_OBJ_BLOB)) {
262
+ e = status_entry_new(NULL, status_path);
263
+
264
+ if (in_head && tree_entry_type == GIT_OBJ_BLOB) {
265
+ status_entry_update_from_tree_entry(e, tree_entry);
266
+ st->tree_position++;
267
+ }
268
+
269
+ if (in_index) {
270
+ status_entry_update_from_index_entry(e, index_entry);
271
+ st->index_position++;
272
+ }
273
+
274
+ if (in_workdir)
275
+ if ((error = status_entry_update_from_workdir(e, full_path)) < GIT_SUCCESS)
276
+ return error; /* The callee has already set the error message */
277
+
278
+ return store_if_changed(st, e);
279
+ }
280
+
281
+ /* Last option, we're dealing with a leftover folder tree entry */
282
+ assert(in_head && !in_index && !in_workdir && (tree_entry_type == GIT_OBJ_TREE));
283
+ return process_folder(st, tree_entry, full_path, path_type);
284
+ }
285
+
286
+ static int path_type_from(char *full_path, int is_dir)
287
+ {
288
+ if (full_path == NULL)
289
+ return GIT_STATUS_PATH_NULL;
290
+
291
+ if (!is_dir)
292
+ return GIT_STATUS_PATH_FILE;
293
+
294
+ if (!git__suffixcmp(full_path, "/" DOT_GIT "/"))
295
+ return GIT_STATUS_PATH_IGNORE;
296
+
297
+ return GIT_STATUS_PATH_FOLDER;
298
+ }
299
+
300
+ static const char *status_path(const char *first, const char *second, const char *third)
301
+ {
302
+ /* At least one of them can not be NULL */
303
+ assert(first != NULL || second != NULL || third != NULL);
304
+
305
+ /* TODO: Fixme. Ensure that when non null, they're all equal */
306
+ if (first != NULL)
307
+ return first;
308
+
309
+ if (second != NULL)
310
+ return second;
311
+
312
+ return third;
313
+ }
314
+
315
+ static int compare(const char *left, const char *right)
316
+ {
317
+ if (left == NULL && right == NULL)
318
+ return 0;
319
+
320
+ if (left == NULL)
321
+ return 1;
322
+
323
+ if (right == NULL)
324
+ return -1;
325
+
326
+ return strcmp(left, right);
327
+ }
328
+
329
+ /* Greatly inspired from JGit IndexTreeWalker */
330
+ /* https://github.com/spearce/jgit/blob/ed47e29c777accfa78c6f50685a5df2b8f5b8ff5/org.spearce.jgit/src/org/spearce/jgit/lib/IndexTreeWalker.java#L88 */
331
+
332
+ static int dirent_cb(void *state, char *a)
333
+ {
334
+ const git_tree_entry *m;
335
+ const git_index_entry *entry;
336
+ enum path_type path_type;
337
+ int cmpma, cmpmi, cmpai, error;
338
+ const char *pm, *pa, *pi;
339
+ const char *m_name, *i_name, *a_name;
340
+
341
+ struct status_st *st = (struct status_st *)state;
342
+
343
+ path_type = path_type_from(a, st->is_dir);
344
+
345
+ if (path_type == GIT_STATUS_PATH_IGNORE)
346
+ return GIT_SUCCESS; /* Let's skip the ".git" directory */
347
+
348
+ a_name = (path_type != GIT_STATUS_PATH_NULL) ? a + st->workdir_path_len : NULL;
349
+
350
+ while (1) {
351
+ if (st->tree == NULL)
352
+ m = NULL;
353
+ else
354
+ m = git_tree_entry_byindex(st->tree, st->tree_position);
355
+
356
+ entry = git_index_get(st->index, st->index_position);
357
+
358
+ if ((m == NULL) && (a == NULL) && (entry == NULL))
359
+ return GIT_SUCCESS;
360
+
361
+ if (m != NULL) {
362
+ st->head_tree_relative_path[st->head_tree_relative_path_len] = '\0';
363
+
364
+ /* When the tree entry is a folder, append a forward slash to its name */
365
+ if (git_tree_entry_type(m) == GIT_OBJ_TREE)
366
+ git_path_join_n(st->head_tree_relative_path, 3, st->head_tree_relative_path, m->filename, "");
367
+ else
368
+ git_path_join(st->head_tree_relative_path, st->head_tree_relative_path, m->filename);
369
+
370
+ m_name = st->head_tree_relative_path;
371
+ } else
372
+ m_name = NULL;
373
+
374
+ i_name = (entry != NULL) ? entry->path : NULL;
375
+
376
+ cmpma = compare(m_name, a_name);
377
+ cmpmi = compare(m_name, i_name);
378
+ cmpai = compare(a_name, i_name);
379
+
380
+ pm = ((cmpma <= 0) && (cmpmi <= 0)) ? m_name : NULL;
381
+ pa = ((cmpma >= 0) && (cmpai <= 0)) ? a_name : NULL;
382
+ pi = ((cmpmi >= 0) && (cmpai >= 0)) ? i_name : NULL;
383
+
384
+ if((error = determine_status(st, pm != NULL, pi != NULL, pa != NULL, m, entry, a, status_path(pm, pi, pa), path_type)) < GIT_SUCCESS)
385
+ return git__rethrow(error, "An error occured while determining the status of '%s'", a);
386
+
387
+ if ((pa != NULL) || (path_type == GIT_STATUS_PATH_FOLDER))
388
+ return GIT_SUCCESS;
389
+ }
390
+ }
391
+
392
+ static int status_cmp(const void *a, const void *b)
393
+ {
394
+ const struct status_entry *entry_a = (const struct status_entry *)(a);
395
+ const struct status_entry *entry_b = (const struct status_entry *)(b);
396
+
397
+ return strcmp(entry_a->path, entry_b->path);
398
+ }
399
+
400
+ #define DEFAULT_SIZE 16
401
+
402
+ int git_status_foreach(git_repository *repo, int (*callback)(const char *, unsigned int, void *), void *payload)
403
+ {
404
+ git_vector entries;
405
+ git_index *index = NULL;
406
+ char temp_path[GIT_PATH_MAX];
407
+ char tree_path[GIT_PATH_MAX] = "";
408
+ struct status_st dirent_st;
409
+ int error = GIT_SUCCESS;
410
+ unsigned int i;
411
+ git_tree *tree;
412
+ struct status_entry *e;
413
+ const char *workdir;
414
+
415
+ if ((workdir = git_repository_workdir(repo)) == NULL)
416
+ return git__throw(GIT_ERROR,
417
+ "Cannot retrieve status on a bare repository");
418
+
419
+ if ((error = git_repository_index__weakptr(&index, repo)) < GIT_SUCCESS) {
420
+ return git__rethrow(error,
421
+ "Failed to determine statuses. Index can't be opened");
422
+ }
423
+
424
+ if ((error = retrieve_head_tree(&tree, repo)) < GIT_SUCCESS) {
425
+ error = git__rethrow(error, "Failed to determine statuses");
426
+ goto exit;
427
+ }
428
+
429
+ git_vector_init(&entries, DEFAULT_SIZE, status_cmp);
430
+
431
+ dirent_st.workdir_path_len = strlen(workdir);
432
+ dirent_st.tree_position = 0;
433
+ dirent_st.index_position = 0;
434
+ dirent_st.tree = tree;
435
+ dirent_st.index = index;
436
+ dirent_st.vector = &entries;
437
+ dirent_st.head_tree_relative_path = tree_path;
438
+ dirent_st.head_tree_relative_path_len = 0;
439
+ dirent_st.is_dir = 1;
440
+
441
+ strcpy(temp_path, workdir);
442
+
443
+ if (git_futils_isdir(temp_path)) {
444
+ error = git__throw(GIT_EINVALIDPATH,
445
+ "Failed to determine status of file '%s'. "
446
+ "The given path doesn't lead to a folder", temp_path);
447
+ goto exit;
448
+ }
449
+
450
+ error = alphasorted_futils_direach(
451
+ temp_path, sizeof(temp_path),
452
+ dirent_cb, &dirent_st
453
+ );
454
+
455
+ if (error < GIT_SUCCESS)
456
+ error = git__rethrow(error,
457
+ "Failed to determine statuses. "
458
+ "An error occured while processing the working directory");
459
+
460
+ if ((error == GIT_SUCCESS) && ((error = dirent_cb(&dirent_st, NULL)) < GIT_SUCCESS))
461
+ error = git__rethrow(error,
462
+ "Failed to determine statuses. "
463
+ "An error occured while post-processing the HEAD tree and the index");
464
+
465
+ for (i = 0; i < entries.length; ++i) {
466
+ e = (struct status_entry *)git_vector_get(&entries, i);
467
+
468
+ if (error == GIT_SUCCESS) {
469
+ error = callback(e->path, e->status_flags, payload);
470
+ if (error < GIT_SUCCESS)
471
+ error = git__rethrow(error,
472
+ "Failed to determine statuses. User callback failed");
473
+ }
474
+
475
+ git__free(e);
476
+ }
477
+
478
+ exit:
479
+ git_vector_free(&entries);
480
+ git_tree_free(tree);
481
+ return error;
482
+ }
483
+
484
+ static int recurse_tree_entry(git_tree *tree, struct status_entry *e, const char *path)
485
+ {
486
+ char *dir_sep;
487
+ const git_tree_entry *tree_entry;
488
+ git_tree *subtree;
489
+ int error = GIT_SUCCESS;
490
+
491
+ dir_sep = strchr(path, '/');
492
+ if (!dir_sep) {
493
+ tree_entry = git_tree_entry_byname(tree, path);
494
+ if (tree_entry == NULL)
495
+ return GIT_SUCCESS; /* The leaf doesn't exist in the tree*/
496
+
497
+ status_entry_update_from_tree_entry(e, tree_entry);
498
+ return GIT_SUCCESS;
499
+ }
500
+
501
+ /* Retrieve subtree name */
502
+ *dir_sep = '\0';
503
+
504
+ tree_entry = git_tree_entry_byname(tree, path);
505
+ if (tree_entry == NULL)
506
+ return GIT_SUCCESS; /* The subtree doesn't exist in the tree*/
507
+
508
+ *dir_sep = '/';
509
+
510
+ /* Retreive subtree */
511
+ if ((error = git_tree_lookup(&subtree, tree->object.repo, &tree_entry->oid)) < GIT_SUCCESS)
512
+ return git__throw(GIT_EOBJCORRUPTED, "Can't find tree object '%s'", tree_entry->filename);
513
+
514
+ error = recurse_tree_entry(subtree, e, dir_sep+1);
515
+ git_tree_free(subtree);
516
+ return error;
517
+ }
518
+
519
+ int git_status_file(unsigned int *status_flags, git_repository *repo, const char *path)
520
+ {
521
+ struct status_entry *e;
522
+ git_index *index = NULL;
523
+ char temp_path[GIT_PATH_MAX];
524
+ int error = GIT_SUCCESS;
525
+ git_tree *tree = NULL;
526
+ const char *workdir;
527
+
528
+ assert(status_flags && repo && path);
529
+
530
+ if ((workdir = git_repository_workdir(repo)) == NULL)
531
+ return git__throw(GIT_ERROR,
532
+ "Cannot retrieve status on a bare repository");
533
+
534
+ git_path_join(temp_path, workdir, path);
535
+ if (git_futils_isdir(temp_path) == GIT_SUCCESS)
536
+ return git__throw(GIT_EINVALIDPATH,
537
+ "Failed to determine status of file '%s'. "
538
+ "Given path leads to a folder, not a file", path);
539
+
540
+ e = status_entry_new(NULL, path);
541
+ if (e == NULL)
542
+ return GIT_ENOMEM;
543
+
544
+ /* Find file in Workdir */
545
+ if (git_futils_exists(temp_path) == GIT_SUCCESS) {
546
+ if ((error = status_entry_update_from_workdir(e, temp_path)) < GIT_SUCCESS)
547
+ goto exit; /* The callee has already set the error message */
548
+ }
549
+
550
+ /* Find file in Index */
551
+ if ((error = git_repository_index__weakptr(&index, repo)) < GIT_SUCCESS) {
552
+ error = git__rethrow(error,
553
+ "Failed to determine status of file '%s'."
554
+ "Index can't be opened", path);
555
+ goto exit;
556
+ }
557
+
558
+ status_entry_update_from_index(e, index);
559
+
560
+ if ((error = retrieve_head_tree(&tree, repo)) < GIT_SUCCESS) {
561
+ error = git__rethrow(error,
562
+ "Failed to determine status of file '%s'", path);
563
+ goto exit;
564
+ }
565
+
566
+ /* If the repository is not empty, try and locate the file in HEAD */
567
+ if (tree != NULL) {
568
+ strcpy(temp_path, path);
569
+
570
+ error = recurse_tree_entry(tree, e, temp_path);
571
+ if (error < GIT_SUCCESS) {
572
+ error = git__rethrow(error,
573
+ "Failed to determine status of file '%s'. "
574
+ "An error occured while processing the tree", path);
575
+ goto exit;
576
+ }
577
+ }
578
+
579
+ /* Determine status */
580
+ if ((error = status_entry_update_flags(e)) < GIT_SUCCESS) {
581
+ error = git__throw(error, "Nonexistent file");
582
+ goto exit;
583
+ }
584
+
585
+ *status_flags = e->status_flags;
586
+
587
+ exit:
588
+ git_tree_free(tree);
589
+ git__free(e);
590
+ return error;
591
+ }
592
+
593
+ /*
594
+ * git_futils_direach is not supposed to return entries in an ordered manner.
595
+ * alphasorted_futils_direach wraps git_futils_direach and invokes the callback
596
+ * function by passing it alphabeticcally sorted paths parameters.
597
+ *
598
+ */
599
+
600
+ struct alphasorted_dirent_info {
601
+ int is_dir;
602
+
603
+ char path[GIT_FLEX_ARRAY]; /* more */
604
+ };
605
+
606
+ static struct alphasorted_dirent_info *alphasorted_dirent_info_new(const char *path)
607
+ {
608
+ int is_dir, size;
609
+ struct alphasorted_dirent_info *di;
610
+
611
+ is_dir = git_futils_isdir(path) == GIT_SUCCESS ? 1 : 0;
612
+ size = sizeof(*di) + (is_dir ? GIT_PATH_MAX : strlen(path)) + 2;
613
+
614
+ di = git__malloc(size);
615
+ if (di == NULL)
616
+ return NULL;
617
+
618
+ memset(di, 0x0, size);
619
+
620
+ strcpy(di->path, path);
621
+
622
+ if (is_dir) {
623
+ di->is_dir = 1;
624
+
625
+ /*
626
+ * Append a forward slash to the name to force folders
627
+ * to be ordered in a similar way than in a tree
628
+ *
629
+ * The file "subdir" should appear before the file "subdir.txt"
630
+ * The folder "subdir" should appear after the file "subdir.txt"
631
+ */
632
+ di->path[strlen(path)] = '/';
633
+ }
634
+
635
+ return di;
636
+ }
637
+
638
+ static int alphasorted_dirent_info_cmp(const void *a, const void *b)
639
+ {
640
+ struct alphasorted_dirent_info *stra = (struct alphasorted_dirent_info *)a;
641
+ struct alphasorted_dirent_info *strb = (struct alphasorted_dirent_info *)b;
642
+
643
+ return strcmp(stra->path, strb->path);
644
+ }
645
+
646
+ static int alphasorted_dirent_cb(void *state, char *full_path)
647
+ {
648
+ struct alphasorted_dirent_info *entry;
649
+ git_vector *entry_names;
650
+
651
+ entry_names = (git_vector *)state;
652
+ entry = alphasorted_dirent_info_new(full_path);
653
+
654
+ if (entry == NULL)
655
+ return GIT_ENOMEM;
656
+
657
+ if (git_vector_insert(entry_names, entry) < GIT_SUCCESS) {
658
+ git__free(entry);
659
+ return GIT_ENOMEM;
660
+ }
661
+
662
+ return GIT_SUCCESS;
663
+ }
664
+
665
+ static int alphasorted_futils_direach(
666
+ char *path,
667
+ size_t path_sz,
668
+ int (*fn)(void *, char *),
669
+ void *arg)
670
+ {
671
+ struct alphasorted_dirent_info *entry;
672
+ git_vector entry_names;
673
+ unsigned int idx;
674
+ int error = GIT_SUCCESS;
675
+
676
+ if (git_vector_init(&entry_names, 16, alphasorted_dirent_info_cmp) < GIT_SUCCESS)
677
+ return GIT_ENOMEM;
678
+
679
+ error = git_futils_direach(path, path_sz, alphasorted_dirent_cb, &entry_names);
680
+
681
+ git_vector_sort(&entry_names);
682
+
683
+ for (idx = 0; idx < entry_names.length; ++idx) {
684
+ entry = (struct alphasorted_dirent_info *)git_vector_get(&entry_names, idx);
685
+
686
+ if (error == GIT_SUCCESS) {
687
+ ((struct status_st *)arg)->is_dir = entry->is_dir;
688
+ error = fn(arg, entry->path);
689
+ }
690
+
691
+ git__free(entry);
692
+ }
693
+
694
+ git_vector_free(&entry_names);
695
+ return error;
696
+ }