store_agent 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +14 -0
  3. data/.rspec +3 -0
  4. data/Gemfile +4 -0
  5. data/Guardfile +5 -0
  6. data/LICENSE +202 -0
  7. data/README.md +433 -0
  8. data/Rakefile +2 -0
  9. data/lib/store_agent.rb +31 -0
  10. data/lib/store_agent/config.rb +152 -0
  11. data/lib/store_agent/data_encoder.rb +32 -0
  12. data/lib/store_agent/data_encoder/gzip_encoder.rb +50 -0
  13. data/lib/store_agent/data_encoder/openssl_aes_256_cbc_encoder.rb +65 -0
  14. data/lib/store_agent/exceptions.rb +87 -0
  15. data/lib/store_agent/node.rb +26 -0
  16. data/lib/store_agent/node/attachment.rb +93 -0
  17. data/lib/store_agent/node/attachment/metadata.rb +120 -0
  18. data/lib/store_agent/node/attachment/permission.rb +121 -0
  19. data/lib/store_agent/node/object.rb +233 -0
  20. data/lib/store_agent/node/object/directory_object.rb +264 -0
  21. data/lib/store_agent/node/object/file_object.rb +197 -0
  22. data/lib/store_agent/node/object/virtual_object.rb +25 -0
  23. data/lib/store_agent/node/prepend_module/locker.rb +125 -0
  24. data/lib/store_agent/node/prepend_module/path_validator.rb +138 -0
  25. data/lib/store_agent/node/prepend_module/permission_checker.rb +96 -0
  26. data/lib/store_agent/user.rb +111 -0
  27. data/lib/store_agent/validator.rb +60 -0
  28. data/lib/store_agent/version.rb +19 -0
  29. data/lib/store_agent/version_manager.rb +101 -0
  30. data/lib/store_agent/version_manager/ruby_git.rb +100 -0
  31. data/lib/store_agent/version_manager/rugged_git.rb +133 -0
  32. data/lib/store_agent/workspace.rb +88 -0
  33. data/spec/spec_helper.rb +47 -0
  34. data/spec/store_agent/data_encoder/encoder_shared_context.rb +74 -0
  35. data/spec/store_agent/data_encoder/gzip_encoder_spec.rb +41 -0
  36. data/spec/store_agent/data_encoder/openssl_aes_256_cbc_encoder_spec.rb +42 -0
  37. data/spec/store_agent/data_encoder_spec.rb +78 -0
  38. data/spec/store_agent/node/directory_object_spec.rb +563 -0
  39. data/spec/store_agent/node/file_object_spec.rb +379 -0
  40. data/spec/store_agent/node/locker_spec.rb +191 -0
  41. data/spec/store_agent/node/metadata_spec.rb +339 -0
  42. data/spec/store_agent/node/object_spec.rb +73 -0
  43. data/spec/store_agent/node/path_validator_spec.rb +121 -0
  44. data/spec/store_agent/node/permission_spec.rb +232 -0
  45. data/spec/store_agent/user_spec.rb +127 -0
  46. data/spec/store_agent/version_manager/git_shared_context.rb +286 -0
  47. data/spec/store_agent/version_manager/ruby_git_spec.rb +32 -0
  48. data/spec/store_agent/version_manager/rugged_git_spec.rb +32 -0
  49. data/spec/store_agent/workspace_spec.rb +107 -0
  50. data/spec/store_agent_spec.rb +53 -0
  51. data/store_agent.gemspec +33 -0
  52. metadata +252 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 541cd57d63698ce014940dccfb89492af36d1ecc
4
+ data.tar.gz: c2db5fb40adedf6cfb80fbc26b55e011ccee8527
5
+ SHA512:
6
+ metadata.gz: 6849a47f777b73f0a8b77c36e82176b4227725f5df1f7511ada23330fd706a0cbe6aff07334e5664504d01968444925f2fdc1c9fe34701898a6e91e2daad4972
7
+ data.tar.gz: b40d9481c17f04288f7229f121e7dc4e74b7b82657548ffe4f76ff28c2c68ffe9c44b6b4375524825e0656c76130d026752cb99c9f7c598c313e4fcc811738d4
@@ -0,0 +1,14 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --color
2
+ --require spec_helper
3
+ --format documentation
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in store_agent.gemspec
4
+ gemspec
@@ -0,0 +1,5 @@
1
+ guard :rspec, cmd: "rspec", failed_mode: :none do
2
+ watch(%r{^spec/.+_spec\.rb$})
3
+ watch(%r{^lib/(.+)\.rb$}) { "spec/" }
4
+ watch('spec/spec_helper.rb') { "spec/" }
5
+ end
data/LICENSE ADDED
@@ -0,0 +1,202 @@
1
+
2
+ Apache License
3
+ Version 2.0, January 2004
4
+ http://www.apache.org/licenses/
5
+
6
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7
+
8
+ 1. Definitions.
9
+
10
+ "License" shall mean the terms and conditions for use, reproduction,
11
+ and distribution as defined by Sections 1 through 9 of this document.
12
+
13
+ "Licensor" shall mean the copyright owner or entity authorized by
14
+ the copyright owner that is granting the License.
15
+
16
+ "Legal Entity" shall mean the union of the acting entity and all
17
+ other entities that control, are controlled by, or are under common
18
+ control with that entity. For the purposes of this definition,
19
+ "control" means (i) the power, direct or indirect, to cause the
20
+ direction or management of such entity, whether by contract or
21
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
22
+ outstanding shares, or (iii) beneficial ownership of such entity.
23
+
24
+ "You" (or "Your") shall mean an individual or Legal Entity
25
+ exercising permissions granted by this License.
26
+
27
+ "Source" form shall mean the preferred form for making modifications,
28
+ including but not limited to software source code, documentation
29
+ source, and configuration files.
30
+
31
+ "Object" form shall mean any form resulting from mechanical
32
+ transformation or translation of a Source form, including but
33
+ not limited to compiled object code, generated documentation,
34
+ and conversions to other media types.
35
+
36
+ "Work" shall mean the work of authorship, whether in Source or
37
+ Object form, made available under the License, as indicated by a
38
+ copyright notice that is included in or attached to the work
39
+ (an example is provided in the Appendix below).
40
+
41
+ "Derivative Works" shall mean any work, whether in Source or Object
42
+ form, that is based on (or derived from) the Work and for which the
43
+ editorial revisions, annotations, elaborations, or other modifications
44
+ represent, as a whole, an original work of authorship. For the purposes
45
+ of this License, Derivative Works shall not include works that remain
46
+ separable from, or merely link (or bind by name) to the interfaces of,
47
+ the Work and Derivative Works thereof.
48
+
49
+ "Contribution" shall mean any work of authorship, including
50
+ the original version of the Work and any modifications or additions
51
+ to that Work or Derivative Works thereof, that is intentionally
52
+ submitted to Licensor for inclusion in the Work by the copyright owner
53
+ or by an individual or Legal Entity authorized to submit on behalf of
54
+ the copyright owner. For the purposes of this definition, "submitted"
55
+ means any form of electronic, verbal, or written communication sent
56
+ to the Licensor or its representatives, including but not limited to
57
+ communication on electronic mailing lists, source code control systems,
58
+ and issue tracking systems that are managed by, or on behalf of, the
59
+ Licensor for the purpose of discussing and improving the Work, but
60
+ excluding communication that is conspicuously marked or otherwise
61
+ designated in writing by the copyright owner as "Not a Contribution."
62
+
63
+ "Contributor" shall mean Licensor and any individual or Legal Entity
64
+ on behalf of whom a Contribution has been received by Licensor and
65
+ subsequently incorporated within the Work.
66
+
67
+ 2. Grant of Copyright License. Subject to the terms and conditions of
68
+ this License, each Contributor hereby grants to You a perpetual,
69
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70
+ copyright license to reproduce, prepare Derivative Works of,
71
+ publicly display, publicly perform, sublicense, and distribute the
72
+ Work and such Derivative Works in Source or Object form.
73
+
74
+ 3. Grant of Patent License. Subject to the terms and conditions of
75
+ this License, each Contributor hereby grants to You a perpetual,
76
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77
+ (except as stated in this section) patent license to make, have made,
78
+ use, offer to sell, sell, import, and otherwise transfer the Work,
79
+ where such license applies only to those patent claims licensable
80
+ by such Contributor that are necessarily infringed by their
81
+ Contribution(s) alone or by combination of their Contribution(s)
82
+ with the Work to which such Contribution(s) was submitted. If You
83
+ institute patent litigation against any entity (including a
84
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
85
+ or a Contribution incorporated within the Work constitutes direct
86
+ or contributory patent infringement, then any patent licenses
87
+ granted to You under this License for that Work shall terminate
88
+ as of the date such litigation is filed.
89
+
90
+ 4. Redistribution. You may reproduce and distribute copies of the
91
+ Work or Derivative Works thereof in any medium, with or without
92
+ modifications, and in Source or Object form, provided that You
93
+ meet the following conditions:
94
+
95
+ (a) You must give any other recipients of the Work or
96
+ Derivative Works a copy of this License; and
97
+
98
+ (b) You must cause any modified files to carry prominent notices
99
+ stating that You changed the files; and
100
+
101
+ (c) You must retain, in the Source form of any Derivative Works
102
+ that You distribute, all copyright, patent, trademark, and
103
+ attribution notices from the Source form of the Work,
104
+ excluding those notices that do not pertain to any part of
105
+ the Derivative Works; and
106
+
107
+ (d) If the Work includes a "NOTICE" text file as part of its
108
+ distribution, then any Derivative Works that You distribute must
109
+ include a readable copy of the attribution notices contained
110
+ within such NOTICE file, excluding those notices that do not
111
+ pertain to any part of the Derivative Works, in at least one
112
+ of the following places: within a NOTICE text file distributed
113
+ as part of the Derivative Works; within the Source form or
114
+ documentation, if provided along with the Derivative Works; or,
115
+ within a display generated by the Derivative Works, if and
116
+ wherever such third-party notices normally appear. The contents
117
+ of the NOTICE file are for informational purposes only and
118
+ do not modify the License. You may add Your own attribution
119
+ notices within Derivative Works that You distribute, alongside
120
+ or as an addendum to the NOTICE text from the Work, provided
121
+ that such additional attribution notices cannot be construed
122
+ as modifying the License.
123
+
124
+ You may add Your own copyright statement to Your modifications and
125
+ may provide additional or different license terms and conditions
126
+ for use, reproduction, or distribution of Your modifications, or
127
+ for any such Derivative Works as a whole, provided Your use,
128
+ reproduction, and distribution of the Work otherwise complies with
129
+ the conditions stated in this License.
130
+
131
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
132
+ any Contribution intentionally submitted for inclusion in the Work
133
+ by You to the Licensor shall be under the terms and conditions of
134
+ this License, without any additional terms or conditions.
135
+ Notwithstanding the above, nothing herein shall supersede or modify
136
+ the terms of any separate license agreement you may have executed
137
+ with Licensor regarding such Contributions.
138
+
139
+ 6. Trademarks. This License does not grant permission to use the trade
140
+ names, trademarks, service marks, or product names of the Licensor,
141
+ except as required for reasonable and customary use in describing the
142
+ origin of the Work and reproducing the content of the NOTICE file.
143
+
144
+ 7. Disclaimer of Warranty. Unless required by applicable law or
145
+ agreed to in writing, Licensor provides the Work (and each
146
+ Contributor provides its Contributions) on an "AS IS" BASIS,
147
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148
+ implied, including, without limitation, any warranties or conditions
149
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150
+ PARTICULAR PURPOSE. You are solely responsible for determining the
151
+ appropriateness of using or redistributing the Work and assume any
152
+ risks associated with Your exercise of permissions under this License.
153
+
154
+ 8. Limitation of Liability. In no event and under no legal theory,
155
+ whether in tort (including negligence), contract, or otherwise,
156
+ unless required by applicable law (such as deliberate and grossly
157
+ negligent acts) or agreed to in writing, shall any Contributor be
158
+ liable to You for damages, including any direct, indirect, special,
159
+ incidental, or consequential damages of any character arising as a
160
+ result of this License or out of the use or inability to use the
161
+ Work (including but not limited to damages for loss of goodwill,
162
+ work stoppage, computer failure or malfunction, or any and all
163
+ other commercial damages or losses), even if such Contributor
164
+ has been advised of the possibility of such damages.
165
+
166
+ 9. Accepting Warranty or Additional Liability. While redistributing
167
+ the Work or Derivative Works thereof, You may choose to offer,
168
+ and charge a fee for, acceptance of support, warranty, indemnity,
169
+ or other liability obligations and/or rights consistent with this
170
+ License. However, in accepting such obligations, You may act only
171
+ on Your own behalf and on Your sole responsibility, not on behalf
172
+ of any other Contributor, and only if You agree to indemnify,
173
+ defend, and hold each Contributor harmless for any liability
174
+ incurred by, or claims asserted against, such Contributor by reason
175
+ of your accepting any such warranty or additional liability.
176
+
177
+ END OF TERMS AND CONDITIONS
178
+
179
+ APPENDIX: How to apply the Apache License to your work.
180
+
181
+ To apply the Apache License to your work, attach the following
182
+ boilerplate notice, with the fields enclosed by brackets "[]"
183
+ replaced with your own identifying information. (Don't include
184
+ the brackets!) The text should be enclosed in the appropriate
185
+ comment syntax for the file format. We also recommend that a
186
+ file or class name and description of purpose be included on the
187
+ same "printed page" as the copyright notice for easier
188
+ identification within third-party archives.
189
+
190
+ Copyright [yyyy] [name of copyright owner]
191
+
192
+ Licensed under the Apache License, Version 2.0 (the "License");
193
+ you may not use this file except in compliance with the License.
194
+ You may obtain a copy of the License at
195
+
196
+ http://www.apache.org/licenses/LICENSE-2.0
197
+
198
+ Unless required by applicable law or agreed to in writing, software
199
+ distributed under the License is distributed on an "AS IS" BASIS,
200
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201
+ See the License for the specific language governing permissions and
202
+ limitations under the License.
@@ -0,0 +1,433 @@
1
+ # StoreAgent
2
+
3
+ Simple Access Controllable Storage Interface.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'store_agent'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install store_agent
20
+
21
+ ## Usage
22
+
23
+ 基本的な使用方法は以下。
24
+
25
+ ### 1. ユーザー
26
+
27
+ ストレージのデータにアクセスするユーザー。
28
+
29
+ ```ruby
30
+ # 一般ユーザー
31
+ user = StoreAgent::User.new("user_xxx")
32
+ user = StoreAgent::User.new(:user_xxx) # シンボルは文字列に変換される
33
+ # ルートユーザー
34
+ root_user = StoreAgent::Superuser.new
35
+ # ゲストユーザー
36
+ guest_user = StoreAgent::Guest.new
37
+ ```
38
+
39
+ 一般ユーザーの初期化時には引数としてIDが必要だが、これは可変引数で複数のIDを渡す事もできる。
40
+ その場合、権限チェック時には受け取った引数の後ろから順に権限をチェックし、最初に見つかった権限が適用される。
41
+ ユーザー自身のIDとしては最後の引数が使用され、このIDがオブジェクト作成時のオーナーになる。
42
+
43
+ ```ruby
44
+ # グループに所属する場合など、複数IDを持つユーザー
45
+ group_user = StoreAgent::User.new("group_001", "group_002", ..., "user_xxx")
46
+ group_user.identifier # => "user_xxx"
47
+ ```
48
+
49
+ IDとして文字列ではなく配列を渡すと、権限情報をネームスペースで分ける事ができる。
50
+ 権限情報は配列の要素の順にネストして保存され、権限チェックはネームスペースを順に辿って行う。
51
+ 同じユーザーでもネームスペースが違うと、それぞれ別の権限情報を持つ事になる。
52
+ ファイルやディレクトリの作成者としては配列の先頭要素が使用される。
53
+
54
+ ```ruby
55
+ # ネームスペース付きのユーザー
56
+ namespaced_user = StoreAgent::User.new(["user_xxx", "namespace_001", "namespace_002"])
57
+ namespaced_user.identifier # => "user_xxx"
58
+ # 権限チェック時には、permission["user_xxx"]["namespace_001"]["namespace_002"] をチェックする
59
+ ```
60
+
61
+ ### 2. ワークスペース
62
+
63
+ ストレージ、メタデータ、権限情報を管理する名前空間。
64
+ バージョン管理を使用する場合には、ワークスペースが一つのgitリポジトリになる。
65
+
66
+ ```ruby
67
+ workspace = user.workspace("workspace_01")
68
+ workspace.exists? # => false
69
+ workspace.create
70
+ workspace.exists? # => true
71
+ ```
72
+
73
+ ### 3. ストレージ
74
+
75
+ ワークスペースの/storage/以下をストレージ領域として使用する。
76
+ ファイル/ディレクトリ名の命名規則はシステムに準拠するが、それに加えて以下の制限がある。
77
+
78
+ * config.reserved_filenamesで設定されている名前は使用できない。
79
+ * gitのバージョン管理を使用する場合は、.gitおよび.keepという名前は使用できない。
80
+ * メタデータや権限情報と名前の衝突が起きないよう、最後が.metaや.permで終わるような名前は使用できない。
81
+
82
+ ```ruby
83
+ # ディレクトリ作成
84
+ directory_01 = workspace.directory("foo")
85
+ directory_01.path # => "/foo/"
86
+ directory_01.exists? # => false
87
+ directory_01.create
88
+ directory_01.exists? # => true
89
+ directory_02 = directory_01.directory("bar")
90
+ directory_02.path # => "/foo/bar/"
91
+ directory_02.create
92
+ workspace.directory("foo/bar").exists? # => true
93
+
94
+ # ファイル作成
95
+ file_01 = workspace.file("hoge.txt")
96
+ file_01.path # => "/hoge.txt"
97
+ file_01.exists? # => false
98
+ file_01.create("hoge")
99
+ file_01.exists? # => true
100
+ file_01.read # => "hoge"
101
+ file_02 = directory_01.file("fuga.txt")
102
+ file_02.path # => "/foo/fuga.txt"
103
+ file_02.exists? # => false
104
+ file_02.create{|f| f.body = "fuga"}
105
+ file_02.exists? # => true
106
+ file_02.read # => "fuga"
107
+ directory_01.read # => ["bar", "fuga.txt"]
108
+
109
+ # ファイル更新
110
+ file_01.update("updated") # => true
111
+ file_01.read # => "updated"
112
+
113
+ # ファイル削除
114
+ file_02.delete # => true
115
+ file_02.exists? # => false
116
+ file_02.update("fuga") # => StoreAgent::PathError
117
+ file_02.delete # => StoreAgent::PathError
118
+
119
+ # ファイル/ディレクトリの移動
120
+ file_01.move("move.txt")
121
+ directory_01.move("move_dir")
122
+ workspace.root.read # => ["move.txt", "move_dir"]
123
+
124
+ # ファイル/ディレクトリのコピー
125
+ workspace.file("move.txt").copy("hoge.txt")
126
+ workspace.directory("move_dir").copy("foo")
127
+ workspace.root.read # => ["move.txt", "hoge.txt", "move_dir", "foo"]
128
+ ```
129
+
130
+ ### 4. メタデータ
131
+
132
+ ストレージと同様の構成で /metadata/ 以下にメタデータ用のファイルが作成される。
133
+ storage/${path} に対応するメタデータは metadata/${path}.meta に保存され、オブジェクトの操作時に更新される。
134
+ 例えば、
135
+
136
+ * `/` に対応するメタデータは `/.meta`
137
+ * `/foo/` に対応するメタデータは `/foo/.meta`
138
+ * `/foo/bar.json` に対応するメタデータは `/foo/bar.json.meta`
139
+
140
+ となる。
141
+ また metadata/${path}.meta.lock という名前でロックファイルも作成され、オブジェクトの操作時にはこのファイルがロックされる。
142
+
143
+ ```ruby
144
+ # メタデータ
145
+ workspace.directory("foo").metadata # => {...}
146
+ workspace.file("hoge.txt").metadata # => {...}
147
+
148
+ # オーナー変更
149
+ workspace.file("hoge.txt").chown(identifier: "user_yyy")
150
+ workspace.file("hoge.txt").metadata # => {...}
151
+ workspace.directory("foo").chown(identifier: "user_zzz", recursive: true)
152
+ workspace.directory("foo/bar").metadata # => {...}
153
+ ```
154
+
155
+ メタデータの形式は以下のようなJSON。
156
+
157
+ ```json
158
+ # オブジェクトがディレクトリの場合
159
+ {
160
+ "size": "4.00KB",
161
+ "bytes": 4096,
162
+ "owner": "xxx-xxx-xxx-xxx",
163
+ "is_dir": true,
164
+ "created_at": "YYYY-mm-dd HH:MM:SS Z",
165
+ "updated_at": "YYYY-mm-dd HH:MM:SS Z",
166
+ "created_at_unix_timestamp": 1412345678,
167
+ "updated_at_unix_timestamp": 1412345678,
168
+ "directory_size": "8.00KB",
169
+ "directory_bytes": 8192,
170
+ "directory_size_limit": "1.00GB",
171
+ "directory_bytes_limit": 1073741824,
172
+ "directory_file_count": 1,
173
+ "tree_file_count": 1
174
+ }
175
+
176
+ # オブジェクトがファイルの場合
177
+ {
178
+ "size": "10.4KB",
179
+ "bytes": 10634,
180
+ "owner": "xxx-xxx-xxx-xxx",
181
+ "is_dir": false,
182
+ "created_at": "YYYY-mm-dd HH:MM:SS Z",
183
+ "updated_at": "YYYY-mm-dd HH:MM:SS Z",
184
+ "created_at_unix_timestamp": 1412345678,
185
+ "updated_at_unix_timestamp": 1412345678
186
+ }
187
+ ```
188
+
189
+ ### 5. 権限情報
190
+
191
+ ストレージと同様の構成で /permission/ 以下に権限情報用のファイルが作成される。
192
+ storage/${path} に対応する権限情報は permission/${path}.perm に保存する。
193
+
194
+ ```ruby
195
+ # パーミッション
196
+ workspace.directory("foo").permission # => {...}
197
+ workspace.file("hoge.txt").permission # => {...}
198
+
199
+ # パーミッション変更
200
+ r_file_01 = root_user.workspace("workspace_01").file("hoge.txt")
201
+ r_directory_01 = root_user.workspace("workspace_01").directory("foo")
202
+ r_directory_02 = r_directory_01.directory("bar")
203
+ r_file_01.set_permission(identifier: "user_yyy", permission_values: {"read" => true, "write" => false})
204
+ r_directory_01.set_permission(identifier: "user_yyy", permission_values: {"read" => true})
205
+ r_directory_02.set_permission(identifier: "user_yyy", permission_values: {"write" => true}, recursive: true)
206
+
207
+ # パーミッション解除
208
+ r_file_01.unset_permission(identifier: "user_yyy", permission_names: "read")
209
+ r_directory_01.unset_permission(identifier: "user_yyy", permission_names: ["read"])
210
+ r_directory_02.unset_permission(identifier: "user_yyy", permission_names: ["read", "write"], recursive: true)
211
+ ```
212
+
213
+ 権限情報の形式は以下のようなJSON。
214
+
215
+ ```json
216
+ {
217
+ "users":{
218
+ "user-xxx-uid":{
219
+ "read":true,
220
+ "write":true,
221
+ "execute":true,
222
+ "chown":true,
223
+ "chmod":true
224
+ },
225
+ "user-yyy-uid":{
226
+ "namespace-zzz":{
227
+ "read":true,
228
+ "write":false
229
+ }
230
+ }
231
+ },
232
+ "guest":{
233
+ "read":true,
234
+ "execute":true
235
+ }
236
+ }
237
+ ```
238
+
239
+ 権限のチェックは以下の順に処理される。
240
+
241
+ 1. ルートユーザーは全ての権限を持つ。
242
+ 2. 一般ユーザーの場合、上記のJSONの"users"をユーザーIDで検索する。キーが見つかり、値の中に権限と一致するキーがあればその値が使用される。ユーザーIDが配列の場合、配列の順にこの処理が実行される。
243
+ 3. ゲストユーザーまたは一般ユーザーだが権限情報が登録されていない場合、上記JSONの"guest"の中に権限と一致するキーがあればその値が使用される。キーが無い場合には権限が無い。
244
+
245
+ ### 6. 設定変更
246
+
247
+ 使用前に、以下のようにして一部の設定を変更する事ができる。
248
+
249
+ ```ruby
250
+ StoreAgent.configure do |c|
251
+ c.storage_root = "path/to/storage/directory"
252
+ c.version_manager = StoreAgent::VersionManager::RuggedGit
253
+ c.storage_data_encoders = [] <<
254
+ StoreAgent::DataEncoder::GzipEncoder.new <<
255
+ StoreAgent::DataEncoder::OpensslAes256CbcEncoder.new
256
+ c.json_indent_level = 2
257
+ end
258
+ ```
259
+
260
+ 変更可能な設定は以下。
261
+ デフォルト値はlib/store_agent/config.rbを参照。
262
+
263
+ ```ruby
264
+ storage_root # ファイル/メタデータ/権限情報を保存するディレクトリ
265
+ storage_dirname # ファイルを保存するディレクトリ名
266
+ metadata_dirname # メタデータを保存するディレクトリ名
267
+ permission_dirname # 権限情報を保存するディレクトリ名
268
+ metadata_extension # メタデータの拡張子
269
+ permission_extension # 権限情報の拡張子
270
+ superuser_identifier # ルートユーザーのID
271
+ guest_identifier # ゲストユーザーのID
272
+ version_manager # バージョン管理に使用するクラス
273
+ storage_data_encoders # ファイルのエンコードに使用するオブジェクトのリスト
274
+ attachment_data_encoders # メタデータおよび権限情報のエンコードに使用するオブジェクトのリスト
275
+ reserved_filenames # システムが予約しているファイル名
276
+ lock_timeout # ファイルのロック時のタイムアウト秒数
277
+ default_directory_bytesize_limit # 使用していない
278
+ default_owner_permission # ファイル/ディレクトリ作成時に作成者に付与されるデフォルトの権限
279
+ default_guest_permission # ファイル/ディレクトリ作成時にゲストユーザーに付与されるデフォルトの権限
280
+ ```
281
+
282
+ ### 7. バージョン管理
283
+
284
+ ワークスペースをgitリポジトリとしてバージョン管理する事ができる。
285
+ デフォルトでは無効になっているので、有効化する場合は別途gemをインストールし、以下のように設定する必要がある。
286
+ 使用できるgemは[rugged](https://github.com/libgit2/rugged)、あるいは[ruby-git](https://github.com/schacon/ruby-git)のどちらか。
287
+
288
+ ```ruby
289
+ ### ruggedを使用する場合
290
+ # Gemfile
291
+ gem "rugged"
292
+
293
+ # 設定変更
294
+ StoreAgent.configure do |c|
295
+ c.version_manager = StoreAgent::VersionManager::RuggedGit
296
+ end
297
+
298
+ ### ruby-gitを使用する場合
299
+ # Gemfile
300
+ gem "git"
301
+
302
+ # 設定変更
303
+ StoreAgent.configure do |c|
304
+ c.version_manager = StoreAgent::VersionManager::RubyGit
305
+ end
306
+ ```
307
+
308
+ 過去のバージョンのファイルやディレクトリを読み込む場合は以下のように実行する。
309
+
310
+ ```ruby
311
+ # リビジョン一覧
312
+ file_01.revisions # => ["xxxxxx", "yyyyyy", ...]
313
+ directory_01.revisions # => ["zzzzzz", ...]
314
+
315
+ # 過去のバージョンのファイルやディレクトリ
316
+ file_01.read # => current version file
317
+ file_01.read(revision: "version") # => old version file
318
+ directory_01.read # => ["file_xxx", "file_yyy", ...]
319
+ directory_01.read # => ["old_file_xxx", "old_file_yyy", ...]
320
+ ```
321
+
322
+ ### 8. エンコード
323
+
324
+ ファイルやメタデータ+パーミッション情報をgzip圧縮、暗号化して保存しておく事ができる。
325
+ デフォルトではエンコードしない設定になっているので、圧縮や暗号化をしたい場合には以下のように設定する。
326
+ 圧縮/暗号化は配列の順番通りに実行され、解凍/復号はその逆順に処理される。
327
+ 暗号化方式はOpenSSL AES-256-CBCで、パスワードには環境変数 STORE_AGENT_DATA_ENCODER_PASSWORD を使用する。
328
+ STORE_AGENT_DATA_ENCODER_PASSWORD が設定されていない場合には空文字列がパスワードとして使用される。
329
+
330
+ ```ruby
331
+ # set config
332
+ StoreAgent.configure do |c|
333
+ # ファイルを暗号化する
334
+ c.storage_data_encoders = [StoreAgent::DataEncoder::OpensslAes256CbcEncoder.new]
335
+ # メタデータやパーミッション情報をgzip圧縮した上で暗号化する
336
+ c.attachment_data_encoders = [] <<
337
+ StoreAgent::DataEncoder::GzipEncoder.new <<
338
+ StoreAgent::DataEncoder::OpensslAes256CbcEncoder.new
339
+ # 暗号化してからgzip圧縮する場合は以下の順に指定する
340
+ # c.attachment_data_encoders = [] <<
341
+ # StoreAgent::DataEncoder::OpensslAes256CbcEncoder.new <<
342
+ # StoreAgent::DataEncoder::GzipEncoder.new
343
+ end
344
+ ```
345
+
346
+ 圧縮/暗号化されたファイルをシェル上から確認する場合は以下のようにする。
347
+
348
+ ```sh
349
+ ### gzip圧縮のみ使用している場合
350
+ $ cat path/to/gzipped/file.txt
351
+ # 圧縮されたファイル
352
+ > ########
353
+
354
+ $ cat path/to/gzipped/file.txt | gunzip
355
+ # 元のファイル
356
+ > gunzipped file
357
+
358
+ ### 暗号化のみ使用している場合
359
+ $ cat path/to/encrypted/file.txt
360
+ # 暗号化されたファイル
361
+ > Salted__########################
362
+
363
+ # パスワードは適宜変更する
364
+ $ openssl enc -d -aes-256-cbc -k "" -in path/to/encrypted/file.txt
365
+ # 元のファイル
366
+ > decoded file
367
+
368
+ ### gzip圧縮した後に暗号化している場合
369
+ $ cat path/to/gzipped/and/encrypted/file.txt
370
+ # 圧縮&暗号化されたファイル
371
+ > Salted__########################
372
+
373
+ $ openssl enc -d -aes-256-cbc -k "" -in path/to/gzipped/and/encrypted/file.txt | gunzip
374
+ # 元のファイル
375
+ > decoded and gunzipped file
376
+
377
+ ### 暗号化した後にgzip圧縮している場合
378
+ $ cat path/to/encrypted/and/gzipped/file.txt
379
+ # 暗号化&圧縮されたファイル
380
+ > ########
381
+
382
+ $ cat path/to/encrypted/and/gzipped/file.txt | gunzip | openssl enc -d -aes-256-cbc -k ""
383
+ # 元のファイル
384
+ > gunzipped and decoded file
385
+ ```
386
+
387
+ ### ディレクトリ構造
388
+
389
+ ストレージ領域のディレクトリ構造は以下のようになる。
390
+ .git と .keep はバージョン管理を使用している場合にのみ作成される。
391
+
392
+ ```
393
+ storage_root/
394
+ ├ ...
395
+ └ workspace/
396
+ ├ .git/
397
+ ├ permission/
398
+ | ├ .perm
399
+ | ├ ...
400
+ | └ directory_x/
401
+ | ├ .perm
402
+ | ├ file_1.perm
403
+ | ├ ...
404
+ | └ file_n.perm
405
+ ├ metadata/
406
+ | ├ .meta
407
+ | ├ .meta.lock
408
+ | ├ ...
409
+ | └ directory_x/
410
+ | ├ .meta
411
+ | ├ .meta.lock
412
+ | ├ file_1.meta
413
+ | ├ file_1.meta.lock
414
+ | ├ ...
415
+ | ├ file_n.meta
416
+ | └ file_n.meta.lock
417
+ └ storage/
418
+ ├ .keep
419
+ ├ ...
420
+ └ directory_x/
421
+ ├ .keep
422
+ ├ file_1
423
+ ├ ...
424
+ └ file_n
425
+ ```
426
+
427
+ ## Contributing
428
+
429
+ 1. Fork it ( https://github.com/[my-github-username]/store_agent/fork )
430
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
431
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
432
+ 4. Push to the branch (`git push origin my-new-feature`)
433
+ 5. Create a new Pull Request