tmsu_file_db 0.0.1
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 +7 -0
- data/bin/tmsu_file_db +10 -0
- data/lib/tmsu_file_db.rb +270 -0
- data/lib/version.rb +3 -0
- metadata +61 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 87c86606a333c58a62d8d6c1d6db1cdee4da35dc
|
4
|
+
data.tar.gz: fbae0484413b490c0e1c98f5a415b95e7ef46b0f
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 220887318854f6a1a9037bf265edc70f547384f8acc44b4d75b7b3a5f00026fdf0c75c913e453c7d6800446f857cb357ac40d9ed2526817b185a42f7f39f6d11
|
7
|
+
data.tar.gz: f5fc16da123e6a2c8eb1eec9f476905e7d4a85193125298efac7e42119f41d2b33ea762da7902a8fbffaf1519599b83d22ce87a76c02c374beefe109b418aa5a
|
data/bin/tmsu_file_db
ADDED
data/lib/tmsu_file_db.rb
ADDED
@@ -0,0 +1,270 @@
|
|
1
|
+
require 'securerandom'
|
2
|
+
require 'gemmy'
|
3
|
+
|
4
|
+
module TmsuFileDb
|
5
|
+
def self.start
|
6
|
+
::TmsuRuby.start
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
class TmsuModel
|
11
|
+
Config = { root_path: "." }
|
12
|
+
Validations = Hash.new { |h,k| h[k] = [] }
|
13
|
+
Callbacks = {}
|
14
|
+
|
15
|
+
def self.query_glob
|
16
|
+
"#{Config[:root_path] || "."}/*"
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.configure(root_path:)
|
20
|
+
Config[:root_path] = root_path || "./db".tap do |path|
|
21
|
+
`mkdir #{path}`
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.validate(attribute=nil, &blk)
|
26
|
+
if attribute
|
27
|
+
Validations[:generic] << blk
|
28
|
+
else
|
29
|
+
Validations[attribute] << blk
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.add_callback name, &blk
|
34
|
+
Callbacks[name] = blk
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.opts_to_query opts
|
38
|
+
case opts
|
39
|
+
when Array
|
40
|
+
opts.join " "
|
41
|
+
when Hash
|
42
|
+
opts.map { |k,v| "#{k}={v}" }.join(" ")
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.find_by opts
|
47
|
+
where(opts).first
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.where opts={}
|
51
|
+
query opts_to_query opts
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.query string
|
55
|
+
TmsuFile.new(query_glob).paths_query(query)
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.update_all opts={}
|
59
|
+
Dir.glob(query_glob).each { |path| new(path).update(opts) }
|
60
|
+
end
|
61
|
+
|
62
|
+
def self.destroy_all opts={}
|
63
|
+
Dir.glob(query_glob).each { |path| `rm #{path}` }
|
64
|
+
end
|
65
|
+
|
66
|
+
attr_reader :attributes, :errors, :path
|
67
|
+
|
68
|
+
def initialize(attrs={})
|
69
|
+
attrs = attrs.with_indifferent_access
|
70
|
+
@path = build_id(attrs.delete :id)
|
71
|
+
@attributes = attrs
|
72
|
+
@persisted = File.exists? @path
|
73
|
+
@errors = []
|
74
|
+
end
|
75
|
+
|
76
|
+
def build_id(given=nil)
|
77
|
+
rand_id = given || SecureRandom.urlsafe_base64
|
78
|
+
prefix = "#{self.class::Config[:root_path]}"
|
79
|
+
if prefix
|
80
|
+
"#{prefix}/#{rand_id}"
|
81
|
+
else
|
82
|
+
"#{rand_id}"
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def []=(k,v)
|
87
|
+
attributes[k] = v
|
88
|
+
end
|
89
|
+
|
90
|
+
def [](k)
|
91
|
+
attributes[k]
|
92
|
+
end
|
93
|
+
|
94
|
+
def method_missing(sym, *arguments, &blk)
|
95
|
+
if attributes.keys.include? sym
|
96
|
+
attributes[sym]
|
97
|
+
else
|
98
|
+
super
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def write(text, append: false)
|
103
|
+
return unless text
|
104
|
+
File.open(path, "w#{"a" if append}") { |f| f.write text }
|
105
|
+
self
|
106
|
+
end
|
107
|
+
|
108
|
+
def append(text)
|
109
|
+
write(text, append: true)
|
110
|
+
self
|
111
|
+
end
|
112
|
+
|
113
|
+
def valid?
|
114
|
+
@errors = []
|
115
|
+
Validations.each do |type, procs|
|
116
|
+
procs.each do |proc|
|
117
|
+
some_errors = if type.eql?(:generic)
|
118
|
+
proc.call self
|
119
|
+
else
|
120
|
+
proc.call self[type], self
|
121
|
+
end
|
122
|
+
raise(
|
123
|
+
ArgumentError, "validations must return arrays"
|
124
|
+
) unless some_errors.is_a?(Array)
|
125
|
+
@errors.concat some_errors
|
126
|
+
end
|
127
|
+
end
|
128
|
+
@errors.empty?
|
129
|
+
end
|
130
|
+
|
131
|
+
def persisted?
|
132
|
+
!!@persisted
|
133
|
+
end
|
134
|
+
|
135
|
+
def ensure_persisted
|
136
|
+
`touch #{path}` unless persisted?
|
137
|
+
end
|
138
|
+
|
139
|
+
def save
|
140
|
+
ensure_persisted
|
141
|
+
tag attributes
|
142
|
+
self
|
143
|
+
end
|
144
|
+
|
145
|
+
def update attrs={}
|
146
|
+
attrs.each_key { |k| self[k] = attrs[k] }
|
147
|
+
save
|
148
|
+
self
|
149
|
+
end
|
150
|
+
|
151
|
+
def destroy
|
152
|
+
`rm #{path}`
|
153
|
+
self
|
154
|
+
end
|
155
|
+
|
156
|
+
end
|
157
|
+
|
158
|
+
module SystemPatch
|
159
|
+
refine Object do
|
160
|
+
def system string
|
161
|
+
`#{string}`.tap &method(:puts)
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
module TmsuRubyInitializer
|
167
|
+
using SystemPatch
|
168
|
+
def start
|
169
|
+
init_tmsu
|
170
|
+
end
|
171
|
+
def init_tmsu
|
172
|
+
puts "initializing tmsu"
|
173
|
+
puts system "tmsu init"
|
174
|
+
puts "making vfs_path #{vfs_path}"
|
175
|
+
puts system "mkdir #{vfs_path}"
|
176
|
+
puts "mounting vfs path"
|
177
|
+
puts system "tmsu mount #{vfs_path}"
|
178
|
+
end
|
179
|
+
def vfs_path
|
180
|
+
"/home/max/tmsu_vfs"
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
module TmsuFileAPI
|
185
|
+
|
186
|
+
using SystemPatch
|
187
|
+
|
188
|
+
def tags
|
189
|
+
ensure_persisted
|
190
|
+
system("tmsu tags #{path}").split(" ")[1..-1].reduce({}) do |res, tag|
|
191
|
+
key, val = tag.split("=")
|
192
|
+
res.tap { res[key] = val }
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
def paths_query(query)
|
197
|
+
query_root = "#{vfs_path}/queries/#{query}"
|
198
|
+
system("ls #{query_root}").split("\n").map do |filename|
|
199
|
+
system("readlink #{query_root}/#{filename}").chomp
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
def untag tag_list
|
204
|
+
`touch #{path}` unless persisted?
|
205
|
+
attributes.delete
|
206
|
+
system "tmsu untag #{path} #{tag_list}"
|
207
|
+
tags
|
208
|
+
end
|
209
|
+
|
210
|
+
def tag tag_obj
|
211
|
+
`touch #{path}` unless persisted?
|
212
|
+
system "tmsu tag #{path} #{build_tag_arg tag_obj}"
|
213
|
+
tags
|
214
|
+
end
|
215
|
+
|
216
|
+
def build_tag_arg obj
|
217
|
+
case obj
|
218
|
+
when String
|
219
|
+
obj
|
220
|
+
when Array
|
221
|
+
obj.join " "
|
222
|
+
when Hash
|
223
|
+
obj.map {|k,v| "#{k}=#{v}" }.join " "
|
224
|
+
else
|
225
|
+
obj
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
def tag_selector(tag_obj)
|
230
|
+
system "tmsu tag --tags '#{build_tag_arg tag_obj}' #{path}"
|
231
|
+
files tag_obj
|
232
|
+
end
|
233
|
+
|
234
|
+
def merge_tag(source, dest)
|
235
|
+
source_files = files source
|
236
|
+
dest_files = files dest
|
237
|
+
raise(ArgumentError, "#{source} tag not found") if source_files.empty?
|
238
|
+
raise(ArgumentError, "#{dest} tag not found") if dest_files.empty?
|
239
|
+
system("tmsu merge #{source} #{dest}")
|
240
|
+
source_files
|
241
|
+
end
|
242
|
+
|
243
|
+
def files(tag_obj)
|
244
|
+
system("tmsu files #{build_tag_arg tag_obj }").split("\n")
|
245
|
+
end
|
246
|
+
|
247
|
+
end
|
248
|
+
|
249
|
+
class TmsuRuby
|
250
|
+
extend TmsuRubyInitializer
|
251
|
+
|
252
|
+
def self.file(path=nil)
|
253
|
+
TmsuRuby::TmsuFile.new path, vfs_path
|
254
|
+
end
|
255
|
+
|
256
|
+
def self.model(path=nil)
|
257
|
+
record = TmsuModel.new id: path
|
258
|
+
end
|
259
|
+
|
260
|
+
class TmsuFile
|
261
|
+
include TmsuFileAPI
|
262
|
+
attr_reader :path, :vfs_path
|
263
|
+
def initialize path, vfs_path
|
264
|
+
@path = path
|
265
|
+
@vfs_path = vfs_path
|
266
|
+
end
|
267
|
+
end
|
268
|
+
end
|
269
|
+
|
270
|
+
TmsuModel.include TmsuFileAPI
|
data/lib/version.rb
ADDED
metadata
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: tmsu_file_db
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- maxpleaner
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2017-01-08 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: gemmyrb
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
description: ''
|
28
|
+
email: maxpleaner@gmail.com
|
29
|
+
executables:
|
30
|
+
- tmsu_file_db
|
31
|
+
extensions: []
|
32
|
+
extra_rdoc_files: []
|
33
|
+
files:
|
34
|
+
- bin/tmsu_file_db
|
35
|
+
- lib/tmsu_file_db.rb
|
36
|
+
- lib/version.rb
|
37
|
+
homepage: http://github.com/maxpleaner/tmsu_file_db
|
38
|
+
licenses:
|
39
|
+
- MIT
|
40
|
+
metadata: {}
|
41
|
+
post_install_message:
|
42
|
+
rdoc_options: []
|
43
|
+
require_paths:
|
44
|
+
- lib
|
45
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - "~>"
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: '2.3'
|
50
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 2.5.1
|
55
|
+
requirements: []
|
56
|
+
rubyforge_project:
|
57
|
+
rubygems_version: 2.5.1
|
58
|
+
signing_key:
|
59
|
+
specification_version: 4
|
60
|
+
summary: a 'database' using TMSU file tagging system
|
61
|
+
test_files: []
|