vcs 0.3.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- 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/bin/vcs-prcs
CHANGED
@@ -1,10 +1,9 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
-
# Author
|
3
|
-
# Copyright
|
4
|
-
# License
|
2
|
+
# Author:: Nicolas Pouillard <ertai@lrde.epita.fr>.
|
3
|
+
# Copyright:: Copyright (c) 2004 LRDE. All rights reserved.
|
4
|
+
# License:: GNU General Public License (GPL).
|
5
|
+
# Revision:: $Id$
|
5
6
|
|
6
|
-
|
7
|
-
# $Id: header 98 2004-09-29 12:07:43Z ertai $
|
7
|
+
require File.join(File.dirname(__FILE__), '..', 'lib', 'vcs', 'app') unless defined? VcsApp
|
8
8
|
|
9
|
-
|
10
|
-
exec('vcs', '--vcs', VCS, '--', *ARGV)
|
9
|
+
VcsApp.new(__FILE__, :prcs).run
|
data/bin/vcs-svn
CHANGED
@@ -1,10 +1,9 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
-
# Author
|
3
|
-
# Copyright
|
4
|
-
# License
|
2
|
+
# Author:: Nicolas Pouillard <ertai@lrde.epita.fr>.
|
3
|
+
# Copyright:: Copyright (c) 2004 LRDE. All rights reserved.
|
4
|
+
# License:: GNU General Public License (GPL).
|
5
|
+
# Revision:: $Id$
|
5
6
|
|
6
|
-
|
7
|
-
# $Id: header 98 2004-09-29 12:07:43Z ertai $
|
7
|
+
require File.join(File.dirname(__FILE__), '..', 'lib', 'vcs', 'app') unless defined? VcsApp
|
8
8
|
|
9
|
-
|
10
|
-
exec('vcs', '--vcs', VCS, '--', *ARGV)
|
9
|
+
VcsApp.new(__FILE__, :svn).run
|
data/lib/vcs/add.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# Copyright:: Copyright (c) 2005 LRDE. All rights reserved.
|
2
|
+
# Author:: Nicolas Pouillard <ertai@lrde.epita.fr>.
|
3
|
+
# License:: Gnu General Public License.
|
4
|
+
# Revision:: $Id: add.rb 265 2005-10-03 12:37:03Z pouill_n $
|
5
|
+
|
6
|
+
class Vcs
|
7
|
+
|
8
|
+
specific_options << '--auto'
|
9
|
+
|
10
|
+
def add! ( files=[], options={} )
|
11
|
+
if options[:auto]
|
12
|
+
options.delete(:auto)
|
13
|
+
list!(files, :unrecognize => true) do |path_list|
|
14
|
+
add_!(path_list.stringify, options) unless path_list.empty?
|
15
|
+
end
|
16
|
+
else
|
17
|
+
add_!(files, options)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
end # class Vcs
|
data/lib/vcs/app.rb
ADDED
@@ -0,0 +1,129 @@
|
|
1
|
+
# Copyright:: Copyright (c) 2005 LRDE. All rights reserved.
|
2
|
+
# Author:: Nicolas Pouillard <ertai@lrde.epita.fr>.
|
3
|
+
# License:: Gnu General Public License.
|
4
|
+
# Revision:: $Id: app.rb 261 2005-10-03 00:45:53Z pouill_n $
|
5
|
+
|
6
|
+
require 'pathname'
|
7
|
+
|
8
|
+
# vcs: The version control system wrapper.
|
9
|
+
#
|
10
|
+
# Vcs is a wrapper over any version control system.
|
11
|
+
class VcsApp
|
12
|
+
|
13
|
+
@@vcs_dir ||= Pathname.new(__FILE__).expand_path.dirname
|
14
|
+
@@dir ||= @@vcs_dir.parent
|
15
|
+
@@extension_dirs ||= []
|
16
|
+
|
17
|
+
require @@vcs_dir + 'vcs' unless defined? Vcs
|
18
|
+
|
19
|
+
@@dir.load_path!
|
20
|
+
|
21
|
+
cattr_accessor :vcs_dir
|
22
|
+
cattr_accessor :dir
|
23
|
+
cattr_accessor :extension_dirs
|
24
|
+
cattr_accessor :path
|
25
|
+
cattr_accessor :logger
|
26
|
+
self.logger = Vcs.logger
|
27
|
+
|
28
|
+
class << self
|
29
|
+
|
30
|
+
def requirements
|
31
|
+
Pathname.glob("{#{vcs_dir},#{extension_dirs.join(',')}}/*.rb") do |file|
|
32
|
+
next if file.to_s =~ /\/(app|opt_parse|vcs)\.rb$/
|
33
|
+
logger.debug { file.basename.to_s } if require file.to_s
|
34
|
+
end
|
35
|
+
grab_all_vcs()
|
36
|
+
end
|
37
|
+
|
38
|
+
def grab_all_vcs
|
39
|
+
@@all_vcs ||= {}
|
40
|
+
|
41
|
+
if @@all_vcs.empty?
|
42
|
+
ObjectSpace.each_object(Class) do |aClass|
|
43
|
+
if aClass != Vcs and aClass.ancestors.include? Vcs
|
44
|
+
name = aClass.to_s.demodulize.underscore.to_sym
|
45
|
+
@@all_vcs[name] = aClass
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def all_vcs
|
52
|
+
@@all_vcs.keys
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
requirements()
|
58
|
+
require 'vcs/opt_parse'
|
59
|
+
@@parser = Vcs::OptParse.new
|
60
|
+
|
61
|
+
def initialize ( __file__, vcs_type=nil )
|
62
|
+
@@path = __file__.to_path
|
63
|
+
Vcs.default ||= vcs_type
|
64
|
+
end
|
65
|
+
|
66
|
+
def grab_dirs ( basename, dir=Pathname.pwd )
|
67
|
+
results = []
|
68
|
+
while not dir.root?
|
69
|
+
path = dir + basename
|
70
|
+
results << path if path.exist?
|
71
|
+
dir = dir.parent
|
72
|
+
end
|
73
|
+
path = ENV['HOME'].to_path/basename
|
74
|
+
results << path if path.exist? and not results.include? path
|
75
|
+
results
|
76
|
+
end
|
77
|
+
|
78
|
+
def vcs_extensions_setup
|
79
|
+
grab_dirs('vcs').each do |vcs_dir|
|
80
|
+
vcs_dir = vcs_dir.expand_path
|
81
|
+
vcs_dir.load_path!
|
82
|
+
extension_dirs << vcs_dir
|
83
|
+
end
|
84
|
+
VcsApp.requirements()
|
85
|
+
end
|
86
|
+
|
87
|
+
def user_configuration_setup
|
88
|
+
grab_dirs('.vcs').each do |vcs_user_conf|
|
89
|
+
Vcs.merge_user_conf(vcs_user_conf)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def run
|
94
|
+
vcs = nil
|
95
|
+
begin
|
96
|
+
user_configuration_setup()
|
97
|
+
Vcs.logger.color = Vcs.color? { STDERR.tty? }
|
98
|
+
vcs_extensions_setup()
|
99
|
+
@@parser.parse! ARGV if Vcs.default.nil?
|
100
|
+
if Vcs.default.nil?
|
101
|
+
STDERR.puts @@parser
|
102
|
+
STDERR.puts "
|
103
|
+
|
|
104
|
+
|Specify at least a Vcs type, or use a wrapped command
|
105
|
+
|like svn, cvs, prcs in the vcs bin directory.
|
106
|
+
".head_cut!
|
107
|
+
exit
|
108
|
+
end
|
109
|
+
vcs = @@all_vcs[Vcs.default.to_s.downcase.to_sym].new
|
110
|
+
vcs.run_argv(ARGV)
|
111
|
+
|
112
|
+
rescue SystemExit => ex
|
113
|
+
raise ex
|
114
|
+
rescue Exception => ex
|
115
|
+
if vcs.nil?
|
116
|
+
logger.error { "No Vcs instanciated" }
|
117
|
+
else
|
118
|
+
vcs.call_handlers
|
119
|
+
end
|
120
|
+
err = ex.to_s.sub(/\.$/, '')
|
121
|
+
logger.debug { err = ex.long_pp ; "Backtrace enabled:" }
|
122
|
+
err = ex.inspect if err.empty?
|
123
|
+
logger.error { err }
|
124
|
+
exit 1
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
end # class VcsApp
|
129
|
+
|
data/lib/vcs/back.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
# Copyright:: Copyright (c) 2005 Nicolas Pouillard. All rights reserved.
|
2
|
+
# Author:: Nicolas Pouillard <ertai@lrde.epita.fr>.
|
3
|
+
# License:: Gnu General Public License.
|
4
|
+
# Revision:: $Id: back.rb 261 2005-10-03 00:45:53Z pouill_n $
|
5
|
+
|
6
|
+
class Vcs
|
7
|
+
# This command take a command as argument and search the last revision where
|
8
|
+
# this command success.
|
9
|
+
#
|
10
|
+
# Example:
|
11
|
+
# * this dummy example success only if the revision is equal to 0 modulo X
|
12
|
+
# * replace X by the success revision and Y by a greater revision
|
13
|
+
# vcs-svn back -r Y vcs-svn script 'exit(rev.read.to_i % X)'
|
14
|
+
def back! ( files=[], options={} )
|
15
|
+
sub_vcs = sub_vcs_with_name('checkout-4-vcs-back')
|
16
|
+
dir = TempPath.new('checkout-dir-4-vcs-back')
|
17
|
+
cmd = files.to_cmd
|
18
|
+
cmd.dir = dir
|
19
|
+
rev = options[:revision] || revision.read.chomp
|
20
|
+
raise ArgumentError, "Just integers are supported for revisions" if rev !~ /^\d+$/
|
21
|
+
rev = rev.to_i
|
22
|
+
target_url = url.read.chomp
|
23
|
+
while not rev.zero?
|
24
|
+
sub_vcs.checkout([target_url, dir], :quiet => true, :revision => rev)
|
25
|
+
data = cmd.system
|
26
|
+
data.display if options[:verbose]
|
27
|
+
if data.status.success?
|
28
|
+
logger.info { "Your command success on revision #{rev}"}
|
29
|
+
break
|
30
|
+
else
|
31
|
+
logger.warn { "Your command fail on revision #{rev}" }
|
32
|
+
end
|
33
|
+
rev -= 1
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end # class Vcs
|
data/lib/vcs/changelog.rb
CHANGED
@@ -1,164 +1,109 @@
|
|
1
1
|
# Author:: Nicolas Pouillard <ertai@lrde.epita.fr>.
|
2
|
-
# Copyright:: Copyright (c) 2004 LRDE. All rights reserved.
|
2
|
+
# Copyright:: Copyright (c) 2004, 2005 LRDE. All rights reserved.
|
3
3
|
# License:: GNU General Public License (GPL).
|
4
4
|
# Revision:: $Id: header 98 2004-09-29 12:07:43Z ertai $
|
5
5
|
|
6
|
-
require 'vcs/vcs'
|
7
|
-
require 'vcs/svn'
|
8
6
|
|
9
|
-
class
|
7
|
+
class Vcs
|
10
8
|
|
11
|
-
@@file_st
|
9
|
+
@@file_st ||=
|
12
10
|
{
|
13
|
-
|
14
|
-
|
11
|
+
?A => 'new',
|
12
|
+
?D => 'remove',
|
15
13
|
}
|
16
|
-
@@file_st.default = ''
|
17
14
|
|
18
|
-
@@prop_st
|
15
|
+
@@prop_st ||=
|
19
16
|
{
|
20
|
-
|
17
|
+
?M => 'changed property'
|
21
18
|
}
|
22
19
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
20
|
+
@@entries ||= {}
|
21
|
+
|
22
|
+
def mk_log_entry_contents ( *args )
|
23
|
+
return @@entries[args] if @@entries.has_key? args
|
24
|
+
@@entries[args] = result = []
|
25
|
+
status(*args) do |se|
|
26
|
+
next if se.file_st.chr =~ /[?X\\,+]/
|
27
|
+
next if se.file.to_s == 'ChangeLog'
|
28
|
+
ls = [@@file_st[se.file_st], @@prop_st[se.prop_st]].compact!
|
29
|
+
ls.first.capitalize! unless ls.empty?
|
30
|
+
se.comment = ls.join(', ')
|
31
|
+
result << se
|
32
32
|
end
|
33
33
|
raise Failure, 'No changes, so no ChangeLog entry.' if result.empty?
|
34
34
|
result
|
35
35
|
end
|
36
|
-
private :
|
37
|
-
|
38
|
-
end # class Svn
|
39
|
-
|
36
|
+
private :mk_log_entry_contents
|
40
37
|
|
41
|
-
class Vcs
|
42
38
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
39
|
+
# Same switches as status
|
40
|
+
def mk_log_entry! ( *args )
|
41
|
+
with_cache! LogEntry, 'Log entry' do
|
42
|
+
mk_log_entry_contents(*args).each do |se|
|
43
|
+
puts "- #{se.file}: #{se.comment}."
|
44
|
+
end
|
48
45
|
end
|
49
46
|
end
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
def
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
cl = ADD_CL
|
61
|
-
|
62
|
-
# Already filled if ,ChangeLog.add exists and not begin by ---
|
63
|
-
if cl.exist?
|
64
|
-
raise MustBeFilled, cl if cl.read =~ /\A---/
|
65
|
-
require 'erb'
|
66
|
-
ls = []
|
67
|
-
YAML.each_document("--- |\n" + cl.read) { |x| (ls.size == 2)? break : ls << x }
|
68
|
-
title_subject, input = ls
|
69
|
-
header = { 'title' => title_subject[/^title: (.*)$/, 1],
|
70
|
-
'subject' => title_subject[/^subject: (.*)$/, 1] }
|
71
|
-
rev = revision.read.to_i + 1
|
72
|
-
header.merge!('rev' => rev, 'revision' => rev)
|
73
|
-
raise "no title: reopen #{ADD_CL}" if header['title'].nil?
|
74
|
-
header['title'].sub!(/\.$/, '')
|
75
|
-
b = getBinding(header)
|
76
|
-
header = ERB.new(header.to_yaml, $SAFE, '<-%->', '$erbout_').result(b)
|
77
|
-
META.open('w') { |f| f.puts header }
|
78
|
-
output = ERB.new(input, $SAFE, '<-%->', '$erbout_').result(b)
|
79
|
-
return output
|
47
|
+
alias_command :mkl, :mk_log_entry
|
48
|
+
LogEntry = ',log'.to_path unless defined? LogEntry
|
49
|
+
|
50
|
+
def log_to_changelog ( aString )
|
51
|
+
if aString.blank?
|
52
|
+
puts
|
53
|
+
else
|
54
|
+
putc ?\t
|
55
|
+
aString.sub!(/^-/, '*')
|
56
|
+
puts aString
|
80
57
|
end
|
58
|
+
end
|
59
|
+
private :log_to_changelog
|
81
60
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|subject: #{@@subject_format}.
|
90
|
-
|
|
91
|
-
|--- | ###################### Your ChangeLog entrie ###################### | ---
|
92
|
-
|#{head}
|
93
|
-
|
|
94
|
-
|\t<%= title %>.
|
95
|
-
|
|
96
|
-
|".head_cut!
|
97
|
-
|
98
|
-
cl_add.each do |file, str|
|
99
|
-
f.puts "\t* #{file}: #{str}."
|
100
|
-
end
|
61
|
+
# Same switches as mk_log_entry
|
62
|
+
def mk_changelog_entry! ( *args )
|
63
|
+
puts Time.now.strftime("%Y-%m-%d #{Vcs.full_email}")
|
64
|
+
puts
|
65
|
+
mk_log_entry(*args).each_line(&method(:log_to_changelog))
|
66
|
+
end
|
67
|
+
alias_command :mkcl, :mk_changelog_entry
|
101
68
|
|
102
|
-
f.puts "|
|
103
|
-
|--- | ########### This line, and those below, will be ignored ########### | ---
|
104
|
-
|Instructions:
|
105
|
-
|\t* The first line must be removed when this file is filled.
|
106
|
-
|\t* After you must specify a title, for the news/mail subject.
|
107
|
-
|\t* The line containing <%= title %> will be replaced by your title,
|
108
|
-
|\t <%= subject %> by the subject line, <%= rev %> by the revision...
|
109
|
-
|\t* Everywhere in the document you can get/compute some values with
|
110
|
-
|\t these tags <%= aRubyExpression %> even some vcs specific call.
|
111
|
-
|\t For example <%= status.read %> will include the `svn status' output.
|
112
|
-
|
|
113
|
-
|".head_cut!
|
114
|
-
with(f).diff!(*args)
|
115
|
-
end
|
116
69
|
|
117
|
-
|
70
|
+
# Same switches as mk_log_entry
|
71
|
+
def mk_message_entry! ( *args )
|
72
|
+
puts 'Index: ChangeLog'
|
73
|
+
puts "from #{Vcs.full_email}"
|
74
|
+
puts
|
75
|
+
mk_log_entry(*args).each_line(&method(:log_to_changelog))
|
118
76
|
end
|
77
|
+
alias_command :mkml, :mk_message_entry
|
119
78
|
|
120
|
-
def concat_changelog! ( *args )
|
121
|
-
error_handling :changelog_failed
|
122
|
-
|
123
|
-
if cl_entry = mkchangelog(*args)
|
124
79
|
|
125
|
-
unless TMP_CL.exist?
|
126
|
-
LOG.info "Moving `#{CL}' to `#{TMP_CL}' ..."
|
127
|
-
CL.rename(TMP_CL)
|
128
|
-
end
|
129
80
|
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
file.puts
|
134
|
-
file.print TMP_CL.read
|
135
|
-
end
|
81
|
+
# Same switches as mk_changelog_entry
|
82
|
+
def concat_changelog! ( *args )
|
83
|
+
error_handling :concat_changelog_failed
|
136
84
|
|
137
|
-
|
85
|
+
unless TMP_CL.exist?
|
86
|
+
logger.info "Backup your `#{CL}' to `#{TMP_CL}' ..."
|
87
|
+
CL.rename(TMP_CL)
|
88
|
+
end
|
138
89
|
|
90
|
+
CL.open('w') do |file|
|
91
|
+
logger.info "#{CL}: Writing your new entry ..."
|
92
|
+
with(file).mk_changelog_entry!(*args)
|
93
|
+
file.puts
|
94
|
+
logger.info "#{CL}: Writing the others ..."
|
95
|
+
file.print TMP_CL.read
|
139
96
|
end
|
140
97
|
end
|
98
|
+
alias_command :catcl, :concat_changelog
|
141
99
|
|
142
|
-
def
|
100
|
+
def concat_changelog_failed
|
143
101
|
if TMP_CL.exist?
|
144
|
-
|
102
|
+
logger.info "Restoring `#{CL}' from `#{TMP_CL}' ..."
|
145
103
|
TMP_CL.rename(CL)
|
146
104
|
end
|
147
|
-
LOG.info "#{ADD_CL}: Contains your ChangeLog entry" if ADD_CL.exist?
|
148
|
-
end
|
149
|
-
|
150
|
-
def getBinding ( header )
|
151
|
-
code = []
|
152
|
-
header.each do |k, v|
|
153
|
-
code << "#{k} = #{v.inspect}"
|
154
|
-
end
|
155
|
-
code << 'binding'
|
156
|
-
eval(code.join('; '))
|
157
105
|
end
|
158
|
-
protected :getBinding
|
159
106
|
|
160
|
-
alias_command :mkcl, :mkchangelog
|
161
|
-
alias_command :ctcl, :concat_changelog
|
162
107
|
|
163
108
|
end # class Vcs
|
164
109
|
|