royw-git_shoes 0.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Roy Wright
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,15 @@
1
+ = git_shoes
2
+
3
+ This is an exploration of using shoes for a real application.
4
+ As this is a learning experience, the files are likely to be
5
+ in a high state of flux.
6
+
7
+ If the shoes UI works out, then this project's goal is to
8
+ facilitate git workflows and not be a simple porting of the
9
+ CLI to a GUI.
10
+
11
+ Onward thru the fog...
12
+
13
+ == Copyright
14
+
15
+ Copyright (c) 2009 Roy Wright. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,48 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "git_shoes"
8
+ gem.summary = %Q{TODO}
9
+ gem.email = "roy@wright.org"
10
+ gem.homepage = "http://github.com/royw/git_shoes"
11
+ gem.authors = ["Roy Wright"]
12
+
13
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
14
+ end
15
+ rescue LoadError
16
+ puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
17
+ end
18
+
19
+ require 'spec/rake/spectask'
20
+ Spec::Rake::SpecTask.new(:spec) do |spec|
21
+ spec.libs << 'lib' << 'spec'
22
+ spec.spec_files = FileList['spec/**/*_spec.rb']
23
+ end
24
+
25
+ Spec::Rake::SpecTask.new(:rcov) do |spec|
26
+ spec.libs << 'lib' << 'spec'
27
+ spec.pattern = 'spec/**/*_spec.rb'
28
+ spec.rcov = true
29
+ end
30
+
31
+
32
+ task :default => :spec
33
+
34
+ require 'rake/rdoctask'
35
+ Rake::RDocTask.new do |rdoc|
36
+ if File.exist?('VERSION.yml')
37
+ config = YAML.load(File.read('VERSION.yml'))
38
+ version = "#{config[:major]}.#{config[:minor]}.#{config[:patch]}"
39
+ else
40
+ version = ""
41
+ end
42
+
43
+ rdoc.rdoc_dir = 'rdoc'
44
+ rdoc.title = "git_shoes #{version}"
45
+ rdoc.rdoc_files.include('README*')
46
+ rdoc.rdoc_files.include('lib/**/*.rb')
47
+ end
48
+
data/VERSION.yml ADDED
@@ -0,0 +1,4 @@
1
+ ---
2
+ :patch: 0
3
+ :major: 0
4
+ :minor: 0
@@ -0,0 +1,115 @@
1
+ # This is the start of the application controller.
2
+
3
+ class Controller
4
+ class << self
5
+ include GitHelper
6
+ end
7
+
8
+ ALL = 'All'
9
+ MANAGED = 'Managed'
10
+ MODIFIED = 'Modified'
11
+ CANDIDATE = 'Unmanaged'
12
+ GIT_FILTER_NAMES = [ALL, MANAGED, MODIFIED, CANDIDATE]
13
+ FILTER_NAMES = [ALL]
14
+
15
+ NAME = 'Name'
16
+ REVERSE_NAME = 'Reverse Name'
17
+ DATE = 'Newest First'
18
+ REVERSE_DATE = 'Oldest First'
19
+ SORT_NAMES = [NAME, REVERSE_NAME, DATE, REVERSE_DATE]
20
+
21
+ # current working directory
22
+ def self.cwd
23
+ Directory.cwd
24
+ # Dir.getwd
25
+ end
26
+
27
+ # change directory
28
+ # Yes, could just use Dir.chdir but I'm wanting project
29
+ # accesses encapsulated by the controller/model and not
30
+ # in the view.
31
+ def self.chdir(path)
32
+ Directory.change(path)
33
+ end
34
+
35
+ # return nil or the top level directory of the current
36
+ # git repository
37
+ def self.git_project_dir
38
+ Directory.repository_path
39
+ end
40
+
41
+ def self.in_repository?
42
+ Directory.git?
43
+ end
44
+
45
+ def self.repository_info
46
+ Directory.repository_info
47
+ end
48
+
49
+ def self.branch(verbose=false)
50
+ Directory.branch(verbose)
51
+ end
52
+
53
+ def self.branches
54
+ Directory.branches
55
+ end
56
+
57
+ def self.branch=(name)
58
+ Directory.branch = name
59
+ end
60
+
61
+ def self.stash
62
+ Directory.stash
63
+ end
64
+
65
+ def self.stash_pop
66
+ Directory.stash_pop
67
+ end
68
+
69
+ def self.get_git_log(name)
70
+ Directory.get_git_log(name)
71
+ end
72
+
73
+ # return the list of files in the current directory
74
+ def self.files(&blk)
75
+ items = Directory.contents.collect do |item|
76
+ item.options[:click] = lambda {Controller.chdir(item.path); blk.call(nil)} if item.directory?
77
+ item.options[:click] = lambda {blk.call(item.path)} if item.file?
78
+ item
79
+ end
80
+ # puts "files items => #{items.inspect}"
81
+ items
82
+ end
83
+
84
+ # filter the list of files
85
+ def self.filter_by(filter_name, values)
86
+ case filter_name
87
+ when ALL
88
+ # leave values alone
89
+ when MANAGED
90
+ values = values.select{|item| item.managed? || item.directory?}
91
+ when MODIFIED
92
+ values = values.select{|item| item.modified? || item.directory?}
93
+ when CANDIDATE
94
+ values = values.select{|item| item.candidate? || item.directory?}
95
+ end
96
+ # puts "filter_by values => #{values.inspect}"
97
+ values
98
+ end
99
+
100
+ # sort the list of files
101
+ def self.sort_by(sort_name, values)
102
+ case sort_name
103
+ when NAME
104
+ values = values.sort {|a,b| a.path <=> b.path}
105
+ when REVERSE_NAME
106
+ values = values.sort {|a,b| b.path <=> a.path}
107
+ when DATE
108
+ values = values.sort {|a,b| a.mtime <=> b.mtime}
109
+ when REVERSE_DATE
110
+ values = values.sort {|a,b| b.mtime <=> a.mtime}
111
+ end
112
+ # puts "sort_by values => #{values.inspect}"
113
+ values
114
+ end
115
+ end
data/lib/loader.rb ADDED
@@ -0,0 +1,19 @@
1
+ APP_ENV = "development" unless defined? APP_ENV
2
+ $:.push(File.join(File.dirname(__FILE__)))
3
+ require 'yaml'
4
+ require 'logger'
5
+ require 'singleton'
6
+ # require 'ruby-debug'
7
+
8
+ require 'logger_facade'
9
+
10
+ require 'models/git_helper'
11
+ require 'models/directory'
12
+ require 'models/dir_item'
13
+
14
+ require 'views/bullet_list'
15
+ require 'views/action'
16
+ require 'views/dir_action'
17
+
18
+ require 'controllers/controller'
19
+
@@ -0,0 +1,29 @@
1
+ # From Matt Payne's slimtimeronshoes
2
+ class LoggerFacade
3
+
4
+ @@logger = Logger.new(APP_ENV == "development" ? STDOUT :
5
+ File.open('SlimTimerOnShoesErrors.log', File::WRONLY | File::APPEND | File::CREAT))
6
+ @@logger.level = APP_ENV == "production" ? Logger::WARN : Logger::INFO
7
+
8
+ FATAL = Logger::FATAL
9
+ ERROR = Logger::ERROR
10
+ WARN = Logger::WARN
11
+ INFO = Logger::INFO
12
+ DEBUG = Logger::DEBUG
13
+
14
+ def self.log(message, status=LoggerFacade::INFO)
15
+ case status
16
+ when LoggerFacade::DEBUG
17
+ @@logger.debug(message)
18
+ when LoggerFacade::ERROR
19
+ @@logger.error(message)
20
+ when LoggerFacade::FATAL
21
+ @@logger.fatal(message)
22
+ when LoggerFacade::INFO
23
+ @@logger.info(message)
24
+ when LoggerFacade::WARN
25
+ @@logger.warn(message)
26
+ end
27
+ end
28
+
29
+ end
@@ -0,0 +1,47 @@
1
+ class DirItem
2
+ include GitHelper
3
+
4
+ attr_reader :path, :options
5
+ attr_writer :managed, :modified, :candidate
6
+
7
+ def initialize(path)
8
+ @path = path
9
+ @managed = false
10
+ @modified = false
11
+ @candidate = false
12
+ @options = {}
13
+ end
14
+
15
+ def managed?
16
+ @managed
17
+ end
18
+
19
+ def modified?
20
+ @modified
21
+ end
22
+
23
+ def candidate?
24
+ @candidate
25
+ end
26
+
27
+ def directory?
28
+ File.directory?(@path)
29
+ end
30
+
31
+ def file?
32
+ File.file?(@path)
33
+ end
34
+
35
+ def mtime
36
+ File.mtime(@path)
37
+ end
38
+
39
+ def diff
40
+ git_diff(@path)
41
+ end
42
+
43
+ def log
44
+ git_log(@path)
45
+ end
46
+
47
+ end
@@ -0,0 +1,146 @@
1
+ class Directory
2
+ include Singleton
3
+ include GitHelper
4
+
5
+ def self.change(path,&blk)
6
+ instance.change(path, &blk)
7
+ end
8
+
9
+ def self.git?
10
+ instance.git?
11
+ end
12
+
13
+ def self.repository_path
14
+ instance.repository_path
15
+ end
16
+
17
+ def self.repository_info
18
+ instance.repository_info
19
+ end
20
+
21
+ def self.branch(verbose=false)
22
+ instance.branch(verbose)
23
+ end
24
+
25
+ def self.branches
26
+ instance.branches
27
+ end
28
+
29
+ def self.branch=(name)
30
+ instance.branch = name
31
+ end
32
+
33
+ def self.stash
34
+ instance.stash
35
+ end
36
+
37
+ def self.stash_pop
38
+ instance.stash_pop
39
+ end
40
+
41
+ def self.get_git_log(name)
42
+ instance.get_git_log(name)
43
+ end
44
+
45
+ def self.contents
46
+ instance.contents
47
+ end
48
+
49
+ def self.cwd
50
+ instance.cwd
51
+ end
52
+
53
+ protected
54
+
55
+ def initialize
56
+ @cwd = Dir.getwd
57
+ end
58
+
59
+ public
60
+
61
+ attr_reader :cwd
62
+
63
+ def change(path,&blk)
64
+ Dir.chdir(path, &blk)
65
+ @cwd = Dir.getwd
66
+ end
67
+
68
+ def git?
69
+ git_dir?(@cwd)
70
+ end
71
+
72
+ def repository_path
73
+ git_dir(@cwd)
74
+ end
75
+
76
+ def repository_info
77
+ repo_info = {}
78
+ if git?
79
+ # auto pop the directory when we are done
80
+ Dir.chdir(repository_path) do
81
+ repo_info['Managed'] = git_ls_files.length
82
+ repo_info['Modified'] = git_modified_files.length
83
+ repo_info['Unmanaged'] = git_new_files.length
84
+ end
85
+ end
86
+ repo_info
87
+ end
88
+
89
+ def branch(verbose=false)
90
+ git? ? git_branch(verbose) : ''
91
+ end
92
+
93
+ def branches
94
+ git_branch_names
95
+ end
96
+
97
+ def branch=(name)
98
+ git_checkout_branch(name)
99
+ end
100
+
101
+ def stash
102
+ git_stash
103
+ end
104
+
105
+ def stash_pop
106
+ git_stash_pop
107
+ end
108
+
109
+ def get_git_log(name)
110
+ git_log(name)
111
+ end
112
+
113
+ def contents
114
+ git? ? git_contents : non_git_contents
115
+ end
116
+
117
+ private
118
+
119
+ def git_contents
120
+ managed_files = git_ls_files
121
+ managed_dirs = managed_files.collect{|path| path =~ /^([^\/]+)\// ? $1 : nil}.compact.uniq
122
+ modified_files = git_modified_files
123
+ candidate_files = git_new_files
124
+ entries = Dir.entries(@cwd)
125
+ entries.delete('.')
126
+ items = entries.collect do |filename|
127
+ item = DirItem.new(filename)
128
+ item.managed = managed_files.include?(filename)
129
+ item.modified = modified_files.include?(filename)
130
+ item.candidate = candidate_files.include?(filename)
131
+ item
132
+ end
133
+ # puts "contents items => #{items.inspect}"
134
+ items
135
+ end
136
+
137
+ def non_git_contents
138
+ entries = Dir.entries(@cwd)
139
+ entries.delete('.')
140
+ items = entries.collect do |filename|
141
+ DirItem.new(filename)
142
+ end
143
+ items
144
+ end
145
+
146
+ end
@@ -0,0 +1,162 @@
1
+ # This is a temporary hack while I learn more about git.
2
+ # As such I'm using very ugly, non-portable code to invoke
3
+ # git via the command line. This ugliness will eventually
4
+ # be replaced with a gem library.
5
+ #
6
+ # The current goal is to define the high level interface
7
+ # needed to git.
8
+ #
9
+ # A really good git reference:
10
+ # http://skwpspace.com/git-workflows-book/
11
+ module GitHelper
12
+
13
+ # is the given path in a git repository?
14
+ def git_dir?(path)
15
+ # debug "git_dir?(#{path})"
16
+ result = false
17
+ unless path.nil? || path.strip.empty?
18
+ if File.directory?(path)
19
+ result = File.exist?(File.join(path, '.git'))
20
+ end
21
+ unless result
22
+ unless File.dirname(path) == path
23
+ result = git_dir?(File.dirname(path))
24
+ end
25
+ end
26
+ end
27
+ result
28
+ end
29
+
30
+ # return nil or the path to the top level directory of the
31
+ # git repository that includes the given path
32
+ def git_dir(path)
33
+ # debug "git_dir?(#{path})"
34
+ result = nil
35
+ unless path.nil? || path.strip.empty?
36
+ # if the given path is a directory then check if it has a .git sub-directory
37
+ if File.directory?(path)
38
+ git_pathspec = File.join(path, '.git')
39
+ if File.exist?(git_pathspec) && File.directory?(git_pathspec)
40
+ result = path
41
+ end
42
+ end
43
+ # only recurse if we haven't found a .git directory
44
+ if result.nil?
45
+ # stop recurse when we can't traverse up the tree any farther
46
+ unless File.dirname(path) == path
47
+ # recurse into the parent directory
48
+ result = git_dir(File.dirname(path))
49
+ end
50
+ end
51
+ end
52
+ result
53
+ end
54
+
55
+ # return an array of filespecs of all the files in the
56
+ # current directory that are already in the git repository
57
+ def git_ls_files
58
+ `git ls-files`.split("\n")
59
+ end
60
+
61
+ # return an array of filespecs of all the files that have
62
+ # been modified in the working tree relative to the current
63
+ # directory
64
+ def git_modified_files
65
+ s1 = `git status`
66
+ parse_modified_files(s1)
67
+ end
68
+
69
+ def parse_modified_files(s1)
70
+ s1.split("\n").collect{ |line| line =~ /^\#\s+modified\:\s+(\S.*)/ ? $1 : nil}.compact
71
+ end
72
+
73
+ # return an array of filespecs relative to the current directory
74
+ # of all the files in the working tree that are not ignored by
75
+ # .gitignore and are not currently in the repository.
76
+ def git_new_files
77
+ s1 = `git status`
78
+ parse_new_files(s1)
79
+ end
80
+
81
+ def parse_new_files(s1)
82
+ filenames = []
83
+ re1 = /^\#\s+Untracked files\:/m
84
+ md1 = re1.match(s1)
85
+ unless md1.nil?
86
+ s2 = md1.post_match
87
+ re2 = /^#\s+\(use \"git add \<file\>\.\.\.\" to include in what will be committed\)/m
88
+ md2 = re2.match(s2)
89
+ unless md2.nil?
90
+ s3 = md2.post_match
91
+ filenames = s3.split("\n").collect{|line| line =~ /^#\s+(\S.*)/ ? $1 : nil}.compact
92
+ end
93
+ end
94
+ filenames
95
+ end
96
+
97
+ def git_branch(verbose=false)
98
+ branch = ''
99
+ `git branch#{verbose ? ' -v' : ''}`.split("\n").each do |s|
100
+ if s =~ /^\*\s+(\S.*)\s*$/
101
+ branch = $1
102
+ break
103
+ end
104
+ end
105
+ branch
106
+ end
107
+
108
+ def git_branch_names
109
+ `git branch`.split("\n").collect{|name| (name =~ /^\*\s+(\S.*)\s*$/) ? $1 : name }
110
+ end
111
+
112
+ def git_create_branch(name)
113
+ `git branch #{name}`
114
+ end
115
+
116
+ def git_checkout_branch(name)
117
+ unless git_branch == name
118
+ `git checkout #{name}`
119
+ end
120
+ end
121
+
122
+ def git_squash(from_branch_name)
123
+ `git merge --squash #{from_branch_name}`
124
+ end
125
+
126
+ def git_delete_branch(name)
127
+ `git branch -D #{name}`
128
+ end
129
+
130
+ def git_uncommit
131
+ `git uncommit`
132
+ end
133
+
134
+ def git_stash
135
+ `git stash`
136
+ end
137
+
138
+ def git_stash_pop
139
+ `git stash pop`
140
+ end
141
+
142
+ def git_log(name)
143
+ `git log #{name}`
144
+ end
145
+
146
+ def git_diff(name)
147
+ `git diff #{name}`
148
+ end
149
+
150
+ # def git_config_list_popup
151
+ # window :title => 'Git Repository Config' do
152
+ # stack do
153
+ # para `git config --list`
154
+ # stack(:align => 'center') do
155
+ # button('OK') do
156
+ # close
157
+ # end
158
+ # end
159
+ # end
160
+ # end
161
+ # end
162
+ end
@@ -0,0 +1,10 @@
1
+ # From Matt Payne's slimtimeronshoes
2
+ class Action
3
+
4
+ attr_accessor :app
5
+
6
+ def execute(obj=nil)
7
+
8
+ end
9
+
10
+ end
@@ -0,0 +1,66 @@
1
+ # As shoes does not provide a listview, here's the start
2
+ # of one. Yes, I know, pretty crude...
3
+ module BulletList
4
+
5
+ STAR_BULLET = :star
6
+ CIRCLE_BULLET = :circle
7
+ PLUS_BULLET = :plus
8
+ SPACE_BULLET = :space
9
+
10
+ BULLETS = {
11
+ :star => lambda{|app| app.star(-6,13,5,6,3)},
12
+ :circle => lambda{|app| app.oval(-7,10,7)},
13
+ :plus => lambda do |app|
14
+ # rect(x,y,w,h) NOTE, docs are wrong
15
+ length = 9
16
+ beam = 1
17
+ app.rect(-5,8,beam,length,1) # vertical bar
18
+ app.rect(-9,12,length,beam,1) # horizontal bar
19
+ end,
20
+ :space => lambda {|app| }
21
+ }
22
+
23
+ public
24
+
25
+ # create the bullet list and return as a stack instance
26
+ # values is an array of DirItem instances
27
+ #
28
+ # list_opts is a hash of options for the list itself
29
+ # Example:
30
+ # list_opts => { :bullet => lambda{ |filename| star_bullet } }
31
+ # TODO a lot more docs here
32
+ def bullet_list(values, list_opts={})
33
+ # app.stroke = app.black
34
+ # app.fill = app.red
35
+ app.stack(:margin_bottom => 10) do
36
+ values.each do |dir_item|
37
+ opts = dir_item.options
38
+ slot_opts = {}
39
+ slot_opts[:height] = opts[:height] unless opts[:height].nil?
40
+ slot_opts[:scroll] = opts[:scroll] unless opts[:scroll].nil?
41
+ right = 0
42
+ right += opts[:margin_right] unless opts[:margin_right].nil?
43
+ left = 10
44
+ app.flow(:margin_left => 15) do
45
+ unless list_opts[:bullet].nil?
46
+ # app.debug "list_opts[:bullet] => #{list_opts[:bullet].inspect}.call(#{dir_item})"
47
+ BULLETS[list_opts[:bullet].call(dir_item)].call(app)
48
+ end
49
+ app.stack(slot_opts) do
50
+ if opts[:background]
51
+ app.background(opts[:background], :margin_left => left)
52
+ left += 5
53
+ end
54
+ if opts[:click].nil?
55
+ app.para(dir_item.path, :margin_left => left, :margin_right => right, :margin_bottom => 0)
56
+ else
57
+ app.para(app.link(dir_item.path, :click => opts[:click]), :margin_left => left, :margin_right => right, :margin_bottom => 0)
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
64
+
65
+ end
66
+
@@ -0,0 +1,217 @@
1
+ class DirAction < Action
2
+ include BulletList
3
+
4
+ DIR_PAGE = '/'
5
+ FILE_PAGE = '/file'
6
+ VIEW_AREA_OPTS = {:width => -100, :margin_left => 10, :margin_right => @gutter}
7
+
8
+ def initialize
9
+ super
10
+ @filter_selection = Controller::FILTER_NAMES.first
11
+ @sort_selection = Controller::SORT_NAMES.first
12
+ end
13
+
14
+
15
+ def execute(filename=nil)
16
+ info "dir_action.execute(#{filename})"
17
+ dir_item = @values.select{|item| item.path == filename}.first rescue nil
18
+ @gutter = app.gutter
19
+ app.background app.palegreen
20
+ app.style(Shoes::Link, :underline => false, :stroke => app.blue)
21
+ app.style(Shoes::LinkHover, :underline => true, :stroke => app.red)
22
+
23
+ app.flow(:width => '100%') do
24
+ title_stack = app.stack(:width => '100%') do
25
+ app.background app.gradient(app.rgb(0, 255, 0), app.rgb(225, 255, 0), :angle => 135)
26
+ app.title("Git Shoes", :align => 'center')
27
+ end
28
+ command_widget(dir_item, :width => 100)
29
+ if dir_item.nil?
30
+ @view_area = directory_widget(VIEW_AREA_OPTS)
31
+ else
32
+ @view_area = file_widget(dir_item, VIEW_AREA_OPTS)
33
+ end
34
+ end
35
+ end
36
+
37
+ def command_widget(dir_item, opt={})
38
+ app.stack(opt) do
39
+ app.background app.gradient(app.rgb(0, 255, 0), app.rgb(255, 255, 0), :angle => -35)
40
+ app.para app.link("Files", :click => lambda{app.visit(DIR_PAGE)})
41
+ app.rect(5, 30, 90, 1)
42
+ if Controller.in_repository?
43
+ app.para app.link("Status", :click => lambda{status_action})
44
+ if !dir_item.nil? && (dir_item.modified? || dir_item.candidate?)
45
+ app.para app.link("Add", :click => lambda{add_action})
46
+ else
47
+ app.para "Add"
48
+ end
49
+ if !dir_item.nil? && dir_item.modified?
50
+ app.para app.link("Diff", :click => lambda{diff_action})
51
+ else
52
+ app.para "Diff"
53
+ end
54
+ app.para app.link("Commit", :click => lambda{commit_action})
55
+ app.para "Config"
56
+ else
57
+ # app.para 'Status'
58
+ # app.para "Diff"
59
+ # app.para "Commit"
60
+ # app.para "Branch"
61
+ # app.para "Config"
62
+ end
63
+ end
64
+ end
65
+
66
+ def add_action
67
+ # TODO implement
68
+ puts "need to implement add_action"
69
+ end
70
+
71
+ def diff_action
72
+ # TODO implement
73
+ puts "need to implement diff_action"
74
+ end
75
+
76
+ def commit_action
77
+ # TODO implement
78
+ puts "need to implement commit_action"
79
+ end
80
+
81
+ def status_action
82
+ if Controller.in_repository?
83
+ @view_area.clear {status_widget(VIEW_AREA_OPTS)}
84
+ end
85
+ end
86
+
87
+ def status_widget(opt={})
88
+ app.stack(opt) do
89
+ app.para `git status`
90
+ app.info app.para.text
91
+ end
92
+ end
93
+
94
+ def file_widget(dir_item, opt={})
95
+ app.stack(opt) do
96
+ app.para "filename: #{dir_item.path}"
97
+ # TODO: everything there is to know about the file ;)
98
+ app.para(app.strong('Log'))
99
+ app.flow(:height => 200, :margin_right => @gutter, :scroll => true) do
100
+ app.background app.turquoise
101
+ app.para(dir_item.log)
102
+ end
103
+ if dir_item.modified?
104
+ app.para
105
+ app.para(app.strong('Diff'))
106
+ app.flow(:height => 200, :margin_right => @gutter, :scroll => true) do
107
+ app.background app.turquoise
108
+ app.para dir_item.diff
109
+ end
110
+ end
111
+ end
112
+ end
113
+
114
+ def directory_widget(opt={})
115
+ app.stack(opt) do
116
+ cwd = Controller.cwd
117
+ git_project_dir = Controller.git_project_dir
118
+ if git_project_dir.nil?
119
+ app.caption("Directory", :align => 'center')
120
+ app.para(cwd)
121
+ else
122
+ repository_widget(cwd, git_project_dir)
123
+ end
124
+
125
+ file_selection(git_project_dir)
126
+ end
127
+ end
128
+
129
+ def repository_widget(cwd, git_project_dir)
130
+ app.caption("Git Repository", :align => 'center')
131
+ app.flow do
132
+ app.para "Branch: "
133
+ @branch_listbox = app.list_box(:items => Controller.branches) do |list|
134
+ Controller.branch = list.text
135
+ file_selection_changed
136
+ end
137
+ @branch_listbox.choose(Controller.branch(false))
138
+ app.button("New", :margin_left => 10) # TODO Hook it up
139
+ app.button("Delete", :margin_left => 10) # TODO Hook it up
140
+ app.button("Stash", :margin_left => 10) { Controller.stash }
141
+ app.button("Stash Pop", :margin_left => 10) { Controller.stash_pop }
142
+ end
143
+ app.para("Branch: ", app.strong(Controller.branch(true)))
144
+ app.para(app.strong(git_project_dir, app.em(cwd.gsub(git_project_dir, ''))))
145
+ buf = []
146
+ repository_info = Controller.repository_info
147
+ repository_info.each do |key, value|
148
+ buf << "#{value} #{key} files"
149
+ end
150
+ app.para buf.join(", ")
151
+ end
152
+
153
+ def file_selection(git_project_dir)
154
+ app.flow do
155
+ app.para 'Filter by: '
156
+ if git_project_dir.nil?
157
+ filter_items = Controller::FILTER_NAMES
158
+ unless filter_items.include?(@filter_selection)
159
+ @filter_selection = filter_items.first
160
+ end
161
+ else
162
+ filter_items = Controller::GIT_FILTER_NAMES
163
+ end
164
+ @filter_by = app.list_box(:items => filter_items) do |list|
165
+ file_selection_changed
166
+ end
167
+ app.para ' Sort by: '
168
+ @sort_by = app.list_box(:items => Controller::SORT_NAMES) do |list|
169
+ file_selection_changed
170
+ end
171
+ @listing = app.stack
172
+ @filter_by.choose(@filter_selection)
173
+ @sort_by.choose(@sort_selection)
174
+
175
+ # need to fire a selection changed to get the intial loading of @listing
176
+ file_selection_changed
177
+ end
178
+ end
179
+
180
+ def file_selection_changed
181
+ @filter_selection = @filter_by.text
182
+ @sort_selection = @sort_by.text
183
+ @values = Controller.files do |filename|
184
+ if filename.nil?
185
+ app.visit(DIR_PAGE)
186
+ else
187
+ app.visit(FILE_PAGE + '/' + filename)
188
+ end
189
+ end
190
+ @values = Controller.filter_by(@filter_by.text, @values)
191
+ @values = Controller.sort_by(@sort_by.text, @values)
192
+ @listing.clear {bullet_list(@values, :bullet => fs_bullets)}
193
+ end
194
+
195
+ def fs_bullets
196
+ lambda do |item|
197
+ if item.path == '..'
198
+ bullet = BulletList::SPACE_BULLET
199
+ else
200
+ if item.directory?
201
+ app.fill app.black
202
+ bullet = BulletList::PLUS_BULLET
203
+ else
204
+ if item.modified?
205
+ app.fill app.red
206
+ elsif item.managed?
207
+ app.fill app.lime
208
+ else
209
+ app.fill app.black
210
+ end
211
+ bullet = BulletList::CIRCLE_BULLET
212
+ end
213
+ end
214
+ bullet
215
+ end
216
+ end
217
+ end
@@ -0,0 +1,35 @@
1
+ require 'spec_helper'
2
+
3
+ STATUS_1 = <<END_STATUS_1
4
+ # On branch master
5
+ # Changed but not updated:
6
+ # (use "git add <file>..." to update what will be committed)
7
+ # (use "git checkout -- <file>..." to discard changes in working directory)
8
+ #
9
+ # modified: lib/dvdprofiler2xbmc/controllers/app.rb
10
+ # modified: lib/dvdprofiler2xbmc/models/dvdprofiler_info.rb
11
+ #
12
+ # Untracked files:
13
+ # (use "git add <file>..." to include in what will be committed)
14
+ #
15
+ # t1
16
+ # t2
17
+ no changes added to commit (use "git add" and/or "git commit -a")
18
+ END_STATUS_1
19
+
20
+ describe "GitHelper" do
21
+ it "should parse the status and find modified files" do
22
+ class A
23
+ include GitHelper
24
+ end
25
+ a = A.new
26
+ a.parse_modified_files(STATUS_1).should == ['lib/dvdprofiler2xbmc/controllers/app.rb', 'lib/dvdprofiler2xbmc/models/dvdprofiler_info.rb']
27
+ end
28
+ it "should parse the status and find new files" do
29
+ class A
30
+ include GitHelper
31
+ end
32
+ a = A.new
33
+ a.parse_new_files(STATUS_1).should == ['t1', 't2']
34
+ end
35
+ end
@@ -0,0 +1,9 @@
1
+ require 'spec'
2
+
3
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
4
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
5
+ require 'git_shoes'
6
+
7
+ Spec::Runner.configure do |config|
8
+
9
+ end
metadata ADDED
@@ -0,0 +1,69 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: royw-git_shoes
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Roy Wright
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-04-27 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description:
17
+ email: roy@wright.org
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files:
23
+ - LICENSE
24
+ - README.rdoc
25
+ files:
26
+ - LICENSE
27
+ - README.rdoc
28
+ - Rakefile
29
+ - VERSION.yml
30
+ - lib/controllers/controller.rb
31
+ - lib/loader.rb
32
+ - lib/logger_facade.rb
33
+ - lib/models/dir_item.rb
34
+ - lib/models/directory.rb
35
+ - lib/models/git_helper.rb
36
+ - lib/views/action.rb
37
+ - lib/views/bullet_list.rb
38
+ - lib/views/dir_action.rb
39
+ - spec/git_helper_spec.rb
40
+ - spec/spec_helper.rb
41
+ has_rdoc: true
42
+ homepage: http://github.com/royw/git_shoes
43
+ post_install_message:
44
+ rdoc_options:
45
+ - --charset=UTF-8
46
+ require_paths:
47
+ - lib
48
+ required_ruby_version: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: "0"
53
+ version:
54
+ required_rubygems_version: !ruby/object:Gem::Requirement
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ version: "0"
59
+ version:
60
+ requirements: []
61
+
62
+ rubyforge_project:
63
+ rubygems_version: 1.2.0
64
+ signing_key:
65
+ specification_version: 2
66
+ summary: TODO
67
+ test_files:
68
+ - spec/spec_helper.rb
69
+ - spec/git_helper_spec.rb