oktags 0.1.0 → 0.2.2
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.
- 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
|