royw-git_shoes 0.0.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.
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