oktags 0.1.0 → 0.2.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/{ruby.yml → ci.yml} +1 -1
- data/Gemfile +5 -3
- data/Gemfile.lock +3 -1
- data/README.org +74 -57
- data/Rakefile +8 -8
- data/bin/console +3 -3
- data/bin/oktags +2 -2
- data/lib/hash.rb +15 -0
- data/lib/ok/tags.rb +135 -47
- data/lib/ok/version.rb +1 -1
- data/lib/oktags.rb +1 -1
- data/oktags.gemspec +1 -1
- metadata +8 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 627114b53a234963a6e1547602f9bdabbd2e91814b6d7b07de8d2f07989170c4
|
4
|
+
data.tar.gz: 16fe1866c9793190c90af178b5125685b4afd4645cb2e43574c952466408bb5b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d85747e3fd8ccad82fa328a853a3aea67e4ae6d2116474e34f61599fe535624f89ba8d540e296a847e652b5273bbcb60e95c340d236039ac4124a9d79b0bf983
|
7
|
+
data.tar.gz: 5d606c25adf29ace1025ce67a2287f4078775254c3dba57768dcdfc8e79a5390abdddd8976e3c4d6a37f45dd60e417271d9a3093a2db6d4dfbabe5812cc18530
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,11 +1,12 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
oktags (0.1
|
4
|
+
oktags (0.2.1)
|
5
5
|
|
6
6
|
GEM
|
7
7
|
remote: https://rubygems.org/
|
8
8
|
specs:
|
9
|
+
byebug (11.1.3)
|
9
10
|
diff-lcs (1.4.4)
|
10
11
|
rake (12.3.2)
|
11
12
|
rspec (3.9.0)
|
@@ -26,6 +27,7 @@ PLATFORMS
|
|
26
27
|
ruby
|
27
28
|
|
28
29
|
DEPENDENCIES
|
30
|
+
byebug!
|
29
31
|
oktags!
|
30
32
|
rake (~> 12.0)!
|
31
33
|
rspec!
|
data/README.org
CHANGED
@@ -7,6 +7,9 @@
|
|
7
7
|
|___/
|
8
8
|
#+end_example
|
9
9
|
|
10
|
+
#+html: <img src="https://github.com/200ok-ch/oktags/workflows/CI/badge.svg"/>
|
11
|
+
#+html: <a href="https://rubygems.org/gems/oktags"> <img src="https://badge.fury.io/rb/oktags.svg"/></a>
|
12
|
+
|
10
13
|
* NAME
|
11
14
|
|
12
15
|
=oktags= - manage tags on plain old files
|
@@ -15,52 +18,53 @@
|
|
15
18
|
|
16
19
|
#+begin_example
|
17
20
|
Usage: oktags [options]
|
18
|
-
-l, --list [PATH] List file tags (optionally for PATH)
|
19
21
|
-a, --add-tags TAGS FILE Add comma-separated TAGS to FILE
|
22
|
+
-d TAG FILE, Delete TAG from FILE
|
23
|
+
--delete-tag-from-file
|
20
24
|
-i FILE, Auto-complete tags and add them to FILE
|
21
25
|
--add-tags-interactively
|
26
|
+
-l, --list [PATH] List file tags (optional PATH)
|
22
27
|
-r, --rename-tag OLD_TAG NEW_TAG Rename OLD_TAG to NEW_TAG(S) recursively for all files
|
23
|
-
-
|
24
|
-
--
|
28
|
+
-s TAGS [PATH], Search files which include (comma-separated) tags recursively (optional PATH)
|
29
|
+
--search-files-with-tags
|
25
30
|
#+end_example
|
26
31
|
|
27
32
|
* DESCRIPTION
|
28
33
|
|
29
|
-
=oktags= helps you organize your files by managing tags on them.
|
30
|
-
|
31
|
-
|
32
|
-
|
34
|
+
=oktags= helps you organize your files by managing tags on them. It
|
35
|
+
works by adding/removing at the end of the filename. Given a file
|
36
|
+
=cat.jpg=, when adding the tags =tag1= and =tag2=, the filename will
|
37
|
+
become =cat--[tag1,tag2].jpg=. The implementation is OS-agnostic, so
|
38
|
+
it should work on Linux, macOS and Windows.
|
33
39
|
|
34
40
|
* EXAMPLES
|
35
41
|
|
36
|
-
|
37
|
-
|
38
|
-
#+begin_example
|
39
|
-
$ touch foo
|
40
|
-
$ touch bar.txt
|
41
|
-
$ touch foobar--tag1,tag2.pdf
|
42
|
-
$ touch baz--tag1.txt
|
43
|
-
$ oktags -l
|
44
|
-
tag1(2)
|
45
|
-
tag2(1)
|
46
|
-
#+end_example
|
47
|
-
|
48
|
-
Listing all tags for a given path glob (assuming the same data set as above).
|
42
|
+
Add tags to a file. Tags are always unique.
|
49
43
|
|
50
44
|
#+begin_example
|
51
|
-
$
|
52
|
-
tag1
|
45
|
+
$ touch foobar
|
46
|
+
$ oktags -a tag1 foobar
|
47
|
+
$ ls foobar*
|
48
|
+
foobar--[tag1]
|
49
|
+
$ oktags -a tag2 foobar--\[tag1\]
|
50
|
+
$ ls foobar*
|
51
|
+
foobar--[tag1,tag2]
|
52
|
+
$ oktags -a tag3,tag2 foobar--[tag1,tag2].pdf
|
53
|
+
$ ls foobar*
|
54
|
+
foobar--[tag1,tag2,tag3].pdf
|
53
55
|
#+end_example
|
54
56
|
|
55
|
-
|
57
|
+
Delete a tag from a file.
|
56
58
|
|
57
59
|
#+begin_example
|
58
|
-
|
59
|
-
|
60
|
-
|
60
|
+
$ find . | grep business_card | head -n 1
|
61
|
+
./archiv/Reto_Huber--[business_card,somedia,seo].pdf
|
62
|
+
$ oktags -d seo ./archiv/Reto_Huber--[business_card,somedia,seo].pdf
|
63
|
+
$ find . | grep business_card | head -n 1
|
64
|
+
./archiv/Reto_Huber--[business_card,somedia].pdf
|
61
65
|
#+end_example
|
62
66
|
|
63
|
-
Interactively
|
67
|
+
Interactively add tags (with auto-completion through readline) to a file.
|
64
68
|
|
65
69
|
#+begin_example
|
66
70
|
$ oktags -i foo
|
@@ -68,30 +72,50 @@ Interactively adding tags (with auto-completion through readline) to a file.
|
|
68
72
|
tag1 tag2 tag3
|
69
73
|
> tag2, new tag
|
70
74
|
$ ls foo* | grep new
|
71
|
-
foo--
|
75
|
+
foo--[new_tag,tag2]
|
76
|
+
#+end_example
|
77
|
+
|
78
|
+
List all tags in the current folder.
|
79
|
+
|
80
|
+
#+begin_example
|
81
|
+
$ touch foo
|
82
|
+
$ touch bar.txt
|
83
|
+
$ touch foobar--[tag1,tag2].pdf
|
84
|
+
$ touch baz--[tag1].txt
|
85
|
+
$ oktags -l
|
86
|
+
tag1(2)
|
87
|
+
tag2(1)
|
88
|
+
#+end_example
|
89
|
+
|
90
|
+
List all tags for a given path glob (assuming the same data set as above).
|
91
|
+
|
92
|
+
#+begin_example
|
93
|
+
$ oktags -l '*txt'
|
94
|
+
tag1(1)
|
72
95
|
#+end_example
|
73
96
|
|
74
|
-
|
97
|
+
Rename tag.
|
75
98
|
|
76
99
|
#+begin_example
|
77
100
|
$ oktags -l
|
78
101
|
200ok_expense(8)
|
79
102
|
business_card(4)
|
80
|
-
$ oktags -r 200ok_expense
|
103
|
+
$ oktags -r 200ok_expense 200ok,expense
|
81
104
|
$ oktags -l
|
82
105
|
expense(8)
|
83
106
|
200ok(8)
|
84
107
|
business_card(4)
|
85
108
|
#+end_example
|
86
109
|
|
87
|
-
|
110
|
+
Search files with tags.
|
88
111
|
|
89
112
|
#+begin_example
|
90
|
-
$
|
91
|
-
|
92
|
-
|
93
|
-
$
|
94
|
-
|
113
|
+
$ oktags -s somedia,seo,business_card
|
114
|
+
archiv/Reto_Huber--[business_card,seo,somedia].pdf
|
115
|
+
archiv/Reto_Huber--[business_card,seo,somedia].txt
|
116
|
+
$ oktags -s business_card '**/*pdf'
|
117
|
+
archiv/Reto_Huber--[business_card,seo,somedia].pdf
|
118
|
+
archiv/Stefan_Schmidt--[business_card,lawoon].pdf
|
95
119
|
#+end_example
|
96
120
|
|
97
121
|
* INSTALLATION
|
@@ -111,28 +135,21 @@ You can also run =bin/console= for an interactive prompt that will
|
|
111
135
|
allow you to experiment.
|
112
136
|
|
113
137
|
To install this gem onto your local machine, run =bundle exec rake
|
114
|
-
install=. To
|
115
|
-
=version.rb=, and then run =bundle exec rake
|
138
|
+
install=. To publish a new version, update the version number in
|
139
|
+
=version.rb=, and then run =bundle exec rake publish=, which will
|
116
140
|
create a git tag for the version, push git commits and tags, and push
|
117
141
|
the =.gem= file to [[https://rubygems.org][rubygems.org]].
|
118
142
|
|
119
143
|
* TESTS
|
120
144
|
|
121
|
-
|
122
|
-
|
123
|
-
#+begin_src shell
|
124
|
-
$ rpsec spec
|
125
|
-
.....
|
126
|
-
|
127
|
-
Finished in 0.00351 seconds (files took 0.06834 seconds to load)
|
128
|
-
5 examples, 0 failures
|
129
|
-
#+end_src
|
145
|
+
Tests are implemented with [[https://rspec.info/][RSpec]] and can be run with =bundle exec
|
146
|
+
rspec spec=.
|
130
147
|
|
131
148
|
* NOTES
|
132
149
|
|
133
150
|
Software systems come and go. It is easy to lose important data in
|
134
|
-
(proprietary) legacy systems. Plain old files are boring and
|
135
|
-
|
151
|
+
(proprietary) legacy systems. Plain old files are boring and are
|
152
|
+
therefore here to stay; at least they [[https://en.wikipedia.org/wiki/Computer_file#Storage][have been around since 1961]].
|
136
153
|
Additional benefits of using plain old files are:
|
137
154
|
|
138
155
|
- They are (mostly) platform independent.
|
@@ -143,14 +160,14 @@ Additional benefits of using plain old files are:
|
|
143
160
|
- They can be transported independently from the software that captured/created them.
|
144
161
|
- They are not proprietary.
|
145
162
|
|
146
|
-
=oktags= is decidedly built to be just as boring as plain old
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
163
|
+
=oktags= is decidedly built to be just as boring as plain old files.
|
164
|
+
It's written in a language that's been proven for shell scripts ([[https://www.ruby-lang.org/en/][Ruby]])
|
165
|
+
rather than using something more 'cool'/'interesting'. It also only
|
166
|
+
uses Ruby built-ins and has no dependencies when run as a CLI or
|
167
|
+
library. =oktags= is therefore boring and here to stay. The idea is to
|
168
|
+
tag your files once and for all, so you will not loose your important
|
169
|
+
data in something that will become an unsupported legacy system at
|
170
|
+
some point.
|
154
171
|
|
155
172
|
At [[https://200ok.ch/][200ok]], we develop various Free Software projects that work on plain
|
156
173
|
old files:
|
data/Rakefile
CHANGED
@@ -1,23 +1,23 @@
|
|
1
1
|
require './lib/oktags'
|
2
2
|
require './lib/ok/version'
|
3
3
|
|
4
|
-
GEM_NAME =
|
4
|
+
GEM_NAME = 'oktags'
|
5
5
|
GEM_VERSION = OK::Tags::VERSION
|
6
6
|
|
7
|
-
task :
|
7
|
+
task default: :build
|
8
8
|
|
9
9
|
task :build do
|
10
|
-
system
|
10
|
+
system 'gem build ' + GEM_NAME + '.gemspec'
|
11
11
|
end
|
12
12
|
|
13
|
-
task :
|
14
|
-
system
|
13
|
+
task install: :build do
|
14
|
+
system 'gem install ' + GEM_NAME + '-' + GEM_VERSION + '.gem'
|
15
15
|
end
|
16
16
|
|
17
|
-
task :
|
18
|
-
system 'gem push ' + GEM_NAME +
|
17
|
+
task publish: :build do
|
18
|
+
system 'gem push ' + GEM_NAME + '-' + GEM_VERSION + '.gem'
|
19
19
|
end
|
20
20
|
|
21
21
|
task :clean do
|
22
|
-
system
|
22
|
+
system 'rm *.gem'
|
23
23
|
end
|
data/bin/console
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
3
|
+
require 'bundler/setup'
|
4
|
+
require 'oktags'
|
5
5
|
|
6
6
|
# You can add fixtures and/or initialization code here to make experimenting
|
7
7
|
# with your gem easier. You can also use a different console, if you like.
|
@@ -10,5 +10,5 @@ require "oktags"
|
|
10
10
|
# require "pry"
|
11
11
|
# Pry.start
|
12
12
|
|
13
|
-
require
|
13
|
+
require 'irb'
|
14
14
|
IRB.start(__FILE__)
|
data/bin/oktags
CHANGED
data/lib/hash.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
class Hash
|
2
|
+
# like invert but not lossy. possibly a good blog post.
|
3
|
+
def safe_invert
|
4
|
+
inject({}) do |acc, (k, v)|
|
5
|
+
if v.is_a? Array
|
6
|
+
v.each do |vx|
|
7
|
+
acc[vx] = acc[vx].nil? ? k : [acc[vx], k].flatten
|
8
|
+
end
|
9
|
+
else
|
10
|
+
acc[v] = acc[v].nil? ? k : [acc[v], k].flatten
|
11
|
+
end
|
12
|
+
acc
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
data/lib/ok/tags.rb
CHANGED
@@ -2,41 +2,72 @@
|
|
2
2
|
# coding: utf-8
|
3
3
|
|
4
4
|
require 'optparse'
|
5
|
+
require 'set'
|
5
6
|
require 'readline'
|
6
7
|
require 'fileutils'
|
8
|
+
require File.expand_path(File.join(%w[.. .. hash]), __FILE__)
|
7
9
|
|
8
10
|
module OK
|
9
11
|
module Tags
|
10
12
|
class Error < StandardError; end
|
11
13
|
extend self
|
12
14
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
15
|
+
# oktags uses --[] as the place to save tags. [] does have special
|
16
|
+
# meaning for Ruby Dir.glob, though. Hence, it's escaped.
|
17
|
+
def escape_glob(s)
|
18
|
+
s&.gsub(/[\[\]]/) { |x| "\\" + x }
|
19
|
+
end
|
20
|
+
|
21
|
+
def search_files_with_tags(path = '**/*')
|
22
|
+
tagged_files = Hash.new { |h, k| h[k] = [] }
|
23
|
+
|
24
|
+
Dir.glob(escape_glob(path)).each do |file|
|
25
|
+
basename = File.basename(file, '.*')
|
26
|
+
file_tags =
|
27
|
+
basename.match(/--\[(.*)\]/)&.to_a&.at(1)&.split(',')&.map(&:strip)
|
28
|
+
&.map(&:downcase)
|
29
|
+
file_tags.each { |t| tagged_files[t] << file } if file_tags
|
19
30
|
end
|
31
|
+
tagged_files
|
32
|
+
end
|
33
|
+
|
34
|
+
def list_files_with_tags(tags, path = '**/*')
|
35
|
+
# TODO: Refactor reused code
|
36
|
+
tags = tags.split(',')&.map(&:strip)&.map(&:downcase)
|
37
|
+
|
38
|
+
tagged_files = search_files_with_tags(path)
|
39
|
+
files =
|
40
|
+
tagged_files.safe_invert.filter do |files, file_tags|
|
41
|
+
file_tags = [file_tags] if file_tags.is_a? String
|
42
|
+
tags.to_set.subset?(file_tags.to_set)
|
43
|
+
end&.keys&.flatten&.sort
|
44
|
+
|
45
|
+
puts files
|
46
|
+
files
|
47
|
+
end
|
20
48
|
|
21
|
-
|
49
|
+
def find_tags_for(path = '**/*')
|
50
|
+
tagged_files =
|
51
|
+
path ? search_files_with_tags(path) : search_files_with_tags
|
52
|
+
# return an array with redundant tags
|
53
|
+
tagged_files.map { |k, v| Array.new(v.count, k) }.flatten.sort
|
22
54
|
end
|
23
55
|
|
24
56
|
def count_tags(tags)
|
25
|
-
tags.inject({})
|
57
|
+
tags.inject({}) do |acc, tag|
|
26
58
|
acc[tag] = acc[tag].to_i + 1
|
27
59
|
acc
|
28
|
-
|
60
|
+
end
|
29
61
|
end
|
30
62
|
|
31
|
-
def list_pretty_tags(path =
|
32
|
-
tags = find_tags_for(path
|
63
|
+
def list_pretty_tags(path = '**/*')
|
64
|
+
tags = find_tags_for(path)
|
33
65
|
counts = count_tags(tags)
|
34
66
|
|
35
|
-
pretty_counts =
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
end
|
67
|
+
pretty_counts =
|
68
|
+
counts.sort_by { |tag, count| count }.reverse.map do |tag, count|
|
69
|
+
"#{tag}(#{count})"
|
70
|
+
end
|
40
71
|
|
41
72
|
puts pretty_counts
|
42
73
|
end
|
@@ -44,58 +75,82 @@ module OK
|
|
44
75
|
def filename_with_tags(file, tags)
|
45
76
|
dirname = File.dirname(file)
|
46
77
|
ext = File.extname(file)
|
47
|
-
basename = File.basename(file,
|
48
|
-
|
78
|
+
basename = File.basename(file, '.*')
|
79
|
+
tag_part = basename.match(/--\[(.*)\]/)&.to_a&.at(0)
|
80
|
+
basename = basename.gsub(tag_part, '') if tag_part
|
81
|
+
File.join(dirname, "#{basename}--[#{tags.join(',')}]#{ext}")
|
49
82
|
end
|
50
83
|
|
51
84
|
def add_tags_to_file(new_tags, file)
|
52
|
-
|
85
|
+
unless file
|
86
|
+
(
|
87
|
+
puts 'Needs a FILE input; i.e. `-a tag filename`'
|
88
|
+
exit
|
89
|
+
)
|
90
|
+
end
|
53
91
|
|
54
92
|
tags = find_tags_for(file)
|
55
|
-
tags <<
|
93
|
+
tags <<
|
94
|
+
new_tags.split(',')&.map(&:strip)&.map(&:downcase)&.map do |t|
|
95
|
+
# Replace spaces in tags with underscores, because spaces in
|
96
|
+
# filenames can cause all kinds of issues depending on what
|
97
|
+
# tools are used on the filenames. The less requirements for
|
98
|
+
# escaping filenames, the better.
|
99
|
+
t.gsub(' ', '_')
|
100
|
+
end
|
101
|
+
|
56
102
|
tags = tags.flatten.uniq.sort
|
57
103
|
|
58
104
|
new_filename = filename_with_tags(file, tags)
|
59
|
-
if file != new_filename
|
60
|
-
FileUtils.mv(file, new_filename)
|
61
|
-
end
|
105
|
+
FileUtils.mv(file, new_filename) if file != new_filename
|
62
106
|
|
63
107
|
new_filename
|
64
108
|
end
|
65
109
|
|
66
|
-
def read_and_add_tags_for(file, tags_path =
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
110
|
+
def read_and_add_tags_for(file, tags_path = '**/*')
|
111
|
+
unless File.exist?(file)
|
112
|
+
(
|
113
|
+
puts "File '#{file}' does not exist."
|
114
|
+
exit 1
|
115
|
+
)
|
72
116
|
end
|
73
117
|
|
74
|
-
|
75
|
-
|
118
|
+
tags = find_tags_for(tags_path)
|
119
|
+
Readline.completion_proc =
|
120
|
+
proc { |input| tags.select { |tag| tag.start_with?(input) } }
|
121
|
+
|
122
|
+
puts 'Add new tags:'
|
123
|
+
new_tags = Readline.readline('> ', false)
|
76
124
|
new_filename = add_tags_to_file(new_tags, file)
|
77
125
|
[new_tags, new_filename]
|
78
126
|
end
|
79
127
|
|
80
128
|
def delete_tag_from_file(tag, file)
|
81
|
-
|
129
|
+
unless file
|
130
|
+
(
|
131
|
+
puts 'Needs a FILE input; i.e. `-d tag1 filename`'
|
132
|
+
exit
|
133
|
+
)
|
134
|
+
end
|
82
135
|
|
83
136
|
tags = find_tags_for(file)
|
84
137
|
tags = tags.reject { |t| t == tag }
|
85
138
|
|
86
139
|
new_filename = filename_with_tags(file, tags)
|
87
|
-
if file != new_filename
|
88
|
-
FileUtils.mv(file, new_filename)
|
89
|
-
end
|
140
|
+
FileUtils.mv(file, new_filename) if file != new_filename
|
90
141
|
|
91
142
|
new_filename
|
92
143
|
end
|
93
144
|
|
94
|
-
|
95
145
|
def rename_tag(path, old_tag, new_tag)
|
96
|
-
|
146
|
+
unless new_tag
|
147
|
+
(
|
148
|
+
puts 'Needs a NEW_TAG input; i.e. `-r old_tag new_tag`'
|
149
|
+
exit
|
150
|
+
)
|
151
|
+
end
|
97
152
|
|
98
|
-
Dir.glob("#{path}
|
153
|
+
Dir.glob("#{path}/**/*--\\[*#{old_tag}*\\]*").each do |file|
|
99
154
|
file = add_tags_to_file(new_tag, file)
|
100
155
|
delete_tag_from_file(old_tag, file)
|
101
156
|
end
|
@@ -104,28 +159,61 @@ module OK
|
|
104
159
|
def main
|
105
160
|
OptionParser.new do |opts|
|
106
161
|
opts.banner = 'Usage: oktags [options]'
|
107
|
-
opts.on(
|
108
|
-
|
162
|
+
opts.on(
|
163
|
+
'-a',
|
164
|
+
'--add-tags TAGS FILE',
|
165
|
+
'Add comma-separated TAGS to FILE'
|
166
|
+
) do |tags|
|
167
|
+
add_tags_to_file(tags, ARGV[0])
|
109
168
|
exit
|
110
169
|
end
|
111
|
-
opts.on(
|
112
|
-
|
170
|
+
opts.on(
|
171
|
+
'-d',
|
172
|
+
'--delete-tag-from-file TAG FILE',
|
173
|
+
'Delete TAG from FILE'
|
174
|
+
) do |tag|
|
175
|
+
delete_tag_from_file(tag, ARGV[0])
|
113
176
|
exit
|
114
177
|
end
|
115
|
-
opts.on(
|
178
|
+
opts.on(
|
179
|
+
'-i',
|
180
|
+
'--add-tags-interactively FILE',
|
181
|
+
'Auto-complete tags and add them to FILE'
|
182
|
+
) do |file|
|
116
183
|
read_and_add_tags_for(file)
|
117
184
|
exit
|
118
185
|
end
|
119
|
-
opts.on(
|
186
|
+
opts.on(
|
187
|
+
'-l',
|
188
|
+
'--list [PATH]',
|
189
|
+
'List file tags recursively (at optional PATH)'
|
190
|
+
) do |path|
|
191
|
+
path ? list_pretty_tags(path) : list_pretty_tags
|
192
|
+
exit
|
193
|
+
end
|
194
|
+
opts.on(
|
195
|
+
'-r',
|
196
|
+
'--rename-tag OLD_TAG NEW_TAG',
|
197
|
+
'Rename OLD_TAG to NEW_TAG(S) recursively for all files'
|
198
|
+
) do |old_tag|
|
120
199
|
rename_tag('.', old_tag, ARGV[0])
|
121
200
|
exit
|
122
201
|
end
|
123
|
-
opts.on(
|
124
|
-
|
202
|
+
opts.on(
|
203
|
+
'-s',
|
204
|
+
'--search-files-with-tags TAGS [PATH]',
|
205
|
+
'Search files which include (comma-separated) TAGS recursively (at optional PATH)'
|
206
|
+
) do |tags|
|
207
|
+
if ARGV[0]
|
208
|
+
list_files_with_tags(tags, ARGV[0])
|
209
|
+
else
|
210
|
+
list_files_with_tags(tags)
|
211
|
+
end
|
125
212
|
exit
|
126
213
|
end
|
127
214
|
end.parse!
|
128
|
-
|
129
215
|
end
|
130
216
|
end
|
131
217
|
end
|
218
|
+
|
219
|
+
OK::Tags.main if $0 == __FILE__
|
data/lib/ok/version.rb
CHANGED
data/lib/oktags.rb
CHANGED
@@ -1 +1 @@
|
|
1
|
-
require File.expand_path(File.join(%w
|
1
|
+
require File.expand_path(File.join(%w[.. ok tags]), __FILE__)
|
data/oktags.gemspec
CHANGED
@@ -8,7 +8,7 @@ Gem::Specification.new do |spec|
|
|
8
8
|
spec.licenses = "AGPL-3.0-or-later"
|
9
9
|
|
10
10
|
spec.summary = %q{Manage tags on plain old files.}
|
11
|
-
spec.description = %q{oktags helps you organize your files by managing tags on them. It works by adding/removing
|
11
|
+
spec.description = %q{oktags helps you organize your files by managing tags on them. It works by adding/removing at the end of the filename. Given a file 'cat.jpg', when adding the tags 'tag1' and 'tag2', the filename will become 'cat--[tag1,tag2].jpg'. The implementation is OS-agnostic, so it should work on Linux, macOS and Windows. }
|
12
12
|
spec.homepage = "https://200ok.ch"
|
13
13
|
spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0")
|
14
14
|
|
metadata
CHANGED
@@ -1,18 +1,19 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: oktags
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alain M. Lafon
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-10-
|
11
|
+
date: 2020-10-19 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
|
-
description: oktags helps you organize your files by managing tags on them. It works
|
14
|
-
by adding/removing
|
15
|
-
|
13
|
+
description: 'oktags helps you organize your files by managing tags on them. It works
|
14
|
+
by adding/removing at the end of the filename. Given a file ''cat.jpg'', when adding
|
15
|
+
the tags ''tag1'' and ''tag2'', the filename will become ''cat--[tag1,tag2].jpg''.
|
16
|
+
The implementation is OS-agnostic, so it should work on Linux, macOS and Windows. '
|
16
17
|
email:
|
17
18
|
- info@200ok.ch
|
18
19
|
executables:
|
@@ -20,7 +21,7 @@ executables:
|
|
20
21
|
extensions: []
|
21
22
|
extra_rdoc_files: []
|
22
23
|
files:
|
23
|
-
- ".github/workflows/
|
24
|
+
- ".github/workflows/ci.yml"
|
24
25
|
- ".gitignore"
|
25
26
|
- ".rspec"
|
26
27
|
- ".ruby-version"
|
@@ -32,6 +33,7 @@ files:
|
|
32
33
|
- bin/console
|
33
34
|
- bin/oktags
|
34
35
|
- bin/setup
|
36
|
+
- lib/hash.rb
|
35
37
|
- lib/ok/tags.rb
|
36
38
|
- lib/ok/version.rb
|
37
39
|
- lib/oktags.rb
|