motion-yapper 0.0.3 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (294) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.travis.yml +3 -1
  4. data/lib/yapper.rb +3 -3
  5. data/lib/yapper/db.rb +61 -4
  6. data/lib/yapper/document/persistence.rb +4 -0
  7. data/lib/yapper/document/selection.rb +13 -0
  8. data/lib/yapper/version.rb +1 -1
  9. data/motion-yapper.gemspec +1 -1
  10. data/spec/integration/search_spec.rb +111 -0
  11. data/vendor/Podfile.lock +11 -7
  12. data/vendor/YapDatabaseRubyMotion/YapDatabaseRubyMotion.bridgesupport +16 -2
  13. data/vendor/YapDatabaseRubyMotion/YapDatabaseRubyMotion.h +10 -7
  14. data/vendor/YapDatabaseRubyMotion/YapDatabaseRubyMotion.m +20 -2
  15. metadata +19 -297
  16. data/vendor/Pods/.build/libPods-CocoaLumberjack.a +0 -0
  17. data/vendor/Pods/.build/libPods-NSData+MD5Digest.a +0 -0
  18. data/vendor/Pods/.build/libPods-YapDatabase.a +0 -0
  19. data/vendor/Pods/.build/libPods.a +0 -0
  20. data/vendor/Pods/BuildHeaders/CocoaLumberjack/DDASLLogger.h +0 -41
  21. data/vendor/Pods/BuildHeaders/CocoaLumberjack/DDAbstractDatabaseLogger.h +0 -102
  22. data/vendor/Pods/BuildHeaders/CocoaLumberjack/DDContextFilterLogFormatter.h +0 -63
  23. data/vendor/Pods/BuildHeaders/CocoaLumberjack/DDDispatchQueueLogFormatter.h +0 -128
  24. data/vendor/Pods/BuildHeaders/CocoaLumberjack/DDFileLogger.h +0 -369
  25. data/vendor/Pods/BuildHeaders/CocoaLumberjack/DDLog+LOGV.h +0 -99
  26. data/vendor/Pods/BuildHeaders/CocoaLumberjack/DDLog.h +0 -634
  27. data/vendor/Pods/BuildHeaders/CocoaLumberjack/DDMultiFormatter.h +0 -30
  28. data/vendor/Pods/BuildHeaders/CocoaLumberjack/DDTTYLogger.h +0 -181
  29. data/vendor/Pods/BuildHeaders/NSData+MD5Digest/NSData+MD5Digest.h +0 -18
  30. data/vendor/Pods/BuildHeaders/YapDatabase/NSDictionary+YapDatabase.h +0 -8
  31. data/vendor/Pods/BuildHeaders/YapDatabase/YapCache.h +0 -91
  32. data/vendor/Pods/BuildHeaders/YapDatabase/YapCollectionKey.h +0 -23
  33. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabase.h +0 -547
  34. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseConnection.h +0 -449
  35. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseConnectionState.h +0 -29
  36. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseDefaults.h +0 -37
  37. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseExtension.h +0 -15
  38. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseExtensionConnection.h +0 -11
  39. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseExtensionPrivate.h +0 -444
  40. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseExtensionTransaction.h +0 -11
  41. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseFilteredView.h +0 -81
  42. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseFilteredViewConnection.h +0 -12
  43. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseFilteredViewPrivate.h +0 -17
  44. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseFilteredViewTransaction.h +0 -39
  45. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseFilteredViewTypes.h +0 -32
  46. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseFullTextSearch.h +0 -89
  47. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseFullTextSearchConnection.h +0 -32
  48. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseFullTextSearchPrivate.h +0 -77
  49. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseFullTextSearchSnippetOptions.h +0 -79
  50. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseFullTextSearchTransaction.h +0 -68
  51. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseLogging.h +0 -158
  52. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseManager.h +0 -17
  53. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabasePrivate.h +0 -446
  54. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseQuery.h +0 -42
  55. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseRelationship.h +0 -35
  56. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseRelationshipConnection.h +0 -29
  57. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseRelationshipEdge.h +0 -163
  58. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseRelationshipEdgePrivate.h +0 -79
  59. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseRelationshipNode.h +0 -99
  60. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseRelationshipOptions.h +0 -59
  61. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseRelationshipPrivate.h +0 -125
  62. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseRelationshipTransaction.h +0 -384
  63. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseSecondaryIndex.h +0 -149
  64. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseSecondaryIndexConnection.h +0 -33
  65. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseSecondaryIndexPrivate.h +0 -83
  66. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseSecondaryIndexSetup.h +0 -33
  67. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseSecondaryIndexSetupPrivate.h +0 -18
  68. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseSecondaryIndexTransaction.h +0 -58
  69. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseStatement.h +0 -13
  70. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseString.h +0 -121
  71. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseTransaction.h +0 -651
  72. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseView.h +0 -127
  73. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseViewChange.h +0 -272
  74. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseViewChangePrivate.h +0 -94
  75. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseViewConnection.h +0 -116
  76. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseViewMappings.h +0 -842
  77. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseViewMappingsPrivate.h +0 -72
  78. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseViewOptions.h +0 -63
  79. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseViewPage.h +0 -36
  80. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseViewPageMetadata.h +0 -27
  81. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseViewPrivate.h +0 -170
  82. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseViewRangeOptions.h +0 -330
  83. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseViewRangeOptionsPrivate.h +0 -17
  84. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseViewTransaction.h +0 -498
  85. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseViewTypes.h +0 -99
  86. data/vendor/Pods/BuildHeaders/YapDatabase/YapMemoryTable.h +0 -74
  87. data/vendor/Pods/BuildHeaders/YapDatabase/YapNull.h +0 -17
  88. data/vendor/Pods/BuildHeaders/YapDatabase/YapSet.h +0 -41
  89. data/vendor/Pods/BuildHeaders/YapDatabase/YapTouch.h +0 -15
  90. data/vendor/Pods/CocoaLumberjack/LICENSE.txt +0 -18
  91. data/vendor/Pods/CocoaLumberjack/Lumberjack/DDASLLogger.h +0 -41
  92. data/vendor/Pods/CocoaLumberjack/Lumberjack/DDASLLogger.m +0 -100
  93. data/vendor/Pods/CocoaLumberjack/Lumberjack/DDAbstractDatabaseLogger.h +0 -102
  94. data/vendor/Pods/CocoaLumberjack/Lumberjack/DDAbstractDatabaseLogger.m +0 -727
  95. data/vendor/Pods/CocoaLumberjack/Lumberjack/DDFileLogger.h +0 -369
  96. data/vendor/Pods/CocoaLumberjack/Lumberjack/DDFileLogger.m +0 -1539
  97. data/vendor/Pods/CocoaLumberjack/Lumberjack/DDLog+LOGV.h +0 -99
  98. data/vendor/Pods/CocoaLumberjack/Lumberjack/DDLog.h +0 -634
  99. data/vendor/Pods/CocoaLumberjack/Lumberjack/DDLog.m +0 -1208
  100. data/vendor/Pods/CocoaLumberjack/Lumberjack/DDTTYLogger.h +0 -181
  101. data/vendor/Pods/CocoaLumberjack/Lumberjack/DDTTYLogger.m +0 -1520
  102. data/vendor/Pods/CocoaLumberjack/Lumberjack/Extensions/DDContextFilterLogFormatter.h +0 -63
  103. data/vendor/Pods/CocoaLumberjack/Lumberjack/Extensions/DDContextFilterLogFormatter.m +0 -191
  104. data/vendor/Pods/CocoaLumberjack/Lumberjack/Extensions/DDDispatchQueueLogFormatter.h +0 -128
  105. data/vendor/Pods/CocoaLumberjack/Lumberjack/Extensions/DDDispatchQueueLogFormatter.m +0 -253
  106. data/vendor/Pods/CocoaLumberjack/Lumberjack/Extensions/DDMultiFormatter.h +0 -30
  107. data/vendor/Pods/CocoaLumberjack/Lumberjack/Extensions/DDMultiFormatter.m +0 -127
  108. data/vendor/Pods/CocoaLumberjack/Lumberjack/Extensions/README.txt +0 -7
  109. data/vendor/Pods/CocoaLumberjack/README.markdown +0 -74
  110. data/vendor/Pods/Headers/CocoaLumberjack/DDASLLogger.h +0 -41
  111. data/vendor/Pods/Headers/CocoaLumberjack/DDAbstractDatabaseLogger.h +0 -102
  112. data/vendor/Pods/Headers/CocoaLumberjack/DDContextFilterLogFormatter.h +0 -63
  113. data/vendor/Pods/Headers/CocoaLumberjack/DDDispatchQueueLogFormatter.h +0 -128
  114. data/vendor/Pods/Headers/CocoaLumberjack/DDFileLogger.h +0 -369
  115. data/vendor/Pods/Headers/CocoaLumberjack/DDLog+LOGV.h +0 -99
  116. data/vendor/Pods/Headers/CocoaLumberjack/DDLog.h +0 -634
  117. data/vendor/Pods/Headers/CocoaLumberjack/DDMultiFormatter.h +0 -30
  118. data/vendor/Pods/Headers/CocoaLumberjack/DDTTYLogger.h +0 -181
  119. data/vendor/Pods/Headers/NSData+MD5Digest/NSData+MD5Digest.h +0 -18
  120. data/vendor/Pods/Headers/YapDatabase/YapCollectionKey.h +0 -23
  121. data/vendor/Pods/Headers/YapDatabase/YapDatabase.h +0 -547
  122. data/vendor/Pods/Headers/YapDatabase/YapDatabaseConnection.h +0 -449
  123. data/vendor/Pods/Headers/YapDatabase/YapDatabaseExtension.h +0 -15
  124. data/vendor/Pods/Headers/YapDatabase/YapDatabaseExtensionConnection.h +0 -11
  125. data/vendor/Pods/Headers/YapDatabase/YapDatabaseExtensionTransaction.h +0 -11
  126. data/vendor/Pods/Headers/YapDatabase/YapDatabaseFilteredView.h +0 -81
  127. data/vendor/Pods/Headers/YapDatabase/YapDatabaseFilteredViewConnection.h +0 -12
  128. data/vendor/Pods/Headers/YapDatabase/YapDatabaseFilteredViewTransaction.h +0 -39
  129. data/vendor/Pods/Headers/YapDatabase/YapDatabaseFilteredViewTypes.h +0 -32
  130. data/vendor/Pods/Headers/YapDatabase/YapDatabaseFullTextSearch.h +0 -89
  131. data/vendor/Pods/Headers/YapDatabase/YapDatabaseFullTextSearchConnection.h +0 -32
  132. data/vendor/Pods/Headers/YapDatabase/YapDatabaseFullTextSearchSnippetOptions.h +0 -79
  133. data/vendor/Pods/Headers/YapDatabase/YapDatabaseFullTextSearchTransaction.h +0 -68
  134. data/vendor/Pods/Headers/YapDatabase/YapDatabaseQuery.h +0 -42
  135. data/vendor/Pods/Headers/YapDatabase/YapDatabaseRelationship.h +0 -35
  136. data/vendor/Pods/Headers/YapDatabase/YapDatabaseRelationshipConnection.h +0 -29
  137. data/vendor/Pods/Headers/YapDatabase/YapDatabaseRelationshipEdge.h +0 -163
  138. data/vendor/Pods/Headers/YapDatabase/YapDatabaseRelationshipNode.h +0 -99
  139. data/vendor/Pods/Headers/YapDatabase/YapDatabaseRelationshipOptions.h +0 -59
  140. data/vendor/Pods/Headers/YapDatabase/YapDatabaseRelationshipTransaction.h +0 -384
  141. data/vendor/Pods/Headers/YapDatabase/YapDatabaseSecondaryIndex.h +0 -149
  142. data/vendor/Pods/Headers/YapDatabase/YapDatabaseSecondaryIndexConnection.h +0 -33
  143. data/vendor/Pods/Headers/YapDatabase/YapDatabaseSecondaryIndexSetup.h +0 -33
  144. data/vendor/Pods/Headers/YapDatabase/YapDatabaseSecondaryIndexTransaction.h +0 -58
  145. data/vendor/Pods/Headers/YapDatabase/YapDatabaseTransaction.h +0 -651
  146. data/vendor/Pods/Headers/YapDatabase/YapDatabaseView.h +0 -127
  147. data/vendor/Pods/Headers/YapDatabase/YapDatabaseViewChange.h +0 -272
  148. data/vendor/Pods/Headers/YapDatabase/YapDatabaseViewConnection.h +0 -116
  149. data/vendor/Pods/Headers/YapDatabase/YapDatabaseViewMappings.h +0 -842
  150. data/vendor/Pods/Headers/YapDatabase/YapDatabaseViewOptions.h +0 -63
  151. data/vendor/Pods/Headers/YapDatabase/YapDatabaseViewRangeOptions.h +0 -330
  152. data/vendor/Pods/Headers/YapDatabase/YapDatabaseViewTransaction.h +0 -498
  153. data/vendor/Pods/Headers/YapDatabase/YapDatabaseViewTypes.h +0 -99
  154. data/vendor/Pods/Headers/YapDatabase/YapSet.h +0 -41
  155. data/vendor/Pods/Headers/____Pods-CocoaLumberjack-prefix.h +0 -7
  156. data/vendor/Pods/Headers/____Pods-NSData+MD5Digest-prefix.h +0 -5
  157. data/vendor/Pods/Headers/____Pods-YapDatabase-prefix.h +0 -5
  158. data/vendor/Pods/Headers/____Pods-environment.h +0 -38
  159. data/vendor/Pods/Manifest.lock +0 -22
  160. data/vendor/Pods/NSData+MD5Digest/NSData+MD5Digest/NSData+MD5Digest.h +0 -18
  161. data/vendor/Pods/NSData+MD5Digest/NSData+MD5Digest/NSData+MD5Digest.m +0 -39
  162. data/vendor/Pods/NSData+MD5Digest/README.md +0 -11
  163. data/vendor/Pods/Pods-CocoaLumberjack-Private.xcconfig +0 -5
  164. data/vendor/Pods/Pods-CocoaLumberjack-dummy.m +0 -5
  165. data/vendor/Pods/Pods-CocoaLumberjack-prefix.pch +0 -7
  166. data/vendor/Pods/Pods-CocoaLumberjack.xcconfig +0 -0
  167. data/vendor/Pods/Pods-NSData+MD5Digest-Private.xcconfig +0 -5
  168. data/vendor/Pods/Pods-NSData+MD5Digest-dummy.m +0 -5
  169. data/vendor/Pods/Pods-NSData+MD5Digest-prefix.pch +0 -5
  170. data/vendor/Pods/Pods-NSData+MD5Digest.xcconfig +0 -0
  171. data/vendor/Pods/Pods-YapDatabase-Private.xcconfig +0 -5
  172. data/vendor/Pods/Pods-YapDatabase-dummy.m +0 -5
  173. data/vendor/Pods/Pods-YapDatabase-prefix.pch +0 -5
  174. data/vendor/Pods/Pods-YapDatabase.xcconfig +0 -1
  175. data/vendor/Pods/Pods-acknowledgements.markdown +0 -59
  176. data/vendor/Pods/Pods-acknowledgements.plist +0 -97
  177. data/vendor/Pods/Pods-dummy.m +0 -5
  178. data/vendor/Pods/Pods-environment.h +0 -38
  179. data/vendor/Pods/Pods-resources.sh +0 -68
  180. data/vendor/Pods/Pods.xcconfig +0 -5
  181. data/vendor/Pods/Pods.xcodeproj/project.pbxproj +0 -4807
  182. data/vendor/Pods/Pods.xcodeproj/xcuserdata/kareemk.xcuserdatad/xcschemes/Pods-CocoaLumberjack.xcscheme +0 -59
  183. data/vendor/Pods/Pods.xcodeproj/xcuserdata/kareemk.xcuserdatad/xcschemes/Pods-NSData+MD5Digest.xcscheme +0 -59
  184. data/vendor/Pods/Pods.xcodeproj/xcuserdata/kareemk.xcuserdatad/xcschemes/Pods-YapDatabase.xcscheme +0 -59
  185. data/vendor/Pods/Pods.xcodeproj/xcuserdata/kareemk.xcuserdatad/xcschemes/Pods.xcscheme +0 -59
  186. data/vendor/Pods/Pods.xcodeproj/xcuserdata/kareemk.xcuserdatad/xcschemes/xcschememanagement.plist +0 -31
  187. data/vendor/Pods/YapDatabase/LICENSE.txt +0 -18
  188. data/vendor/Pods/YapDatabase/README.md +0 -32
  189. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/FilteredViews/Internal/YapDatabaseFilteredViewPrivate.h +0 -17
  190. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/FilteredViews/YapDatabaseFilteredView.h +0 -81
  191. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/FilteredViews/YapDatabaseFilteredView.m +0 -159
  192. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/FilteredViews/YapDatabaseFilteredViewConnection.h +0 -12
  193. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/FilteredViews/YapDatabaseFilteredViewConnection.m +0 -41
  194. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/FilteredViews/YapDatabaseFilteredViewTransaction.h +0 -39
  195. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/FilteredViews/YapDatabaseFilteredViewTransaction.m +0 -1235
  196. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/FilteredViews/YapDatabaseFilteredViewTypes.h +0 -32
  197. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/FullTextSearch/Internal/YapDatabaseFullTextSearchPrivate.h +0 -77
  198. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/FullTextSearch/YapDatabaseFullTextSearch.h +0 -89
  199. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/FullTextSearch/YapDatabaseFullTextSearch.m +0 -146
  200. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/FullTextSearch/YapDatabaseFullTextSearchConnection.h +0 -32
  201. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/FullTextSearch/YapDatabaseFullTextSearchConnection.m +0 -298
  202. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/FullTextSearch/YapDatabaseFullTextSearchSnippetOptions.h +0 -79
  203. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/FullTextSearch/YapDatabaseFullTextSearchSnippetOptions.m +0 -95
  204. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/FullTextSearch/YapDatabaseFullTextSearchTransaction.h +0 -68
  205. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/FullTextSearch/YapDatabaseFullTextSearchTransaction.m +0 -1403
  206. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Protocol/Internal/YapDatabaseExtensionPrivate.h +0 -444
  207. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Protocol/YapDatabaseExtension.h +0 -15
  208. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Protocol/YapDatabaseExtension.m +0 -83
  209. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Protocol/YapDatabaseExtensionConnection.h +0 -11
  210. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Protocol/YapDatabaseExtensionConnection.m +0 -46
  211. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Protocol/YapDatabaseExtensionTransaction.h +0 -11
  212. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Protocol/YapDatabaseExtensionTransaction.m +0 -204
  213. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Relationships/Internal/YapDatabaseRelationshipEdgePrivate.h +0 -79
  214. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Relationships/Internal/YapDatabaseRelationshipPrivate.h +0 -125
  215. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Relationships/YapDatabaseRelationship.h +0 -35
  216. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Relationships/YapDatabaseRelationship.m +0 -129
  217. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Relationships/YapDatabaseRelationshipConnection.h +0 -29
  218. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Relationships/YapDatabaseRelationshipConnection.m +0 -802
  219. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Relationships/YapDatabaseRelationshipEdge.h +0 -163
  220. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Relationships/YapDatabaseRelationshipEdge.m +0 -408
  221. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Relationships/YapDatabaseRelationshipNode.h +0 -99
  222. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Relationships/YapDatabaseRelationshipOptions.h +0 -59
  223. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Relationships/YapDatabaseRelationshipOptions.m +0 -29
  224. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Relationships/YapDatabaseRelationshipTransaction.h +0 -384
  225. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Relationships/YapDatabaseRelationshipTransaction.m +0 -5254
  226. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/SecondaryIndex/Internal/YapDatabaseSecondaryIndexPrivate.h +0 -83
  227. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/SecondaryIndex/Internal/YapDatabaseSecondaryIndexSetupPrivate.h +0 -18
  228. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/SecondaryIndex/YapDatabaseSecondaryIndex.h +0 -149
  229. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/SecondaryIndex/YapDatabaseSecondaryIndex.m +0 -161
  230. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/SecondaryIndex/YapDatabaseSecondaryIndexConnection.h +0 -33
  231. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/SecondaryIndex/YapDatabaseSecondaryIndexConnection.m +0 -331
  232. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/SecondaryIndex/YapDatabaseSecondaryIndexSetup.h +0 -33
  233. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/SecondaryIndex/YapDatabaseSecondaryIndexSetup.m +0 -245
  234. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/SecondaryIndex/YapDatabaseSecondaryIndexTransaction.h +0 -58
  235. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/SecondaryIndex/YapDatabaseSecondaryIndexTransaction.m +0 -1269
  236. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/Internal/YapDatabaseViewChangePrivate.h +0 -94
  237. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/Internal/YapDatabaseViewMappingsPrivate.h +0 -72
  238. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/Internal/YapDatabaseViewPage.h +0 -36
  239. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/Internal/YapDatabaseViewPage.mm +0 -296
  240. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/Internal/YapDatabaseViewPageMetadata.h +0 -27
  241. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/Internal/YapDatabaseViewPageMetadata.m +0 -28
  242. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/Internal/YapDatabaseViewPrivate.h +0 -170
  243. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/Internal/YapDatabaseViewRangeOptionsPrivate.h +0 -17
  244. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/Utilities/YapDatabaseViewChange.h +0 -272
  245. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/Utilities/YapDatabaseViewChange.m +0 -2500
  246. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/Utilities/YapDatabaseViewMappings.h +0 -842
  247. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/Utilities/YapDatabaseViewMappings.m +0 -1714
  248. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/Utilities/YapDatabaseViewRangeOptions.h +0 -330
  249. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/Utilities/YapDatabaseViewRangeOptions.m +0 -141
  250. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/YapDatabaseView.h +0 -127
  251. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/YapDatabaseView.m +0 -194
  252. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/YapDatabaseViewConnection.h +0 -116
  253. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/YapDatabaseViewConnection.m +0 -888
  254. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/YapDatabaseViewOptions.h +0 -63
  255. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/YapDatabaseViewOptions.m +0 -27
  256. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/YapDatabaseViewTransaction.h +0 -498
  257. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/YapDatabaseViewTransaction.m +0 -4986
  258. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/YapDatabaseViewTypes.h +0 -99
  259. data/vendor/Pods/YapDatabase/YapDatabase/Internal/NSDictionary+YapDatabase.h +0 -8
  260. data/vendor/Pods/YapDatabase/YapDatabase/Internal/NSDictionary+YapDatabase.m +0 -19
  261. data/vendor/Pods/YapDatabase/YapDatabase/Internal/YapCache.h +0 -91
  262. data/vendor/Pods/YapDatabase/YapDatabase/Internal/YapCache.m +0 -465
  263. data/vendor/Pods/YapDatabase/YapDatabase/Internal/YapDatabaseConnectionState.h +0 -29
  264. data/vendor/Pods/YapDatabase/YapDatabase/Internal/YapDatabaseConnectionState.m +0 -48
  265. data/vendor/Pods/YapDatabase/YapDatabase/Internal/YapDatabaseDefaults.h +0 -37
  266. data/vendor/Pods/YapDatabase/YapDatabase/Internal/YapDatabaseDefaults.m +0 -83
  267. data/vendor/Pods/YapDatabase/YapDatabase/Internal/YapDatabaseLogging.h +0 -158
  268. data/vendor/Pods/YapDatabase/YapDatabase/Internal/YapDatabaseLogging.m +0 -73
  269. data/vendor/Pods/YapDatabase/YapDatabase/Internal/YapDatabaseManager.h +0 -17
  270. data/vendor/Pods/YapDatabase/YapDatabase/Internal/YapDatabaseManager.m +0 -56
  271. data/vendor/Pods/YapDatabase/YapDatabase/Internal/YapDatabasePrivate.h +0 -446
  272. data/vendor/Pods/YapDatabase/YapDatabase/Internal/YapDatabaseStatement.h +0 -13
  273. data/vendor/Pods/YapDatabase/YapDatabase/Internal/YapDatabaseStatement.m +0 -26
  274. data/vendor/Pods/YapDatabase/YapDatabase/Internal/YapDatabaseString.h +0 -121
  275. data/vendor/Pods/YapDatabase/YapDatabase/Internal/YapMemoryTable.h +0 -74
  276. data/vendor/Pods/YapDatabase/YapDatabase/Internal/YapMemoryTable.m +0 -603
  277. data/vendor/Pods/YapDatabase/YapDatabase/Internal/YapNull.h +0 -17
  278. data/vendor/Pods/YapDatabase/YapDatabase/Internal/YapNull.m +0 -35
  279. data/vendor/Pods/YapDatabase/YapDatabase/Internal/YapTouch.h +0 -15
  280. data/vendor/Pods/YapDatabase/YapDatabase/Internal/YapTouch.m +0 -31
  281. data/vendor/Pods/YapDatabase/YapDatabase/Utilities/YapCollectionKey.h +0 -23
  282. data/vendor/Pods/YapDatabase/YapDatabase/Utilities/YapCollectionKey.m +0 -199
  283. data/vendor/Pods/YapDatabase/YapDatabase/Utilities/YapDatabaseQuery.h +0 -42
  284. data/vendor/Pods/YapDatabase/YapDatabase/Utilities/YapDatabaseQuery.m +0 -96
  285. data/vendor/Pods/YapDatabase/YapDatabase/Utilities/YapSet.h +0 -41
  286. data/vendor/Pods/YapDatabase/YapDatabase/Utilities/YapSet.m +0 -82
  287. data/vendor/Pods/YapDatabase/YapDatabase/YapDatabase.h +0 -547
  288. data/vendor/Pods/YapDatabase/YapDatabase/YapDatabase.m +0 -2013
  289. data/vendor/Pods/YapDatabase/YapDatabase/YapDatabaseConnection.h +0 -449
  290. data/vendor/Pods/YapDatabase/YapDatabase/YapDatabaseConnection.m +0 -4046
  291. data/vendor/Pods/YapDatabase/YapDatabase/YapDatabaseTransaction.h +0 -651
  292. data/vendor/Pods/YapDatabase/YapDatabase/YapDatabaseTransaction.m +0 -5602
  293. data/vendor/Pods/build-iPhoneSimulator/Pods.bridgesupport +0 -3172
  294. data/vendor/Pods/build-iPhoneSimulator/libPods.a +0 -0
@@ -1,369 +0,0 @@
1
- #import <Foundation/Foundation.h>
2
- #import "DDLog.h"
3
-
4
- @class DDLogFileInfo;
5
-
6
- /**
7
- * Welcome to Cocoa Lumberjack!
8
- *
9
- * The project page has a wealth of documentation if you have any questions.
10
- * https://github.com/CocoaLumberjack/CocoaLumberjack
11
- *
12
- * If you're new to the project you may wish to read the "Getting Started" wiki.
13
- * https://github.com/CocoaLumberjack/CocoaLumberjack/wiki/GettingStarted
14
- *
15
- *
16
- * This class provides a logger to write log statements to a file.
17
- **/
18
-
19
-
20
- // Default configuration and safety/sanity values.
21
- //
22
- // maximumFileSize -> DEFAULT_LOG_MAX_FILE_SIZE
23
- // rollingFrequency -> DEFAULT_LOG_ROLLING_FREQUENCY
24
- // maximumNumberOfLogFiles -> DEFAULT_LOG_MAX_NUM_LOG_FILES
25
- //
26
- // You should carefully consider the proper configuration values for your application.
27
-
28
- #define DEFAULT_LOG_MAX_FILE_SIZE (1024 * 1024) // 1 MB
29
- #define DEFAULT_LOG_ROLLING_FREQUENCY (60 * 60 * 24) // 24 Hours
30
- #define DEFAULT_LOG_MAX_NUM_LOG_FILES (5) // 5 Files
31
-
32
-
33
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
34
- #pragma mark -
35
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
36
-
37
- // The LogFileManager protocol is designed to allow you to control all aspects of your log files.
38
- //
39
- // The primary purpose of this is to allow you to do something with the log files after they have been rolled.
40
- // Perhaps you want to compress them to save disk space.
41
- // Perhaps you want to upload them to an FTP server.
42
- // Perhaps you want to run some analytics on the file.
43
- //
44
- // A default LogFileManager is, of course, provided.
45
- // The default LogFileManager simply deletes old log files according to the maximumNumberOfLogFiles property.
46
- //
47
- // This protocol provides various methods to fetch the list of log files.
48
- //
49
- // There are two variants: sorted and unsorted.
50
- // If sorting is not necessary, the unsorted variant is obviously faster.
51
- // The sorted variant will return an array sorted by when the log files were created,
52
- // with the most recently created log file at index 0, and the oldest log file at the end of the array.
53
- //
54
- // You can fetch only the log file paths (full path including name), log file names (name only),
55
- // or an array of DDLogFileInfo objects.
56
- // The DDLogFileInfo class is documented below, and provides a handy wrapper that
57
- // gives you easy access to various file attributes such as the creation date or the file size.
58
-
59
- @protocol DDLogFileManager <NSObject>
60
- @required
61
-
62
- // Public properties
63
-
64
- /**
65
- * The maximum number of archived log files to keep on disk.
66
- * For example, if this property is set to 3,
67
- * then the LogFileManager will only keep 3 archived log files (plus the current active log file) on disk.
68
- * Once the active log file is rolled/archived, then the oldest of the existing 3 rolled/archived log files is deleted.
69
- *
70
- * You may optionally disable deleting old/rolled/archived log files by setting this property to zero.
71
- **/
72
- @property (readwrite, assign) NSUInteger maximumNumberOfLogFiles;
73
-
74
- // Public methods
75
-
76
- - (NSString *)logsDirectory;
77
-
78
- - (NSArray *)unsortedLogFilePaths;
79
- - (NSArray *)unsortedLogFileNames;
80
- - (NSArray *)unsortedLogFileInfos;
81
-
82
- - (NSArray *)sortedLogFilePaths;
83
- - (NSArray *)sortedLogFileNames;
84
- - (NSArray *)sortedLogFileInfos;
85
-
86
- // Private methods (only to be used by DDFileLogger)
87
-
88
- - (NSString *)createNewLogFile;
89
-
90
- @optional
91
-
92
- // Notifications from DDFileLogger
93
-
94
- - (void)didArchiveLogFile:(NSString *)logFilePath;
95
- - (void)didRollAndArchiveLogFile:(NSString *)logFilePath;
96
-
97
- @end
98
-
99
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
100
- #pragma mark -
101
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
102
-
103
- /**
104
- * Default log file manager.
105
- *
106
- * All log files are placed inside the logsDirectory.
107
- * If a specific logsDirectory isn't specified, the default directory is used.
108
- * On Mac, this is in ~/Library/Logs/<Application Name>.
109
- * On iPhone, this is in ~/Library/Caches/Logs.
110
- *
111
- * Log files are named "<bundle identifier> <date> <time>.log"
112
- * Example: com.organization.myapp 2013-12-03 17-14.log
113
- *
114
- * Archived log files are automatically deleted according to the maximumNumberOfLogFiles property.
115
- **/
116
- @interface DDLogFileManagerDefault : NSObject <DDLogFileManager>
117
- {
118
- NSUInteger maximumNumberOfLogFiles;
119
- NSString *_logsDirectory;
120
- }
121
-
122
- - (id)init;
123
- - (instancetype)initWithLogsDirectory:(NSString *)logsDirectory;
124
-
125
- /*
126
- * Methods to override.
127
- *
128
- * Log files are named "<bundle identifier> <date> <time>.log"
129
- * Example: com.organization.myapp 2013-12-03 17-14.log
130
- *
131
- * If you wish to change default filename, you can override following two methods.
132
- * - newLogFileName method would be called on new logfile creation.
133
- * - isLogFile: method would be called to filter logfiles from all other files in logsDirectory.
134
- * You have to parse given filename and return YES if it is logFile.
135
- *
136
- * **NOTE**
137
- * newLogFileName returns filename. If appropriate file already exists, number would be added
138
- * to filename before extension. You have to handle this case in isLogFile: method.
139
- *
140
- * Example:
141
- * - newLogFileName returns "com.organization.myapp 2013-12-03.log",
142
- * file "com.organization.myapp 2013-12-03.log" would be created.
143
- * - after some time "com.organization.myapp 2013-12-03.log" is archived
144
- * - newLogFileName again returns "com.organization.myapp 2013-12-03.log",
145
- * file "com.organization.myapp 2013-12-03 2.log" would be created.
146
- * - after some time "com.organization.myapp 2013-12-03 1.log" is archived
147
- * - newLogFileName again returns "com.organization.myapp 2013-12-03.log",
148
- * file "com.organization.myapp 2013-12-03 3.log" would be created.
149
- **/
150
- - (NSString *)newLogFileName;
151
- - (BOOL)isLogFile:(NSString *)fileName;
152
-
153
- /* Inherited from DDLogFileManager protocol:
154
-
155
- @property (readwrite, assign) NSUInteger maximumNumberOfLogFiles;
156
-
157
- - (NSString *)logsDirectory;
158
-
159
- - (NSArray *)unsortedLogFilePaths;
160
- - (NSArray *)unsortedLogFileNames;
161
- - (NSArray *)unsortedLogFileInfos;
162
-
163
- - (NSArray *)sortedLogFilePaths;
164
- - (NSArray *)sortedLogFileNames;
165
- - (NSArray *)sortedLogFileInfos;
166
-
167
- */
168
-
169
- @end
170
-
171
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
172
- #pragma mark -
173
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
174
-
175
- /**
176
- * Most users will want file log messages to be prepended with the date and time.
177
- * Rather than forcing the majority of users to write their own formatter,
178
- * we will supply a logical default formatter.
179
- * Users can easily replace this formatter with their own by invoking the setLogFormatter method.
180
- * It can also be removed by calling setLogFormatter, and passing a nil parameter.
181
- *
182
- * In addition to the convenience of having a logical default formatter,
183
- * it will also provide a template that makes it easy for developers to copy and change.
184
- **/
185
- @interface DDLogFileFormatterDefault : NSObject <DDLogFormatter>
186
- {
187
- NSDateFormatter *dateFormatter;
188
- }
189
-
190
- - (id)init;
191
- - (instancetype)initWithDateFormatter:(NSDateFormatter *)dateFormatter;
192
-
193
- @end
194
-
195
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
196
- #pragma mark -
197
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
198
-
199
- @interface DDFileLogger : DDAbstractLogger <DDLogger>
200
- {
201
- __strong id <DDLogFileManager> logFileManager;
202
-
203
- DDLogFileInfo *currentLogFileInfo;
204
- NSFileHandle *currentLogFileHandle;
205
-
206
- dispatch_source_t currentLogFileVnode;
207
- dispatch_source_t rollingTimer;
208
-
209
- unsigned long long maximumFileSize;
210
- NSTimeInterval rollingFrequency;
211
- }
212
-
213
- - (id)init;
214
- - (instancetype)initWithLogFileManager:(id <DDLogFileManager>)logFileManager;
215
-
216
- /**
217
- * Log File Rolling:
218
- *
219
- * maximumFileSize:
220
- * The approximate maximum size to allow log files to grow.
221
- * If a log file is larger than this value after a log statement is appended,
222
- * then the log file is rolled.
223
- *
224
- * rollingFrequency
225
- * How often to roll the log file.
226
- * The frequency is given as an NSTimeInterval, which is a double that specifies the interval in seconds.
227
- * Once the log file gets to be this old, it is rolled.
228
- *
229
- * Both the maximumFileSize and the rollingFrequency are used to manage rolling.
230
- * Whichever occurs first will cause the log file to be rolled.
231
- *
232
- * For example:
233
- * The rollingFrequency is 24 hours,
234
- * but the log file surpasses the maximumFileSize after only 20 hours.
235
- * The log file will be rolled at that 20 hour mark.
236
- * A new log file will be created, and the 24 hour timer will be restarted.
237
- *
238
- * You may optionally disable rolling due to filesize by setting maximumFileSize to zero.
239
- * If you do so, rolling is based solely on rollingFrequency.
240
- *
241
- * You may optionally disable rolling due to time by setting rollingFrequency to zero (or any non-positive number).
242
- * If you do so, rolling is based solely on maximumFileSize.
243
- *
244
- * If you disable both maximumFileSize and rollingFrequency, then the log file won't ever be rolled.
245
- * This is strongly discouraged.
246
- **/
247
- @property (readwrite, assign) unsigned long long maximumFileSize;
248
- @property (readwrite, assign) NSTimeInterval rollingFrequency;
249
-
250
- /**
251
- * The DDLogFileManager instance can be used to retrieve the list of log files,
252
- * and configure the maximum number of archived log files to keep.
253
- *
254
- * @see DDLogFileManager.maximumNumberOfLogFiles
255
- **/
256
- @property (strong, nonatomic, readonly) id <DDLogFileManager> logFileManager;
257
-
258
-
259
- // You can optionally force the current log file to be rolled with this method.
260
- // CompletionBlock will be called on main queue.
261
-
262
- - (void)rollLogFileWithCompletionBlock:(void (^)())completionBlock;
263
-
264
- // Method is deprecated. Use rollLogFileWithCompletionBlock: method instead.
265
-
266
- - (void)rollLogFile __attribute((deprecated));
267
-
268
- // Inherited from DDAbstractLogger
269
-
270
- // - (id <DDLogFormatter>)logFormatter;
271
- // - (void)setLogFormatter:(id <DDLogFormatter>)formatter;
272
-
273
- @end
274
-
275
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
276
- #pragma mark -
277
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
278
-
279
- /**
280
- * DDLogFileInfo is a simple class that provides access to various file attributes.
281
- * It provides good performance as it only fetches the information if requested,
282
- * and it caches the information to prevent duplicate fetches.
283
- *
284
- * It was designed to provide quick snapshots of the current state of log files,
285
- * and to help sort log files in an array.
286
- *
287
- * This class does not monitor the files, or update it's cached attribute values if the file changes on disk.
288
- * This is not what the class was designed for.
289
- *
290
- * If you absolutely must get updated values,
291
- * you can invoke the reset method which will clear the cache.
292
- **/
293
- @interface DDLogFileInfo : NSObject
294
- {
295
- __strong NSString *filePath;
296
- __strong NSString *fileName;
297
-
298
- __strong NSDictionary *fileAttributes;
299
-
300
- __strong NSDate *creationDate;
301
- __strong NSDate *modificationDate;
302
-
303
- unsigned long long fileSize;
304
- }
305
-
306
- @property (strong, nonatomic, readonly) NSString *filePath;
307
- @property (strong, nonatomic, readonly) NSString *fileName;
308
-
309
- @property (strong, nonatomic, readonly) NSDictionary *fileAttributes;
310
-
311
- @property (strong, nonatomic, readonly) NSDate *creationDate;
312
- @property (strong, nonatomic, readonly) NSDate *modificationDate;
313
-
314
- @property (nonatomic, readonly) unsigned long long fileSize;
315
-
316
- @property (nonatomic, readonly) NSTimeInterval age;
317
-
318
- @property (nonatomic, readwrite) BOOL isArchived;
319
-
320
- + (instancetype)logFileWithPath:(NSString *)filePath;
321
-
322
- - (instancetype)initWithFilePath:(NSString *)filePath;
323
-
324
- - (void)reset;
325
- - (void)renameFile:(NSString *)newFileName;
326
-
327
- #if TARGET_IPHONE_SIMULATOR
328
-
329
- // So here's the situation.
330
- // Extended attributes are perfect for what we're trying to do here (marking files as archived).
331
- // This is exactly what extended attributes were designed for.
332
- //
333
- // But Apple screws us over on the simulator.
334
- // Everytime you build-and-go, they copy the application into a new folder on the hard drive,
335
- // and as part of the process they strip extended attributes from our log files.
336
- // Normally, a copy of a file preserves extended attributes.
337
- // So obviously Apple has gone to great lengths to piss us off.
338
- //
339
- // Thus we use a slightly different tactic for marking log files as archived in the simulator.
340
- // That way it "just works" and there's no confusion when testing.
341
- //
342
- // The difference in method names is indicative of the difference in functionality.
343
- // On the simulator we add an attribute by appending a filename extension.
344
- //
345
- // For example:
346
- // "mylog.txt" -> "mylog.archived.txt"
347
- // "mylog" -> "mylog.archived"
348
-
349
- - (BOOL)hasExtensionAttributeWithName:(NSString *)attrName;
350
-
351
- - (void)addExtensionAttributeWithName:(NSString *)attrName;
352
- - (void)removeExtensionAttributeWithName:(NSString *)attrName;
353
-
354
- #else
355
-
356
- // Normal use of extended attributes used everywhere else,
357
- // such as on Macs and on iPhone devices.
358
-
359
- - (BOOL)hasExtendedAttributeWithName:(NSString *)attrName;
360
-
361
- - (void)addExtendedAttributeWithName:(NSString *)attrName;
362
- - (void)removeExtendedAttributeWithName:(NSString *)attrName;
363
-
364
- #endif
365
-
366
- - (NSComparisonResult)reverseCompareByCreationDate:(DDLogFileInfo *)another;
367
- - (NSComparisonResult)reverseCompareByModificationDate:(DDLogFileInfo *)another;
368
-
369
- @end
@@ -1,1539 +0,0 @@
1
- #import "DDFileLogger.h"
2
-
3
- #import <unistd.h>
4
- #import <sys/attr.h>
5
- #import <sys/xattr.h>
6
- #import <libkern/OSAtomic.h>
7
-
8
- /**
9
- * Welcome to Cocoa Lumberjack!
10
- *
11
- * The project page has a wealth of documentation if you have any questions.
12
- * https://github.com/CocoaLumberjack/CocoaLumberjack
13
- *
14
- * If you're new to the project you may wish to read the "Getting Started" wiki.
15
- * https://github.com/CocoaLumberjack/CocoaLumberjack/wiki/GettingStarted
16
- **/
17
-
18
- #if ! __has_feature(objc_arc)
19
- #warning This file must be compiled with ARC. Use -fobjc-arc flag (or convert project to ARC).
20
- #endif
21
-
22
- // We probably shouldn't be using DDLog() statements within the DDLog implementation.
23
- // But we still want to leave our log statements for any future debugging,
24
- // and to allow other developers to trace the implementation (which is a great learning tool).
25
- //
26
- // So we use primitive logging macros around NSLog.
27
- // We maintain the NS prefix on the macros to be explicit about the fact that we're using NSLog.
28
-
29
- #define LOG_LEVEL 2
30
-
31
- #define NSLogError(frmt, ...) do{ if(LOG_LEVEL >= 1) NSLog((frmt), ##__VA_ARGS__); } while(0)
32
- #define NSLogWarn(frmt, ...) do{ if(LOG_LEVEL >= 2) NSLog((frmt), ##__VA_ARGS__); } while(0)
33
- #define NSLogInfo(frmt, ...) do{ if(LOG_LEVEL >= 3) NSLog((frmt), ##__VA_ARGS__); } while(0)
34
- #define NSLogDebug(frmt, ...) do{ if(LOG_LEVEL >= 4) NSLog((frmt), ##__VA_ARGS__); } while(0)
35
- #define NSLogVerbose(frmt, ...) do{ if(LOG_LEVEL >= 5) NSLog((frmt), ##__VA_ARGS__); } while(0)
36
-
37
- @interface DDLogFileManagerDefault (PrivateAPI)
38
-
39
- - (void)deleteOldLogFiles;
40
- - (NSString *)defaultLogsDirectory;
41
-
42
- @end
43
-
44
- @interface DDFileLogger (PrivateAPI)
45
-
46
- - (void)rollLogFileNow;
47
- - (void)maybeRollLogFileDueToAge;
48
- - (void)maybeRollLogFileDueToSize;
49
-
50
- @end
51
-
52
- #if TARGET_OS_IPHONE
53
- BOOL doesAppRunInBackground(void);
54
- #endif
55
-
56
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
57
- #pragma mark -
58
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
59
-
60
- @implementation DDLogFileManagerDefault
61
-
62
- @synthesize maximumNumberOfLogFiles;
63
-
64
- - (id)init
65
- {
66
- return [self initWithLogsDirectory:nil];
67
- }
68
-
69
- - (instancetype)initWithLogsDirectory:(NSString *)aLogsDirectory
70
- {
71
- if ((self = [super init]))
72
- {
73
- maximumNumberOfLogFiles = DEFAULT_LOG_MAX_NUM_LOG_FILES;
74
-
75
- if (aLogsDirectory)
76
- _logsDirectory = [aLogsDirectory copy];
77
- else
78
- _logsDirectory = [[self defaultLogsDirectory] copy];
79
-
80
- NSKeyValueObservingOptions kvoOptions = NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew;
81
-
82
- [self addObserver:self forKeyPath:NSStringFromSelector(@selector(maximumNumberOfLogFiles)) options:kvoOptions context:nil];
83
-
84
- NSLogVerbose(@"DDFileLogManagerDefault: logsDirectory:\n%@", [self logsDirectory]);
85
- NSLogVerbose(@"DDFileLogManagerDefault: sortedLogFileNames:\n%@", [self sortedLogFileNames]);
86
- }
87
- return self;
88
- }
89
-
90
- - (void)dealloc
91
- {
92
- // try-catch because the observer might be removed or never added. In this case, removeObserver throws and exception
93
- @try {
94
- [self removeObserver:self forKeyPath:NSStringFromSelector(@selector(maximumNumberOfLogFiles))];
95
- }
96
- @catch (NSException *exception) {
97
-
98
- }
99
- }
100
-
101
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
102
- #pragma mark Configuration
103
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
104
-
105
- - (void)observeValueForKeyPath:(NSString *)keyPath
106
- ofObject:(id)object
107
- change:(NSDictionary *)change
108
- context:(void *)context
109
- {
110
- NSNumber *old = [change objectForKey:NSKeyValueChangeOldKey];
111
- NSNumber *new = [change objectForKey:NSKeyValueChangeNewKey];
112
-
113
- if ([old isEqual:new])
114
- {
115
- // No change in value - don't bother with any processing.
116
- return;
117
- }
118
-
119
- if ([keyPath isEqualToString:NSStringFromSelector(@selector(maximumNumberOfLogFiles))])
120
- {
121
- NSLogInfo(@"DDFileLogManagerDefault: Responding to configuration change: maximumNumberOfLogFiles");
122
-
123
- dispatch_async([DDLog loggingQueue], ^{ @autoreleasepool {
124
-
125
- [self deleteOldLogFiles];
126
- }});
127
- }
128
- }
129
-
130
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
131
- #pragma mark File Deleting
132
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
133
-
134
- /**
135
- * Deletes archived log files that exceed the maximumNumberOfLogFiles configuration value.
136
- **/
137
- - (void)deleteOldLogFiles
138
- {
139
- NSLogVerbose(@"DDLogFileManagerDefault: deleteOldLogFiles");
140
-
141
- NSUInteger maxNumLogFiles = self.maximumNumberOfLogFiles;
142
- if (maxNumLogFiles == 0)
143
- {
144
- // Unlimited - don't delete any log files
145
- return;
146
- }
147
-
148
- NSArray *sortedLogFileInfos = [self sortedLogFileInfos];
149
-
150
- // Do we consider the first file?
151
- // We are only supposed to be deleting archived files.
152
- // In most cases, the first file is likely the log file that is currently being written to.
153
- // So in most cases, we do not want to consider this file for deletion.
154
-
155
- NSUInteger count = [sortedLogFileInfos count];
156
- BOOL excludeFirstFile = NO;
157
-
158
- if (count > 0)
159
- {
160
- DDLogFileInfo *logFileInfo = [sortedLogFileInfos objectAtIndex:0];
161
-
162
- if (!logFileInfo.isArchived)
163
- {
164
- excludeFirstFile = YES;
165
- }
166
- }
167
-
168
- NSArray *sortedArchivedLogFileInfos;
169
- if (excludeFirstFile)
170
- {
171
- count--;
172
- sortedArchivedLogFileInfos = [sortedLogFileInfos subarrayWithRange:NSMakeRange(1, count)];
173
- }
174
- else
175
- {
176
- sortedArchivedLogFileInfos = sortedLogFileInfos;
177
- }
178
-
179
- NSUInteger i;
180
- for (i = maxNumLogFiles; i < count; i++)
181
- {
182
- DDLogFileInfo *logFileInfo = [sortedArchivedLogFileInfos objectAtIndex:i];
183
-
184
- NSLogInfo(@"DDLogFileManagerDefault: Deleting file: %@", logFileInfo.fileName);
185
-
186
- [[NSFileManager defaultManager] removeItemAtPath:logFileInfo.filePath error:nil];
187
- }
188
- }
189
-
190
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
191
- #pragma mark Log Files
192
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
193
-
194
- /**
195
- * Returns the path to the default logs directory.
196
- * If the logs directory doesn't exist, this method automatically creates it.
197
- **/
198
- - (NSString *)defaultLogsDirectory
199
- {
200
- #if TARGET_OS_IPHONE
201
- NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
202
- NSString *baseDir = ([paths count] > 0) ? [paths objectAtIndex:0] : nil;
203
- NSString *logsDirectory = [baseDir stringByAppendingPathComponent:@"Logs"];
204
-
205
- #else
206
- NSString *appName = [[NSProcessInfo processInfo] processName];
207
- NSArray *paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES);
208
- NSString *basePath = ([paths count] > 0) ? [paths objectAtIndex:0] : NSTemporaryDirectory();
209
- NSString *logsDirectory = [[basePath stringByAppendingPathComponent:@"Logs"] stringByAppendingPathComponent:appName];
210
-
211
- #endif
212
-
213
- return logsDirectory;
214
- }
215
-
216
- - (NSString *)logsDirectory
217
- {
218
- // We could do this check once, during initalization, and not bother again.
219
- // But this way the code continues to work if the directory gets deleted while the code is running.
220
-
221
- if (![[NSFileManager defaultManager] fileExistsAtPath:_logsDirectory])
222
- {
223
- NSError *err = nil;
224
- if (![[NSFileManager defaultManager] createDirectoryAtPath:_logsDirectory
225
- withIntermediateDirectories:YES attributes:nil error:&err])
226
- {
227
- NSLogError(@"DDFileLogManagerDefault: Error creating logsDirectory: %@", err);
228
- }
229
- }
230
-
231
- return _logsDirectory;
232
- }
233
-
234
- /**
235
- * Default log file name is "<bundle identifier> <date> <time>.log".
236
- * Example: MobileSafari 2013-12-03 17-14.log
237
- *
238
- * You can change it by overriding newLogFileName and isLogFile: methods.
239
- **/
240
- - (BOOL)isLogFile:(NSString *)fileName
241
- {
242
- NSString *appName = [self applicationName];
243
-
244
- BOOL hasProperPrefix = [fileName hasPrefix:appName];
245
- BOOL hasProperSuffix = [fileName hasSuffix:@".log"];
246
- BOOL hasProperDate = NO;
247
-
248
- if (hasProperPrefix && hasProperSuffix)
249
- {
250
- NSUInteger lengthOfMiddle = fileName.length - appName.length - @".log".length;
251
-
252
- // Date string should have at least 16 characters - " 2013-12-03 17-14"
253
- if (lengthOfMiddle >= 17)
254
- {
255
- NSRange range = NSMakeRange(appName.length, lengthOfMiddle);
256
-
257
- NSString *middle = [fileName substringWithRange:range];
258
- NSArray *components = [middle componentsSeparatedByString:@" "];
259
-
260
- // When creating logfile if there is existing file with the same name, we append attemp number at the end.
261
- // Thats why here we can have three or four components. For details see createNewLogFile method.
262
- //
263
- // Components:
264
- // "", "2013-12-03", "17-14"
265
- // or
266
- // "", "2013-12-03", "17-14", "1"
267
- if (components.count == 3 || components.count == 4)
268
- {
269
- NSString *dateString = [NSString stringWithFormat:@"%@ %@", components[1], components[2]];
270
- NSDateFormatter *dateFormatter = [self logFileDateFormatter];
271
-
272
- NSDate *date = [dateFormatter dateFromString:dateString];
273
-
274
- if (date)
275
- {
276
- hasProperDate = YES;
277
- }
278
- }
279
- }
280
- }
281
-
282
- return (hasProperPrefix && hasProperDate && hasProperSuffix);
283
- }
284
-
285
- - (NSDateFormatter *)logFileDateFormatter
286
- {
287
- NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
288
- [dateFormatter setDateFormat:@"yyyy'-'MM'-'dd' 'HH'-'mm'"];
289
- [dateFormatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]];
290
-
291
- return dateFormatter;
292
- }
293
-
294
- /**
295
- * Returns an array of NSString objects,
296
- * each of which is the filePath to an existing log file on disk.
297
- **/
298
- - (NSArray *)unsortedLogFilePaths
299
- {
300
- NSString *logsDirectory = [self logsDirectory];
301
- NSArray *fileNames = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:logsDirectory error:nil];
302
-
303
- NSMutableArray *unsortedLogFilePaths = [NSMutableArray arrayWithCapacity:[fileNames count]];
304
-
305
- for (NSString *fileName in fileNames)
306
- {
307
- // Filter out any files that aren't log files. (Just for extra safety)
308
-
309
- #if TARGET_IPHONE_SIMULATOR
310
- // In case of iPhone simulator there can be 'archived' extension. isLogFile:
311
- // method knows nothing about it. Thus removing it for this method.
312
- //
313
- // See full explanation in the header file.
314
- NSString *theFileName = [fileName stringByReplacingOccurrencesOfString:@".archived"
315
- withString:@""];
316
-
317
- if ([self isLogFile:theFileName])
318
- #else
319
- if ([self isLogFile:fileName])
320
- #endif
321
- {
322
- NSString *filePath = [logsDirectory stringByAppendingPathComponent:fileName];
323
-
324
- [unsortedLogFilePaths addObject:filePath];
325
- }
326
- }
327
-
328
- return unsortedLogFilePaths;
329
- }
330
-
331
- /**
332
- * Returns an array of NSString objects,
333
- * each of which is the fileName of an existing log file on disk.
334
- **/
335
- - (NSArray *)unsortedLogFileNames
336
- {
337
- NSArray *unsortedLogFilePaths = [self unsortedLogFilePaths];
338
-
339
- NSMutableArray *unsortedLogFileNames = [NSMutableArray arrayWithCapacity:[unsortedLogFilePaths count]];
340
-
341
- for (NSString *filePath in unsortedLogFilePaths)
342
- {
343
- [unsortedLogFileNames addObject:[filePath lastPathComponent]];
344
- }
345
-
346
- return unsortedLogFileNames;
347
- }
348
-
349
- /**
350
- * Returns an array of DDLogFileInfo objects,
351
- * each representing an existing log file on disk,
352
- * and containing important information about the log file such as it's modification date and size.
353
- **/
354
- - (NSArray *)unsortedLogFileInfos
355
- {
356
- NSArray *unsortedLogFilePaths = [self unsortedLogFilePaths];
357
-
358
- NSMutableArray *unsortedLogFileInfos = [NSMutableArray arrayWithCapacity:[unsortedLogFilePaths count]];
359
-
360
- for (NSString *filePath in unsortedLogFilePaths)
361
- {
362
- DDLogFileInfo *logFileInfo = [[DDLogFileInfo alloc] initWithFilePath:filePath];
363
-
364
- [unsortedLogFileInfos addObject:logFileInfo];
365
- }
366
-
367
- return unsortedLogFileInfos;
368
- }
369
-
370
- /**
371
- * Just like the unsortedLogFilePaths method, but sorts the array.
372
- * The items in the array are sorted by creation date.
373
- * The first item in the array will be the most recently created log file.
374
- **/
375
- - (NSArray *)sortedLogFilePaths
376
- {
377
- NSArray *sortedLogFileInfos = [self sortedLogFileInfos];
378
-
379
- NSMutableArray *sortedLogFilePaths = [NSMutableArray arrayWithCapacity:[sortedLogFileInfos count]];
380
-
381
- for (DDLogFileInfo *logFileInfo in sortedLogFileInfos)
382
- {
383
- [sortedLogFilePaths addObject:[logFileInfo filePath]];
384
- }
385
-
386
- return sortedLogFilePaths;
387
- }
388
-
389
- /**
390
- * Just like the unsortedLogFileNames method, but sorts the array.
391
- * The items in the array are sorted by creation date.
392
- * The first item in the array will be the most recently created log file.
393
- **/
394
- - (NSArray *)sortedLogFileNames
395
- {
396
- NSArray *sortedLogFileInfos = [self sortedLogFileInfos];
397
-
398
- NSMutableArray *sortedLogFileNames = [NSMutableArray arrayWithCapacity:[sortedLogFileInfos count]];
399
-
400
- for (DDLogFileInfo *logFileInfo in sortedLogFileInfos)
401
- {
402
- [sortedLogFileNames addObject:[logFileInfo fileName]];
403
- }
404
-
405
- return sortedLogFileNames;
406
- }
407
-
408
- /**
409
- * Just like the unsortedLogFileInfos method, but sorts the array.
410
- * The items in the array are sorted by creation date.
411
- * The first item in the array will be the most recently created log file.
412
- **/
413
- - (NSArray *)sortedLogFileInfos
414
- {
415
- return [[self unsortedLogFileInfos] sortedArrayUsingSelector:@selector(reverseCompareByCreationDate:)];
416
- }
417
-
418
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
419
- #pragma mark Creation
420
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
421
-
422
- /**
423
- * Generates log file name with default format "<bundle identifier> <date> <time>.log"
424
- * Example: MobileSafari 2013-12-03 17-14.log
425
- *
426
- * You can change it by overriding newLogFileName and isLogFile: methods.
427
- **/
428
- - (NSString *)newLogFileName
429
- {
430
- NSString *appName = [self applicationName];
431
-
432
- NSDateFormatter *dateFormatter = [self logFileDateFormatter];
433
- NSString *formattedDate = [dateFormatter stringFromDate:[NSDate date]];
434
-
435
- return [NSString stringWithFormat:@"%@ %@.log", appName, formattedDate];
436
- }
437
-
438
- /**
439
- * Generates a new unique log file path, and creates the corresponding log file.
440
- **/
441
- - (NSString *)createNewLogFile
442
- {
443
- NSString *fileName = [self newLogFileName];
444
- NSString *logsDirectory = [self logsDirectory];
445
-
446
- NSUInteger attempt = 1;
447
- do
448
- {
449
- NSString *actualFileName = fileName;
450
-
451
- if (attempt > 1) {
452
- NSString *extension = [actualFileName pathExtension];
453
-
454
- actualFileName = [actualFileName stringByDeletingPathExtension];
455
- actualFileName = [actualFileName stringByAppendingFormat:@" %lu", (unsigned long)attempt];
456
- if (extension.length) {
457
- actualFileName = [actualFileName stringByAppendingPathExtension:extension];
458
- }
459
- }
460
-
461
- NSString *filePath = [logsDirectory stringByAppendingPathComponent:actualFileName];
462
-
463
- if (![[NSFileManager defaultManager] fileExistsAtPath:filePath])
464
- {
465
- NSLogVerbose(@"DDLogFileManagerDefault: Creating new log file: %@", actualFileName);
466
-
467
- NSDictionary *attributes = nil;
468
-
469
- #if TARGET_OS_IPHONE
470
- // When creating log file on iOS we're setting NSFileProtectionKey attribute to NSFileProtectionCompleteUnlessOpen.
471
- //
472
- // But in case if app is able to launch from background we need to have an ability to open log file any time we
473
- // want (even if device is locked). Thats why that attribute have to be changed to
474
- // NSFileProtectionCompleteUntilFirstUserAuthentication.
475
-
476
- NSString *key = doesAppRunInBackground() ?
477
- NSFileProtectionCompleteUntilFirstUserAuthentication : NSFileProtectionCompleteUnlessOpen;
478
-
479
- attributes = @{ NSFileProtectionKey : key };
480
- #endif
481
-
482
- [[NSFileManager defaultManager] createFileAtPath:filePath contents:nil attributes:attributes];
483
-
484
- // Since we just created a new log file, we may need to delete some old log files
485
- [self deleteOldLogFiles];
486
-
487
- return filePath;
488
- } else {
489
- attempt++;
490
- }
491
-
492
- } while(YES);
493
- }
494
-
495
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
496
- #pragma mark Utility
497
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
498
-
499
- - (NSString *)applicationName
500
- {
501
- static NSString *_appName;
502
- static dispatch_once_t onceToken;
503
-
504
- dispatch_once(&onceToken, ^{
505
- _appName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleIdentifier"];
506
-
507
- if (! _appName)
508
- {
509
- _appName = [[NSProcessInfo processInfo] processName];
510
- }
511
-
512
- if (! _appName)
513
- {
514
- _appName = @"";
515
- }
516
- });
517
-
518
- return _appName;
519
- }
520
-
521
- @end
522
-
523
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
524
- #pragma mark -
525
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
526
-
527
- @implementation DDLogFileFormatterDefault
528
-
529
- - (id)init
530
- {
531
- return [self initWithDateFormatter:nil];
532
- }
533
-
534
- - (instancetype)initWithDateFormatter:(NSDateFormatter *)aDateFormatter
535
- {
536
- if ((self = [super init]))
537
- {
538
- if (aDateFormatter)
539
- {
540
- dateFormatter = aDateFormatter;
541
- }
542
- else
543
- {
544
- dateFormatter = [[NSDateFormatter alloc] init];
545
- [dateFormatter setFormatterBehavior:NSDateFormatterBehavior10_4]; // 10.4+ style
546
- [dateFormatter setDateFormat:@"yyyy/MM/dd HH:mm:ss:SSS"];
547
- }
548
- }
549
- return self;
550
- }
551
-
552
- - (NSString *)formatLogMessage:(DDLogMessage *)logMessage
553
- {
554
- NSString *dateAndTime = [dateFormatter stringFromDate:(logMessage->timestamp)];
555
-
556
- return [NSString stringWithFormat:@"%@ %@", dateAndTime, logMessage->logMsg];
557
- }
558
-
559
- @end
560
-
561
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
562
- #pragma mark -
563
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
564
-
565
- @implementation DDFileLogger
566
-
567
- - (id)init
568
- {
569
- DDLogFileManagerDefault *defaultLogFileManager = [[DDLogFileManagerDefault alloc] init];
570
-
571
- return [self initWithLogFileManager:defaultLogFileManager];
572
- }
573
-
574
- - (instancetype)initWithLogFileManager:(id <DDLogFileManager>)aLogFileManager
575
- {
576
- if ((self = [super init]))
577
- {
578
- maximumFileSize = DEFAULT_LOG_MAX_FILE_SIZE;
579
- rollingFrequency = DEFAULT_LOG_ROLLING_FREQUENCY;
580
-
581
- logFileManager = aLogFileManager;
582
-
583
- formatter = [[DDLogFileFormatterDefault alloc] init];
584
- }
585
- return self;
586
- }
587
-
588
- - (void)dealloc
589
- {
590
- [currentLogFileHandle synchronizeFile];
591
- [currentLogFileHandle closeFile];
592
-
593
- if (currentLogFileVnode) {
594
- dispatch_source_cancel(currentLogFileVnode);
595
- currentLogFileVnode = NULL;
596
- }
597
-
598
- if (rollingTimer)
599
- {
600
- dispatch_source_cancel(rollingTimer);
601
- rollingTimer = NULL;
602
- }
603
- }
604
-
605
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
606
- #pragma mark Properties
607
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
608
-
609
- @synthesize logFileManager;
610
-
611
- - (unsigned long long)maximumFileSize
612
- {
613
- __block unsigned long long result;
614
-
615
- dispatch_block_t block = ^{
616
- result = maximumFileSize;
617
- };
618
-
619
- // The design of this method is taken from the DDAbstractLogger implementation.
620
- // For extensive documentation please refer to the DDAbstractLogger implementation.
621
-
622
- // Note: The internal implementation MUST access the maximumFileSize variable directly,
623
- // This method is designed explicitly for external access.
624
- //
625
- // Using "self." syntax to go through this method will cause immediate deadlock.
626
- // This is the intended result. Fix it by accessing the ivar directly.
627
- // Great strides have been take to ensure this is safe to do. Plus it's MUCH faster.
628
-
629
- NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
630
- NSAssert(![self isOnInternalLoggerQueue], @"MUST access ivar directly, NOT via self.* syntax.");
631
-
632
- dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
633
-
634
- dispatch_sync(globalLoggingQueue, ^{
635
- dispatch_sync(loggerQueue, block);
636
- });
637
-
638
- return result;
639
- }
640
-
641
- - (void)setMaximumFileSize:(unsigned long long)newMaximumFileSize
642
- {
643
- dispatch_block_t block = ^{ @autoreleasepool {
644
-
645
- maximumFileSize = newMaximumFileSize;
646
- [self maybeRollLogFileDueToSize];
647
-
648
- }};
649
-
650
- // The design of this method is taken from the DDAbstractLogger implementation.
651
- // For extensive documentation please refer to the DDAbstractLogger implementation.
652
-
653
- // Note: The internal implementation MUST access the maximumFileSize variable directly,
654
- // This method is designed explicitly for external access.
655
- //
656
- // Using "self." syntax to go through this method will cause immediate deadlock.
657
- // This is the intended result. Fix it by accessing the ivar directly.
658
- // Great strides have been take to ensure this is safe to do. Plus it's MUCH faster.
659
-
660
- NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
661
- NSAssert(![self isOnInternalLoggerQueue], @"MUST access ivar directly, NOT via self.* syntax.");
662
-
663
- dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
664
-
665
- dispatch_async(globalLoggingQueue, ^{
666
- dispatch_async(loggerQueue, block);
667
- });
668
- }
669
-
670
- - (NSTimeInterval)rollingFrequency
671
- {
672
- __block NSTimeInterval result;
673
-
674
- dispatch_block_t block = ^{
675
- result = rollingFrequency;
676
- };
677
-
678
- // The design of this method is taken from the DDAbstractLogger implementation.
679
- // For extensive documentation please refer to the DDAbstractLogger implementation.
680
-
681
- // Note: The internal implementation should access the rollingFrequency variable directly,
682
- // This method is designed explicitly for external access.
683
- //
684
- // Using "self." syntax to go through this method will cause immediate deadlock.
685
- // This is the intended result. Fix it by accessing the ivar directly.
686
- // Great strides have been take to ensure this is safe to do. Plus it's MUCH faster.
687
-
688
- NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
689
- NSAssert(![self isOnInternalLoggerQueue], @"MUST access ivar directly, NOT via self.* syntax.");
690
-
691
- dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
692
-
693
- dispatch_sync(globalLoggingQueue, ^{
694
- dispatch_sync(loggerQueue, block);
695
- });
696
-
697
- return result;
698
- }
699
-
700
- - (void)setRollingFrequency:(NSTimeInterval)newRollingFrequency
701
- {
702
- dispatch_block_t block = ^{ @autoreleasepool {
703
-
704
- rollingFrequency = newRollingFrequency;
705
- [self maybeRollLogFileDueToAge];
706
- }};
707
-
708
- // The design of this method is taken from the DDAbstractLogger implementation.
709
- // For extensive documentation please refer to the DDAbstractLogger implementation.
710
-
711
- // Note: The internal implementation should access the rollingFrequency variable directly,
712
- // This method is designed explicitly for external access.
713
- //
714
- // Using "self." syntax to go through this method will cause immediate deadlock.
715
- // This is the intended result. Fix it by accessing the ivar directly.
716
- // Great strides have been take to ensure this is safe to do. Plus it's MUCH faster.
717
-
718
- NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
719
- NSAssert(![self isOnInternalLoggerQueue], @"MUST access ivar directly, NOT via self.* syntax.");
720
-
721
- dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
722
-
723
- dispatch_async(globalLoggingQueue, ^{
724
- dispatch_async(loggerQueue, block);
725
- });
726
- }
727
-
728
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
729
- #pragma mark File Rolling
730
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
731
-
732
- - (void)scheduleTimerToRollLogFileDueToAge
733
- {
734
- if (rollingTimer)
735
- {
736
- dispatch_source_cancel(rollingTimer);
737
- rollingTimer = NULL;
738
- }
739
-
740
- if (currentLogFileInfo == nil || rollingFrequency <= 0.0)
741
- {
742
- return;
743
- }
744
-
745
- NSDate *logFileCreationDate = [currentLogFileInfo creationDate];
746
-
747
- NSTimeInterval ti = [logFileCreationDate timeIntervalSinceReferenceDate];
748
- ti += rollingFrequency;
749
-
750
- NSDate *logFileRollingDate = [NSDate dateWithTimeIntervalSinceReferenceDate:ti];
751
-
752
- NSLogVerbose(@"DDFileLogger: scheduleTimerToRollLogFileDueToAge");
753
-
754
- NSLogVerbose(@"DDFileLogger: logFileCreationDate: %@", logFileCreationDate);
755
- NSLogVerbose(@"DDFileLogger: logFileRollingDate : %@", logFileRollingDate);
756
-
757
- rollingTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, loggerQueue);
758
-
759
- dispatch_source_set_event_handler(rollingTimer, ^{ @autoreleasepool {
760
-
761
- [self maybeRollLogFileDueToAge];
762
-
763
- }});
764
-
765
- #if !OS_OBJECT_USE_OBJC
766
- dispatch_source_t theRollingTimer = rollingTimer;
767
- dispatch_source_set_cancel_handler(rollingTimer, ^{
768
- dispatch_release(theRollingTimer);
769
- });
770
- #endif
771
-
772
- uint64_t delay = (uint64_t)([logFileRollingDate timeIntervalSinceNow] * NSEC_PER_SEC);
773
- dispatch_time_t fireTime = dispatch_time(DISPATCH_TIME_NOW, delay);
774
-
775
- dispatch_source_set_timer(rollingTimer, fireTime, DISPATCH_TIME_FOREVER, 1.0);
776
- dispatch_resume(rollingTimer);
777
- }
778
-
779
-
780
- - (void)rollLogFile
781
- {
782
- [self rollLogFileWithCompletionBlock:nil];
783
- }
784
-
785
- - (void)rollLogFileWithCompletionBlock:(void (^)())completionBlock
786
- {
787
- // This method is public.
788
- // We need to execute the rolling on our logging thread/queue.
789
-
790
- dispatch_block_t block = ^{ @autoreleasepool {
791
-
792
- [self rollLogFileNow];
793
-
794
- if (completionBlock)
795
- {
796
- dispatch_async(dispatch_get_main_queue(), ^{
797
- completionBlock();
798
- });
799
- }
800
- }};
801
-
802
- // The design of this method is taken from the DDAbstractLogger implementation.
803
- // For extensive documentation please refer to the DDAbstractLogger implementation.
804
-
805
- if ([self isOnInternalLoggerQueue])
806
- {
807
- block();
808
- }
809
- else
810
- {
811
- dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
812
- NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
813
-
814
- dispatch_async(globalLoggingQueue, ^{
815
- dispatch_async(loggerQueue, block);
816
- });
817
- }
818
- }
819
-
820
- - (void)rollLogFileNow
821
- {
822
- NSLogVerbose(@"DDFileLogger: rollLogFileNow");
823
-
824
-
825
- if (currentLogFileHandle == nil) return;
826
-
827
- [currentLogFileHandle synchronizeFile];
828
- [currentLogFileHandle closeFile];
829
- currentLogFileHandle = nil;
830
-
831
- currentLogFileInfo.isArchived = YES;
832
-
833
- if ([logFileManager respondsToSelector:@selector(didRollAndArchiveLogFile:)])
834
- {
835
- [logFileManager didRollAndArchiveLogFile:(currentLogFileInfo.filePath)];
836
- }
837
-
838
- currentLogFileInfo = nil;
839
-
840
- if (currentLogFileVnode) {
841
- dispatch_source_cancel(currentLogFileVnode);
842
- currentLogFileVnode = NULL;
843
- }
844
-
845
- if (rollingTimer)
846
- {
847
- dispatch_source_cancel(rollingTimer);
848
- rollingTimer = NULL;
849
- }
850
- }
851
-
852
- - (void)maybeRollLogFileDueToAge
853
- {
854
- if (rollingFrequency > 0.0 && currentLogFileInfo.age >= rollingFrequency)
855
- {
856
- NSLogVerbose(@"DDFileLogger: Rolling log file due to age...");
857
-
858
- [self rollLogFileNow];
859
- }
860
- else
861
- {
862
- [self scheduleTimerToRollLogFileDueToAge];
863
- }
864
- }
865
-
866
- - (void)maybeRollLogFileDueToSize
867
- {
868
- // This method is called from logMessage.
869
- // Keep it FAST.
870
-
871
- // Note: Use direct access to maximumFileSize variable.
872
- // We specifically wrote our own getter/setter method to allow us to do this (for performance reasons).
873
-
874
- if (maximumFileSize > 0)
875
- {
876
- unsigned long long fileSize = [currentLogFileHandle offsetInFile];
877
-
878
- if (fileSize >= maximumFileSize)
879
- {
880
- NSLogVerbose(@"DDFileLogger: Rolling log file due to size (%qu)...", fileSize);
881
-
882
- [self rollLogFileNow];
883
- }
884
- }
885
- }
886
-
887
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
888
- #pragma mark File Logging
889
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
890
-
891
- /**
892
- * Returns the log file that should be used.
893
- * If there is an existing log file that is suitable,
894
- * within the constraints of maximumFileSize and rollingFrequency, then it is returned.
895
- *
896
- * Otherwise a new file is created and returned.
897
- **/
898
- - (DDLogFileInfo *)currentLogFileInfo
899
- {
900
- if (currentLogFileInfo == nil)
901
- {
902
- NSArray *sortedLogFileInfos = [logFileManager sortedLogFileInfos];
903
-
904
- if ([sortedLogFileInfos count] > 0)
905
- {
906
- DDLogFileInfo *mostRecentLogFileInfo = [sortedLogFileInfos objectAtIndex:0];
907
-
908
- BOOL useExistingLogFile = YES;
909
- BOOL shouldArchiveMostRecent = NO;
910
-
911
- if (mostRecentLogFileInfo.isArchived)
912
- {
913
- useExistingLogFile = NO;
914
- shouldArchiveMostRecent = NO;
915
- }
916
- else if (maximumFileSize > 0 && mostRecentLogFileInfo.fileSize >= maximumFileSize)
917
- {
918
- useExistingLogFile = NO;
919
- shouldArchiveMostRecent = YES;
920
- }
921
- else if (rollingFrequency > 0.0 && mostRecentLogFileInfo.age >= rollingFrequency)
922
- {
923
- useExistingLogFile = NO;
924
- shouldArchiveMostRecent = YES;
925
- }
926
-
927
-
928
- #if TARGET_OS_IPHONE
929
- // When creating log file on iOS we're setting NSFileProtectionKey attribute to NSFileProtectionCompleteUnlessOpen.
930
- //
931
- // But in case if app is able to launch from background we need to have an ability to open log file any time we
932
- // want (even if device is locked). Thats why that attribute have to be changed to
933
- // NSFileProtectionCompleteUntilFirstUserAuthentication.
934
- //
935
- // If previous log was created when app wasn't running in background, but now it is - we archive it and create
936
- // a new one.
937
-
938
- if (useExistingLogFile && doesAppRunInBackground()) {
939
- NSString *key = mostRecentLogFileInfo.fileAttributes[NSFileProtectionKey];
940
-
941
- if (! [key isEqualToString:NSFileProtectionCompleteUntilFirstUserAuthentication]) {
942
- useExistingLogFile = NO;
943
- shouldArchiveMostRecent = YES;
944
- }
945
- }
946
- #endif
947
-
948
- if (useExistingLogFile)
949
- {
950
- NSLogVerbose(@"DDFileLogger: Resuming logging with file %@", mostRecentLogFileInfo.fileName);
951
-
952
- currentLogFileInfo = mostRecentLogFileInfo;
953
- }
954
- else
955
- {
956
- if (shouldArchiveMostRecent)
957
- {
958
- mostRecentLogFileInfo.isArchived = YES;
959
-
960
- if ([logFileManager respondsToSelector:@selector(didArchiveLogFile:)])
961
- {
962
- [logFileManager didArchiveLogFile:(mostRecentLogFileInfo.filePath)];
963
- }
964
- }
965
- }
966
- }
967
-
968
- if (currentLogFileInfo == nil)
969
- {
970
- NSString *currentLogFilePath = [logFileManager createNewLogFile];
971
-
972
- currentLogFileInfo = [[DDLogFileInfo alloc] initWithFilePath:currentLogFilePath];
973
- }
974
- }
975
-
976
- return currentLogFileInfo;
977
- }
978
-
979
- - (NSFileHandle *)currentLogFileHandle
980
- {
981
- if (currentLogFileHandle == nil)
982
- {
983
- NSString *logFilePath = [[self currentLogFileInfo] filePath];
984
-
985
- currentLogFileHandle = [NSFileHandle fileHandleForWritingAtPath:logFilePath];
986
- [currentLogFileHandle seekToEndOfFile];
987
-
988
- if (currentLogFileHandle)
989
- {
990
- [self scheduleTimerToRollLogFileDueToAge];
991
-
992
- // Here we are monitoring the log file. In case if it would be deleted ormoved
993
- // somewhere we want to roll it and use a new one.
994
- currentLogFileVnode = dispatch_source_create(
995
- DISPATCH_SOURCE_TYPE_VNODE,
996
- [currentLogFileHandle fileDescriptor],
997
- DISPATCH_VNODE_DELETE | DISPATCH_VNODE_RENAME,
998
- loggerQueue
999
- );
1000
-
1001
- dispatch_source_set_event_handler(currentLogFileVnode, ^{ @autoreleasepool {
1002
- NSLogInfo(@"DDFileLogger: Current logfile was moved. Rolling it and creating a new one");
1003
- [self rollLogFileNow];
1004
- }});
1005
-
1006
- #if !OS_OBJECT_USE_OBJC
1007
- dispatch_source_t vnode = currentLogFileVnode;
1008
- dispatch_source_set_cancel_handler(currentLogFileVnode, ^{
1009
- dispatch_release(vnode);
1010
- });
1011
- #endif
1012
-
1013
- dispatch_resume(currentLogFileVnode);
1014
- }
1015
- }
1016
-
1017
- return currentLogFileHandle;
1018
- }
1019
-
1020
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1021
- #pragma mark DDLogger Protocol
1022
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1023
-
1024
- static int exception_count = 0;
1025
- - (void)logMessage:(DDLogMessage *)logMessage
1026
- {
1027
- NSString *logMsg = logMessage->logMsg;
1028
-
1029
- if (formatter)
1030
- {
1031
- logMsg = [formatter formatLogMessage:logMessage];
1032
- }
1033
-
1034
- if (logMsg)
1035
- {
1036
- if (![logMsg hasSuffix:@"\n"])
1037
- {
1038
- logMsg = [logMsg stringByAppendingString:@"\n"];
1039
- }
1040
-
1041
- NSData *logData = [logMsg dataUsingEncoding:NSUTF8StringEncoding];
1042
-
1043
- @try {
1044
- [[self currentLogFileHandle] writeData:logData];
1045
-
1046
- [self maybeRollLogFileDueToSize];
1047
- }
1048
- @catch (NSException *exception) {
1049
- exception_count++;
1050
- if (exception_count <= 10) {
1051
- NSLogError(@"DDFileLogger.logMessage: %@", exception);
1052
- if (exception_count == 10)
1053
- NSLogError(@"DDFileLogger.logMessage: Too many exceptions -- will not log any more of them.");
1054
- }
1055
- }
1056
- }
1057
- }
1058
-
1059
- - (void)willRemoveLogger
1060
- {
1061
- // If you override me be sure to invoke [super willRemoveLogger];
1062
-
1063
- [self rollLogFileNow];
1064
- }
1065
-
1066
- - (NSString *)loggerName
1067
- {
1068
- return @"cocoa.lumberjack.fileLogger";
1069
- }
1070
-
1071
- @end
1072
-
1073
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1074
- #pragma mark -
1075
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1076
-
1077
- #if TARGET_IPHONE_SIMULATOR
1078
- #define XATTR_ARCHIVED_NAME @"archived"
1079
- #else
1080
- #define XATTR_ARCHIVED_NAME @"lumberjack.log.archived"
1081
- #endif
1082
-
1083
- @implementation DDLogFileInfo
1084
-
1085
- @synthesize filePath;
1086
-
1087
- @dynamic fileName;
1088
- @dynamic fileAttributes;
1089
- @dynamic creationDate;
1090
- @dynamic modificationDate;
1091
- @dynamic fileSize;
1092
- @dynamic age;
1093
-
1094
- @dynamic isArchived;
1095
-
1096
-
1097
- #pragma mark Lifecycle
1098
-
1099
- + (instancetype)logFileWithPath:(NSString *)aFilePath
1100
- {
1101
- return [[self alloc] initWithFilePath:aFilePath];
1102
- }
1103
-
1104
- - (instancetype)initWithFilePath:(NSString *)aFilePath
1105
- {
1106
- if ((self = [super init]))
1107
- {
1108
- filePath = [aFilePath copy];
1109
- }
1110
- return self;
1111
- }
1112
-
1113
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1114
- #pragma mark Standard Info
1115
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1116
-
1117
- - (NSDictionary *)fileAttributes
1118
- {
1119
- if (fileAttributes == nil)
1120
- {
1121
- fileAttributes = [[NSFileManager defaultManager] attributesOfItemAtPath:filePath error:nil];
1122
- }
1123
- return fileAttributes;
1124
- }
1125
-
1126
- - (NSString *)fileName
1127
- {
1128
- if (fileName == nil)
1129
- {
1130
- fileName = [filePath lastPathComponent];
1131
- }
1132
- return fileName;
1133
- }
1134
-
1135
- - (NSDate *)modificationDate
1136
- {
1137
- if (modificationDate == nil)
1138
- {
1139
- modificationDate = [[self fileAttributes] objectForKey:NSFileModificationDate];
1140
- }
1141
-
1142
- return modificationDate;
1143
- }
1144
-
1145
- - (NSDate *)creationDate
1146
- {
1147
- if (creationDate == nil)
1148
- {
1149
- creationDate = [[self fileAttributes] objectForKey:NSFileCreationDate];
1150
- }
1151
- return creationDate;
1152
- }
1153
-
1154
- - (unsigned long long)fileSize
1155
- {
1156
- if (fileSize == 0)
1157
- {
1158
- fileSize = [[[self fileAttributes] objectForKey:NSFileSize] unsignedLongLongValue];
1159
- }
1160
-
1161
- return fileSize;
1162
- }
1163
-
1164
- - (NSTimeInterval)age
1165
- {
1166
- return [[self creationDate] timeIntervalSinceNow] * -1.0;
1167
- }
1168
-
1169
- - (NSString *)description
1170
- {
1171
- return [@{@"filePath": self.filePath ?: @"",
1172
- @"fileName": self.fileName ?: @"",
1173
- @"fileAttributes": self.fileAttributes ?: @"",
1174
- @"creationDate": self.creationDate ?: @"",
1175
- @"modificationDate": self.modificationDate ?: @"",
1176
- @"fileSize": @(self.fileSize),
1177
- @"age": @(self.age),
1178
- @"isArchived": @(self.isArchived)} description];
1179
- }
1180
-
1181
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1182
- #pragma mark Archiving
1183
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1184
-
1185
- - (BOOL)isArchived
1186
- {
1187
-
1188
- #if TARGET_IPHONE_SIMULATOR
1189
-
1190
- // Extended attributes don't work properly on the simulator.
1191
- // So we have to use a less attractive alternative.
1192
- // See full explanation in the header file.
1193
-
1194
- return [self hasExtensionAttributeWithName:XATTR_ARCHIVED_NAME];
1195
-
1196
- #else
1197
-
1198
- return [self hasExtendedAttributeWithName:XATTR_ARCHIVED_NAME];
1199
-
1200
- #endif
1201
- }
1202
-
1203
- - (void)setIsArchived:(BOOL)flag
1204
- {
1205
-
1206
- #if TARGET_IPHONE_SIMULATOR
1207
-
1208
- // Extended attributes don't work properly on the simulator.
1209
- // So we have to use a less attractive alternative.
1210
- // See full explanation in the header file.
1211
-
1212
- if (flag)
1213
- [self addExtensionAttributeWithName:XATTR_ARCHIVED_NAME];
1214
- else
1215
- [self removeExtensionAttributeWithName:XATTR_ARCHIVED_NAME];
1216
-
1217
- #else
1218
-
1219
- if (flag)
1220
- [self addExtendedAttributeWithName:XATTR_ARCHIVED_NAME];
1221
- else
1222
- [self removeExtendedAttributeWithName:XATTR_ARCHIVED_NAME];
1223
-
1224
- #endif
1225
- }
1226
-
1227
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1228
- #pragma mark Changes
1229
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1230
-
1231
- - (void)reset
1232
- {
1233
- fileName = nil;
1234
- fileAttributes = nil;
1235
- creationDate = nil;
1236
- modificationDate = nil;
1237
- }
1238
-
1239
- - (void)renameFile:(NSString *)newFileName
1240
- {
1241
- // This method is only used on the iPhone simulator, where normal extended attributes are broken.
1242
- // See full explanation in the header file.
1243
-
1244
- if (![newFileName isEqualToString:[self fileName]])
1245
- {
1246
- NSString *fileDir = [filePath stringByDeletingLastPathComponent];
1247
-
1248
- NSString *newFilePath = [fileDir stringByAppendingPathComponent:newFileName];
1249
-
1250
- NSLogVerbose(@"DDLogFileInfo: Renaming file: '%@' -> '%@'", self.fileName, newFileName);
1251
-
1252
- NSError *error = nil;
1253
- if (![[NSFileManager defaultManager] fileExistsAtPath:newFilePath]){
1254
- if([[NSFileManager defaultManager] removeItemAtPath:newFilePath error:&error]){
1255
- NSLogError(@"DDLogFileInfo: Error deleting archive (%@): %@", self.fileName, error);
1256
- }
1257
- }
1258
-
1259
- if (![[NSFileManager defaultManager] moveItemAtPath:filePath toPath:newFilePath error:&error])
1260
- {
1261
- NSLogError(@"DDLogFileInfo: Error renaming file (%@): %@", self.fileName, error);
1262
- }
1263
-
1264
- filePath = newFilePath;
1265
- [self reset];
1266
- }
1267
- }
1268
-
1269
-
1270
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1271
- #pragma mark Attribute Management
1272
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1273
-
1274
- #if TARGET_IPHONE_SIMULATOR
1275
-
1276
- // Extended attributes don't work properly on the simulator.
1277
- // So we have to use a less attractive alternative.
1278
- // See full explanation in the header file.
1279
-
1280
- - (BOOL)hasExtensionAttributeWithName:(NSString *)attrName
1281
- {
1282
- // This method is only used on the iPhone simulator, where normal extended attributes are broken.
1283
- // See full explanation in the header file.
1284
-
1285
- // Split the file name into components. File name may have various format, but generally
1286
- // structure is same:
1287
- //
1288
- // <name part>.<extension part> and <name part>.archived.<extension part>
1289
- // or
1290
- // <name part> and <name part>.archived
1291
- //
1292
- // So we want to search for the attrName in the components (ignoring the first array index).
1293
-
1294
- NSArray *components = [[self fileName] componentsSeparatedByString:@"."];
1295
-
1296
- // Watch out for file names without an extension
1297
-
1298
- for (NSUInteger i = 1; i < components.count; i++)
1299
- {
1300
- NSString *attr = [components objectAtIndex:i];
1301
-
1302
- if ([attrName isEqualToString:attr])
1303
- {
1304
- return YES;
1305
- }
1306
- }
1307
-
1308
- return NO;
1309
- }
1310
-
1311
- - (void)addExtensionAttributeWithName:(NSString *)attrName
1312
- {
1313
- // This method is only used on the iPhone simulator, where normal extended attributes are broken.
1314
- // See full explanation in the header file.
1315
-
1316
- if ([attrName length] == 0) return;
1317
-
1318
- // Example:
1319
- // attrName = "archived"
1320
- //
1321
- // "mylog.txt" -> "mylog.archived.txt"
1322
- // "mylog" -> "mylog.archived"
1323
-
1324
- NSArray *components = [[self fileName] componentsSeparatedByString:@"."];
1325
-
1326
- NSUInteger count = [components count];
1327
-
1328
- NSUInteger estimatedNewLength = [[self fileName] length] + [attrName length] + 1;
1329
- NSMutableString *newFileName = [NSMutableString stringWithCapacity:estimatedNewLength];
1330
-
1331
- if (count > 0)
1332
- {
1333
- [newFileName appendString:[components objectAtIndex:0]];
1334
- }
1335
-
1336
- NSString *lastExt = @"";
1337
-
1338
- NSUInteger i;
1339
- for (i = 1; i < count; i++)
1340
- {
1341
- NSString *attr = [components objectAtIndex:i];
1342
- if ([attr length] == 0)
1343
- {
1344
- continue;
1345
- }
1346
-
1347
- if ([attrName isEqualToString:attr])
1348
- {
1349
- // Extension attribute already exists in file name
1350
- return;
1351
- }
1352
-
1353
- if ([lastExt length] > 0)
1354
- {
1355
- [newFileName appendFormat:@".%@", lastExt];
1356
- }
1357
-
1358
- lastExt = attr;
1359
- }
1360
-
1361
- [newFileName appendFormat:@".%@", attrName];
1362
-
1363
- if ([lastExt length] > 0)
1364
- {
1365
- [newFileName appendFormat:@".%@", lastExt];
1366
- }
1367
-
1368
- [self renameFile:newFileName];
1369
- }
1370
-
1371
- - (void)removeExtensionAttributeWithName:(NSString *)attrName
1372
- {
1373
- // This method is only used on the iPhone simulator, where normal extended attributes are broken.
1374
- // See full explanation in the header file.
1375
-
1376
- if ([attrName length] == 0) return;
1377
-
1378
- // Example:
1379
- // attrName = "archived"
1380
- //
1381
- // "mylog.archived.txt" -> "mylog.txt"
1382
- // "mylog.archived" -> "mylog"
1383
-
1384
- NSArray *components = [[self fileName] componentsSeparatedByString:@"."];
1385
-
1386
- NSUInteger count = [components count];
1387
-
1388
- NSUInteger estimatedNewLength = [[self fileName] length];
1389
- NSMutableString *newFileName = [NSMutableString stringWithCapacity:estimatedNewLength];
1390
-
1391
- if (count > 0)
1392
- {
1393
- [newFileName appendString:[components objectAtIndex:0]];
1394
- }
1395
-
1396
- BOOL found = NO;
1397
-
1398
- NSUInteger i;
1399
- for (i = 1; i < count; i++)
1400
- {
1401
- NSString *attr = [components objectAtIndex:i];
1402
-
1403
- if ([attrName isEqualToString:attr])
1404
- {
1405
- found = YES;
1406
- }
1407
- else
1408
- {
1409
- [newFileName appendFormat:@".%@", attr];
1410
- }
1411
- }
1412
-
1413
- if (found)
1414
- {
1415
- [self renameFile:newFileName];
1416
- }
1417
- }
1418
-
1419
- #else
1420
-
1421
- - (BOOL)hasExtendedAttributeWithName:(NSString *)attrName
1422
- {
1423
- const char *path = [filePath UTF8String];
1424
- const char *name = [attrName UTF8String];
1425
-
1426
- ssize_t result = getxattr(path, name, NULL, 0, 0, 0);
1427
-
1428
- return (result >= 0);
1429
- }
1430
-
1431
- - (void)addExtendedAttributeWithName:(NSString *)attrName
1432
- {
1433
- const char *path = [filePath UTF8String];
1434
- const char *name = [attrName UTF8String];
1435
-
1436
- int result = setxattr(path, name, NULL, 0, 0, 0);
1437
-
1438
- if (result < 0)
1439
- {
1440
- NSLogError(@"DDLogFileInfo: setxattr(%@, %@): error = %s",
1441
- attrName,
1442
- self.fileName,
1443
- strerror(errno));
1444
- }
1445
- }
1446
-
1447
- - (void)removeExtendedAttributeWithName:(NSString *)attrName
1448
- {
1449
- const char *path = [filePath UTF8String];
1450
- const char *name = [attrName UTF8String];
1451
-
1452
- int result = removexattr(path, name, 0);
1453
-
1454
- if (result < 0 && errno != ENOATTR)
1455
- {
1456
- NSLogError(@"DDLogFileInfo: removexattr(%@, %@): error = %s",
1457
- attrName,
1458
- self.fileName,
1459
- strerror(errno));
1460
- }
1461
- }
1462
-
1463
- #endif
1464
-
1465
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1466
- #pragma mark Comparisons
1467
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1468
-
1469
- - (BOOL)isEqual:(id)object
1470
- {
1471
- if ([object isKindOfClass:[self class]])
1472
- {
1473
- DDLogFileInfo *another = (DDLogFileInfo *)object;
1474
-
1475
- return [filePath isEqualToString:[another filePath]];
1476
- }
1477
-
1478
- return NO;
1479
- }
1480
-
1481
- - (NSComparisonResult)reverseCompareByCreationDate:(DDLogFileInfo *)another
1482
- {
1483
- NSDate *us = [self creationDate];
1484
- NSDate *them = [another creationDate];
1485
-
1486
- NSComparisonResult result = [us compare:them];
1487
-
1488
- if (result == NSOrderedAscending)
1489
- return NSOrderedDescending;
1490
-
1491
- if (result == NSOrderedDescending)
1492
- return NSOrderedAscending;
1493
-
1494
- return NSOrderedSame;
1495
- }
1496
-
1497
- - (NSComparisonResult)reverseCompareByModificationDate:(DDLogFileInfo *)another
1498
- {
1499
- NSDate *us = [self modificationDate];
1500
- NSDate *them = [another modificationDate];
1501
-
1502
- NSComparisonResult result = [us compare:them];
1503
-
1504
- if (result == NSOrderedAscending)
1505
- return NSOrderedDescending;
1506
-
1507
- if (result == NSOrderedDescending)
1508
- return NSOrderedAscending;
1509
-
1510
- return NSOrderedSame;
1511
- }
1512
-
1513
- @end
1514
-
1515
- #if TARGET_OS_IPHONE
1516
- /**
1517
- * When creating log file on iOS we're setting NSFileProtectionKey attribute to NSFileProtectionCompleteUnlessOpen.
1518
- *
1519
- * But in case if app is able to launch from background we need to have an ability to open log file any time we
1520
- * want (even if device is locked). Thats why that attribute have to be changed to
1521
- * NSFileProtectionCompleteUntilFirstUserAuthentication.
1522
- */
1523
- BOOL doesAppRunInBackground()
1524
- {
1525
- BOOL answer = NO;
1526
-
1527
- NSArray *backgroundModes = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"UIBackgroundModes"];
1528
-
1529
- for (NSString *mode in backgroundModes) {
1530
- if (mode.length > 0) {
1531
- answer = YES;
1532
- break;
1533
- }
1534
- }
1535
-
1536
- return answer;
1537
- }
1538
- #endif
1539
-