pdfmd 1.9.1 → 2.0.0
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/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
|