ext 1.1.2 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG +47 -14
- data/LICENSE-MPL-2.0.txt +373 -0
- data/LICENSE.txt +9 -0
- data/README +5 -13
- data/lib/externals/command.rb +6 -5
- data/lib/externals/configuration/configuration.rb +27 -22
- data/lib/externals/ext.rb +164 -186
- data/lib/externals/extensions/file_utils.rb +15 -15
- data/lib/externals/extensions/string.rb +7 -10
- data/lib/externals/project.rb +37 -50
- data/lib/externals/scms/git_project.rb +69 -60
- data/lib/externals/scms/svn_project.rb +57 -29
- data/version.rb +4 -0
- metadata +41 -117
- data/MIT_LICENSE.txt +0 -22
- data/Rakefile +0 -75
- data/lib/externals/extensions/symbol.rb +0 -7
- data/lib/externals/project_types/rails.rb +0 -35
- data/test/setup/empty_plugin.svn.gz +0 -0
- data/test/setup/foreign_key_migrations.svn.gz +0 -0
- data/test/setup/redhillonrails_core.svn.gz +0 -0
- data/test/test_checkout_git.rb +0 -32
- data/test/test_checkout_with_subprojects_git.rb +0 -169
- data/test/test_checkout_with_subprojects_svn.rb +0 -384
- data/test/test_file_utils_extensions.rb +0 -29
- data/test/test_freeze_to_revision.rb +0 -176
- data/test/test_git_project_extract_name.rb +0 -20
- data/test/test_help.rb +0 -27
- data/test/test_init_git.rb +0 -40
- data/test/test_out_of_date_git_subproject.rb +0 -83
- data/test/test_projects.rb +0 -148
- data/test/test_rails_detection.rb +0 -23
- data/test/test_string_extensions.rb +0 -51
- data/test/test_svn_branches.rb +0 -353
- data/test/test_touch_emptydirs.rb +0 -59
- data/test/test_version.rb +0 -33
data/lib/externals/ext.rb
CHANGED
|
@@ -4,59 +4,55 @@ require 'optparse'
|
|
|
4
4
|
require 'externals/command'
|
|
5
5
|
require 'fileutils'
|
|
6
6
|
|
|
7
|
+
require_relative "../../version"
|
|
8
|
+
|
|
7
9
|
Dir.entries(File.join(File.dirname(__FILE__), 'extensions')).each do |extension|
|
|
8
10
|
require "externals/extensions/#{extension}" if extension =~ /.rb$/
|
|
9
11
|
end
|
|
10
12
|
|
|
11
13
|
module Externals
|
|
12
|
-
VERSION = '1.1.2'
|
|
13
|
-
PROJECT_TYPES_DIRECTORY = File.join(File.dirname(__FILE__), '..', 'externals','project_types')
|
|
14
|
-
|
|
15
14
|
# Full commands operate on the main project as well as the externals
|
|
16
15
|
# short commands only operate on the externals
|
|
17
16
|
# Main commands only operate on the main project
|
|
18
17
|
FULL_COMMANDS_HASH = [
|
|
19
18
|
[:checkout, "ext checkout <repository>",
|
|
20
|
-
|
|
19
|
+
%{Checks out <repository>, and checks out any subprojects
|
|
21
20
|
registered in <repository>'s .externals file.}],
|
|
22
21
|
[:export, "ext export <repository>",
|
|
23
|
-
|
|
22
|
+
%{Like checkout except this command fetches as little
|
|
24
23
|
history as possible.}],
|
|
25
24
|
[:status, "ext status",
|
|
26
|
-
|
|
25
|
+
%{Prints out the status of the main project, followed by
|
|
27
26
|
the status of each subproject.}],
|
|
28
27
|
[:update, "ext update",
|
|
29
|
-
|
|
28
|
+
%{Brings the main project, and all subprojects, up to the
|
|
30
29
|
latest version.}]
|
|
31
|
-
]
|
|
30
|
+
].freeze
|
|
32
31
|
SHORT_COMMANDS_HASH = [
|
|
33
32
|
[:co, "Like checkout, but skips the main project and
|
|
34
33
|
only checks out subprojects."],
|
|
35
34
|
[:ex, "Like export, but skips the main project."],
|
|
36
35
|
[:st, "Like status, but skips the main project."],
|
|
37
36
|
[:up, "Like update, but skips the main project."]
|
|
38
|
-
]
|
|
37
|
+
].freeze
|
|
39
38
|
MAIN_COMMANDS_HASH = [
|
|
40
39
|
[:freeze, "ext freeze <subproject> [REVISION]",
|
|
41
|
-
|
|
40
|
+
%{Locks a subproject into a specific revision/branch. If no
|
|
42
41
|
revision is supplied, the current revision/branch of the
|
|
43
42
|
project will be used. You can specify the subproject by name
|
|
44
43
|
or path.}],
|
|
45
44
|
[:help, "You probably just ran this command just now."],
|
|
46
45
|
[:init, "Creates a .externals file containing only [main]
|
|
47
|
-
It will try to determine the SCM used by the main project,
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
[:install, "ext install <repository> [-b <branch>] [path]",
|
|
53
|
-
"Registers <repository> in .externals under the appropriate
|
|
54
|
-
SCM. Checks out the project, and also adds it to the ignore
|
|
46
|
+
It will try to determine the SCM used by the main project."],
|
|
47
|
+
[:install, "ext install <repository> [-b <branch>] <path>",
|
|
48
|
+
"Registers <repository> in .externals under the appropriate
|
|
49
|
+
SCM. Checks out the subproject at given path,
|
|
50
|
+
and also adds it to the ignore
|
|
55
51
|
feature offered by the SCM of the main project. If the SCM
|
|
56
52
|
type is not obvious from the repository URL, use the --scm,
|
|
57
53
|
--git, or --svn flags."],
|
|
58
54
|
[:switch, "ext switch <branch_name>",
|
|
59
|
-
|
|
55
|
+
"Changes to the named branch <branch_name> and updates any
|
|
60
56
|
subprojects and applies any changes that have been made to the
|
|
61
57
|
.externals file."],
|
|
62
58
|
[:touch_emptydirs, "Recurses through all directories from the
|
|
@@ -64,10 +60,10 @@ module Externals
|
|
|
64
60
|
comes across. Useful for dealing with SCMs that refuse to
|
|
65
61
|
track empty directories (such as git, for example)"],
|
|
66
62
|
[:unfreeze, "ext unfreeze <subproject>",
|
|
67
|
-
|
|
63
|
+
%{Unfreezes a previously frozen subproject. You can specify
|
|
68
64
|
the subproject by name or path.}],
|
|
69
65
|
[:uninstall, "ext uninstall [-f|--force_removal] <project>",
|
|
70
|
-
|
|
66
|
+
"Removes a subproject from being tracked by ext. If you
|
|
71
67
|
want the files associated with this subproject deleted as well
|
|
72
68
|
(if, for example, you wish to reinstall it from a different
|
|
73
69
|
repository) then you can use the -f option to remove the files."],
|
|
@@ -77,11 +73,10 @@ module Externals
|
|
|
77
73
|
and so you probably only will run this if you are manually
|
|
78
74
|
maintaining .externals"],
|
|
79
75
|
[:version, "Displays the version number of externals and exits."],
|
|
80
|
-
]
|
|
81
|
-
|
|
76
|
+
].freeze
|
|
82
77
|
|
|
83
78
|
FULL_COMMANDS = FULL_COMMANDS_HASH.map(&:first)
|
|
84
|
-
SHORT_COMMANDS =
|
|
79
|
+
SHORT_COMMANDS = SHORT_COMMANDS_HASH.map(&:first)
|
|
85
80
|
MAIN_COMMANDS = MAIN_COMMANDS_HASH.map(&:first)
|
|
86
81
|
|
|
87
82
|
COMMANDS = FULL_COMMANDS + SHORT_COMMANDS + MAIN_COMMANDS
|
|
@@ -89,40 +84,14 @@ module Externals
|
|
|
89
84
|
COULD_NOT_DETERMINE_SCM = 1
|
|
90
85
|
NO_EXTERNALS_FILE = 2
|
|
91
86
|
|
|
92
|
-
Dir.entries(File.join(File.dirname(__FILE__), '..', 'externals','scms')).each do |project|
|
|
87
|
+
Dir.entries(File.join(File.dirname(__FILE__), '..', 'externals', 'scms')).each do |project|
|
|
93
88
|
require "externals/scms/#{project}" if project =~ /_project.rb$/
|
|
94
89
|
end
|
|
95
90
|
|
|
96
|
-
Dir.entries(PROJECT_TYPES_DIRECTORY).each do |type|
|
|
97
|
-
require File.join(PROJECT_TYPES_DIRECTORY, type) if type =~ /\.rb$/
|
|
98
|
-
end
|
|
99
|
-
|
|
100
91
|
class Ext
|
|
101
92
|
include FileUtils
|
|
102
93
|
extend FileUtils
|
|
103
94
|
|
|
104
|
-
attr_accessor :path_calculator
|
|
105
|
-
|
|
106
|
-
def self.project_types
|
|
107
|
-
types = Dir.entries(PROJECT_TYPES_DIRECTORY).select do |file|
|
|
108
|
-
file =~ /\.rb$/
|
|
109
|
-
end
|
|
110
|
-
|
|
111
|
-
types.map do |type|
|
|
112
|
-
/^(.*)\.rb$/.match(type)[1]
|
|
113
|
-
end
|
|
114
|
-
end
|
|
115
|
-
|
|
116
|
-
def self.project_type_files
|
|
117
|
-
project_types.map do |project_type|
|
|
118
|
-
"#{File.join(PROJECT_TYPES_DIRECTORY, project_type)}.rb"
|
|
119
|
-
end
|
|
120
|
-
end
|
|
121
|
-
|
|
122
|
-
project_type_files.each do |file|
|
|
123
|
-
require file
|
|
124
|
-
end
|
|
125
|
-
|
|
126
95
|
def self.new_opts main_options, sub_options
|
|
127
96
|
opts = OptionParser.new(
|
|
128
97
|
"ext [OPTIONS] <command> [repository] [-b <branch>] [path]"
|
|
@@ -133,37 +102,35 @@ module Externals
|
|
|
133
102
|
|
|
134
103
|
project_classes.each do |project_class|
|
|
135
104
|
project_class.fill_in_opts(opts, main_options, sub_options,
|
|
136
|
-
|
|
105
|
+
:summary_width => summary_width)
|
|
137
106
|
end
|
|
138
107
|
|
|
139
|
-
opts.on("--type TYPE", "-t TYPE",
|
|
140
|
-
String,
|
|
141
|
-
*"The type of project the main project is.
|
|
142
|
-
For example, 'rails'.".lines_by_width(summary_width)
|
|
143
|
-
) {|type| sub_options[:scm] = main_options[:type] = type}
|
|
144
108
|
opts.on("--scm SCM", "-s SCM",
|
|
145
|
-
|
|
146
|
-
|
|
109
|
+
String,
|
|
110
|
+
*"The SCM used to manage the main project. For example, '--scm svn'.".lines_by_width(summary_width)
|
|
147
111
|
) {|scm| sub_options[:scm] = main_options[:scm] = scm}
|
|
148
112
|
opts.on("--branch BRANCH", "-b BRANCH",
|
|
149
|
-
|
|
150
|
-
|
|
113
|
+
String,
|
|
114
|
+
*"The branch you want the
|
|
151
115
|
subproject to checkout when doing 'ext install'".lines_by_width(summary_width)
|
|
152
116
|
) {|branch| sub_options[:branch] = main_options[:branch] = branch}
|
|
153
117
|
opts.on("--revision REVISION", "-r REVISION",
|
|
154
|
-
|
|
155
|
-
|
|
118
|
+
String,
|
|
119
|
+
*"The revision you want the
|
|
156
120
|
subproject to checkout when doing 'ext install'".lines_by_width(summary_width)
|
|
157
121
|
) {|revision| sub_options[:revision] = main_options[:revision] = revision}
|
|
158
122
|
opts.on("--force_removal", "-f",
|
|
159
|
-
|
|
160
|
-
|
|
123
|
+
String,
|
|
124
|
+
*"When doing an uninstall of a subproject,
|
|
161
125
|
remove it's files and subfolders, too.".lines_by_width(summary_width)
|
|
162
|
-
) {
|
|
163
|
-
opts.on(
|
|
126
|
+
) { sub_options[:force_removal] = true }
|
|
127
|
+
opts.on(
|
|
128
|
+
"--workdir DIR", "-w DIR", String,
|
|
129
|
+
*"The working directory to execute commands from. Use this if for some reason you
|
|
164
130
|
cannot execute ext from the main project's directory (or if it's just inconvenient, such as in a script
|
|
165
131
|
or in a Capistrano task)".lines_by_width(summary_width)) {|dir|
|
|
166
|
-
raise "No such directory: #{dir}" unless File.
|
|
132
|
+
raise "No such directory: #{dir}" unless File.exist?(dir) && File.directory?(dir)
|
|
133
|
+
|
|
167
134
|
main_options[:workdir] = dir
|
|
168
135
|
}
|
|
169
136
|
opts.on(
|
|
@@ -187,7 +154,7 @@ module Externals
|
|
|
187
154
|
|
|
188
155
|
unless args.nil? || args.empty?
|
|
189
156
|
command = args[0]
|
|
190
|
-
args = args[1..
|
|
157
|
+
args = args[1..] || []
|
|
191
158
|
end
|
|
192
159
|
|
|
193
160
|
command &&= command.to_sym
|
|
@@ -196,20 +163,23 @@ module Externals
|
|
|
196
163
|
command = :version if main_options[:version]
|
|
197
164
|
|
|
198
165
|
if !command || command.to_s == ''
|
|
166
|
+
# :nocov:
|
|
199
167
|
puts "hey... you didn't tell me what you want to do."
|
|
200
168
|
puts "Try 'ext help' for a list of commands"
|
|
201
|
-
exit
|
|
169
|
+
exit 1
|
|
170
|
+
# :nocov:
|
|
202
171
|
end
|
|
203
172
|
|
|
204
173
|
unless COMMANDS.index command
|
|
174
|
+
# :nocov:
|
|
205
175
|
puts "unknown command: #{command}"
|
|
206
176
|
puts "for a list of commands try 'ext help'"
|
|
207
|
-
exit
|
|
177
|
+
exit 1
|
|
178
|
+
# :nocov:
|
|
208
179
|
end
|
|
209
180
|
|
|
210
|
-
|
|
211
181
|
Dir.chdir(main_options[:workdir] || ".") do
|
|
212
|
-
|
|
182
|
+
new(main_options).send(command, args, sub_options)
|
|
213
183
|
end
|
|
214
184
|
end
|
|
215
185
|
|
|
@@ -220,9 +190,9 @@ module Externals
|
|
|
220
190
|
puts
|
|
221
191
|
end
|
|
222
192
|
|
|
223
|
-
def help(
|
|
193
|
+
def help(_args, _options)
|
|
224
194
|
puts "There's a tutorial available at http://nopugs.com/ext-tutorial\n\n"
|
|
225
|
-
puts "#{self.class.new_opts({},{})
|
|
195
|
+
puts "#{self.class.new_opts({}, {})}\n\n"
|
|
226
196
|
|
|
227
197
|
puts "\nCommands that apply to the main project or the .externals file:"
|
|
228
198
|
puts "#{MAIN_COMMANDS.join(', ')}\n\n"
|
|
@@ -237,8 +207,10 @@ module Externals
|
|
|
237
207
|
print_commands(SHORT_COMMANDS_HASH)
|
|
238
208
|
end
|
|
239
209
|
|
|
210
|
+
@registered_scms = nil
|
|
240
211
|
def self.registered_scms
|
|
241
212
|
return @registered_scms if @registered_scms
|
|
213
|
+
|
|
242
214
|
@registered_scms ||= []
|
|
243
215
|
|
|
244
216
|
scmdir = File.join(File.dirname(__FILE__), 'scms')
|
|
@@ -254,9 +226,10 @@ module Externals
|
|
|
254
226
|
|
|
255
227
|
def projects
|
|
256
228
|
return @projects if @projects
|
|
229
|
+
|
|
257
230
|
@projects = []
|
|
258
231
|
configuration.sections.each do |section|
|
|
259
|
-
@projects << Ext.project_class(section[:scm]||infer_scm(section[:repository])).new(
|
|
232
|
+
@projects << Ext.project_class(section[:scm] || infer_scm(section[:repository])).new(
|
|
260
233
|
section.attributes.merge(:path => section.title))
|
|
261
234
|
end
|
|
262
235
|
#let's set the parents of these projects
|
|
@@ -271,11 +244,14 @@ module Externals
|
|
|
271
244
|
project ||= subprojects.detect do |p|
|
|
272
245
|
File.split(p.path).last.strip == name
|
|
273
246
|
end
|
|
274
|
-
project
|
|
247
|
+
project || subprojects.detect do |p|
|
|
248
|
+
# TODO: test (or delete) this code path!
|
|
249
|
+
# :nocov:
|
|
275
250
|
p.name == name
|
|
251
|
+
# :nocov:
|
|
276
252
|
end
|
|
277
253
|
end
|
|
278
|
-
alias
|
|
254
|
+
alias subproject subproject_by_name_or_path
|
|
279
255
|
|
|
280
256
|
def subprojects
|
|
281
257
|
s = []
|
|
@@ -286,14 +262,14 @@ module Externals
|
|
|
286
262
|
end
|
|
287
263
|
|
|
288
264
|
def main_project
|
|
289
|
-
projects.detect
|
|
265
|
+
projects.detect(&:main_project?)
|
|
290
266
|
end
|
|
291
267
|
|
|
292
268
|
def configuration
|
|
293
269
|
return @configuration if @configuration
|
|
294
270
|
|
|
295
271
|
file_string = ''
|
|
296
|
-
if File.
|
|
272
|
+
if File.exist?('.externals')
|
|
297
273
|
open('.externals', 'r') do |f|
|
|
298
274
|
file_string = f.read
|
|
299
275
|
end
|
|
@@ -310,45 +286,22 @@ module Externals
|
|
|
310
286
|
def initialize options = {}
|
|
311
287
|
super()
|
|
312
288
|
|
|
289
|
+
@configuration = nil
|
|
290
|
+
@projects = nil
|
|
291
|
+
|
|
313
292
|
scm = configuration['.']
|
|
314
293
|
scm = scm['scm'] if scm
|
|
315
|
-
scm
|
|
316
|
-
|
|
317
|
-
type = configuration['.']
|
|
318
|
-
type = type['type'] if type
|
|
319
|
-
|
|
320
|
-
type ||= options[:type]
|
|
321
|
-
|
|
322
|
-
if type
|
|
323
|
-
install_project_type type
|
|
324
|
-
else
|
|
325
|
-
possible_project_types = self.class.project_types.select do |project_type|
|
|
326
|
-
self.class.project_type_detector(project_type).detected?
|
|
327
|
-
end
|
|
328
|
-
|
|
329
|
-
if possible_project_types.size > 1
|
|
330
|
-
raise "We found multiple project types that this could be: #{possible_project_types.join(',')}
|
|
331
|
-
Please use
|
|
332
|
-
the --type option to tell ext which to use."
|
|
333
|
-
else
|
|
334
|
-
possible_project_types.each do |project_type|
|
|
335
|
-
install_project_type project_type
|
|
336
|
-
end
|
|
337
|
-
end
|
|
338
|
-
end
|
|
294
|
+
scm || options[:scm]
|
|
339
295
|
end
|
|
340
296
|
|
|
341
297
|
def self.project_class(scm)
|
|
342
|
-
Externals.
|
|
298
|
+
Externals.const_get("#{scm.to_s.cap_first}Project")
|
|
343
299
|
end
|
|
344
300
|
|
|
345
301
|
def self.project_classes
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
retval << project_class(scm)
|
|
302
|
+
registered_scms.map do |scm|
|
|
303
|
+
project_class(scm)
|
|
349
304
|
end
|
|
350
|
-
|
|
351
|
-
retval
|
|
352
305
|
end
|
|
353
306
|
|
|
354
307
|
SHORT_COMMANDS.each do |command_name|
|
|
@@ -360,20 +313,22 @@ Please use
|
|
|
360
313
|
end
|
|
361
314
|
|
|
362
315
|
if project_name_or_path
|
|
363
|
-
project = subprojects.detect do |
|
|
364
|
-
|
|
316
|
+
project = subprojects.detect do |p|
|
|
317
|
+
p.name == project_name_or_path || p.path == project_name_or_path
|
|
365
318
|
end
|
|
366
319
|
|
|
320
|
+
# :nocov:
|
|
367
321
|
raise "no such project" unless project
|
|
322
|
+
# :nocov:
|
|
368
323
|
|
|
369
324
|
project.send command_name, args, options
|
|
370
325
|
else
|
|
371
|
-
subprojects.each {|p| p.send(*
|
|
326
|
+
subprojects.each {|p| p.send(*[command_name, args, options].flatten)}
|
|
372
327
|
end
|
|
373
328
|
end
|
|
374
329
|
end
|
|
375
330
|
|
|
376
|
-
def freeze args,
|
|
331
|
+
def freeze args, _options
|
|
377
332
|
project = subproject_by_name_or_path(args[0])
|
|
378
333
|
|
|
379
334
|
raise "No such project named #{args[0]}" unless project
|
|
@@ -387,7 +342,10 @@ Please use
|
|
|
387
342
|
if branch
|
|
388
343
|
section[:branch] = branch
|
|
389
344
|
else
|
|
345
|
+
# TODO: test (or delete) this code path!
|
|
346
|
+
# :nocov:
|
|
390
347
|
section.rm_setting :branch
|
|
348
|
+
# :nocov:
|
|
391
349
|
end
|
|
392
350
|
end
|
|
393
351
|
section[:revision] = revision
|
|
@@ -397,7 +355,7 @@ Please use
|
|
|
397
355
|
subproject_by_name_or_path(args[0]).up
|
|
398
356
|
end
|
|
399
357
|
|
|
400
|
-
def unfreeze args,
|
|
358
|
+
def unfreeze args, _options
|
|
401
359
|
project = subproject_by_name_or_path(args[0])
|
|
402
360
|
|
|
403
361
|
raise "No such project named #{args[0]}" unless project
|
|
@@ -405,8 +363,10 @@ Please use
|
|
|
405
363
|
section = configuration[project.path]
|
|
406
364
|
|
|
407
365
|
unless section[:revision]
|
|
366
|
+
# :nocov:
|
|
408
367
|
puts "Uhh... #{project.name} wasn't frozen, so I can't unfreeze it."
|
|
409
|
-
exit
|
|
368
|
+
exit 1
|
|
369
|
+
# :nocov:
|
|
410
370
|
end
|
|
411
371
|
|
|
412
372
|
section.rm_setting :revision
|
|
@@ -417,9 +377,11 @@ Please use
|
|
|
417
377
|
end
|
|
418
378
|
|
|
419
379
|
def install args, options
|
|
420
|
-
if !File.
|
|
421
|
-
|
|
380
|
+
if !File.exist?('.externals')
|
|
381
|
+
# :nocov:
|
|
382
|
+
warn "This project does not appear to be managed by externals. Try 'ext init' first"
|
|
422
383
|
exit NO_EXTERNALS_FILE
|
|
384
|
+
# :nocov:
|
|
423
385
|
end
|
|
424
386
|
repository = args[0]
|
|
425
387
|
path = args[1]
|
|
@@ -431,15 +393,17 @@ Please use
|
|
|
431
393
|
scm ||= infer_scm(repository)
|
|
432
394
|
|
|
433
395
|
unless scm
|
|
434
|
-
|
|
396
|
+
# :nocov:
|
|
397
|
+
warn "Unable to determine SCM from the repository name.
|
|
435
398
|
You need to either specify the scm used to manage the subproject
|
|
436
399
|
that you are installing. Use an option to specify it
|
|
437
400
|
(such as --git or --svn)"
|
|
438
401
|
exit COULD_NOT_DETERMINE_SCM
|
|
402
|
+
# :nocov:
|
|
439
403
|
end
|
|
440
404
|
|
|
441
405
|
project = self.class.project_class(scm).new(:repository => repository,
|
|
442
|
-
|
|
406
|
+
:path => path, :scm => scm)
|
|
443
407
|
path = project.path
|
|
444
408
|
|
|
445
409
|
raise "no path" unless path
|
|
@@ -461,7 +425,11 @@ that you are installing. Use an option to specify it
|
|
|
461
425
|
end
|
|
462
426
|
|
|
463
427
|
def uninstall args, options
|
|
464
|
-
|
|
428
|
+
unless File.exist?('.externals')
|
|
429
|
+
# :nocov:
|
|
430
|
+
raise "Hmm... there's no .externals file in this directory."
|
|
431
|
+
# :nocov:
|
|
432
|
+
end
|
|
465
433
|
|
|
466
434
|
project = subproject_by_name_or_path(args[0])
|
|
467
435
|
|
|
@@ -469,7 +437,6 @@ that you are installing. Use an option to specify it
|
|
|
469
437
|
|
|
470
438
|
main_project.drop_from_ignore project.path
|
|
471
439
|
|
|
472
|
-
|
|
473
440
|
configuration.remove_section(project.path)
|
|
474
441
|
configuration.write '.externals'
|
|
475
442
|
reload_configuration
|
|
@@ -481,15 +448,18 @@ that you are installing. Use an option to specify it
|
|
|
481
448
|
end
|
|
482
449
|
end
|
|
483
450
|
|
|
484
|
-
def update_ignore
|
|
451
|
+
def update_ignore _args, options
|
|
485
452
|
scm = configuration['.']
|
|
486
453
|
scm = scm['scm'] if scm
|
|
487
454
|
|
|
488
455
|
scm ||= options[:scm]
|
|
489
456
|
|
|
490
457
|
unless scm
|
|
491
|
-
|
|
458
|
+
# :nocov:
|
|
459
|
+
raise "You need to either specify the scm as the first line in .externals (for example, scm = git), " \
|
|
460
|
+
"or use an option to specify it
|
|
492
461
|
(such as --git or --svn)"
|
|
462
|
+
# :nocov:
|
|
493
463
|
end
|
|
494
464
|
|
|
495
465
|
project = self.class.project_class(scm).new(:path => ".")
|
|
@@ -501,10 +471,10 @@ that you are installing. Use an option to specify it
|
|
|
501
471
|
end
|
|
502
472
|
end
|
|
503
473
|
|
|
504
|
-
def touch_emptydirs
|
|
474
|
+
def touch_emptydirs _args, _options
|
|
505
475
|
require 'find'
|
|
506
476
|
|
|
507
|
-
excludes = ['.','..','.svn', '.git']
|
|
477
|
+
excludes = ['.', '..', '.svn', '.git']
|
|
508
478
|
|
|
509
479
|
excludes.dup.each do |exclude|
|
|
510
480
|
excludes << "./#{exclude}"
|
|
@@ -516,23 +486,26 @@ that you are installing. Use an option to specify it
|
|
|
516
486
|
if File.directory?(f)
|
|
517
487
|
excluded = false
|
|
518
488
|
File.split(f).each do |part|
|
|
519
|
-
|
|
489
|
+
excluded ||= excludes.index(part)
|
|
520
490
|
end
|
|
521
491
|
|
|
522
|
-
if !excluded && (
|
|
492
|
+
if !excluded && (Dir.entries(f) - excludes).empty?
|
|
523
493
|
paths << f
|
|
524
494
|
end
|
|
525
495
|
end
|
|
526
496
|
end
|
|
527
497
|
|
|
528
498
|
paths.each do |p|
|
|
529
|
-
|
|
499
|
+
# TODO: is there not an easier way to touch a file??
|
|
500
|
+
# rubocop:disable Style/FileOpen
|
|
501
|
+
f = File.open(File.join(p, ".emptydir"), "w")
|
|
502
|
+
# rubocop:enable Style/FileOpen
|
|
503
|
+
ensure
|
|
504
|
+
f.close
|
|
530
505
|
end
|
|
531
|
-
|
|
532
506
|
end
|
|
533
507
|
|
|
534
|
-
|
|
535
|
-
def status args, options
|
|
508
|
+
def status _args, options
|
|
536
509
|
options ||= {}
|
|
537
510
|
scm = options[:scm]
|
|
538
511
|
|
|
@@ -542,24 +515,27 @@ that you are installing. Use an option to specify it
|
|
|
542
515
|
end
|
|
543
516
|
|
|
544
517
|
if !scm
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
518
|
+
# TODO: test (or delete) this code path!
|
|
519
|
+
# :nocov:
|
|
520
|
+
possible_project_classes = self.class.project_classes.select(&:detected?)
|
|
548
521
|
|
|
549
|
-
raise "Could not determine this projects scm" if
|
|
522
|
+
raise "Could not determine this projects scm" if possible_project_classes.empty?
|
|
550
523
|
if possible_project_classes.size > 1
|
|
551
524
|
raise "This project appears to be managed by multiple SCMs: #{
|
|
552
|
-
possible_project_classes.
|
|
525
|
+
possible_project_classes.join(',')}
|
|
553
526
|
Please explicitly declare the SCM (by using --git or --svn, or,
|
|
554
527
|
by creating the .externals file manually"
|
|
555
528
|
end
|
|
556
529
|
|
|
557
530
|
scm = possible_project_classes.first.scm
|
|
531
|
+
# :nocov:
|
|
558
532
|
end
|
|
559
533
|
|
|
560
534
|
unless scm
|
|
535
|
+
# :nocov:
|
|
561
536
|
raise "You need to either specify the scm as the first line in .externals, or use an option to specify it
|
|
562
537
|
(such as --git or --svn)"
|
|
538
|
+
# :nocov:
|
|
563
539
|
end
|
|
564
540
|
|
|
565
541
|
project = main_project
|
|
@@ -581,24 +557,27 @@ by creating the .externals file manually"
|
|
|
581
557
|
end
|
|
582
558
|
|
|
583
559
|
if !scm
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
560
|
+
# TODO: test (or delete) this code path!
|
|
561
|
+
# :nocov:
|
|
562
|
+
possible_project_classes = self.class.project_classes.select(&:detected?)
|
|
587
563
|
|
|
588
|
-
raise "Could not determine this projects scm" if
|
|
564
|
+
raise "Could not determine this projects scm" if possible_project_classes.empty?
|
|
589
565
|
if possible_project_classes.size > 1
|
|
590
566
|
raise "This project appears to be managed by multiple SCMs: #{
|
|
591
|
-
possible_project_classes.
|
|
567
|
+
possible_project_classes.join(',')}
|
|
592
568
|
Please explicitly declare the SCM (by using --git or --svn, or,
|
|
593
569
|
by creating the .externals file manually"
|
|
594
570
|
end
|
|
595
571
|
|
|
596
572
|
scm = possible_project_classes.first.scm
|
|
573
|
+
# :nocov:
|
|
597
574
|
end
|
|
598
575
|
|
|
599
576
|
unless scm
|
|
577
|
+
# :nocov:
|
|
600
578
|
raise "You need to either specify the scm as the first line in .externals, or use an option to specify it
|
|
601
579
|
(such as --git or --svn)"
|
|
580
|
+
# :nocov:
|
|
602
581
|
end
|
|
603
582
|
|
|
604
583
|
old_config = configuration
|
|
@@ -618,14 +597,14 @@ by creating the .externals file manually"
|
|
|
618
597
|
|
|
619
598
|
removed_project_paths = old_config.removed_project_paths(
|
|
620
599
|
configuration
|
|
621
|
-
).select{|path| File.
|
|
600
|
+
).select{|path| File.exist?(path)}
|
|
622
601
|
|
|
623
602
|
if !removed_project_paths.empty?
|
|
624
603
|
puts "WARNING: The following subprojects are no longer being maintained in the
|
|
625
604
|
.externals file. You might want to remove them. You can copy and paste the
|
|
626
605
|
commands below if you actually wish to delete them."
|
|
627
606
|
removed_project_paths.each do |path|
|
|
628
|
-
if File.
|
|
607
|
+
if File.exist?(path)
|
|
629
608
|
puts " rm -r #{path}"
|
|
630
609
|
end
|
|
631
610
|
end
|
|
@@ -633,7 +612,7 @@ commands below if you actually wish to delete them."
|
|
|
633
612
|
end
|
|
634
613
|
end
|
|
635
614
|
|
|
636
|
-
def update
|
|
615
|
+
def update _args, options
|
|
637
616
|
options ||= {}
|
|
638
617
|
scm = options[:scm]
|
|
639
618
|
|
|
@@ -643,8 +622,10 @@ commands below if you actually wish to delete them."
|
|
|
643
622
|
end
|
|
644
623
|
|
|
645
624
|
unless scm
|
|
625
|
+
# :nocov:
|
|
646
626
|
raise "You need to either specify the scm as the first line in .externals, or use an option to specify it
|
|
647
627
|
(such as --git or --svn)"
|
|
628
|
+
# :nocov:
|
|
648
629
|
end
|
|
649
630
|
|
|
650
631
|
project = main_project
|
|
@@ -667,7 +648,7 @@ commands below if you actually wish to delete them."
|
|
|
667
648
|
end
|
|
668
649
|
|
|
669
650
|
Dir.chdir path do
|
|
670
|
-
self.class.new({}).co [], {}
|
|
651
|
+
self.class.new({}).co [], {}
|
|
671
652
|
end
|
|
672
653
|
end
|
|
673
654
|
|
|
@@ -680,7 +661,10 @@ commands below if you actually wish to delete them."
|
|
|
680
661
|
main_project = do_checkout_or_export repository, path, options, :export
|
|
681
662
|
|
|
682
663
|
if path == "."
|
|
664
|
+
# TODO: test (or delete) this code path!
|
|
665
|
+
# :nocov:
|
|
683
666
|
path = main_project.name
|
|
667
|
+
# :nocov:
|
|
684
668
|
end
|
|
685
669
|
|
|
686
670
|
Dir.chdir path do
|
|
@@ -689,44 +673,29 @@ commands below if you actually wish to delete them."
|
|
|
689
673
|
end
|
|
690
674
|
|
|
691
675
|
def init args, options = {}
|
|
692
|
-
|
|
676
|
+
# :nocov:
|
|
677
|
+
raise ".externals already exists" if File.exist?('.externals')
|
|
678
|
+
# :nocov:
|
|
693
679
|
|
|
694
680
|
scm = options[:scm]
|
|
695
|
-
type = options[:type]
|
|
696
681
|
|
|
697
682
|
if !scm
|
|
698
|
-
possible_project_classes = self.class.project_classes.select
|
|
699
|
-
project_class.detected?
|
|
700
|
-
end
|
|
683
|
+
possible_project_classes = self.class.project_classes.select(&:detected?)
|
|
701
684
|
|
|
702
|
-
raise "Could not determine this project's scm" if
|
|
685
|
+
raise "Could not determine this project's scm" if possible_project_classes.empty?
|
|
703
686
|
if possible_project_classes.size > 1
|
|
687
|
+
# :nocov:
|
|
704
688
|
raise "This project appears to be managed by multiple SCMs: #{
|
|
705
|
-
possible_project_classes.
|
|
689
|
+
possible_project_classes.join(',')}
|
|
706
690
|
Please explicitly declare the SCM (using --git or --svn, or, by creating .externals manually"
|
|
691
|
+
# :nocov:
|
|
707
692
|
end
|
|
708
693
|
|
|
709
694
|
scm = possible_project_classes.first.scm
|
|
710
695
|
end
|
|
711
696
|
|
|
712
|
-
if !type
|
|
713
|
-
possible_project_types = self.class.project_types.select do |project_type|
|
|
714
|
-
self.class.project_type_detector(project_type).detected?
|
|
715
|
-
end
|
|
716
|
-
|
|
717
|
-
if possible_project_types.size > 1
|
|
718
|
-
raise "We found multiple project types that this could be: #{possible_project_types.join(',')}
|
|
719
|
-
Please use the --type option to tell ext which to use."
|
|
720
|
-
elsif possible_project_types.size == 0
|
|
721
|
-
puts "WARNING: We could not automatically determine the project type.
|
|
722
|
-
Be sure to specify paths when adding subprojects to your .externals file"
|
|
723
|
-
else
|
|
724
|
-
type = possible_project_types.first
|
|
725
|
-
end
|
|
726
|
-
end
|
|
727
|
-
|
|
728
697
|
config = Configuration::Configuration.new_empty
|
|
729
|
-
raise ".externals already exists" if File.
|
|
698
|
+
raise ".externals already exists" if File.exist?('.externals')
|
|
730
699
|
|
|
731
700
|
config.add_empty_section '.'
|
|
732
701
|
|
|
@@ -738,33 +707,30 @@ Please use the --type option to tell ext which to use."
|
|
|
738
707
|
options[:branch]
|
|
739
708
|
)
|
|
740
709
|
elsif args[0]
|
|
710
|
+
# TODO: test (or delete) this code path!
|
|
711
|
+
# :nocov:
|
|
741
712
|
config['.'][:repository] = args[0].strip
|
|
713
|
+
# :nocov:
|
|
742
714
|
end
|
|
743
715
|
end
|
|
744
716
|
|
|
745
717
|
config['.'][:scm] = scm
|
|
746
|
-
config['.'][:type] = type if type
|
|
747
718
|
|
|
748
719
|
config.write '.externals'
|
|
749
720
|
reload_configuration
|
|
750
721
|
end
|
|
751
722
|
|
|
752
|
-
def version(
|
|
723
|
+
def version(_args, _options)
|
|
753
724
|
puts Externals::VERSION
|
|
754
725
|
end
|
|
755
726
|
|
|
756
|
-
def self.project_type_detector name
|
|
757
|
-
Externals.module_eval("#{name.classify}Detector", __FILE__, __LINE__)
|
|
758
|
-
end
|
|
759
|
-
|
|
760
|
-
def install_project_type name
|
|
761
|
-
self.path_calculator = Externals.module_eval("#{name.classify}ProjectType::DefaultPathCalculator", __FILE__, __LINE__)
|
|
762
|
-
end
|
|
763
|
-
|
|
764
727
|
protected
|
|
728
|
+
|
|
765
729
|
def do_checkout_or_export repository, path, options, sym
|
|
766
|
-
if File.
|
|
730
|
+
if File.exist?('.externals')
|
|
731
|
+
# :nocov:
|
|
767
732
|
raise "seems main project is already checked out here?"
|
|
733
|
+
# :nocov:
|
|
768
734
|
else
|
|
769
735
|
#We appear to be attempting to checkout/export a main project
|
|
770
736
|
scm = options[:scm]
|
|
@@ -772,13 +738,18 @@ Please use the --type option to tell ext which to use."
|
|
|
772
738
|
scm ||= infer_scm(repository)
|
|
773
739
|
|
|
774
740
|
if !scm
|
|
741
|
+
# TODO: test (or delete) this code path!
|
|
742
|
+
# :nocov:
|
|
775
743
|
scm ||= configuration['main']
|
|
776
744
|
scm &&= scm['scm']
|
|
745
|
+
# :nocov:
|
|
777
746
|
end
|
|
778
747
|
|
|
779
748
|
unless scm
|
|
749
|
+
# :nocov:
|
|
780
750
|
raise "You need to either specify the scm as the first line in .externals, or use an option to specify it
|
|
781
751
|
(such as --git or --svn)"
|
|
752
|
+
# :nocov:
|
|
782
753
|
end
|
|
783
754
|
|
|
784
755
|
main_project = self.class.project_class(scm).new(
|
|
@@ -793,12 +764,19 @@ Please use the --type option to tell ext which to use."
|
|
|
793
764
|
end
|
|
794
765
|
|
|
795
766
|
def infer_scm(path)
|
|
796
|
-
|
|
797
|
-
|
|
767
|
+
registered_scms.find do |scm|
|
|
768
|
+
project_class(scm).scm_path?(path)
|
|
798
769
|
end
|
|
799
|
-
nil
|
|
800
770
|
end
|
|
801
|
-
end
|
|
802
|
-
end
|
|
803
771
|
|
|
772
|
+
private
|
|
773
|
+
|
|
774
|
+
def registered_scms
|
|
775
|
+
self.class.registered_scms
|
|
776
|
+
end
|
|
804
777
|
|
|
778
|
+
def project_class(scm)
|
|
779
|
+
self.class.project_class(scm)
|
|
780
|
+
end
|
|
781
|
+
end
|
|
782
|
+
end
|