/
abstract_repository.rb
319 lines (276 loc) · 9.63 KB
/
abstract_repository.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
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
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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
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
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
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
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
module Sashimi
class PluginNotFound < StandardError #:nodoc:
def initialize(plugin_name, message = nil)
@plugin_name, @message = plugin_name, message
end
def to_s
@message || @plugin_name + " isn't in the local repository."
end
end
class AbstractRepository
@@plugins_path = File.join('.rails', 'plugins')
@@cache_file = '.plugins'
cattr_accessor :cache_file
attr_reader :plugin
def initialize(plugin)
@plugin = plugin
end
# Remove the repository
def uninstall
with_path local_repository_path do
raise PluginNotFound.new(plugin.name) unless File.exists?(plugin.name)
FileUtils.rm_rf(plugin.name)
remove_from_cache
end
end
# Add to a Rails app.
def add
raise PluginNotFound.new(plugin.name) unless cache_content.keys.include?(plugin.name)
puts plugin.name.titleize + "\n"
copy_plugin_and_remove_hidden_folders
rename_temp_folder
run_install_hook
end
# Copy a plugin to a Rails app and remove SCM hidden folders
def copy_plugin_and_remove_hidden_folders
copy_plugin_to_rails_app
remove_hidden_folders
end
class << self
def instantiate_repository(plugin)
with_path local_repository_path do
unless plugin.name.nil?
instantiate_repository_by_cache(plugin)
else
instantiate_repository_by_url(plugin)
end.new(plugin)
end
end
# Return all installed plugin names and summary, formatted for stdout.
def list
cache_content.sort.collect do |plugin, contents|
"#{plugin}\t\t#{contents['summary']}"
end.join("\n")
end
# Return all installed plugins names.
def plugins_names
cache_content.keys.sort
end
# Update the plugins installed in a rails app.
def update_rails_plugins(plugins_names)
with_path path_to_rails_app do
if under_version_control?
update_versioned_rails_plugins(plugins_names)
else
update_unversioned_rails_plugins(plugins_names)
end
end
end
# Update the plugins installed in a non versioned rails app.
def update_unversioned_rails_plugins(plugins_names)
with_path rails_plugins_path do
plugins_names.each do |plugin_name|
FileUtils.rm_rf(plugin_name)
Plugin.new(plugin_name).add
end
end
end
# Update the plugins installed in a versioned rails app.
def update_versioned_rails_plugins(plugins_names)
change_dir(plugins_dir)
plugins_names.each do |plugin_name|
raise PluginNotFound.new(plugin_name) unless File.exists?(plugin_name)
repository = Plugin.new(plugin_name).repository
repository.copy_plugin_and_remove_hidden_folders
files_scheduled_for_remove = repository.files_scheduled_for_remove
files_scheduled_for_add = repository.files_scheduled_for_add
FileUtils.cp_r(plugin_name+'-tmp/.', plugin_name)
repository.remove_temp_folder
change_dir(plugin_name)
files_scheduled_for_remove.each {|file| scm_remove file}
files_scheduled_for_add.each {|file| scm_add file}
end
end
# Schedules an add for the given file on the current SCM system used by the Rails app.
def scm_add(file)
scm_command(:add, file)
end
def scm_remove(file)
scm_command(:rm, file)
end
# Execute the given command for the current SCM system used by the Rails app.
def scm_command(command, file)
scm = guess_version_control_system
Kernel.system("#{scm} #{command} #{file}")
end
def local_repository_path #:nodoc:
@local_repository_path ||= File.join(find_home, @@plugins_path)
end
# Return the path to the Rails app where the user launched sashimi command.
def path_to_rails_app
$rails_app
end
# Read the cache file and return the content as an <tt>Hash</tt>.
def cache_content
with_path local_repository_path do
@@cache_content ||= (YAML::load_file(cache_file) || {}).to_hash
end
end
def instantiate_repository_by_url(plugin)
git_url?(plugin.url) ? GitRepository : SvnRepository
end
def instantiate_repository_by_cache(plugin)
cached_plugin = cache_content[plugin.name]
raise PluginNotFound.new(plugin.name) if cached_plugin.nil?
cached_plugin['type'] == 'git' ? GitRepository : SvnRepository
end
# Change the current directory with the fully qualified
# path to Rails app and plugins_dir.
def absolute_rails_plugins_path
@@absolute_rails_plugins_path ||= File.join(File.expand_path(path_to_rails_app),
rails_plugins_path)
end
# Rails app plugins dir
def rails_plugins_path
@@rails_plugins_path ||= File.join('vendor', 'plugins')
end
# Check if the current working directory is under version control
def under_version_control?
!Dir.glob(".{git,svn}").empty?
end
# Guess the version control system for the current working directory.
def guess_version_control_system
File.exists?('.git') ? :git : :svn
end
# Find the user home directory
def find_home
['HOME', 'USERPROFILE'].each do |homekey|
return ENV[homekey] if ENV[homekey]
end
if ENV['HOMEDRIVE'] && ENV['HOMEPATH']
return "#{ENV['HOMEDRIVE']}:#{ENV['HOMEPATH']}"
end
begin
File.expand_path("~")
rescue StandardError => ex
if File::ALT_SEPARATOR
"C:/"
else
"/"
end
end
end
# Try to guess if it's a Git url.
def git_url?(url)
url =~ /^git:\/\// || url =~ /\.git$/
end
def with_path(path, &block)
begin
old_path = Dir.pwd
FileUtils.cd(path)
yield
ensure
FileUtils.cd(old_path)
end
end
end
# Return the SCM type
#
# Subversion # => svn
# Git # => git
def scm_type
self.class.name.demodulize.gsub(/Repository$/, '').downcase
end
# Read the content of the <tt>about.yml</tt>.
# New feature of Rails 2.1.x http:://dev.rubyonrails.org/changeset/9098
def about
with_path plugin_path do
return {} unless File.exists?('about.yml')
(YAML::load_file('about.yml') || {}).to_hash
end
end
# Returns a list of files that should be scheduled for SCM add.
def files_scheduled_for_add
with_path absolute_rails_plugins_path do
Dir[plugin.name+"-tmp/**/*"].collect {|fn| fn.gsub(plugin.name+'-tmp', '.')} -
Dir[plugin.name+"/**/*"].collect{|fn| fn.gsub(plugin.name, '.')}
end
end
# Returns a list of files that should be scheduled for SCM remove.
def files_scheduled_for_remove
with_path absolute_rails_plugins_path do
Dir[plugin.name+"/**/*"].collect {|fn| fn.gsub(plugin.name, '.')} -
Dir[plugin.name+"-tmp/**/*"].collect {|fn| fn.gsub(plugin.name+"-tmp", '.')}
end
end
# Remove the temp folder, used by update process.
def remove_temp_folder
with_path absolute_rails_plugins_path do
FileUtils.rm_rf(plugin.name+'-tmp')
end
end
class_method_proxy :local_repository_path, :cache_file,
:cache_content, :path_to_rails_app, :rails_plugins_path,
:with_path, :absolute_rails_plugins_path
private
# Returns the path to the plugin
def plugin_path
File.join(local_repository_path, plugin.name || plugin.guess_name)
end
# Prepare the plugin installation
def prepare_installation
FileUtils.mkdir_p(local_repository_path)
with_path local_repository_path do
FileUtils.touch(cache_file)
end
end
# Add a plugin into the cache
def add_to_cache(plugin)
write_to_cache cache_content.to_hash.merge!(plugin)
end
# Remove a plugin from the cache
def remove_from_cache
cache_content.delete(plugin.name)
write_to_cache cache_content
end
# Write all the plugins into the cache
def write_to_cache(plugins)
with_path local_repository_path do
FileUtils.mv(cache_file, "#{cache_file}-backup")
File.open(cache_file, 'w'){|f| f.write(plugins.to_yaml)}
FileUtils.rm("#{cache_file}-backup")
end
end
# Copy a plugin to a Rails app.
def copy_plugin_to_rails_app
FileUtils.mkdir_p(plugins_path)
FileUtils.cp_r(File.join(local_repository_path, plugin.name),
File.join(rails_plugins_path, plugin.name+'-tmp'))
end
# Rename the *-tmp folder used by the installation process.
#
# Example:
# click-to-globalize-tmp # => click-to-globalize
def rename_temp_folder
FileUtils.mv(File.join(rails_plugins_path, plugin.name+'-tmp'),
File.join(rails_plugins_path, plugin.name))
end
# Remove SCM hidden folders.
def remove_hidden_folders
require 'find'
with_path File.join(absolute_rails_plugins_path, plugin.name + '-tmp') do
Find.find('./') do |path|
if File.basename(path) == '.'+scm_type
FileUtils.remove_dir(path, true)
Find.prune
end
end
end
end
# Run the plugin install hook.
def run_install_hook
install_hook_file = File.join(rails_plugins_path, plugin.name, 'install.rb')
load install_hook_file if File.exist? install_hook_file
end
end
end