vcs 0.3.0 → 0.4.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.
- data/NEWS +112 -0
- data/NEWS.FR +90 -0
- data/SPEC.dyn.yml +5 -5
- data/SPEC.gemspec +4 -4
- data/SPEC.yml +5 -1
- data/bin/vcs +6 -161
- data/bin/vcs-cvs +6 -7
- data/bin/vcs-prcs +6 -7
- data/bin/vcs-svn +6 -7
- data/lib/vcs/add.rb +21 -0
- data/lib/vcs/app.rb +129 -0
- data/lib/vcs/back.rb +36 -0
- data/lib/vcs/changelog.rb +68 -123
- data/lib/vcs/common_commit.rb +110 -0
- data/lib/vcs/conflict.rb +9 -3
- data/lib/vcs/cvs.rb +4 -7
- data/lib/vcs/delete.rb +21 -0
- data/lib/vcs/diff.rb +29 -9
- data/lib/vcs/diffstat.rb +3 -3
- data/lib/vcs/edit.rb +4 -5
- data/lib/vcs/environment.rb +59 -0
- data/lib/vcs/form.rb +97 -0
- data/lib/vcs/ignore.rb +26 -0
- data/lib/vcs/junk.rb +26 -0
- data/lib/vcs/last_changed_date.rb +7 -9
- data/lib/vcs/list.rb +71 -0
- data/lib/vcs/mail.rb +25 -20
- data/lib/vcs/message.rb +32 -62
- data/lib/vcs/news.rb +9 -10
- data/lib/vcs/opt_parse.rb +82 -0
- data/lib/vcs/revision.rb +1 -1
- data/lib/vcs/script.rb +12 -6
- data/lib/vcs/status.rb +77 -5
- data/lib/vcs/svn.rb +53 -13
- data/lib/vcs/url.rb +4 -8
- data/lib/vcs/vcs.rb +443 -58
- metadata +16 -7
- data/lib/vcs/mycommit.rb +0 -90
data/lib/vcs/revision.rb
CHANGED
data/lib/vcs/script.rb
CHANGED
@@ -1,19 +1,25 @@
|
|
1
1
|
# Author:: Nicolas Pouillard <ertai@lrde.epita.fr>.
|
2
2
|
# Copyright:: Copyright (c) 2005 LRDE. All rights reserved.
|
3
3
|
# License:: GNU General Public License (GPL).
|
4
|
-
# Revision:: $Id: script.rb
|
4
|
+
# Revision:: $Id: script.rb 261 2005-10-03 00:45:53Z pouill_n $
|
5
5
|
|
6
6
|
require 'vcs/vcs'
|
7
7
|
|
8
8
|
class Vcs
|
9
9
|
|
10
|
-
def script
|
10
|
+
def script ( files=[], options={} )
|
11
|
+
puts script!(files, options)
|
12
|
+
end
|
13
|
+
|
14
|
+
def script! ( files=[], options={} )
|
11
15
|
begin
|
12
|
-
eval(
|
16
|
+
eval(files.join(' '))
|
17
|
+
rescue SystemExit => ex
|
18
|
+
raise ex
|
13
19
|
rescue Exception => ex
|
14
|
-
|
15
|
-
|
20
|
+
logger.error { 'Vcs#script: during the client execution' }
|
21
|
+
logger.error { ex.long_pp }
|
16
22
|
end
|
17
23
|
end
|
18
24
|
|
19
|
-
end # class
|
25
|
+
end # class Vcs
|
data/lib/vcs/status.rb
CHANGED
@@ -3,15 +3,87 @@
|
|
3
3
|
# License:: GNU General Public License (GPL).
|
4
4
|
# Revision:: $Id$
|
5
5
|
|
6
|
+
require 'vcs/svn'
|
7
|
+
|
6
8
|
class Svn
|
7
9
|
|
8
|
-
|
9
|
-
|
10
|
+
class StatusEntry
|
11
|
+
attr_accessor :line, :file_st, :prop_st, :cpy, :file, :category, :comment
|
12
|
+
|
13
|
+
def initialize ( high_line, aString )
|
14
|
+
@high_line = high_line
|
15
|
+
m = /^(.)(.)(.)(.)(.\s*)(.*)$/.match(aString)
|
16
|
+
line, file_st, bl1, prop_st, cpy, bl2, file = m.to_a
|
17
|
+
@file = file.to_path
|
18
|
+
@file_st, @prop_st, @cpy = file_st[0], prop_st[0], cpy[0]
|
19
|
+
@category = Vcs.classify(@file, @file_st)
|
20
|
+
if @file_st == ??
|
21
|
+
@file_st = @@category_symbol[@category] || @file_st
|
22
|
+
end
|
23
|
+
@line = "#{@file_st.chr}#{bl1}#{prop_st}#{cpy}#{bl2}#{file}"
|
24
|
+
end
|
25
|
+
|
26
|
+
def colorize!
|
27
|
+
@line[0] = @high_line.color(@file_st.chr, *@@style[@file_st])
|
28
|
+
end
|
29
|
+
|
30
|
+
def to_s
|
31
|
+
@file.to_s
|
32
|
+
end
|
33
|
+
|
34
|
+
@@category_symbol ||=
|
35
|
+
{
|
36
|
+
:precious => ?+,
|
37
|
+
:unmask => ?\\,
|
38
|
+
:junk => ?,
|
39
|
+
}
|
40
|
+
|
41
|
+
@@style ||=
|
42
|
+
{
|
43
|
+
?A => [:GREEN],
|
44
|
+
?M => [:GREEN],
|
45
|
+
?\\ => [:YELLOW],
|
46
|
+
?, => [:YELLOW],
|
47
|
+
?+ => [:YELLOW],
|
48
|
+
?G => [:BLUE],
|
49
|
+
?X => [:BLUE],
|
50
|
+
?D => [:MAGENTA],
|
51
|
+
?R => [:MAGENTA],
|
52
|
+
?~ => [:RED],
|
53
|
+
?! => [:RED],
|
54
|
+
?? => [:BLINK, :RED],
|
55
|
+
?C => [:BLINK, :RED],
|
56
|
+
}
|
57
|
+
end # class StatusEntry
|
58
|
+
|
59
|
+
def status ( *args, &block )
|
60
|
+
return status_(*args) if block.nil?
|
61
|
+
result = PathList.new
|
62
|
+
status_(*args).each_line do |line|
|
10
63
|
next unless line =~ /^.{5} /
|
11
|
-
|
12
|
-
|
64
|
+
status_entry = StatusEntry.new(@h, line)
|
65
|
+
next if status_entry.category == :exclude
|
66
|
+
result << status_entry
|
67
|
+
end
|
68
|
+
result.sort_with_regex_list! Vcs.regex_list
|
69
|
+
result.each(&block)
|
70
|
+
end
|
71
|
+
|
72
|
+
def color_status! ( *args )
|
73
|
+
status(*args) do |status_entry|
|
74
|
+
status_entry.colorize!
|
75
|
+
puts status_entry.line
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def status! ( *args )
|
80
|
+
if color?
|
81
|
+
color_status!(*args)
|
82
|
+
else
|
83
|
+
status(*args) do |status_entry|
|
84
|
+
puts status_entry.line
|
85
|
+
end
|
13
86
|
end
|
14
87
|
end
|
15
|
-
protected :from_status
|
16
88
|
|
17
89
|
end # class Svn
|
data/lib/vcs/svn.rb
CHANGED
@@ -1,16 +1,7 @@
|
|
1
|
-
# Author::
|
2
|
-
# Copyright:: Copyright (c) 2004 LRDE. All rights reserved.
|
3
|
-
# License::
|
4
|
-
|
5
|
-
# $LastChangedBy: ertai $
|
6
|
-
# $Id: header 98 2004-09-29 12:07:43Z ertai $
|
7
|
-
|
8
|
-
require 'vcs/vcs'
|
9
|
-
|
10
|
-
CL = Pathname.new('ChangeLog')
|
11
|
-
ADD_CL = Pathname.new(',ChangeLog')
|
12
|
-
TMP_CL = Pathname.new(',,ChangeLog')
|
13
|
-
META = Pathname.new(',meta')
|
1
|
+
# Author:: Nicolas Pouillard <ertai@lrde.epita.fr>.
|
2
|
+
# Copyright:: Copyright (c) 2004, 2005 LRDE. All rights reserved.
|
3
|
+
# License:: GNU General Public License (GPL).
|
4
|
+
# Revision:: $Id: header 98 2004-09-29 12:07:43Z ertai $
|
14
5
|
|
15
6
|
class Svn < Vcs
|
16
7
|
|
@@ -19,6 +10,10 @@ class Svn < Vcs
|
|
19
10
|
|
20
11
|
def initialize ( aCmd='svn' )
|
21
12
|
super
|
13
|
+
@@svn_option_controller ||=
|
14
|
+
OptionController.new(Svn, @@options_specification +
|
15
|
+
Vcs.specific_options.to_a.join("\n"))
|
16
|
+
self.option_controller = @@svn_option_controller
|
22
17
|
end
|
23
18
|
|
24
19
|
%w[ blame cat cleanup copy export import list log merge mkdir move propedit
|
@@ -26,4 +21,49 @@ class Svn < Vcs
|
|
26
21
|
add_basic_method(m)
|
27
22
|
end
|
28
23
|
|
24
|
+
@@options_specification ||= "
|
25
|
+
--auto-props
|
26
|
+
--config-dir DIR
|
27
|
+
--diff-cmd CMD
|
28
|
+
--diff3-cmd CMD
|
29
|
+
--dry-run
|
30
|
+
--editor-cmd CMD
|
31
|
+
--encoding ENC
|
32
|
+
--extensions (-x) ARGS
|
33
|
+
--file (-F) FILENAME
|
34
|
+
--force
|
35
|
+
--force-log
|
36
|
+
--help (-h or -?)
|
37
|
+
--ignore-ancestry
|
38
|
+
--ignore-externals
|
39
|
+
--incremental
|
40
|
+
--limit NUM {Integer}
|
41
|
+
--message (-m) MESSAGE
|
42
|
+
--new ARG
|
43
|
+
--no-auth-cache
|
44
|
+
--no-auto-props
|
45
|
+
--no-diff-added
|
46
|
+
--no-diff-deleted
|
47
|
+
--no-ignore
|
48
|
+
--no-unlock
|
49
|
+
--non-interactive
|
50
|
+
--non-recursive (-N)
|
51
|
+
--notice-ancestry
|
52
|
+
--old ARG
|
53
|
+
--password PASS
|
54
|
+
--quiet (-q)
|
55
|
+
--recursive (-R)
|
56
|
+
--relocate FROM TO [PATH...]
|
57
|
+
--revision (-r) REV
|
58
|
+
--revprop
|
59
|
+
--show-updates (-u)
|
60
|
+
--stop-on-copy
|
61
|
+
--strict
|
62
|
+
--targets FILENAME
|
63
|
+
--username NAME
|
64
|
+
--verbose (-v)
|
65
|
+
--version
|
66
|
+
--xml
|
67
|
+
"
|
68
|
+
|
29
69
|
end # class Svn
|
data/lib/vcs/url.rb
CHANGED
@@ -1,16 +1,12 @@
|
|
1
1
|
# Author:: Nicolas Pouillard <ertai@lrde.epita.fr>.
|
2
2
|
# Copyright:: Copyright (c) 2004 LRDE. All rights reserved.
|
3
3
|
# License:: GNU General Public License (GPL).
|
4
|
-
# Revision:: $Id: url.rb
|
4
|
+
# Revision:: $Id: url.rb 236 2005-09-26 13:08:22Z pouill_n $
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
class Svn
|
6
|
+
class Vcs
|
9
7
|
|
10
8
|
def url! ( *args )
|
11
|
-
puts info.read[/^URL:\s+(.*)$/, 1]
|
9
|
+
puts info(*args).read[/^URL:\s+(.*)$/, 1]
|
12
10
|
end
|
13
11
|
|
14
|
-
|
15
|
-
|
16
|
-
end # class Svn
|
12
|
+
end # class Vcs
|
data/lib/vcs/vcs.rb
CHANGED
@@ -1,22 +1,42 @@
|
|
1
|
-
# Author::
|
2
|
-
# Copyright:: Copyright (c) 2004 LRDE. All rights reserved.
|
3
|
-
# License::
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
1
|
+
# Author:: Nicolas Pouillard <ertai@lrde.epita.fr>.
|
2
|
+
# Copyright:: Copyright (c) 2004, 2005 LRDE. All rights reserved.
|
3
|
+
# License:: GNU General Public License (GPL).
|
4
|
+
# Revision:: $Id: header 98 2004-09-29 12:07:43Z ertai $
|
5
|
+
|
6
|
+
require 'pathname'
|
7
|
+
lib = Pathname.new(__FILE__).dirname.parent
|
8
|
+
vendor = lib.parent + 'vendor'
|
9
|
+
unless defined? RubyEx
|
10
|
+
$CORE_EX_VENDORS ||= []
|
11
|
+
$CORE_EX_VENDORS << vendor
|
12
|
+
file = vendor + 'ruby_ex' + 'lib' + 'ruby_ex.rb'
|
13
|
+
if file.exist?
|
14
|
+
require file.to_s
|
15
|
+
else
|
16
|
+
require 'rubygems'
|
17
|
+
require_gem 'ruby_ex'
|
18
|
+
require 'ruby_ex'
|
19
|
+
end
|
20
|
+
end
|
21
|
+
lib.load_path!
|
22
|
+
RubyEx.import!
|
11
23
|
Commands.import!
|
12
24
|
Yaml::ChopHeader.import!
|
13
25
|
|
26
|
+
require 'logger'
|
27
|
+
require 'optparse'
|
28
|
+
require 'etc'
|
29
|
+
require 'ostruct'
|
30
|
+
ENV['LC_ALL'] = 'C'
|
31
|
+
|
32
|
+
unless defined? Vcs
|
33
|
+
|
14
34
|
# The abstract class for a Vcs wrapper.
|
15
35
|
# Conventions:
|
16
36
|
# example:
|
17
37
|
# svn checkout http://foo.bar/proj # alias
|
18
38
|
# vcs-svn checkout http://foo.bar/proj # wrapper
|
19
|
-
# vcs --vcs
|
39
|
+
# vcs --vcs svn checkout http://foo.bar/proj # manual
|
20
40
|
#
|
21
41
|
# checkout
|
22
42
|
# checkout_
|
@@ -24,6 +44,112 @@ Yaml::ChopHeader.import!
|
|
24
44
|
# checkout_!
|
25
45
|
#
|
26
46
|
class Vcs
|
47
|
+
@@version ||= '0.4.0'
|
48
|
+
@@user_conf ||= OpenStruct.new(
|
49
|
+
:exclude => [/^-/],
|
50
|
+
:unmask => [/^\\/],
|
51
|
+
:junk => [/^,/],
|
52
|
+
:precious => [/^(\+|\.vcs)/],
|
53
|
+
:color => :auto,
|
54
|
+
:sorting => [],
|
55
|
+
:sign => true
|
56
|
+
)
|
57
|
+
@@output_io_methods ||= %w[ print puts putc ] # FIXME and so ...
|
58
|
+
@@specific_options ||= Set.new
|
59
|
+
|
60
|
+
@@user_defined_categories ||= [:precious, :unmask, :exclude, :junk]
|
61
|
+
@@symbol_category ||=
|
62
|
+
{
|
63
|
+
?A => :add,
|
64
|
+
?C => :conflict,
|
65
|
+
?D => :delete,
|
66
|
+
?G => :merge,
|
67
|
+
?I => :ignore,
|
68
|
+
?M => :modify,
|
69
|
+
?R => :replace,
|
70
|
+
?X => :external,
|
71
|
+
?? => :unrecognize,
|
72
|
+
?! => :missing,
|
73
|
+
?~ => :obstruct,
|
74
|
+
}
|
75
|
+
@@categories ||= @@user_defined_categories + @@symbol_category.values
|
76
|
+
|
77
|
+
|
78
|
+
cattr_accessor :version
|
79
|
+
cattr_accessor :default
|
80
|
+
cattr_accessor :user_conf
|
81
|
+
cattr_accessor :output_io_methods
|
82
|
+
cattr_accessor :logger
|
83
|
+
cattr_accessor :specific_options
|
84
|
+
cattr_accessor :user_defined_categories
|
85
|
+
cattr_accessor :symbol_category
|
86
|
+
cattr_accessor :categories
|
87
|
+
class_inheritable_accessor :option_controller
|
88
|
+
|
89
|
+
|
90
|
+
class Logger < ::Logger
|
91
|
+
|
92
|
+
attr_accessor :color
|
93
|
+
|
94
|
+
def initialize ( *a, &b )
|
95
|
+
super
|
96
|
+
@high_line = HighLine.new
|
97
|
+
@color = false
|
98
|
+
end
|
99
|
+
|
100
|
+
def header ( progname, severity )
|
101
|
+
@@headers[[progname, severity]] ||= [
|
102
|
+
'[', 'vcs', ']', ' ', progname, severity, ':', ' '
|
103
|
+
].compact.map { |x| stylize x }.join
|
104
|
+
end
|
105
|
+
|
106
|
+
def mk_message ( severity, progname, msg )
|
107
|
+
progname += ': ' unless progname.nil? or progname.empty?
|
108
|
+
msg.inject([]) do |accu, line|
|
109
|
+
accu << header(progname, severity) << line.chomp << "\n"
|
110
|
+
end.join
|
111
|
+
end
|
112
|
+
|
113
|
+
if ::Logger.const_defined? :VERSION and ::Logger::VERSION >= '1.2.6'
|
114
|
+
def format_message(severity, timestamp, progname, msg)
|
115
|
+
mk_message(severity, progname, msg)
|
116
|
+
end
|
117
|
+
else
|
118
|
+
def format_message(severity, timestamp, msg, progname)
|
119
|
+
mk_message(severity, progname, msg)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
@@headers ||= {}
|
124
|
+
|
125
|
+
@@style =
|
126
|
+
{
|
127
|
+
:vcs => [:cyan],
|
128
|
+
:debug => [:magenta],
|
129
|
+
:info => [:green],
|
130
|
+
:warn => [:yellow],
|
131
|
+
:error => [:red],
|
132
|
+
:fatal => [:red, :blink],
|
133
|
+
:'[' => [:blue],
|
134
|
+
:']' => [:blue],
|
135
|
+
:':' => [:red],
|
136
|
+
}
|
137
|
+
|
138
|
+
def stylize ( aString )
|
139
|
+
aString = aString.downcase
|
140
|
+
if @color
|
141
|
+
@high_line.color(aString, *@@style[aString.to_sym])
|
142
|
+
else
|
143
|
+
aString
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
end # class Logger
|
148
|
+
|
149
|
+
self.logger = Logger.new(STDERR)
|
150
|
+
ENV['VCS_SEVERITY'] ||= 'info'
|
151
|
+
logger.level = Logger.const_get(ENV['VCS_SEVERITY'].upcase)
|
152
|
+
logger.color = STDERR.tty?
|
27
153
|
|
28
154
|
class Failure < Exception
|
29
155
|
end
|
@@ -32,61 +158,165 @@ class Vcs
|
|
32
158
|
|
33
159
|
attr_reader :out_io
|
34
160
|
|
35
|
-
def puts ( *a, &b )
|
36
|
-
@out_io.puts(*a, &b)
|
37
|
-
end
|
38
|
-
|
39
161
|
def output= ( anObject )
|
40
162
|
super
|
41
163
|
@out_io = @output.to_io_for_commands
|
42
164
|
end
|
43
165
|
|
166
|
+
def to_s
|
167
|
+
begin
|
168
|
+
@output.read
|
169
|
+
rescue IOError => ex
|
170
|
+
super
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
44
174
|
end # class VcsCmdData
|
45
|
-
|
46
|
-
class VcsCmdDataFactory < Commands::Datas::Factory
|
47
175
|
|
48
|
-
|
176
|
+
class VcsCmdDataFactory < Commands::Datas::Factory
|
49
177
|
|
50
178
|
def initialize ( values )
|
51
179
|
super
|
52
180
|
@command_data_class = VcsCmdData
|
53
|
-
@__instance = real_new_command_data
|
54
181
|
end
|
55
182
|
|
56
183
|
def new_command_data
|
184
|
+
@__instance ||= super
|
57
185
|
@__instance.status = nil
|
58
186
|
@__instance
|
59
187
|
end
|
60
188
|
|
61
189
|
end # class VcsCmdDataFactory
|
62
|
-
|
190
|
+
|
191
|
+
|
192
|
+
|
193
|
+
class Switch
|
194
|
+
cattr_reader :shortcuts
|
195
|
+
attr_reader :name, :shortcuts, :argument
|
196
|
+
|
197
|
+
@@re ||=
|
198
|
+
/^
|
199
|
+
\s*
|
200
|
+
--([\w-]+) # The option (--foo)
|
201
|
+
\s*
|
202
|
+
(?: \(
|
203
|
+
(-\w) # A shortcut (-f)
|
204
|
+
(?:\sor\s(-(?:\?|\w)))? # Another one (-f or -o)
|
205
|
+
\)
|
206
|
+
)?
|
207
|
+
\s*
|
208
|
+
(.*?) # An argument (--foo NUM)
|
209
|
+
\s*
|
210
|
+
(?:\{(.*)\})? # A type (--foo NUM {Integer})
|
211
|
+
$/x
|
212
|
+
|
213
|
+
def initialize ( aString )
|
214
|
+
match = @@re.match(aString)
|
215
|
+
raise "Cannot parse switch: `#{aString}'" if match.nil?
|
216
|
+
@name, @argument, @type = match[1], match[4], match[5]
|
217
|
+
@type = eval(@type) unless @type.nil?
|
218
|
+
@shortcuts = match[2..3].compact
|
219
|
+
end
|
220
|
+
|
221
|
+
def to_s
|
222
|
+
'--' + @name
|
223
|
+
end
|
224
|
+
|
225
|
+
def to_a_for_option_parser
|
226
|
+
argument = (@argument.nil? || @argument.empty?)? '' : ' ' + @argument
|
227
|
+
@shortcuts + ["--#@name#{argument}", @type].compact
|
228
|
+
end
|
229
|
+
|
230
|
+
def to_sym
|
231
|
+
@name.gsub('-', '_').to_sym
|
232
|
+
end
|
233
|
+
|
234
|
+
end # class Switch
|
235
|
+
|
236
|
+
|
237
|
+
|
238
|
+
class OptionController
|
239
|
+
|
240
|
+
attr_reader :switches, :shortcuts, :vcs_name, :option_parser, :options
|
241
|
+
protected :options
|
242
|
+
|
243
|
+
def initialize ( aVcsClass, aString )
|
244
|
+
Vcs.logger.debug { "Creating an option_controller for #{aVcsClass}..." }
|
245
|
+
@switches = []
|
246
|
+
@shortcuts = {}
|
247
|
+
aString.each_line do |line|
|
248
|
+
next if line.blank?
|
249
|
+
switch = Switch.new(line)
|
250
|
+
@switches << switch
|
251
|
+
switch.shortcuts.each do |shortcut|
|
252
|
+
@shortcuts[shortcut] = switch.name
|
253
|
+
end
|
254
|
+
end
|
255
|
+
@option_parser = OptionParser.new do |o|
|
256
|
+
o.banner = "Type '#{$0} help' for usage."
|
257
|
+
o.separator ''
|
258
|
+
@switches.each do |switch|
|
259
|
+
o.on(*switch.to_a_for_option_parser) do |a, *b|
|
260
|
+
raise unless b.empty?
|
261
|
+
options[switch.to_sym] = a
|
262
|
+
end
|
263
|
+
end
|
264
|
+
end
|
265
|
+
Vcs.logger.debug { @option_parser.to_s }
|
266
|
+
end
|
267
|
+
|
268
|
+
def parse ( argv )
|
269
|
+
@options = {}
|
270
|
+
[@options, @option_parser.parse(argv)]
|
271
|
+
end
|
272
|
+
|
273
|
+
def short_to_long ( short_option )
|
274
|
+
@shortcuts[short_option]
|
275
|
+
end
|
276
|
+
|
277
|
+
def to_strings ( options )
|
278
|
+
result = []
|
279
|
+
options.each do |k, v|
|
280
|
+
raise if v == false
|
281
|
+
result << '--' + k.to_s.gsub('_', '-')
|
282
|
+
result << v.to_s if v != true
|
283
|
+
end
|
284
|
+
result
|
285
|
+
end
|
286
|
+
|
287
|
+
end # class OptionController
|
288
|
+
|
289
|
+
|
63
290
|
def initialize ( aCmd )
|
64
291
|
@cmd = aCmd.to_cmd
|
65
|
-
@handlers = Set.new
|
66
292
|
@runner = Commands::Runners::System.new
|
67
293
|
@h = HighLine.new
|
68
294
|
self.cmd_data_factory = VcsCmdDataFactory.new(:output => STDOUT, :error => STDERR)
|
69
295
|
|
70
296
|
@runner.subscribe_hook(:failure) do |data|
|
71
297
|
if data.output == STDOUT
|
72
|
-
|
298
|
+
logger.debug { raise data.to_yaml }
|
73
299
|
exit((data.status)? data.status.exitstatus : 1)
|
74
300
|
else
|
75
301
|
raise data.to_yaml
|
76
302
|
end
|
77
303
|
end
|
78
304
|
@runner.subscribe_hook(:display_command) do |cmd|
|
79
|
-
|
305
|
+
logger.debug { "running: #{cmd.to_sh}" }
|
306
|
+
end
|
307
|
+
@runner.subscribe_hook(:before_exec) do
|
308
|
+
STDOUT.flush
|
309
|
+
STDERR.flush
|
80
310
|
end
|
81
311
|
end
|
82
312
|
|
83
313
|
def self.add_basic_method ( meth )
|
84
314
|
class_eval <<-end_eval
|
85
315
|
def #{meth}! ( *args )
|
86
|
-
|
316
|
+
run!("#{meth}", *args)
|
87
317
|
end
|
88
318
|
def #{meth}_! ( *args )
|
89
|
-
|
319
|
+
run!("#{meth}", *args)
|
90
320
|
end
|
91
321
|
end_eval
|
92
322
|
end
|
@@ -103,14 +333,18 @@ class Vcs
|
|
103
333
|
def #{m1} ( *args )
|
104
334
|
#{m2}(*args)
|
105
335
|
end
|
106
|
-
|
107
|
-
#{
|
336
|
+
unless method_defined? :#{m1}
|
337
|
+
def #{m1}_ ( *args )
|
338
|
+
#{m2}_(*args)
|
339
|
+
end
|
108
340
|
end
|
109
341
|
def #{m1}! ( *args )
|
110
342
|
#{m2}!(*args)
|
111
343
|
end
|
112
|
-
|
113
|
-
#{
|
344
|
+
unless method_defined? :#{m1}!
|
345
|
+
def #{m1}_! ( *args )
|
346
|
+
#{m2}_!(*args)
|
347
|
+
end
|
114
348
|
end
|
115
349
|
end_eval
|
116
350
|
end
|
@@ -126,29 +360,52 @@ class Vcs
|
|
126
360
|
|
127
361
|
attr_reader :cmd_data
|
128
362
|
|
363
|
+
def self.delegate_to_cmd_data ( *syms )
|
364
|
+
syms.flatten.each do |meth|
|
365
|
+
define_method(meth) do |*a|
|
366
|
+
raise if block_given?
|
367
|
+
@cmd_data.out_io.send(meth, *a)
|
368
|
+
end
|
369
|
+
end
|
370
|
+
end
|
371
|
+
|
372
|
+
delegate_to_cmd_data Vcs.output_io_methods
|
373
|
+
|
129
374
|
@@checkers = Set.new
|
375
|
+
OrderedHash.import!
|
376
|
+
@@handlers = OHash.new
|
130
377
|
|
131
|
-
def run! (
|
132
|
-
|
378
|
+
def run! ( command, files=[], options={} )
|
379
|
+
flush
|
380
|
+
cmd_options = option_controller.to_strings(options)
|
381
|
+
(@cmd + command + cmd_options + '--' + files).run(@runner)
|
133
382
|
end
|
134
383
|
|
135
|
-
def sub_vcs ( out, err )
|
384
|
+
def sub_vcs ( out, err, &block )
|
136
385
|
copy = self.class.new(@cmd)
|
137
386
|
copy.cmd_data_factory = VcsCmdDataFactory.new(:output => out, :error => err)
|
138
|
-
|
387
|
+
if block.nil?
|
388
|
+
copy
|
389
|
+
else
|
390
|
+
copy.instance_eval(&block)
|
391
|
+
end
|
139
392
|
end
|
140
393
|
|
141
|
-
def sub_vcs_with_name ( name )
|
142
|
-
sub_vcs(TempPath.new("#{name}-out"), TempPath.new("#{name}-err"))
|
394
|
+
def sub_vcs_with_name ( name, &block )
|
395
|
+
sub_vcs(TempPath.new("#{name}-out"), TempPath.new("#{name}-err"), &block)
|
143
396
|
end
|
144
397
|
|
145
|
-
def with ( io )
|
398
|
+
def with ( io, &block )
|
146
399
|
io.flush if io.respond_to? :flush
|
147
|
-
sub_vcs(io, io)
|
400
|
+
sub_vcs(io, io, &block)
|
401
|
+
end
|
402
|
+
|
403
|
+
def output
|
404
|
+
@cmd_data.out_io
|
148
405
|
end
|
149
406
|
|
150
|
-
def
|
151
|
-
|
407
|
+
def flush
|
408
|
+
output.flush
|
152
409
|
end
|
153
410
|
|
154
411
|
def run ( *args )
|
@@ -156,16 +413,29 @@ class Vcs
|
|
156
413
|
end
|
157
414
|
|
158
415
|
def run_missing! ( name, orig, *args )
|
159
|
-
return help!(*args) if name == '--help'
|
160
416
|
if name =~ /^(.*)_$/
|
161
417
|
run!($1, *args)
|
162
418
|
else
|
163
|
-
|
419
|
+
logger.warn { "unknown method #{orig}" }
|
164
420
|
run!(name, *args)
|
165
421
|
end
|
166
422
|
end
|
423
|
+
protected :run_missing!
|
167
424
|
|
168
|
-
|
425
|
+
def run_argv ( argv )
|
426
|
+
options, files = option_controller.parse(argv)
|
427
|
+
if files.empty?
|
428
|
+
options.delete(:help)
|
429
|
+
meth = :help!
|
430
|
+
else
|
431
|
+
meth = files.shift.dup
|
432
|
+
meth.sub!(/([^!])$/, '\1!') if meth != 'script'
|
433
|
+
end
|
434
|
+
logger.debug { "meth: #{meth}, files: #{files.inspect}, options: #{options.inspect}" }
|
435
|
+
send(meth, files, options)
|
436
|
+
end
|
437
|
+
|
438
|
+
%w[ checkout delete diff status log add update commit ].each do |m|
|
169
439
|
add_basic_method(m)
|
170
440
|
end
|
171
441
|
|
@@ -173,22 +443,58 @@ class Vcs
|
|
173
443
|
meth = meth.to_s
|
174
444
|
if meth =~ /^(.*)!$/
|
175
445
|
no_bang = $1
|
176
|
-
|
177
|
-
|
446
|
+
if respond_to? no_bang
|
447
|
+
puts send(no_bang, *args)
|
448
|
+
else
|
449
|
+
run_missing!(no_bang, meth, *args)
|
450
|
+
end
|
178
451
|
else
|
179
452
|
with_bang = meth + '!'
|
180
453
|
return run_missing!(meth, meth, *args) unless respond_to? with_bang
|
181
454
|
copy = sub_vcs_with_name(meth)
|
182
|
-
|
183
|
-
return res unless res.nil?
|
455
|
+
copy.send(with_bang, *args)
|
184
456
|
out = copy.cmd_data
|
185
|
-
out.out_io.
|
457
|
+
out.out_io.close
|
186
458
|
out
|
187
459
|
end
|
188
460
|
end
|
189
461
|
|
190
|
-
|
191
|
-
|
462
|
+
@@cache ||= {}
|
463
|
+
|
464
|
+
def with_cache ( path=nil, description=nil, &block )
|
465
|
+
loc = block.source_location # FIXME verify that this type of cache is working
|
466
|
+
return @@cache[loc].dup if @@cache.has_key? loc
|
467
|
+
unless path.nil?
|
468
|
+
if description.nil?
|
469
|
+
raise ArgumentError, "need a description for #{path}"
|
470
|
+
end
|
471
|
+
error_handling(path) do
|
472
|
+
logger.info "#{path}: Contains your #{description}" if path.exist?
|
473
|
+
end
|
474
|
+
end
|
475
|
+
if path.exist?
|
476
|
+
logger.info "#{path} already exists"
|
477
|
+
return path.read
|
478
|
+
end
|
479
|
+
begin
|
480
|
+
logger.info "Creating a new `#{path}' file ..."
|
481
|
+
path.open('w') { |f| result = with(f, &block) }
|
482
|
+
rescue Exception => ex
|
483
|
+
logger.error "Removing `#{path}' ..."
|
484
|
+
path.unlink
|
485
|
+
raise ex
|
486
|
+
end
|
487
|
+
path.read
|
488
|
+
end
|
489
|
+
protected :with_cache
|
490
|
+
|
491
|
+
def with_cache! ( *a, &b )
|
492
|
+
puts with_cache(*a, &b)
|
493
|
+
end
|
494
|
+
protected :with_cache!
|
495
|
+
|
496
|
+
def help! ( files=[], options={} )
|
497
|
+
return help_!(files, options) unless files.empty? and options.empty?
|
192
498
|
puts "usage: #{@cmd.command} <subcommand> [options] [args]
|
193
499
|
|Type '#{@cmd.command} help <subcommand>' for help on a specific subcommand.
|
194
500
|
|
|
@@ -198,7 +504,7 @@ class Vcs
|
|
198
504
|
|
|
199
505
|
|Available subcommands:".head_cut!
|
200
506
|
cmds = []
|
201
|
-
|
507
|
+
public_methods.each do |meth|
|
202
508
|
next if meth =~ /_!?$/
|
203
509
|
next unless meth =~ /^(.+)!$/
|
204
510
|
cmd = $1
|
@@ -217,6 +523,22 @@ class Vcs
|
|
217
523
|
end
|
218
524
|
end
|
219
525
|
|
526
|
+
def color?
|
527
|
+
Vcs.color? { output.tty? }
|
528
|
+
end
|
529
|
+
|
530
|
+
def color ( aString, *someStyles )
|
531
|
+
if color?
|
532
|
+
@h.color(aString, *someStyles)
|
533
|
+
else
|
534
|
+
aString
|
535
|
+
end
|
536
|
+
end
|
537
|
+
|
538
|
+
CL = Pathname.new('ChangeLog') unless defined? CL
|
539
|
+
TMP_CL = Pathname.new(',,ChangeLog') unless defined? TMP_CL
|
540
|
+
|
541
|
+
|
220
542
|
alias_command :ann, :blame
|
221
543
|
alias_command :annotate, :blame
|
222
544
|
alias_command :praise, :blame
|
@@ -260,20 +582,83 @@ class Vcs
|
|
260
582
|
alias_command :checkin, :commit
|
261
583
|
alias_command :populate, :add
|
262
584
|
|
263
|
-
def error_handling (
|
264
|
-
|
585
|
+
def error_handling ( meth_or_path, &block )
|
586
|
+
@@handlers[meth_or_path] = (block.nil?)? method(meth_or_path) : block
|
265
587
|
end
|
266
588
|
|
267
589
|
def call_handlers
|
268
|
-
|
269
|
-
end
|
270
|
-
|
271
|
-
def self.add_conf_checker ( meth )
|
272
|
-
@@checkers << meth
|
590
|
+
@@handlers.each { |k, v| (v.arity.abs == 1)? v[k] : v[] }
|
273
591
|
end
|
274
592
|
|
275
593
|
def call_conf_checkers
|
276
|
-
@@checkers.each { |
|
594
|
+
@@checkers.each { |x| (x.is_a? Proc)? x[] : send(x) }
|
277
595
|
end
|
278
596
|
|
597
|
+
class << self
|
598
|
+
|
599
|
+
def add_conf_checker ( meth=nil, &block )
|
600
|
+
@@checkers << (block.nil?)? meth : block
|
601
|
+
end
|
602
|
+
|
603
|
+
def user_conf_match ( sym, file )
|
604
|
+
if user_conf.nil? or (regexps = user_conf.send(sym)).nil?
|
605
|
+
return false
|
606
|
+
end
|
607
|
+
regexps.each do |re|
|
608
|
+
return true if re.match(file) or re.match(file.basename)
|
609
|
+
end
|
610
|
+
return false
|
611
|
+
end
|
612
|
+
|
613
|
+
def classify ( file, status=nil )
|
614
|
+
if status and category = Vcs.symbol_category[status]
|
615
|
+
return category unless category == :unrecognize
|
616
|
+
end
|
617
|
+
Vcs.user_defined_categories.each do |category|
|
618
|
+
return category if Vcs.user_conf_match(category, file)
|
619
|
+
end
|
620
|
+
return :unrecognize
|
621
|
+
end
|
622
|
+
|
623
|
+
def color? ( &auto_block )
|
624
|
+
case color = Vcs.user_conf.color
|
625
|
+
when :never then return false
|
626
|
+
when :auto then return (auto_block.nil?)? false : auto_block[]
|
627
|
+
when :always then return true
|
628
|
+
else raise ArgumentError, "Bad value for `color' (#{color})"
|
629
|
+
end
|
630
|
+
end
|
631
|
+
|
632
|
+
def regex_list
|
633
|
+
@@regex_list ||= RegexList.new(user_conf.sorting)
|
634
|
+
end
|
635
|
+
|
636
|
+
def merge_user_conf ( conf )
|
637
|
+
conf = YAML.load(conf.read) if conf.is_a? Pathname
|
638
|
+
conf.each do |k, v|
|
639
|
+
v = v.to_sym if v.is_a? String
|
640
|
+
user_conf.send("#{k}=", (v.is_a? Array)? ((user_conf.send(k) || []) + v) : v)
|
641
|
+
end
|
642
|
+
end
|
643
|
+
|
644
|
+
# Here we can handle version conflicts with vcs extensions
|
645
|
+
def protocol_version ( aVersion )
|
646
|
+
if aVersion != '0.1'
|
647
|
+
raise ArgumentError, "Bad protocol version #{aVersion} but 0.1 is needed"
|
648
|
+
end
|
649
|
+
end
|
650
|
+
|
651
|
+
# Set the given method as default commit action, use commit_ for the old one
|
652
|
+
# This method can be called just once to avoid conflicts
|
653
|
+
def default_commit ( meth )
|
654
|
+
just_once do
|
655
|
+
alias_command :commit, meth
|
656
|
+
alias_command :ci, meth
|
657
|
+
end
|
658
|
+
end
|
659
|
+
|
660
|
+
end # class << self
|
661
|
+
|
279
662
|
end # class Vcs
|
663
|
+
|
664
|
+
end
|