ext 0.0.10 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README +11 -10
- data/Rakefile +2 -2
- data/lib/{ext → extensions}/string.rb +0 -0
- data/lib/{ext → extensions}/symbol.rb +0 -0
- data/lib/externals/configuration/configuration.rb +112 -77
- data/lib/externals/configuration/old_configuration.rb +166 -0
- data/lib/externals/ext.rb +181 -48
- data/lib/externals/old_project.rb +114 -0
- data/lib/externals/old_scms/old_git_project.rb +116 -0
- data/lib/externals/old_scms/old_svn_project.rb +98 -0
- data/lib/externals/project.rb +59 -52
- data/lib/externals/project_types/rails.rb +18 -6
- data/lib/externals/scms/git_project.rb +6 -0
- data/lib/externals/scms/svn_project.rb +5 -0
- data/test/test_checkout_git.rb +4 -0
- data/test/test_checkout_with_subprojects_git.rb +10 -1
- data/test/test_checkout_with_subprojects_svn.rb +26 -12
- data/test/test_upgrade_externals_file.rb +84 -0
- metadata +9 -4
data/README
CHANGED
@@ -17,12 +17,14 @@ short form. The longer form applies the action to the main project. The short
|
|
17
17
|
forms apply the action to all sub projects.
|
18
18
|
|
19
19
|
The commands and usage are as follows (from 'ext help'):
|
20
|
+
There's a tutorial available at http://nopugs.com/ext-tutorial
|
20
21
|
|
21
|
-
ext [OPTIONS] <command> [repository[
|
22
|
+
ext [OPTIONS] <command> [repository] [-b <branch>] [path]
|
22
23
|
-g, --git same as '--scm git' Uses git to checkout/export the main project
|
23
24
|
-s, --svn, --subversion same as '--scm svn' Uses subversion to checkout/export the main project
|
24
25
|
-t, --type TYPE The type of project the main project is. For example, 'rails'.
|
25
26
|
--scm SCM The SCM used to manage the main project. For example, '--scm svn'.
|
27
|
+
-b, --branch BRANCH The branch you want the subproject to checkout when doing 'ext install'
|
26
28
|
-w, --workdir DIR The working directory to execute commands from. Use this if for some reason you
|
27
29
|
cannot execute ext from the main project's directory (or if it's just inconvenient, such as in a script
|
28
30
|
or in a Capistrano task)
|
@@ -32,7 +34,7 @@ ext [OPTIONS] <command> [repository[:branch]] [path]
|
|
32
34
|
|
33
35
|
|
34
36
|
Commands that apply to the main project or the .externals file:
|
35
|
-
update_ignore, install, init, touch_emptydirs, help
|
37
|
+
update_ignore, install, init, touch_emptydirs, help, upgrade_externals_file
|
36
38
|
|
37
39
|
update_ignore Adds all paths to subprojects that are
|
38
40
|
registered in .externals to the ignore feature of the
|
@@ -40,12 +42,12 @@ update_ignore Adds all paths to subprojects that are
|
|
40
42
|
and so you probably only will run this if you are manually
|
41
43
|
maintaining .externals
|
42
44
|
|
43
|
-
install Usage: ext install <repository[
|
45
|
+
install Usage: ext install <repository> [-b <branch>] [path]
|
44
46
|
Registers <repository> in .externals under the appropriate
|
45
47
|
SCM. Checks out the project, and also adds it to the ignore
|
46
|
-
feature offered by the SCM of the main project. If the SCM
|
47
|
-
is not obvious from the repository URL, use the --scm,
|
48
|
-
or --svn flags.
|
48
|
+
feature offered by the SCM of the main project. If the SCM
|
49
|
+
type is not obvious from the repository URL, use the --scm,
|
50
|
+
--git, or --svn flags.
|
49
51
|
|
50
52
|
init Creates a .externals file containing only [main]
|
51
53
|
It will try to determine the SCM used by the main project,
|
@@ -61,6 +63,9 @@ touch_emptydirs Recurses through all directories from the
|
|
61
63
|
|
62
64
|
help You probably just ran this command just now.
|
63
65
|
|
66
|
+
upgrade_externals_fileConverts the old format that stored
|
67
|
+
as [main][svn][git] to [<path1>][<path2>]...
|
68
|
+
|
64
69
|
|
65
70
|
|
66
71
|
Commands that apply to the main project and all subprojects:
|
@@ -93,14 +98,10 @@ co, ex, st, up
|
|
93
98
|
|
94
99
|
co Like checkout, but skips the main project and
|
95
100
|
only checks out subprojects.
|
96
|
-
|
97
101
|
ex Like export, but skips the main project.
|
98
|
-
|
99
102
|
st Like status, but skips the main project.
|
100
|
-
|
101
103
|
up Like update, but skips the main project.
|
102
104
|
|
103
|
-
|
104
105
|
The externals project is copyright 2008 by Miles Georgi, nopugs.com, azimux.com
|
105
106
|
and is released under the MIT license.
|
106
107
|
|
data/Rakefile
CHANGED
@@ -6,12 +6,12 @@ require 'rake/gempackagetask'
|
|
6
6
|
Rake::TestTask.new('test') do |task|
|
7
7
|
task.libs = [File.expand_path('lib'),File.expand_path('test')]
|
8
8
|
task.pattern = './test/test_*.rb'
|
9
|
-
task.warning = true
|
9
|
+
#task.warning = true
|
10
10
|
end
|
11
11
|
|
12
12
|
gem_specification = Gem::Specification.new do |specification|
|
13
13
|
specification.name = 'ext'
|
14
|
-
specification.version = '0.0
|
14
|
+
specification.version = '0.1.0'
|
15
15
|
specification.platform = Gem::Platform::RUBY
|
16
16
|
specification.rubyforge_project = 'ext'
|
17
17
|
|
File without changes
|
File without changes
|
@@ -1,78 +1,104 @@
|
|
1
1
|
module Externals
|
2
2
|
module Configuration
|
3
|
-
|
4
|
-
|
3
|
+
SECTION_TITLE_REGEX_NO_GROUPS = /^\s*\[(?:[^\]]*)\]\s*$/
|
4
|
+
SECTION_TITLE_REGEX = /^\s*\[([^\]]*)\]\s*$/
|
5
5
|
|
6
6
|
|
7
7
|
class Section
|
8
|
-
attr_accessor :title_string, :body_string, :title, :rows
|
8
|
+
attr_accessor :title_string, :body_string, :title, :rows
|
9
9
|
|
10
|
-
def
|
11
|
-
title == 'main'
|
12
|
-
end
|
13
|
-
|
14
|
-
def initialize title_string, body_string, scm = nil
|
10
|
+
def initialize title_string, body_string
|
15
11
|
self.title_string = title_string
|
16
12
|
self.body_string = body_string
|
17
|
-
self.scm = scm
|
18
13
|
|
19
14
|
self.title = SECTION_TITLE_REGEX.match(title_string)[1]
|
20
|
-
|
21
|
-
self.scm ||= self.title
|
22
15
|
|
23
16
|
raise "Invalid section title: #{title_string}" unless title
|
24
17
|
|
25
|
-
self.rows = body_string.split(/\n/)
|
18
|
+
self.rows = body_string.strip.split(/\n/)
|
26
19
|
end
|
27
20
|
|
28
|
-
def setting key
|
29
|
-
if !main?
|
30
|
-
raise "this isn't a section of the configuration that can contain settings"
|
31
|
-
end
|
32
21
|
|
22
|
+
SETTING_REGEX = /^\s*([\.\w_-]+)\s*=\s*([^#\n]*)(?:#[^\n]*)?$/
|
23
|
+
SET_SETTING_REGEX = /^(\s*(?:[\.\w_-]+)\s*=\s*)(?:[^#\n]*)(#[^\n]*)?$/
|
24
|
+
|
25
|
+
def attributes
|
26
|
+
retval = {}
|
33
27
|
rows.each do |row|
|
34
|
-
if row =~
|
28
|
+
if row =~ SETTING_REGEX
|
29
|
+
retval[$1.strip] = $2.strip
|
30
|
+
end
|
31
|
+
end
|
32
|
+
retval
|
33
|
+
end
|
34
|
+
def setting key
|
35
|
+
rows.each do |row|
|
36
|
+
if row =~ SETTING_REGEX && key.to_s == $1
|
35
37
|
return $2.strip
|
36
38
|
end
|
37
39
|
end
|
38
40
|
nil
|
39
41
|
end
|
42
|
+
def set_setting key, value
|
43
|
+
key = key.to_s
|
44
|
+
found = nil
|
45
|
+
|
46
|
+
rows.each_with_index do |row, index|
|
47
|
+
if row =~ SETTING_REGEX && key == $1
|
48
|
+
raise "found #{key} twice!" if found
|
49
|
+
found = index
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
if found
|
54
|
+
if rows[found] !~ SET_SETTING_REGEX
|
55
|
+
raise "thought I found the row, but didn't"
|
56
|
+
end
|
57
|
+
rows[found] = "#{$1}#{value}#{$2}"
|
58
|
+
else
|
59
|
+
rows << "#{key} = #{value}"
|
60
|
+
end
|
61
|
+
value
|
62
|
+
end
|
40
63
|
|
41
64
|
def [] key
|
42
65
|
setting(key)
|
43
66
|
end
|
67
|
+
def []= key, value
|
68
|
+
set_setting(key, value)
|
69
|
+
end
|
44
70
|
|
45
71
|
|
46
|
-
def projects
|
47
|
-
return @projects if @projects
|
48
|
-
|
49
|
-
@projects = []
|
50
|
-
|
51
|
-
if main?
|
52
|
-
@projects = [Ext.project_class(self['scm']).new(".", :is_main)]
|
53
|
-
else
|
54
|
-
rows.each do |row|
|
55
|
-
if Project.project_line?(row)
|
56
|
-
@projects << Ext.project_class(title).new(row)
|
57
|
-
end
|
58
|
-
end
|
59
|
-
@projects
|
60
|
-
end
|
61
|
-
end
|
72
|
+
# def projects
|
73
|
+
# return @projects if @projects
|
74
|
+
#
|
75
|
+
# @projects = []
|
76
|
+
#
|
77
|
+
# if main?
|
78
|
+
# @projects = [Ext.project_class(self['scm']).new(".", :is_main)]
|
79
|
+
# else
|
80
|
+
# rows.each do |row|
|
81
|
+
# if Project.project_line?(row)
|
82
|
+
# @projects << Ext.project_class(title).new(row)
|
83
|
+
# end
|
84
|
+
# end
|
85
|
+
# @projects
|
86
|
+
# end
|
87
|
+
# end
|
62
88
|
|
63
89
|
def add_row(row)
|
64
90
|
rows << row
|
65
91
|
|
66
92
|
self.body_string = body_string.chomp + "\n#{row}\n"
|
67
|
-
clear_caches
|
93
|
+
#clear_caches
|
68
94
|
end
|
69
95
|
|
70
|
-
def clear_caches
|
71
|
-
@projects = nil
|
72
|
-
end
|
96
|
+
# def clear_caches
|
97
|
+
# @projects = nil
|
98
|
+
# end
|
73
99
|
|
74
100
|
def to_s
|
75
|
-
"#{
|
101
|
+
"[#{title}]\n#{rows.join("\n")}"
|
76
102
|
end
|
77
103
|
end
|
78
104
|
|
@@ -88,33 +114,39 @@ module Externals
|
|
88
114
|
sections.detect {|section| section.title == title}
|
89
115
|
end
|
90
116
|
|
117
|
+
def []= title, hash
|
118
|
+
add_empty_section title
|
119
|
+
section = self[title]
|
120
|
+
hash.each_pair do |key,value|
|
121
|
+
section[key] = value
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
91
125
|
def add_empty_section title
|
92
126
|
raise "Section already exists" if self[title]
|
93
|
-
sections << Section.new("
|
127
|
+
sections << Section.new("[#{title.to_s}]", "")
|
94
128
|
end
|
95
|
-
|
129
|
+
|
96
130
|
def self.new_empty
|
97
131
|
new nil, true
|
98
132
|
end
|
99
133
|
|
100
|
-
def initialize
|
101
|
-
|
102
|
-
self.file_string = ''
|
103
|
-
return
|
104
|
-
end
|
105
|
-
|
106
|
-
if !externals_file && File.exists?('.externals')
|
107
|
-
open('.externals', 'r') do |f|
|
108
|
-
externals_file = f.read
|
109
|
-
end
|
110
|
-
end
|
134
|
+
def initialize file_string = nil, empty = false
|
135
|
+
self.file_string = file_string
|
111
136
|
|
112
|
-
|
137
|
+
return if empty
|
138
|
+
raise "I was given no file_string" unless file_string
|
113
139
|
|
114
|
-
|
140
|
+
# if !externals_file && File.exists?('.externals')
|
141
|
+
# open('.externals', 'r') do |f|
|
142
|
+
# externals_file = f.read
|
143
|
+
# end
|
144
|
+
# end
|
115
145
|
|
116
|
-
|
117
|
-
|
146
|
+
#externals_file ||= ""
|
147
|
+
|
148
|
+
titles = file_string.grep SECTION_TITLE_REGEX
|
149
|
+
bodies = file_string.split SECTION_TITLE_REGEX_NO_GROUPS
|
118
150
|
|
119
151
|
if titles.size > 0 && bodies.size > 0
|
120
152
|
if titles.size + 1 != bodies.size
|
@@ -129,31 +161,34 @@ module Externals
|
|
129
161
|
end
|
130
162
|
end
|
131
163
|
|
132
|
-
def projects
|
133
|
-
retval = []
|
134
|
-
sections.each do |section|
|
135
|
-
retval += section.projects
|
136
|
-
end
|
137
|
-
|
138
|
-
retval
|
139
|
-
end
|
140
|
-
|
141
|
-
def subprojects
|
142
|
-
retval = []
|
143
|
-
sections.each do |section|
|
144
|
-
retval += section.projects unless section.main?
|
145
|
-
end
|
146
|
-
|
147
|
-
retval
|
148
|
-
end
|
149
|
-
|
150
|
-
def write path = ".externals"
|
164
|
+
# def projects
|
165
|
+
# retval = []
|
166
|
+
# sections.each do |section|
|
167
|
+
# retval += section.projects
|
168
|
+
# end
|
169
|
+
#
|
170
|
+
# retval
|
171
|
+
# end
|
172
|
+
|
173
|
+
# def subprojects
|
174
|
+
# retval = []
|
175
|
+
# sections.each do |section|
|
176
|
+
# retval += section.projects unless section.main?
|
177
|
+
# end
|
178
|
+
#
|
179
|
+
# retval
|
180
|
+
# end
|
181
|
+
|
182
|
+
def write path # = ".externals"
|
183
|
+
raise "no path given" unless path
|
151
184
|
open(path, 'w') do |f|
|
152
|
-
|
153
|
-
f.write section.to_s
|
154
|
-
end
|
185
|
+
f.write to_s
|
155
186
|
end
|
156
187
|
end
|
188
|
+
|
189
|
+
def to_s
|
190
|
+
sections.map(&:to_s).join("\n\n")
|
191
|
+
end
|
157
192
|
end
|
158
193
|
end
|
159
194
|
end
|
@@ -0,0 +1,166 @@
|
|
1
|
+
module Externals
|
2
|
+
module OldConfiguration
|
3
|
+
SECTION_TITLE_REGEX = /^\s*\[(\w+)\]\s*$/
|
4
|
+
SECTION_TITLE_REGEX_NO_GROUPS = /^\s*\[(?:\w+)\]\s*$/
|
5
|
+
|
6
|
+
|
7
|
+
class Section
|
8
|
+
attr_accessor :title_string, :body_string, :title, :rows, :scm
|
9
|
+
|
10
|
+
def main?
|
11
|
+
title == 'main'
|
12
|
+
end
|
13
|
+
|
14
|
+
def initialize title_string, body_string, scm = nil
|
15
|
+
self.title_string = title_string
|
16
|
+
self.body_string = body_string
|
17
|
+
self.scm = scm
|
18
|
+
|
19
|
+
self.title = SECTION_TITLE_REGEX.match(title_string)[1]
|
20
|
+
|
21
|
+
self.scm ||= self.title
|
22
|
+
|
23
|
+
raise "Invalid section title: #{title_string}" unless title
|
24
|
+
|
25
|
+
self.rows = body_string.split(/\n/)
|
26
|
+
end
|
27
|
+
|
28
|
+
def setting key
|
29
|
+
if !main?
|
30
|
+
raise "this isn't a section of the configuration that can contain settings"
|
31
|
+
end
|
32
|
+
|
33
|
+
rows.each do |row|
|
34
|
+
if row =~ /\s*(\w+)\s*=\s*([^#\n]*)(?:#[^\n])?$/ && key.to_s == $1
|
35
|
+
return $2.strip
|
36
|
+
end
|
37
|
+
end
|
38
|
+
nil
|
39
|
+
end
|
40
|
+
|
41
|
+
def [] key
|
42
|
+
setting(key)
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
def projects
|
47
|
+
return @projects if @projects
|
48
|
+
|
49
|
+
@projects = []
|
50
|
+
|
51
|
+
if main?
|
52
|
+
@projects = [Ext.old_project_class(self['scm']).new(".", :is_main)]
|
53
|
+
else
|
54
|
+
rows.each do |row|
|
55
|
+
if Project.project_line?(row)
|
56
|
+
@projects << Ext.old_project_class(title).new(row)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
@projects
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def add_row(row)
|
64
|
+
rows << row
|
65
|
+
|
66
|
+
self.body_string = body_string.chomp + "\n#{row}\n"
|
67
|
+
clear_caches
|
68
|
+
end
|
69
|
+
|
70
|
+
def clear_caches
|
71
|
+
@projects = nil
|
72
|
+
end
|
73
|
+
|
74
|
+
def to_s
|
75
|
+
"#{title_string}#{body_string}"
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
class Configuration
|
80
|
+
attr_accessor :file_string
|
81
|
+
|
82
|
+
def sections
|
83
|
+
@sections ||= []
|
84
|
+
end
|
85
|
+
|
86
|
+
def [] title
|
87
|
+
title = title.to_s
|
88
|
+
sections.detect {|section| section.title == title}
|
89
|
+
end
|
90
|
+
|
91
|
+
def add_empty_section title
|
92
|
+
raise "Section already exists" if self[title]
|
93
|
+
sections << Section.new("\n\n[#{title.to_s}]\n", "")
|
94
|
+
end
|
95
|
+
|
96
|
+
def self.new_empty
|
97
|
+
new nil, true
|
98
|
+
end
|
99
|
+
|
100
|
+
def initialize externals_file = nil, empty = false
|
101
|
+
if empty
|
102
|
+
self.file_string = ''
|
103
|
+
return
|
104
|
+
end
|
105
|
+
|
106
|
+
if !externals_file && File.exists?('.externals')
|
107
|
+
open('.externals', 'r') do |f|
|
108
|
+
externals_file = f.read
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
externals_file ||= ""
|
113
|
+
|
114
|
+
self.file_string = externals_file
|
115
|
+
|
116
|
+
titles = externals_file.grep SECTION_TITLE_REGEX
|
117
|
+
bodies = externals_file.split SECTION_TITLE_REGEX_NO_GROUPS
|
118
|
+
|
119
|
+
if titles.size > 0 && bodies.size > 0
|
120
|
+
if titles.size + 1 != bodies.size
|
121
|
+
raise "bodies and sections do not match up"
|
122
|
+
end
|
123
|
+
|
124
|
+
bodies = bodies[1..(bodies.size - 1)]
|
125
|
+
|
126
|
+
(0...(bodies.size)).each do |index|
|
127
|
+
sections << Section.new(titles[index], bodies[index])
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
def projects
|
133
|
+
retval = []
|
134
|
+
sections.each do |section|
|
135
|
+
retval += section.projects
|
136
|
+
end
|
137
|
+
|
138
|
+
retval
|
139
|
+
end
|
140
|
+
|
141
|
+
def subprojects
|
142
|
+
retval = []
|
143
|
+
sections.each do |section|
|
144
|
+
retval += section.projects unless section.main?
|
145
|
+
end
|
146
|
+
|
147
|
+
retval
|
148
|
+
end
|
149
|
+
|
150
|
+
def main_project
|
151
|
+
sections.each do |section|
|
152
|
+
return section.projects.first if section.main?
|
153
|
+
end
|
154
|
+
nil
|
155
|
+
end
|
156
|
+
|
157
|
+
def write path = ".externals"
|
158
|
+
open(path, 'w') do |f|
|
159
|
+
sections.each do |section|
|
160
|
+
f.write section.to_s
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|