vcs 0.3.0 → 0.4.0

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