Class: Vcs
- Inherits:
-
Object
- Object
- Vcs
- Defined in:
- lib/vcs/add.rb,
lib/vcs/url.rb,
lib/vcs/back.rb,
lib/vcs/diff.rb,
lib/vcs/edit.rb,
lib/vcs/form.rb,
lib/vcs/junk.rb,
lib/vcs/mail.rb,
lib/vcs/news.rb,
lib/vcs/delete.rb,
lib/vcs/script.rb,
lib/vcs/status.rb,
lib/vcs/message.rb,
lib/vcs/version.rb,
lib/vcs/conflict.rb,
lib/vcs/diffstat.rb,
lib/vcs/changelog.rb,
lib/vcs/opt_parse.rb,
lib/vcs/environment.rb,
lib/vcs/common_commit.rb,
lib/vcs/last_changed_date.rb
Overview
- Author
-
Nicolas Pouillard <[email protected]>.
- Copyright
-
Copyright © 2004, 2005 LRDE. All rights reserved.
- License
-
GNU General Public License (GPL).
- Revision
-
$Id$
Defined Under Namespace
Classes: OptParse, StatusEntry
Constant Summary collapse
- IForm =
',iform'.to_path
- Form =
',form'.to_path
- MAIL =
Sendmail::MAIL_FILE
- NEWS =
',news'.to_path
- Message =
',message'.to_path
- Version =
::Version.parse("dev-util/vcs-0.5_beta4")
- LogEntry =
',log'.to_path
- @@diffstat =
'diffstat'.to_cmd
Class Method Summary collapse
- .editor ⇒ Object
- .env(name, &block) ⇒ Object
- .full_email ⇒ Object
- .fullname ⇒ Object
- .method_missing(meth) ⇒ Object
- .pager ⇒ Object
Instance Method Summary collapse
- #add!(files = [], options = {}) ⇒ Object
-
#back!(files = [], options = {}) ⇒ Object
This command take a command as argument and search the last revision where this command success.
- #check_diffstat ⇒ Object
-
#check_env ⇒ Object
class << self.
- #check_gnu_diff ⇒ Object
-
#color_status!(*args) ⇒ Object
class StatusEntry.
- #commit_failed(ex = nil) ⇒ Object
- #committed? ⇒ Boolean
- #committing? ⇒ Boolean
-
#concat_changelog!(*args) ⇒ Object
Same switches as mk_changelog_entry.
- #concat_changelog_failed ⇒ Object
- #delete!(files = [], options = {}) ⇒ Object
-
#diffstat!(*a) ⇒ Object
Use the diffstat command to display statitics on your patch.
- #diffw!(*args) ⇒ Object
- #diffw_base(files_orig = [], options = {}) ⇒ Object
- #edit!(files = [], options = {}) ⇒ Object
- #edit_conflicts!(files = [], options = {}) ⇒ Object
- #edit_form!(*args) ⇒ Object
- #editing? ⇒ Boolean
-
#junk!(files = [], options = {}) ⇒ Object
This command removes all junk files (by default all files begining with ‘,’).
- #last_changed_date!(*args) ⇒ Object
-
#mail!(files = [], options = {}) ⇒ Object
Mail.
- #mail_conf_checker ⇒ Object
-
#mk_changelog_entry!(*args) ⇒ Object
Same switches as mk_log_entry.
- #mk_form!(files = [], options = {}) ⇒ Object
- #mk_iform!(*args) ⇒ Object
-
#mk_log_entry!(*args) ⇒ Object
Same switches as status.
- #mk_message!(files = [], options = {}) ⇒ Object
-
#mk_message_entry!(*args) ⇒ Object
Same switches as mk_log_entry.
-
#mk_yaml_log_entry!(*args) ⇒ Object
Same switches as status.
-
#news!(*args) ⇒ Object
Post the news.
- #news_conf_checker ⇒ Object
- #news_failed ⇒ Object
- #paginate!(files = [], options = {}) ⇒ Object
- #resolve_conflicts!(files = [], options = {}) ⇒ Object
- #script(files = [], options = {}) ⇒ Object
- #script!(files = [], options = {}) ⇒ Object
- #sending? ⇒ Boolean
- #spawn_status_entries(status_data, &block) ⇒ Object
- #status!(*args) ⇒ Object
- #url!(*args) ⇒ Object
Class Method Details
.editor ⇒ Object
14 15 16 |
# File 'lib/vcs/environment.rb', line 14 def editor env('EDITOR').to_cmd end |
.env(name, &block) ⇒ Object
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
# File 'lib/vcs/environment.rb', line 33 def env ( name, &block ) return @@vars[name] if @@vars.has_key? name @@vars[name] = if var = ENV[name] var elsif block.nil? logger.error "Need #{name} in the environement" @@env_status = false "!!! #{name} not set !!!" else default = block[] logger.warn "Need #{name} in the environement (default: #{default})" ENV[name] = default default end end |
.full_email ⇒ Object
22 23 24 |
# File 'lib/vcs/environment.rb', line 22 def full_email "#{fullname} <#{email}>" end |
.fullname ⇒ Object
10 11 12 |
# File 'lib/vcs/environment.rb', line 10 def fullname env('FULLNAME') { Etc.getpwnam(user).gecos.gsub(/,+$/, '') } end |
.method_missing(meth) ⇒ Object
26 27 28 |
# File 'lib/vcs/environment.rb', line 26 def method_missing ( meth ) env meth.to_s.upcase end |
.pager ⇒ Object
18 19 20 |
# File 'lib/vcs/environment.rb', line 18 def pager env('PAGER').to_cmd end |
Instance Method Details
#add!(files = [], options = {}) ⇒ Object
10 11 12 13 14 15 16 17 18 19 |
# File 'lib/vcs/add.rb', line 10 def add! ( files=[], ={} ) if [:auto] .delete(:auto) list!(files, :unrecognize => true) do |path_list| add_!(path_list.stringify, ) unless path_list.empty? end else add_!(files, ) end end |
#back!(files = [], options = {}) ⇒ Object
This command take a command as argument and search the last revision where this command success.
Example:
* this dummy example success only if the revision is equal to 0 modulo X
* replace X by the success revision and Y by a greater revision
vcs-svn back -r Y vcs-svn script ‘exit(rev.read.to_i % X)’
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
# File 'lib/vcs/back.rb', line 14 def back! ( files=[], ={} ) sub_vcs = sub_vcs_with_name('checkout-4-vcs-back') dir = TempPath.new('checkout-dir-4-vcs-back') cmd = files.to_cmd cmd.dir = dir rev = [:revision] || revision.read.chomp raise ArgumentError, "Just integers are supported for revisions" if rev !~ /^\d+$/ rev = rev.to_i target_url = url.read.chomp while not rev.zero? sub_vcs.checkout([target_url, dir], :quiet => true, :revision => rev) data = cmd.system data.display if [:verbose] if data.status.success? logger.info { "Your command success on revision #{rev}"} break else logger.warn { "Your command fail on revision #{rev}" } end rev -= 1 end end |
#check_diffstat ⇒ Object
19 20 21 22 23 |
# File 'lib/vcs/diffstat.rb', line 19 def check_diffstat unless `diffstat -V` =~ /diffstat version/ raise ArgumentError, 'diffstat: diffstat is required' end end |
#check_env ⇒ Object
class << self
52 53 54 |
# File 'lib/vcs/environment.rb', line 52 def check_env %w[ email fullname editor pager ].each { |m| Vcs.send(m) } end |
#check_gnu_diff ⇒ Object
12 13 14 15 16 |
# File 'lib/vcs/diff.rb', line 12 def check_gnu_diff unless `diff --version` =~ /GNU/ raise ArgumentError, 'diffw: Gnu diff is required' end end |
#color_status!(*args) ⇒ Object
class StatusEntry
59 60 61 62 63 64 |
# File 'lib/vcs/status.rb', line 59 def color_status! ( *args ) status(*args) do |status_entry| status_entry.colorize! puts status_entry.line end end |
#commit_failed(ex = nil) ⇒ Object
132 133 134 135 136 137 |
# File 'lib/vcs/common_commit.rb', line 132 def commit_failed ( ex=nil ) Message.unlink if defined? Message and Message.exist? and not committed? logger.error { "Aborting #{ex}" } logger.info { 'You can rerun the same command to resume the commit' } raise 'Commit failed' end |
#committed? ⇒ Boolean
139 140 141 |
# File 'lib/vcs/common_commit.rb', line 139 def committed? Vcs.commit_state.is_a? Integer end |
#committing? ⇒ Boolean
151 152 153 |
# File 'lib/vcs/common_commit.rb', line 151 def committing? [:editing, :committing, :sending].include? Vcs.commit_state end |
#concat_changelog!(*args) ⇒ Object
Same switches as mk_changelog_entry
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 |
# File 'lib/vcs/changelog.rb', line 98 def concat_changelog! ( *args ) error_handling :concat_changelog_failed unless TMP_CL.exist? logger.info "Backup your `#{CL}' to `#{TMP_CL}' ..." CL.rename(TMP_CL) end CL.open('w') do |file| logger.info "#{CL}: Writing your new entry ..." with(file).mk_changelog_entry!(*args) file.puts logger.info "#{CL}: Writing the others ..." file.print TMP_CL.read end end |
#concat_changelog_failed ⇒ Object
116 117 118 119 120 121 |
# File 'lib/vcs/changelog.rb', line 116 def concat_changelog_failed if TMP_CL.exist? logger.info "Restoring `#{CL}' from `#{TMP_CL}' ..." TMP_CL.rename(CL) end end |
#delete!(files = [], options = {}) ⇒ Object
10 11 12 13 14 15 16 17 18 19 |
# File 'lib/vcs/delete.rb', line 10 def delete! ( files=[], ={} ) if [:auto] .delete(:auto) list!(files, :missing => true) do |path_list| delete_!(path_list.stringify, ) unless path_list.empty? end else delete_!(files, ) end end |
#diffstat!(*a) ⇒ Object
Use the diffstat command to display statitics on your patch.
13 14 15 16 |
# File 'lib/vcs/diffstat.rb', line 13 def diffstat! ( *a ) check_diffstat (diffw(*a) | @@diffstat).run(@runner) end |
#diffw!(*args) ⇒ Object
8 9 10 |
# File 'lib/vcs/diff.rb', line 8 def diffw! ( *args ) diff_!(*args) end |
#diffw_base(files_orig = [], options = {}) ⇒ Object
19 20 21 22 23 24 25 26 27 28 |
# File 'lib/vcs/diff.rb', line 19 def diffw_base ( files_orig=[], ={} ) files = [] status(files_orig, ()) do |se| next if se.file_st.chr =~ /[?X\\,+D]/ next if se.file.to_s == 'ChangeLog' next if se.file.directory? files << se.file unless files.include? se.file end files end |
#edit!(files = [], options = {}) ⇒ Object
10 11 12 13 |
# File 'lib/vcs/edit.rb', line 10 def edit! ( files=[], ={} ) cmd = Vcs.editor + files > [STDOUT, STDERR] cmd.run(@runner) end |
#edit_conflicts!(files = [], options = {}) ⇒ Object
18 19 20 21 |
# File 'lib/vcs/conflict.rb', line 18 def edit_conflicts! ( files=[], ={} ) edit! mk_conflicts_list(files, ) resolve_conflicts! files, end |
#edit_form!(*args) ⇒ Object
8 9 10 11 12 13 |
# File 'lib/vcs/form.rb', line 8 def edit_form! ( *args ) mk_form(*args) edit! Form mk_iform(*args) return YAML.load(IForm.read)['Revision'] || :committing end |
#editing? ⇒ Boolean
143 144 145 |
# File 'lib/vcs/common_commit.rb', line 143 def editing? Vcs.commit_state == :editing end |
#junk!(files = [], options = {}) ⇒ Object
This command removes all junk files (by default all files begining with ‘,’). Warning: this command removes some files that may contains some important information. For example during a commit the information that you type is stored in one of these ‘,files’. So be careful using this command. See the user configuration to customize what is considered a junk file.
14 15 16 17 18 19 20 21 22 23 24 |
# File 'lib/vcs/junk.rb', line 14 def junk! ( files=[], ={} ) list!(files, .merge(:junk => true)) do |path_list| path_list.each { |path| logger.info { "Remove #{path}" } } if @h.agree('Are you sure? (y/n)', true) path_list.each do |path| logger.info { "Removing #{path}..." } path.rm_f end end end end |
#last_changed_date!(*args) ⇒ Object
8 9 10 |
# File 'lib/vcs/last_changed_date.rb', line 8 def last_changed_date! ( *args ) puts info(*args).read[/^Last Changed Date:.*?\(([^)]*)\).*$/, 1] end |
#mail!(files = [], options = {}) ⇒ Object
Mail.
FIXME handle options properly. Delegate the option parsing to Sendmail.
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
# File 'lib/vcs/mail.rb', line 24 def mail! ( files=[], ={} ) # Backward compatiblity files, = [], files if files.is_a? Hash or files.is_a? OpenStruct = @@default_options.merge() [:signed] = Vcs.user_conf.sign = @@mailer.() if editing? Vcs. = return end header = YAML.load(IForm.read) %w[ Log ChangeLog YamlLog Message Title ].each { |x| header.delete x } .to = header['To'] from = header['From'] .from = from[/<(.*)>/, 1] || from .header.merge! header .header.symbolize_keys! return if header['To'].nil? rev = header['Revision'] unless MAIL.exist? print_body(MAIL, , files) end if sending? mail = MAIL.read.gsub(/<%= rev %>/, rev.to_s) MAIL.open('w') { |f| f.puts mail } @@mailer.sendmail puts 'Mail: Sent.' end end |
#mail_conf_checker ⇒ Object
56 57 58 59 60 61 62 63 64 65 |
# File 'lib/vcs/mail.rb', line 56 def mail_conf_checker if Vcs.user_conf.sign unless `gpg --version` =~ /^gpg \(GnuPG\)/ logger.error 'mail: gunpg is required' end unless File.exist?("#{ENV['HOME']}/.gnupg/secring.gpg") logger.error 'no private key: in your ~/.gnupg' end end end |
#mk_changelog_entry!(*args) ⇒ Object
Same switches as mk_log_entry
77 78 79 80 81 |
# File 'lib/vcs/changelog.rb', line 77 def mk_changelog_entry! ( *args ) puts Time.now.strftime("%Y-%m-%d #{Vcs.full_email}") puts mk_log_entry(*args).each_line(&method(:log_to_changelog)) end |
#mk_form!(files = [], options = {}) ⇒ Object
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 |
# File 'lib/vcs/form.rb', line 61 def mk_form! ( files=[], ={} ) with_cache! Form, 'complete form (title, subject, ChangeLog entry, diff)' do puts " |--You must fill this file correctly to continue--#{' '*13}-*- vcs -*- |Title: \"\" |Subject: #{@@subject_format.dump} |From: \"#{Vcs.full_email}\" |To: [#{[:to].join(', ')}] |".head_cut! = case Vcs.user_conf.log_mode.to_sym when :change_log puts " |ChangeLog: |".head_cut! mk_log_entry(files, ).each_line(&method(:log_to_changelog)) when :log puts " |Log: |2 |".head_cut! mk_log_entry(files, ).each_line { |line| puts " #{line}" } when :yaml_log puts " |YamlLog: |".head_cut! mk_yaml_log_entry!(files, ) end puts " |#{@@message_line} | |#{@@last_line} |".head_cut! if Vcs.user_conf.new_user puts "| |Instructions: |- Fill the changelog/log entry. |- The first line must be removed when this file is filled. |- After you must specify a title, for the news/mail subject. | The tag <%= Title %> will be automatically replaced by your title, | <%= Subject %> by the subject line, <%= Rev %> by the revision... |- Everywhere in the document you can get/compute some values with | these tags <%= aRubyExpression %> even some vcs specific call. | For example <%= status.read %> will include the 'svn status' output. |- The Title will be automatically added on the top of your ChangeLog | entry. The line with the date and your name will be added too. | |".head_cut! case Vcs.user_conf.log_mode.to_sym when :log puts "- Tabulations and stars ('*') will be added in the ChangeLog before each line." end end (files, ) Message.unlink end end |
#mk_iform!(*args) ⇒ Object
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
# File 'lib/vcs/form.rb', line 17 def mk_iform! ( *args ) with_cache! IForm, 'instanciated form' do form = mk_form(*args).read # Remove the first info line if present form.gsub!(/\A--.*\n/, '') # Get the message between the `message line' and the `last line' = form[/^#{@@message_line}$(.*)^#{@@last_line}$/m, 1] # Remove every thing after the `message line' form.gsub!(/^#{@@message_line}$.*\Z/m, '') # Handle ChangeLog entries to make it Yaml compliant form.gsub!(/^(ChangeLog:)$/, '\1 |2') form.gsub!(/^\t/, " \t") form.gsub!(/^ {8}/, " \t") header = YAML.load(form) input = header['Log'] || header['ChangeLog'] if header['Title'].nil? or header['Title'].blank? raise Failure, "No title found. Reopen `#{Form}' and add it" end header['Title'] += '.' unless header['Title'] =~ /[.?!]$/ rev = '<%= rev %>' # make the revision substitution afterward b = getBinding(header.merge(:rev => rev, :revision => rev)) input = ERB.new(input, nil, '<-%->', '$erbout_').result(b) LogEntry.open('w') { |f| f.print input } header['Message'] = header.each_value do |v| next unless v.is_a? String v.replace(ERB.new(v, nil, '<-%->', '$erbout_').result(b)) end puts header.to_yaml end end |
#mk_log_entry!(*args) ⇒ Object
Same switches as status
40 41 42 43 44 45 46 47 48 |
# File 'lib/vcs/changelog.rb', line 40 def mk_log_entry! ( *args ) with_cache! LogEntry, 'Log entry' do puts '<%= Title %>' puts mk_log_entry_contents(*args).each do |se| puts "- #{se.file}: #{se.comment}." end end end |
#mk_message!(files = [], options = {}) ⇒ Object
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
# File 'lib/vcs/message.rb', line 22 def ( files=[], ={} ) with_cache! Message, 'generated message (ChangeLog, diffstat, diff)' do url! if msg = ['Message'] puts msg end = if defined? COLLABOA puts 'You can also view this changeset here:' puts puts "http://#{COLLABOA}/repository/changesets/<%= rev %>" end puts flush (files, ) puts flush diffstat!(files, ) puts flush diffw(files, ).each_line do |line| print line if line !~ /^=+$/ end end end |
#mk_message_entry!(*args) ⇒ Object
Same switches as mk_log_entry
86 87 88 89 90 91 92 |
# File 'lib/vcs/changelog.rb', line 86 def ( *args ) puts 'Index: ChangeLog' puts "from #{Vcs.full_email}" puts puts "\tDo not fill this draft entry!" if editing? mk_log_entry(*args).each_line(&method(:log_to_changelog)) end |
#mk_yaml_log_entry!(*args) ⇒ Object
Same switches as status
54 55 56 57 58 59 60 61 |
# File 'lib/vcs/changelog.rb', line 54 def mk_yaml_log_entry! ( *args ) raise NotImplentedError # with_cache! LogEntry, 'Log entry' do # mk_log_entry_contents(*args).each do |se| # puts " - #{se.file}: >2\n #{se.comment}." # end # end end |
#news!(*args) ⇒ Object
Post the news.
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 |
# File 'lib/vcs/news.rb', line 61 def news! ( *args ) error_handling :news_failed print_body(NEWS, (*args)) unless NEWS.exist? @news_status = 'Sent.' NEWS.open('r') do |file| opt = YAML::chop_header(file) server, port = opt[:server].split(/:/) port ||= 119 logger.info('news') { "Nntp Server: #{server}:#{port}" } unless @h.agree("Post a news, with this subject: #{opt[:subject]}\n" + " to #{opt[:groups].join(', ')}\n from #{opt[:from]}\n" + 'Are you sure? (y/n)', true) logger.error('news') { 'Aborting' } exit end require 'socket' TCPSocket.open(server, port) do |f| check_line(f, /^200/) f.puts 'post' check_line(f, /^340/) f.puts "Newsgroups: #{opt[:groups].join(', ')}" f.puts "From: #{opt[:from]}" f.puts "Subject: #{opt[:subject]}" f.puts file.each do |line| f.print line.gsub(/^\./, ' .') end f.puts '.' check_line(f, /^240/) f.puts 'quit' check_line(f, /^205/) end end NEWS.delete puts @news_status end |
#news_conf_checker ⇒ Object
107 108 109 110 111 112 113 |
# File 'lib/vcs/news.rb', line 107 def news_conf_checker %w[ NNTPSERVER ].each do |var| if ENV[var].nil? or ENV[var].empty? logger.error "environment variable `#{var}' not set" end end end |
#news_failed ⇒ Object
100 101 102 103 104 105 |
# File 'lib/vcs/news.rb', line 100 def news_failed if defined? NEWS and NEWS.exist? logger.info "#{NEWS}: Contains the generated news" + "(generated from #{@@message})" end end |
#paginate!(files = [], options = {}) ⇒ Object
15 16 17 18 |
# File 'lib/vcs/edit.rb', line 15 def paginate! ( files=[], ={} ) cmd = Vcs.pager + files > [STDOUT, STDERR] cmd.run(@runner) end |
#resolve_conflicts!(files = [], options = {}) ⇒ Object
23 24 25 26 27 28 29 |
# File 'lib/vcs/conflict.rb', line 23 def resolve_conflicts! ( files=[], ={} ) conflicts = mk_conflicts_list(files, ) question = "Resolve these conflicts?: \n - #{conflicts.join("\n - ")}\n(y/n)" if @h.agree question, true return resolved(conflicts) end end |
#script(files = [], options = {}) ⇒ Object
10 11 12 |
# File 'lib/vcs/script.rb', line 10 def script ( files=[], ={} ) puts script!(files, ) end |
#script!(files = [], options = {}) ⇒ Object
14 15 16 17 18 19 20 21 22 23 |
# File 'lib/vcs/script.rb', line 14 def script! ( files=[], ={} ) begin eval(files.join(' ')) rescue SystemExit => ex raise ex rescue Exception => ex logger.error { 'Vcs#script: during the client execution' } logger.error { ex.long_pp } end end |
#sending? ⇒ Boolean
147 148 149 |
# File 'lib/vcs/common_commit.rb', line 147 def sending? Vcs.commit_state == :sending end |
#spawn_status_entries(status_data, &block) ⇒ Object
76 77 78 79 80 81 82 83 84 85 86 |
# File 'lib/vcs/status.rb', line 76 def spawn_status_entries ( status_data, &block ) result = PathList.new status_data.each_line do |line| next unless line =~ /^.{5} / status_entry = StatusEntry.new(@h, line) next if status_entry.category == :exclude result << status_entry end result.sort_with_regex_list! Vcs.regex_list result.each(&block) end |
#status!(*args) ⇒ Object
66 67 68 69 70 71 72 73 74 |
# File 'lib/vcs/status.rb', line 66 def status! ( *args ) if color? color_status!(*args) else status(*args) do |status_entry| puts status_entry.line end end end |
#url!(*args) ⇒ Object
8 9 10 |
# File 'lib/vcs/url.rb', line 8 def url! ( *args ) puts info(*args).read[/^URL:\s+(.*)$/, 1] end |