Class: Planter::Plant

Inherits:
Object
  • Object
show all
Defined in:
lib/planter/plant.rb

Overview

Primary class

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(template = nil, variables = nil) ⇒ Plant

Initialize a new Plant object

Parameters:

  • template (String) (defaults to: nil)

    the template name

  • variables (Hash) (defaults to: nil)

    Pre-populated variables



14
15
16
17
18
19
20
21
22
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
# File 'lib/planter/plant.rb', line 14

def initialize(template = nil, variables = nil)
  Planter.variables = variables if variables.is_a?(Hash)
  # Planter.config = template if template
  template ||= Planter.template
  die('No template specified', :config) unless template

  @config = Planter::Config.new

  @basedir = File.join(Planter.base_dir, 'templates', @config.template)
  @target = Planter.target || Dir.pwd

  @git = @config.git_init || false
  @debug = Planter.debug
  @repo = @config.repo || false

  # Coerce any existing variables (like from the command line) to the types
  # defined in configuration
  coerced = {}
  Planter.variables.each do |k, v|
    cfg_var = @config.variables.select { |var| k = var[:key] }
    next unless cfg_var.count.positive?

    var = cfg_var.first
    type = var[:type].normalize_type
    coerced[k] = v.coerce(type)
  end
  coerced.each { |k, v| Planter.variables[k] = v }

  # Ask user for any variables not already defined
  @config.variables.each do |var|
    key = var[:key].to_var
    next if Planter.variables.keys.include?(key)

    q = Planter::Prompt::Question.new(
      key: key,
      prompt: var[:prompt] || var[:key],
      type: var[:type].normalize_type || :string,
      default: var[:default],
      value: var[:value],
      min: var[:min],
      max: var[:max],
      choices: var[:choices] || nil,
      date_format: var[:date_format] || nil
    )
    answer = q.ask
    if answer.nil?
      Planter.notify("Missing value #{key}", :error, exit_code: 15) unless var[:default]

      answer = var[:default]
    end

    Planter.variables[key] = answer.apply_all
  end

  git_pull if @repo

  @files = FileList.new(@basedir)
end

Instance Attribute Details

#configObject (readonly)

Returns the value of attribute config.



6
7
8
# File 'lib/planter/plant.rb', line 6

def config
  @config
end

Instance Method Details

#add_gitObject

Initialize a git repo and create initial commit/tag

Returns:

  • true if successful, otherwise an error description



215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
# File 'lib/planter/plant.rb', line 215

def add_git
  return if File.directory?('.git')

  res = pass_fail('git init')
  res = pass_fail('git add .') if res
  res = pass_fail('git commit -a -m "initial commit"') if res
  res = pass_fail('git tag -a 0.0.1 -m "v0.0.1"') if res

  raise StandardError unless res

  true
rescue StandardError => e
  Planter.notify("#{e}\n#{e.backtrace}", :debug)
  'Error initializing git'
end

#copy_filesObject

Copy files from template directory, renaming if %%template vars%% exist in title

Returns:

  • true if successful, otherwise error description



178
179
180
181
# File 'lib/planter/plant.rb', line 178

def copy_files
  @files.copy
  true
end

#expand_repo(repo) ⇒ description_of_the_return_value

Expand GitHub name to full path

Examples:

Pass a GitHub-style repo path and get full url

expand_repo("ttscoff/planter-cli") #=> https://github.com/ttscoff/planter-cli.git

Parameters:

Returns:

  • (description_of_the_return_value)


83
84
85
# File 'lib/planter/plant.rb', line 83

def expand_repo(repo)
  repo =~ %r{(?!=http)\w+/\w+} ? "https://github.com/#{repo}.git" : repo
end

#git_pullString

Pull or clone a git repo

Returns:

  • (String)

    new base directory



101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# File 'lib/planter/plant.rb', line 101

def git_pull
  Planter.spinner.update(title: 'Pulling git repo')

  die('`git` executable not found', :git) unless TTY::Which.exist?('git')

  pwd = Dir.pwd
  @repo = expand_repo(@repo)

  if File.exist?(repo_dir)
    Dir.chdir(repo_dir)
    die("Directory #{repo_dir} exists but is not git repo", :git) unless File.exist?('.git')

    res = `git pull`
    die("Error pulling #{@repo}:\n#{res}", :git) unless $?.success?
  else
    Dir.chdir(@basedir)
    res = `git clone "#{@repo}" "#{repo_dir}"`
    die("Error cloning #{@repo}:\n#{res}", :git) unless $?.success?
  end
  Dir.chdir(pwd)
  @basedir = repo_dir
rescue StandardError => e
  die("Error pulling #{@repo}:\n#{e.message}", :git)
end

#plantObject

Plant the template to current directory



129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
# File 'lib/planter/plant.rb', line 129

def plant
  Dir.chdir(@target)

  Planter.spinner.auto_spin
  Planter.spinner.update(title: 'Copying files')
  res = copy_files
  if res.is_a?(String)
    Planter.spinner.error("(#{res})")
    Process.exit 1
  end

  Planter.spinner.update(title: 'Applying variables')

  res = update_files
  if res.is_a?(String)
    Planter.spinner.error('(Error)')
    Planter.notify(res, :error, exit_code: 1)
  end

  if @git
    die('`git` executable not found', :git) unless TTY::Which.exist?('git')

    Planter.spinner.update(title: 'Initializing git repo')
    res = add_git
    if res.is_a?(String)
      Planter.spinner.error('(Error)')
      Planter.notify(res, :error, exit_code: 1)
    end
  end

  if @config.script
    Planter.spinner.update(title: 'Running script')

    scripts = @config.script
    scripts = [scripts] if scripts.is_a?(String)
    scripts.each do |script|
      s = Planter::Script.new(@basedir, Dir.pwd, script)
      s.run
    end
  end
  Planter.spinner.update(title: 'Planting complete!')
  Planter.spinner.success
end

#repo_dirString

Directory for repo, subdirectory of template

Returns:



92
93
94
# File 'lib/planter/plant.rb', line 92

def repo_dir
  File.join(@basedir, File.basename(@repo).sub(/\.git$/, ''))
end

#update_filesObject

Update content of files in new directory using template variables



186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
# File 'lib/planter/plant.rb', line 186

def update_files
  files = Dir.glob('**/*', File::FNM_DOTMATCH).reject { |f| File.directory?(f) || f =~ /^(\.git|config\.yml)/ }

  files.each do |file|
    next if File.binary?(file)

    content = IO.read(file)

    new_content = content.apply_all

    new_content.gsub!(%r{^.{.4}/?merge *.{,4}\n}, '') if new_content =~ /^.{.4}merge *\n/

    unless content == new_content
      Planter.notify("Applying variables to #{file}", :debug)
      File.open(file, 'w') { |f| f.puts new_content }
    end
  end

  true
rescue StandardError => e
  Planter.notify("#{e}\n#{e.backtrace}", :debug)
  'Error updating files/directories'
end