six-rsync 0.1.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/LICENSE +3 -0
- data/README +3 -0
- data/Rakefile +45 -0
- data/lib/six/rsync/base.rb +154 -0
- data/lib/six/rsync/lib.rb +835 -0
- data/lib/six/rsync/path.rb +33 -0
- data/lib/six/rsync/repository.rb +10 -0
- data/lib/six/rsync/working_directory.rb +10 -0
- data/lib/six/rsync.rb +145 -0
- metadata +64 -0
data/LICENSE
ADDED
data/README
ADDED
data/Rakefile
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
#
|
2
|
+
# To change this template, choose Tools | Templates
|
3
|
+
# and open the template in the editor.
|
4
|
+
|
5
|
+
|
6
|
+
require 'rubygems'
|
7
|
+
require 'rake'
|
8
|
+
require 'rake/clean'
|
9
|
+
require 'rake/gempackagetask'
|
10
|
+
require 'rake/rdoctask'
|
11
|
+
require 'rake/testtask'
|
12
|
+
|
13
|
+
spec = Gem::Specification.new do |s|
|
14
|
+
s.name = 'six-rsync'
|
15
|
+
s.version = '0.1.0'
|
16
|
+
s.has_rdoc = true
|
17
|
+
s.extra_rdoc_files = ['README', 'LICENSE']
|
18
|
+
s.summary = 'Your summary here'
|
19
|
+
s.description = s.summary
|
20
|
+
s.author = 'Sickboy'
|
21
|
+
s.email = 'sb@dev-heaven.net'
|
22
|
+
# s.executables = ['your_executable_here']
|
23
|
+
s.files = %w(LICENSE README Rakefile) + Dir.glob("{bin,spec}/**/*") + Dir.glob("lib/*/**/*.rb")
|
24
|
+
s.require_path = "lib"
|
25
|
+
s.bindir = "bin"
|
26
|
+
end
|
27
|
+
|
28
|
+
Rake::GemPackageTask.new(spec) do |p|
|
29
|
+
p.gem_spec = spec
|
30
|
+
p.need_tar = true
|
31
|
+
p.need_zip = true
|
32
|
+
end
|
33
|
+
|
34
|
+
Rake::RDocTask.new do |rdoc|
|
35
|
+
files =['README', 'LICENSE', "lib/*/**/*.rb"]
|
36
|
+
rdoc.rdoc_files.add(files)
|
37
|
+
rdoc.main = "README" # page to start on
|
38
|
+
rdoc.title = "six-updater-gui Docs"
|
39
|
+
rdoc.rdoc_dir = 'doc/rdoc' # rdoc output folder
|
40
|
+
rdoc.options << '--line-numbers'
|
41
|
+
end
|
42
|
+
|
43
|
+
Rake::TestTask.new do |t|
|
44
|
+
t.test_files = FileList['test/**/*.rb']
|
45
|
+
end
|
@@ -0,0 +1,154 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
module Six
|
4
|
+
module Repositories
|
5
|
+
module Rsync
|
6
|
+
class Base
|
7
|
+
attr_reader :repository
|
8
|
+
|
9
|
+
# opens a new Rsync Project from a working directory
|
10
|
+
# you can specify non-standard rsync_dir and index file in the options
|
11
|
+
def self.open(working_dir, opts={})
|
12
|
+
self.new({:working_directory => working_dir}.merge(opts))
|
13
|
+
end
|
14
|
+
|
15
|
+
# initializes a rsync repository
|
16
|
+
#
|
17
|
+
# options:
|
18
|
+
# :repository
|
19
|
+
# :index_file
|
20
|
+
#
|
21
|
+
def self.init(working_dir, opts = {})
|
22
|
+
opts = {
|
23
|
+
:working_directory => working_dir,
|
24
|
+
:repository => File.join(working_dir, '.rsync')
|
25
|
+
}.merge(opts)
|
26
|
+
|
27
|
+
#FileUtils.mkdir_p(opts[:working_directory]) if opts[:working_directory] && !File.directory?(opts[:working_directory])
|
28
|
+
|
29
|
+
# run rsync_init there
|
30
|
+
logger = if opts[:log]
|
31
|
+
opts[:log]
|
32
|
+
else
|
33
|
+
nil
|
34
|
+
end
|
35
|
+
Rsync::Lib.new(opts, logger).init
|
36
|
+
|
37
|
+
self.new(opts)
|
38
|
+
end
|
39
|
+
|
40
|
+
# clones a rsync repository locally
|
41
|
+
#
|
42
|
+
# repository - http://repo.or.cz/w/sinatra.git
|
43
|
+
# name - sinatra
|
44
|
+
#
|
45
|
+
# options:
|
46
|
+
# :repository
|
47
|
+
#
|
48
|
+
# :bare
|
49
|
+
# or
|
50
|
+
# :working_directory
|
51
|
+
# :index_file
|
52
|
+
#
|
53
|
+
def self.clone(host, name, opts = {})
|
54
|
+
# run Rsync clone
|
55
|
+
logger = if opts[:log]
|
56
|
+
opts[:log]
|
57
|
+
else
|
58
|
+
nil
|
59
|
+
end
|
60
|
+
self.new(Rsync::Lib.new(nil, logger).clone(host, name, opts))
|
61
|
+
end
|
62
|
+
|
63
|
+
def initialize(options = {})
|
64
|
+
if working_dir = options[:working_directory]
|
65
|
+
options[:repository] ||= File.join(working_dir, '.rsync')
|
66
|
+
end
|
67
|
+
if options[:log]
|
68
|
+
@logger = options[:log]
|
69
|
+
@logger.debug("Starting Rsync on #{working_dir}")
|
70
|
+
else
|
71
|
+
@logger = nil
|
72
|
+
end
|
73
|
+
@working_directory = options[:working_directory] ? Rsync::WorkingDirectory.new(options[:working_directory]) : nil
|
74
|
+
@repository = options[:repository] ? Rsync::Repository.new(options[:repository]) : nil
|
75
|
+
|
76
|
+
end
|
77
|
+
|
78
|
+
def update
|
79
|
+
lib.update('')
|
80
|
+
end
|
81
|
+
|
82
|
+
def reset(opts = {})
|
83
|
+
lib.reset(opts)
|
84
|
+
end
|
85
|
+
|
86
|
+
def add(file = '')
|
87
|
+
lib.add(file)
|
88
|
+
end
|
89
|
+
|
90
|
+
def commit
|
91
|
+
lib.commit
|
92
|
+
end
|
93
|
+
|
94
|
+
def push
|
95
|
+
lib.push
|
96
|
+
end
|
97
|
+
|
98
|
+
# returns a reference to the working directory
|
99
|
+
# @rsync.dir.path
|
100
|
+
# @rsync.dir.writeable?
|
101
|
+
def dir
|
102
|
+
@working_directory
|
103
|
+
end
|
104
|
+
|
105
|
+
# returns reference to the rsync repository directory
|
106
|
+
# @rsync.dir.path
|
107
|
+
def repo
|
108
|
+
@repository
|
109
|
+
end
|
110
|
+
|
111
|
+
def set_working(work_dir, check = true)
|
112
|
+
@lib = nil
|
113
|
+
@working_directory = Rsync::WorkingDirectory.new(work_dir.to_s, check)
|
114
|
+
end
|
115
|
+
|
116
|
+
# changes current working directory for a block
|
117
|
+
# to the rsync working directory
|
118
|
+
#
|
119
|
+
# example
|
120
|
+
# @rsync.chdir do
|
121
|
+
# # write files
|
122
|
+
# @rsync.add
|
123
|
+
# @rsync.commit('message')
|
124
|
+
# end
|
125
|
+
def chdir # :yields: the Rsync::Path
|
126
|
+
Dir.chdir(dir.path) do
|
127
|
+
yield dir.path
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
# returns the repository size in bytes
|
132
|
+
def repo_size
|
133
|
+
size = 0
|
134
|
+
Dir.chdir(repo.path) do
|
135
|
+
(size, dot) = `du -s`.chomp.split
|
136
|
+
end
|
137
|
+
size.to_i
|
138
|
+
end
|
139
|
+
|
140
|
+
# returns a Rsync::Status object
|
141
|
+
def status
|
142
|
+
Rsync::Status.new(self)
|
143
|
+
end
|
144
|
+
|
145
|
+
# this is a convenience method for accessing the class that wraps all the
|
146
|
+
# actual 'git' forked system calls. At some point I hope to replace the Git::Lib
|
147
|
+
# class with one that uses native methods or libgit C bindings
|
148
|
+
def lib
|
149
|
+
@lib ||= Rsync::Lib.new(self, @logger)
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
@@ -0,0 +1,835 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
# TODO: Add Rsync add, commit and push (Update should be pull?), either with staging like area like Git, or add is pack into .pack, and commit is update sum ?
|
4
|
+
# TODO: Seperate command lib from custom layer over rsync?
|
5
|
+
|
6
|
+
module Six
|
7
|
+
module Repositories
|
8
|
+
module Rsync
|
9
|
+
DIR_RSYNC = '.rsync'
|
10
|
+
DIR_PACK = File.join(DIR_RSYNC, '.pack')
|
11
|
+
REGEX_FOLDER = /(.*)[\\|\/](.*)/
|
12
|
+
|
13
|
+
class RsyncExecuteError < StandardError
|
14
|
+
end
|
15
|
+
|
16
|
+
class RsyncError < StandardError
|
17
|
+
end
|
18
|
+
|
19
|
+
class Lib
|
20
|
+
attr_accessor :verbose
|
21
|
+
PROTECTED = false
|
22
|
+
WINDRIVE = /\"(\w)\:/
|
23
|
+
DEFAULT_CONFIG = {:hosts => [], :exclude => []}.to_yaml
|
24
|
+
PARAMS = if PROTECTED
|
25
|
+
"--dry-run --times -O --no-whole-file -r --delete --progress -h --exclude=.rsync"
|
26
|
+
else
|
27
|
+
"--times -O --no-whole-file -r --delete --progress -h --exclude=.rsync"
|
28
|
+
end
|
29
|
+
|
30
|
+
def initialize(base = nil, logger = nil)
|
31
|
+
@rsync_dir = nil
|
32
|
+
@rsync_work_dir = nil
|
33
|
+
@path = nil
|
34
|
+
@stats = false
|
35
|
+
@verbose = true
|
36
|
+
|
37
|
+
@repos_local = {:pack => Hash.new, :wd => Hash.new, :version => 0}
|
38
|
+
@repos_remote = {:pack => Hash.new, :wd => Hash.new, :version => 0}
|
39
|
+
|
40
|
+
if base.is_a?(Rsync::Base)
|
41
|
+
@rsync_dir = base.repo.path
|
42
|
+
@rsync_work_dir = base.dir.path if base.dir
|
43
|
+
elsif base.is_a?(Hash)
|
44
|
+
@rsync_dir = base[:repository]
|
45
|
+
@rsync_work_dir = base[:working_directory]
|
46
|
+
end
|
47
|
+
@logger = logger
|
48
|
+
|
49
|
+
etc = File.join(TOOLS_PATH, 'etc')
|
50
|
+
FileUtils.mkdir_p etc
|
51
|
+
fstab = File.join(etc, 'fstab')
|
52
|
+
str = ""
|
53
|
+
str = File.open(fstab) {|file| file.read} if FileTest.exist?(fstab)
|
54
|
+
unless str[/cygdrive/]
|
55
|
+
str += "\nnone /cygdrive cygdrive user,noacl,posix=0 0 0\n"
|
56
|
+
File.open(fstab, 'w') {|file| file.puts str}
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def init
|
61
|
+
@logger.info "Processing: #{rsync_path}"
|
62
|
+
if FileTest.exist? rsync_path
|
63
|
+
@logger.error "Seems to already be an Rsync repository, Aborting!"
|
64
|
+
raise RsyncError
|
65
|
+
end
|
66
|
+
if FileTest.exist? @rsync_work_dir
|
67
|
+
@logger.error "Seems to already be a folder, Aborting!"
|
68
|
+
raise RsyncError
|
69
|
+
end
|
70
|
+
FileUtils.mkdir_p pack_path
|
71
|
+
save_config(config)
|
72
|
+
save_repos(:local)
|
73
|
+
save_repos(:remote)
|
74
|
+
end
|
75
|
+
|
76
|
+
def clone(repository, name, opts = {})
|
77
|
+
@path = opts[:path] || '.'
|
78
|
+
@rsync_work_dir = opts[:path] ? File.join(@path, name) : name
|
79
|
+
|
80
|
+
# TODO: Solve logger mess completely.
|
81
|
+
@logger = opts[:log] if opts[:log]
|
82
|
+
|
83
|
+
case repository
|
84
|
+
when Array
|
85
|
+
config[:hosts] += repository
|
86
|
+
when String
|
87
|
+
config[:hosts] << repository
|
88
|
+
end
|
89
|
+
|
90
|
+
begin
|
91
|
+
init
|
92
|
+
|
93
|
+
# TODO: Eval move to update?
|
94
|
+
arr_opts = []
|
95
|
+
arr_opts << "-I" if opts[:force]
|
96
|
+
begin
|
97
|
+
update('', arr_opts)
|
98
|
+
rescue RsyncError
|
99
|
+
@logger.error "Unable to sucessfully update, aborting..."
|
100
|
+
# Dangerous? :D
|
101
|
+
FileUtils.rm_rf @rsync_work_dir if File.exists?(@rsync_work_dir)
|
102
|
+
#rescue
|
103
|
+
# FileUtils.rm_rf @rsync_work_dir if File.exists?(@rsync_work_dir)
|
104
|
+
end
|
105
|
+
rescue RsyncError
|
106
|
+
@logger.error "Unable to initialize"
|
107
|
+
end
|
108
|
+
|
109
|
+
opts[:bare] ? {:repository => @rsync_work_dir} : {:working_directory => @rsync_work_dir}
|
110
|
+
end
|
111
|
+
|
112
|
+
def update(cmd, x_opts = [], opts = {})
|
113
|
+
@logger.info "Checking for updates..."
|
114
|
+
@config = load_config
|
115
|
+
unless @config
|
116
|
+
@logger.error "Not an Rsync repository!"
|
117
|
+
raise RsyncError
|
118
|
+
end
|
119
|
+
|
120
|
+
unless config[:hosts].size > 0
|
121
|
+
@logger.error "No hosts configured!"
|
122
|
+
raise RsyncError
|
123
|
+
end
|
124
|
+
|
125
|
+
#unpack
|
126
|
+
|
127
|
+
# FIXME: This does not work when not forced, as host is sampled in comparesums :)
|
128
|
+
host = config[:hosts].sample
|
129
|
+
@logger.info "Trying: #{host}, please wait..."
|
130
|
+
|
131
|
+
if opts[:force]
|
132
|
+
arr_opts = []
|
133
|
+
arr_opts << PARAMS
|
134
|
+
arr_opts += x_opts
|
135
|
+
|
136
|
+
# TODO: UNCLUSTERFUCK
|
137
|
+
arr_opts << esc(File.join(host, '.pack/.'))
|
138
|
+
arr_opts << esc(pack_path)
|
139
|
+
|
140
|
+
command(cmd, arr_opts)
|
141
|
+
calc
|
142
|
+
save_repos
|
143
|
+
else
|
144
|
+
#reset(:hard => true)
|
145
|
+
calc
|
146
|
+
save_repos
|
147
|
+
|
148
|
+
# fetch latest sums and only update when changed
|
149
|
+
compare_sums(true, host)
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
# TODO: Allow local-self healing, AND remote healing. reset and fetch?
|
154
|
+
def reset(opts = {})
|
155
|
+
@logger.info "Resetting!"
|
156
|
+
if opts[:hard]
|
157
|
+
@config = load_config
|
158
|
+
calc
|
159
|
+
save_repos
|
160
|
+
compare_sums(false)
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
# TODO: WIP
|
165
|
+
def add(file)
|
166
|
+
@logger.error "Please use commit instead!"
|
167
|
+
return
|
168
|
+
@logger.info "Adding #{file}"
|
169
|
+
if (file == ".")
|
170
|
+
load_repos(:remote)
|
171
|
+
@logger.info "Calculating Checksums..."
|
172
|
+
ar = Dir[File.join(@rsync_work_dir, '/**/*')]
|
173
|
+
|
174
|
+
change = false
|
175
|
+
i = 0
|
176
|
+
ar.each do |file|
|
177
|
+
i += 1
|
178
|
+
unless file[/\.gz\Z/]
|
179
|
+
relative = file.clone
|
180
|
+
relative.gsub!(@rsync_work_dir, '')
|
181
|
+
relative.gsub!(/\A[\\|\/]/, '')
|
182
|
+
|
183
|
+
checksum = md5(file)
|
184
|
+
if checksum != @repos_remote[:wd][relative]
|
185
|
+
change = true
|
186
|
+
@logger.info "Packing #{i}/#{ar.size}: #{file}"
|
187
|
+
gzip(file)
|
188
|
+
@repos_remote[:wd][relative] = checksum
|
189
|
+
@repos_remote[:pack]["#{relative}.gz"] = md5("#{file}.gz")
|
190
|
+
FileUtils.mv("#{file}.gz", pack_path("#{relative}.gz"))
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
194
|
+
if change
|
195
|
+
save_repos
|
196
|
+
#File.open(File.join(@rsync_work_dir, '.sums.yml'), 'w') { |file| file.puts remote_wd[:list].sort.to_yaml }
|
197
|
+
#File.open(pack_path('.sums.yml'), 'w') { |file| file.puts remote_pack[:list].sort.to_yaml }
|
198
|
+
end
|
199
|
+
else
|
200
|
+
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
def commit
|
205
|
+
@logger.info "Committing changes on #{@rsync_work_dir}"
|
206
|
+
@config = load_config
|
207
|
+
unless @config
|
208
|
+
@logger.error "Not an Rsync repository!"
|
209
|
+
return
|
210
|
+
end
|
211
|
+
|
212
|
+
unless config[:hosts].size > 0
|
213
|
+
@logger.error "No hosts configured!"
|
214
|
+
return
|
215
|
+
end
|
216
|
+
|
217
|
+
load_repos(:local)
|
218
|
+
load_repos(:remote)
|
219
|
+
|
220
|
+
@logger.info "Calculating Checksums..."
|
221
|
+
@repos_local[:wd] = calc_sums(:wd)
|
222
|
+
# Added or Changed files
|
223
|
+
ar = Dir[File.join(@rsync_work_dir, '/**/*')]
|
224
|
+
|
225
|
+
|
226
|
+
change = false
|
227
|
+
i = 0
|
228
|
+
@repos_local[:wd].each_pair do |key, value|
|
229
|
+
i += 1
|
230
|
+
if value != @repos_remote[:wd][key]
|
231
|
+
change = true
|
232
|
+
@logger.info "Packing #{i}/#{@repos_local[:wd].size}: #{key}"
|
233
|
+
file = File.join(@rsync_work_dir, key)
|
234
|
+
file[REGEX_FOLDER]
|
235
|
+
folder = $2
|
236
|
+
gzip(file)
|
237
|
+
@repos_local[:pack]["#{key}.gz"] = md5("#{file}.gz")
|
238
|
+
FileUtils.mkdir_p pack_path(folder) if folder
|
239
|
+
FileUtils.mv("#{file}.gz", pack_path("#{key}.gz"))
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
=begin
|
244
|
+
i = 0
|
245
|
+
ar.each do |file|
|
246
|
+
i += 1
|
247
|
+
unless file[/\.gz\Z/]
|
248
|
+
relative = file.clone
|
249
|
+
relative.gsub!(@rsync_work_dir, '')
|
250
|
+
relative.gsub!(/\A[\\|\/]/, '')
|
251
|
+
#checksum = md5(file)
|
252
|
+
if @repos_local[:wd][relative] != @repos_remote[:wd][relative]
|
253
|
+
relative[/(.*)\/(.*)/]
|
254
|
+
folder = $1
|
255
|
+
change = true
|
256
|
+
@logger.info "Packing #{i}/#{ar.size}: #{relative}"
|
257
|
+
gzip(file)
|
258
|
+
#@repos_local[:wd][relative] = checksum
|
259
|
+
@repos_local[:pack]["#{relative}.gz"] = md5("#{file}.gz")
|
260
|
+
FileUtils.mkdir_p pack_path(folder) if folder
|
261
|
+
FileUtils.mv("#{file}.gz", pack_path("#{relative}.gz"))
|
262
|
+
end
|
263
|
+
end
|
264
|
+
end
|
265
|
+
=end
|
266
|
+
# Deleted files
|
267
|
+
@logger.info "Checking for deleted files..."
|
268
|
+
|
269
|
+
@repos_remote[:wd].each_pair do |key, value|
|
270
|
+
i += 1
|
271
|
+
if @repos_local[:wd][key].nil?
|
272
|
+
packed = "#{key}.gz"
|
273
|
+
change = true
|
274
|
+
file = pack_path(packed)
|
275
|
+
file[REGEX_FOLDER]
|
276
|
+
folder = $2
|
277
|
+
|
278
|
+
@logger.info "Removing #{i}/#{@repos_remote[:wd].size}: #{packed}"
|
279
|
+
@repos_local[:wd].delete key
|
280
|
+
@repos_local[:pack].delete packed
|
281
|
+
FileUtils.rm_f(file) if File.exists?(file)
|
282
|
+
end
|
283
|
+
end
|
284
|
+
|
285
|
+
=begin
|
286
|
+
p @repos_local[:wd]
|
287
|
+
ar2 = Dir[File.join(@rsync_work_dir, '/.rsync/.pack/**/*')]
|
288
|
+
i = 0
|
289
|
+
ar2.each do |file|
|
290
|
+
i += 1
|
291
|
+
if file[/\.gz\Z/]
|
292
|
+
relative = file.clone
|
293
|
+
relative.gsub!(@rsync_work_dir, '')
|
294
|
+
relative.gsub!(/\A[\\|\/]\.rsync[\\|\/]\.pack[\\|\/]/, '')
|
295
|
+
local = relative.clone
|
296
|
+
local.gsub!(/\.gz\Z/, '')
|
297
|
+
p file
|
298
|
+
p local
|
299
|
+
p @repos_local[:wd][local]
|
300
|
+
puts
|
301
|
+
if @repos_local[:wd][local].nil?
|
302
|
+
relative[/(.*)\/(.*)/]
|
303
|
+
folder = $1
|
304
|
+
change = true
|
305
|
+
@logger.info "Deleting #{i}/#{ar2.size}: #{relative}"
|
306
|
+
@repos_local[:wd].delete local
|
307
|
+
@repos_local[:pack].delete relative
|
308
|
+
FileUtils.rm_f(file)
|
309
|
+
end
|
310
|
+
end
|
311
|
+
end
|
312
|
+
=end
|
313
|
+
|
314
|
+
#gets
|
315
|
+
if change
|
316
|
+
@logger.info "Changes found!"
|
317
|
+
cmd = ''
|
318
|
+
save_repos(:local)
|
319
|
+
|
320
|
+
# TODO: Change to repositories.yml
|
321
|
+
host = config[:hosts].sample
|
322
|
+
verfile_srv = File.join(".pack", ".repository.yml")
|
323
|
+
begin
|
324
|
+
verbose = @verbose
|
325
|
+
@verbose = false
|
326
|
+
fetch_file(verfile_srv, host)
|
327
|
+
@verbose = verbose
|
328
|
+
rescue
|
329
|
+
@verbose = verbose
|
330
|
+
# FIXME: Should never assume that :)
|
331
|
+
@logger.warn "Unable to retrieve version file from server, repository probably doesnt exist!"
|
332
|
+
# raise RsyncExecuteError
|
333
|
+
end
|
334
|
+
load_repos(:remote)
|
335
|
+
if @repos_local[:version] < @repos_remote[:version] # && !force
|
336
|
+
@logger.warn "WARNING, version on server is NEWER, aborting!"
|
337
|
+
raise RsyncError
|
338
|
+
end
|
339
|
+
@repos_local[:version] += 1
|
340
|
+
@repos_remote[:version] = @repos_local[:version]
|
341
|
+
@repos_remote[:pack] = @repos_local[:pack].clone
|
342
|
+
@repos_remote[:wd] = @repos_local[:wd].clone
|
343
|
+
save_repos(:remote)
|
344
|
+
save_repos(:local)
|
345
|
+
push(host)
|
346
|
+
else
|
347
|
+
@logger.info "No changes found!"
|
348
|
+
end
|
349
|
+
end
|
350
|
+
|
351
|
+
def push(host = nil)
|
352
|
+
@logger.info "Pushing..."
|
353
|
+
@config = load_config
|
354
|
+
host = config[:hosts].sample unless host
|
355
|
+
# TODO: UNCLUSTERFUCK
|
356
|
+
arr_opts = []
|
357
|
+
arr_opts << PARAMS
|
358
|
+
|
359
|
+
# Upload .pack changes
|
360
|
+
if host[/\A(\w)*\@/]
|
361
|
+
arr_opts << "-e ssh"
|
362
|
+
end
|
363
|
+
arr_opts << esc(pack_path('.'))
|
364
|
+
arr_opts << esc(File.join(host, '.pack'))
|
365
|
+
|
366
|
+
command('', arr_opts)
|
367
|
+
end
|
368
|
+
|
369
|
+
def compare_set(typ, host, online = true)
|
370
|
+
load_repos(:local)
|
371
|
+
load_repos(:remote)
|
372
|
+
|
373
|
+
#if local[typ][:md5] == remote[typ][:md5]
|
374
|
+
# @logger.info "#{typ} Match!"
|
375
|
+
#else
|
376
|
+
# @logger.info "#{typ} NOT match, updating!"
|
377
|
+
|
378
|
+
mismatch = []
|
379
|
+
@repos_remote[typ].each_pair do |key, value|
|
380
|
+
if value == @repos_local[typ][key]
|
381
|
+
#@logger.info "Match! #{key}"
|
382
|
+
else
|
383
|
+
@logger.debug "Mismatch! #{key}"
|
384
|
+
mismatch << key
|
385
|
+
end
|
386
|
+
end
|
387
|
+
|
388
|
+
if mismatch.size > 0
|
389
|
+
case typ
|
390
|
+
when :pack
|
391
|
+
# direct unpack of gz into working folder
|
392
|
+
# Update file
|
393
|
+
if online
|
394
|
+
# TODO: Progress bar
|
395
|
+
if mismatch.count > (@repos_remote[typ].count / 4)
|
396
|
+
@logger.info "Many files mismatched (#{mismatch.count}), running full update on .pack folder"
|
397
|
+
arr_opts = []
|
398
|
+
arr_opts << PARAMS
|
399
|
+
arr_opts << File.join(host, '.pack/.')
|
400
|
+
arr_opts << esc(pack_path)
|
401
|
+
|
402
|
+
command('', arr_opts)
|
403
|
+
else
|
404
|
+
c = mismatch.size
|
405
|
+
i = 0
|
406
|
+
mismatch.each do |e|
|
407
|
+
# TODO: Nicer progress bar...
|
408
|
+
i += 1
|
409
|
+
@logger.info "Fetching #{i}/#{c}: #{e}"
|
410
|
+
fetch_file(File.join(".pack", e), host)
|
411
|
+
end
|
412
|
+
end
|
413
|
+
end
|
414
|
+
when :wd
|
415
|
+
c = mismatch.size
|
416
|
+
i = 0
|
417
|
+
mismatch.each do |e|
|
418
|
+
# TODO: Nicer progress bar...
|
419
|
+
i += 1
|
420
|
+
@logger.info "Unpacking #{i}/#{c}: #{e}"
|
421
|
+
unpack(:path => "#{e}.gz")
|
422
|
+
end
|
423
|
+
end
|
424
|
+
end
|
425
|
+
|
426
|
+
del = []
|
427
|
+
@repos_local[typ].each_pair do |key, value|
|
428
|
+
if @repos_remote[typ][key].nil?
|
429
|
+
@logger.info "File does not exist in remote! #{key}"
|
430
|
+
del << key unless config[:exclude].include?(key)
|
431
|
+
end
|
432
|
+
end
|
433
|
+
del.each { |e| del_file(e, typ) }
|
434
|
+
@repos_local[typ] = calc_sums(typ)
|
435
|
+
@repos_local[:version] = @repos_remote[:version]
|
436
|
+
save_repos
|
437
|
+
end
|
438
|
+
|
439
|
+
def compare_sums(online = true, host = config[:hosts].sample)
|
440
|
+
hosts = config[:hosts].clone
|
441
|
+
done = false
|
442
|
+
|
443
|
+
## Pack
|
444
|
+
if online
|
445
|
+
b = false
|
446
|
+
while hosts.size > 0 && !done do
|
447
|
+
# FIXME: Nasty
|
448
|
+
if b
|
449
|
+
host = hosts.sample
|
450
|
+
end
|
451
|
+
b = true
|
452
|
+
hosts -= [host]
|
453
|
+
|
454
|
+
begin
|
455
|
+
verbose = @verbose
|
456
|
+
@verbose = false
|
457
|
+
fetch_file(".pack/.repository.yml", host)
|
458
|
+
@verbose = verbose
|
459
|
+
|
460
|
+
load_repos(:remote)
|
461
|
+
load_repos(:local)
|
462
|
+
|
463
|
+
if @repos_local[:version] > @repos_remote[:version] # && !force
|
464
|
+
@logger.warn "WARNING, version on server is OLDER, aborting!"
|
465
|
+
raise RsyncError
|
466
|
+
end
|
467
|
+
done = true
|
468
|
+
rescue
|
469
|
+
@logger.info "Failed #{host}, trying next.."
|
470
|
+
end
|
471
|
+
end
|
472
|
+
# TODO: CLEANUP, Should depricate in time.
|
473
|
+
if FileTest.exists? pack_path('.repository.yml')
|
474
|
+
[pack_path('.version'), pack_path('.sums.yml'), File.join(@rsync_work_dir, '.sums.yml')].each do |f|
|
475
|
+
FileUtils.rm_f f if FileTest.exists? f
|
476
|
+
end
|
477
|
+
end
|
478
|
+
end
|
479
|
+
if done || online
|
480
|
+
# TODO: Don't do actions when not online
|
481
|
+
@logger.info "Verifying Packed files..."
|
482
|
+
compare_set(:pack, host)
|
483
|
+
@logger.info "Verifying Unpacked files..."
|
484
|
+
compare_set(:wd, host)
|
485
|
+
save_repos
|
486
|
+
end
|
487
|
+
end
|
488
|
+
|
489
|
+
private
|
490
|
+
def config
|
491
|
+
cfg = @config ||= YAML::load(DEFAULT_CONFIG)
|
492
|
+
cfg[:exclude] = [] unless cfg[:exclude]
|
493
|
+
cfg[:hosts] = [] unless cfg[:hosts]
|
494
|
+
cfg
|
495
|
+
end
|
496
|
+
|
497
|
+
def rsync_path(path = '')
|
498
|
+
p = File.join(@rsync_work_dir, DIR_RSYNC)
|
499
|
+
p = File.join(p, path) unless path.size == 0
|
500
|
+
p
|
501
|
+
end
|
502
|
+
|
503
|
+
def pack_path(path = '')
|
504
|
+
p = File.join(@rsync_work_dir, DIR_PACK)
|
505
|
+
p = File.join(p, path) unless path.size == 0
|
506
|
+
p
|
507
|
+
end
|
508
|
+
|
509
|
+
def esc(val)
|
510
|
+
"\"#{val}\""
|
511
|
+
end
|
512
|
+
|
513
|
+
def escape(s)
|
514
|
+
"\"" + s.to_s.gsub('\"', '\"\\\"\"') + "\""
|
515
|
+
end
|
516
|
+
|
517
|
+
def fetch_file(path, host)
|
518
|
+
path[/(.*)\/(.*)/]
|
519
|
+
folder, file = $1, $2
|
520
|
+
folder = "." unless folder
|
521
|
+
file = path unless file
|
522
|
+
# Only fetch a specific file
|
523
|
+
@logger.debug "Fetching #{path} from #{host}"
|
524
|
+
arr_opts = []
|
525
|
+
arr_opts << PARAMS
|
526
|
+
if host[/\A(\w)*\@/]
|
527
|
+
arr_opts << "-e ssh"
|
528
|
+
end
|
529
|
+
arr_opts << esc(File.join(host, path))
|
530
|
+
arr_opts << esc(rsync_path(folder))
|
531
|
+
|
532
|
+
command('', arr_opts)
|
533
|
+
end
|
534
|
+
|
535
|
+
def calc
|
536
|
+
[:pack, :wd].each { |t| @repos_local[t] = calc_sums(t) }
|
537
|
+
end
|
538
|
+
|
539
|
+
def calc_sums(typ)
|
540
|
+
@logger.debug "Calculating checksums of #{typ} files"
|
541
|
+
ar = []
|
542
|
+
reg = case typ
|
543
|
+
when :pack
|
544
|
+
ar = Dir[pack_path('**/*')]
|
545
|
+
/\A[\\|\/]\.rsync[\\|\/]\.pack[\\|\/]/
|
546
|
+
when :wd
|
547
|
+
ar = Dir[File.join(@rsync_work_dir, '/**/*')]
|
548
|
+
/\A[\\|\/]/
|
549
|
+
end
|
550
|
+
h = Hash.new
|
551
|
+
ar.each do |file|
|
552
|
+
relative = file.clone
|
553
|
+
relative.gsub!(@rsync_work_dir, '')
|
554
|
+
relative.gsub!(reg, '')
|
555
|
+
|
556
|
+
sum = md5(file)
|
557
|
+
h[relative] = sum if sum && !config[:exclude].include?(relative)
|
558
|
+
end
|
559
|
+
h
|
560
|
+
end
|
561
|
+
|
562
|
+
def load_config
|
563
|
+
# TODO: Remove after a while, depricated .pack
|
564
|
+
old = File.join(@rsync_work_dir, '.pack')
|
565
|
+
FileUtils.mv(old, pack_path) if FileTest.exists?(old)
|
566
|
+
load_yaml(File.join(rsync_path, 'config.yml'))
|
567
|
+
end
|
568
|
+
|
569
|
+
def load_yaml(file)
|
570
|
+
if FileTest.exist?(file)
|
571
|
+
YAML::load_file(file)
|
572
|
+
else
|
573
|
+
nil
|
574
|
+
end
|
575
|
+
end
|
576
|
+
|
577
|
+
def save_default_config
|
578
|
+
FileUtils.mkdir_p rsync_path
|
579
|
+
save_config(config)
|
580
|
+
end
|
581
|
+
|
582
|
+
def save_config(config = YAML::load(DEFAULT_CONFIG))
|
583
|
+
File.open(File.join(rsync_path, 'config.yml'), 'w') { |file| file.puts config.to_yaml }
|
584
|
+
end
|
585
|
+
|
586
|
+
def save_repos(typ = :local)
|
587
|
+
file, config = nil, nil
|
588
|
+
case typ
|
589
|
+
when :local
|
590
|
+
file = rsync_path('.repository.yml')
|
591
|
+
config = @repos_local.clone
|
592
|
+
when :remote
|
593
|
+
file = pack_path('.repository.yml')
|
594
|
+
config = @repos_remote.clone
|
595
|
+
end
|
596
|
+
config[:pack] = config[:pack].sort
|
597
|
+
config[:wd] = config[:wd].sort
|
598
|
+
File.open(file, 'w') { |file| file.puts config.to_yaml }
|
599
|
+
|
600
|
+
# TODO: CLEANUP, Should depricate in time.
|
601
|
+
[File.join(@rsync_work_dir, '.rsync/.version'), File.join(@rsync_work_dir, '.rsync/sums_pack.yml'), File.join(@rsync_work_dir, '.rsync/sums_wd.yml')].each do |f|
|
602
|
+
FileUtils.rm_f f if FileTest.exists? f
|
603
|
+
end
|
604
|
+
end
|
605
|
+
|
606
|
+
def load_repos(typ)
|
607
|
+
config = Hash.new
|
608
|
+
case typ
|
609
|
+
when :local
|
610
|
+
File.open(rsync_path('.repository.yml')) { |file| config = YAML::load(file) }
|
611
|
+
when :remote
|
612
|
+
if FileTest.exists?(pack_path('.repository.yml'))
|
613
|
+
File.open(pack_path('.repository.yml')) { |file| config = YAML::load(file) }
|
614
|
+
else
|
615
|
+
# Deprecated
|
616
|
+
config[:wd] = File.open(File.join(@rsync_work_dir, '.sums.yml')) { |file| YAML::load(file) }
|
617
|
+
config[:pack] = File.open(pack_path('.sums.yml')) { |file| YAML::load(file) }
|
618
|
+
config[:version] = File.open(pack_path('.version')) { |file| file.read.to_i }
|
619
|
+
end
|
620
|
+
end
|
621
|
+
|
622
|
+
[:wd, :pack].each do |t|
|
623
|
+
h = Hash.new
|
624
|
+
config[t].each { |e| h[e[0]] = e[1] }
|
625
|
+
config[t] = h
|
626
|
+
end
|
627
|
+
|
628
|
+
case typ
|
629
|
+
when :local
|
630
|
+
@repos_local = config
|
631
|
+
when :remote
|
632
|
+
@repos_remote = config
|
633
|
+
end
|
634
|
+
end
|
635
|
+
|
636
|
+
def del_file(file, typ, opts = {})
|
637
|
+
file = case typ
|
638
|
+
when :pack
|
639
|
+
File.join(DIR_PACK, file)
|
640
|
+
when :wd
|
641
|
+
file
|
642
|
+
end
|
643
|
+
FileUtils.rm_f File.join(@rsync_work_dir, file)
|
644
|
+
end
|
645
|
+
|
646
|
+
def md5(path)
|
647
|
+
unless File.directory? path
|
648
|
+
path[/(.*)[\/|\\](.*)/]
|
649
|
+
folder, file = $1, $2
|
650
|
+
Dir.chdir(folder) do
|
651
|
+
r = %x[md5sum #{esc(file)}]
|
652
|
+
@logger.debug r
|
653
|
+
r[/\A\w*/]
|
654
|
+
end
|
655
|
+
end
|
656
|
+
end
|
657
|
+
|
658
|
+
def zip7(file)
|
659
|
+
out = %x[7z x #{esc(file)} -y]
|
660
|
+
@logger.debug out
|
661
|
+
out
|
662
|
+
end
|
663
|
+
|
664
|
+
def gzip(file)
|
665
|
+
@logger.info "Packing #{file}"
|
666
|
+
out = %x[gzip -f --best --rsyncable --keep #{esc(file)}]
|
667
|
+
@logger.debug out
|
668
|
+
end
|
669
|
+
|
670
|
+
def unpack_file(file, path)
|
671
|
+
Dir.chdir(path) do |dir|
|
672
|
+
zip7(file)
|
673
|
+
# TODO: Evaluate if this is actually wanted / useful at all..
|
674
|
+
=begin
|
675
|
+
if file[/\.tar\.?/]
|
676
|
+
file[/(.*)\/(.*)/]
|
677
|
+
fil = $2
|
678
|
+
fil = file unless fil
|
679
|
+
f2 = fil.gsub('.gz', '')
|
680
|
+
zip7(f2)
|
681
|
+
FileUtils.rm_f f2
|
682
|
+
end
|
683
|
+
=end
|
684
|
+
end
|
685
|
+
end
|
686
|
+
|
687
|
+
def unpack(opts = {})
|
688
|
+
items = if opts[:path]
|
689
|
+
[pack_path(opts[:path])]
|
690
|
+
else
|
691
|
+
Dir[pack_path('**/*')]
|
692
|
+
end
|
693
|
+
|
694
|
+
items.each do |file|
|
695
|
+
unless File.directory? file
|
696
|
+
relative = file.clone
|
697
|
+
relative.gsub!(@rsync_work_dir, '')
|
698
|
+
relative.gsub!(/\A[\\|\/]\.rsync[\\|\/]\.pack[\\|\/]/, '')
|
699
|
+
fil = relative
|
700
|
+
folder = "."
|
701
|
+
folder, fil = $1, $2 if relative[/(.*)\/(.*)/]
|
702
|
+
#puts "Relative: #{relative}, Folder: #{folder}, File: #{fil} (Origin: #{file})"
|
703
|
+
|
704
|
+
path = File.join(@rsync_work_dir, folder)
|
705
|
+
FileUtils.mkdir_p path
|
706
|
+
unpack_file(file, path)
|
707
|
+
end
|
708
|
+
end
|
709
|
+
end
|
710
|
+
|
711
|
+
def command_lines(cmd, opts = [], chdir = true, redirect = '')
|
712
|
+
command(cmd, opts, chdir).split("\n")
|
713
|
+
end
|
714
|
+
|
715
|
+
def command(cmd, opts = [], chdir = true, redirect = '', &block)
|
716
|
+
path = @rsync_work_dir || @rsync_dir || @path
|
717
|
+
|
718
|
+
opts << "--stats" if @stats
|
719
|
+
|
720
|
+
opts = [opts].flatten.map {|s| s }.join(' ') # escape()
|
721
|
+
rsync_cmd = "rsync #{cmd} #{opts} #{redirect} 2>&1"
|
722
|
+
|
723
|
+
while rsync_cmd[WINDRIVE] do
|
724
|
+
drive = rsync_cmd[WINDRIVE]
|
725
|
+
#if ENV['six-app-root']
|
726
|
+
# rsync_cmd.gsub!(drive, "\"#{ENV['six-app-root']}") # /cygdrive/#{$1}
|
727
|
+
#else
|
728
|
+
rsync_cmd.gsub!(drive, "\"/cygdrive/#{$1}")
|
729
|
+
#end
|
730
|
+
end
|
731
|
+
|
732
|
+
if @logger
|
733
|
+
@logger.debug(rsync_cmd)
|
734
|
+
end
|
735
|
+
|
736
|
+
out = nil
|
737
|
+
if chdir && (Dir.getwd != path)
|
738
|
+
Dir.chdir(path) { out = run_command(rsync_cmd, &block) }
|
739
|
+
else
|
740
|
+
out = run_command(rsync_cmd, &block)
|
741
|
+
end
|
742
|
+
|
743
|
+
#@logger.debug(out)
|
744
|
+
|
745
|
+
out
|
746
|
+
end
|
747
|
+
|
748
|
+
def run_command(rsync_cmd, &block)
|
749
|
+
# TODO: Make this switchable? Verbosity ?
|
750
|
+
# Or actually parse this live for own stats?
|
751
|
+
#puts rsync_cmd
|
752
|
+
s = nil
|
753
|
+
out = ''
|
754
|
+
$stdout.sync = true # Seems to fix C:/Packaging/six-updater/NEW - Copy/ruby/lib/ruby/gems/1.9.1/gems/log4r-1.0.5/lib/log4r/outputter/iooutputter.rb:43:in `flush': Broken pipe (Errno::EPIPE)
|
755
|
+
|
756
|
+
# Simpler method but on windows the !? exitstatus is not working properly..
|
757
|
+
# Does nicely display error output in logwindow though
|
758
|
+
#io = IO.popen(rsync_cmd)
|
759
|
+
#io.sync = true
|
760
|
+
#io.each do |buffer|
|
761
|
+
# process_msg buffer
|
762
|
+
# out << buffer
|
763
|
+
#end
|
764
|
+
status = Open3.popen3(rsync_cmd) { |io_in, io_out, io_err, waitth|
|
765
|
+
io_out.sync = true
|
766
|
+
io_err.sync = true
|
767
|
+
|
768
|
+
io_out.each do |buffer|
|
769
|
+
process_msg buffer
|
770
|
+
out << buffer
|
771
|
+
end
|
772
|
+
|
773
|
+
#while !io_out.eof?
|
774
|
+
# buffer = io_out.readline
|
775
|
+
# # print buf#.gsub("\r", '')
|
776
|
+
# process_msg buffer
|
777
|
+
# out << buffer
|
778
|
+
#end
|
779
|
+
error = io_err.gets
|
780
|
+
if error
|
781
|
+
puts "Error: " + error.chomp
|
782
|
+
# exit
|
783
|
+
end
|
784
|
+
# puts "Result: " + io_out.gets
|
785
|
+
s = waitth.value
|
786
|
+
}
|
787
|
+
# FIXME: This doesn't work with the new popen or is there a way?
|
788
|
+
if s.exitstatus > 0
|
789
|
+
if s.exitstatus == 1 && out == ''
|
790
|
+
return ''
|
791
|
+
end
|
792
|
+
raise Rsync::RsyncExecuteError.new(rsync_cmd + ':' + out.to_s)
|
793
|
+
end
|
794
|
+
status
|
795
|
+
end
|
796
|
+
|
797
|
+
def process_msg(msg)
|
798
|
+
if msg[/[k|m|g]?B\/s/i]
|
799
|
+
msg.gsub!("\n", '')
|
800
|
+
print "#{msg}\r" if @verbose
|
801
|
+
else
|
802
|
+
@logger.debug msg
|
803
|
+
print msg if @verbose
|
804
|
+
end
|
805
|
+
msg
|
806
|
+
|
807
|
+
=begin
|
808
|
+
m = nil
|
809
|
+
if msg[/\r/]
|
810
|
+
# TODO; must still be written even if there is no next message :P
|
811
|
+
|
812
|
+
if @write
|
813
|
+
print msg
|
814
|
+
end
|
815
|
+
m = msg.gsub("\r", '')
|
816
|
+
#@previous = m
|
817
|
+
else
|
818
|
+
m = msg
|
819
|
+
#if @previous
|
820
|
+
# @logger.debug @previous
|
821
|
+
# @previous = nil
|
822
|
+
#end
|
823
|
+
#unless @previous
|
824
|
+
# @logger.debug m
|
825
|
+
#end
|
826
|
+
@logger.debug m
|
827
|
+
puts m if @write
|
828
|
+
end
|
829
|
+
m
|
830
|
+
=end
|
831
|
+
end
|
832
|
+
end
|
833
|
+
end
|
834
|
+
end
|
835
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
module Six
|
4
|
+
module Repositories
|
5
|
+
module Rsync
|
6
|
+
class Path
|
7
|
+
|
8
|
+
attr_accessor :path
|
9
|
+
|
10
|
+
def initialize(path, check_path = true)
|
11
|
+
if !check_path || File.exists?(path)
|
12
|
+
@path = File.expand_path(path)
|
13
|
+
else
|
14
|
+
raise ArgumentError, "path does not exist", File.expand_path(path)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def readable?
|
19
|
+
File.readable?(@path)
|
20
|
+
end
|
21
|
+
|
22
|
+
def writable?
|
23
|
+
File.writable?(@path)
|
24
|
+
end
|
25
|
+
|
26
|
+
def to_s
|
27
|
+
@path
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
data/lib/six/rsync.rb
ADDED
@@ -0,0 +1,145 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
require 'fileutils'
|
4
|
+
require 'digest/md5'
|
5
|
+
require 'yaml'
|
6
|
+
|
7
|
+
require 'six/rsync/path'
|
8
|
+
require 'six/rsync/repository'
|
9
|
+
require 'six/rsync/working_directory'
|
10
|
+
require 'six/rsync/lib'
|
11
|
+
require 'six/rsync/base'
|
12
|
+
#require 'six/popen'
|
13
|
+
|
14
|
+
require 'open3'
|
15
|
+
#require 'win32/open3'
|
16
|
+
|
17
|
+
if RUBY_VERSION == "1.8.7"
|
18
|
+
class Array
|
19
|
+
def sample
|
20
|
+
self[rand self.size]
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
module Six
|
26
|
+
module Repositories
|
27
|
+
module Md5
|
28
|
+
end
|
29
|
+
|
30
|
+
module Rsync
|
31
|
+
VERSION = '0.0.1'
|
32
|
+
BASE_PATH = Dir.pwd
|
33
|
+
TOOLS_PATH = File.join(BASE_PATH, 'tools')
|
34
|
+
FOLDER = /(.*)\/(.*)/
|
35
|
+
ENV['PATH'] = ENV['PATH'] + ";#{TOOLS_PATH};#{File.join(TOOLS_PATH, 'bin')}"
|
36
|
+
# No meaning on Cygwin 1.7
|
37
|
+
# ENV['CYGWIN'] = "nontsec"
|
38
|
+
|
39
|
+
# open a bare repository
|
40
|
+
#
|
41
|
+
# this takes the path to a bare rsync repo
|
42
|
+
# it expects not to be able to use a working directory
|
43
|
+
# so you can't checkout stuff, commit things, etc.
|
44
|
+
# but you can do most read operations
|
45
|
+
def self.bare(rsync_dir, options = {})
|
46
|
+
Base.bare(rsync_dir, options)
|
47
|
+
end
|
48
|
+
|
49
|
+
# open an existing rsync working directory
|
50
|
+
#
|
51
|
+
# this will most likely be the most common way to create
|
52
|
+
# a rsync reference, referring to a working directory.
|
53
|
+
# if not provided in the options, the library will assume
|
54
|
+
# your rsync_dir is in the default place (.rsync/)
|
55
|
+
#
|
56
|
+
# options
|
57
|
+
# :repository => '/path/to/alt_rsync_dir'
|
58
|
+
# :index => '/path/to/alt_index_file'
|
59
|
+
def self.open(working_dir, options = {})
|
60
|
+
Base.open(working_dir, options)
|
61
|
+
end
|
62
|
+
|
63
|
+
# initialize a new rsync repository, defaults to the current working directory
|
64
|
+
#
|
65
|
+
# options
|
66
|
+
# :repository => '/path/to/alt_rsync_dir'
|
67
|
+
# :index => '/path/to/alt_index_file'
|
68
|
+
def self.init(working_dir = '.', options = {})
|
69
|
+
Base.init(working_dir, options)
|
70
|
+
end
|
71
|
+
|
72
|
+
# clones a remote repository
|
73
|
+
#
|
74
|
+
# options
|
75
|
+
# :bare => true (does a bare clone)
|
76
|
+
# :repository => '/path/to/alt_rsync_dir'
|
77
|
+
# :index => '/path/to/alt_index_file'
|
78
|
+
#
|
79
|
+
# example
|
80
|
+
# Rsync.clone('rsync://repo.or.cz/ruby', 'clone', :bare => true)
|
81
|
+
#
|
82
|
+
def self.clone(repository, name, options = {})
|
83
|
+
Base.clone(repository, name, options)
|
84
|
+
end
|
85
|
+
|
86
|
+
=begin
|
87
|
+
# Export the current HEAD (or a branch, if <tt>options[:branch]</tt>
|
88
|
+
# is specified) into the +name+ directory, then remove all traces of rsync from the
|
89
|
+
# directory.
|
90
|
+
#
|
91
|
+
# See +clone+ for options. Does not obey the <tt>:remote</tt> option,
|
92
|
+
# since the rsync info will be deleted anyway; always uses the default
|
93
|
+
# remote, 'origin.'
|
94
|
+
def self.export(repository, name, options = {})
|
95
|
+
options.delete(:remote)
|
96
|
+
repo = clone(repository, name, {:depth => 1}.merge(options))
|
97
|
+
repo.checkout("origin/#{options[:branch]}") if options[:branch]
|
98
|
+
Dir.chdir(repo.dir.to_s) { FileUtils.rm_r '.rsync' }
|
99
|
+
end
|
100
|
+
|
101
|
+
#g.config('user.name', 'Scott Chacon') # sets value
|
102
|
+
#g.config('user.email', 'email@email.com') # sets value
|
103
|
+
#g.config('user.name') # returns 'Scott Chacon'
|
104
|
+
#g.config # returns whole config hash
|
105
|
+
def config(name = nil, value = nil)
|
106
|
+
lib = Rsync::Lib.new
|
107
|
+
if(name && value)
|
108
|
+
# set value
|
109
|
+
lib.config_set(name, value)
|
110
|
+
elsif (name)
|
111
|
+
# return value
|
112
|
+
lib.config_get(name)
|
113
|
+
else
|
114
|
+
# return hash
|
115
|
+
lib.config_list
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
# Same as g.config, but forces it to be at the global level
|
120
|
+
#
|
121
|
+
#g.config('user.name', 'Scott Chacon') # sets value
|
122
|
+
#g.config('user.email', 'email@email.com') # sets value
|
123
|
+
#g.config('user.name') # returns 'Scott Chacon'
|
124
|
+
#g.config # returns whole config hash
|
125
|
+
def self.global_config(name = nil, value = nil)
|
126
|
+
lib = Rsync::Lib.new(nil, nil)
|
127
|
+
if(name && value)
|
128
|
+
# set value
|
129
|
+
lib.global_config_set(name, value)
|
130
|
+
elsif (name)
|
131
|
+
# return value
|
132
|
+
lib.global_config_get(name)
|
133
|
+
else
|
134
|
+
# return hash
|
135
|
+
lib.global_config_list
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
def global_config(name = nil, value = nil)
|
140
|
+
self.class.global_config(name, value)
|
141
|
+
end
|
142
|
+
=end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
metadata
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: six-rsync
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Sickboy
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-09-25 00:00:00 +02:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: Your summary here
|
17
|
+
email: sb@dev-heaven.net
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files:
|
23
|
+
- README
|
24
|
+
- LICENSE
|
25
|
+
files:
|
26
|
+
- LICENSE
|
27
|
+
- README
|
28
|
+
- Rakefile
|
29
|
+
- lib/six/rsync/base.rb
|
30
|
+
- lib/six/rsync/lib.rb
|
31
|
+
- lib/six/rsync/path.rb
|
32
|
+
- lib/six/rsync/repository.rb
|
33
|
+
- lib/six/rsync/working_directory.rb
|
34
|
+
- lib/six/rsync.rb
|
35
|
+
has_rdoc: true
|
36
|
+
homepage:
|
37
|
+
licenses: []
|
38
|
+
|
39
|
+
post_install_message:
|
40
|
+
rdoc_options: []
|
41
|
+
|
42
|
+
require_paths:
|
43
|
+
- lib
|
44
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
45
|
+
requirements:
|
46
|
+
- - ">="
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: "0"
|
49
|
+
version:
|
50
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: "0"
|
55
|
+
version:
|
56
|
+
requirements: []
|
57
|
+
|
58
|
+
rubyforge_project:
|
59
|
+
rubygems_version: 1.3.5
|
60
|
+
signing_key:
|
61
|
+
specification_version: 3
|
62
|
+
summary: Your summary here
|
63
|
+
test_files: []
|
64
|
+
|