public
Description: The Git TextMate Bundle
Homepage: http://tim.theenchanter.com/
Clone URL: git://github.com/timcharper/git-tmbundle.git
git-tmbundle / Support / app / controllers / log_controller.rb
100644 174 lines (145 sloc) 5.734 kb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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
55
56
57
58
59
60
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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
require ENV['TM_SUPPORT_PATH'] + '/lib/ui.rb'
require "#{ENV["TM_SUPPORT_PATH"]}/lib/osx/plist"
require "#{ENV["TM_SUPPORT_PATH"]}/lib/progress"
require LIB_ROOT + '/date_helpers.rb'
location = ENV["TM_BUNDLE_SUPPORT"]
$nib = "#{location}/nibs/RevisionSelector.nib"
ListNib = File.dirname(__FILE__) + "/../../nibs/RevisionSelector.nib"
 
 
class LogController < ApplicationController
  layout "application", :only => "index"
  before_filter :set_script_at_top
  
  def set_script_at_top
    @script_at_top = true
  end
  
  DEFAULT_LOG_LIMIT = 100
  include DateHelpers
  
  def index
    params[:path] ||= git.make_local_path(git.paths.first)
    params[:limit] ||= DEFAULT_LOG_LIMIT
    path = params[:path]
    # Get the desired revision number
    if File.directory?(git.git_base + path)
      title = "View revision of Directory #{path}"
    else
      title = "View revision of file #{File.basename(path)}"
    end
    
    log
  end
  
  def log
    @path = params[:path]
    @log_entries = git.log(params)
    @branch ||= Git.new.branch.current_name
    render "log_entries"
  end
  
  def open_revision
    filepath = params[:filepath]
    revision = params[:revision]
    line = params[:line]
    if revision.blank?
      tm_open(filepath, :line => line)
      abort
    end
 
    tmp_file = git.show_to_tmp_file(filepath, revision)
    fork do
      tm_open(tmp_file, :line => line, :wait => true)
      File.delete(tmp_file)
    end
  end
  
  def create_branch_from_revision
    revision = params[:revision]
    if revision.blank?
      TextMate::UI.alert(:warning, "Error", "Cannot create a branch from 'current'", 'OK')
      abort
    end
 
    Dir.chdir(ENV['TM_PROJECT_DIRECTORY'])
 
    branch_name = TextMate::UI.request_string(:title => "Create Branch from revision #{revision}", :prompt => "What would you like to call this branch?")
    abort if branch_name.blank?
 
    output = git.branch.create(branch_name, :revision => revision)
 
    if output.blank? # git returns nothing if successful
      TextMate::UI.alert(:informational, "Success!", "Branch has successfully been created!", 'OK')
    else
      TextMate::UI.alert(:warning, "Error!", "#{output}", 'OK')
    end
  end
  
  def create_tag_from_revision
    revision = params[:revision]
    if revision.blank?
      TextMate::UI.alert(:warning, "Error", "Cannot create a tag from 'current'", 'OK')
      abort
    end
 
    tag_name = TextMate::UI.request_string(:title => "Create tag from revision #{revision}", :prompt => "What would you like to call this tag?")
    abort if tag_name.blank?
 
    output = git.command("tag", tag_name, revision)
 
    if output.blank? # git returns nothing if successful
      TextMate::UI.alert(:informational, "Success!", "Tag '#{tag_name}' has successfully been created!", 'OK')
    else
      TextMate::UI.alert(:warning, "Error!", "#{output}", 'OK')
    end
  end
  
    # on failure: returns nil
    def choose_revision(path, prompt = "Choose a revision", number_of_revisions = 1, options = {})
      path = git.make_local_path(path)
      # Validate file
      # puts command("status", path)
      if /error: pathspec .+ did not match any file.+ known to git./.match(git.command("status", path))
        TextMate::UI.alert(:warning, "File “#{File.basename(path)}” is not in the repository.", "Please add the file to the repository before using this command.")
        return nil
      end
 
      # # Get the server name
      # info = YAML::load(svn_cmd("info #{escaped_path}"))
      # repository = info['Repository Root']
      # uri = URI::parse(repository)
 
      # the above will fail for users that run a localized system
      # instead we should do ‘svn info --xml’, though since the
      # code is not used, I just commented it. --Allan 2007-02-20
 
      # Display progress dialog
      # Show the log
      revision = 0
      log_data = nil
    
      TextMate::UI.dialog(:nib => ListNib,
                              :center => true,
                              :parameters => {'title' => prompt,'entries' => [], 'hideProgressIndicator' => false}) do |dialog|
 
        # Parse the log
        log_data = stringify(git.log(:path => path, :limit => 200))
        dialog.parameters = {'entries' => log_data, 'hideProgressIndicator' => true}
 
        dialog.wait_for_input do |params|
          revision = params['returnArgument']
          button_clicked = params['returnButton']
 
          if (button_clicked != nil) and (button_clicked == 'Cancel')
            false # exit
          else
            unless (number_of_revisions == :multiple) or (revision.length == number_of_revisions) then
              TextMate::UI.alert(:warning, "Please select #{number_of_revisions} revision#{number_of_revisions == 1 ? '' : 's'}.", "So far, you have selected #{revision.length} revision#{revision.length == 1 ? '' : 's'}.")
              true # continue
            else
              false # exit
            end
          end
        end
      end
 
      # Return the revision number or nil
      revision = nil if revision == 0
      if options[:sort] && revision
        time_revision_pairs = []
        selected_entries = log_data.select{ |l| revision.include?(l["rev"]) }
        selected_entries.sort!{ |a,b| a["date"] <=> b["date"] } # sorts them descending (latest on the bottom)
        selected_entries.reverse! if options[:sort] == :asc
        revision = selected_entries.map{|se| se["rev"]}
      end
      revision
    end
  
  protected
    def stringify(results)
      results.each{|r| r.stringify_keys! }
    end
end
 
class Hash
  def stringify_keys!
    keys.each{|k|
      if k.is_a?(Symbol)
        value = delete(k)
        self[k.to_s] = value
      end
    }
  end
end