s3backup 0.5.1 → 0.6.1

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.
data/History.txt CHANGED
@@ -1,4 +1,4 @@
1
- === 0.0.1 2009-10-21
2
-
3
- * 1 major enhancement:
4
- * Initial release
1
+ === 0.0.1 2009-10-21
2
+
3
+ * 1 major enhancement:
4
+ * Initial release
data/Manifest.txt CHANGED
@@ -9,6 +9,7 @@ lib/s3backup.rb
9
9
  lib/s3backup/backup.rb
10
10
  lib/s3backup/cli.rb
11
11
  lib/s3backup/crypt.rb
12
+ lib/s3backup/manager.rb
12
13
  lib/s3backup/restore.rb
13
14
  lib/s3backup/s3log.rb
14
15
  lib/s3backup/s3wrapper.rb
data/PostInstall.txt CHANGED
@@ -1,7 +1,7 @@
1
-
2
- For more information on s3backup, see http://s3backup.rubyforge.org
3
-
4
- NOTE: Change this information in PostInstall.txt
5
- You can also delete it if you don't want it.
6
-
7
-
1
+
2
+ For more information on s3backup, see http://s3backup.rubyforge.org
3
+
4
+ NOTE: Change this information in PostInstall.txt
5
+ You can also delete it if you don't want it.
6
+
7
+
@@ -1,7 +1,6 @@
1
- require 'cgi'
2
1
  require 's3backup/s3wrapper'
3
2
  require 's3backup/s3log'
4
- require 's3backup/tree_info'
3
+ require 's3backup/manager'
5
4
  module S3backup
6
5
  class Backup
7
6
  def initialize(config)
@@ -9,21 +8,16 @@ module S3backup
9
8
  directories = config["directories"]
10
9
  @directories = directories.map{|d| d=~/\/$/ ? d.chop : d}
11
10
  begin
12
- @s3_obj = S3Wrapper.new(config)
11
+ @s3_obj = S3Wrapper.new(config,true)
13
12
  rescue => err
14
13
  S3log.error(err.backtrace.join("\n")+"\n"+err.message)
15
14
  exit -1
16
15
  end
17
- @target_infos = {:attributes=> [],:tree_infos => []}
18
- @directories.each do |dir|
19
- @target_infos[:tree_infos].push(TreeInfo.new(dir))
20
- S3log.debug("tree_info=#{@target_infos[:tree_infos].inspect}")
21
- @target_infos[:attributes].push({:base => dir,:update_date => Date.today})
22
- end
16
+ @manager = Manager.new(@s3_obj,config)
23
17
  end
24
18
  def check_config(config)
25
19
  unless config["directories"]
26
- S3log.error("directories doesn't exist in #{config_file}.")
20
+ S3log.error("directories doesn't exist in config file.")
27
21
  exit -1
28
22
  end
29
23
  unless config["directories"].class == Array
@@ -45,27 +39,8 @@ module S3backup
45
39
  def start
46
40
  begin
47
41
  first_flg=false
48
- unless @s3_obj.bucket_exist?
49
- first_flg = true
50
- @s3_obj.create_bucket
51
- end
52
- @target_infos[:attributes].each_with_index do |attribute,i|
53
- base = CGI.escape(attribute[:base])
54
- tree_file_name = "tree_"+base+".yml"
55
- tree_data = nil
56
- unless first_flg
57
- #前回のファイル・ツリーをAWS S3から取得
58
- tree_data = @s3_obj.get(tree_file_name)
59
- end
60
- #前回と今回のファイル・ツリーを比較
61
- diff_info = @target_infos[:tree_infos][i].diff(TreeInfo.new(tree_data))
62
- S3log.debug("diff_info=#{diff_info.inspect}")
63
- #更新されたディレクトリをAWS S3にアップロード
64
- @s3_obj.store_directories(diff_info[:directory][:add] + diff_info[:directory][:modify])
65
- #削除されたディレクトリをAWS S3からdelete
66
- @s3_obj.delete_directories(diff_info[:directory][:remove])
67
- #今回のファイル・ツリーをAWS S3に登録
68
- @s3_obj.post(tree_file_name,@target_infos[:tree_infos][i].dump_yaml)
42
+ @directories.each do |dir|
43
+ @manager.differential_copy(dir)
69
44
  end
70
45
  rescue => err
71
46
  S3log.error(err.backtrace.join("\n")+"\n"+err.message)
@@ -0,0 +1,232 @@
1
+ require 'cgi'
2
+ require 'tempfile'
3
+ require 'fileutils'
4
+ require 's3backup/s3log'
5
+ require 's3backup/tree_info'
6
+ module S3backup
7
+ class Manager
8
+ DEFAULT_BUF_READ_SIZE=1024*1024*128
9
+ def initialize(target,config)
10
+ @target = target
11
+ set_config(config)
12
+ end
13
+ def set_config(config)
14
+ if config["password"] and config["password"] != ""
15
+ unless config["salt"]
16
+ raise "salt doesn't exist in config file.\n"
17
+ end
18
+ unless config["salt"] =~ /[0-9A-Fa-f]{16}/
19
+ raise "salt format shoud be HexString and length should be 16.\n"
20
+ end
21
+ if config["BUF_SIEZE"]
22
+ size=config["BUF_SIEZE"]
23
+ if size > 1000*1000*1000*5
24
+ raise "BUF_SIZE must be less than 5G"
25
+ end
26
+ else
27
+ @buf_size = DEFAULT_BUF_READ_SIZE
28
+ end
29
+ @aes = Crypt.new(config["password"],config["salt"])
30
+ end
31
+ end
32
+ #指定されたディレクトリをtar gzip形式で圧縮する
33
+ def to_tgz(path,dir)
34
+ #サブディレクトリを圧縮の対象外にする。
35
+ sub_dir = []
36
+ Dir.foreach(dir) do |file|
37
+ next if /^\.+$/ =~ file
38
+ sub_dir.push(file) if File.directory?(dir+"/"+file)
39
+ end
40
+ exclude = ""
41
+ exclude = exclude + " --exclude=" + sub_dir.join(" --exclude=") if sub_dir.length != 0
42
+ cmd = "(cd #{File.dirname(dir)};tar -czvf #{path} #{exclude} #{File.basename(dir)} > /dev/null 2>&1)"
43
+ S3log.debug(cmd)
44
+ system(cmd)
45
+ unless $?.success?
46
+ raise "feiled #{cmd} execute. #{$?.inspect}"
47
+ end
48
+ end
49
+ def from_tgz(path,dir)
50
+ cmd = "tar -xzvf #{path} -C #{dir} > /dev/null 2>&1"
51
+ S3log.debug(cmd)
52
+ system(cmd)
53
+ unless $?.success?
54
+ raise "feiled #{cmd} execute. #{$?.inspect}"
55
+ end
56
+ end
57
+ def get_chain(key)
58
+ data = nil
59
+ data_set = nil
60
+ i=1
61
+ if @aes
62
+ key = @aes.encrypt(key)
63
+ end
64
+ while 1
65
+ key_name = i.to_s()+"_"+key
66
+ data = @target.get(key_name)
67
+ if data == nil
68
+ break
69
+ end
70
+ if i==1
71
+ data_set = ''
72
+ end
73
+ if @aes
74
+ data = @aes.decrypt(data)
75
+ end
76
+ data_set += data
77
+ i+=1
78
+ end
79
+ return data_set
80
+ end
81
+ def get_directory(dir,out_dir)
82
+ data = get_chain(dir)
83
+ tmp = Tempfile.open("s3backup")
84
+ tmp.write(data)
85
+ tmp.close
86
+ #tgzのファイルをcur_dirに展開
87
+ from_tgz(tmp.path,out_dir)
88
+ tmp.close(true)
89
+ end
90
+ def get_directories(dirs,prefix,output_dir)
91
+ prefix_len = prefix.length
92
+ dirs.each do |dir|
93
+ parent = File.dirname(dir)
94
+ p_len = parent.length
95
+ relative_path = parent.slice(prefix_len,p_len - prefix_len)
96
+ cur_dir = output_dir + relative_path
97
+ get_directory(dir,cur_dir)
98
+ end
99
+ end
100
+ def store_directory(dir)
101
+ tmp = Tempfile.open("s3backup")
102
+ tmp.close
103
+ #tgzのファイルをtmp.pathに作成
104
+ to_tgz(tmp.path,dir)
105
+ #S3にディレクトリの絶対パスをキーにして、圧縮したデータをストア
106
+ i=1
107
+ key = nil
108
+ if @aes
109
+ key = @aes.encrypt(dir)
110
+ else
111
+ key = dir
112
+ end
113
+ #前回のバックアップデータ削除
114
+ cnt = 1
115
+ while @target.exists?(cnt.to_s() + "_" + key)
116
+ @target.delete(cnt.to_s() + "_" + key)
117
+ cnt+=1
118
+ end
119
+ f = File.open(tmp.path,"r")
120
+ begin
121
+ while 1
122
+ key_name = i.to_s()+"_"+key
123
+ data = f.readpartial(@buf_size)
124
+ if @aes
125
+ data = @aes.encrypt(data)
126
+ end
127
+ @target.post(key_name,data)
128
+ i+=1
129
+ end
130
+ rescue EOFError
131
+ end
132
+ tmp.close(true)
133
+ end
134
+ def delete_direcory(dir)
135
+ if @aes
136
+ dir = @aes.encrypt(dir)
137
+ end
138
+ i=1
139
+ while @target.delete("#{i}_#{dir}")
140
+ i+=1
141
+ end
142
+ end
143
+ def differential_copy(dir)
144
+ #現在のファイル・ツリーを比較
145
+ tree_info = TreeInfo.new(dir)
146
+
147
+ target_tree_name = "tree_"+dir+".yml"
148
+ tree_data = nil
149
+ #前回のファイル・ツリーを取得
150
+ old_tree = TreeInfo.new(@target.get(target_tree_name))
151
+
152
+ #前回と今回のファイル・ツリーを比較
153
+ diff_info = tree_info.diff(old_tree)
154
+ S3log.debug("diff_info=#{diff_info.inspect}")
155
+
156
+ update_dir = diff_info[:directory][:add] + diff_info[:directory][:modify]
157
+ #更新されたディレクトリをアップロード
158
+ update_dir.each do |udir|
159
+ store_directory(udir)
160
+ udir_info = tree_info.get_dir_info(udir)
161
+ #前回のファイル・ツリー情報のうち、今回アップデートしたディレクトリ情報ファイル情報を更新
162
+ old_tree.update_dir(udir,udir_info)
163
+ #更新したファイル・ツリー情報をアップロード(途中で失敗しても、resumeできるようにするため。)
164
+ @target.post(target_tree_name,old_tree.dump_yaml)
165
+ end
166
+ diff_info[:directory][:remove].each do |rm_dir|
167
+ delete_direcory(rm_dir)
168
+ end
169
+ end
170
+ def get_target_tree(dir)
171
+ base_dir = dir
172
+ tree_data = nil
173
+ before_base=""
174
+ #バックアップしたディレクトリよりも下位のディレクトリが指定されることがあるため
175
+ while 1
176
+ base = base_dir
177
+ if base == before_base
178
+ break
179
+ end
180
+ tree_file_name = "tree_"+base+".yml"
181
+ tree_data = @target.get(tree_file_name)
182
+ if tree_data
183
+ break
184
+ end
185
+ before_base = base
186
+ base_dir = File.dirname(base_dir)
187
+ end
188
+ unless tree_data
189
+ return nil
190
+ end
191
+ return TreeInfo.new(tree_data)
192
+ end
193
+ def get_target_bases
194
+ files = @target.find(/^tree_.*\.yml/)
195
+ dirs = files.map do |d|
196
+ m=/tree_(.*)\.yml/.match(d)
197
+ next nil unless m
198
+ m[1]
199
+ end
200
+ return dirs.compact
201
+ end
202
+ def expand_tree(dir,tree_info,output_dir)
203
+ tree = tree_info.hierarchie(dir)
204
+ top = tree[0].keys[0]
205
+ top_dir = File.dirname(top)
206
+ tmp_dir = CGI.escape(top_dir)
207
+ output_dir = output_dir+"/"+tmp_dir
208
+ FileUtils.mkdir_p(output_dir)
209
+ tree.each do |node|
210
+ get_directories(node.keys,top_dir,output_dir)
211
+ end
212
+ top_dir_len = top_dir.length
213
+ (tree.length - 1).downto(0){|n|
214
+ tree[n].each do |k,v|
215
+ dir_len = k.length
216
+ relative_path = k.slice(top_dir_len,dir_len - top_dir_len)
217
+ dir = output_dir + relative_path
218
+ File.utime(v[:atime],v[:mtime],dir)
219
+ end
220
+ }
221
+ end
222
+ def restore(dir,output_dir)
223
+ tree = get_target_tree(dir)
224
+ unless tree
225
+ S3log.warn("#{dir} isn't find in AWS S3. ignore")
226
+ return
227
+ end
228
+ expand_tree(dir,tree,output_dir)
229
+ S3log.debug("expand_tree=#{tree.inspect}")
230
+ end
231
+ end
232
+ end
@@ -1,8 +1,6 @@
1
- require 'cgi'
2
1
  require 's3backup/s3wrapper'
3
2
  require 's3backup/s3log'
4
- require 's3backup/tree_info'
5
- require 'fileutils'
3
+ require 's3backup/manager'
6
4
  module S3backup
7
5
  class Restore
8
6
  def initialize(output_dir,config)
@@ -10,12 +8,12 @@ module S3backup
10
8
  @output_dir = output_dir
11
9
  @directories = config["directories"]
12
10
  begin
13
- @s3_obj = S3Wrapper.new(config)
11
+ @s3_obj = S3Wrapper.new(config,false)
14
12
  rescue => err
15
13
  S3log.error(err.backtrace.join("\n")+"\n"+err.message)
16
14
  exit -1
17
15
  end
18
- @target_infos = {:attributes=> [],:tree_infos => []}
16
+ @manager = Manager.new(@s3_obj,config)
19
17
  end
20
18
  def check_config(config)
21
19
  if config["directories"]
@@ -27,67 +25,11 @@ module S3backup
27
25
  config["directories"] = config["directories"].map{|d| d=~/\/$/ ? d.chop : d}
28
26
  end
29
27
  end
30
- def get_tree(dir)
31
- base_dir = dir
32
- tree_data = nil
33
- while 1
34
- base = CGI.escape(base_dir)
35
- tree_file_name = "tree_"+base+".yml"
36
- tree_data = @s3_obj.get(tree_file_name)
37
- if tree_data or base_dir == "/"
38
- break
39
- end
40
- base_dir = File.dirname(base_dir)
41
- end
42
- unless tree_data
43
- return nil
44
- end
45
- tree_info = TreeInfo.new(tree_data)
46
- return tree_info.hierarchie(dir)
47
- end
48
- def get_bases
49
- files = @s3_obj.find(/^tree_.*\.yml/)
50
- dirs = files.map do |d|
51
- m=/tree_(.*)\.yml/.match(d)
52
- next nil unless m
53
- CGI.unescape(m[1])
54
- end
55
- return dirs.compact
56
- end
57
- def expand_tree(tree)
58
- top = tree[0].keys[0]
59
- top_dir = File.dirname(top)
60
- tmp_dir = CGI.escape(top_dir)
61
- output_dir = @output_dir+"/"+tmp_dir
62
- FileUtils.mkdir_p(output_dir)
63
- tree.each do |node|
64
- @s3_obj.get_directories(node.keys,top_dir,output_dir)
65
- end
66
- top_dir_len = top_dir.length
67
- (tree.length - 1).downto(0){|n|
68
- tree[n].each do |k,v|
69
- dir_len = k.length
70
- relative_path = k.slice(top_dir_len,dir_len - top_dir_len)
71
- dir = output_dir + relative_path
72
- File.utime(v[:atime],v[:mtime],dir)
73
- end
74
- }
75
- end
76
28
  def start
77
29
  begin
78
- unless @s3_obj.bucket_exist?
79
- S3log.error("bucket: #{@s3_obj.bucket} isn't found!")
80
- exit -1
81
- end
82
- @directories = get_bases unless @directories
30
+ @directories = @manager.get_target_bases unless @directories
83
31
  @directories.each do |dir|
84
- tree = get_tree(dir)
85
- unless tree
86
- s3log.warn("#{dir} isn't find in AWS S3. ignore")
87
- next
88
- end
89
- puts tree.inspect
90
- expand_tree(tree)
32
+ @manager.restore(dir,@output_dir)
91
33
  end
92
34
  rescue => err
93
35
  S3log.error(err.backtrace.join("\n")+"\n"+err.message)
@@ -1,13 +1,15 @@
1
+ require 'cgi'
1
2
  require 'aws/s3'
2
- require 'tempfile'
3
3
  require 's3backup/crypt'
4
4
  module S3backup
5
5
  class S3Wrapper
6
- BUF_READ_SIZE=1024*1024*128
7
6
  attr_reader :bucket
8
- def initialize(config)
7
+ def initialize(config,create_flg)
8
+ @bucket= nil
9
+ @s3objects =nil
9
10
  #設定ファイルの内容をメンバ変数にセット
10
11
  set_config(config)
12
+ #設定ファイルの内容をメンバ変数にセット
11
13
  args = {
12
14
  :access_key_id => @access_key_id,
13
15
  :secret_access_key => @secret_access_key
@@ -17,77 +19,43 @@ module S3backup
17
19
  end
18
20
  #AWS S3に接続
19
21
  AWS::S3::Base.establish_connection!(args)
20
- end
21
- def bucket_exist?()
22
- #AWS S3にあがっているすべてのBucketを取得
23
- buckets = AWS::S3::Service.buckets
24
- #すべてのBuckeから指定されたBucketの検索
25
- first_flg = true
26
- buckets.each do |bucket|
27
- if bucket.name == @bucket
28
- return true
22
+ if create_flg
23
+ begin
24
+ @bucket = AWS::S3::Bucket.find(@bucket_name)
25
+ rescue AWS::S3::NoSuchBucket
26
+ @bucket = create_bucket
29
27
  end
28
+ else
29
+ @bucket = AWS::S3::Bucket.find(@bucket_name)
30
30
  end
31
- return false
32
31
  end
33
32
  def create_bucket()
34
- S3log.info("Bucket.create(#{@bucket})")
33
+ S3log.info("Bucket.create(#{@bucket_name})")
35
34
  #Bucket作成
36
- ret = AWS::S3::Bucket.create(@bucket)
35
+ ret = AWS::S3::Bucket.create(@bucket_name)
37
36
  unless ret
38
37
  raise "AWS::S3::Bucket create error"
39
38
  end
40
39
  end
40
+ def rename(orig,dest)
41
+ AWS::S3::S3Object.rename(orig,dest,@bucket_name)
42
+ end
43
+ def exists?(key)
44
+ key=CGI.escape(key)
45
+ ret = AWS::S3::S3Object.exists? key,@bucket_name
46
+ end
41
47
  def get(key)
42
48
  key_name = CGI.escape(key)
43
49
  data = nil
44
- if AWS::S3::S3Object.exists? key_name,@bucket
45
- data = AWS::S3::S3Object.value(key_name,@bucket)
46
- if @aes
47
- data = @aes.decrypt(data)
48
- end
50
+ if AWS::S3::S3Object.exists? key_name,@bucket_name
51
+ data = AWS::S3::S3Object.value(key_name,@bucket_name)
49
52
  end
50
53
  return data
51
54
  end
52
- def store_directories(dirs)
53
- dirs.each do |dir|
54
- store_directory(dir)
55
- end
56
- end
57
- def get_directory(dir,out_dir)
58
- data = get_chain(dir)
59
- tmp = Tempfile.open("s3backup")
60
- tmp.write(data)
61
- tmp.close
62
- #tgzのファイルをcur_dirに展開
63
- from_tgz(tmp.path,out_dir)
64
- tmp.close(true)
65
- end
66
- def get_directories(dirs,prefix,output_dir)
67
- prefix_len = prefix.length
68
- dirs.each do |dir|
69
- parent = File.dirname(dir)
70
- p_len = parent.length
71
- relative_path = parent.slice(prefix_len,p_len - prefix_len)
72
- cur_dir = output_dir + relative_path
73
- get_directory(dir,cur_dir)
74
- end
75
- end
76
- def delete_directories(dirs)
77
- dirs.each do |dir|
78
- delete_chain(dir)
79
- end
80
- end
81
55
  def post(key,val)
82
- if val.length > BUF_READ_SIZE
83
- raise "max size = #{BUF_READ_SIZE} but size = #{val.size}"
84
- end
85
56
  key_name = CGI.escape(key)
86
- if @aes
87
- val = @aes.encrypt(val)
88
- end
89
- AWS::S3::S3Object.store(key_name,val,@bucket)
90
57
  S3log.info("S3Object.store(#{key_name})")
58
+ AWS::S3::S3Object.store(key_name,val,@bucket_name)
91
59
  end
92
60
  def set_config(config)
93
61
  err_msg = ""
@@ -107,109 +75,35 @@ module S3backup
107
75
  @proxy[:port] = config["proxy_port"] if config["proxy_port"]
108
76
  @proxy[:user] = config["proxy_user"] if config["proxy_user"]
109
77
  @proxy[:password] = config["proxy_password"] if config["proxy_password"]
110
- @bucket = config["bucket"]
111
- if config["password"] and config["password"] != ""
112
- if config["salt"]
113
- if config["salt"] =~ /[0-9A-Fa-f]{16}/
114
- @aes = Crypt.new(config["password"],config["salt"])
115
- else
116
- err_msg += "salt format shoud be HexString and length should be 16.\n"
117
- end
118
- else
119
- err_msg += "salt doesn't exist in config file.\n"
120
- end
121
- end
78
+ @bucket_name = config["bucket"]
122
79
  if err_msg != ""
123
80
  raise err_msg
124
81
  end
125
82
  end
126
- #指定されたディレクトリをtar gzip形式で圧縮する
127
- def to_tgz(path,dir)
128
- #サブディレクトリを圧縮の対象外にする。
129
- sub_dir = []
130
- Dir.foreach(dir) do |file|
131
- next if /^\.+$/ =~ file
132
- sub_dir.push(file) if File.directory?(dir+"/"+file)
133
- end
134
- exclude = ""
135
- exclude = exclude + " --exclude=" + sub_dir.join(" --exclude=") if sub_dir.length != 0
136
- cmd = "(cd #{File.dirname(dir)};tar -czvf #{path} #{exclude} #{File.basename(dir)} > /dev/null 2>&1)"
137
- S3log.info(cmd)
138
- system(cmd)
139
- unless $?.success?
140
- raise "feiled #{cmd} execute. #{$?.inspect}"
141
- end
142
- end
143
- def from_tgz(path,dir)
144
- cmd = "tar -xzvf #{path} -C #{dir} > /dev/null 2>&1"
145
- S3log.info(cmd)
146
- system(cmd)
147
- unless $?.success?
148
- raise "feiled #{cmd} execute. #{$?.inspect}"
149
- end
150
- end
151
83
  def delete(key)
152
- if @aes
153
- key_name = CGI.escape(@aes.encrypt(key))
154
- else
155
- key_name = CGI.escape(key)
156
- end
157
- if AWS::S3::S3Object.exists? key_name
158
- S3log.info("S3Object.delete(#{key_name})")
159
- AWS::S3::S3Object.delete(key_name,@bucket)
84
+ if exists? key
85
+ S3log.info("S3Object.delete(#{CGI.escape(key)})")
86
+ AWS::S3::S3Object.delete(CGI.escape(key),@bucket_name)
160
87
  return true
161
88
  end
162
89
  return false
163
90
  end
164
- def delete_chain(key)
165
- i=1
166
- while delete(i.to_s + "_" + key)
167
- i+=1
168
- end
169
- end
170
- def post_chain(key,f)
171
- i=1
172
- begin
173
- while 1
174
- key_name = i.to_s()+"_"+key
175
- if @aes
176
- key_name = @aes.encrypt(key_name)
91
+ def find(dest)
92
+ @s3objects = @backet.objects unless @s3objects
93
+ find_obj=[]
94
+ keys=@s3objects.map { |o| CGI.unescape(CGI.unescape(o.key.sub("#{@bucket_name}/","")))}
95
+ keys.each do |key|
96
+ if dest.class == Regexp
97
+ if key =~ dest
98
+ find_obj.push(key)
99
+ end
100
+ else
101
+ if key == dest
102
+ find_obj.push(key)
177
103
  end
178
- post(key_name,f.readpartial(BUF_READ_SIZE))
179
- i+=1
180
- end
181
- rescue EOFError
182
- end
183
- end
184
- def get_chain(key)
185
- data = nil
186
- data_set = nil
187
- i=1
188
- while 1
189
- key_name = i.to_s()+"_"+key
190
- if @aes
191
- key_name = @aes.encrypt(key_name)
192
- end
193
- data = get(key_name)
194
- if data == nil
195
- break
196
- end
197
- if i==1
198
- data_set = ''
199
104
  end
200
- data_set += data
201
- i+=1
202
105
  end
203
- return data_set
204
- end
205
- def store_directory(dir)
206
- tmp = Tempfile.open("s3backup")
207
- tmp.close
208
- #tgzのファイルをtmp.pathに作成
209
- to_tgz(tmp.path,dir)
210
- #S3にディレクトリの絶対パスをキーにして、圧縮したデータをストア
211
- post_chain(dir,File.open(tmp.path,"r"))
212
- tmp.close(true)
106
+ return find_obj
213
107
  end
214
108
  end
215
109
  end
@@ -3,17 +3,25 @@ module S3backup
3
3
  class TreeInfo
4
4
  attr_reader :fileMap
5
5
  def initialize(target)
6
+ @dir_map={}
7
+ @orig = nil
6
8
  if target.nil?
7
9
  @fileMap = {:file => Hash.new,:symlink => Hash.new,:directory => Hash.new}
8
10
  elsif File.directory?(target)
11
+ @orig = {:type=>"directory",:target=>target}
9
12
  @fileMap = {:file => Hash.new,:symlink => Hash.new,:directory => Hash.new}
10
13
  stat = File.stat(target)
11
14
  @fileMap[:directory][target] = {:mtime => stat.mtime, :atime => stat.atime}
15
+ @dir_map[target] = {:mtime => stat.mtime, :atime => stat.atime,:file=>{},:symlink=>{}}
12
16
  makeFileMap(target)
13
17
  elsif File.file?(target)
18
+ @orig = {:type=>"file",:target=>target}
14
19
  load_yaml(File.read(target))
20
+ make_dir_map
15
21
  else
22
+ @orig = {:type=>"data",:target=>""}
16
23
  load_yaml(target)
24
+ make_dir_map
17
25
  end
18
26
  end
19
27
  def makeFileMap(dir)
@@ -24,16 +32,70 @@ module S3backup
24
32
  name = dir + "/" + e
25
33
  if File.directory?(name)
26
34
  stat = File.stat(name)
35
+ @dir_map[name] = {:mtime => stat.mtime, :atime => stat.atime,:file=>{},:symlink=>{}}
27
36
  @fileMap[:directory][name] = {:mtime => stat.mtime, :atime => stat.atime}
28
37
  makeFileMap(name)
29
38
  elsif File.symlink?(name)
39
+ @dir_map[dir][:symlink][name] = {:source => File.readlink(name)}
30
40
  @fileMap[:symlink][name] = {:source => File.readlink(name)}
31
41
  else
32
42
  stat = File.stat(name)
43
+ @dir_map[dir][:file][name] ={:size => stat.size,:date => stat.mtime}
33
44
  @fileMap[:file][name] = {:size => stat.size,:date => stat.mtime}
34
45
  end
35
46
  end
36
47
  end
48
+ def make_dir_map
49
+ @fileMap[:directory].each do |k,v|
50
+ @dir_map[k] = {:mtime => v[:mtime], :atime => v[:atime],:file=>{},:symlink=>{}}
51
+ end
52
+ @fileMap[:file].each do |k,v|
53
+ target = @dir_map[File.dirname(k)]
54
+ #不整合だけど適当に作る
55
+ unless target
56
+ S3log.warn("Tree Data isn't correct.#{@orig.inspect}")
57
+ target = {:mtime => DateTime.now.to_s,:atime => DateTime.now.to_s,:file=>{},:symlink=>{}}
58
+ @dir_map[File.dirname(k)] = target
59
+ end
60
+ target[:file][k] = {:size => v[:size], :date => v[:date]}
61
+ end
62
+ @fileMap[:symlink].each do |k,v|
63
+ target = @dir_map[File.dirname(k)]
64
+ #不整合だけど適当に作る
65
+ unless target
66
+ S3log.warn("Tree Data isn't correct.#{@orig.inspect}")
67
+ target = {:mtime => DateTime.now.to_s,:atime => DateTime.now.to_s,:file=>{},:symlink=>{}}
68
+ @dir_map[File.dirname(k)] = target
69
+ end
70
+ target[:symlink][k] = {:source => v[:source]}
71
+ end
72
+ end
73
+ def get_dir_info(name)
74
+ return @dir_map[name]
75
+ end
76
+ def update_dir_map(name,dir_info)
77
+ @dir_map[name][:file] = dir_info[:file]
78
+ @dir_map[name][:symlink] = dir_info[:symlink]
79
+ @dir_map[name][:mtime] = dir_info[:mtime]
80
+ @dir_map[name][:atime] = dir_info[:atime]
81
+ end
82
+ def update_dir(name,dir_info)
83
+ @dir_map[name] = {:file => {},:symlink=>{}} unless @dir_map[name]
84
+ @dir_map[name][:file].each do |k,v|
85
+ @fileMap[:file].delete(k)
86
+ end
87
+ @dir_map[name][:symlink].each do |k,v|
88
+ @fileMap[:symlink].delete(k)
89
+ end
90
+ @fileMap[:directory][name] = {:mtime => dir_info[:mtime],:atime =>dir_info[:atime]}
91
+ dir_info[:file].each do |k,v|
92
+ @fileMap[:file][k] = v
93
+ end
94
+ dir_info[:symlink].each do |k,v|
95
+ @fileMap[:symlink][k] = v
96
+ end
97
+ update_dir_map(name,dir_info)
98
+ end
37
99
  def load_yaml(data)
38
100
  @fileMap = YAML.load(data)
39
101
  end
data/lib/s3backup.rb CHANGED
@@ -2,5 +2,5 @@ $:.unshift(File.dirname(__FILE__)) unless
2
2
  $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
3
3
 
4
4
  module S3backup
5
- VERSION = '0.5.1'
5
+ VERSION = '0.6.1'
6
6
  end
data/script/console CHANGED
File without changes
data/script/destroy CHANGED
File without changes
data/script/generate CHANGED
File without changes
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: s3backup
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.1
4
+ version: 0.6.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Takeshi Morita
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-10-22 00:00:00 +09:00
12
+ date: 2009-10-24 00:00:00 +09:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -55,6 +55,7 @@ files:
55
55
  - lib/s3backup/backup.rb
56
56
  - lib/s3backup/cli.rb
57
57
  - lib/s3backup/crypt.rb
58
+ - lib/s3backup/manager.rb
58
59
  - lib/s3backup/restore.rb
59
60
  - lib/s3backup/s3log.rb
60
61
  - lib/s3backup/s3wrapper.rb
@@ -92,7 +93,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
92
93
  requirements: []
93
94
 
94
95
  rubyforge_project: s3backup
95
- rubygems_version: 1.3.5
96
+ rubygems_version: 1.3.4
96
97
  signing_key:
97
98
  specification_version: 3
98
99
  summary: S3Backup is a backup tool to local directory to Amazon S3.