twig 1.3 → 1.4

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,9 +1,9 @@
1
1
  class Twig
2
2
  class Branch
3
3
 
4
- EMPTY_PROPERTY_NAME_ERROR = 'Branch property names cannot be empty strings.'
5
- PROPERTY_NAME_FROM_GIT_CONFIG = /^branch\.[^.]+\.([^=]+)=.*$/
6
- RESERVED_BRANCH_PROPERTIES = %w[branch merge rebase remote]
4
+ EMPTY_PROPERTY_NAME_ERROR = 'Branch property names cannot be empty strings.'
5
+ PROPERTY_NAME_FROM_GIT_CONFIG = /^branch\.[^.]+\.([^=]+)=.*$/
6
+ RESERVED_BRANCH_PROPERTY_NAMES = %w[branch merge rebase remote]
7
7
 
8
8
  class EmptyPropertyNameError < ArgumentError
9
9
  def initialize(message = nil)
@@ -15,8 +15,8 @@ class Twig
15
15
 
16
16
  attr_accessor :name, :last_commit_time
17
17
 
18
- def self.all_properties
19
- @_all_properties ||= begin
18
+ def self.all_property_names
19
+ @_all_property_names ||= begin
20
20
  config_lines = Twig.run('git config --list').split("\n")
21
21
 
22
22
  properties = config_lines.map do |line|
@@ -29,7 +29,7 @@ class Twig
29
29
  key_parts.last if key_parts[0] == 'branch' && key_parts.size > 2
30
30
  end.compact
31
31
 
32
- properties.uniq.sort - RESERVED_BRANCH_PROPERTIES
32
+ properties.uniq.sort - RESERVED_BRANCH_PROPERTY_NAMES
33
33
  end
34
34
  end
35
35
 
@@ -46,12 +46,43 @@ class Twig
46
46
  property_name.gsub(/[ _]+/, '')
47
47
  end
48
48
 
49
+ def get_properties(property_names)
50
+ return {} if property_names.empty?
51
+
52
+ property_name_regexps = property_names.map do |property_name|
53
+ property_name = sanitize_property(property_name)
54
+ raise EmptyPropertyNameError if property_name.empty?
55
+ Regexp.escape(property_name)
56
+ end.join('|')
57
+
58
+ git_config_regexp = "branch\.#{name}\.(#{ property_name_regexps })$"
59
+ cmd = %{git config --get-regexp "#{git_config_regexp}"}
60
+
61
+ git_result = Twig.run(cmd) || ''
62
+ git_result_lines = git_result.split("\n")
63
+
64
+ git_result_lines.inject({}) do |properties, line|
65
+ match_data = line.match(/^branch\.#{name}\.([^\s]+)\s+(.*)$/)
66
+
67
+ if match_data
68
+ property_name = match_data[1]
69
+ property_value = match_data[2]
70
+ else
71
+ property_value = ''
72
+ end
73
+
74
+ if property_value.empty?
75
+ properties
76
+ else
77
+ properties.merge(property_name => property_value)
78
+ end
79
+ end
80
+
81
+ end
82
+
49
83
  def get_property(property_name)
50
84
  property_name = sanitize_property(property_name)
51
- raise EmptyPropertyNameError if property_name.empty?
52
-
53
- value = Twig.run("git config branch.#{name}.#{property_name}")
54
- value == '' ? nil : value
85
+ get_properties([property_name])[property_name]
55
86
  end
56
87
 
57
88
  def set_property(property_name, value)
@@ -60,14 +91,15 @@ class Twig
60
91
 
61
92
  if property_name.empty?
62
93
  raise EmptyPropertyNameError
63
- elsif RESERVED_BRANCH_PROPERTIES.include?(property_name)
94
+ elsif RESERVED_BRANCH_PROPERTY_NAMES.include?(property_name)
64
95
  raise ArgumentError,
65
96
  %{Can't modify the reserved property "#{property_name}".}
66
97
  elsif value.empty?
67
98
  raise ArgumentError,
68
99
  %{Can't set a branch property to an empty string.}
69
100
  else
70
- Twig.run(%{git config branch.#{name}.#{property_name} "#{value}"})
101
+ git_config = "branch.#{name}.#{property_name}"
102
+ Twig.run(%{git config #{git_config} "#{value}"})
71
103
  result_body = %{property "#{property_name}" as "#{value}" for branch "#{name}".}
72
104
  if $?.success?
73
105
  "Saved #{result_body}"
@@ -84,7 +116,8 @@ class Twig
84
116
  value = get_property(property_name)
85
117
 
86
118
  if value
87
- Twig.run(%{git config --unset branch.#{name}.#{property_name}})
119
+ git_config = "branch.#{name}.#{property_name}"
120
+ Twig.run(%{git config --unset #{git_config}})
88
121
  %{Removed property "#{property_name}" for branch "#{name}".}
89
122
  else
90
123
  raise MissingPropertyError,
@@ -94,7 +94,7 @@ class Twig
94
94
  end
95
95
 
96
96
  def read_cli_options!(args)
97
- custom_properties = Twig::Branch.all_properties
97
+ custom_properties = Twig::Branch.all_property_names
98
98
 
99
99
  option_parser = OptionParser.new do |opts|
100
100
  opts.banner = help_intro
@@ -186,7 +186,7 @@ class Twig
186
186
  desc =
187
187
  'Lists all branches regardless of other filtering options. ' +
188
188
  'Useful for overriding options in ' +
189
- File.basename(Twig::Options::CONFIG_FILE) + '.'
189
+ File.basename(Twig::Options::CONFIG_PATH) + '.'
190
190
  opts.on('--all', *help_description(desc)) do |pattern|
191
191
  unset_option(:max_days_old)
192
192
  unset_option(:property_except)
@@ -240,15 +240,42 @@ class Twig
240
240
 
241
241
 
242
242
 
243
+ help_separator(opts, 'GitHub integration:')
244
+
245
+ desc = <<-DESC
246
+ Set a custom GitHub API URI prefix, e.g.,
247
+ https://github-enterprise.example.com/api/v3.
248
+ DESC
249
+ opts.on(
250
+ '--github-api-uri-prefix PREFIX',
251
+ *help_description(desc, :add_separator => true)
252
+ ) do |prefix|
253
+ set_option(:github_api_uri_prefix, prefix)
254
+ end
255
+
256
+ desc = <<-DESC
257
+ Set a custom GitHub URI prefix, e.g.,
258
+ https://github-enterprise.example.com.
259
+ DESC
260
+ opts.on(
261
+ '--github-uri-prefix PREFIX',
262
+ *help_description(desc, :add_separator => true)
263
+ ) do |prefix|
264
+ set_option(:github_uri_prefix, prefix)
265
+ end
266
+
267
+
268
+
243
269
  help_separator(opts, help_paragraph(%{
244
270
  You can put your most frequently used options for filtering and
245
- listing branches into #{Twig::Options::CONFIG_FILE}. For example:
271
+ listing branches into #{Twig::Options::CONFIG_PATH}. For example:
246
272
  }), :trailing => '')
247
273
 
248
274
  help_separator(opts, [
249
275
  ' except-branch: staging',
250
276
  ' header-style: green bold',
251
- ' max-days-old: 30'
277
+ ' max-days-old: 30',
278
+ ' reverse: true',
252
279
  ].join("\n"), :trailing => '')
253
280
 
254
281
  help_separator(opts, help_paragraph(%{
@@ -66,6 +66,7 @@ class Twig
66
66
  end
67
67
 
68
68
  def branch_list_headers(header_options = {})
69
+ all_property_names = Twig::Branch.all_property_names
69
70
  branch_indicator_padding = ' ' * CURRENT_BRANCH_INDICATOR.size
70
71
 
71
72
  header_options.merge!(
@@ -80,7 +81,7 @@ class Twig
80
81
  )
81
82
 
82
83
  out = column(' ', :width => date_time_column_width) << column_gutter
83
- out << Twig::Branch.all_properties.map do |property|
84
+ out << all_property_names.map do |property|
84
85
  width = property_column_width(property)
85
86
  column(property, header_options.merge(:width => width)) << column_gutter
86
87
  end.join
@@ -88,7 +89,7 @@ class Twig
88
89
  out << "\n"
89
90
 
90
91
  out << column(' ', :width => date_time_column_width) << column_gutter
91
- out << Twig::Branch.all_properties.map do |property|
92
+ out << all_property_names.map do |property|
92
93
  width = property_column_width(property)
93
94
  underline = '-' * property.size
94
95
  column(underline, header_options.merge(:width => width)) << column_gutter
@@ -100,20 +101,22 @@ class Twig
100
101
  end
101
102
 
102
103
  def branch_list_line(branch)
103
- is_current_branch = branch.name == current_branch_name
104
-
105
- properties = Twig::Branch.all_properties.inject({}) do |result, property_name|
106
- property = (get_branch_property(branch.name, property_name) || '').strip
107
- property = EMPTY_BRANCH_PROPERTY_INDICATOR if property.empty?
108
- property.gsub!(/[\n\r]+/, ' ')
109
- result.merge(property_name => property)
104
+ all_property_names = Twig::Branch.all_property_names
105
+ is_current_branch = branch.name == current_branch_name
106
+
107
+ properties = branch.get_properties(all_property_names)
108
+ properties = all_property_names.inject({}) do |result, property_name|
109
+ property_value = (properties[property_name] || '').strip
110
+ property_value = EMPTY_BRANCH_PROPERTY_INDICATOR if property_value.empty?
111
+ property_value.gsub!(/[\n\r]+/, ' ')
112
+ result.merge(property_name => property_value)
110
113
  end
111
114
 
112
115
  line = column(branch.last_commit_time.to_s, :width => date_time_column_width)
113
116
  line << column_gutter
114
117
 
115
118
  line <<
116
- Twig::Branch.all_properties.map do |property_name|
119
+ all_property_names.map do |property_name|
117
120
  property_value = properties[property_name] || ''
118
121
  width = property_column_width(property_name)
119
122
  column(property_value, :width => width) << column_gutter
@@ -144,7 +147,10 @@ class Twig
144
147
  string_options << WEIGHTS[options[:weight]] if options[:weight]
145
148
  return string if string_options.empty?
146
149
 
147
- "\e[#{string_options.join(';')}m#{string}\e[0m"
150
+ open_format = "\e[#{string_options.join(';')}m"
151
+ close_format = "\e[0m"
152
+
153
+ open_format + string.to_s + close_format
148
154
  end
149
155
 
150
156
  def unformat_string(string)
@@ -1,3 +1,5 @@
1
+ require 'uri'
2
+
1
3
  class Twig
2
4
  class GithubRepo
3
5
  def initialize
@@ -21,7 +23,9 @@ class Twig
21
23
  end
22
24
 
23
25
  def github_repo?
24
- origin_url.include?('github.com')
26
+ gh_url_prefix = 'https://github.com'
27
+ uri = URI.parse(gh_url_prefix)
28
+ origin_url.include?(uri.host)
25
29
  end
26
30
 
27
31
  def username
@@ -1,15 +1,24 @@
1
1
  class Twig
2
2
  module Options
3
3
 
4
- CONFIG_FILE = '~/.twigrc'
4
+ CONFIG_PATH = '~/.twigconfig'
5
+ DEPRECATED_CONFIG_PATH = '~/.twigrc'
5
6
  MIN_PROPERTY_WIDTH = 3
6
7
 
7
8
  def read_config_file!
8
- config_file_path = File.expand_path(Twig::CONFIG_FILE)
9
- return unless File.readable?(config_file_path)
9
+ config_path = File.expand_path(Twig::CONFIG_PATH)
10
+ unless File.readable?(config_path)
11
+ config_path = File.expand_path(Twig::DEPRECATED_CONFIG_PATH)
12
+ if File.readable?(config_path)
13
+ $stderr.puts "DEPRECATED: #{DEPRECATED_CONFIG_PATH} is deprecated. " <<
14
+ "Please rename it to #{CONFIG_PATH}."
15
+ else
16
+ return
17
+ end
18
+ end
10
19
 
11
- File.open(config_file_path) do |f|
12
- opts = f.read.split("\n").inject({}) do |hsh, line|
20
+ File.open(config_path) do |file|
21
+ opts = file.read.split("\n").inject({}) do |hsh, line|
13
22
  line = line.strip
14
23
 
15
24
  if line !~ /^#/
@@ -44,6 +53,12 @@ class Twig
44
53
  property_name = key.sub(/-width$/, '').to_sym
45
54
  set_option(:property_width, property_name => value)
46
55
 
56
+ # GitHub integration:
57
+ when 'github-api-uri-prefix'
58
+ set_option(:github_api_uri_prefix, value)
59
+ when 'github-uri-prefix'
60
+ set_option(:github_uri_prefix, value)
61
+
47
62
  end
48
63
  end
49
64
  end
@@ -58,6 +73,9 @@ class Twig
58
73
  abort %{The branch "#{value}" could not be found.}
59
74
  end
60
75
 
76
+ when :github_api_uri_prefix, :github_uri_prefix
77
+ options[key] = value
78
+
61
79
  when :header_style
62
80
  set_header_style_option(value)
63
81
 
@@ -122,17 +140,18 @@ class Twig
122
140
 
123
141
  property_name_width = property_name.to_s.size
124
142
  property_value = property_value.to_i
143
+ min_property_value = [property_name_width, MIN_PROPERTY_WIDTH].max
125
144
 
126
- if property_value < [property_name_width, MIN_PROPERTY_WIDTH].max
127
- error = %{The value `--#{property_name}-width=#{property_value}` } +
128
- %{is too low. The minimum is }
129
-
130
- if property_value < property_name_width
131
- error << %{#{property_name_width} (width of "#{property_name}").}
132
- elsif property_value < MIN_PROPERTY_WIDTH
133
- error << %{#{MIN_PROPERTY_WIDTH}.}
145
+ if property_value < min_property_value
146
+ min_desc = if property_value < property_name_width
147
+ %{#{property_name_width} (width of "#{property_name}")}
148
+ else
149
+ %{#{MIN_PROPERTY_WIDTH}}
134
150
  end
135
151
 
152
+ error = %{The value `--#{property_name}-width=#{property_value}` } +
153
+ %{is too low. The minimum is #{min_desc}.}
154
+
136
155
  abort error
137
156
  end
138
157
 
@@ -1,3 +1,3 @@
1
1
  class Twig
2
- VERSION = '1.3'
2
+ VERSION = '1.4'
3
3
  end
@@ -5,9 +5,9 @@ describe Twig::Branch do
5
5
  @twig = Twig.new
6
6
  end
7
7
 
8
- describe '.all_properties' do
8
+ describe '.all_property_names' do
9
9
  before :each do
10
- Twig::Branch.instance_variable_set(:@_all_properties, nil)
10
+ Twig::Branch.instance_variable_set(:@_all_property_names, nil)
11
11
  @config = %{
12
12
  user.name=Ron DeVera
13
13
  branch.autosetupmerge=always
@@ -29,7 +29,7 @@ describe Twig::Branch do
29
29
  it 'returns the union of properties for all branches' do
30
30
  Twig.should_receive(:run).with('git config --list').and_return(@config)
31
31
 
32
- result = Twig::Branch.all_properties
32
+ result = Twig::Branch.all_property_names
33
33
  result.should == %w[test0 test1 test2]
34
34
  end
35
35
 
@@ -37,7 +37,7 @@ describe Twig::Branch do
37
37
  @config << 'branch.dot1.dot2.dot3.dotproperty=dotvalue'
38
38
  Twig.should_receive(:run).with('git config --list').and_return(@config)
39
39
 
40
- result = Twig::Branch.all_properties
40
+ result = Twig::Branch.all_property_names
41
41
  result.should == %w[dotproperty test0 test1 test2]
42
42
  end
43
43
 
@@ -45,20 +45,20 @@ describe Twig::Branch do
45
45
  @config << 'branch.eq1=eq2=eq3.eqproperty=eqvalue'
46
46
  Twig.should_receive(:run).with('git config --list').and_return(@config)
47
47
 
48
- result = Twig::Branch.all_properties
48
+ result = Twig::Branch.all_property_names
49
49
  result.should == %w[eqproperty test0 test1 test2]
50
50
  end
51
51
 
52
52
  it 'skips path values with an equal sign but no value' do
53
53
  @config << 'foo_path='
54
54
  Twig.should_receive(:run).with('git config --list').and_return(@config)
55
- result = Twig::Branch.all_properties
55
+ result = Twig::Branch.all_property_names
56
56
  result.should_not include 'foo_path'
57
57
  end
58
58
 
59
59
  it 'memoizes the result' do
60
60
  Twig.should_receive(:run).once.and_return(@config)
61
- 2.times { Twig::Branch.all_properties }
61
+ 2.times { Twig::Branch.all_property_names }
62
62
  end
63
63
  end
64
64
 
@@ -100,50 +100,78 @@ describe Twig::Branch do
100
100
  end
101
101
  end
102
102
 
103
- describe '#get_property' do
103
+ describe '#get_properties' do
104
104
  before :each do
105
105
  @branch = Twig::Branch.new('test')
106
106
  end
107
107
 
108
- it 'returns a property value' do
109
- property = 'test'
110
- value = 'value'
108
+ it 'returns a hash of property names and values' do
109
+ properties = {
110
+ 'test1' => 'value1',
111
+ 'test2' => 'value2'
112
+ }
113
+ git_result = [
114
+ "branch.#{@branch}.test1 value1",
115
+ "branch.#{@branch}.test2 value2"
116
+ ].join("\n")
111
117
  Twig.should_receive(:run).
112
- with(%{git config branch.#{@branch}.#{property}}).
113
- and_return(value)
118
+ with(%{git config --get-regexp "branch.#{@branch}.(test1|test2)$"}).
119
+ and_return(git_result)
114
120
 
115
- result = @branch.get_property(property)
116
- result.should == value
121
+ result = @branch.get_properties(%w[test1 test2])
122
+ result.should == properties
117
123
  end
118
124
 
119
- it 'removes whitespace from branch property names' do
120
- bad_property = ' foo foo '
121
- property = 'foofoo'
122
- value = 'bar'
125
+ it 'returns an empty hash if no property names are given' do
126
+ Twig.should_not_receive(:run)
127
+
128
+ result = @branch.get_properties([])
129
+ result.should == {}
130
+ end
131
+
132
+ it 'returns an empty hash if no matching property names are found' do
133
+ git_result = ''
123
134
  Twig.should_receive(:run).
124
- with(%{git config branch.#{@branch}.#{property}}).
125
- and_return(value)
135
+ with(%{git config --get-regexp "branch.#{@branch}.(test1|test2)$"}).
136
+ and_return(git_result)
126
137
 
127
- result = @branch.get_property(bad_property)
128
- result.should == value
138
+ result = @branch.get_properties(%w[test1 test2])
139
+ result.should == {}
129
140
  end
130
141
 
131
- it 'returns nil if the property value is an empty string' do
132
- property = 'test'
142
+ it 'removes whitespace from property names' do
143
+ bad_property_name = ' foo foo '
144
+ property_name = 'foofoo'
145
+ property_value = 'bar'
146
+ properties = { property_name => property_value }
147
+ git_result = "branch.#{@branch}.#{property_name} #{property_value}"
133
148
  Twig.should_receive(:run).
134
- with(%{git config branch.#{@branch}.#{property}}).
135
- and_return('')
149
+ with(%{git config --get-regexp "branch.#{@branch}.(#{property_name})$"}).
150
+ and_return(git_result)
136
151
 
137
- result = @branch.get_property(property)
138
- result.should == nil
152
+ result = @branch.get_properties([bad_property_name])
153
+ result.should == properties
139
154
  end
140
155
 
141
- it 'raises an error if the property name is an empty string' do
142
- property = ' '
156
+ it 'excludes properties whose values are empty strings' do
157
+ git_result = [
158
+ "branch.#{@branch}.test1 value1",
159
+ "branch.#{@branch}.test2"
160
+ ].join("\n")
161
+ Twig.should_receive(:run).
162
+ with(%{git config --get-regexp "branch.#{@branch}.(test1|test2)$"}).
163
+ and_return(git_result)
164
+
165
+ result = @branch.get_properties(%w[test1 test2])
166
+ result.should == { 'test1' => 'value1' }
167
+ end
168
+
169
+ it 'raises an error if any property name is an empty string' do
170
+ property_name = ' '
143
171
  Twig.should_not_receive(:run)
144
172
 
145
173
  begin
146
- @branch.get_property(property)
174
+ @branch.get_properties(['test1', property_name])
147
175
  rescue Twig::Branch::EmptyPropertyNameError => exception
148
176
  expected_exception = exception
149
177
  end
@@ -152,6 +180,35 @@ describe Twig::Branch do
152
180
  end
153
181
  end
154
182
 
183
+ describe '#get_property' do
184
+ before :each do
185
+ @branch = Twig::Branch.new('test')
186
+ end
187
+
188
+ it 'returns a property value' do
189
+ property = 'test'
190
+ value = 'value'
191
+ @branch.should_receive(:get_properties).
192
+ with([property]).
193
+ and_return(property => value)
194
+
195
+ result = @branch.get_property(property)
196
+ result.should == value
197
+ end
198
+
199
+ it 'removes whitespace from branch property names' do
200
+ bad_property = ' foo foo '
201
+ property = 'foofoo'
202
+ value = 'bar'
203
+ @branch.should_receive(:get_properties).
204
+ with([property]).
205
+ and_return(property => value)
206
+
207
+ result = @branch.get_property(bad_property)
208
+ result.should == value
209
+ end
210
+ end
211
+
155
212
  describe '#set_property' do
156
213
  before :each do
157
214
  @branch = Twig::Branch.new('test')