vcs 0.3.0 → 0.4.0

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.
@@ -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