vcs 0.1

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/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
@@ -0,0 +1,12 @@
1
+ class Vcs
2
+
3
+ def lrdetools_commit! ( s, *args )
4
+
5
+ common_commit!(*args) do |rev|
6
+ news!(:groups => ['lrde.proj'], :subject => "LT #{rev}: #{s}")
7
+ end
8
+
9
+ end
10
+ alias_command :ltci, :lrdetools_commit
11
+
12
+ end # class Vcs
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
@@ -0,0 +1,14 @@
1
+
2
+
3
+ class Vcs
4
+ def replymail! ( rev )
5
+ mail() do |f|
6
+ log("-r#{rev}").each do |line|
7
+ f.print '> ', line
8
+ end
9
+ f.puts '[...]'
10
+ f.puts
11
+ f.puts 'Ok.'
12
+ end
13
+ end
14
+ end
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: []