cloudsync 1.0.4 → 2.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.
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