store_agent 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +14 -0
- data/.rspec +3 -0
- data/Gemfile +4 -0
- data/Guardfile +5 -0
- data/LICENSE +202 -0
- data/README.md +433 -0
- data/Rakefile +2 -0
- data/lib/store_agent.rb +31 -0
- data/lib/store_agent/config.rb +152 -0
- data/lib/store_agent/data_encoder.rb +32 -0
- data/lib/store_agent/data_encoder/gzip_encoder.rb +50 -0
- data/lib/store_agent/data_encoder/openssl_aes_256_cbc_encoder.rb +65 -0
- data/lib/store_agent/exceptions.rb +87 -0
- data/lib/store_agent/node.rb +26 -0
- data/lib/store_agent/node/attachment.rb +93 -0
- data/lib/store_agent/node/attachment/metadata.rb +120 -0
- data/lib/store_agent/node/attachment/permission.rb +121 -0
- data/lib/store_agent/node/object.rb +233 -0
- data/lib/store_agent/node/object/directory_object.rb +264 -0
- data/lib/store_agent/node/object/file_object.rb +197 -0
- data/lib/store_agent/node/object/virtual_object.rb +25 -0
- data/lib/store_agent/node/prepend_module/locker.rb +125 -0
- data/lib/store_agent/node/prepend_module/path_validator.rb +138 -0
- data/lib/store_agent/node/prepend_module/permission_checker.rb +96 -0
- data/lib/store_agent/user.rb +111 -0
- data/lib/store_agent/validator.rb +60 -0
- data/lib/store_agent/version.rb +19 -0
- data/lib/store_agent/version_manager.rb +101 -0
- data/lib/store_agent/version_manager/ruby_git.rb +100 -0
- data/lib/store_agent/version_manager/rugged_git.rb +133 -0
- data/lib/store_agent/workspace.rb +88 -0
- data/spec/spec_helper.rb +47 -0
- data/spec/store_agent/data_encoder/encoder_shared_context.rb +74 -0
- data/spec/store_agent/data_encoder/gzip_encoder_spec.rb +41 -0
- data/spec/store_agent/data_encoder/openssl_aes_256_cbc_encoder_spec.rb +42 -0
- data/spec/store_agent/data_encoder_spec.rb +78 -0
- data/spec/store_agent/node/directory_object_spec.rb +563 -0
- data/spec/store_agent/node/file_object_spec.rb +379 -0
- data/spec/store_agent/node/locker_spec.rb +191 -0
- data/spec/store_agent/node/metadata_spec.rb +339 -0
- data/spec/store_agent/node/object_spec.rb +73 -0
- data/spec/store_agent/node/path_validator_spec.rb +121 -0
- data/spec/store_agent/node/permission_spec.rb +232 -0
- data/spec/store_agent/user_spec.rb +127 -0
- data/spec/store_agent/version_manager/git_shared_context.rb +286 -0
- data/spec/store_agent/version_manager/ruby_git_spec.rb +32 -0
- data/spec/store_agent/version_manager/rugged_git_spec.rb +32 -0
- data/spec/store_agent/workspace_spec.rb +107 -0
- data/spec/store_agent_spec.rb +53 -0
- data/store_agent.gemspec +33 -0
- metadata +252 -0
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
#--
|
|
2
|
+
# Copyright 2015 realglobe, Inc.
|
|
3
|
+
#
|
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
# you may not use this file except in compliance with the License.
|
|
6
|
+
# You may obtain a copy of the License at
|
|
7
|
+
#
|
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
#
|
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
# See the License for the specific language governing permissions and
|
|
14
|
+
# limitations under the License.
|
|
15
|
+
#++
|
|
16
|
+
|
|
17
|
+
module StoreAgent
|
|
18
|
+
module Node
|
|
19
|
+
# メタデータや権限情報など、オブジェクトに付属する情報<br>
|
|
20
|
+
# データはJSON形式のファイルで保存され、ハッシュ形式のデータとしてアクセスできる
|
|
21
|
+
class Attachment
|
|
22
|
+
extend Forwardable
|
|
23
|
+
include StoreAgent::Validator
|
|
24
|
+
|
|
25
|
+
attr_reader :object
|
|
26
|
+
def_delegators :object, *%w(current_user root? directory?)
|
|
27
|
+
|
|
28
|
+
def initialize(object: nil) # :nodoc:
|
|
29
|
+
@object = object
|
|
30
|
+
validates_to_be_not_nil_value!(:object)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# ハッシュ形式のデータにアクセスするためのメソッド
|
|
34
|
+
def data
|
|
35
|
+
@data ||= (load || initial_data)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# オブジェクトの作成時に一緒に作成される
|
|
39
|
+
def create
|
|
40
|
+
dirname = File.dirname(file_path)
|
|
41
|
+
if !File.exists?(dirname)
|
|
42
|
+
FileUtils.mkdir(dirname)
|
|
43
|
+
end
|
|
44
|
+
save
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# オブジェクトの削除時に一緒に削除される
|
|
48
|
+
def delete
|
|
49
|
+
if object.directory?
|
|
50
|
+
FileUtils.remove_dir(File.dirname(file_path))
|
|
51
|
+
else
|
|
52
|
+
FileUtils.rm(file_path)
|
|
53
|
+
end
|
|
54
|
+
object.workspace.version_manager.remove(file_path)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# データをファイルに保存するメソッド
|
|
58
|
+
def save
|
|
59
|
+
json_data = Oj.dump(data, mode: :compat, indent: StoreAgent.config.json_indent_level)
|
|
60
|
+
encoded_data = StoreAgent.config.attachment_data_encoders.inject(json_data) do |data, encoder|
|
|
61
|
+
encoder.encode(data)
|
|
62
|
+
end
|
|
63
|
+
open(file_path, File::WRONLY | File::CREAT) do |f|
|
|
64
|
+
f.truncate(0)
|
|
65
|
+
f.write encoded_data
|
|
66
|
+
end
|
|
67
|
+
object.workspace.version_manager.add(file_path)
|
|
68
|
+
reload
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# データをファイルから読み込むメソッド
|
|
72
|
+
def load
|
|
73
|
+
if File.exists?(file_path)
|
|
74
|
+
encoded_data = open(file_path, "rb").read
|
|
75
|
+
json_data = StoreAgent.config.attachment_data_encoders.reverse.inject(encoded_data) do |data, encoder|
|
|
76
|
+
encoder.decode(data)
|
|
77
|
+
end
|
|
78
|
+
Oj.load(json_data)
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# 保存されていない変更を破棄する
|
|
83
|
+
def reload
|
|
84
|
+
@data = nil
|
|
85
|
+
self
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def inspect # :nodoc:
|
|
89
|
+
Oj.dump(data, mode: :compat, indent: 2)
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
#--
|
|
2
|
+
# Copyright 2015 realglobe, Inc.
|
|
3
|
+
#
|
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
# you may not use this file except in compliance with the License.
|
|
6
|
+
# You may obtain a copy of the License at
|
|
7
|
+
#
|
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
#
|
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
# See the License for the specific language governing permissions and
|
|
14
|
+
# limitations under the License.
|
|
15
|
+
#++
|
|
16
|
+
|
|
17
|
+
module StoreAgent
|
|
18
|
+
module Node
|
|
19
|
+
# ファイルサイズ、作成者、更新日時などの情報
|
|
20
|
+
class Metadata < Attachment
|
|
21
|
+
def_delegators :data, *%w([] []=)
|
|
22
|
+
|
|
23
|
+
# TODO check disk_usage before save
|
|
24
|
+
|
|
25
|
+
def create
|
|
26
|
+
super
|
|
27
|
+
parent.update(disk_usage: disk_usage, directory_file_count: 1, tree_file_count: 1, recursive: true)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def update(disk_usage: 0, directory_file_count: 0, tree_file_count: 0, recursive: false)
|
|
31
|
+
if directory?
|
|
32
|
+
self["directory_file_count"] += directory_file_count
|
|
33
|
+
self["tree_file_count"] += tree_file_count
|
|
34
|
+
end
|
|
35
|
+
self.disk_usage += disk_usage
|
|
36
|
+
save
|
|
37
|
+
if recursive
|
|
38
|
+
parent.update(disk_usage: disk_usage, tree_file_count: tree_file_count, recursive: recursive)
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def delete
|
|
43
|
+
parent.update(disk_usage: -disk_usage, directory_file_count: -1, tree_file_count: -1, recursive: true)
|
|
44
|
+
super
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def base_path # :nodoc:
|
|
48
|
+
"#{@object.workspace.metadata_dirname}#{@object.path}"
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# オブジェクトのメタデータを保存しているファイルの絶対パス
|
|
52
|
+
def file_path
|
|
53
|
+
"#{base_path}#{StoreAgent.config.metadata_extension}"
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# ディスク使用量をバイトからキロバイトなどの単位に変換するメソッド
|
|
57
|
+
def self.datasize_format(size)
|
|
58
|
+
byte_names = %w(KB MB GB TB PB)
|
|
59
|
+
byte_length = size.abs.to_s(2).length
|
|
60
|
+
if byte_length <= 10
|
|
61
|
+
"#{size} bytes"
|
|
62
|
+
else
|
|
63
|
+
exponent = [byte_names.length, (byte_length - 1) / 10].min
|
|
64
|
+
sprintf("%0.2f%s", size.to_f / (2 ** (10 * exponent)), byte_names[exponent - 1])
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def disk_usage
|
|
69
|
+
if directory?
|
|
70
|
+
self["directory_bytes"]
|
|
71
|
+
else
|
|
72
|
+
self["bytes"]
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def disk_usage=(usage)
|
|
77
|
+
usage_string = StoreAgent::Node::Metadata.datasize_format(usage)
|
|
78
|
+
if directory?
|
|
79
|
+
self["directory_size"] = usage_string
|
|
80
|
+
self["directory_bytes"] = usage
|
|
81
|
+
else
|
|
82
|
+
self["size"] = usage_string
|
|
83
|
+
self["bytes"] = usage
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def owner=(identifier)
|
|
88
|
+
self["owner"] = identifier
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def updated_at=(time)
|
|
92
|
+
self["updated_at"] = time.to_s
|
|
93
|
+
self["updated_at_unix_timestamp"] = time.to_i
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
private
|
|
97
|
+
|
|
98
|
+
def parent
|
|
99
|
+
if root?
|
|
100
|
+
SuperRootMetadata.new
|
|
101
|
+
else
|
|
102
|
+
object.parent_directory.metadata
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def initial_data
|
|
107
|
+
object.default_metadata
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# 最上位階層の親ディレクトリのメタデータとして振る舞うダミーのクラス
|
|
111
|
+
class SuperRootMetadata < Metadata # :nodoc:
|
|
112
|
+
def initialize(*)
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def update(*)
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
end
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
#--
|
|
2
|
+
# Copyright 2015 realglobe, Inc.
|
|
3
|
+
#
|
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
# you may not use this file except in compliance with the License.
|
|
6
|
+
# You may obtain a copy of the License at
|
|
7
|
+
#
|
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
#
|
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
# See the License for the specific language governing permissions and
|
|
14
|
+
# limitations under the License.
|
|
15
|
+
#++
|
|
16
|
+
|
|
17
|
+
module StoreAgent
|
|
18
|
+
module Node
|
|
19
|
+
# オブジェクトの権限情報
|
|
20
|
+
class Permission < Attachment
|
|
21
|
+
# オブジェクトに対して、引数で受け取った権限を持つなら true を返す
|
|
22
|
+
def allow?(permission_name)
|
|
23
|
+
case
|
|
24
|
+
when current_user.super_user?
|
|
25
|
+
true
|
|
26
|
+
when !(permission_value = get_permission_value(permission_name)).nil?
|
|
27
|
+
permission_value
|
|
28
|
+
else
|
|
29
|
+
!!data["guest"][permission_name]
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# 権限を設定する
|
|
34
|
+
def set!(identifier: nil, permission_values: {})
|
|
35
|
+
return if permission_values.empty?
|
|
36
|
+
user_permission = [identifier].flatten.inject(data["users"]) do |r, id|
|
|
37
|
+
r[id] ||= {}
|
|
38
|
+
end
|
|
39
|
+
permission_values.each do |permission_name, value|
|
|
40
|
+
user_permission[permission_name] = value
|
|
41
|
+
end
|
|
42
|
+
save
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# 権限を解除する
|
|
46
|
+
def unset!(identifier: nil, permission_names: [])
|
|
47
|
+
identifiers = [identifier].flatten
|
|
48
|
+
permission_names = [permission_names].flatten
|
|
49
|
+
user_permission = find_permission(data["users"], identifiers)
|
|
50
|
+
if user_permission
|
|
51
|
+
user_permission.delete_if do |permission_name, _|
|
|
52
|
+
permission_names.include?(permission_name)
|
|
53
|
+
end
|
|
54
|
+
sweep_permission(data["users"], identifiers)
|
|
55
|
+
save
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def base_path # :nodoc:
|
|
60
|
+
"#{@object.workspace.permission_dirname}#{@object.path}"
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# オブジェクトの権限情報を保存しているファイルの絶対パス
|
|
64
|
+
def file_path
|
|
65
|
+
"#{base_path}#{StoreAgent.config.permission_extension}"
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
private
|
|
69
|
+
|
|
70
|
+
def find_permission(data, identifiers)
|
|
71
|
+
identifier = identifiers.first
|
|
72
|
+
next_data = data[identifier]
|
|
73
|
+
next_identifiers = identifiers[1..-1]
|
|
74
|
+
case
|
|
75
|
+
when next_identifiers.empty?
|
|
76
|
+
next_data
|
|
77
|
+
when next_data
|
|
78
|
+
find_permission(next_data, next_identifiers)
|
|
79
|
+
else
|
|
80
|
+
nil
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def sweep_permission(data, identifiers)
|
|
85
|
+
identifier = identifiers.first
|
|
86
|
+
next_data = data[identifier]
|
|
87
|
+
if next_data
|
|
88
|
+
sweep_permission(next_data, identifiers[1..-1])
|
|
89
|
+
if next_data.empty?
|
|
90
|
+
data.delete(identifier)
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def get_permission_value(permission_name)
|
|
96
|
+
current_user.identifiers.reverse.each do |identifier|
|
|
97
|
+
user_permission = [identifier].flatten.inject(data["users"]) do |r, id|
|
|
98
|
+
r[id] || break
|
|
99
|
+
end
|
|
100
|
+
if user_permission && user_permission.key?(permission_name)
|
|
101
|
+
return user_permission[permission_name]
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
nil
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def initial_data
|
|
108
|
+
user_permission = {}
|
|
109
|
+
if !(current_user.super_user? || current_user.guest?)
|
|
110
|
+
user_permission = current_user.identifier_array.reverse.inject(@object.initial_permission) do |r, id|
|
|
111
|
+
{id => r}
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
{
|
|
115
|
+
"users" => user_permission,
|
|
116
|
+
"guest" => StoreAgent.config.default_guest_permission
|
|
117
|
+
}
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
end
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
#--
|
|
2
|
+
# Copyright 2015 realglobe, Inc.
|
|
3
|
+
#
|
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
# you may not use this file except in compliance with the License.
|
|
6
|
+
# You may obtain a copy of the License at
|
|
7
|
+
#
|
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
#
|
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
# See the License for the specific language governing permissions and
|
|
14
|
+
# limitations under the License.
|
|
15
|
+
#++
|
|
16
|
+
|
|
17
|
+
module StoreAgent
|
|
18
|
+
module Node
|
|
19
|
+
# ファイルやディレクトリなど、オブジェクトの雛形となるクラス<br>
|
|
20
|
+
# 実際にはファイルやディレクトリなど、このクラスを継承したクラスを使用する
|
|
21
|
+
class Object
|
|
22
|
+
extend Forwardable
|
|
23
|
+
include StoreAgent::Validator
|
|
24
|
+
prepend *[] <<
|
|
25
|
+
StoreAgent::Node::PathValidator <<
|
|
26
|
+
StoreAgent::Node::PermissionChecker <<
|
|
27
|
+
StoreAgent::Node::Locker
|
|
28
|
+
|
|
29
|
+
# def self.inherited(child)
|
|
30
|
+
# child.include StoreAgent::Node::Locker
|
|
31
|
+
# child.include StoreAgent::Node::PermissionChecker
|
|
32
|
+
# child.include StoreAgent::Node::PathValidator
|
|
33
|
+
# end
|
|
34
|
+
|
|
35
|
+
attr_reader :workspace, :path
|
|
36
|
+
def_delegators :workspace, *%w(current_user)
|
|
37
|
+
|
|
38
|
+
def initialize(workspace: nil, path: "/") # :nodoc:
|
|
39
|
+
@workspace = workspace
|
|
40
|
+
validates_to_be_not_nil_value!(:workspace)
|
|
41
|
+
@path = sanitize_path(path)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# オブジェクトに紐づくメタデータのインスタンス
|
|
45
|
+
def metadata
|
|
46
|
+
@metadata ||= StoreAgent::Node::Metadata.new(object: self)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# オブジェクトに紐づく権限情報のインスタンス
|
|
50
|
+
def permission
|
|
51
|
+
@permission ||= StoreAgent::Node::Permission.new(object: self)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def initial_owner # :nodoc:
|
|
55
|
+
@initial_owner ||= current_user.identifier
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def initial_owner=(owner_identifier) # :nodoc:
|
|
59
|
+
authorize!("chown")
|
|
60
|
+
@initial_owner = owner_identifier
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def initial_permission # :nodoc:
|
|
64
|
+
@initial_permission ||= StoreAgent.config.default_owner_permission
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def initial_permission=(permissions) # :nodoc:
|
|
68
|
+
authorize!("chmod")
|
|
69
|
+
@initial_permission = permissions
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def create(*)
|
|
73
|
+
workspace.version_manager.transaction("created #{path}") do
|
|
74
|
+
yield
|
|
75
|
+
metadata.create
|
|
76
|
+
permission.create
|
|
77
|
+
end
|
|
78
|
+
self
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def read(*)
|
|
82
|
+
yield
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def update(*)
|
|
86
|
+
workspace.version_manager.transaction("updated #{path}") do
|
|
87
|
+
yield
|
|
88
|
+
end
|
|
89
|
+
true
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def delete(*)
|
|
93
|
+
workspace.version_manager.transaction("deleted #{path}") do
|
|
94
|
+
yield
|
|
95
|
+
metadata.delete
|
|
96
|
+
permission.delete
|
|
97
|
+
end
|
|
98
|
+
true
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def touch(*)
|
|
102
|
+
workspace.version_manager.transaction("touch #{path}") do
|
|
103
|
+
metadata.reload
|
|
104
|
+
yield
|
|
105
|
+
metadata.updated_at = Time.now
|
|
106
|
+
metadata.save
|
|
107
|
+
workspace.version_manager.add(permission.file_path)
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def copy(dest_path = nil)
|
|
112
|
+
workspace.version_manager.transaction("copy #{path} to #{dest_path}") do
|
|
113
|
+
yield
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def move(dest_path = nil)
|
|
118
|
+
workspace.version_manager.transaction("move #{path} to #{dest_path}") do
|
|
119
|
+
yield
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def get_metadata(*) # :nodoc:
|
|
124
|
+
yield
|
|
125
|
+
metadata.data
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def get_permissions(*) # :nodoc:
|
|
129
|
+
yield
|
|
130
|
+
permission.data
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def chown(*, identifier: nil, **_)
|
|
134
|
+
workspace.version_manager.transaction("change_owner #{path}") do
|
|
135
|
+
yield
|
|
136
|
+
metadata.owner = identifier
|
|
137
|
+
metadata.save
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def set_permission(identifier: nil, permission_values: {}, **_)
|
|
142
|
+
workspace.version_manager.transaction("add_permission #{path}") do
|
|
143
|
+
permission.set!(identifier: identifier, permission_values: permission_values)
|
|
144
|
+
yield
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
def unset_permission(identifier: nil, permission_names: [], **_)
|
|
149
|
+
workspace.version_manager.transaction("remove_permission #{path}") do
|
|
150
|
+
permission.unset!(identifier: identifier, permission_names: permission_names)
|
|
151
|
+
yield
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
# 親階層のディレクトリオブジェクトを返す
|
|
156
|
+
def parent_directory
|
|
157
|
+
if !root?
|
|
158
|
+
@parent_directory ||= StoreAgent::Node::DirectoryObject.new(workspace: @workspace, path: File.dirname(@path))
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
# バージョン管理をしている場合、変更があったリビジョンの一覧を返す
|
|
163
|
+
def revisions
|
|
164
|
+
workspace.version_manager.revisions("storage#{path}")
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
# オブジェクトが存在するなら true を返す
|
|
168
|
+
def exists?
|
|
169
|
+
File.exists?(storage_object_path)
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
# ファイルの種類。file、directory など
|
|
173
|
+
def filetype
|
|
174
|
+
File.ftype(storage_object_path)
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
def initial_metadata # :nodoc:
|
|
178
|
+
@initial_metadata ||= {}
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
def default_metadata # :nodoc:
|
|
182
|
+
{
|
|
183
|
+
"size" => StoreAgent::Node::Metadata.datasize_format(initial_bytesize),
|
|
184
|
+
"bytes" => initial_bytesize,
|
|
185
|
+
"owner" => initial_owner,
|
|
186
|
+
"is_dir" => directory?,
|
|
187
|
+
"created_at" => updated_at.to_s,
|
|
188
|
+
"updated_at" => updated_at.to_s,
|
|
189
|
+
"created_at_unix_timestamp" => updated_at.to_i,
|
|
190
|
+
"updated_at_unix_timestamp" => updated_at.to_i,
|
|
191
|
+
}.merge(initial_metadata)
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
# true を返す場合、ファイルツリーの最上位ディレクトリとして認識される
|
|
195
|
+
def root?
|
|
196
|
+
@path == "/"
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
# true を返す場合、ディレクトリとして認識される
|
|
200
|
+
def directory?
|
|
201
|
+
false
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
# true を返す場合、ファイルとして認識される
|
|
205
|
+
def file?
|
|
206
|
+
false
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
# オブジェクトの絶対パス
|
|
210
|
+
def storage_object_path
|
|
211
|
+
"#{@workspace.storage_dirname}#{@path}"
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
private
|
|
215
|
+
|
|
216
|
+
def sanitize_path(path)
|
|
217
|
+
File.absolute_path("/./#{path}")
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
def owner?
|
|
221
|
+
metadata["owner"] == current_user.identifier
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
def initial_bytesize
|
|
225
|
+
0
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
def updated_at
|
|
229
|
+
File.mtime(storage_object_path)
|
|
230
|
+
end
|
|
231
|
+
end
|
|
232
|
+
end
|
|
233
|
+
end
|