evertils 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/lib/command.rb +179 -0
- data/lib/config.rb +14 -0
- data/lib/configs/templates/daily-friday.enml +14 -0
- data/lib/configs/templates/daily.enml +9 -0
- data/lib/configs/templates/monthly.enml +21 -0
- data/lib/configs/templates/quarterly.enml +0 -0
- data/lib/configs/templates/weekly.enml +18 -0
- data/lib/constants.rb +12 -0
- data/lib/controller.rb +113 -0
- data/lib/controllers/convert.rb +63 -0
- data/lib/controllers/generate.rb +51 -0
- data/lib/controllers/get.rb +70 -0
- data/lib/controllers/new.rb +88 -0
- data/lib/helper.rb +19 -0
- data/lib/helpers/evernote-enml.rb +33 -0
- data/lib/helpers/evernote-markdown.rb +210 -0
- data/lib/helpers/evernote.rb +260 -0
- data/lib/helpers/generate.rb +39 -0
- data/lib/helpers/time.rb +28 -0
- data/lib/log.rb +111 -0
- data/lib/logs.rb +34 -0
- data/lib/model.rb +26 -0
- data/lib/model_data.rb +97 -0
- data/lib/request.rb +20 -0
- data/lib/router.rb +73 -0
- data/lib/utils.rb +123 -0
- metadata +69 -0
@@ -0,0 +1,33 @@
|
|
1
|
+
module Granify
|
2
|
+
module Helper
|
3
|
+
class EvernoteENML
|
4
|
+
attr_reader :element, :embeddable_element
|
5
|
+
|
6
|
+
def initialize(file = nil)
|
7
|
+
@file = file
|
8
|
+
@element = enml_element
|
9
|
+
|
10
|
+
if !@element.nil?
|
11
|
+
@embeddable_element = "<hr/>Attachment with hash #{@element.data.bodyHash}<br /><en-media type=\"#{@element.mime}\" hash=\"#{@element.data.bodyHash}\" /><br /><br />"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
def enml_element
|
17
|
+
if @file
|
18
|
+
read_file = File.open(@file, 'rb') { |io| io.read }
|
19
|
+
|
20
|
+
el = ::Evernote::EDAM::Type::Resource.new()
|
21
|
+
el.mime = MIME::Types.type_for(@file)[0].content_type
|
22
|
+
el.data = ::Evernote::EDAM::Type::Data.new()
|
23
|
+
el.data.size = read_file.size
|
24
|
+
el.data.bodyHash = Digest::MD5.hexdigest(read_file)
|
25
|
+
el.data.body = read_file
|
26
|
+
el.attributes = ::Evernote::EDAM::Type::ResourceAttributes.new()
|
27
|
+
el.attributes.fileName = @file # temporary for now, the actual file name
|
28
|
+
el
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,210 @@
|
|
1
|
+
require 'rexml/document'
|
2
|
+
require 'benchmark'
|
3
|
+
include REXML
|
4
|
+
include Benchmark
|
5
|
+
|
6
|
+
# reverse markdown for ruby
|
7
|
+
# author: JO
|
8
|
+
# e-mail: xijo@gmx.de
|
9
|
+
# date: 14.7.2009
|
10
|
+
# version: 0.1
|
11
|
+
# license: GPL
|
12
|
+
# edited by: Daniel Spencer
|
13
|
+
# https://github.com/indspenceable/en-cli/blob/master/lib/en/markdown_parser.rb
|
14
|
+
|
15
|
+
# TODO
|
16
|
+
# - ol numbering is buggy, in fact doesn't matter for markdown code
|
17
|
+
|
18
|
+
module Granify
|
19
|
+
module Helper
|
20
|
+
class EvernoteMD
|
21
|
+
# set basic variables:
|
22
|
+
# - @li_counter: numbering list item (li) tags in an ordered list (ol)
|
23
|
+
# - @links: hold the links for adding them to the bottom of the @output
|
24
|
+
# this means 'reference style', please take a look at http://daringfireball.net/projects/markdown/syntax#link
|
25
|
+
# - @outout: fancy markdown code in here!
|
26
|
+
# - @indent: control indention level for nested lists
|
27
|
+
# - @errors: appearing errors, like unknown tags, go into this array
|
28
|
+
def initialize()
|
29
|
+
@li_counter = 0
|
30
|
+
@links = []
|
31
|
+
@output = ""
|
32
|
+
@indent = 0
|
33
|
+
@errors = []
|
34
|
+
end
|
35
|
+
|
36
|
+
# Invokes the HTML parsing by using a string. Returns the markdown code in @output.
|
37
|
+
# To garantuee well-formed xml for REXML a <root> element will be added, but has no effect.
|
38
|
+
# After parsing all elements, the 'reference style'-links will be inserted.
|
39
|
+
def parse_string(string)
|
40
|
+
doc = Document.new("<root>\n"+string+"\n</root>")
|
41
|
+
root = doc.root
|
42
|
+
root.elements.each do |element|
|
43
|
+
parse_element(element, :root)
|
44
|
+
end
|
45
|
+
insert_links()
|
46
|
+
@output
|
47
|
+
end
|
48
|
+
|
49
|
+
# Parsing an element and its children (recursive) and writing its markdown code to @output
|
50
|
+
# 1. do indent for nested list items
|
51
|
+
# 2. add the markdown opening tag for this element
|
52
|
+
# 3a. if element only contains text, handle it like a text node
|
53
|
+
# 3b. if element is a container handle its children, which may be text- or element nodes
|
54
|
+
# 4. finally add the markdown ending tag for this element
|
55
|
+
def parse_element(element, parent)
|
56
|
+
name = element.name.to_sym
|
57
|
+
# 1.
|
58
|
+
@output << indent() if name.eql?(:li)
|
59
|
+
# 2.
|
60
|
+
@output << opening(element, parent)
|
61
|
+
|
62
|
+
# 3a.
|
63
|
+
if (element.has_text? and element.children.size < 2)
|
64
|
+
@output << text_node(element, parent)
|
65
|
+
end
|
66
|
+
|
67
|
+
# 3b.
|
68
|
+
if element.has_elements?
|
69
|
+
element.children.each do |child|
|
70
|
+
# increase indent if nested list
|
71
|
+
@indent += 1 if element.name=~/(ul|ol)/ and parent.eql?(:li)
|
72
|
+
|
73
|
+
if child.node_type.eql?(:element)
|
74
|
+
parse_element(child, element.name.to_sym)
|
75
|
+
else
|
76
|
+
if parent.eql?(:blockquote)
|
77
|
+
@output << child.to_s.gsub("\n ", "\n>")
|
78
|
+
else
|
79
|
+
@output << child.to_s
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
# decrease indent if end of nested list
|
84
|
+
@indent -= 1 if element.name=~/(ul|ol)/ and parent.eql?(:li)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
# 4.
|
89
|
+
@output << ending(element, parent)
|
90
|
+
end
|
91
|
+
|
92
|
+
# Returns opening markdown tag for the element. Its parent matters sometimes!
|
93
|
+
def opening(type, parent)
|
94
|
+
case type.name.to_sym
|
95
|
+
when :h1
|
96
|
+
"# "
|
97
|
+
when :li || :"en-todo"
|
98
|
+
parent.eql?(:ul) ? " - " : " "+(@li_counter+=1).to_s+". "
|
99
|
+
when :ol
|
100
|
+
@li_counter = 0
|
101
|
+
""
|
102
|
+
when :ul
|
103
|
+
""
|
104
|
+
when :h2
|
105
|
+
"## "
|
106
|
+
when :em
|
107
|
+
"*"
|
108
|
+
when :strong
|
109
|
+
"**"
|
110
|
+
when :blockquote
|
111
|
+
# remove leading newline
|
112
|
+
type.children.first.value = ""
|
113
|
+
"> "
|
114
|
+
when :code
|
115
|
+
parent.eql?(:pre) ? " " : "`"
|
116
|
+
when :a
|
117
|
+
"["
|
118
|
+
when :img
|
119
|
+
"!["
|
120
|
+
when :hr
|
121
|
+
"----------\n\n"
|
122
|
+
else
|
123
|
+
@errors << "unknown start tag: "+type.name.to_s
|
124
|
+
""
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
# Returns the closing markdown tag, like opening()
|
129
|
+
def ending(type, parent)
|
130
|
+
case type.name.to_sym
|
131
|
+
when :h1
|
132
|
+
" #\n\n"
|
133
|
+
when :h2
|
134
|
+
" ##\n\n"
|
135
|
+
when :p
|
136
|
+
parent.eql?(:root) ? "\n\n" : "\n"
|
137
|
+
when :ol
|
138
|
+
parent.eql?(:li) ? "" : "\n"
|
139
|
+
when :ul
|
140
|
+
parent.eql?(:li) ? "" : "\n"
|
141
|
+
when :em
|
142
|
+
"*"
|
143
|
+
when :strong
|
144
|
+
"**"
|
145
|
+
when :li
|
146
|
+
""
|
147
|
+
when :blockquote
|
148
|
+
""
|
149
|
+
when :code
|
150
|
+
parent.eql?(:pre) ? "" : "`"
|
151
|
+
when :a
|
152
|
+
@links << type.attribute('href').to_s
|
153
|
+
"][" + @links.size.to_s + "] "
|
154
|
+
when :img
|
155
|
+
@links << type.attribute('src').to_s
|
156
|
+
"" + type.attribute('alt').to_s + "][" + @links.size.to_s + "] "
|
157
|
+
"#{type.attribute('alt')}][#{@links.size}] "
|
158
|
+
else
|
159
|
+
@errors << " unknown end tag: "+type.name.to_s
|
160
|
+
""
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
# Perform indent: two space, @indent times - quite simple! :)
|
165
|
+
def indent
|
166
|
+
str = ""
|
167
|
+
@indent.times do
|
168
|
+
str << " "
|
169
|
+
end
|
170
|
+
str
|
171
|
+
end
|
172
|
+
|
173
|
+
# Return the content of element, which should be just text.
|
174
|
+
# If its a code block to indent of 4 spaces.
|
175
|
+
# For block quotation add a leading '>'
|
176
|
+
def text_node(element, parent)
|
177
|
+
if element.name.to_sym.eql?(:code) and parent.eql?(:pre)
|
178
|
+
element.text.gsub("\n","\n ") << "\n"
|
179
|
+
elsif parent.eql?(:blockquote)
|
180
|
+
element.text.gsub!("\n ","\n>")
|
181
|
+
else
|
182
|
+
element.text
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
# Insert the mentioned reference style links.
|
187
|
+
def insert_links
|
188
|
+
@output << "\n"
|
189
|
+
@links.each_index do |index|
|
190
|
+
@output << " [#{index+1}]: #{@links[index]}\n"
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
# Print out all errors, that occured and have been written to @errors.
|
195
|
+
def print_errors
|
196
|
+
@errors.each do |error|
|
197
|
+
puts error
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
# Perform a benchmark on a given string n-times.
|
202
|
+
def speed_benchmark(string, n)
|
203
|
+
initialize()
|
204
|
+
bm(15) do |test|
|
205
|
+
test.report("reverse markdown:") { n.times do; parse_string(string); initialize(); end; }
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end
|
210
|
+
end
|
@@ -0,0 +1,260 @@
|
|
1
|
+
module Granify
|
2
|
+
module Helper
|
3
|
+
class Evernote
|
4
|
+
@@developer_token = ENV["EVERTILS_TOKEN"]
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
authenticate
|
8
|
+
end
|
9
|
+
|
10
|
+
def authenticate
|
11
|
+
if @@developer_token.nil?
|
12
|
+
Notify.error("Evernote developer token is not configured properly!\n$EVERTILS_TOKEN == nil")
|
13
|
+
end
|
14
|
+
|
15
|
+
@evernoteHost = "www.evernote.com"
|
16
|
+
userStoreUrl = "https://#{@evernoteHost}/edam/user"
|
17
|
+
|
18
|
+
userStoreTransport = Thrift::HTTPClientTransport.new(userStoreUrl)
|
19
|
+
userStoreProtocol = Thrift::BinaryProtocol.new(userStoreTransport)
|
20
|
+
@@user = ::Evernote::EDAM::UserStore::UserStore::Client.new(userStoreProtocol)
|
21
|
+
@@shardId = user.shardId
|
22
|
+
|
23
|
+
versionOK = @@user.checkVersion("evernote-data",
|
24
|
+
::Evernote::EDAM::UserStore::EDAM_VERSION_MAJOR,
|
25
|
+
::Evernote::EDAM::UserStore::EDAM_VERSION_MINOR)
|
26
|
+
|
27
|
+
@version = "#{::Evernote::EDAM::UserStore::EDAM_VERSION_MAJOR}.#{::Evernote::EDAM::UserStore::EDAM_VERSION_MINOR}"
|
28
|
+
|
29
|
+
if !versionOK
|
30
|
+
Notify.error("Evernote API requires an update. Latest version is #{@version}")
|
31
|
+
end
|
32
|
+
|
33
|
+
noteStoreUrl = @@user.getNoteStoreUrl(@@developer_token)
|
34
|
+
|
35
|
+
noteStoreTransport = Thrift::HTTPClientTransport.new(noteStoreUrl)
|
36
|
+
noteStoreProtocol = Thrift::BinaryProtocol.new(noteStoreTransport)
|
37
|
+
@@store = ::Evernote::EDAM::NoteStore::NoteStore::Client.new(noteStoreProtocol)
|
38
|
+
end
|
39
|
+
|
40
|
+
def info
|
41
|
+
{
|
42
|
+
:user => "#{user.name} (#{user.username}) - ID##{user.id}",
|
43
|
+
:shard => user.shardId,
|
44
|
+
:api_version => @version,
|
45
|
+
}
|
46
|
+
end
|
47
|
+
|
48
|
+
def notebooks
|
49
|
+
@@store.listNotebooks(@@developer_token)
|
50
|
+
end
|
51
|
+
|
52
|
+
def tags
|
53
|
+
@@store.listTags(@@developer_token)
|
54
|
+
end
|
55
|
+
|
56
|
+
def user
|
57
|
+
@@user.getUser(@@developer_token)
|
58
|
+
end
|
59
|
+
|
60
|
+
def notebook_by_name(name = $request.command)
|
61
|
+
output = {}
|
62
|
+
notebooks.each do |notebook|
|
63
|
+
if notebook.name == name.to_s.capitalize
|
64
|
+
output = notebook
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
output
|
69
|
+
end
|
70
|
+
|
71
|
+
def notes_by_notebook(name)
|
72
|
+
output = {}
|
73
|
+
notebooks.each do |notebook|
|
74
|
+
if notebook.name.to_s == name.capitalize.to_s
|
75
|
+
filter = ::Evernote::EDAM::NoteStore::NoteFilter.new
|
76
|
+
filter.notebookGuid = notebook.guid
|
77
|
+
|
78
|
+
result = ::Evernote::EDAM::NoteStore::NotesMetadataResultSpec.new
|
79
|
+
result.includeTitle = true
|
80
|
+
result.includeUpdated = true
|
81
|
+
result.includeTagGuids = true
|
82
|
+
|
83
|
+
#output = @@store.findNotesMetadata(@@developer_token, filter, 0, 400, result)
|
84
|
+
notes(nil, notebook.guid).notes.each do |note|
|
85
|
+
output[note.guid] = @@store.getNoteContent(@@developer_token, note.guid)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
output
|
91
|
+
end
|
92
|
+
|
93
|
+
def notebooks_by_stack(stack)
|
94
|
+
output = {}
|
95
|
+
notebooks.each do |notebook|
|
96
|
+
if notebook.stack == stack
|
97
|
+
#output[notebook.name] = []
|
98
|
+
|
99
|
+
filter = ::Evernote::EDAM::NoteStore::NoteFilter.new
|
100
|
+
filter.notebookGuid = notebook.guid
|
101
|
+
|
102
|
+
result = ::Evernote::EDAM::NoteStore::NotesMetadataResultSpec.new
|
103
|
+
result.includeTitle = true
|
104
|
+
result.includeUpdated = true
|
105
|
+
result.includeTagGuids = true
|
106
|
+
|
107
|
+
notes = @@store.findNotesMetadata(@@developer_token, filter, 0, 400, result)
|
108
|
+
output[notebook.name] = notes
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
output
|
113
|
+
end
|
114
|
+
|
115
|
+
def note(title_filter = nil, notebook_filter = nil)
|
116
|
+
filter = ::Evernote::EDAM::NoteStore::NoteFilter.new
|
117
|
+
filter.words = "intitle:#{title_filter}" if title_filter
|
118
|
+
filter.notebookGuid = notebook_filter if notebook_filter
|
119
|
+
|
120
|
+
@@store.findNotes(@@developer_token, filter, nil, 1)
|
121
|
+
end
|
122
|
+
|
123
|
+
def notes(title_filter = nil, notebook_filter = nil)
|
124
|
+
filter = ::Evernote::EDAM::NoteStore::NoteFilter.new
|
125
|
+
filter.words = "intitle:#{title_filter}" if title_filter
|
126
|
+
filter.notebookGuid = notebook_filter if notebook_filter
|
127
|
+
|
128
|
+
@@store.findNotes(@@developer_token, filter, nil, 300)
|
129
|
+
end
|
130
|
+
|
131
|
+
def note_exists
|
132
|
+
note = note(date_templates[$request.command])
|
133
|
+
note.totalNotes > 0
|
134
|
+
end
|
135
|
+
|
136
|
+
def create_note(title = date_templates[$request.command], body = template_contents, p_notebook_name = nil, file = nil, share_note = false)
|
137
|
+
if $request.command == :weekly && !Date.today.monday?
|
138
|
+
Notify.error("Sorry, you can only create new weekly logs on Mondays")
|
139
|
+
end
|
140
|
+
|
141
|
+
# Create note object
|
142
|
+
our_note = ::Evernote::EDAM::Type::Note.new
|
143
|
+
our_note.resources = []
|
144
|
+
our_note.tagNames = []
|
145
|
+
|
146
|
+
# only join when required
|
147
|
+
if body.is_a? Array
|
148
|
+
body = body.join
|
149
|
+
end
|
150
|
+
|
151
|
+
# a file was requested, lets prepare it for storage
|
152
|
+
if !file.nil?
|
153
|
+
media_resource = EvernoteENML.new(file)
|
154
|
+
body.concat(media_resource.embeddable_element)
|
155
|
+
our_note.resources << media_resource.element
|
156
|
+
end
|
157
|
+
|
158
|
+
n_body = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
|
159
|
+
n_body += "<!DOCTYPE en-note SYSTEM \"http://xml.evernote.com/pub/enml2.dtd\">"
|
160
|
+
n_body += "<en-note>#{body}</en-note>"
|
161
|
+
|
162
|
+
# setup note properties
|
163
|
+
our_note.title = title
|
164
|
+
our_note.content = n_body
|
165
|
+
|
166
|
+
# properly tag logs
|
167
|
+
case $request.command
|
168
|
+
when :weekly
|
169
|
+
our_note.tagNames << "week-#{Time.now.strftime('%V').to_i}"
|
170
|
+
when :monthly
|
171
|
+
our_note.tagNames << "month-#{Time.now.strftime('%-m').to_i}"
|
172
|
+
end
|
173
|
+
|
174
|
+
if p_notebook_name.nil?
|
175
|
+
parent_notebook = notebook_by_name
|
176
|
+
else
|
177
|
+
parent_notebook = notebook_by_name(p_notebook_name)
|
178
|
+
end
|
179
|
+
|
180
|
+
## parent_notebook is optional; if omitted, default notebook is used
|
181
|
+
if parent_notebook.is_a? ::Evernote::EDAM::Type::Notebook
|
182
|
+
our_note.notebookGuid = parent_notebook.guid
|
183
|
+
end
|
184
|
+
|
185
|
+
## Attempt to create note in Evernote account
|
186
|
+
begin
|
187
|
+
output = {}
|
188
|
+
output[:note] = @@store.createNote(@@developer_token, our_note)
|
189
|
+
|
190
|
+
if share_note
|
191
|
+
shareKey = @@store.shareNote(@@developer_token, output[:note].guid)
|
192
|
+
output[:share_url] = "https://#{@evernoteHost}/shard/#{@@shardId}/sh/#{output[:note].guid}/#{shareKey}"
|
193
|
+
end
|
194
|
+
rescue ::Evernote::EDAM::Error::EDAMUserException => edue
|
195
|
+
## Something was wrong with the note data
|
196
|
+
## See EDAMErrorCode enumeration for error code explanation
|
197
|
+
## http://dev.evernote.com/documentation/reference/Errors.html#Enum_EDAMErrorCode
|
198
|
+
Notify.error "EDAMUserException: #{edue}"
|
199
|
+
rescue ::Evernote::EDAM::Error::EDAMNotFoundException => ednfe
|
200
|
+
## Parent Notebook GUID doesn't correspond to an actual notebook
|
201
|
+
Notify.error "EDAMNotFoundException: Invalid parent notebook GUID"
|
202
|
+
end
|
203
|
+
|
204
|
+
# A parent notebook object exists, otherwise it was saved to the default
|
205
|
+
# notebook
|
206
|
+
if parent_notebook.is_a? ::Evernote::EDAM::Type::Notebook
|
207
|
+
Notify.success("#{parent_notebook.stack}/#{parent_notebook.name}/#{our_note.title} created")
|
208
|
+
else
|
209
|
+
Notify.success("DEFAULT_NOTEBOOK/#{our_note.title} created")
|
210
|
+
end
|
211
|
+
|
212
|
+
output
|
213
|
+
end
|
214
|
+
|
215
|
+
def generate_stats
|
216
|
+
{
|
217
|
+
"Statistic description" => 9845.3894
|
218
|
+
}
|
219
|
+
end
|
220
|
+
|
221
|
+
private
|
222
|
+
# Legacy notes will have single/double character denotations for day of
|
223
|
+
# week, this maps them.
|
224
|
+
def day_of_week
|
225
|
+
case Date.today.strftime('%a')
|
226
|
+
when 'Mon'
|
227
|
+
:M
|
228
|
+
when 'Tue'
|
229
|
+
:Tu
|
230
|
+
when 'Wed'
|
231
|
+
:W
|
232
|
+
when 'Thu'
|
233
|
+
:Th
|
234
|
+
when 'Fri'
|
235
|
+
:F
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
239
|
+
def template_contents
|
240
|
+
if Date.today.friday? && $request.command == :daily
|
241
|
+
# Friday uses a slightly different template
|
242
|
+
IO.readlines("#{Granify::TEMPLATE_DIR}#{$request.command}-friday.enml").join("").gsub!("\n", '')
|
243
|
+
else
|
244
|
+
IO.readlines("#{Granify::TEMPLATE_DIR}#{$request.command}.enml").join("").gsub!("\n", '')
|
245
|
+
end
|
246
|
+
end
|
247
|
+
|
248
|
+
def date_templates
|
249
|
+
now = DateTime.now
|
250
|
+
end_of_week = now + 4 # days
|
251
|
+
|
252
|
+
{
|
253
|
+
:daily => "Daily Log [#{now.strftime('%B %-d')} - #{day_of_week}]",
|
254
|
+
:weekly => "Weekly Log [#{now.strftime('%B %-d')} - #{end_of_week.strftime('%B %-d')}]",
|
255
|
+
:monthly => "Monthly Log [#{now.strftime('%B %Y')}]"
|
256
|
+
}
|
257
|
+
end
|
258
|
+
end
|
259
|
+
end
|
260
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Granify
|
2
|
+
module Helper
|
3
|
+
class Generate
|
4
|
+
def self.format_date(title)
|
5
|
+
if title =~ /Daily/
|
6
|
+
resp = /Daily Log \[([A-Z].*) \- [A-Z]\]/.match(title)
|
7
|
+
|
8
|
+
if resp
|
9
|
+
Time.parse($1)
|
10
|
+
end
|
11
|
+
elsif title =~ /Weekly/
|
12
|
+
resp = /Weekly Log \[([A-Z].*) (\d+) \- (\d+)\]/.match(title)
|
13
|
+
|
14
|
+
if resp
|
15
|
+
first = Time.parse($1 +" "+ $2)
|
16
|
+
second = Time.parse($1 +" "+ $3)
|
17
|
+
|
18
|
+
[first, second]
|
19
|
+
end
|
20
|
+
elsif title =~ /Monthly/
|
21
|
+
resp = /Monthly Log \[([A-Z].*) (\d+)\]/.match(title)
|
22
|
+
|
23
|
+
if resp
|
24
|
+
Time.parse($1 +" "+ $2)
|
25
|
+
end
|
26
|
+
elsif title =~ /Quarterly/
|
27
|
+
resp = /Quarterly Log \[([A-Z].*) \- ([A-Z].*) (\d+)\]/.match(title)
|
28
|
+
|
29
|
+
if resp
|
30
|
+
first = Time.parse($1 +" "+ $3)
|
31
|
+
second = Time.parse($2 +" "+ $3)
|
32
|
+
|
33
|
+
[first, second]
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
data/lib/helpers/time.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
module Granify
|
2
|
+
module Helper
|
3
|
+
class Time
|
4
|
+
def self.human_readable(start, finish)
|
5
|
+
seconds = finish.to_f - start.to_f
|
6
|
+
|
7
|
+
if seconds < 60
|
8
|
+
"No time at all!"
|
9
|
+
else
|
10
|
+
minutes = (seconds / 60).round(1)
|
11
|
+
if minutes < 1
|
12
|
+
"#{minutes} minute"
|
13
|
+
else
|
14
|
+
"#{minutes} minutes"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.formatted(time = nil)
|
20
|
+
if time.nil?
|
21
|
+
time = ::Time.now
|
22
|
+
end
|
23
|
+
|
24
|
+
time.strftime("%e/%-m/%Y @ %I:%M:%S%P")
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
data/lib/log.rb
ADDED
@@ -0,0 +1,111 @@
|
|
1
|
+
module Granify
|
2
|
+
class Log
|
3
|
+
attr_accessor :path, :total_files_processed
|
4
|
+
attr_reader :template
|
5
|
+
|
6
|
+
def initialize(*args)
|
7
|
+
if args.length == 0
|
8
|
+
# default log
|
9
|
+
@template = "#{Granify::LOG_DIR}/%s"
|
10
|
+
@path = sprintf(@template, "default.log")
|
11
|
+
else
|
12
|
+
@template = "#{Granify::LOG_DIR}/%s/%s-%s.log"
|
13
|
+
|
14
|
+
format(args)
|
15
|
+
end
|
16
|
+
|
17
|
+
@path
|
18
|
+
end
|
19
|
+
|
20
|
+
def stale?
|
21
|
+
Time.now - last_write > 60
|
22
|
+
end
|
23
|
+
|
24
|
+
def exists?
|
25
|
+
File.exist? @path
|
26
|
+
end
|
27
|
+
|
28
|
+
def delete
|
29
|
+
if exists?
|
30
|
+
File.delete @path
|
31
|
+
end
|
32
|
+
|
33
|
+
Notify.sinfo("Deleting truncated log file #{@path}")
|
34
|
+
@path = nil
|
35
|
+
end
|
36
|
+
|
37
|
+
def num_lines
|
38
|
+
File.foreach(@path).inject(0) {|c, line| c+1}
|
39
|
+
end
|
40
|
+
|
41
|
+
def faults
|
42
|
+
matchdata = { :errors => 0, :warnings => 0, :total => 0 }
|
43
|
+
|
44
|
+
begin
|
45
|
+
case @log_type
|
46
|
+
when :js
|
47
|
+
last_line = IO.readlines(@path)[-5].chomp
|
48
|
+
matches = last_line.match(/(\d+) example, (\d+) failure/)
|
49
|
+
|
50
|
+
if matches
|
51
|
+
matchdata[:errors] += matches[2].to_i
|
52
|
+
end
|
53
|
+
when :coffeelint
|
54
|
+
total = 0
|
55
|
+
File.foreach(@path) do |line|
|
56
|
+
matches = line.match(/Lint\! » (\d+) errors and (\d+)/)
|
57
|
+
|
58
|
+
if matches
|
59
|
+
matchdata[:errors] += matches[1].to_i
|
60
|
+
matchdata[:warnings] += matches[2].to_i
|
61
|
+
end
|
62
|
+
end
|
63
|
+
when :ruby
|
64
|
+
last_line = IO.readlines(@path)[-1].chomp
|
65
|
+
matches = last_line.match(/(\d+) files inspected\, (\d+)/)
|
66
|
+
|
67
|
+
if matches
|
68
|
+
matchdata[:errors] += matches[2].to_i
|
69
|
+
matchdata[:total] += matches[1].to_i
|
70
|
+
end
|
71
|
+
when :goliath
|
72
|
+
|
73
|
+
else
|
74
|
+
raise ArgumentError, "Unknown log type - #{log_type}"
|
75
|
+
end
|
76
|
+
rescue => e
|
77
|
+
Notify.error(e.message)
|
78
|
+
end
|
79
|
+
|
80
|
+
matchdata
|
81
|
+
end
|
82
|
+
|
83
|
+
def to_s
|
84
|
+
@path
|
85
|
+
end
|
86
|
+
|
87
|
+
private
|
88
|
+
def format(args)
|
89
|
+
@identifier = args[2]
|
90
|
+
|
91
|
+
@path = sprintf(@template,
|
92
|
+
@identifier,
|
93
|
+
args[0],
|
94
|
+
args[1].strftime('%Y-%m-%d-%T')
|
95
|
+
)
|
96
|
+
|
97
|
+
if !File.exists? @path
|
98
|
+
Utils.generate_path(args[0], args[1].strftime('%Y-%m-%d-%T'), @identifier)
|
99
|
+
end
|
100
|
+
|
101
|
+
# create the log file, populate it with temporary data
|
102
|
+
File.open(@path, 'w+') do |f|
|
103
|
+
f.write("Command output will be logged below when it finishes running\n")
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def last_write
|
108
|
+
File.mtime(@path)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|