vcs 0.1

Sign up to get free protection for your applications and to get access to all the features.
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: []