twig 1.1 → 1.2

Sign up to get free protection for your applications and to get access to all the features.
data/HISTORY.md CHANGED
@@ -1,6 +1,17 @@
1
1
  Twig
2
2
  ====
3
3
 
4
+ 1.2 (2013-03-21)
5
+ ----------------
6
+ * ENHANCEMENT: Add `--only-<property>` and `--except-<property>` options for
7
+ filtering custom properties by value.
8
+ * ENHANCEMENT: Simplify setup for writing GitHub-related Twig subcommands.
9
+ * FIX: Fix showing `twig --help` outside of a Git repository. (GH-16. Thanks
10
+ [ryangreenberg](https://github.com/ryangreenberg)!)
11
+ * FIX: Fix showing `twig --version` outside of a Git repository.
12
+ * FIX: Fix the project's homepage URL in `twig --help`. (GH-17. Thanks
13
+ [ryangreenberg](https://github.com/ryangreenberg)!)
14
+
4
15
  1.1 (2013-03-06)
5
16
  ----------------
6
17
  * ENHANCEMENT: Add branch name tab completion for `-b` and `--branch` options.
data/README.md CHANGED
@@ -52,14 +52,18 @@ Filtering branches
52
52
  ------------------
53
53
 
54
54
  Twig lists all of your branches by default (newest first), but you can filter
55
- them by name and age:
55
+ them by age, name, and custom properties:
56
56
 
57
+ * `twig --max-days-old <age>`:
58
+ Only list branches below a given age
57
59
  * `twig --only-branch <pattern>`:
58
60
  Only list branches whose name matches a given pattern
59
61
  * `twig --except-branch <pattern>`:
60
62
  Don't list branches whose name matches a given pattern
61
- * `twig --max-days-old <age>`:
62
- Only list branches below a given age
63
+ * `twig --only-<property> <pattern>`:
64
+ Only list branches with a given property that matches a given pattern
65
+ * `twig --except-<property> <pattern>`:
66
+ Don't list branches with a given property that matches a given pattern
63
67
  * `twig --all`:
64
68
  List all branches regardless of other filtering options
65
69
 
data/bin/twig CHANGED
@@ -3,7 +3,11 @@
3
3
  require File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib', 'twig'))
4
4
 
5
5
  twig = Twig.new
6
- abort unless twig.repo?
6
+ repo_required = ARGV != ['--help'] && ARGV != ['help'] && ARGV != ['--version']
7
+
8
+ if repo_required && !twig.repo?
9
+ abort "Current directory is not a git repository."
10
+ end
7
11
 
8
12
  # Gettin' twiggy wit' it.
9
13
  twig.read_config_file!
@@ -4,37 +4,10 @@
4
4
  #
5
5
  # Author: Ron DeVera <http://rondevera.com>
6
6
 
7
- class TwigGithubRepo
8
- def initialize
9
- if origin_url.empty? || username.empty? || repository.empty?
10
- abort_for_non_github_repo
11
- end
7
+ require 'rubygems'
8
+ require 'twig/github'
12
9
 
13
- yield(self)
14
- end
15
-
16
- def origin_url
17
- @origin_url ||= `git config remote.origin.url`.strip
18
- end
19
-
20
- def origin_url_parts
21
- @origin_url_parts ||= origin_url.split(/[\/:]/)
22
- end
23
-
24
- def username
25
- @username ||= origin_url_parts[-2] || ''
26
- end
27
-
28
- def repository
29
- @repo ||= origin_url_parts[-1].sub(/\.git$/, '') || ''
30
- end
31
-
32
- def abort_for_non_github_repo
33
- abort 'This does not appear to be a GitHub repository.'
34
- end
35
- end
36
-
37
- TwigGithubRepo.new do |gh_repo|
10
+ Twig::GithubRepo.new do |gh_repo|
38
11
  url = "https://github.com/#{gh_repo.username}/#{gh_repo.repository}"
39
12
  puts "GitHub URL: #{url}"
40
13
  `which open && open #{url}`
@@ -11,37 +11,7 @@
11
11
  require 'rubygems'
12
12
  require 'twig'
13
13
 
14
- class TwigGithubRepo
15
- def initialize
16
- if origin_url.empty? || username.empty? || repository.empty?
17
- abort_for_non_github_repo
18
- end
19
-
20
- yield(self)
21
- end
22
-
23
- def origin_url
24
- @origin_url ||= `git config remote.origin.url`.strip
25
- end
26
-
27
- def origin_url_parts
28
- @origin_url_parts ||= origin_url.split(/[\/:]/)
29
- end
30
-
31
- def username
32
- @username ||= origin_url_parts[-2] || ''
33
- end
34
-
35
- def repository
36
- @repo ||= origin_url_parts[-1].sub(/\.git$/, '') || ''
37
- end
38
-
39
- def abort_for_non_github_repo
40
- abort 'This does not appear to be a GitHub repository.'
41
- end
42
- end
43
-
44
- TwigGithubRepo.new do |gh_repo|
14
+ Twig::GithubRepo.new do |gh_repo|
45
15
  twig = Twig.new
46
16
  twig.read_cli_options!(ARGV)
47
17
  branch_name = twig.options[:branch] || twig.current_branch_name
@@ -10,41 +10,11 @@ require 'json'
10
10
  require 'net/https'
11
11
  require 'uri'
12
12
 
13
- class TwigGithubRepo
14
- def initialize
15
- if origin_url.empty? || username.empty? || repository.empty?
16
- abort_for_non_github_repo
17
- end
18
-
19
- yield(self)
20
- end
21
-
22
- def origin_url
23
- @origin_url ||= `git config remote.origin.url`.strip
24
- end
25
-
26
- def origin_url_parts
27
- @origin_url_parts ||= origin_url.split(/[\/:]/)
28
- end
29
-
30
- def username
31
- @username ||= origin_url_parts[-2] || ''
32
- end
33
-
34
- def repository
35
- @repo ||= origin_url_parts[-1].sub(/\.git$/, '') || ''
36
- end
37
-
38
- def abort_for_non_github_repo
39
- abort 'This does not appear to be a GitHub repository.'
40
- end
41
- end
42
-
43
13
  twig = Twig.new
44
14
  twig.read_config_file!
45
15
  twig.read_cli_options!(ARGV)
46
16
 
47
- TwigGithubRepo.new do |gh_repo|
17
+ Twig::GithubRepo.new do |gh_repo|
48
18
  $stdout.sync = true
49
19
  print 'Getting latest states for GitHub issues...'
50
20
 
@@ -26,7 +26,7 @@ class Twig
26
26
  end
27
27
 
28
28
  def repo?
29
- Twig.run('git rev-parse')
29
+ Twig.run('git rev-parse 2>&1')
30
30
  $?.success?
31
31
  end
32
32
 
@@ -57,15 +57,30 @@ class Twig
57
57
  max_seconds_old = options[:max_days_old] * 86400 if options[:max_days_old]
58
58
 
59
59
  branches.select do |branch|
60
- if max_seconds_old
61
- seconds_old = now.to_i - branch.last_commit_time.to_i
62
- next if seconds_old > max_seconds_old
60
+ catch :skip_branch do
61
+ if max_seconds_old
62
+ seconds_old = now.to_i - branch.last_commit_time.to_i
63
+ next if seconds_old > max_seconds_old
64
+ end
65
+
66
+ (options[:property_except] || {}).each do |property_name, property_value|
67
+ if property_name == :branch
68
+ throw :skip_branch if branch.name =~ property_value
69
+ elsif branch.get_property(property_name.to_s) =~ property_value
70
+ throw :skip_branch
71
+ end
72
+ end
73
+
74
+ (options[:property_only] || {}).each do |property_name, property_value|
75
+ if property_name == :branch
76
+ throw :skip_branch if branch.name !~ property_value
77
+ elsif branch.get_property(property_name.to_s) !~ property_value
78
+ throw :skip_branch
79
+ end
80
+ end
81
+
82
+ true
63
83
  end
64
-
65
- next if options[:branch_except] && branch.name =~ options[:branch_except]
66
- next if options[:branch_only] && branch.name !~ options[:branch_only]
67
-
68
- true
69
84
  end
70
85
  end
71
86
 
@@ -19,7 +19,7 @@ class Twig
19
19
 
20
20
  #{intro}
21
21
 
22
- https://rondevera.github.com/twig
22
+ http://rondevera.github.com/twig
23
23
 
24
24
  BANNER
25
25
  end
@@ -37,8 +37,8 @@ class Twig
37
37
  # Split words into lines
38
38
  while words.any?
39
39
  current_word = words.shift
40
- current_word_size = formatted_string_display_size(current_word)
41
- last_line_size = lines.last && formatted_string_display_size(lines.last)
40
+ current_word_size = unformat_string(current_word).size
41
+ last_line_size = lines.last && unformat_string(lines.last).size
42
42
 
43
43
  if last_line_size && (last_line_size + current_word_size + 1 <= width)
44
44
  lines.last << ' ' << current_word
@@ -82,7 +82,26 @@ class Twig
82
82
 
83
83
  desc = 'Show this help content.'
84
84
  opts.on('--help', *help_description(desc)) do
85
- puts opts; exit
85
+ summary_lines = opts.to_a
86
+
87
+ # Filter out `--only-PROPERTY` lines
88
+ summary_lines.each do |line|
89
+ is_custom_property_only = (
90
+ line.include?('--only-') &&
91
+ !line.include?('--only-branch') &&
92
+ !line.include?('--only-PROPERTY')
93
+ )
94
+ is_custom_property_except = (
95
+ line.include?('--except-') &&
96
+ !line.include?('--except-branch') &&
97
+ !line.include?('--except-PROPERTY')
98
+ )
99
+ unless is_custom_property_only || is_custom_property_except
100
+ puts line
101
+ end
102
+ end
103
+
104
+ exit
86
105
  end
87
106
 
88
107
  desc = 'Show Twig version.'
@@ -94,37 +113,62 @@ class Twig
94
113
 
95
114
  help_separator(opts, 'Filtering branches:')
96
115
 
116
+ desc = 'Only list branches below a given age.'
117
+ opts.on(
118
+ '--max-days-old AGE', *help_description(desc, :add_separator => true)
119
+ ) do |age|
120
+ set_option(:max_days_old, age)
121
+ end
122
+
97
123
  desc = 'Only list branches whose name matches a given pattern.'
98
124
  opts.on(
99
125
  '--only-branch PATTERN',
100
126
  *help_description(desc, :add_separator => true)
101
127
  ) do |pattern|
102
- set_option(:branch_only, pattern)
128
+ set_option(:property_only, :branch => pattern)
103
129
  end
104
130
 
105
131
  desc = 'Do not list branches whose name matches a given pattern.'
106
132
  opts.on(
107
133
  '--except-branch PATTERN',
108
- *help_description(desc, :add_separator => true)
134
+ *help_description(desc, :add_separator => false)
135
+ # `:add_separator => false` skips the extra line generated by the
136
+ # custom property filters below.
109
137
  ) do |pattern|
110
- set_option(:branch_except, pattern)
138
+ set_option(:property_except, :branch => pattern)
111
139
  end
112
140
 
113
- desc = 'Only list branches below a given age.'
114
- opts.on(
115
- '--max-days-old AGE', *help_description(desc, :add_separator => true)
116
- ) do |age|
117
- set_option(:max_days_old, age)
141
+ custom_properties = Twig::Branch.all_properties
142
+ custom_properties.each do |property_name|
143
+ opts.on("--only-#{property_name} PATTERN") do |pattern|
144
+ set_option(:property_only, property_name.to_sym => pattern)
145
+ end
146
+
147
+ opts.on("--except-#{property_name} PATTERN") do |pattern|
148
+ set_option(:property_except, property_name.to_sym => pattern)
149
+ end
118
150
  end
119
151
 
152
+ custom_properties_desc_lines = [
153
+ ['--only-PROPERTY PATTERN', 'Only list branches with a given property'],
154
+ ['', 'that matches a given pattern.'],
155
+ ['', ''],
156
+ ['--except-PROPERTY PATTERN', 'Do not list branches with a given property'],
157
+ ['', 'that matches a given pattern.']
158
+ ]
159
+ custom_properties_desc = custom_properties_desc_lines.inject('') do |desc, line_parts|
160
+ desc + sprintf(' %-29s', line_parts[0]) + line_parts[1] + "\n"
161
+ end
162
+ help_separator(opts, custom_properties_desc, :trailing => "\n")
163
+
120
164
  desc =
121
- 'Lists all branches regardless of age or name options. ' +
165
+ 'Lists all branches regardless of other filtering options. ' +
122
166
  'Useful for overriding options in ' +
123
167
  File.basename(Twig::Options::CONFIG_FILE) + '.'
124
168
  opts.on('--all', *help_description(desc)) do |pattern|
125
169
  unset_option(:max_days_old)
126
- unset_option(:branch_except)
127
- unset_option(:branch_only)
170
+ unset_option(:property_except)
171
+ unset_option(:property_only)
128
172
  end
129
173
 
130
174
 
@@ -171,7 +215,11 @@ class Twig
171
215
 
172
216
  option_parser.parse!(args)
173
217
  rescue OptionParser::InvalidOption, OptionParser::MissingArgument => exception
174
- puts exception.to_s
218
+ abort_for_option_exception(exception)
219
+ end
220
+
221
+ def abort_for_option_exception(exception)
222
+ puts exception.message
175
223
  puts 'For a list of options, run `twig --help`.'
176
224
  exit
177
225
  end
@@ -200,36 +248,49 @@ class Twig
200
248
  # Get/set branch property
201
249
  if property_value
202
250
  # `$ twig <key> <value>`
203
- begin
204
- puts set_branch_property(branch_name, property_name, property_value)
205
- rescue ArgumentError, RuntimeError => exception
206
- abort exception.message
207
- end
251
+ set_branch_property_for_cli(branch_name, property_name, property_value)
208
252
  else
209
253
  # `$ twig <key>`
210
- begin
211
- value = get_branch_property(branch_name, property_name)
212
- if value
213
- puts value
214
- else
215
- abort %{The branch "#{branch_name}" does not have the property "#{property_name}".}
216
- end
217
- rescue ArgumentError => exception
218
- abort exception.message
219
- end
254
+ get_branch_property_for_cli(branch_name, property_name)
220
255
  end
221
256
  elsif property_to_unset
222
257
  # `$ twig --unset <key>`
223
- begin
224
- puts unset_branch_property(branch_name, property_to_unset)
225
- rescue ArgumentError, Twig::Branch::MissingPropertyError => exception
226
- abort exception.message
227
- end
258
+ unset_branch_property_for_cli(branch_name, property_to_unset)
228
259
  else
229
260
  # `$ twig`
230
261
  puts list_branches
231
262
  end
232
263
  end
233
264
 
265
+ def get_branch_property_for_cli(branch_name, property_name)
266
+ begin
267
+ value = get_branch_property(branch_name, property_name)
268
+ if value
269
+ puts value
270
+ else
271
+ raise Twig::Branch::MissingPropertyError,
272
+ %{The branch "#{branch_name}" does not have the property "#{property_name}".}
273
+ end
274
+ rescue ArgumentError, Twig::Branch::MissingPropertyError => exception
275
+ abort exception.message
276
+ end
277
+ end
278
+
279
+ def set_branch_property_for_cli(branch_name, property_name, property_value)
280
+ begin
281
+ puts set_branch_property(branch_name, property_name, property_value)
282
+ rescue ArgumentError, RuntimeError => exception
283
+ abort exception.message
284
+ end
285
+ end
286
+
287
+ def unset_branch_property_for_cli(branch_name, property_name)
288
+ begin
289
+ puts unset_branch_property(branch_name, property_name)
290
+ rescue ArgumentError, Twig::Branch::MissingPropertyError => exception
291
+ abort exception.message
292
+ end
293
+ end
294
+
234
295
  end
235
296
  end
@@ -125,8 +125,8 @@ class Twig
125
125
  "\e[#{string_options.join(';')}m#{string}\e[0m"
126
126
  end
127
127
 
128
- def formatted_string_display_size(string)
129
- string.gsub(/\e\[[0-9]+(;[0-9]+)?m/, '').size
128
+ def unformat_string(string)
129
+ string.gsub(/\e\[[0-9]+(;[0-9]+)?m/, '')
130
130
  end
131
131
  end # module Display
132
132
  end
@@ -0,0 +1,36 @@
1
+ class Twig
2
+ class GithubRepo
3
+ def self.run(command)
4
+ # Duplicated from `Twig.run` for making lightweight subcommands.
5
+ `#{command}`.strip
6
+ end
7
+
8
+ def initialize
9
+ if origin_url.empty? || username.empty? || repository.empty?
10
+ abort_for_non_github_repo
11
+ end
12
+
13
+ yield(self)
14
+ end
15
+
16
+ def origin_url
17
+ @origin_url ||= Twig::GithubRepo.run('git config remote.origin.url')
18
+ end
19
+
20
+ def origin_url_parts
21
+ @origin_url_parts ||= origin_url.split(/[\/:]/)
22
+ end
23
+
24
+ def username
25
+ @username ||= origin_url_parts[-2] || ''
26
+ end
27
+
28
+ def repository
29
+ @repo ||= origin_url_parts[-1].sub(/\.git$/, '') || ''
30
+ end
31
+
32
+ def abort_for_non_github_repo
33
+ abort 'This does not appear to be a GitHub repository.'
34
+ end
35
+ end
36
+ end