pdfmd 1.9.1 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +22 -2
- data/README.md +2 -2
- data/TODO.mkd +26 -0
- data/bin/pdfmd +267 -1
- data/lib/pdfmd.rb +242 -634
- data/lib/pdfmd/explain.hiera.md +25 -4
- data/lib/pdfmd/long_desc.pdfmdconfig.txt +40 -0
- data/lib/pdfmd/long_desc.pdfmdedit.txt +166 -0
- data/lib/pdfmd/long_desc.pdfmdexplain.txt +16 -0
- data/lib/pdfmd/long_desc.pdfmdrename.txt +206 -0
- data/lib/pdfmd/long_desc.pdfmdshow.txt +92 -0
- data/lib/pdfmd/long_desc.pdfmdsort.txt +111 -0
- data/lib/pdfmd/long_desc.pdfmdstat.txt +23 -0
- data/lib/pdfmd/pdfmdconfig.rb +30 -0
- data/lib/pdfmd/pdfmdedit.rb +201 -0
- data/lib/pdfmd/pdfmdmethods.rb +125 -0
- data/lib/pdfmd/pdfmdrename.rb +243 -0
- data/lib/pdfmd/pdfmdshow.rb +88 -0
- data/lib/pdfmd/pdfmdsort.rb +115 -0
- data/lib/pdfmd/pdfmdstat.rb +117 -0
- data/lib/{string_extend.rb → pdfmd/string_extend.rb} +0 -0
- data/lib/run.rb +235 -0
- data/pdfmd.gemspec +3 -2
- metadata +23 -11
- data/lib/pdfmd/check.rb +0 -10
- data/lib/pdfmd/config.rb +0 -59
- data/lib/pdfmd/edit.rb +0 -144
- data/lib/pdfmd/rename.rb +0 -295
- data/lib/pdfmd/show.rb +0 -164
- data/lib/pdfmd/sort.rb +0 -199
@@ -0,0 +1,125 @@
|
|
1
|
+
# == Module: pdfmdmethods
|
2
|
+
#
|
3
|
+
# Method to extend functionalities
|
4
|
+
module Pdfmdmethods
|
5
|
+
|
6
|
+
#
|
7
|
+
# Determine the valid setting
|
8
|
+
# 1. Priority: manual setting
|
9
|
+
# 2. Priority: Hiera setting
|
10
|
+
#
|
11
|
+
# If there is no manual setting, the value of 'manualSetting'
|
12
|
+
# should be set to 'nil'
|
13
|
+
#
|
14
|
+
def determineValidSetting(manualSetting,key)
|
15
|
+
|
16
|
+
if !@hieradata.nil?
|
17
|
+
hieraKey = '@hieradata'
|
18
|
+
hieraValue = ''
|
19
|
+
|
20
|
+
key.split(':').each do |keyname|
|
21
|
+
|
22
|
+
hieraKeyCheck = eval(hieraKey)
|
23
|
+
if !hieraKeyCheck.nil? and hieraKeyCheck.has_key?(keyname)
|
24
|
+
hieraKey = hieraKey + "['#{keyname}']"
|
25
|
+
else
|
26
|
+
# Key has not been found
|
27
|
+
hieraKey = ''
|
28
|
+
break
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
hieraValue = eval(hieraKey)
|
33
|
+
|
34
|
+
else
|
35
|
+
hieraValue = nil
|
36
|
+
end
|
37
|
+
|
38
|
+
if !manualSetting.nil?
|
39
|
+
self.log('debug', "Chosing manual setting '#{key} = #{manualSetting}'.")
|
40
|
+
manualSetting
|
41
|
+
elsif !hieraValue.nil? or
|
42
|
+
!hieraValue == ''
|
43
|
+
|
44
|
+
self.log('debug', "Chosing hiera setting '#{key} = #{hieraValue}'.")
|
45
|
+
hieraValue
|
46
|
+
|
47
|
+
else
|
48
|
+
self.log('debug', "No setting chosen for '#{key}' in hiera.")
|
49
|
+
false
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
|
55
|
+
#
|
56
|
+
# Logging stuff
|
57
|
+
def log(status = 'info', message)
|
58
|
+
|
59
|
+
# Setting the loglevel
|
60
|
+
case @loglevel
|
61
|
+
when /info/i
|
62
|
+
level = 'Logger::INFO'
|
63
|
+
when /warn/i
|
64
|
+
level = 'Logger::WARN'
|
65
|
+
when /error/i
|
66
|
+
level = 'Logger::ERROR'
|
67
|
+
when /debug/i
|
68
|
+
level = 'Logger::DEBUG'
|
69
|
+
else
|
70
|
+
level = 'Logger::INFO'
|
71
|
+
end
|
72
|
+
logger = Logger.new(@logfile)
|
73
|
+
logger.level = eval level
|
74
|
+
logger.send(status, message)
|
75
|
+
logger.close
|
76
|
+
|
77
|
+
end
|
78
|
+
|
79
|
+
|
80
|
+
|
81
|
+
#
|
82
|
+
# Query hiera for settings if available
|
83
|
+
def queryHiera(keyword, facts = 'UNSET')
|
84
|
+
|
85
|
+
pathHieraConfig = [
|
86
|
+
'/etc/hiera.yaml',
|
87
|
+
'/etc/puppet/hiera.yaml',
|
88
|
+
'/etc/puppetlabs/puppet/hiera.yaml',
|
89
|
+
]
|
90
|
+
hieraConfig = ''
|
91
|
+
pathHieraConfig.each do |path|
|
92
|
+
if File.exist? path
|
93
|
+
hieraConfig = path
|
94
|
+
break
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
# Set default facts
|
99
|
+
facts == 'UNSET' ? facts = "fqdn=#{`hostname`}".chomp : ''.chomp
|
100
|
+
|
101
|
+
# If Hiera is not found (damn cat, get of my keyboard!), return false,
|
102
|
+
# otherwise return the hash from Hiera
|
103
|
+
if !system('which hiera > /dev/null 2>&1')
|
104
|
+
self.log('warn','Cannot find hiera command in $path.')
|
105
|
+
puts 'Cannot find "hiera" command in $path.'
|
106
|
+
return eval('{}')
|
107
|
+
else
|
108
|
+
|
109
|
+
self.log('debug', 'Reading hiera values for pdfmd::config.')
|
110
|
+
commandreturn = ''
|
111
|
+
commandreturn = `hiera -c #{hieraConfig} #{keyword} #{facts} 2>/dev/null`
|
112
|
+
|
113
|
+
if $?.exitstatus == 1
|
114
|
+
self.log('warn', 'Could not retrieve configuration from with hiera.')
|
115
|
+
eval('{}')
|
116
|
+
else
|
117
|
+
self.log('debug', 'Could retrieve configuration from hiera.')
|
118
|
+
eval(commandreturn)
|
119
|
+
end
|
120
|
+
|
121
|
+
end
|
122
|
+
|
123
|
+
end # End of queryHiera
|
124
|
+
|
125
|
+
end
|
@@ -0,0 +1,243 @@
|
|
1
|
+
# == Class: pdfmdrename
|
2
|
+
#
|
3
|
+
# Class for renaming the file according to the metadata
|
4
|
+
#
|
5
|
+
class Pdfmdrename < Pdfmd
|
6
|
+
|
7
|
+
attr_accessor :filename, :dryrun, :allkeywords, :outputdir, :nrkeywords, :copy
|
8
|
+
|
9
|
+
# document key mappings to determine the document type based on the
|
10
|
+
# string in the meta field 'title'
|
11
|
+
@@keymapping = {
|
12
|
+
'cno' => ['Customer','Customernumber'],
|
13
|
+
'con' => ['Contract'],
|
14
|
+
'inf' => ['Information'],
|
15
|
+
'inv' => ['Invoice', 'Invoicenumber'],
|
16
|
+
'man' => ['Manual'],
|
17
|
+
'off' => ['Offer', 'Offernumber'],
|
18
|
+
'ord' => ['Order', 'Ordernumber'],
|
19
|
+
'rec' => ['Receipt', 'Receiptnumber'],
|
20
|
+
'tic' => ['Ticket'],
|
21
|
+
}
|
22
|
+
|
23
|
+
def initialize(filename)
|
24
|
+
super(filename)
|
25
|
+
@nrkeywords ||= 3
|
26
|
+
|
27
|
+
# Find the valid keymapping
|
28
|
+
# Use @@keymapping as default and only overwrite when provided by hiera.
|
29
|
+
hierakeymapping = self.determineValidSetting(nil, 'rename:keys')
|
30
|
+
hierakeymapping ? @@keymapping = hierakeymapping : ''
|
31
|
+
|
32
|
+
# FIXME: this default doctype assignment might need to be rewritten as the keymapping above.
|
33
|
+
@defaultDoctype = self.determineValidSetting('doc', 'rename:defaultdoctype')
|
34
|
+
@fileextension = 'pdf'
|
35
|
+
end
|
36
|
+
|
37
|
+
def rename
|
38
|
+
|
39
|
+
# Build new filename elements
|
40
|
+
newFilename = Hash.new
|
41
|
+
newFilename[:date] = @@metadata['createdate'].gsub(/\ \d{2}\:\d{2}\:\d{2}.*$/,'').gsub(/\:/,'')
|
42
|
+
newFilename[:author] = get_author()
|
43
|
+
newFilename[:doctype] = get_doctype()
|
44
|
+
newFilename[:title] = @@metadata['title'].downcase
|
45
|
+
newFilename[:subject] = @@metadata['subject'].downcase.gsub(/(\s|\-|\.|\&|\%)/,'_')
|
46
|
+
newFilename[:keywords] = get_keywords(get_keywordsPreface(newFilename))
|
47
|
+
newFilename[:extension] = @fileextension
|
48
|
+
newFilename[:outputdir] = get_outputdir(@outputdir)
|
49
|
+
|
50
|
+
command = @copy ? 'cp' : 'mv'
|
51
|
+
|
52
|
+
filetarget = get_filename(newFilename)
|
53
|
+
if @dryrun # Do nothing on dryrun
|
54
|
+
if @filename == filetarget
|
55
|
+
self.log('info', "Dryrun: File '#{@filename}' already has the correct name. Doing nothing.")
|
56
|
+
else
|
57
|
+
self.log('info',"Dryrun: Renaming '#{@filename}' to '#{get_filename(newFilename)}'.")
|
58
|
+
end
|
59
|
+
elsif @filename == filetarget # Do nothing when name is already correct.
|
60
|
+
self.log('info',"File '#{@filename}' already has the correct name. Doing nothing.")
|
61
|
+
else
|
62
|
+
self.log('info',"Renaming '#{@filename}' to '#{filetarget}'.")
|
63
|
+
command = command + " '#{@filename}' #{filetarget} 2>/dev/null"
|
64
|
+
system(command)
|
65
|
+
if !$?.exitstatus
|
66
|
+
log('error', "Error renaming '#{@filename}' to '#{filetarget}'.")
|
67
|
+
abort
|
68
|
+
else
|
69
|
+
log('info', "Successfully renamed file to '#{filetarget}'.")
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
#
|
76
|
+
# Return the filename from the available filedata
|
77
|
+
def get_filename(filedata = {})
|
78
|
+
|
79
|
+
if filedata.size > 0
|
80
|
+
|
81
|
+
# Create the filename out of all with some exceptions
|
82
|
+
#
|
83
|
+
# If the doctype is the default one, the first keywords are the
|
84
|
+
# title and the subject
|
85
|
+
if filedata[:doctype] == @defaultDoctype
|
86
|
+
|
87
|
+
# The subject and title is part of the keywords and handled there.
|
88
|
+
filedata[:outputdir] + '/' +
|
89
|
+
filedata[:date] + '-' +
|
90
|
+
filedata[:author] + '-' +
|
91
|
+
filedata[:doctype] + '-' +
|
92
|
+
filedata[:keywords] + '.' +
|
93
|
+
filedata[:extension]
|
94
|
+
else
|
95
|
+
filedata[:outputdir] + '/' + filedata.except(:extension, :title, :subject, :outputdir).values.join('-') + '.' + filedata[:extension]
|
96
|
+
end
|
97
|
+
|
98
|
+
else
|
99
|
+
|
100
|
+
false
|
101
|
+
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
105
|
+
|
106
|
+
# Validate the output directory
|
107
|
+
def get_outputdir(outputdir = '')
|
108
|
+
|
109
|
+
if !outputdir # outputdir is set to false, assume pwd
|
110
|
+
self.log('debug','No outputdir specified. Taking current pwd of file.')
|
111
|
+
outputdir = File.dirname(@filename)
|
112
|
+
elsif outputdir and !File.exist?(outputdir)
|
113
|
+
puts "Error: output directory '#{outputdir}' not found. Abort."
|
114
|
+
self.log('error',"Output directory '#{outputdir}' not accessible. Abort.")
|
115
|
+
exit 1
|
116
|
+
elsif outputdir and File.exist?(outputdir)
|
117
|
+
outputdir
|
118
|
+
else
|
119
|
+
false
|
120
|
+
end
|
121
|
+
|
122
|
+
end
|
123
|
+
|
124
|
+
# Get the keywords
|
125
|
+
def get_keywords(preface = '')
|
126
|
+
|
127
|
+
if !@@metadata['keywords'].empty?
|
128
|
+
|
129
|
+
keywordsarray = @@metadata['keywords'].split(',')
|
130
|
+
# Replace leading spaces and strings from the keymappings
|
131
|
+
# if the value is identical it will be placed at the beginning
|
132
|
+
# of the array (and therefore be right after the preface in the filename)
|
133
|
+
keywordsarraySorted = Array.new
|
134
|
+
keywordsarray.each_with_index do |value,index|
|
135
|
+
value = value.lstrip.chomp
|
136
|
+
|
137
|
+
@@keymapping.each do |abbreviation,keyvaluearray|
|
138
|
+
if keyvaluearray.kind_of?(String)
|
139
|
+
keyvaluearray = keyvaluearray.split(',')
|
140
|
+
end
|
141
|
+
keyvaluearray = keyvaluearray.sort_by{|size| -size.length}
|
142
|
+
keyvaluearray.each do |keystring|
|
143
|
+
value = value.gsub(/#{keystring.lstrip.chomp}\s?/i, abbreviation.to_s)
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
# Remove special characters from string
|
148
|
+
keywordsarray[index] = value.gsub(/\s|\/|\-|\./,'_')
|
149
|
+
|
150
|
+
# If the current value matches some of the replacement abbreviations,
|
151
|
+
# put the value at index 0 in the array. It will then be listed earlier in the filename.
|
152
|
+
if value.match(/^#{@@keymapping.keys.join('|')} /i)
|
153
|
+
keywordsarraySorted.insert(0, keywordsarray[index])
|
154
|
+
else
|
155
|
+
keywordsarraySorted.push(keywordsarray[index])
|
156
|
+
end
|
157
|
+
|
158
|
+
end
|
159
|
+
|
160
|
+
# Insert the preface if it is not empty
|
161
|
+
if !preface.to_s.empty?
|
162
|
+
keywordsarraySorted.insert(0, preface)
|
163
|
+
end
|
164
|
+
|
165
|
+
# Convert the keywordarray to a string an limit the number
|
166
|
+
# of keywords according to @nrkeywords or the parameter 'all'
|
167
|
+
if @@metadata['keywords'] = !@allkeywords
|
168
|
+
keywords = keywordsarraySorted.values_at(*(0..@nrkeywords-1)).join('-')
|
169
|
+
else
|
170
|
+
keywords = keywordsarraySorted.join('-')
|
171
|
+
end
|
172
|
+
|
173
|
+
# Normalize all keywords and return value
|
174
|
+
I18n.enforce_available_locales = false
|
175
|
+
I18n.transliterate(keywords).downcase.chomp('-')
|
176
|
+
|
177
|
+
else # Keywords metafield is empty :(
|
178
|
+
# So we return nothing or the preface (if available)
|
179
|
+
|
180
|
+
!preface.empty? ? preface : ''
|
181
|
+
|
182
|
+
end
|
183
|
+
|
184
|
+
end
|
185
|
+
|
186
|
+
|
187
|
+
|
188
|
+
# Get the preface for the keywords
|
189
|
+
# If the title is meaningful, then the
|
190
|
+
# subject will become the preface ( = first keyword)
|
191
|
+
# If the subject matches number/character combination and contains no spaces,
|
192
|
+
# the preface will be combined with the doctype.
|
193
|
+
# If not: The preface will contain the whole subject with dots and spaces being
|
194
|
+
# replaced with underscores.
|
195
|
+
def get_keywordsPreface(filedata = {})
|
196
|
+
|
197
|
+
I18n.enforce_available_locales = false
|
198
|
+
if filedata[:doctype].nil? or filedata[:doctype].empty?
|
199
|
+
filedata[:doctype] = @defaultDoctype
|
200
|
+
end
|
201
|
+
|
202
|
+
if !filedata[:subject].nil? and !filedata[:subject].empty? and
|
203
|
+
!filedata[:doctype] == @defaultDoctype
|
204
|
+
|
205
|
+
I18n.transliterate(filedata[:subject])
|
206
|
+
|
207
|
+
else
|
208
|
+
|
209
|
+
# Document matches standard document type.
|
210
|
+
# title and subject are being returned.
|
211
|
+
|
212
|
+
# Normalize special characters
|
213
|
+
title = @@metadata['title'].downcase
|
214
|
+
subject = !filedata[:subject].empty? ? '_' + filedata[:subject].downcase : ''
|
215
|
+
subject = subject.gsub(/\s|\-|\&/, '_')
|
216
|
+
I18n.transliterate(title + subject)
|
217
|
+
|
218
|
+
end
|
219
|
+
|
220
|
+
end
|
221
|
+
|
222
|
+
# Get the doctype from the title
|
223
|
+
#
|
224
|
+
def get_doctype()
|
225
|
+
doctype = @defaultDoctype
|
226
|
+
@@keymapping.each do |key,value|
|
227
|
+
value.kind_of?(String) ? value = value.split : ''
|
228
|
+
value.each do |keyword|
|
229
|
+
@@metadata['title'].match(/#{keyword}/i) ? doctype = key : ''
|
230
|
+
end
|
231
|
+
end
|
232
|
+
doctype.downcase
|
233
|
+
end
|
234
|
+
|
235
|
+
# Get the author from the metatags and
|
236
|
+
# normalize the string
|
237
|
+
def get_author()
|
238
|
+
author = @@metadata['author'].gsub(/\./,'_').gsub(/\&/,'').gsub(/\-/,'').gsub(/\s|\//,'_').gsub(/\,/,'_').gsub(/\_\_/,'_')
|
239
|
+
I18n.enforce_available_locales = false
|
240
|
+
I18n.transliterate(author).downcase # Normalising
|
241
|
+
end
|
242
|
+
|
243
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
# == Class: pdfmd.show
|
2
|
+
#
|
3
|
+
class Pdfmdshow < Pdfmd
|
4
|
+
attr_accessor :filename
|
5
|
+
|
6
|
+
@@show_filename = false
|
7
|
+
@@outputformat = ''
|
8
|
+
@@default_tags = ['createdate', 'author', 'title', 'subject', 'keywords']
|
9
|
+
|
10
|
+
def initialize(filename)
|
11
|
+
super(filename)
|
12
|
+
@filename = filename
|
13
|
+
end
|
14
|
+
|
15
|
+
|
16
|
+
# Define if the filename should be visible in the output
|
17
|
+
def show_filename( enable = nil)
|
18
|
+
@@show_filename = enable ? true : false
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
# Define the output format for showing the metadata
|
23
|
+
def set_outputformat( format = 'yaml' )
|
24
|
+
format.nil? ? format = 'yaml' : ''
|
25
|
+
self.log('debug',"Output format set to '#{format}'.")
|
26
|
+
@@outputformat = format
|
27
|
+
end
|
28
|
+
|
29
|
+
# Overvwrite the tags
|
30
|
+
def set_tags( tags = @@default_tags)
|
31
|
+
|
32
|
+
if tags
|
33
|
+
|
34
|
+
# Tags can be specified as array or string
|
35
|
+
#
|
36
|
+
case tags.class.to_s
|
37
|
+
when /array/i
|
38
|
+
@@default_tags = tags
|
39
|
+
when /string/i
|
40
|
+
@@default_tags = tags.split(/,\s+/)
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
# Return the provided metatags
|
48
|
+
def show_metatags( tags = @@default_tags, format = @@outputformat, show_filename = @@show_filename )
|
49
|
+
|
50
|
+
# Build the output hash from the tags matching the values in @@default_tags
|
51
|
+
metadataOutputHash = Hash.new
|
52
|
+
tags.each do |tagname|
|
53
|
+
if @@metadata.has_key?(tagname)
|
54
|
+
metadataOutputHash[tagname] = @@metadata[tagname]
|
55
|
+
elsif tagname.downcase == 'all' # Exception when for keyword 'all'
|
56
|
+
metadataOutputHash = @@metadata
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
if show_filename
|
61
|
+
metadataOutputHash['filename'] = @filename
|
62
|
+
end
|
63
|
+
|
64
|
+
# Return output well formatted
|
65
|
+
case format
|
66
|
+
when /hash/i
|
67
|
+
self.log('info',"Showing metatags for '#{@filename}' in format 'hash'.")
|
68
|
+
metadataOutputHash
|
69
|
+
when /csv/i
|
70
|
+
csvData = Hash.new
|
71
|
+
metadataOutputHash.keys.each do |tagname|
|
72
|
+
csvData[tagname] = '"' + metadataOutputHash[tagname.downcase].to_s.gsub(/"/,'""') + '"'
|
73
|
+
end
|
74
|
+
self.log('info',"Showing metatags for '#{@filename}' in format 'csv'.")
|
75
|
+
csvData.values.join(',')
|
76
|
+
when /json/i
|
77
|
+
require 'json'
|
78
|
+
self.log('info',"Showing metatags for '#{@filename}' in format 'json'.")
|
79
|
+
metadataOutputHash.to_json
|
80
|
+
else
|
81
|
+
require 'yaml'
|
82
|
+
self.log('info',"Showing metatags for '#{@filename}' in format 'yaml'.")
|
83
|
+
metadataOutputHash.to_yaml
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|