Module: MrMurano::SyncUpDown

Included in:
ProductResources, SolutionBase
Defined in:
lib/MrMurano/SyncUpDown.rb

Instance Method Summary collapse

Instance Method Details

#docmp(itemA, itemB) ⇒ Object

True if itemA and itemB are different

Children objects must override this



133
134
135
# File 'lib/MrMurano/SyncUpDown.rb', line 133

def docmp(itemA, itemB)
  true
end

#dodiff(item) ⇒ Object

Call external diff tool on item WARNING: This will download the remote item to do the diff.

Parameters:

  • item

    Hash: The item to get a diff of

Returns:

  • String: The diff output



424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
# File 'lib/MrMurano/SyncUpDown.rb', line 424

def dodiff(item)
  trmt = Tempfile.new([tolocalname(item, @itemkey)+'_remote_', '.lua'])
  tlcl = Tempfile.new([tolocalname(item, @itemkey)+'_local_', '.lua'])
  if item.has_key? :script then
    Pathname.new(tlcl.path).open('wb') do |io|
      io << item[:script]
    end
  else
    Pathname.new(tlcl.path).open('wb') do |io|
      io << item[:local_path].read
    end
  end
  df = ""
  begin
    download(Pathname.new(trmt.path), item)

    cmd = $cfg['diff.cmd'].shellsplit
    cmd << trmt.path.gsub(::File::SEPARATOR, ::File::ALT_SEPARATOR || ::File::SEPARATOR)
    cmd << tlcl.path.gsub(::File::SEPARATOR, ::File::ALT_SEPARATOR || ::File::SEPARATOR)

    df, _ = Open3.capture2e(*cmd)
  ensure
    trmt.close
    trmt.unlink
    tlcl.close
    tlcl.unlink
  end
  df
end

#download(local, item) ⇒ Object

Download an item into local

Children objects should override this or implement #fetch()

Parameters:

  • local

    Pathname: Full path of where to download to

  • item

    Hash: The item to download



206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
# File 'lib/MrMurano/SyncUpDown.rb', line 206

def download(local, item)
  if item[:bundled] then
    warning "Not downloading into bundled item #{synckey(item)}"
    return
  end
  local.dirname.mkpath
  id = item[@itemkey.to_sym]
  if id.nil? then
    debug "!!! Missing '#{@itemkey}', using :id instead!"
    debug ":id => #{item[:id]}"
    id = item[:id]
    raise "Both #{@itemkey} and id in item are nil!" if id.nil?
  end
  local.open('wb') do |io|
    fetch(id) do |chunk|
      io.write chunk
    end
  end
end

#ignoringObject

Returns array of globs of files to ignore



296
297
298
# File 'lib/MrMurano/SyncUpDown.rb', line 296

def ignoring
  %w{*_test.lua *_spec.lua .*}
end

#listObject

Get a list of remote items.

Children objects Must override this

Returns:

  • Array: of Hashes of item details



100
101
102
# File 'lib/MrMurano/SyncUpDown.rb', line 100

def list()
  []
end

#localitems(from) ⇒ Object

Get a list of local items rooted at #from

Children rarely need to override this. Only when the locallist is not a set of files in a directory will they need to override it.

Parameters:

  • from

    Pathname: Directory of items to scan

Returns:

  • Array: of Hashes of item details



308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
# File 'lib/MrMurano/SyncUpDown.rb', line 308

def localitems(from)
  debug "#{self.class.to_s}: Getting local items from: #{from}"
  searchIn = from.to_s
  sf = searchFor.map{|i| ::File.join(searchIn, i)}
  Dir[*sf].flatten.compact.reject do |p|
    ::File.directory?(p) or ignoring.any? do |i|
      ::File.fnmatch(i,p)
    end
  end.map do |path|
    path = Pathname.new(path).realpath
    item = toRemoteItem(from, path)
    if item.kind_of?(Array) then
      item.compact.map{|i| i[:local_path] = path; i}
    elsif not item.nil? then
      item[:local_path] = path
      item
    end
  end.flatten.compact
end

#locallistObject

Get a list of local items.

Children should never need to override this. Instead they should override #localitems

This collects items in the project and all bundles.

Returns:

  • Array: of Hashes of items



256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
# File 'lib/MrMurano/SyncUpDown.rb', line 256

def locallist()
  # so. if @locationbase/bundles exists
  #  gather and merge: @locationbase/bundles/*/@location
  # then merge @locationbase/@location
  #

  bundleDir = $cfg['location.bundles'] or 'bundles'
  bundleDir = 'bundles' if bundleDir.nil?
  items = {}
  if (@locationbase + bundleDir).directory? then
    (@locationbase + bundleDir).children.sort.each do |bndl|
      if (bndl + @location).exist? then
        verbose("Loading from bundle #{bndl.basename}")
        bitems = localitems(bndl + @location)
        bitems.map!{|b| b[:bundled] = true; b} # mark items from bundles.


        # use synckey for quicker merging.
        bitems.each { |b| items[synckey(b)] = b }
      end
    end
  end
  if (@locationbase + @location).exist? then
    bitems = localitems(@locationbase + @location)
    # use synckey for quicker merging.
    bitems.each { |b| items[synckey(b)] = b }
  else
    warning "Skipping missing location #{@locationbase + @location}"
  end

  items.values
end

#remove(itemkey) ⇒ Object

Remove remote item

Children objects Must override this

Parameters:

  • itemkey

    String: The identifying key for this item



109
110
111
112
113
# File 'lib/MrMurano/SyncUpDown.rb', line 109

def remove(itemkey)
  # :nocov:
  raise "Forgotten implementation"
  # :nocov:
end

#removelocal(dest, item) ⇒ Object

Remove local reference of item

Children objects should override this if move than just unlinking the local item.

Parameters:

  • dest

    Pathname: Full path of item to be removed

  • item

    Hash: Full details of item to be removed



233
234
235
# File 'lib/MrMurano/SyncUpDown.rb', line 233

def removelocal(dest, item)
  dest.unlink
end

#searchForObject

Returns array of globs to search for files



291
292
293
# File 'lib/MrMurano/SyncUpDown.rb', line 291

def searchFor
  %w{*.lua */*.lua}
end

#status(options = {}) ⇒ Object

Get status of things here verses there



455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
# File 'lib/MrMurano/SyncUpDown.rb', line 455

def status(options={})
  options = elevate_hash(options)
  there = list()
  here = locallist()
  itemkey = @itemkey.to_sym

  therebox = {}
  there.each do |item|
    item = Hash.transform_keys_to_symbols(item)
    item[:synckey] = synckey(item)
    therebox[ item[:synckey] ] = item
  end
  herebox = {}
  here.each do |item|
    item = Hash.transform_keys_to_symbols(item)
    item[:synckey] = synckey(item)
    herebox[ item[:synckey] ] = item
  end
  toadd = []
  todel = []
  tomod = []
  unchg = []
  if options[:asdown] then
    todel = (herebox.keys - therebox.keys).map{|key| herebox[key] }
    toadd = (therebox.keys - herebox.keys).map{|key| therebox[key] }
  else
    toadd = (herebox.keys - therebox.keys).map{|key| herebox[key] }
    todel = (therebox.keys - herebox.keys).map{|key| therebox[key] }
  end
  (herebox.keys & therebox.keys).each do |key|
    # Want here to override there except for itemkey.
    mrg = herebox[key].reject{|k,v| k==itemkey}
    mrg = therebox[key].merge(mrg)
    if docmp(herebox[key], therebox[key]) then
      mrg[:diff] = dodiff(mrg) if options[:diff]
      tomod << mrg
    else
      unchg << mrg
    end
  end
  { :toadd=>toadd, :todel=>todel, :tomod=>tomod, :unchg=>unchg }
end

#syncdown(options = {}) ⇒ Object



382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
# File 'lib/MrMurano/SyncUpDown.rb', line 382

def syncdown(options={})
  options = elevate_hash(options)
  options[:asdown] = true
  dt = status(options)
  into = @locationbase + @location ###
  toadd = dt[:toadd]
  todel = dt[:todel]
  tomod = dt[:tomod]

  if options[:delete] then
    todel.each do |item|
      verbose "Removing item #{item[:synckey]}"
      unless $cfg['tool.dry'] then
        dest = tolocalpath(into, item)
        removelocal(dest, item)
      end
    end
  end
  if options[:create] then
    toadd.each do |item|
      verbose "Adding item #{item[:synckey]}"
      unless $cfg['tool.dry'] then
        dest = tolocalpath(into, item)
        download(dest, item)
      end
    end
  end
  if options[:update] then
    tomod.each do |item|
      verbose "Updating item #{item[:synckey]}"
      unless $cfg['tool.dry'] then
        dest = tolocalpath(into, item)
        download(dest, item)
      end
    end
  end
end

#synckey(item) ⇒ Object

Get the key used to quickly compare two items

Children objects should override this if synckey is not @itemkey

Parameters:

  • item

    Hash: The item to get a key from



195
196
197
198
# File 'lib/MrMurano/SyncUpDown.rb', line 195

def synckey(item)
  key = @itemkey.to_sym
  item[key]
end

#syncup(options = {}) ⇒ Object



347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
# File 'lib/MrMurano/SyncUpDown.rb', line 347

def syncup(options={})
  options = elevate_hash(options)
  itemkey = @itemkey.to_sym
  options[:asdown] = false
  dt = status(options)
  toadd = dt[:toadd]
  todel = dt[:todel]
  tomod = dt[:tomod]

  if options[:delete] then
    todel.each do |item|
      verbose "Removing item #{item[:synckey]}"
      unless $cfg['tool.dry'] then
        remove(item[itemkey])
      end
    end
  end
  if options[:create] then
    toadd.each do |item|
      verbose "Adding item #{item[:synckey]}"
      unless $cfg['tool.dry'] then
        upload(item[:local_path], item.reject{|k,v| k==:local_path}, false)
      end
    end
  end
  if options[:update] then
    tomod.each do |item|
      verbose "Updating item #{item[:synckey]}"
      unless $cfg['tool.dry'] then
        upload(item[:local_path], item.reject{|k,v| k==:local_path}, true)
      end
    end
  end
end

#tolocalname(item, itemkey) ⇒ Object

Compute the local name from remote item details

Children objects should override this or #tolocalpath

Parameters:

  • item

    Hash: listing details for the item.

  • itemkey

    Symbol: Key for look up.



164
165
166
# File 'lib/MrMurano/SyncUpDown.rb', line 164

def tolocalname(item, itemkey)
  item[itemkey].to_s
end

#tolocalpath(into, item) ⇒ Object

Compute the local path from the listing details

If there is already a matching local item, some of its details are also in the item hash.

Children objects should override this or #tolocalname

Parameters:

  • into

    Pathname: Root path for this resource type from config files

  • item

    Hash: listing details for the item.

Returns:

  • Pathname: path to save (or merge) remote item into



179
180
181
182
183
184
185
186
187
# File 'lib/MrMurano/SyncUpDown.rb', line 179

def tolocalpath(into, item)
  return item[:local_path] if item.has_key? :local_path
  itemkey = @itemkey.to_sym
  name = tolocalname(item, itemkey)
  raise "Bad key(#{itemkey}) for #{item}" if name.nil?
  name = Pathname.new(name) unless name.kind_of? Pathname
  name = name.relative_path_from(Pathname.new('/')) if name.absolute?
  into + name
end

#toRemoteItem(root, path) ⇒ Object

Compute a remote item hash from the local path

Children objects should override this.

Parameters:

  • root

    Pathname: Root path for this resource type from config files

  • path

    Pathname: Path to local item

Returns:

  • Hash: hash of the details for the remote item for this path



151
152
153
154
155
# File 'lib/MrMurano/SyncUpDown.rb', line 151

def toRemoteItem(root, path)
  path = Pathname.new(path) unless path.kind_of? Pathname
  root = Pathname.new(root) unless root.kind_of? Pathname
  {:name => path.realpath.relative_path_from(root.realpath).to_s}
end

#upload(src, item, modify) ⇒ Object

Upload local item to remote

Children objects Must override this

Parameters:

  • src

    Pathname: Full path of where to upload from

  • item

    Hash: The item details to upload

  • modify

    Bool: True if item exists already and this is changing it



122
123
124
125
126
# File 'lib/MrMurano/SyncUpDown.rb', line 122

def upload(src, item, modify)
  # :nocov:
  raise "Forgotten implementation"
  # :nocov:
end