jtag 0.1.7 → 0.1.15
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/bin/jtag +313 -60
- data/lib/jtag.rb +3 -3
- data/lib/jtag/config_files/config.yml +2 -0
- data/lib/jtag/jekylltag.rb +83 -16
- data/lib/jtag/version.rb +1 -1
- metadata +44 -50
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 3e151ce3931cae97e33b988fbb68d8f11d061b6082533675c9d77523a4a8f0d5
|
4
|
+
data.tar.gz: 4533ce25468f2c79e6a847656a60d73e6bd5c262339604d7be95932cf60e6f29
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: afe50224a4bd699348a3fe249030b2b7cd990c0a3862fa8362be80ee27bf1a59b348af3fa4e451ec24a021a4a8278fd8cae55a1dac46abfdacad14773b461cfb
|
7
|
+
data.tar.gz: 2298a87e7d680f2a9a2f411af69106095ca3c9d2c5b181d8ca8eb96cb467911e9ed8efe0cb70a1c51bdf80f9d1f62a47e8ca8f48fd29c6c457af885ba6e258bd
|
data/bin/jtag
CHANGED
@@ -22,19 +22,33 @@ end
|
|
22
22
|
desc 'Debug level'
|
23
23
|
default_value '0'
|
24
24
|
arg_name 'debug_level'
|
25
|
-
flag [:d,:debug]
|
25
|
+
flag [:d,:debug], :must_match => /\d+/, :type => Integer, :default_value => 0
|
26
26
|
|
27
27
|
desc 'Run silently'
|
28
|
-
switch [:s
|
28
|
+
switch [:s,:silent]
|
29
29
|
|
30
|
-
desc
|
30
|
+
desc 'Perform case-insensitive matches and searches'
|
31
|
+
switch [:i,:case_insensitive]
|
32
|
+
|
33
|
+
desc "Test (dry run, don't update files)"
|
31
34
|
long_desc "Run all commands and show results on the command line, but don't overwrite/update any files"
|
32
35
|
default_value false
|
33
|
-
switch [:t
|
36
|
+
switch [:t,:test]
|
34
37
|
|
35
38
|
def console_log(msg="", options={})
|
36
|
-
return if @silent
|
37
39
|
err = options[:err] || false
|
40
|
+
options[:log] ||= false
|
41
|
+
|
42
|
+
if options[:log]
|
43
|
+
if err
|
44
|
+
@log.warn(msg)
|
45
|
+
else
|
46
|
+
@log.info(msg)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
return if @silent
|
51
|
+
|
38
52
|
unless err
|
39
53
|
$stdout.puts msg
|
40
54
|
else
|
@@ -93,10 +107,10 @@ desc 'List tags, optionally filter for keywords/regular expressions (OR)'
|
|
93
107
|
long_desc 'This command can be used to find the exact format for a given tag to keep spaces, underscores, capitalization and pluralization consistent'
|
94
108
|
arg_name 'keyword', :multiple
|
95
109
|
command :search do |c|
|
96
|
-
c.desc 'Format to use when outputting tags to console: list, json, csv or yaml. Defaults to yaml.'
|
110
|
+
c.desc 'Format to use when outputting tags to console: list, json, plist, csv or yaml. Defaults to yaml.'
|
97
111
|
c.arg_name 'output_format'
|
98
112
|
c.default_value 'yaml'
|
99
|
-
c.flag [:f,:format], :must_match => /^(csv|list|yaml|json)$/i, :type => String
|
113
|
+
c.flag [:f,:format], :must_match => /^(csv|list|yaml|json|plist)$/i, :type => String
|
100
114
|
|
101
115
|
c.desc 'Include tag counts'
|
102
116
|
c.arg_name 'counts'
|
@@ -106,8 +120,8 @@ command :search do |c|
|
|
106
120
|
c.action do |global_options,options,args|
|
107
121
|
tags = @jt.get_tags({:counts => true})
|
108
122
|
if args.length > 0
|
123
|
+
re = args.join("|")
|
109
124
|
tags.delete_if {|tag|
|
110
|
-
re = args.join("|")
|
111
125
|
if tag && tag['name'] =~ /(#{re})/i
|
112
126
|
false
|
113
127
|
else
|
@@ -119,7 +133,7 @@ command :search do |c|
|
|
119
133
|
else
|
120
134
|
tags.map! {|tag| tag['name'] }
|
121
135
|
end
|
122
|
-
output_tags(tags,options[:format])
|
136
|
+
output_tags(tags,{ :format => options[:format] })
|
123
137
|
else
|
124
138
|
tags.delete_if {|tag| !tag }
|
125
139
|
if options[:c]
|
@@ -127,18 +141,199 @@ command :search do |c|
|
|
127
141
|
else
|
128
142
|
tags.map! {|tag| tag['name'] }
|
129
143
|
end
|
130
|
-
output_tags(tags,options[:format])
|
144
|
+
output_tags(tags,{ :format => options[:format] })
|
131
145
|
end
|
132
146
|
end
|
133
147
|
end
|
134
148
|
|
149
|
+
desc 'List posts with tag(s)'
|
150
|
+
arg_name 'tags', :multiple
|
151
|
+
command :posts_tagged do |c|
|
152
|
+
c.desc 'Boolean operator for multiple tags (AND/OR/NOT)'
|
153
|
+
c.arg_name 'bool'
|
154
|
+
c.default_value 'OR'
|
155
|
+
c.flag [:b,:bool], :must_match => /(AND|OR|NOT)/i, :type => String
|
156
|
+
|
157
|
+
c.desc 'Format to use when outputting file list: list, json, plist, csv or yaml. Defaults to list.'
|
158
|
+
c.arg_name 'output_format'
|
159
|
+
c.default_value 'list'
|
160
|
+
c.flag [:f,:format], :must_match => /^(csv|list|yaml|json|plist)$/, :type => String
|
161
|
+
|
162
|
+
c.desc 'If output format is list, print without newlines.'
|
163
|
+
c.switch [:print0]
|
164
|
+
|
165
|
+
c.action do |global_options,options,args|
|
166
|
+
bool = options[:bool].upcase
|
167
|
+
files = []
|
168
|
+
tags = []
|
169
|
+
matches = []
|
170
|
+
args.length.times do
|
171
|
+
arg = args.pop
|
172
|
+
if File.exists?(arg)
|
173
|
+
files.push(arg)
|
174
|
+
else
|
175
|
+
tags.push(arg)
|
176
|
+
end
|
177
|
+
end
|
178
|
+
if files.empty?
|
179
|
+
if @jt.default_post_location && File.exists?(File.dirname(@jt.default_post_location))
|
180
|
+
files = Dir.glob(@jt.default_post_location)
|
181
|
+
end
|
182
|
+
end
|
183
|
+
exit_now! "No valid filename in arguments" if files.empty?
|
184
|
+
files.each {|file|
|
185
|
+
if File.exists?(file)
|
186
|
+
post_tags = @jt.post_tags(file)
|
187
|
+
|
188
|
+
if bool == "AND"
|
189
|
+
matched = 0
|
190
|
+
tags.each {|tag|
|
191
|
+
matched += 1 if post_tags.include?(tag)
|
192
|
+
}
|
193
|
+
matches.push(file) if matched == tags.length
|
194
|
+
elsif bool == "NOT"
|
195
|
+
matched = false
|
196
|
+
tags.each {|tag|
|
197
|
+
matched = true if post_tags.include?(tag)
|
198
|
+
}
|
199
|
+
matches.push(file) unless matched
|
200
|
+
else
|
201
|
+
tags.each {|tag|
|
202
|
+
if post_tags.include?(tag)
|
203
|
+
matches.push(file) unless matches.include?(file)
|
204
|
+
end
|
205
|
+
}
|
206
|
+
end
|
207
|
+
else
|
208
|
+
raise "File not found: #{file}"
|
209
|
+
end
|
210
|
+
}
|
211
|
+
|
212
|
+
search_string = tags.join(" #{bool} ")
|
213
|
+
if matches.empty?
|
214
|
+
console_log "No matching files found for #{search_string}"
|
215
|
+
else
|
216
|
+
console_log "(#{search_string})", {:err => true}
|
217
|
+
output_tags(matches, { :format => options[:format], :print0 => options[:print0], :grouping => "files" })
|
218
|
+
end
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
desc 'Show tags with fewer than X posts attached to them, optionally removing them from specified posts'
|
223
|
+
arg_name 'file_pattern', :multiple
|
224
|
+
command :loners do |c|
|
225
|
+
c.desc 'Format to use when outputting tags to console: list, json, plist, csv or yaml. Defaults to yaml.'
|
226
|
+
c.arg_name 'output_format'
|
227
|
+
c.default_value 'yaml'
|
228
|
+
c.flag [:f,:format], :must_match => /^(csv|list|yaml|json|plist)$/, :type => String
|
229
|
+
|
230
|
+
c.desc 'Upper limit for how many posts a tag can be attached to and still be a loner'
|
231
|
+
c.arg_name 'max'
|
232
|
+
c.default_value '2'
|
233
|
+
c.flag [:m,:max], :default_value => 2, :must_match => /^\d+$/
|
234
|
+
|
235
|
+
c.desc "Remove tags with fewer than X posts attached"
|
236
|
+
c.switch [:r,:remove], :default_value => false
|
237
|
+
|
238
|
+
c.desc "Display output without attached occurence counts"
|
239
|
+
c.switch [:no_counts], :default_value => false
|
240
|
+
|
241
|
+
c.desc 'Output a file list of tags that can be edited and passed back in for removing'
|
242
|
+
c.arg_name 'filename'
|
243
|
+
c.flag [:e,:edit], :default_value => false, :type => String
|
244
|
+
|
245
|
+
c.action do |global_options,options,args|
|
246
|
+
max = options[:m].to_i
|
247
|
+
loner_tags = @jt.get_tags({:counts => true})
|
248
|
+
loner_tags.delete_if { |tag|
|
249
|
+
tag.class == FalseClass || tag['count'] > max
|
250
|
+
}
|
251
|
+
loner_tags.sort_by! {|tag| tag['count']}
|
252
|
+
|
253
|
+
exit_now! "No tags matched the criteria" if loner_tags.empty? || loner_tags.nil?
|
254
|
+
|
255
|
+
if options[:e]
|
256
|
+
path = File.expand_path(options[:e])
|
257
|
+
while File.exists?(path)
|
258
|
+
if path =~ /(\d+)(\.[^\.]+?)?$/
|
259
|
+
path.sub!(/(\d+)(\.[^\.]+?)?$/) do |m|
|
260
|
+
$1.next! + $2
|
261
|
+
end
|
262
|
+
else
|
263
|
+
path.sub!(/(\.[^\.]+?)?$/,'01\1')
|
264
|
+
end
|
265
|
+
end
|
266
|
+
File.open(path, 'w+') do |f|
|
267
|
+
f.puts "# Edit this file to remove tags you want to keep,"
|
268
|
+
f.puts "# then run `jtag remove -p '#{path}' [/path/to/posts/*.md]`"
|
269
|
+
f.puts "# to remove any tags left in the file."
|
270
|
+
f.puts "#"
|
271
|
+
f.puts "# The post counts are included for your convenience, and will"
|
272
|
+
f.puts "# be automatically ignored when reading the list back in."
|
273
|
+
f.puts "#"
|
274
|
+
f.puts "# Lines beginning with a # are comments (ignored), but you probably figured that out."
|
275
|
+
loner_tags.each{ |t|
|
276
|
+
f.printf "% 3d |\t%s\n", t['count'], t['name']
|
277
|
+
}
|
278
|
+
end
|
279
|
+
|
280
|
+
console_log "A list of results and instructions for use have been written to #{path}."
|
281
|
+
if ENV['EDITOR']
|
282
|
+
console_log
|
283
|
+
print "Would you like to open the file in #{ENV['EDITOR']} now? (y/N) "
|
284
|
+
input = STDIN.gets
|
285
|
+
if input =~ /^y/i
|
286
|
+
system "#{ENV['EDITOR']} '#{path}'"
|
287
|
+
end
|
288
|
+
end
|
289
|
+
elsif options[:r]
|
290
|
+
files = []
|
291
|
+
args.length.times do
|
292
|
+
arg = args.pop
|
293
|
+
files.push(arg) if File.exists?(arg)
|
294
|
+
end
|
295
|
+
if files.empty?
|
296
|
+
if @jt.default_post_location && File.exists?(File.dirname(@jt.default_post_location))
|
297
|
+
files = Dir.glob(@jt.default_post_location)
|
298
|
+
end
|
299
|
+
end
|
300
|
+
exit_now! "No valid filename in arguments" if files.empty?
|
301
|
+
files.each {|file|
|
302
|
+
tags = @jt.post_tags(file)
|
303
|
+
loner_tags.each { |d|
|
304
|
+
tags.delete_if { |tag|
|
305
|
+
if global_options[:i]
|
306
|
+
tag.downcase == d.downcase
|
307
|
+
else
|
308
|
+
tag == d
|
309
|
+
end
|
310
|
+
}
|
311
|
+
}
|
312
|
+
unless global_options[:t]
|
313
|
+
@jt.update_file_tags(file,tags)
|
314
|
+
console_log "Updated tags for #{file}", :log => true
|
315
|
+
end
|
316
|
+
|
317
|
+
console_log
|
318
|
+
console_log File.basename(file) + ":"
|
319
|
+
output_tags(tags, :format => options[:format], :filename => file )
|
320
|
+
}
|
321
|
+
else
|
322
|
+
output_tags(loner_tags.map{|tag|
|
323
|
+
count = options[:no_counts] ? "" : " (#{tag['count']})"
|
324
|
+
"#{tag['name']}#{count}"}, :format => options[:format] )
|
325
|
+
end
|
326
|
+
end
|
327
|
+
end
|
328
|
+
|
329
|
+
|
135
330
|
desc 'Show the current tags for posts'
|
136
|
-
arg_name '
|
331
|
+
arg_name 'file_pattern', :multiple
|
137
332
|
command :tags do |c|
|
138
|
-
c.desc 'Format to use when outputting tags to console: list, json, csv or yaml. Defaults to yaml.'
|
333
|
+
c.desc 'Format to use when outputting tags to console: list, json, plist, csv or yaml. Defaults to yaml.'
|
139
334
|
c.arg_name 'output_format'
|
140
335
|
c.default_value 'yaml'
|
141
|
-
c.flag [:f,:format], :must_match => /^(csv|list|yaml|json)$/, :type => String
|
336
|
+
c.flag [:f,:format], :must_match => /^(csv|list|yaml|json|plist)$/, :type => String
|
142
337
|
|
143
338
|
c.action do |global_options,options,args|
|
144
339
|
|
@@ -151,7 +346,7 @@ command :tags do |c|
|
|
151
346
|
if tags.empty? || tags.nil?
|
152
347
|
console_log "No tags in post", {:err => true}
|
153
348
|
else
|
154
|
-
output_tags(tags,options[:format])
|
349
|
+
output_tags(tags,{ :format => options[:format] })
|
155
350
|
end
|
156
351
|
end
|
157
352
|
args.each{|file|
|
@@ -164,7 +359,7 @@ command :tags do |c|
|
|
164
359
|
if tags.empty? || tags.nil?
|
165
360
|
console_log "No tags in post", {:err => true}
|
166
361
|
else
|
167
|
-
output_tags(tags,options[:format])
|
362
|
+
output_tags(tags,{ :format => options[:format], :filename => file })
|
168
363
|
end
|
169
364
|
else
|
170
365
|
raise "File not found: #{file}"
|
@@ -175,12 +370,12 @@ end
|
|
175
370
|
|
176
371
|
|
177
372
|
desc 'Sort the existing tags for posts'
|
178
|
-
arg_name '
|
373
|
+
arg_name 'file_pattern', :multiple
|
179
374
|
command :sort do |c|
|
180
|
-
c.desc 'Format to use when outputting tags to console: list, json, csv or yaml. Defaults to yaml.'
|
375
|
+
c.desc 'Format to use when outputting tags to console: list, json, plist, csv or yaml. Defaults to yaml.'
|
181
376
|
c.arg_name 'output_format'
|
182
377
|
c.default_value 'yaml'
|
183
|
-
c.flag [:f,:format], :must_match => /^(csv|list|yaml|json)$/, :type => String
|
378
|
+
c.flag [:f,:format], :must_match => /^(csv|list|yaml|json|plist)$/, :type => String
|
184
379
|
|
185
380
|
c.action do |global_options,options,args|
|
186
381
|
args.each{|file|
|
@@ -190,14 +385,13 @@ command :sort do |c|
|
|
190
385
|
unless global_options[:t]
|
191
386
|
@jt.update_file_tags(file, tags)
|
192
387
|
end
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
end
|
388
|
+
console_log
|
389
|
+
console_log File.basename(file) + ":"
|
390
|
+
|
197
391
|
if tags.empty? || tags.nil?
|
198
392
|
console_log "No tags in post", {:err => true}
|
199
393
|
else
|
200
|
-
output_tags(tags,options[:format])
|
394
|
+
output_tags(tags,{ :format => options[:format], :filename => file })
|
201
395
|
end
|
202
396
|
}
|
203
397
|
end
|
@@ -207,10 +401,10 @@ desc 'Merge multiple tags into one'
|
|
207
401
|
long_desc 'Scans the specified posts for any of the tags, merging any found into the last one in the list'
|
208
402
|
arg_name 'tags to merge merge_tag'
|
209
403
|
command :merge do |c|
|
210
|
-
c.desc 'Format to use when outputting tags to console: list, json, csv or yaml. Defaults to yaml.'
|
404
|
+
c.desc 'Format to use when outputting tags to console: list, json, plist, csv or yaml. Defaults to yaml.'
|
211
405
|
c.arg_name 'output_format'
|
212
406
|
c.default_value 'yaml'
|
213
|
-
c.flag [:f,:format], :must_match => /^(csv|list|yaml|json)$/, :type => String
|
407
|
+
c.flag [:f,:format], :must_match => /^(csv|list|yaml|json|plist)$/, :type => String
|
214
408
|
|
215
409
|
c.action do |global_options, options, args|
|
216
410
|
files = []
|
@@ -220,11 +414,15 @@ command :merge do |c|
|
|
220
414
|
if File.exists?(arg)
|
221
415
|
files.push(arg)
|
222
416
|
else
|
223
|
-
exit_now! "No valid filename in arguments" if files.empty?
|
224
417
|
tags.push(arg)
|
225
418
|
end
|
226
419
|
end
|
227
|
-
|
420
|
+
if files.empty?
|
421
|
+
if @jt.default_post_location && File.exists?(File.dirname(@jt.default_post_location))
|
422
|
+
files = Dir.glob(@jt.default_post_location)
|
423
|
+
end
|
424
|
+
end
|
425
|
+
exit_now! "No valid filename in arguments" if files.empty?
|
228
426
|
exit_now! "Needs at least two tag inputs, one or more to merge, one to merge to" if tags.length < 2
|
229
427
|
tags.reverse!
|
230
428
|
merge_tag = tags.pop
|
@@ -235,11 +433,13 @@ command :merge do |c|
|
|
235
433
|
unless global_options[:t]
|
236
434
|
@jt.update_file_tags(file, new_tags)
|
237
435
|
console_log
|
238
|
-
console_log "Updated tags for #{file}"
|
436
|
+
console_log "Updated tags for #{file}", :log => true
|
239
437
|
end
|
438
|
+
|
240
439
|
console_log
|
241
440
|
console_log File.basename(file) + ":"
|
242
|
-
output_tags(new_tags,options[:format])
|
441
|
+
output_tags(new_tags,{ :format => options[:format], :filename => file })
|
442
|
+
|
243
443
|
}
|
244
444
|
end
|
245
445
|
end
|
@@ -264,11 +464,12 @@ end
|
|
264
464
|
|
265
465
|
desc 'Add tags to post(s)'
|
266
466
|
arg_name 'tags', :multiple
|
467
|
+
arg_name 'file_pattern'
|
267
468
|
command :add do |c|
|
268
|
-
c.desc 'Format to use when outputting tags to console: list, json, csv or yaml. Defaults to yaml.'
|
469
|
+
c.desc 'Format to use when outputting tags to console: list, json, plist, csv or yaml. Defaults to yaml.'
|
269
470
|
c.arg_name 'output_format'
|
270
471
|
c.default_value 'yaml'
|
271
|
-
c.flag [:f,:format], :must_match => /^(csv|list|yaml|json)$/, :type => String
|
472
|
+
c.flag [:f,:format], :must_match => /^(csv|list|yaml|json|plist)$/, :type => String
|
272
473
|
|
273
474
|
|
274
475
|
c.action do |global_options,options,args|
|
@@ -279,11 +480,15 @@ command :add do |c|
|
|
279
480
|
if File.exists?(arg)
|
280
481
|
files.push(arg)
|
281
482
|
else
|
282
|
-
exit_now! "No valid filename in arguments" if files.empty?
|
283
483
|
new_tags.push(arg)
|
284
484
|
end
|
285
485
|
end
|
286
|
-
|
486
|
+
if files.empty?
|
487
|
+
if @jt.default_post_location && File.exists?(File.dirname(@jt.default_post_location))
|
488
|
+
files = Dir.glob(@jt.default_post_location)
|
489
|
+
end
|
490
|
+
end
|
491
|
+
exit_now! "No valid filename in arguments" if files.empty?
|
287
492
|
exit_now! "No tags found in arguments" if new_tags.empty?
|
288
493
|
|
289
494
|
files.each {|file|
|
@@ -293,12 +498,12 @@ command :add do |c|
|
|
293
498
|
tags.sort!
|
294
499
|
unless global_options[:t]
|
295
500
|
@jt.update_file_tags(file,tags)
|
296
|
-
console_log "Updated tags for #{file}"
|
501
|
+
console_log "Updated tags for #{file}", :log => true
|
297
502
|
end
|
298
503
|
|
299
504
|
console_log
|
300
505
|
console_log File.basename(file) + ":"
|
301
|
-
output_tags(tags,options[:format])
|
506
|
+
output_tags(tags, :format => options[:format], :filename => file)
|
302
507
|
}
|
303
508
|
end
|
304
509
|
end
|
@@ -306,10 +511,15 @@ end
|
|
306
511
|
desc 'Remove tags from post(s)'
|
307
512
|
arg_name 'tags', :multiple
|
308
513
|
command :remove do |c|
|
309
|
-
c.desc 'Format to use when outputting tags to console: list, json, csv or yaml. Defaults to yaml.'
|
514
|
+
c.desc 'Format to use when outputting tags to console: list, json, plist, csv or yaml. Defaults to yaml.'
|
310
515
|
c.arg_name 'output_format'
|
311
516
|
c.default_value 'yaml'
|
312
|
-
c.flag [:f,:format], :must_match => /^(csv|list|yaml|json)$/, :type => String
|
517
|
+
c.flag [:f,:format], :must_match => /^(csv|list|yaml|json|plist)$/, :type => String
|
518
|
+
|
519
|
+
c.desc 'A filepath to a list of tags to be removed'
|
520
|
+
c.long_desc 'One tag per line, and leading numbers and pipes (|) will be ignored. This file format is generated automatically by the `loners` command, but any text file will do the trick.'
|
521
|
+
c.arg_name 'input_file'
|
522
|
+
c.flag [:p,:path], :type => String
|
313
523
|
|
314
524
|
c.action do |global_options,options,args|
|
315
525
|
files = []
|
@@ -319,37 +529,60 @@ command :remove do |c|
|
|
319
529
|
if File.exists?(arg)
|
320
530
|
files.push(arg)
|
321
531
|
else
|
322
|
-
|
323
|
-
remove_tags.push(arg)
|
532
|
+
remove_tags.push(arg) unless options[:p]
|
324
533
|
end
|
325
534
|
end
|
535
|
+
if files.empty?
|
536
|
+
if @jt.default_post_location && File.exists?(File.dirname(@jt.default_post_location))
|
537
|
+
files = Dir.glob(@jt.default_post_location)
|
538
|
+
end
|
539
|
+
end
|
540
|
+
exit_now! "No valid filename in arguments" if files.empty?
|
541
|
+
|
542
|
+
if options[:p]
|
543
|
+
path = File.expand_path(options[:p])
|
544
|
+
exit_now! "Input file does not appear to be where you think it is." unless File.exists?(path)
|
545
|
+
IO.read(path).each_line {|l|
|
546
|
+
next if l =~ /^\s*#/
|
547
|
+
if l =~ /^(?:[\s\d])*(?:\|\s*)?(\S.*?)$/
|
548
|
+
remove_tags.push($1.strip)
|
549
|
+
end
|
550
|
+
}
|
551
|
+
console_log "Found #{remove_tags.length} tags in #{File.basename(path)}..."
|
552
|
+
end
|
326
553
|
|
327
|
-
exit_now! "No tags found in
|
554
|
+
exit_now! "No tags found in input, my work here is done" if remove_tags.empty?
|
328
555
|
|
329
556
|
files.each {|file|
|
330
557
|
tags = @jt.post_tags(file)
|
331
558
|
remove_tags.each { |d|
|
332
|
-
tags.delete_if { |tag|
|
559
|
+
tags.delete_if { |tag|
|
560
|
+
if global_options[:i]
|
561
|
+
tag.downcase == d.downcase
|
562
|
+
else
|
563
|
+
tag == d
|
564
|
+
end
|
565
|
+
}
|
333
566
|
}
|
334
567
|
unless global_options[:t]
|
335
568
|
@jt.update_file_tags(file,tags)
|
336
|
-
console_log "Updated tags for #{file}"
|
569
|
+
console_log "Updated tags for #{file}", :log => true
|
337
570
|
end
|
338
571
|
|
339
572
|
console_log
|
340
573
|
console_log File.basename(file) + ":"
|
341
|
-
output_tags(tags,options[:format])
|
574
|
+
output_tags(tags,{ :format => options[:format], :filename => file })
|
342
575
|
}
|
343
576
|
end
|
344
577
|
end
|
345
578
|
|
346
579
|
desc 'Generate a list of recommended tags, optionally updating the file'
|
347
|
-
arg_name '
|
580
|
+
arg_name 'file_pattern', :multiple
|
348
581
|
command :tag do |c|
|
349
|
-
c.desc 'Format to use when outputting tags to console: list, json, csv or yaml. Defaults to yaml.'
|
582
|
+
c.desc 'Format to use when outputting tags to console: list, json, plist, csv or yaml. Defaults to yaml.'
|
350
583
|
c.arg_name 'output_format'
|
351
584
|
c.default_value 'yaml'
|
352
|
-
c.flag [:f,:format], :must_match => /^(csv|list|yaml|json)$/, :type => String
|
585
|
+
c.flag [:f,:format], :must_match => /^(csv|list|yaml|json|plist)$/, :type => String
|
353
586
|
|
354
587
|
c.action do |global_options,options,args|
|
355
588
|
if @piped_content
|
@@ -357,9 +590,9 @@ command :tag do |c|
|
|
357
590
|
if !global_options[:s] || global_options[:t]
|
358
591
|
if args.length > 1
|
359
592
|
console_log
|
360
|
-
console_log "STDIN:",
|
593
|
+
console_log "STDIN:", :err => true
|
361
594
|
end
|
362
|
-
output_tags(suggestions,options[:format])
|
595
|
+
output_tags(suggestions, :format => options[:format], :filename => file )
|
363
596
|
end
|
364
597
|
end
|
365
598
|
args.each {|file|
|
@@ -370,18 +603,18 @@ command :tag do |c|
|
|
370
603
|
unless global_options[:t]
|
371
604
|
if @jt.update_file_tags(file, suggestions)
|
372
605
|
console_log
|
373
|
-
console_log "Updated file #{file} with:"
|
606
|
+
console_log "Updated file #{file} with:", :log => true
|
374
607
|
else
|
375
608
|
console_log
|
376
|
-
console_log "Failed to update #{file} with:"
|
609
|
+
console_log "Failed to update #{file} with:", :log => true
|
377
610
|
end
|
378
611
|
end
|
379
612
|
if !global_options[:s] || global_options[:t]
|
380
613
|
if args.length > 1
|
381
614
|
console_log
|
382
|
-
console_log File.basename(file) + ":",
|
615
|
+
console_log File.basename(file) + ":", :err => true, :log => true
|
383
616
|
end
|
384
|
-
output_tags(suggestions,options[:format])
|
617
|
+
output_tags(suggestions, :format => options[:format], :filename => file )
|
385
618
|
end
|
386
619
|
suggestions = nil
|
387
620
|
else
|
@@ -391,19 +624,38 @@ command :tag do |c|
|
|
391
624
|
end
|
392
625
|
end
|
393
626
|
|
394
|
-
def output_tags(tags,
|
627
|
+
def output_tags(tags,options)
|
628
|
+
format = options[:format] || 'yaml'
|
629
|
+
print0 = options[:print0] || false
|
630
|
+
filename = options[:filename] || false
|
395
631
|
case format
|
396
632
|
when 'list'
|
397
|
-
|
633
|
+
unless print0
|
634
|
+
console_log tags.join("\n")
|
635
|
+
else
|
636
|
+
console_log tags.map {|tag|
|
637
|
+
if tag.strip =~ /\b\s\b/
|
638
|
+
%Q{"#{tag.strip}"}
|
639
|
+
else
|
640
|
+
tag.strip
|
641
|
+
end
|
642
|
+
}.join(" ")
|
643
|
+
end
|
398
644
|
when 'csv'
|
399
645
|
console_log tags.to_csv
|
400
646
|
when 'json'
|
401
647
|
out = {}
|
402
648
|
out['tags'] = tags
|
649
|
+
out['path'] = filename if filename
|
403
650
|
console_log out.to_json
|
404
|
-
|
651
|
+
when 'plist'
|
405
652
|
out = {}
|
406
|
-
out['
|
653
|
+
out['path'] = filename if filename
|
654
|
+
console_log tags.to_plist
|
655
|
+
else
|
656
|
+
out = {}
|
657
|
+
options[:grouping] ||= "tags"
|
658
|
+
out[options[:grouping]] = tags
|
407
659
|
console_log out.to_yaml
|
408
660
|
end
|
409
661
|
end
|
@@ -419,16 +671,17 @@ end
|
|
419
671
|
# end
|
420
672
|
|
421
673
|
pre do |global,command,options,args|
|
422
|
-
# Pre logic here
|
423
|
-
# Return true to proceed; false to abort and not call the
|
424
|
-
# chosen command
|
425
674
|
# Use skips_pre before a command to skip this block
|
426
675
|
# on that command only
|
427
676
|
@silent = global[:silent]
|
428
677
|
|
678
|
+
@logfile = File.open(File.join(Dir.tmpdir, "jtag_actions.log"), 'a')
|
679
|
+
|
680
|
+
@log = Logger.new(@logfile, shift_age = 7, shift_size = 1048576)
|
681
|
+
|
429
682
|
unless config_files_complete?
|
430
683
|
write_config
|
431
|
-
console_log "Missing config files written to #{@config_target}. Please check your configuration."
|
684
|
+
console_log "Missing config files written to #{@config_target}. Please check your configuration.", {:err => true}
|
432
685
|
return false
|
433
686
|
end
|
434
687
|
|
data/lib/jtag.rb
CHANGED
@@ -4,10 +4,10 @@ require 'fileutils'
|
|
4
4
|
require 'yaml'
|
5
5
|
require 'csv'
|
6
6
|
require 'json'
|
7
|
+
require 'plist'
|
7
8
|
require 'jtag/version.rb'
|
8
9
|
require 'jtag/string.rb'
|
9
10
|
require 'jtag/porter_stemming.rb'
|
10
11
|
require 'jtag/jekylltag.rb'
|
11
|
-
|
12
|
-
|
13
|
-
# you just need to require this one file in your bin file
|
12
|
+
require 'tmpdir'
|
13
|
+
require 'logger'
|
data/lib/jtag/jekylltag.rb
CHANGED
@@ -1,13 +1,32 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
+
|
2
3
|
class JTag
|
4
|
+
attr_reader :default_post_location
|
5
|
+
attr_accessor :tags_key
|
3
6
|
|
4
7
|
def initialize(support_dir, config)
|
5
8
|
@support = support_dir
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
+
begin
|
10
|
+
@tags_loc = config['tags_location']
|
11
|
+
@tags_loc.sub!(/^https?:\/\//,'')
|
12
|
+
rescue
|
13
|
+
raise "No tags location in configuration."
|
14
|
+
end
|
15
|
+
@min_matches = config['min_matches'] || 2
|
16
|
+
@tags_key = config['tags_key'] || 'tags'
|
17
|
+
|
18
|
+
if config.has_key? 'default_post_location'
|
19
|
+
@default_post_location = File.expand_path(config['default_post_location']) || false
|
20
|
+
else
|
21
|
+
console_log "#{color('yellow')}No #{color('boldyellow')}default_post_location#{color('yellow')} set.", :err => true
|
22
|
+
console_log "If you commonly work on the same posts you can add the path and *.ext", :err => true
|
23
|
+
console_log "to this key in ~/.jtag/config.yml. Then, if you don't specify files", :err => true
|
24
|
+
console_log "to act on in a command, it will fall back to those. Nice!#{color('default')}", :err => true
|
25
|
+
@default_post_location = false
|
26
|
+
end
|
27
|
+
@blacklistfile = File.join(@support,'blacklist.txt')
|
9
28
|
@blacklist = IO.read(@blacklistfile).split("\n") || []
|
10
|
-
@skipwords = IO.read(File.join(support_dir,
|
29
|
+
@skipwords = IO.read(File.join(support_dir,'stopwords.txt')).split("\n") || []
|
11
30
|
remote_tags = get_tags
|
12
31
|
@tags = {}
|
13
32
|
remote_tags.each {|tag| @tags[Text::PorterStemming.stem(tag).downcase] = tag if tag}
|
@@ -21,13 +40,14 @@ class JTag
|
|
21
40
|
counts = options[:counts] || false
|
22
41
|
host, path = @tags_loc.match(/^([^\/]+)(\/.*)/)[1,2]
|
23
42
|
tags = ""
|
24
|
-
http = Net::HTTP.new(host, 80)
|
25
|
-
http.start do |http|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
end
|
43
|
+
# http = Net::HTTP.new(host, 80)
|
44
|
+
# http.start do |http|
|
45
|
+
# request = Net::HTTP::Get.new(path)
|
46
|
+
# response = http.request(request)
|
47
|
+
# response.value
|
48
|
+
# tags = response.body
|
49
|
+
# end
|
50
|
+
tags = `curl -sSL "#{@tags_loc}"`
|
31
51
|
tags = JSON.parse(tags)
|
32
52
|
if tags && tags.key?("tags")
|
33
53
|
if counts
|
@@ -72,11 +92,11 @@ class JTag
|
|
72
92
|
[yaml, after]
|
73
93
|
end
|
74
94
|
|
75
|
-
def post_tags(file,piped=false)
|
95
|
+
def post_tags(file, piped=false)
|
76
96
|
begin
|
77
97
|
input = piped ? file : IO.read(file)
|
78
98
|
yaml = YAML::load(input)
|
79
|
-
return yaml[
|
99
|
+
return yaml[@tags_key] || []
|
80
100
|
rescue
|
81
101
|
return []
|
82
102
|
end
|
@@ -103,7 +123,7 @@ class JTag
|
|
103
123
|
if parts.length >= 2
|
104
124
|
begin
|
105
125
|
yaml = YAML::load(parts[1])
|
106
|
-
current_tags = yaml[
|
126
|
+
current_tags = yaml[@tags_key] || []
|
107
127
|
title = yaml["title"] || ""
|
108
128
|
rescue
|
109
129
|
current_tags = []
|
@@ -175,7 +195,7 @@ class JTag
|
|
175
195
|
begin
|
176
196
|
if File.exists?(file)
|
177
197
|
yaml, after = split_post(file)
|
178
|
-
yaml[
|
198
|
+
yaml[@tags_key] = tags
|
179
199
|
File.open(file,'w+') do |f|
|
180
200
|
f.puts yaml.to_yaml
|
181
201
|
f.puts "---"
|
@@ -190,5 +210,52 @@ class JTag
|
|
190
210
|
return false
|
191
211
|
end
|
192
212
|
end
|
193
|
-
end
|
194
213
|
|
214
|
+
private
|
215
|
+
|
216
|
+
def color(name)
|
217
|
+
color = {}
|
218
|
+
color['black'] = "\033[0;30m"
|
219
|
+
color['red'] = "\033[0;31m"
|
220
|
+
color['green'] = "\033[0;32m"
|
221
|
+
color['yellow'] = "\033[0;33m"
|
222
|
+
color['blue'] = "\033[0;34m"
|
223
|
+
color['magenta'] = "\033[0;35m"
|
224
|
+
color['cyan'] = "\033[0;36m"
|
225
|
+
color['white'] = "\033[0;37m"
|
226
|
+
color['bgblack'] = "\033[0;40m"
|
227
|
+
color['bgred'] = "\033[0;41m"
|
228
|
+
color['bggreen'] = "\033[0;42m"
|
229
|
+
color['bgyellow'] = "\033[0;43m"
|
230
|
+
color['bgblue'] = "\033[0;44m"
|
231
|
+
color['bgmagenta'] = "\033[0;45m"
|
232
|
+
color['bgcyan'] = "\033[0;46m"
|
233
|
+
color['bgwhite'] = "\033[0;47m"
|
234
|
+
color['boldblack'] = "\033[1;30m"
|
235
|
+
color['boldred'] = "\033[1;31m"
|
236
|
+
color['boldgreen'] = "\033[1;32m"
|
237
|
+
color['boldyellow'] = "\033[1;33m"
|
238
|
+
color['boldblue'] = "\033[1;34m"
|
239
|
+
color['boldmagenta'] = "\033[1;35m"
|
240
|
+
color['boldcyan'] = "\033[1;36m"
|
241
|
+
color['boldwhite'] = "\033[1;37m"
|
242
|
+
color['boldbgblack'] = "\033[1;40m"
|
243
|
+
color['boldbgred'] = "\033[1;41m"
|
244
|
+
color['boldbggreen'] = "\033[1;42m"
|
245
|
+
color['boldbgyellow'] = "\033[1;43m"
|
246
|
+
color['boldbgblue'] = "\033[1;44m"
|
247
|
+
color['boldbgmagenta'] = "\033[1;45m"
|
248
|
+
color['boldbgcyan'] = "\033[1;46m"
|
249
|
+
color['boldbgwhite'] = "\033[1;47m"
|
250
|
+
color['default'] = "\033[0;39m"
|
251
|
+
color['warning'] = color['yellow']
|
252
|
+
color['warningb'] = color['boldyellow']
|
253
|
+
color['success'] = color['green']
|
254
|
+
color['successb'] = color['boldgreen']
|
255
|
+
color['neutral'] = color['white']
|
256
|
+
color['neutralb'] = color['boldwhite']
|
257
|
+
color['info'] = color['cyan']
|
258
|
+
color['infob'] = color['boldcyan']
|
259
|
+
color[name]
|
260
|
+
end
|
261
|
+
end
|
data/lib/jtag/version.rb
CHANGED
metadata
CHANGED
@@ -1,97 +1,100 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jtag
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
5
|
-
prerelease:
|
4
|
+
version: 0.1.15
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Brett Terpstra
|
9
|
-
autorequire:
|
8
|
+
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date:
|
11
|
+
date: 2021-05-14 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
14
|
name: rake
|
16
15
|
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
16
|
requirements:
|
19
|
-
- -
|
17
|
+
- - ">="
|
20
18
|
- !ruby/object:Gem::Version
|
21
19
|
version: '0'
|
22
20
|
type: :development
|
23
21
|
prerelease: false
|
24
22
|
version_requirements: !ruby/object:Gem::Requirement
|
25
|
-
none: false
|
26
23
|
requirements:
|
27
|
-
- -
|
24
|
+
- - ">="
|
28
25
|
- !ruby/object:Gem::Version
|
29
26
|
version: '0'
|
30
27
|
- !ruby/object:Gem::Dependency
|
31
28
|
name: rdoc
|
32
29
|
requirement: !ruby/object:Gem::Requirement
|
33
|
-
none: false
|
34
30
|
requirements:
|
35
|
-
- -
|
31
|
+
- - ">="
|
36
32
|
- !ruby/object:Gem::Version
|
37
33
|
version: '0'
|
38
34
|
type: :development
|
39
35
|
prerelease: false
|
40
36
|
version_requirements: !ruby/object:Gem::Requirement
|
41
|
-
none: false
|
42
37
|
requirements:
|
43
|
-
- -
|
38
|
+
- - ">="
|
44
39
|
- !ruby/object:Gem::Version
|
45
40
|
version: '0'
|
46
41
|
- !ruby/object:Gem::Dependency
|
47
42
|
name: aruba
|
48
43
|
requirement: !ruby/object:Gem::Requirement
|
49
|
-
none: false
|
50
44
|
requirements:
|
51
|
-
- -
|
45
|
+
- - ">="
|
52
46
|
- !ruby/object:Gem::Version
|
53
47
|
version: '0'
|
54
48
|
type: :development
|
55
49
|
prerelease: false
|
56
50
|
version_requirements: !ruby/object:Gem::Requirement
|
57
|
-
none: false
|
58
51
|
requirements:
|
59
|
-
- -
|
52
|
+
- - ">="
|
60
53
|
- !ruby/object:Gem::Version
|
61
54
|
version: '0'
|
62
55
|
- !ruby/object:Gem::Dependency
|
63
56
|
name: gli
|
64
57
|
requirement: !ruby/object:Gem::Requirement
|
65
|
-
none: false
|
66
58
|
requirements:
|
67
|
-
- -
|
59
|
+
- - "~>"
|
68
60
|
- !ruby/object:Gem::Version
|
69
|
-
version: 2.
|
61
|
+
version: 2.20.0
|
70
62
|
type: :runtime
|
71
63
|
prerelease: false
|
72
64
|
version_requirements: !ruby/object:Gem::Requirement
|
73
|
-
none: false
|
74
65
|
requirements:
|
75
|
-
- -
|
66
|
+
- - "~>"
|
76
67
|
- !ruby/object:Gem::Version
|
77
|
-
version: 2.
|
68
|
+
version: 2.20.0
|
78
69
|
- !ruby/object:Gem::Dependency
|
79
70
|
name: json
|
80
71
|
requirement: !ruby/object:Gem::Requirement
|
81
|
-
none: false
|
82
72
|
requirements:
|
83
|
-
- -
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 2.2.0
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 2.2.0
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: plist
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
84
88
|
- !ruby/object:Gem::Version
|
85
89
|
version: '0'
|
86
90
|
type: :runtime
|
87
91
|
prerelease: false
|
88
92
|
version_requirements: !ruby/object:Gem::Requirement
|
89
|
-
none: false
|
90
93
|
requirements:
|
91
|
-
- -
|
94
|
+
- - ">="
|
92
95
|
- !ruby/object:Gem::Version
|
93
96
|
version: '0'
|
94
|
-
description:
|
97
|
+
description:
|
95
98
|
email: me@brettterpstra.com
|
96
99
|
executables:
|
97
100
|
- jtag
|
@@ -100,52 +103,43 @@ extra_rdoc_files:
|
|
100
103
|
- README.rdoc
|
101
104
|
- jtag.rdoc
|
102
105
|
files:
|
106
|
+
- README.rdoc
|
103
107
|
- bin/jtag
|
104
|
-
-
|
108
|
+
- jtag.rdoc
|
109
|
+
- lib/jtag.rb
|
105
110
|
- lib/jtag/config_files/blacklist.txt
|
106
111
|
- lib/jtag/config_files/config.yml
|
107
112
|
- lib/jtag/config_files/stopwords.txt
|
108
113
|
- lib/jtag/config_files/synonyms.yml
|
109
|
-
- lib/jtag/porter_stemming.rb
|
110
114
|
- lib/jtag/jekylltag.rb
|
115
|
+
- lib/jtag/porter_stemming.rb
|
111
116
|
- lib/jtag/string.rb
|
112
|
-
- lib/jtag.rb
|
113
|
-
- README.rdoc
|
114
|
-
- jtag.rdoc
|
117
|
+
- lib/jtag/version.rb
|
115
118
|
homepage: http://brettterpstra.com
|
116
119
|
licenses: []
|
117
|
-
|
120
|
+
metadata: {}
|
121
|
+
post_install_message:
|
118
122
|
rdoc_options:
|
119
|
-
- --title
|
123
|
+
- "--title"
|
120
124
|
- jtag
|
121
|
-
- --main
|
125
|
+
- "--main"
|
122
126
|
- README.rdoc
|
123
|
-
- -ri
|
124
127
|
require_paths:
|
125
128
|
- lib
|
126
129
|
- lib
|
127
130
|
required_ruby_version: !ruby/object:Gem::Requirement
|
128
|
-
none: false
|
129
131
|
requirements:
|
130
|
-
- -
|
132
|
+
- - ">="
|
131
133
|
- !ruby/object:Gem::Version
|
132
134
|
version: '0'
|
133
|
-
segments:
|
134
|
-
- 0
|
135
|
-
hash: -591621506323502236
|
136
135
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
137
|
-
none: false
|
138
136
|
requirements:
|
139
|
-
- -
|
137
|
+
- - ">="
|
140
138
|
- !ruby/object:Gem::Version
|
141
139
|
version: '0'
|
142
|
-
segments:
|
143
|
-
- 0
|
144
|
-
hash: -591621506323502236
|
145
140
|
requirements: []
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
specification_version: 3
|
141
|
+
rubygems_version: 3.2.16
|
142
|
+
signing_key:
|
143
|
+
specification_version: 4
|
150
144
|
summary: Auto-tagging and tagging tools for Jekyll
|
151
145
|
test_files: []
|