Class: VagrantPlugins::ScpSync::ScpSyncHelper

Inherits:
Object
  • Object
show all
Defined in:
lib/vagrant-scp-sync/action/scp_sync.rb

Overview

This will SCP the files

Class Method Summary collapse

Class Method Details

.scp_single(machine, opts, scp_path) ⇒ Object

Raises:

  • (Vagrant::Errors::SSHNotReady)


23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/vagrant-scp-sync/action/scp_sync.rb', line 23

def self.scp_single(machine, opts, scp_path)
  ssh_info = machine.ssh_info
  raise Vagrant::Errors::SSHNotReady if ssh_info.nil?

  source_files = expand_path(opts[:map], machine)
  target_files = expand_path(opts[:to], machine)

  opts[:owner] ||= ssh_info[:username]
  opts[:group] ||= ssh_info[:username]

  ssh_opts = SshOptions.build(ssh_info)
  scp_opts = build_scp_options(opts)

  delete = scp_opts.include?('--delete')

  # Handle source and target path behaviors
  has_trailing_slash_source = opts[:map].end_with?('/')
  has_trailing_slash_target = opts[:to].end_with?('/')
  is_source_directory = File.directory?(source_files)

  if opts[:direction] == :upload || opts[:direction].nil?
    # For upload direction
    target_path = opts[:to]
    target_check = build_ssh_command(ssh_opts, "test -e '#{target_path}' && echo 'EXISTS' || echo 'NOT_EXISTS'", ssh_info)
    target_type_check = build_ssh_command(ssh_opts, "test -d '#{target_path}' && echo 'DIR' || echo 'FILE'", ssh_info)

    # Check if target exists and its type
    target_exists = execute_command_with_output(machine, target_check).strip == 'EXISTS'
    target_is_dir = target_exists && execute_command_with_output(machine, target_type_check).strip == 'DIR'

    # Determine source path based on trailing slash and directory status
    source = if is_source_directory && has_trailing_slash_source
               "'#{source_files}'/*"  # Quote path but leave glob outside quotes
             else
               "'#{source_files}'"    # Copy directory itself or single file with quotes
             end

    # Determine target path based on existence and trailing slash
    target_base = "#{ssh_info[:username]}@#{ssh_info[:host]}:'#{target_path}'"
    target = if target_exists && target_is_dir && !has_trailing_slash_target
               # If target exists as directory but no trailing slash, put source inside it
               "#{ssh_info[:username]}@#{ssh_info[:host]}:'#{target_path}/#{File.basename(source_files)}'"
             else
               target_base
             end

    # Prepare remote target directory with proper permissions
    target_dir = target_path
    target_dir = File.dirname(target_path) unless target_is_dir || has_trailing_slash_target

    make_dir = build_ssh_command(ssh_opts, "sudo mkdir -p '#{target_dir}'", ssh_info)
    change_ownership = build_ssh_command(ssh_opts, "sudo chown -R #{opts[:owner]}:#{opts[:group]} '#{target_dir}'", ssh_info)
    change_permissions = build_ssh_command(ssh_opts, "sudo chmod -R 777 '#{target_dir}'", ssh_info)
    remove_dir = build_ssh_command(ssh_opts, "sudo rm -rf '#{target_path}'", ssh_info) if delete

  elsif opts[:direction] == :download
    # For download direction
    # Use original path for VM side
    source = "#{ssh_info[:username]}@#{ssh_info[:host]}:'#{opts[:map]}'"
    source = "#{ssh_info[:username]}@#{ssh_info[:host]}:'#{opts[:map]}'/*" if has_trailing_slash_source

    # Use expanded path for local side
    target = "'#{target_files}'"
    target_dir = target_files
    target_dir = File.dirname(target_files) unless File.directory?(target_files) || has_trailing_slash_target
    make_dir = "mkdir -p '#{target_dir}'"
  end

  # Execute commands silently for setup
  execute_command(machine, remove_dir, true, nil, opts) if delete
  execute_command(machine, make_dir, true, nil, opts)

  # For upload, ensure remote directory permissions
  if opts[:direction] == :upload || opts[:direction].nil?
    execute_command(machine, change_ownership, true, nil, opts)
    execute_command(machine, change_permissions, true, nil, opts)
  end

  # Build and execute the scp command with sync message
  synchronize = build_scp_command(scp_path, ssh_opts, source, target)
  execute_command(machine, synchronize, true, 'scp_sync_folder', opts)
end