Class: Bard::Target

Inherits:
Object
  • Object
show all
Defined in:
lib/bard/target.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(key, config) ⇒ Target

Returns a new instance of Target.



12
13
14
15
16
17
18
19
20
21
# File 'lib/bard/target.rb', line 12

def initialize(key, config)
  @key = key
  @config = config
  @capabilities = []
  @ping_urls = []
  @strategy_options_hash = {}
  @deploy_strategy = nil
  @path = nil
  @server = nil
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(method, *args, **kwargs, &block) ⇒ Object

Dynamic strategy DSL via method_missing



193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
# File 'lib/bard/target.rb', line 193

def method_missing(method, *args, **kwargs, &block)
  strategy_class = DeployStrategy[method]

  if strategy_class
    # This is a deployment strategy
    @deploy_strategy = method

    # Store options
    @strategy_options_hash[method] = kwargs

    # Auto-configure ping if first arg is a URL
    if args.first && args.first.to_s =~ /^https?:\/\//
      ping(args.first)
    end

    # Call the strategy's initializer if it wants to configure the target
    # (This will be handled by the strategy class)
  else
    super
  end
end

Instance Attribute Details

#configObject (readonly)

Returns the value of attribute config.



9
10
11
# File 'lib/bard/target.rb', line 9

def config
  @config
end

#deploy_strategyObject (readonly)

Deploy strategy



152
153
154
# File 'lib/bard/target.rb', line 152

def deploy_strategy
  @deploy_strategy
end

#keyObject (readonly)

Returns the value of attribute key.



9
10
11
# File 'lib/bard/target.rb', line 9

def key
  @key
end

#serverObject

Returns the value of attribute server.



10
11
12
# File 'lib/bard/target.rb', line 10

def server
  @server
end

Instance Method Details

#copy_dir(path, to:, verbose: false) ⇒ Object



242
243
244
245
246
# File 'lib/bard/target.rb', line 242

def copy_dir(path, to:, verbose: false)
  require_capability!(:ssh)
  to.require_capability!(:ssh) if to.respond_to?(:require_capability!)
  Copy.dir(path, from: self, to: to, verbose: verbose)
end

#copy_file(path, to:, verbose: false) ⇒ Object

File transfer



236
237
238
239
240
# File 'lib/bard/target.rb', line 236

def copy_file(path, to:, verbose: false)
  require_capability!(:ssh)
  to.require_capability!(:ssh) if to.respond_to?(:require_capability!)
  Copy.file(path, from: self, to: to, verbose: verbose)
end

#deploy_strategy_instanceObject



183
184
185
186
187
188
189
190
# File 'lib/bard/target.rb', line 183

def deploy_strategy_instance
  raise "No deployment strategy configured for target #{key}" unless @deploy_strategy

  strategy_class = DeployStrategy[@deploy_strategy]
  raise "Unknown deployment strategy: #{@deploy_strategy}" unless strategy_class

  strategy_class.new(self)
end

#enable_capability(capability) ⇒ Object

Capability tracking



24
25
26
# File 'lib/bard/target.rb', line 24

def enable_capability(capability)
  @capabilities << capability unless @capabilities.include?(capability)
end

#env(value = nil) ⇒ Object



108
109
110
111
112
113
114
115
# File 'lib/bard/target.rb', line 108

def env(value = nil)
  if value
    Deprecation.warn "Separate `env` call is deprecated; pass as keyword argument to `ssh` instead, e.g., `ssh \"user@host\", env: \"#{value}\"` (will be removed in v2.0)"
    @env = value
  else
    @env
  end
end

#exec!(command, home: false) ⇒ Object



230
231
232
233
# File 'lib/bard/target.rb', line 230

def exec!(command, home: false)
  require_capability!(:ssh)
  Command.exec!(command, on: self, home: home)
end

#gateway(value = nil) ⇒ Object

Deprecated separate setter methods - use ssh(…, option: value) instead



90
91
92
93
94
95
96
97
# File 'lib/bard/target.rb', line 90

def gateway(value = nil)
  if value
    Deprecation.warn "Separate `gateway` call is deprecated; pass as keyword argument to `ssh` instead, e.g., `ssh \"user@host\", gateway: \"#{value}\"` (will be removed in v2.0)"
    @gateway = value
  else
    @gateway
  end
end

#github_pages(url = nil) ⇒ Object

GitHub Pages deployment configuration



155
156
157
158
159
160
161
162
163
164
165
# File 'lib/bard/target.rb', line 155

def github_pages(url = nil)
  if url.nil?
    # Getter
    @github_pages_url
  else
    # Setter
    @deploy_strategy = :github_pages
    @github_pages_url = url
    enable_capability(:github_pages)
  end
end

#has_capability?(capability) ⇒ Boolean

Returns:

  • (Boolean)


28
29
30
# File 'lib/bard/target.rb', line 28

def has_capability?(capability)
  @capabilities.include?(capability)
end

#openObject



146
147
148
149
# File 'lib/bard/target.rb', line 146

def open
  require_capability!(:ping)
  system "open #{ping_urls.first}"
end

#option(key, value) ⇒ Object



173
174
175
176
177
# File 'lib/bard/target.rb', line 173

def option(key, value)
  Deprecation.warn "`option` is deprecated; pass options as keyword arguments to the strategy method, e.g., `jets \"url\", #{key}: #{value.inspect}` (will be removed in v2.0)"
  @strategy_options_hash[@deploy_strategy] ||= {}
  @strategy_options_hash[@deploy_strategy][key] = value
end

#path(new_path = nil) ⇒ Object

Path configuration



80
81
82
83
84
85
86
87
# File 'lib/bard/target.rb', line 80

def path(new_path = nil)
  if new_path
    Deprecation.warn "Separate `path` call is deprecated; pass as keyword argument to `ssh` instead, e.g., `ssh \"user@host\", path: \"#{new_path}\"` (will be removed in v2.0)"
    @path = new_path
  else
    @path || config.project_name
  end
end

#ping(*urls) ⇒ Object

Ping configuration



118
119
120
121
122
123
124
125
126
127
128
129
130
131
# File 'lib/bard/target.rb', line 118

def ping(*urls)
  if urls.empty?
    # Getter - normalize URLs like Server does
    @ping_urls.map { |url| normalize_ping(url) }
  elsif urls.first == false
    # Disable ping
    @ping_urls = []
    @capabilities.delete(:ping)
  else
    # Enable ping
    @ping_urls = urls.flatten
    enable_capability(:ping)
  end
end

#ping!Object



137
138
139
140
141
142
143
144
# File 'lib/bard/target.rb', line 137

def ping!
  require_capability!(:ping)
  require "bard/ping"
  failed_urls = Bard::Ping.call(self)
  if failed_urls.any?
    raise "Ping failed for: #{failed_urls.join(', ')}"
  end
end

#ping_urlsObject



133
134
135
# File 'lib/bard/target.rb', line 133

def ping_urls
  @ping_urls
end

#require_capability!(capability) ⇒ Object



32
33
34
35
36
37
38
39
40
41
42
43
44
# File 'lib/bard/target.rb', line 32

def require_capability!(capability)
  unless has_capability?(capability)
    error_message = case capability
    when :ssh
      "SSH not configured for this target"
    when :ping
      "Ping URL not configured for this target"
    else
      "#{capability} capability not configured for this target"
    end
    raise error_message
  end
end

#respond_to_missing?(method, include_private = false) ⇒ Boolean

Returns:

  • (Boolean)


215
216
217
# File 'lib/bard/target.rb', line 215

def respond_to_missing?(method, include_private = false)
  DeployStrategy[method] || super
end

#rsync_uri(file_path = nil) ⇒ Object



255
256
257
258
259
260
261
# File 'lib/bard/target.rb', line 255

def rsync_uri(file_path = nil)
  uri = ssh_uri
  str = "#{uri.user}@#{uri.host}"
  str += ":#{path}"
  str += "/#{file_path}" if file_path
  str
end

#run(command, home: false, verbose: false, quiet: false) ⇒ Object



225
226
227
228
# File 'lib/bard/target.rb', line 225

def run(command, home: false, verbose: false, quiet: false)
  require_capability!(:ssh)
  Command.run(command, on: self, home: home, verbose: verbose, quiet: quiet)
end

#run!(command, home: false, verbose: false, quiet: false) ⇒ Object

Remote command execution



220
221
222
223
# File 'lib/bard/target.rb', line 220

def run!(command, home: false, verbose: false, quiet: false)
  require_capability!(:ssh)
  Command.run!(command, on: self, home: home, verbose: verbose, quiet: quiet)
end

#scp_uri(file_path = nil) ⇒ Object

URI methods for compatibility



249
250
251
252
253
# File 'lib/bard/target.rb', line 249

def scp_uri(file_path = nil)
  full_path = "/#{path}"
  full_path += "/#{file_path}" if file_path
  URI::Generic.build(scheme: "scp", userinfo: server.user, host: server.host, port: server.port.to_i, path: full_path)
end

#ssh(uri_or_false = nil, **options) ⇒ Object

SSH configuration



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
# File 'lib/bard/target.rb', line 47

def ssh(uri_or_false = nil, **options)
  if uri_or_false.nil?
    # Getter - return false if explicitly disabled, otherwise return server
    return @ssh_disabled ? false : @server
  elsif uri_or_false == false
    # Disable SSH
    @server = nil
    @ssh_disabled = true
    @capabilities.delete(:ssh)
  else
    # Enable SSH
    require "bard/ssh_server"
    @server = SSHServer.new(uri_or_false, **options)
    @path = options[:path] if options[:path]
    @gateway = options[:gateway] if options[:gateway]
    @ssh_key = options[:ssh_key] if options[:ssh_key]
    @env = options[:env] if options[:env]
    enable_capability(:ssh)

    # Set SSH as default deployment strategy if none set
    @deploy_strategy ||= :ssh

    # Auto-configure ping from hostname
    hostname = @server.hostname
    ping("https://#{hostname}") if hostname
  end
end

#ssh_key(value = nil) ⇒ Object



99
100
101
102
103
104
105
106
# File 'lib/bard/target.rb', line 99

def ssh_key(value = nil)
  if value
    Deprecation.warn "Separate `ssh_key` call is deprecated; pass as keyword argument to `ssh` instead, e.g., `ssh \"user@host\", ssh_key: \"#{value}\"` (will be removed in v2.0)"
    @ssh_key = value
  else
    @ssh_key
  end
end

#ssh_uriObject



75
76
77
# File 'lib/bard/target.rb', line 75

def ssh_uri
  server&.ssh_uri
end

#strategy(name) ⇒ Object

Deprecated strategy configuration methods



168
169
170
171
# File 'lib/bard/target.rb', line 168

def strategy(name)
  Deprecation.warn "`strategy` is deprecated; use the strategy method directly, e.g., `#{name} \"url\"` instead of `strategy :#{name}` (will be removed in v2.0)"
  @deploy_strategy = name
end

#strategy_options(strategy_name) ⇒ Object



179
180
181
# File 'lib/bard/target.rb', line 179

def strategy_options(strategy_name)
  @strategy_options_hash[strategy_name] || {}
end

#to_sObject

Utility methods



264
265
266
# File 'lib/bard/target.rb', line 264

def to_s
  key.to_s
end

#to_symObject



268
269
270
# File 'lib/bard/target.rb', line 268

def to_sym
  key
end

#with(attrs) ⇒ Object



272
273
274
275
276
277
278
# File 'lib/bard/target.rb', line 272

def with(attrs)
  dup.tap do |t|
    attrs.each do |key, value|
      t.send(key, value)
    end
  end
end