cloudsync 1.0.4 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.0.4
1
+ 2.0.0
data/cloudsync.gemspec CHANGED
@@ -5,7 +5,7 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{cloudsync}
8
- s.version = "1.0.4"
8
+ s.version = "2.0.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Cory Forsyth"]
@@ -3,24 +3,16 @@ require 'tempfile'
3
3
  module Cloudsync
4
4
  module Backend
5
5
  class Base
6
- attr_accessor :store, :sync_manager, :name, :prefix
6
+ attr_accessor :store, :sync_manager, :name, :upload_prefix
7
7
 
8
8
  def initialize(opts = {})
9
9
  @sync_manager = opts[:sync_manager]
10
10
  @name = opts[:name]
11
11
  @backend_type = opts[:backend] || self.class.to_s.split("::").last
12
+ @download_prefix = opts[:download_prefix] || ""
13
+ @upload_prefix = opts[:upload_prefix] || ""
12
14
  end
13
15
 
14
- def upload_prefix
15
- {:bucket => @bucket, :prefix => @prefix}
16
- end
17
-
18
- def upload_prefix_path
19
- if @bucket && @prefix
20
- "#{@bucket}/#{@prefix}"
21
- end
22
- end
23
-
24
16
  # copy
25
17
  def copy(file, to_backend)
26
18
  start_copy = Time.now
@@ -37,7 +29,7 @@ module Cloudsync
37
29
  end
38
30
 
39
31
  def to_s
40
- "#{@name}[:#{@backend_type}/#{upload_prefix_path}]"
32
+ "#{@name}[:#{@backend_type}/#{@upload_prefix}]"
41
33
  end
42
34
 
43
35
  # needs_update?
@@ -92,7 +84,7 @@ module Cloudsync
92
84
  end
93
85
 
94
86
  private
95
-
87
+
96
88
  def dry_run?
97
89
  return false unless @sync_manager
98
90
  @sync_manager.dry_run?
@@ -26,12 +26,12 @@ module Cloudsync
26
26
 
27
27
  def download(file)
28
28
  start_time = Time.now
29
- $LOGGER.info("Downloading file #{file}")
29
+ $LOGGER.info("Downloading file #{file} (#{file.path})")
30
30
 
31
31
  tempfile = file.tempfile
32
32
 
33
33
  if !dry_run?
34
- @store.interface.get(file.bucket, file.path) do |chunk|
34
+ @store.interface.get(file.bucket, file.download_path) do |chunk|
35
35
  tempfile.write chunk
36
36
  end
37
37
  end
@@ -57,7 +57,7 @@ module Cloudsync
57
57
  get_obj_from_store(file).delete
58
58
 
59
59
  if bucket = @store.bucket(file.bucket)
60
- bucket.key(file.path).delete
60
+ bucket.key(file.download_path).delete
61
61
 
62
62
  if delete_bucket_if_empty && bucket.keys.empty?
63
63
  $LOGGER.debug("Deleting empty bucket '#{bucket.name}'")
@@ -68,9 +68,9 @@ module Cloudsync
68
68
  $LOGGER.error("Caught error: #{e} trying to delete #{file}")
69
69
  end
70
70
 
71
- def files_to_sync(upload_prefix={})
71
+ def files_to_sync(upload_prefix="")
72
72
  $LOGGER.info("Getting files to sync [#{self}]")
73
-
73
+
74
74
  buckets_to_sync(upload_prefix).inject([]) do |files, bucket|
75
75
  objects_from_bucket(bucket, upload_prefix).collect do |key|
76
76
  files << Cloudsync::File.from_s3_obj(key, self.to_s)
@@ -81,18 +81,23 @@ module Cloudsync
81
81
 
82
82
  private
83
83
 
84
- def buckets_to_sync(upload_prefix)
85
- if upload_prefix[:bucket]
86
- [@store.bucket(upload_prefix[:bucket], true)]
84
+ def buckets_to_sync(upload_prefix="")
85
+ bucket_name = upload_prefix.split("/").first
86
+ if bucket_name
87
+ [@store.bucket(bucket_name, true)]
87
88
  else
88
89
  @store.buckets
89
90
  end
90
91
  end
91
92
 
92
- def objects_from_bucket(bucket, upload_prefix)
93
- if upload_prefix[:prefix]
94
- bucket.keys(:prefix => upload_prefix[:prefix])
95
- else
93
+ def objects_from_bucket(bucket, upload_prefix="")
94
+ prefix_parts = upload_prefix.split("/")
95
+ prefix_parts.shift
96
+ prefix = prefix_parts.join("/")
97
+
98
+ if !prefix.empty?
99
+ bucket.keys(:prefix => prefix)
100
+ else
96
101
  bucket.keys
97
102
  end
98
103
  end
@@ -107,6 +112,7 @@ module Cloudsync
107
112
  end
108
113
 
109
114
  def get_obj_from_store(file)
115
+ $LOGGER.debug("gofs, buck: #{file.bucket}. upload path: #{file.upload_path}")
110
116
  if bucket = @store.bucket(file.bucket)
111
117
  key = bucket.key(file.upload_path)
112
118
  return key if key.exists?
@@ -8,27 +8,22 @@ module Cloudsync::Backend
8
8
 
9
9
  def initialize(options = {})
10
10
  @host = options[:host]
11
- @base_path = options[:base_path]
12
11
  @username = options[:username]
13
12
  @password = options[:password]
14
- prefix_parts = options[:upload_prefix].split("/")
15
-
16
- @bucket = prefix_parts.shift
17
- @prefix = prefix_parts.join("/")
18
13
 
19
14
  super
20
15
  end
21
16
 
22
17
  # download
23
18
  def download(file)
24
- $LOGGER.info("Downloading #{file}")
19
+ $LOGGER.info("Downloading #{file} from #{file.download_path}")
25
20
  tempfile = file.tempfile
26
21
 
27
22
  if !dry_run?
28
23
  Net::SSH.start(@host, @username, :password => @password) do |ssh|
29
24
  ssh.sftp.connect do |sftp|
30
25
  begin
31
- sftp.download!(absolute_path(file.path), tempfile)
26
+ sftp.download!(file.download_path, tempfile)
32
27
  rescue RuntimeError => e
33
28
  if e.message =~ /permission denied/
34
29
  tempfile.close
@@ -46,12 +41,12 @@ module Cloudsync::Backend
46
41
 
47
42
  # put
48
43
  def put(file, local_filepath)
49
- $LOGGER.info("Putting #{file} to #{self}")
44
+ $LOGGER.info("Putting #{file} to #{self} (#{file.upload_path})")
50
45
  return if dry_run?
51
46
 
52
47
  Net::SSH.start(@host, @username, :password => @password) do |ssh|
53
48
  ssh.sftp.connect do |sftp|
54
- sftp.upload!(local_filepath, absolute_path(file.path))
49
+ sftp.upload!(local_filepath, file.upload_path)
55
50
  end
56
51
  end
57
52
  end
@@ -63,7 +58,7 @@ module Cloudsync::Backend
63
58
 
64
59
  Net::SSH.start(@host, @username, :password => @password) do |ssh|
65
60
  ssh.sftp.connect do |sftp|
66
- sftp.remove!(absolute_path(file.path))
61
+ sftp.remove!(file.download_path)
67
62
  end
68
63
  end
69
64
  end
@@ -73,62 +68,71 @@ module Cloudsync::Backend
73
68
  files = []
74
69
  Net::SSH.start(@host, @username, :password => @password) do |ssh|
75
70
  ssh.sftp.connect do |sftp|
76
- filepaths = sftp.dir.glob(@base_path, "**/**").collect {|entry| entry.name}
71
+ filepaths = sftp.dir.glob(@download_prefix, "**/**").collect {|entry| entry.name}
77
72
 
78
73
  files = filepaths.collect do |filepath|
79
- attrs = sftp.stat!(absolute_path(filepath))
74
+ attrs = sftp.stat!(local_filepath_from_filepath(filepath))
80
75
  next unless attrs.file?
81
76
 
82
77
  e_tag = ssh.exec!(md5sum_cmd(filepath)).split(" ").first
83
78
  Cloudsync::File.new \
84
- :bucket => @bucket,
85
- :path => filepath,
86
- :size => attrs.size,
87
- :last_modified => attrs.mtime,
88
- :e_tag => e_tag,
89
- :backend => self.to_s
79
+ :path => filepath,
80
+ :upload_prefix => @upload_prefix,
81
+ :download_prefix => @download_prefix,
82
+ :size => attrs.size,
83
+ :last_modified => attrs.mtime,
84
+ :e_tag => e_tag,
85
+ :backend => self.to_s,
86
+ :backend_type => Cloudsync::Backend::Sftp
90
87
  end.compact
91
88
  end
92
89
  end
93
90
  files
94
91
  end
95
92
 
96
- def absolute_path(path)
97
- @base_path + "/" + path
98
- end
93
+ # def absolute_path(path)
94
+ # @download_prefix + "/" + path
95
+ # end
99
96
 
100
97
  private
101
98
 
102
99
  def md5sum_cmd(filepath)
103
- Escape.shell_command(["md5sum","#{absolute_path(filepath)}"])
100
+ Escape.shell_command(["md5sum","#{local_filepath_from_filepath(filepath)}"])
101
+ end
102
+
103
+ def local_filepath_from_filepath(filepath)
104
+ stripped_path = filepath.sub(/^#{@upload_prefix}\/?/,"")
105
+ if @download_prefix
106
+ "#{@download_prefix}/#{stripped_path}"
107
+ else
108
+ stripped_path
109
+ end
104
110
  end
105
111
 
106
112
  # get_file_from_store
107
113
  def get_file_from_store(file)
108
- local_filepath = file.path.sub(/^#{@prefix}\/?/,"")
109
-
110
- $LOGGER.debug("Looking for local filepath: #{local_filepath}")
111
- $LOGGER.debug("Abs filepath: #{absolute_path(local_filepath)}")
112
-
114
+ $LOGGER.debug("Looking for local filepath: #{local_filepath_from_filepath(file.full_download_path)}")
115
+
113
116
  sftp_file = nil
114
117
  Net::SSH.start(@host, @username, :password => @password) do |ssh|
115
118
  ssh.sftp.connect do |sftp|
116
119
  begin
117
- attrs = sftp.stat!(absolute_path(local_filepath))
120
+ attrs = sftp.stat!(local_filepath_from_filepath(file.full_download_path))
118
121
  rescue Net::SFTP::StatusException => e
119
122
  break if e.message =~ /no such file/
120
123
  raise
121
124
  end
122
125
  break unless attrs.file?
123
126
 
124
- e_tag = ssh.exec!(md5sum_cmd(filepath)).split(" ").first
125
127
  sftp_file = Cloudsync::File.new \
126
- :bucket => @bucket,
127
- :path => local_filepath,
128
- :size => attrs.size,
129
- :last_modified => attrs.mtime,
130
- :e_tag => e_tag,
131
- :backend => self.to_s
128
+ :path => file.download_path,
129
+ :upload_prefix => @upload_prefix,
130
+ :download_prefix => @download_prefix,
131
+ :size => attrs.size,
132
+ :last_modified => attrs.mtime,
133
+ :e_tag => ssh.exec!(md5sum_cmd(file.download_path)).split(" ").first,
134
+ :backend => self.to_s,
135
+ :backend_type => Cloudsync::Backend::Sftp
132
136
  end
133
137
  end
134
138
  sftp_file
@@ -1,51 +1,55 @@
1
1
  module Cloudsync
2
2
  class File
3
- attr_accessor :bucket, :path, :size, :last_modified, :e_tag, :backend
4
- alias_method :container, :bucket
5
- alias_method :container=, :bucket=
3
+ attr_accessor :path, :size, :last_modified, :e_tag, :backend
6
4
 
7
- def initialize(options={})
8
- @bucket = options[:bucket]
9
- @path = options[:path]
10
- @size = options[:size]
11
- @last_modified = options[:last_modified]
12
- @e_tag = options[:e_tag]
13
- @backend = options[:backend]
5
+ def initialize(options = {})
6
+ @path = options[:path]
7
+ @size = options[:size]
8
+ @last_modified = options[:last_modified]
9
+ @e_tag = options[:e_tag]
10
+ @backend = options[:backend]
11
+ @upload_prefix = options[:upload_prefix]
12
+ @download_prefix = options[:download_prefix]
13
+ @backend_type = options[:backend_type]
14
14
  end
15
15
 
16
16
  def self.from_s3_obj(obj, backend=nil)
17
17
  return nil if obj.nil?
18
18
  new({
19
- :bucket => obj.bucket.name,
19
+ :upload_prefix => obj.bucket.name,
20
20
  :path => obj.name,
21
21
  :size => obj.size,
22
22
  :last_modified => obj.last_modified.to_i,
23
23
  :e_tag => obj.e_tag.gsub('"',''),
24
- :backend => backend})
24
+ :backend => backend,
25
+ :backend_type => Cloudsync::Backend::S3})
25
26
  end
26
27
 
27
28
  def self.from_cf_info(container, path, hash, backend)
28
- new({ :bucket => container.name,
29
+ new({
30
+ :upload_prefix => container.name,
29
31
  :path => path,
30
32
  :size => hash[:bytes],
31
33
  :last_modified => hash[:last_modified].to_gm_time.to_i,
32
34
  :e_tag => hash[:hash],
33
- :backend => backend })
35
+ :backend => backend,
36
+ :backend_type => Cloudsync::Backend::CloudFiles })
34
37
  end
35
38
 
36
39
  def self.from_cf_obj(obj, backend=nil)
37
40
  return nil if obj.nil?
38
41
  new({
39
- :bucket => obj.container.name,
42
+ :upload_prefix => obj.container.name,
40
43
  :path => obj.name,
41
44
  :size => obj.bytes.to_i,
42
45
  :last_modified => obj.last_modified.to_i,
43
46
  :e_tag => obj.etag,
44
- :backend => backend})
47
+ :backend => backend,
48
+ :backend_type => Cloudsync::Backend::CloudFiles})
45
49
  end
46
50
 
47
51
  def to_s
48
- "#{path}"
52
+ "#{full_upload_path}"
49
53
  end
50
54
 
51
55
  def unique_filename
@@ -56,14 +60,34 @@ module Cloudsync
56
60
  [bucket,path].join("/")
57
61
  end
58
62
 
63
+ def bucket
64
+ @bucket ||= begin
65
+ @upload_prefix.split("/").first
66
+ end
67
+ end
68
+ alias_method :container, :bucket
69
+
59
70
  def upload_path
60
- if @prefix
61
- @prefix + "/" + @path
62
- else
71
+ without_bucket_path = @upload_prefix.sub(/^#{bucket}\/?/,"")
72
+ if without_bucket_path.empty?
63
73
  @path
74
+ else
75
+ without_bucket_path + "/" + @path
64
76
  end
65
77
  end
66
78
 
79
+ def download_path
80
+ @download_prefix ? "#{@download_prefix}/#{@path}" : @path
81
+ end
82
+
83
+ def upload_path_without_bucket
84
+
85
+ end
86
+
87
+ def full_download_path
88
+ [bucket, download_path].join("/")
89
+ end
90
+
67
91
  def full_upload_path
68
92
  [bucket, upload_path].join("/")
69
93
  end
@@ -72,4 +96,4 @@ module Cloudsync
72
96
  Tempfile.new(unique_filename)
73
97
  end
74
98
  end
75
- end
99
+ end
@@ -74,14 +74,13 @@ module Cloudsync
74
74
 
75
75
  $LOGGER.info("Prune from #{from_backend} to #{to_backend} started at #{prune_start = Time.now}. Dry-run? #{!!dry_run?}")
76
76
 
77
- from_backend_files = [] # from_backend.files_to_sync(to_backend.upload_prefix)
78
77
  to_backend_files = to_backend.files_to_sync(from_backend.upload_prefix)
79
78
  total_files = to_backend_files.size
80
79
  last_decile_complete = 0
81
80
 
82
81
  to_backend_files.each_with_index do |file, index|
83
82
  $LOGGER.debug("Checking if file #{file} exists on [#{from_backend}]")
84
- if found_file = from_backend.find_file_from_list_or_store(file, from_backend_files)
83
+ if found_file = from_backend.find_file_from_list_or_store(file)
85
84
  $LOGGER.debug("Keeping file #{file} because it was found on #{from_backend}.")
86
85
  file_stats[:skipped] << file
87
86
  else
@@ -108,12 +107,11 @@ module Cloudsync
108
107
  $LOGGER.info("Sync from #{from_backend} to #{to_backend} started at #{sync_start = Time.now}. Mode: #{mode}. Dry-run? #{!!dry_run?}")
109
108
 
110
109
  from_backend_files = from_backend.files_to_sync(to_backend.upload_prefix)
111
- to_backend_files = [] # to_backend.files_to_sync(from_backend.upload_prefix)
112
110
  total_files = from_backend_files.size
113
111
  last_decile_complete = 0
114
112
 
115
113
  from_backend_files.each_with_index do |file, index|
116
- if (mode == :sync_all || to_backend.needs_update?(file, to_backend_files))
114
+ if (mode == :sync_all || to_backend.needs_update?(file))
117
115
  file_stats[:copied] << file
118
116
  from_backend.copy(file, to_backend)
119
117
  else
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cloudsync
3
3
  version: !ruby/object:Gem::Version
4
- hash: 31
4
+ hash: 15
5
5
  prerelease: false
6
6
  segments:
7
- - 1
7
+ - 2
8
8
  - 0
9
- - 4
10
- version: 1.0.4
9
+ - 0
10
+ version: 2.0.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Cory Forsyth