vcs 0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/HOWTO +41 -0
- data/Rakefile +59 -0
- data/TODO +19 -0
- data/bin/vcs +139 -0
- data/bin/vcs-cvs +10 -0
- data/bin/vcs-prcs +10 -0
- data/bin/vcs-svn +10 -0
- data/lrdetools.rb +12 -0
- data/src/ask.rb +101 -0
- data/src/changelog.rb +107 -0
- data/src/cvs.rb +21 -0
- data/src/diffstat.rb +36 -0
- data/src/mail.rb +83 -0
- data/src/message.rb +58 -0
- data/src/mycommit.rb +75 -0
- data/src/news.rb +97 -0
- data/src/prcs.rb +21 -0
- data/src/reply-mail.rb +14 -0
- data/src/revision.rb +19 -0
- data/src/svn.rb +31 -0
- data/src/tools.rb +22 -0
- data/src/vcs.rb +155 -0
- metadata +65 -0
data/HOWTO
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
---
|
2
|
+
|
3
|
+
|
4
|
+
|
5
|
+
Mini Vcs HOWTO:
|
6
|
+
|
7
|
+
- Install Vcs:
|
8
|
+
|
9
|
+
- From a package:
|
10
|
+
|
11
|
+
- Install rubygems: http://rubyforge.org/frs/?group_id=126
|
12
|
+
|
13
|
+
- Install Vcs (as root): gem install vcs
|
14
|
+
|
15
|
+
- From the svn repository:
|
16
|
+
|
17
|
+
- Find a place to install it:
|
18
|
+
cd ~/local
|
19
|
+
|
20
|
+
- Checkout Vcs:
|
21
|
+
svn co https://svn.lrde.epita.fr/svn/lrdetools/trunk/vcs
|
22
|
+
|
23
|
+
- Update your PATH:
|
24
|
+
export PATH=$PATH:~/local/vcs/bin
|
25
|
+
|
26
|
+
- If your shell is zsh: rehash
|
27
|
+
|
28
|
+
- Check Vcs:
|
29
|
+
vcs --help
|
30
|
+
|
31
|
+
- Make aliases:
|
32
|
+
`vcs --mk-alias` # Don't forget backquotes !
|
33
|
+
|
34
|
+
- Check the transparent mode:
|
35
|
+
svn status!
|
36
|
+
|
37
|
+
- Commit in lrdetools:
|
38
|
+
svn lrdetools_commit 'Your news subject'
|
39
|
+
- or:
|
40
|
+
svn ltci 'Your news subject'
|
41
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
require 'rake/testtask'
|
4
|
+
require 'rake/packagetask'
|
5
|
+
require 'rake/gempackagetask'
|
6
|
+
require 'rake/contrib/rubyforgepublisher'
|
7
|
+
|
8
|
+
PKG_VERSION = '0.1'
|
9
|
+
|
10
|
+
PKG_FILES = FileList[*%w"
|
11
|
+
src/**/*.rb
|
12
|
+
bin/**/*
|
13
|
+
*.rb
|
14
|
+
[A-Z]*
|
15
|
+
"].exclude(/\b\.svn\b|\..*\.sw[op]$|~$|README/)
|
16
|
+
|
17
|
+
desc 'Default Task'
|
18
|
+
task :default => :package
|
19
|
+
|
20
|
+
desc 'Publish to RubyForge'
|
21
|
+
task :rubyforge do
|
22
|
+
Rake::RubyForgePublisher.new('vcs', 'ertai').upload
|
23
|
+
end
|
24
|
+
|
25
|
+
# The Gem specification
|
26
|
+
spec = Gem::Specification.new do |s|
|
27
|
+
s.platform = Gem::Platform::RUBY
|
28
|
+
s.name = 'vcs'
|
29
|
+
s.version = PKG_VERSION
|
30
|
+
s.summary = 'A wrapper over any version control system'
|
31
|
+
s.description = '
|
32
|
+
Version control systems (Subversion, CVS, PRCS...), however useful,
|
33
|
+
are not very extensible: adding new features can be cumbersome, especially
|
34
|
+
if you want them for different such systems at once.
|
35
|
+
Vcs provide a simple dynamic hierarchy for Version Control Systems.
|
36
|
+
'
|
37
|
+
|
38
|
+
s.bindir = 'bin'
|
39
|
+
s.executables = %w[ vcs vcs-svn vcs-cvs vcs-prcs ]
|
40
|
+
s.default_executable = 'vcs'
|
41
|
+
s.files = PKG_FILES.to_a
|
42
|
+
s.require_path = 'src'
|
43
|
+
s.autorequire = 'vcs'
|
44
|
+
|
45
|
+
s.has_rdoc = false
|
46
|
+
s.author = 'Nicolas Pouillard'
|
47
|
+
s.email = 'ertai@lrde.epita.fr'
|
48
|
+
s.homepage = 'https://svn.lrde.epita.fr/svn/lrdetools/trunk/vcs/'
|
49
|
+
s.rubyforge_project = s.name
|
50
|
+
end
|
51
|
+
|
52
|
+
# Create compressed packages
|
53
|
+
Rake::GemPackageTask.new(spec) do |p|
|
54
|
+
p.gem_spec = spec
|
55
|
+
# p.need_tar = true
|
56
|
+
# p.need_zip = true
|
57
|
+
end
|
58
|
+
|
59
|
+
|
data/TODO
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
---
|
2
|
+
|
3
|
+
- add verification for ,message at commit beginning.
|
4
|
+
|
5
|
+
- |
|
6
|
+
AMHA mkcl devrait imposer une partie titre au ChangeLog.
|
7
|
+
|
8
|
+
2004- [...]
|
9
|
+
|
10
|
+
TITLE.
|
11
|
+
|
12
|
+
* Makefile.am[...]
|
13
|
+
[...]
|
14
|
+
|
15
|
+
|
16
|
+
puis utiliser ce TITLE au lieu de le demander ailleurs. Il devrait
|
17
|
+
exiger que TITLE ne soit pas trop long, et termine par un point.
|
18
|
+
|
19
|
+
- svn move avec les svn info | grep Copy des files du svn status
|
data/bin/vcs
ADDED
@@ -0,0 +1,139 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
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
|
+
|
6
|
+
# $LastChangedBy: ertai $
|
7
|
+
# $Id: header 98 2004-09-29 12:07:43Z ertai $
|
8
|
+
|
9
|
+
|
10
|
+
# vcs: The version control system wrapper.
|
11
|
+
#
|
12
|
+
# Vcs is a wrapper over any version control system.
|
13
|
+
|
14
|
+
require 'pathname'
|
15
|
+
require 'logger'
|
16
|
+
require 'optparse'
|
17
|
+
|
18
|
+
begin
|
19
|
+
REV="$Rev$".sub(/LastChangedRevision:\s+/, '').to_i
|
20
|
+
rescue
|
21
|
+
REV=-1
|
22
|
+
end
|
23
|
+
|
24
|
+
VCS_PATH = Pathname.new(__FILE__).expand_path
|
25
|
+
VCS_DIR, VCS = VCS_PATH.split
|
26
|
+
SRC = VCS_DIR + '..' + 'src'
|
27
|
+
$: << SRC.to_s
|
28
|
+
$: << Pathname.pwd + 'vcs'
|
29
|
+
|
30
|
+
LOG = Logger.new(STDOUT)
|
31
|
+
LOG.level = Logger::INFO
|
32
|
+
def LOG.format_message(severity, timestamp, msg, progname)
|
33
|
+
progname += ': ' unless progname.nil? or progname.empty?
|
34
|
+
"#{VCS}: #{progname}#{severity.downcase}: #{msg}\n"
|
35
|
+
end
|
36
|
+
|
37
|
+
$debug = ENV['VCS_DEBUG'].to_i
|
38
|
+
|
39
|
+
Pathname.glob("{#{SRC},vcs}/*.rb") do |file|
|
40
|
+
LOG.debug file.basename if $debug > 4
|
41
|
+
require file.basename
|
42
|
+
end
|
43
|
+
|
44
|
+
ALL_VCS_NAMES = []
|
45
|
+
ALL_VCS_BY_NAME = {}
|
46
|
+
ObjectSpace.each_object(Class) do |aClass|
|
47
|
+
if aClass != Vcs and aClass.ancestors.include? Vcs
|
48
|
+
name = aClass.to_s.to_sym
|
49
|
+
ALL_VCS_NAMES << name
|
50
|
+
ALL_VCS_BY_NAME[name] = aClass
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
OPTIONS = {}
|
55
|
+
|
56
|
+
OPTS = OptionParser.new do |opts|
|
57
|
+
|
58
|
+
opts.banner = "Usage: #{VCS} [options] <file>*"
|
59
|
+
opts.separator ''
|
60
|
+
|
61
|
+
opts.on('-c', '--vcs TYPE', ALL_VCS_NAMES, 'Set your vcs') do |aVcs|
|
62
|
+
OPTIONS[:vcs_type] = aVcs
|
63
|
+
end
|
64
|
+
|
65
|
+
opts.on('-l', '--vcs-list', 'List all vcs') do |aVcs|
|
66
|
+
STDERR.puts 'Vcs list:'
|
67
|
+
ALL_VCS_NAMES.each { |n| STDERR.puts " - #{n}" }
|
68
|
+
exit
|
69
|
+
end
|
70
|
+
|
71
|
+
opts.on('--mk-alias', 'Use this command like that `vcs --mk-alias`') do
|
72
|
+
ALL_VCS_NAMES.each do |n|
|
73
|
+
n = n.to_s.downcase
|
74
|
+
if VCS_PATH.executable?
|
75
|
+
puts "alias #{n}=#{VCS_PATH}-#{n}"
|
76
|
+
else
|
77
|
+
puts "alias #{n}=vcs-#{n}"
|
78
|
+
end
|
79
|
+
end
|
80
|
+
exit
|
81
|
+
end
|
82
|
+
|
83
|
+
opts.on('-d', '--debug LEVEL', Integer, 'Set debug level') do |anInteger|
|
84
|
+
$debug = anInteger
|
85
|
+
end
|
86
|
+
|
87
|
+
opts.on_tail('-h', '--help', 'Show this message') do |test|
|
88
|
+
STDERR.puts OPTS
|
89
|
+
exit
|
90
|
+
end
|
91
|
+
|
92
|
+
opts.on_tail('--version', 'Show version') do
|
93
|
+
STDOUT.puts "Vcs revision: #{REV}"
|
94
|
+
exit
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|
98
|
+
|
99
|
+
if ENV.has_key? 'FULLNAME'
|
100
|
+
FULLNAME = ENV['FULLNAME']
|
101
|
+
else
|
102
|
+
require 'etc'
|
103
|
+
ENV['FULLNAME'] = (Etc.getpwnam ENV['USER']).gecos
|
104
|
+
LOG.warn "Need FULLNAME in the environement (default: #{ENV['FULLNAME']})"
|
105
|
+
end
|
106
|
+
env = %w[ EMAIL FULLNAME EDITOR PAGER ]
|
107
|
+
if env.all? { |s| ENV[s] }
|
108
|
+
env.each { |s| Kernel.const_set(s, ENV[s]) }
|
109
|
+
else
|
110
|
+
env.each { |s| LOG.error "Need #{s} in the environement" unless ENV[s] }
|
111
|
+
exit
|
112
|
+
end
|
113
|
+
FULL_EMAIL = "#{FULLNAME} <#{EMAIL}>"
|
114
|
+
|
115
|
+
def main
|
116
|
+
OPTS.parse!(ARGV)
|
117
|
+
unless OPTIONS.has_key? :vcs_type
|
118
|
+
STDERR.puts OPTS
|
119
|
+
STDERR.puts "\nSpecify at least a Vcs type, or use a wrapped command\n" +
|
120
|
+
'like svn, cvs, prcs in the vcs bin directory.'
|
121
|
+
exit
|
122
|
+
end
|
123
|
+
vcs = ALL_VCS_BY_NAME[OPTIONS[:vcs_type]].new
|
124
|
+
|
125
|
+
if ARGV.empty?
|
126
|
+
meth = :help!
|
127
|
+
else
|
128
|
+
meth = ARGV.shift.sub(/([^!])$/, '\1!')
|
129
|
+
end
|
130
|
+
|
131
|
+
vcs.send(meth, *ARGV)
|
132
|
+
end
|
133
|
+
|
134
|
+
begin
|
135
|
+
main()
|
136
|
+
rescue Exception
|
137
|
+
raise if $debug > 0
|
138
|
+
LOG.error $!.to_s.sub(/\.$/, '') unless $!.to_s == 'exit'
|
139
|
+
end
|
data/bin/vcs-cvs
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
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
|
+
|
6
|
+
# $LastChangedBy: ertai $
|
7
|
+
# $Id: header 98 2004-09-29 12:07:43Z ertai $
|
8
|
+
|
9
|
+
VCS='Cvs'
|
10
|
+
exec("vcs --vcs #{VCS} -- '#{ARGV.join(%q[' '])}'")
|
data/bin/vcs-prcs
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
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
|
+
|
6
|
+
# $LastChangedBy: ertai $
|
7
|
+
# $Id: header 98 2004-09-29 12:07:43Z ertai $
|
8
|
+
|
9
|
+
VCS='Prcs'
|
10
|
+
exec('vcs', '--vcs', VCS, '--', *ARGV)
|
data/bin/vcs-svn
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
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
|
+
|
6
|
+
# $LastChangedBy: ertai $
|
7
|
+
# $Id: header 98 2004-09-29 12:07:43Z ertai $
|
8
|
+
|
9
|
+
VCS='Svn'
|
10
|
+
exec('vcs', '--vcs', VCS, '--', *ARGV)
|
data/lrdetools.rb
ADDED
data/src/ask.rb
ADDED
@@ -0,0 +1,101 @@
|
|
1
|
+
# Author:: Nicolas Pouillard <ertai@lrde.epita.fr>.
|
2
|
+
# Copyright:: Copyright (c) 2004 LRDE. All rights reserved.
|
3
|
+
# License:: GNU General Public License (GPL).
|
4
|
+
|
5
|
+
# $LastChangedBy: ertai $
|
6
|
+
# $Id: header 98 2004-09-29 12:07:43Z ertai $
|
7
|
+
|
8
|
+
ANSWERS = [ :y, :n ]
|
9
|
+
ANSWER_NOT_VALID = 'Not a valid answer, please answer correctly'
|
10
|
+
|
11
|
+
# `ask', ask the user to answer, to your question.
|
12
|
+
#
|
13
|
+
# Example:
|
14
|
+
# ask('Commiting, are you sure', :n)
|
15
|
+
#
|
16
|
+
# produce => Commiting, are you sure (y/N):
|
17
|
+
# and wait your answer.
|
18
|
+
def ask ( aQuestion, theDefaultAnswer=:y, cin=STDIN, cout=STDOUT, cerr=STDERR )
|
19
|
+
|
20
|
+
yn = case theDefaultAnswer
|
21
|
+
when :y then ' [Y/n]: '
|
22
|
+
when :n then ' [y/N]: '
|
23
|
+
else raise ArgumentError, "not valid default answer #{theDefaultAnswer}"
|
24
|
+
end
|
25
|
+
|
26
|
+
loop do
|
27
|
+
cout.print aQuestion, yn
|
28
|
+
cout.flush
|
29
|
+
|
30
|
+
answer = cin.readline.chomp.downcase
|
31
|
+
|
32
|
+
return theDefaultAnswer if answer.empty?
|
33
|
+
|
34
|
+
answer = answer.to_sym
|
35
|
+
|
36
|
+
return answer if ANSWERS.include? answer
|
37
|
+
|
38
|
+
cerr.puts ANSWER_NOT_VALID
|
39
|
+
cout.puts
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
if defined? TEST_MODE or $0 == __FILE__
|
45
|
+
|
46
|
+
require 'test/unit'
|
47
|
+
class AskTest < Test::Unit::TestCase
|
48
|
+
|
49
|
+
def ask_checker ( question, default, answer, ref, out, err )
|
50
|
+
require 'stringio'
|
51
|
+
cin, cout, cerr = StringIO.new, StringIO.new, StringIO.new
|
52
|
+
cin.puts answer
|
53
|
+
cin.rewind
|
54
|
+
res = ask(question, default, cin, cout, cerr)
|
55
|
+
cout.rewind
|
56
|
+
cerr.rewind
|
57
|
+
assert_equal(res, ref, 'bad return value')
|
58
|
+
assert_equal(cout.readlines.join, out, 'bad standard output')
|
59
|
+
assert_equal(cerr.readlines.join, err, 'bad error output')
|
60
|
+
end
|
61
|
+
|
62
|
+
def test_bad_default
|
63
|
+
assert_raise(ArgumentError) { ask_checker('Q', :foo, '', :y, [], []) }
|
64
|
+
assert_nothing_raised do
|
65
|
+
ask_checker('Q', :y, 'y', :y, 'Q [Y/n]: ', '')
|
66
|
+
end
|
67
|
+
assert_nothing_raised do
|
68
|
+
ask_checker('Q', :n, 'y', :y, 'Q [y/N]: ', '')
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def test_valid_default_yes
|
73
|
+
ask_checker('Q', :y, 'y', :y, 'Q [Y/n]: ', '')
|
74
|
+
ask_checker('Q', :y, 'Y', :y, 'Q [Y/n]: ', '')
|
75
|
+
ask_checker('Q', :y, 'n', :n, 'Q [Y/n]: ', '')
|
76
|
+
ask_checker('Q', :y, 'N', :n, 'Q [Y/n]: ', '')
|
77
|
+
ask_checker('Q', :y, '', :y, 'Q [Y/n]: ', '')
|
78
|
+
end
|
79
|
+
|
80
|
+
def test_valid_default_no
|
81
|
+
ask_checker('Q', :n, 'y', :y, 'Q [y/N]: ', '')
|
82
|
+
ask_checker('Q', :n, 'Y', :y, 'Q [y/N]: ', '')
|
83
|
+
ask_checker('Q', :n, 'n', :n, 'Q [y/N]: ', '')
|
84
|
+
ask_checker('Q', :n, 'N', :n, 'Q [y/N]: ', '')
|
85
|
+
ask_checker('Q', :n, '', :n, 'Q [y/N]: ', '')
|
86
|
+
end
|
87
|
+
|
88
|
+
def test_invalid_answer
|
89
|
+
ask_checker('Q', :n, "bad\ny", :y,
|
90
|
+
"Q [y/N]: \nQ [y/N]: ", ANSWER_NOT_VALID + "\n")
|
91
|
+
ask_checker('Q', :y, "ad\n\n", :y,
|
92
|
+
"Q [Y/n]: \nQ [Y/n]: ", ANSWER_NOT_VALID + "\n")
|
93
|
+
end
|
94
|
+
|
95
|
+
def test_ask1
|
96
|
+
ask_checker('Q', :y, 'y', :y, 'Q [Y/n]: ', '')
|
97
|
+
end
|
98
|
+
|
99
|
+
end # class AskTest
|
100
|
+
|
101
|
+
end
|
data/src/changelog.rb
ADDED
@@ -0,0 +1,107 @@
|
|
1
|
+
# Author:: Nicolas Pouillard <ertai@lrde.epita.fr>.
|
2
|
+
# Copyright:: Copyright (c) 2004 LRDE. All rights reserved.
|
3
|
+
# License:: GNU General Public License (GPL).
|
4
|
+
|
5
|
+
# $LastChangedBy: ertai $
|
6
|
+
# $Id: header 98 2004-09-29 12:07:43Z ertai $
|
7
|
+
|
8
|
+
require 'vcs'
|
9
|
+
require 'svn'
|
10
|
+
|
11
|
+
class Svn
|
12
|
+
|
13
|
+
@@file_st =
|
14
|
+
{
|
15
|
+
'A' => 'New',
|
16
|
+
'D' => 'Remove',
|
17
|
+
'M' => ''
|
18
|
+
}
|
19
|
+
|
20
|
+
@@prop_st =
|
21
|
+
{
|
22
|
+
'M' => 'Changed property'
|
23
|
+
}
|
24
|
+
|
25
|
+
def mkchangelog_from_status ( *args )
|
26
|
+
result = []
|
27
|
+
status(*args).each do |line|
|
28
|
+
next unless line =~ /^.{5} /
|
29
|
+
line =~ /^(.)(.).(.).\s*(.*)$/
|
30
|
+
if $1 != '?'
|
31
|
+
file_st, prop_st, copy_st, file = @@file_st[$1], @@prop_st[$2], $3, $4
|
32
|
+
str = ''
|
33
|
+
str += file_st if file_st
|
34
|
+
str += (file_st.nil?) ? prop_st : (', ' + prop_st.downcase) if prop_st
|
35
|
+
result << [file, str]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
raise Failure, 'No changes, so no ChangeLog entry.' if result.empty?
|
39
|
+
result
|
40
|
+
end
|
41
|
+
private :mkchangelog_from_status
|
42
|
+
|
43
|
+
end # class Svn
|
44
|
+
|
45
|
+
|
46
|
+
class Vcs
|
47
|
+
|
48
|
+
class MustBeFilled < Exception
|
49
|
+
attr_reader :file
|
50
|
+
def initialize ( file )
|
51
|
+
@file = file
|
52
|
+
super("You must fill this file: `#{file.to_s}'")
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def mkchangelog ( *args )
|
57
|
+
cl = ADD_CL
|
58
|
+
|
59
|
+
if cl.exist?
|
60
|
+
f = cl.open('r')
|
61
|
+
if f.readline !~ /^===/
|
62
|
+
f.rewind
|
63
|
+
return f
|
64
|
+
end
|
65
|
+
f.close
|
66
|
+
else
|
67
|
+
cl_add = mkchangelog_from_status(*args)
|
68
|
+
LOG.warn "Creating a new `#{cl}' file"
|
69
|
+
cl.open('w') do |f|
|
70
|
+
f.puts '=== Fill this file correctly and remove this line ==='
|
71
|
+
f.puts `date +"%Y-%m-%d #{FULL_EMAIL}"`
|
72
|
+
f.puts
|
73
|
+
cl_add.each do |file, str|
|
74
|
+
f.puts "\t* #{file}: #{str}."
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
raise MustBeFilled, cl
|
80
|
+
end
|
81
|
+
|
82
|
+
def changelog! ( *args )
|
83
|
+
unless CL.exist?
|
84
|
+
raise Failure, 'No ChangeLog, you are probably not in a valid directory.'
|
85
|
+
end
|
86
|
+
|
87
|
+
if cl = mkchangelog(*args)
|
88
|
+
|
89
|
+
unless TMP_CL.exist?
|
90
|
+
LOG.warn "Moving #{CL} to `#{TMP_CL}'"
|
91
|
+
CL.rename(TMP_CL)
|
92
|
+
end
|
93
|
+
|
94
|
+
CL.open('w') do |file|
|
95
|
+
cl.each { |line| file.print line }
|
96
|
+
file.puts
|
97
|
+
IO.foreach(TMP_CL) { |line| file.print line }
|
98
|
+
end
|
99
|
+
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
alias_command :mkcl, :mkchangelog
|
104
|
+
alias_command :cl, :changelog
|
105
|
+
|
106
|
+
end # class Vcs
|
107
|
+
|
data/src/cvs.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# Author:: Nicolas Pouillard <ertai@lrde.epita.fr>.
|
2
|
+
# Copyright:: Copyright (c) 2004 LRDE. All rights reserved.
|
3
|
+
# License:: GNU General Public License (GPL).
|
4
|
+
|
5
|
+
# $LastChangedBy: ertai $
|
6
|
+
# $Id: header 98 2004-09-29 12:07:43Z ertai $
|
7
|
+
|
8
|
+
require 'vcs'
|
9
|
+
|
10
|
+
class Cvs < Vcs
|
11
|
+
|
12
|
+
def initialize ( aCmd='cvs' )
|
13
|
+
super
|
14
|
+
end
|
15
|
+
|
16
|
+
%w[ rdiff rtag tag ].each do |m|
|
17
|
+
add_basic_method(m)
|
18
|
+
end
|
19
|
+
|
20
|
+
end # class Cvs
|
21
|
+
|
data/src/diffstat.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
# Author:: Nicolas Pouillard <ertai@lrde.epita.fr>.
|
2
|
+
# Copyright:: Copyright (c) 2004 LRDE. All rights reserved.
|
3
|
+
# License:: GNU General Public License (GPL).
|
4
|
+
|
5
|
+
# $LastChangedBy: ertai $
|
6
|
+
# $Id: header 98 2004-09-29 12:07:43Z ertai $
|
7
|
+
|
8
|
+
require 'vcs'
|
9
|
+
|
10
|
+
class Vcs
|
11
|
+
|
12
|
+
# Use the diffstat command to
|
13
|
+
# display statitics on your patch.
|
14
|
+
def diffstat ( *a )
|
15
|
+
unless `diffstat -V` =~ /diffstat version/
|
16
|
+
raise ArgumentError, 'The `diffstat\' tool is needed by Vcs.diffstat'
|
17
|
+
end
|
18
|
+
patch = diff(*a)
|
19
|
+
rd, wr = IO.pipe
|
20
|
+
pid = fork do
|
21
|
+
rd.close
|
22
|
+
STDIN.reopen(patch)
|
23
|
+
STDOUT.reopen(wr)
|
24
|
+
exec 'diffstat'
|
25
|
+
end
|
26
|
+
wr.close
|
27
|
+
def rd.close
|
28
|
+
super
|
29
|
+
Process.waitpid pid
|
30
|
+
end
|
31
|
+
rd
|
32
|
+
end
|
33
|
+
alias_command :ds, :diffstat
|
34
|
+
|
35
|
+
end # class Vcs
|
36
|
+
|
data/src/mail.rb
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
# Author:: Nicolas Pouillard <ertai@lrde.epita.fr>.
|
2
|
+
# Copyright:: Copyright (c) 2004 LRDE. All rights reserved.
|
3
|
+
# License:: GNU General Public License (GPL).
|
4
|
+
|
5
|
+
# $LastChangedBy: ertai $
|
6
|
+
# $Id: header 98 2004-09-29 12:07:43Z ertai $
|
7
|
+
|
8
|
+
require 'vcs'
|
9
|
+
require 'tools'
|
10
|
+
|
11
|
+
class Vcs
|
12
|
+
|
13
|
+
MAIL = Pathname.new(',mail')
|
14
|
+
|
15
|
+
def parse_mail_options ( *args )
|
16
|
+
require 'optparse'
|
17
|
+
result =
|
18
|
+
{
|
19
|
+
:from => FULL_EMAIL,
|
20
|
+
:to => [],
|
21
|
+
:server => ENV['SMTPSERVER'] || 'localhost',
|
22
|
+
}
|
23
|
+
if !args.nil? and !args.empty? and args[0].is_a?(Hash)
|
24
|
+
args[0].each do |k,v|
|
25
|
+
result[k] = v
|
26
|
+
end
|
27
|
+
return result
|
28
|
+
end
|
29
|
+
OptionParser.new do |opts|
|
30
|
+
opts.separator ''
|
31
|
+
opts.on('-t', '--mail-to NAME', 'Choose a recipient') do |aString|
|
32
|
+
result[:to] << aString
|
33
|
+
end
|
34
|
+
opts.on('-s', '--server NAME', 'Choose a mail server') do |aString|
|
35
|
+
result[:server] = aString
|
36
|
+
end
|
37
|
+
opts.on('-S', '--subject NAME', 'Choose your mail subject') do |aString|
|
38
|
+
result[:subject] = aString.sub(/\.?$/, '.')
|
39
|
+
end
|
40
|
+
opts.on_tail('-h', '--help', 'Show this message') do
|
41
|
+
puts opts
|
42
|
+
exit
|
43
|
+
end
|
44
|
+
end.parse!(args)
|
45
|
+
raise Failure, 'No recipents' if result[:to].empty?
|
46
|
+
raise Failure, 'No mail server' if result[:server].nil?
|
47
|
+
raise Failure, 'No mail subject' if result[:subject].nil?
|
48
|
+
result
|
49
|
+
end
|
50
|
+
protected :parse_mail_options
|
51
|
+
|
52
|
+
#
|
53
|
+
# Mail.
|
54
|
+
#
|
55
|
+
def mail ( *args )
|
56
|
+
|
57
|
+
print_body(MAIL, parse_mail_options(*args)) unless MAIL.exist?
|
58
|
+
|
59
|
+
MAIL.open('r') do |file|
|
60
|
+
opt = YAML::chop_header(file)
|
61
|
+
STDERR.puts "Smtp Server: #{opt[:server]}"
|
62
|
+
if ask("Send a mail, with this subject: #{opt[:subject]}\n" +
|
63
|
+
" to #{opt[:to].join(', ')}\n from #{opt[:from]}\n" +
|
64
|
+
'Are you sure?', :y) == :n
|
65
|
+
LOG.error 'Aborting'
|
66
|
+
exit
|
67
|
+
end
|
68
|
+
require 'net/smtp'
|
69
|
+
Net::SMTP.start(opt[:server], 25) do |smtp|
|
70
|
+
smtp.open_message_stream(EMAIL, opt[:to]) do |f|
|
71
|
+
f.print "From: #{opt[:from]}\n"
|
72
|
+
f.print "Subject: #{opt[:subject]}\n"
|
73
|
+
f.print "To: #{opt[:to].join(', ')}\n"
|
74
|
+
f.print "\n"
|
75
|
+
file.each { |line| f.print line }
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
MAIL.delete
|
80
|
+
StringIO.new('Mail: Sent.')
|
81
|
+
end
|
82
|
+
|
83
|
+
end # class Vcs
|
data/src/message.rb
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
# Author:: Nicolas Pouillard <ertai@lrde.epita.fr>.
|
2
|
+
# Copyright:: Copyright (c) 2004 LRDE. All rights reserved.
|
3
|
+
# License:: GNU General Public License (GPL).
|
4
|
+
|
5
|
+
# $LastChangedBy: ertai $
|
6
|
+
# $Id: header 98 2004-09-29 12:07:43Z ertai $
|
7
|
+
|
8
|
+
require 'vcs'
|
9
|
+
require 'changelog'
|
10
|
+
|
11
|
+
class Vcs
|
12
|
+
def diffw ( *args )
|
13
|
+
diff(*args)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class Svn
|
18
|
+
def diffw ( *args )
|
19
|
+
diff('--diff-cmd', 'diff', '-x', '-NPbuw', *args)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
class Vcs
|
24
|
+
|
25
|
+
@@message = Pathname.new(',message')
|
26
|
+
|
27
|
+
def print_body ( file, options )
|
28
|
+
LOG.warn "Creating a new `#{file}' file"
|
29
|
+
file.open('w') do |f|
|
30
|
+
f.puts options.to_yaml
|
31
|
+
f.puts '---'
|
32
|
+
f.puts
|
33
|
+
message.each do |line|
|
34
|
+
f.print line
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
private :print_body
|
39
|
+
|
40
|
+
def message ( *args )
|
41
|
+
unless @@message.exist?
|
42
|
+
cl = mkchangelog(*args)
|
43
|
+
@@message.open('w') do |f|
|
44
|
+
f.puts 'Index: ChangeLog'
|
45
|
+
cl.each { |line| f.print line.sub(/^\d+-\d+-\d+/, 'from') }
|
46
|
+
f.puts
|
47
|
+
# FIXME: need to remove the ChangeLog entry in diff.
|
48
|
+
diffstat(*args).each { |line| f.print line }
|
49
|
+
f.puts
|
50
|
+
diff(*args).each { |line| f.print line unless line =~ /^=+$/ }
|
51
|
+
end
|
52
|
+
end
|
53
|
+
@@message.open('r')
|
54
|
+
end
|
55
|
+
|
56
|
+
alias_command :msg, :message
|
57
|
+
|
58
|
+
end # class Vcs
|
data/src/mycommit.rb
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
# Author:: Nicolas Pouillard <ertai@lrde.epita.fr>.
|
2
|
+
# Copyright:: Copyright (c) 2004 LRDE. All rights reserved.
|
3
|
+
# License:: GNU General Public License (GPL).
|
4
|
+
|
5
|
+
# $LastChangedBy: ertai $
|
6
|
+
# $Id: header 98 2004-09-29 12:07:43Z ertai $
|
7
|
+
|
8
|
+
require 'vcs'
|
9
|
+
require 'ask'
|
10
|
+
|
11
|
+
class Vcs
|
12
|
+
|
13
|
+
def edit! ( *files )
|
14
|
+
system(ENV['EDITOR'], *files.map { |x| x.to_s })
|
15
|
+
end
|
16
|
+
|
17
|
+
def common_commit! ( *args, &block )
|
18
|
+
|
19
|
+
opts, args = args.partition { |a| a =~ /^-/ }
|
20
|
+
|
21
|
+
update!
|
22
|
+
|
23
|
+
unless @@message.exist?
|
24
|
+
|
25
|
+
begin
|
26
|
+
mkchangelog(*args)
|
27
|
+
rescue MustBeFilled => ex
|
28
|
+
edit! ex.file
|
29
|
+
end
|
30
|
+
|
31
|
+
message(*args)
|
32
|
+
|
33
|
+
edit! @@message
|
34
|
+
|
35
|
+
changelog!(*args)
|
36
|
+
|
37
|
+
#pager! diff
|
38
|
+
#pager! status
|
39
|
+
|
40
|
+
args << 'ChangeLog' unless args.grep(/^[^-]/).empty?
|
41
|
+
|
42
|
+
if ask('Committing, are you sure?', :y) == :n
|
43
|
+
@@message.unlink
|
44
|
+
LOG.error 'Aborting'
|
45
|
+
exit
|
46
|
+
end
|
47
|
+
|
48
|
+
if commit!('-F', ADD_CL, *(opts + args))
|
49
|
+
LOG.info 'Deleting junk files...'
|
50
|
+
ADD_CL.delete
|
51
|
+
TMP_CL.delete if TMP_CL.exist?
|
52
|
+
else
|
53
|
+
@@message.unlink
|
54
|
+
raise Failure, 'commit failed'
|
55
|
+
end
|
56
|
+
|
57
|
+
update!
|
58
|
+
|
59
|
+
end
|
60
|
+
|
61
|
+
rev = self.revision.readline.chomp.to_i
|
62
|
+
|
63
|
+
block.call(rev) if block_given?
|
64
|
+
|
65
|
+
messages = Pathname.new(',messages')
|
66
|
+
messages.mkpath unless messages.directory?
|
67
|
+
message_rev = messages + "#{@@message}.#{rev}"
|
68
|
+
LOG.info "Moving `#{@@message}' to `#{message_rev}'..."
|
69
|
+
@@message.rename(message_rev)
|
70
|
+
LOG.info "Remove `#{message_rev}' if everything is ok."
|
71
|
+
|
72
|
+
end
|
73
|
+
alias_command :cci, :common_commit
|
74
|
+
|
75
|
+
end # class Vcs
|
data/src/news.rb
ADDED
@@ -0,0 +1,97 @@
|
|
1
|
+
# Author:: Nicolas Pouillard <ertai@lrde.epita.fr>.
|
2
|
+
# Copyright:: Copyright (c) 2004 LRDE. All rights reserved.
|
3
|
+
# License:: GNU General Public License (GPL).
|
4
|
+
|
5
|
+
# $LastChangedBy: ertai $
|
6
|
+
# $Id: header 98 2004-09-29 12:07:43Z ertai $
|
7
|
+
|
8
|
+
require 'tools'
|
9
|
+
require 'message'
|
10
|
+
|
11
|
+
class Vcs
|
12
|
+
|
13
|
+
NEWS = Pathname.new(',news')
|
14
|
+
|
15
|
+
def parse_news_options ( *args )
|
16
|
+
require 'optparse'
|
17
|
+
result =
|
18
|
+
{
|
19
|
+
:from => FULL_EMAIL,
|
20
|
+
:groups => [],
|
21
|
+
:server => ENV['NNTPSERVER'],
|
22
|
+
}
|
23
|
+
if !args.nil? and !args.empty? and args[0].is_a?(Hash)
|
24
|
+
return result.merge!(args[0])
|
25
|
+
end
|
26
|
+
OptionParser.new do |opts|
|
27
|
+
opts.separator ''
|
28
|
+
opts.on('-g', '--group NAME', 'Choose a news group') do |aString|
|
29
|
+
result[:groups] << aString
|
30
|
+
end
|
31
|
+
opts.on('-s', '--server NAME', 'Choose a news server') do |aString|
|
32
|
+
result[:server] = aString
|
33
|
+
end
|
34
|
+
opts.on('-S', '--subject NAME', 'Choose your news subject') do |aString|
|
35
|
+
result[:subject] = aString
|
36
|
+
end
|
37
|
+
opts.on_tail('-h', '--help', 'Show this message') do
|
38
|
+
puts opts
|
39
|
+
exit
|
40
|
+
end
|
41
|
+
end.parse!(args)
|
42
|
+
raise Failure, 'No news group' if result[:groups].empty?
|
43
|
+
raise Failure, 'No news server' if result[:server].nil?
|
44
|
+
raise Failure, 'No news subject' if result[:subject].nil?
|
45
|
+
result
|
46
|
+
end
|
47
|
+
protected :parse_news_options
|
48
|
+
|
49
|
+
def check_line ( anIO, aRegex )
|
50
|
+
line = anIO.readline.chomp!
|
51
|
+
LOG.debug('news') { "Server: #{line}" }
|
52
|
+
unless line =~ aRegex
|
53
|
+
LOG.error('news') { "Bad answer: #{line}" }
|
54
|
+
@news_status = 'Error.'
|
55
|
+
end
|
56
|
+
end
|
57
|
+
private :check_line
|
58
|
+
|
59
|
+
#
|
60
|
+
# Post the news.
|
61
|
+
#
|
62
|
+
def news ( *args )
|
63
|
+
print_body(NEWS, parse_news_options(*args)) unless NEWS.exist?
|
64
|
+
|
65
|
+
@news_status = 'Sent.'
|
66
|
+
NEWS.open('r') do |file|
|
67
|
+
opt = YAML::chop_header(file)
|
68
|
+
LOG.info('news') { "Nntp Server: #{opt[:server]}" }
|
69
|
+
if ask("Post a news, with this subject: #{opt[:subject]}\n" +
|
70
|
+
" to #{opt[:groups].join(', ')}\n from #{opt[:from]}\n" +
|
71
|
+
'Are you sure?', :y) == :n
|
72
|
+
LOG.error('news') { 'Aborting' }
|
73
|
+
exit
|
74
|
+
end
|
75
|
+
require 'socket'
|
76
|
+
TCPSocket.open(opt[:server], 119) do |f|
|
77
|
+
check_line(f, /^200/)
|
78
|
+
f.puts 'post'
|
79
|
+
check_line(f, /^340/)
|
80
|
+
f.puts "Newsgroups: #{opt[:groups].join(', ')}"
|
81
|
+
f.puts "From: #{opt[:from]}"
|
82
|
+
f.puts "Subject: #{opt[:subject]}"
|
83
|
+
f.puts
|
84
|
+
file.each do |line|
|
85
|
+
f.print line.gsub(/^\./, ' .')
|
86
|
+
end
|
87
|
+
f.puts '.'
|
88
|
+
check_line(f, /^240/)
|
89
|
+
f.puts 'quit'
|
90
|
+
check_line(f, /^205/)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
NEWS.delete
|
94
|
+
StringIO.new(@news_status)
|
95
|
+
end
|
96
|
+
|
97
|
+
end # class Vcs
|
data/src/prcs.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# Author:: Nicolas Pouillard <ertai@lrde.epita.fr>.
|
2
|
+
# Copyright:: Copyright (c) 2004 LRDE. All rights reserved.
|
3
|
+
# License:: GNU General Public License (GPL).
|
4
|
+
|
5
|
+
# $LastChangedBy: ertai $
|
6
|
+
# $Id: header 98 2004-09-29 12:07:43Z ertai $
|
7
|
+
|
8
|
+
require 'vcs'
|
9
|
+
|
10
|
+
class Prcs < Vcs
|
11
|
+
|
12
|
+
def initialize ( aCmd='prcs' )
|
13
|
+
super
|
14
|
+
end
|
15
|
+
|
16
|
+
%w[ admin ].each do |m|
|
17
|
+
add_basic_method(m)
|
18
|
+
end
|
19
|
+
|
20
|
+
end # class Prcs
|
21
|
+
|
data/src/reply-mail.rb
ADDED
data/src/revision.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
# Author:: Nicolas Pouillard <ertai@lrde.epita.fr>.
|
2
|
+
# Copyright:: Copyright (c) 2004 LRDE. All rights reserved.
|
3
|
+
# License:: GNU General Public License (GPL).
|
4
|
+
|
5
|
+
# $LastChangedBy: ertai $
|
6
|
+
# $Id: header 98 2004-09-29 12:07:43Z ertai $
|
7
|
+
|
8
|
+
require 'svn'
|
9
|
+
require 'stringio'
|
10
|
+
|
11
|
+
class Svn
|
12
|
+
|
13
|
+
def revision ( *args )
|
14
|
+
StringIO.new(info.readlines.grep(/^Revision:/)[0].sub(/^Revision: /, ''))
|
15
|
+
end
|
16
|
+
|
17
|
+
alias_command :rev, :revision
|
18
|
+
|
19
|
+
end # class Svn
|
data/src/svn.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
# Author:: Nicolas Pouillard <ertai@lrde.epita.fr>.
|
2
|
+
# Copyright:: Copyright (c) 2004 LRDE. All rights reserved.
|
3
|
+
# License:: GNU General Public License (GPL).
|
4
|
+
|
5
|
+
# $LastChangedBy: ertai $
|
6
|
+
# $Id: header 98 2004-09-29 12:07:43Z ertai $
|
7
|
+
|
8
|
+
require 'vcs'
|
9
|
+
require 'tools'
|
10
|
+
|
11
|
+
CL = Pathname.new('ChangeLog')
|
12
|
+
ADD_CL = Pathname.new(',ChangeLog')
|
13
|
+
TMP_CL = Pathname.new(',,ChangeLog')
|
14
|
+
|
15
|
+
class Svn < Vcs
|
16
|
+
|
17
|
+
class Failure < Vcs::Failure
|
18
|
+
end
|
19
|
+
|
20
|
+
def initialize ( aCmd='svn' )
|
21
|
+
super
|
22
|
+
end
|
23
|
+
|
24
|
+
%w[ blame copy list move switch revert info
|
25
|
+
propdel propget proplist propset mkdir ].each do |m|
|
26
|
+
add_basic_method(m)
|
27
|
+
end
|
28
|
+
|
29
|
+
add_basic_method!(:propedit)
|
30
|
+
|
31
|
+
end # class Svn
|
data/src/tools.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# Author:: Nicolas Pouillard <ertai@lrde.epita.fr>.
|
2
|
+
# Copyright:: Copyright (c) 2004 LRDE. All rights reserved.
|
3
|
+
# License:: GNU General Public License (GPL).
|
4
|
+
|
5
|
+
# $LastChangedBy: ertai $
|
6
|
+
# $Id: header 98 2004-09-29 12:07:43Z ertai $
|
7
|
+
|
8
|
+
require 'yaml'
|
9
|
+
module YAML
|
10
|
+
|
11
|
+
def self.chop_header ( io )
|
12
|
+
aStr = io.gets
|
13
|
+
raise Exception, "First line is not valid: `#{aLine}'" unless aStr =~ /^---/
|
14
|
+
io.each do |aLine|
|
15
|
+
break if aLine =~ /^---/
|
16
|
+
aStr += aLine
|
17
|
+
end
|
18
|
+
YAML::load(aStr)
|
19
|
+
end
|
20
|
+
|
21
|
+
end # module YAML
|
22
|
+
|
data/src/vcs.rb
ADDED
@@ -0,0 +1,155 @@
|
|
1
|
+
# Author:: Nicolas Pouillard <ertai@lrde.epita.fr>.
|
2
|
+
# Copyright:: Copyright (c) 2004 LRDE. All rights reserved.
|
3
|
+
# License:: GNU General Public License (GPL).
|
4
|
+
|
5
|
+
# $LastChangedBy: ertai $
|
6
|
+
# $Id: header 98 2004-09-29 12:07:43Z ertai $
|
7
|
+
|
8
|
+
class Class # :nodoc:
|
9
|
+
|
10
|
+
def add_basic_method ( meth )
|
11
|
+
class_eval <<-end_eval
|
12
|
+
def #{meth} ( *args )
|
13
|
+
run("#{meth}", *args)
|
14
|
+
end
|
15
|
+
def #{meth}_ ( *args )
|
16
|
+
run("#{meth}", *args)
|
17
|
+
end
|
18
|
+
end_eval
|
19
|
+
end
|
20
|
+
|
21
|
+
def add_basic_method! ( meth )
|
22
|
+
class_eval <<-end_eval
|
23
|
+
def #{meth}! ( *args )
|
24
|
+
run!("#{meth}", *args)
|
25
|
+
end
|
26
|
+
def #{meth}_! ( *args )
|
27
|
+
run!("#{meth}", *args)
|
28
|
+
end
|
29
|
+
end_eval
|
30
|
+
end
|
31
|
+
|
32
|
+
def alias_command ( m1, m2 )
|
33
|
+
class_eval <<-end_eval
|
34
|
+
def #{m1} ( *args )
|
35
|
+
#{m2}(*args)
|
36
|
+
end
|
37
|
+
def #{m1}_ ( *args )
|
38
|
+
#{m2}_(*args)
|
39
|
+
end
|
40
|
+
def #{m1}! ( *args )
|
41
|
+
#{m2}!(*args)
|
42
|
+
end
|
43
|
+
def #{m1}_! ( *args )
|
44
|
+
#{m2}_!(*args)
|
45
|
+
end
|
46
|
+
end_eval
|
47
|
+
end
|
48
|
+
|
49
|
+
end # class Class
|
50
|
+
|
51
|
+
# The abstract class for a Vcs wrapper.
|
52
|
+
# Conventions:
|
53
|
+
# example:
|
54
|
+
# svn checkout http://foo.bar/proj # normal command
|
55
|
+
# xrcs checkout http://foo.bar/proj # normal
|
56
|
+
#
|
57
|
+
# checkout
|
58
|
+
# checkout_
|
59
|
+
# checkout!
|
60
|
+
# checkout_!
|
61
|
+
#
|
62
|
+
class Vcs
|
63
|
+
|
64
|
+
class Failure < Exception
|
65
|
+
end
|
66
|
+
|
67
|
+
def initialize ( aCmd )
|
68
|
+
@cmd = aCmd
|
69
|
+
end
|
70
|
+
|
71
|
+
def common_run ( args )
|
72
|
+
cmd = @cmd + ' "' + args.join('" "') + '"'
|
73
|
+
LOG.debug "running: #{cmd}" if $debug > 1
|
74
|
+
cmd
|
75
|
+
end
|
76
|
+
private :common_run
|
77
|
+
|
78
|
+
def run ( *args )
|
79
|
+
IO.popen(common_run(args))
|
80
|
+
end
|
81
|
+
|
82
|
+
def run! ( *args )
|
83
|
+
system(common_run(args))
|
84
|
+
end
|
85
|
+
|
86
|
+
%w[ checkout delete diff help status log add update ].each do |m|
|
87
|
+
add_basic_method(m)
|
88
|
+
end
|
89
|
+
|
90
|
+
add_basic_method!(:commit)
|
91
|
+
|
92
|
+
def method_missing ( meth, *args )
|
93
|
+
meth = meth.to_s
|
94
|
+
if meth =~ /^(.*)!$/
|
95
|
+
if respond_to? $1
|
96
|
+
send($1, *args).each do |line|
|
97
|
+
puts line
|
98
|
+
end
|
99
|
+
else
|
100
|
+
LOG.warn "unknown method #{meth}"
|
101
|
+
run!($1.sub(/_$/, ''), *args)
|
102
|
+
end
|
103
|
+
else
|
104
|
+
LOG.warn "unknown method #{meth}"
|
105
|
+
run(meth.sub(/_$/, ''), *args)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
alias_command :ann, :blame
|
110
|
+
alias_command :annotate, :blame
|
111
|
+
alias_command :praise, :blame
|
112
|
+
alias_command :co, :checkout
|
113
|
+
alias_command :ci, :commit
|
114
|
+
alias_command :cp, :copy
|
115
|
+
alias_command :del, :delete
|
116
|
+
alias_command :remove, :delete
|
117
|
+
alias_command :rm, :delete
|
118
|
+
alias_command :di, :diff
|
119
|
+
alias_command :h, :help
|
120
|
+
alias_command :ls, :list
|
121
|
+
alias_command :mv, :move
|
122
|
+
alias_command :rename, :move
|
123
|
+
alias_command :ren, :move
|
124
|
+
alias_command :pdel, :propdel
|
125
|
+
alias_command :pd, :propdel
|
126
|
+
alias_command :pedit, :propedit
|
127
|
+
alias_command :pe, :propedit
|
128
|
+
alias_command :pget, :propget
|
129
|
+
alias_command :pg, :propget
|
130
|
+
alias_command :plist, :proplist
|
131
|
+
alias_command :pl, :proplist
|
132
|
+
alias_command :pset, :propset
|
133
|
+
alias_command :ps, :propset
|
134
|
+
alias_command :st, :status
|
135
|
+
alias_command :stat, :status
|
136
|
+
alias_command :sw, :switch
|
137
|
+
alias_command :up, :update
|
138
|
+
|
139
|
+
# Cvs Alias
|
140
|
+
alias_command :new, :add
|
141
|
+
alias_command :rcs, :admin
|
142
|
+
alias_command :get, :checkout
|
143
|
+
alias_command :rlog, :log
|
144
|
+
alias_command :patch, :rdiff
|
145
|
+
alias_command :remove, :delete
|
146
|
+
alias_command :rm, :delete
|
147
|
+
alias_command :rfreeze, :rtag
|
148
|
+
alias_command :freeze, :tag
|
149
|
+
|
150
|
+
# Prcs Alias
|
151
|
+
alias_command :checkin, :commit
|
152
|
+
alias_command :populate, :add
|
153
|
+
|
154
|
+
end # class Vcs
|
155
|
+
|
metadata
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
rubygems_version: 0.8.4
|
3
|
+
specification_version: 1
|
4
|
+
name: vcs
|
5
|
+
version: !ruby/object:Gem::Version
|
6
|
+
version: "0.1"
|
7
|
+
date: 2005-02-08
|
8
|
+
summary: A wrapper over any version control system
|
9
|
+
require_paths:
|
10
|
+
- src
|
11
|
+
email: ertai@lrde.epita.fr
|
12
|
+
homepage: https://svn.lrde.epita.fr/svn/lrdetools/trunk/vcs/
|
13
|
+
rubyforge_project: vcs
|
14
|
+
description: "Version control systems (Subversion, CVS, PRCS...), however useful, are not very
|
15
|
+
extensible: adding new features can be cumbersome, especially if you want them
|
16
|
+
for different such systems at once. Vcs provide a simple dynamic hierarchy for
|
17
|
+
Version Control Systems."
|
18
|
+
autorequire: vcs
|
19
|
+
default_executable: vcs
|
20
|
+
bindir: bin
|
21
|
+
has_rdoc: false
|
22
|
+
required_ruby_version: !ruby/object:Gem::Version::Requirement
|
23
|
+
requirements:
|
24
|
+
-
|
25
|
+
- ">"
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
version: 0.0.0
|
28
|
+
version:
|
29
|
+
platform: ruby
|
30
|
+
authors:
|
31
|
+
- Nicolas Pouillard
|
32
|
+
files:
|
33
|
+
- src/ask.rb
|
34
|
+
- src/changelog.rb
|
35
|
+
- src/cvs.rb
|
36
|
+
- src/diffstat.rb
|
37
|
+
- src/mail.rb
|
38
|
+
- src/message.rb
|
39
|
+
- src/mycommit.rb
|
40
|
+
- src/news.rb
|
41
|
+
- src/prcs.rb
|
42
|
+
- src/reply-mail.rb
|
43
|
+
- src/revision.rb
|
44
|
+
- src/svn.rb
|
45
|
+
- src/tools.rb
|
46
|
+
- src/vcs.rb
|
47
|
+
- bin/vcs
|
48
|
+
- bin/vcs-cvs
|
49
|
+
- bin/vcs-prcs
|
50
|
+
- bin/vcs-svn
|
51
|
+
- lrdetools.rb
|
52
|
+
- HOWTO
|
53
|
+
- Rakefile
|
54
|
+
- TODO
|
55
|
+
test_files: []
|
56
|
+
rdoc_options: []
|
57
|
+
extra_rdoc_files: []
|
58
|
+
executables:
|
59
|
+
- vcs
|
60
|
+
- vcs-svn
|
61
|
+
- vcs-cvs
|
62
|
+
- vcs-prcs
|
63
|
+
extensions: []
|
64
|
+
requirements: []
|
65
|
+
dependencies: []
|