mail2frontmatter 0.1.0 → 0.1.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/.gitignore +2 -0
- data/.travis.yml +0 -1
- data/README.md +26 -3
- data/Rakefile +3 -7
- data/bin/mail2frontmatter +17 -17
- data/fixtures/mail2frontmatter/broken-processor.rb +2 -2
- data/fixtures/mail2frontmatter/fake-processor-with-options.rb +1 -1
- data/fixtures/mail2frontmatter/fake-processor.rb +1 -1
- data/lib/mail2frontmatter.rb +2 -1
- data/lib/mail2frontmatter/committer.rb +68 -0
- data/lib/mail2frontmatter/configuration.rb +10 -11
- data/lib/mail2frontmatter/parser.rb +7 -8
- data/lib/mail2frontmatter/preprocessor.rb +5 -7
- data/lib/mail2frontmatter/version.rb +1 -1
- data/lib/mail2frontmatter/watcher.rb +13 -7
- data/lib/mail2frontmatter/writer.rb +9 -10
- data/mail2frontmatter.gemspec +16 -15
- data/spec/committer_spec.rb +27 -0
- data/spec/configuration_spec.rb +18 -20
- data/spec/installation/data/.gitkeep +0 -0
- data/spec/installation/media/.gitkeep +0 -0
- data/spec/parser_spec.rb +14 -16
- data/spec/preprocessor_spec.rb +28 -29
- data/spec/remote/.gitkeep +0 -0
- data/spec/spec_helper.rb +62 -1
- data/spec/writer_spec.rb +21 -0
- metadata +32 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0ca545c2952a483060ba2c7b90aa0aeed1c85891
|
4
|
+
data.tar.gz: 96be89bc2de5e5cc89d2daecd2cf0633a8d0fdcd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2af70109d10996401cb9b20bf429af5493ef41da128352350d5e31a793aa7a5cc8cf3dfe1b5ef3d824936f57742325e706163df48bb1fdc81990bfd8f3b18e39
|
7
|
+
data.tar.gz: 124aa40da8be4e7bb23199384b0b375046c4f057ca0355999ac1f7a7d4f2f863307946db6b9c76ea25d150d2e59ad740142367ed9b97815d6830c1b98245f366
|
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -4,7 +4,9 @@
|
|
4
4
|
|
5
5
|
Email-to-blog parser which creates YAML FrontMatter and saves your attachments.
|
6
6
|
|
7
|
-
Designed to be used with either Middleman or Jekyll
|
7
|
+
Designed to be used with either Middleman or Jekyll.
|
8
|
+
|
9
|
+
This project is actively being developed. I wrap the executable with the [eye](https://github.com/kostya/eye) gem at the moment.
|
8
10
|
|
9
11
|
## Installation
|
10
12
|
|
@@ -147,6 +149,27 @@ You should always always return metadata and body as shown since this will be pa
|
|
147
149
|
|
148
150
|
### TODO
|
149
151
|
|
150
|
-
*
|
151
|
-
|
152
|
+
* core plugins
|
153
|
+
|
154
|
+
Core plugins should be included out of the box and disabled upon request. It's just simpler to use
|
155
|
+
|
156
|
+
* zero config for Jekyll
|
157
|
+
|
158
|
+
current we 'detect' the directory structure to see if the executable is run from Middleman,
|
159
|
+
do the same for Jekyll in order to support it out of the box with zero configuration
|
160
|
+
|
161
|
+
* remove dependency on Mailman, use Mail directly
|
162
|
+
|
163
|
+
no need to use Mailman if I intend to manage the process myself. Use Mail directly
|
164
|
+
|
165
|
+
* detach runner
|
166
|
+
|
167
|
+
incoming mail checks in the main thread, processing, writing, commiting should be handled in a separate process to discard leaks
|
168
|
+
|
169
|
+
|
170
|
+
|
171
|
+
|
172
|
+
|
173
|
+
|
174
|
+
|
152
175
|
|
data/Rakefile
CHANGED
data/bin/mail2frontmatter
CHANGED
@@ -13,34 +13,34 @@ options = {
|
|
13
13
|
}
|
14
14
|
|
15
15
|
OptionParser.new do |opts|
|
16
|
-
opts.banner =
|
16
|
+
opts.banner = 'Usage: mail2frontmatter [options]'
|
17
17
|
|
18
|
-
opts.on(
|
18
|
+
opts.on('-k', '--stop', 'stop the running process if any') do
|
19
19
|
stop = true
|
20
20
|
end
|
21
21
|
|
22
|
-
opts.on(
|
22
|
+
opts.on('-cCONFIG', '--config=CONFIG', 'path to configuration file, defaults to ./data/mail2frontmatter.yml') do |config_file|
|
23
23
|
config = config_file
|
24
24
|
end
|
25
25
|
|
26
|
-
opts.on(
|
26
|
+
opts.on('-d', '--detach', 'detach process and run in the background') do
|
27
27
|
options[:background] = true
|
28
28
|
end
|
29
29
|
|
30
|
-
opts.on(
|
30
|
+
opts.on('-lLOGFILE', '--log=LOGFILE', 'path to log file, defaults to STDOUT in the foreground or ./log/mail2frontmatter.log when daemonized') do |log_file|
|
31
31
|
config[:log_file] = log_file
|
32
32
|
end
|
33
33
|
|
34
|
-
opts.on(
|
34
|
+
opts.on('-pPIDFILE', '--pid=PIDFILE', 'path to pid file, defaults to ./tmp/pids/mail2frontmatter.pid') do |pid_file|
|
35
35
|
options[:pid_file] = pid_file
|
36
36
|
end
|
37
37
|
|
38
|
-
opts.on(
|
38
|
+
opts.on('-h', '--help', 'Prints this help') do
|
39
39
|
puts opts
|
40
40
|
exit
|
41
41
|
end
|
42
42
|
|
43
|
-
opts.on_tail(
|
43
|
+
opts.on_tail('-v', '--version', 'Prints version') do
|
44
44
|
require File.join(File.dirname(__FILE__), '..', 'lib', 'mail2frontmatter', 'version')
|
45
45
|
puts Mail2FrontMatter::VERSION
|
46
46
|
exit
|
@@ -50,8 +50,8 @@ end.parse!
|
|
50
50
|
# TRY TO KILL
|
51
51
|
if stop
|
52
52
|
|
53
|
-
|
54
|
-
puts
|
53
|
+
unless File.exist?(options[:pid_file])
|
54
|
+
puts 'no pidfile! are you sure mail2frontmatter is running?'
|
55
55
|
exit 1
|
56
56
|
end
|
57
57
|
|
@@ -63,13 +63,13 @@ if stop
|
|
63
63
|
Process.kill('TERM', pid)
|
64
64
|
exit 0
|
65
65
|
|
66
|
-
|
67
|
-
|
68
|
-
|
66
|
+
# FUTURE: library intercepts TERM,
|
67
|
+
# waits to finish processing if it is
|
68
|
+
# or if kill exits dirty.
|
69
69
|
|
70
70
|
# CATCH STALE PID
|
71
71
|
rescue Errno::ESRCH
|
72
|
-
puts
|
72
|
+
puts 'stale pidfile... cleaning'
|
73
73
|
|
74
74
|
# also exit here! but don't move exit 0 to ensure block
|
75
75
|
# because "in the future" we may intelligently intercept pkill above
|
@@ -90,7 +90,7 @@ require File.join(File.dirname(__FILE__), '..', 'lib', 'mail2frontmatter')
|
|
90
90
|
if options[:background]
|
91
91
|
|
92
92
|
# CHECKING ALREADY RUNNING / CHECK STALE
|
93
|
-
if File.
|
93
|
+
if File.exist?(options[:pid_file])
|
94
94
|
pid = File.read(options[:pid_file]).to_i
|
95
95
|
|
96
96
|
begin
|
@@ -99,12 +99,12 @@ if options[:background]
|
|
99
99
|
exit 1
|
100
100
|
|
101
101
|
rescue Errno::ESRCH
|
102
|
-
puts
|
102
|
+
puts 'stale pidfile... cleaning'
|
103
103
|
File.delete(options[:pid_file])
|
104
104
|
end
|
105
105
|
end
|
106
106
|
|
107
|
-
puts
|
107
|
+
puts 'daemonizing...'
|
108
108
|
|
109
109
|
# SET CONFIG...
|
110
110
|
Mail2FrontMatter.set_config(config)
|
data/lib/mail2frontmatter.rb
CHANGED
@@ -2,5 +2,6 @@ require 'mail2frontmatter/version'
|
|
2
2
|
require 'mail2frontmatter/configuration'
|
3
3
|
require 'mail2frontmatter/watcher'
|
4
4
|
require 'mail2frontmatter/parser'
|
5
|
-
require 'mail2frontmatter/writer'
|
6
5
|
require 'mail2frontmatter/preprocessor'
|
6
|
+
require 'mail2frontmatter/writer'
|
7
|
+
require 'mail2frontmatter/committer'
|
@@ -0,0 +1,68 @@
|
|
1
|
+
|
2
|
+
# Commits Changes to git
|
3
|
+
#
|
4
|
+
module Mail2FrontMatter
|
5
|
+
class Committer
|
6
|
+
begin
|
7
|
+
require 'rugged'
|
8
|
+
@@available = true
|
9
|
+
|
10
|
+
rescue LoadError
|
11
|
+
@@available = false
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.available?
|
15
|
+
@@available
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.commit(metadata, _body)
|
19
|
+
repo = Rugged::Repository.new(Mail2FrontMatter.config[:git][:path])
|
20
|
+
index = repo.index
|
21
|
+
|
22
|
+
# stage frontmatter/erb
|
23
|
+
relative_path = metadata[:filepath].gsub(Mail2FrontMatter.config[:git][:path] + '/', '')
|
24
|
+
|
25
|
+
index.add(path: relative_path,
|
26
|
+
oid: (Rugged::Blob.from_workdir repo, relative_path),
|
27
|
+
mode: 0100644)
|
28
|
+
|
29
|
+
# stage attachments
|
30
|
+
metadata[:attachments].each_pair do |_k, filemeta|
|
31
|
+
relative_path = filemeta[:filepath].gsub(Mail2FrontMatter.config[:git][:path] + '/', '')
|
32
|
+
|
33
|
+
index.add(path: relative_path,
|
34
|
+
oid: (Rugged::Blob.from_workdir repo, relative_path),
|
35
|
+
mode: 0100644)
|
36
|
+
end
|
37
|
+
|
38
|
+
# commit
|
39
|
+
tree = index.write_tree(repo)
|
40
|
+
index.write
|
41
|
+
|
42
|
+
author = {
|
43
|
+
email: Mail2FrontMatter.config[:git][:email] || metadata[:from].match(/\<(.*)\>/)[1],
|
44
|
+
name: Mail2FrontMatter.config[:git][:name] || metadata[:from].match(/(.*) \<.*\>/)[1],
|
45
|
+
time: Time.now
|
46
|
+
}
|
47
|
+
|
48
|
+
Rugged::Commit.create(repo, author: author,
|
49
|
+
committer: author,
|
50
|
+
message: "post via email, #{metadata[:subject]}",
|
51
|
+
parents: [repo.head.target],
|
52
|
+
tree: tree,
|
53
|
+
update_ref: 'HEAD')
|
54
|
+
|
55
|
+
# push
|
56
|
+
begin
|
57
|
+
credentials = Rugged::Credentials::SshKeyFromAgent.new(username: 'git')
|
58
|
+
repo.push 'origin', ['refs/heads/master'], { credentials: credentials }
|
59
|
+
rescue StandardError => e
|
60
|
+
Mail2FrontMatter.logger.info("Could not push!")
|
61
|
+
Mail2FrontMatter.logger.error(e)
|
62
|
+
end
|
63
|
+
|
64
|
+
# return sha
|
65
|
+
repo.references['refs/heads/master'].target_id
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -3,15 +3,11 @@ module Mail2FrontMatter
|
|
3
3
|
require 'active_support/inflector'
|
4
4
|
|
5
5
|
class << self
|
6
|
-
|
7
|
-
@logger
|
8
|
-
end
|
6
|
+
attr_reader :logger
|
9
7
|
|
10
|
-
|
11
|
-
@config
|
12
|
-
end
|
8
|
+
attr_reader :config
|
13
9
|
|
14
|
-
def set_config(passed_config = nil, &
|
10
|
+
def set_config(passed_config = nil, &_block)
|
15
11
|
# load config from file
|
16
12
|
if passed_config.is_a?(String)
|
17
13
|
@config = YAML.load_file(passed_config).deep_symbolize_keys!
|
@@ -24,14 +20,14 @@ module Mail2FrontMatter
|
|
24
20
|
if File.exist?(default_config)
|
25
21
|
@config = YAML.load_file(default_config).deep_symbolize_keys!
|
26
22
|
else
|
27
|
-
|
23
|
+
fail LoadError, 'no configuration given or found at ./data/mail2frontmatter.yml'
|
28
24
|
end
|
29
25
|
|
30
26
|
elsif passed_config.is_a?(Hash)
|
31
27
|
@config = passed_config
|
32
28
|
|
33
29
|
else
|
34
|
-
|
30
|
+
fail ArgumentError, 'not a valid configuration type'
|
35
31
|
end
|
36
32
|
|
37
33
|
# setup logger, use provided location
|
@@ -47,6 +43,10 @@ module Mail2FrontMatter
|
|
47
43
|
@logger = Logger.new(STDOUT)
|
48
44
|
end
|
49
45
|
|
46
|
+
@config[:git] ||= {
|
47
|
+
path: Dir.pwd
|
48
|
+
}
|
49
|
+
|
50
50
|
# set default for data directory unless already specified
|
51
51
|
# the data directory is where the posts will be written to
|
52
52
|
unless @config[:data_directory]
|
@@ -83,9 +83,8 @@ module Mail2FrontMatter
|
|
83
83
|
raise e
|
84
84
|
end
|
85
85
|
|
86
|
-
|
86
|
+
"Mail2FrontMatter::#{processor[:key].underscore.camelize}".constantize.register(processor[:options] || {})
|
87
87
|
end
|
88
|
-
|
89
88
|
end
|
90
89
|
end
|
91
90
|
end
|
@@ -8,19 +8,19 @@ module Mail2FrontMatter
|
|
8
8
|
attr_accessor :message, :metadata, :body
|
9
9
|
|
10
10
|
ALLOWED_TYPES = {
|
11
|
-
|
12
|
-
|
13
|
-
|
11
|
+
'audio' => 'audio',
|
12
|
+
'video' => 'videos',
|
13
|
+
'image' => 'images'
|
14
14
|
}
|
15
15
|
|
16
16
|
def initialize(message)
|
17
17
|
@message = message
|
18
18
|
raw_parsed_html = Nokogiri::HTML.parse(@message.html_part.decoded.strip)
|
19
19
|
|
20
|
-
@body = raw_parsed_html.at(
|
20
|
+
@body = raw_parsed_html.at('body')
|
21
21
|
|
22
22
|
# remove extraneous nesting
|
23
|
-
while
|
23
|
+
while @body.children.count == 1 && @body.children.first.name == 'div'
|
24
24
|
@body = @body.children.first
|
25
25
|
end
|
26
26
|
|
@@ -33,10 +33,10 @@ module Mail2FrontMatter
|
|
33
33
|
media_type_directory = File.join(Mail2FrontMatter.config[:media_directory], Parser::ALLOWED_TYPES[attachment.main_type])
|
34
34
|
FileUtils.mkdir_p(media_type_directory)
|
35
35
|
|
36
|
-
filepath = File.join(media_type_directory, attachment.filename)
|
36
|
+
filepath = File.join(media_type_directory, attachment.filename)
|
37
37
|
|
38
38
|
# save attachment
|
39
|
-
File.open(filepath,
|
39
|
+
File.open(filepath, 'w+b', 0644) { |f| f.write attachment.body.decoded }
|
40
40
|
|
41
41
|
# retain metadata
|
42
42
|
attachments[attachment.cid] = {
|
@@ -67,7 +67,6 @@ module Mail2FrontMatter
|
|
67
67
|
subject: message.subject,
|
68
68
|
attachments: attachments
|
69
69
|
}
|
70
|
-
|
71
70
|
end
|
72
71
|
end
|
73
72
|
end
|
@@ -1,11 +1,10 @@
|
|
1
|
-
|
2
1
|
# Pre-processes blog data, allows hooks
|
3
2
|
|
4
3
|
module Mail2FrontMatter
|
5
4
|
class PreProcessor
|
6
5
|
require 'set'
|
7
6
|
|
8
|
-
class InvalidProcessor < StandardError
|
7
|
+
class InvalidProcessor < StandardError; end
|
9
8
|
|
10
9
|
@@processors = Set.new
|
11
10
|
|
@@ -14,8 +13,8 @@ module Mail2FrontMatter
|
|
14
13
|
end
|
15
14
|
|
16
15
|
def self.register(options = {})
|
17
|
-
|
18
|
-
|
16
|
+
fail InvalidProcessor, "run method not defined on #{self}" unless self.respond_to?(:run)
|
17
|
+
fail ArgumentError, 'options must be a hash' unless options.is_a? Hash
|
19
18
|
@options = options
|
20
19
|
|
21
20
|
@@processors << self
|
@@ -26,13 +25,12 @@ module Mail2FrontMatter
|
|
26
25
|
begin
|
27
26
|
metadata, body = processor.run(metadata, body)
|
28
27
|
rescue StandardError => e
|
29
|
-
Mail2FrontMatter.logger.error(
|
28
|
+
Mail2FrontMatter.logger.error('processor failed!')
|
30
29
|
Mail2FrontMatter.logger.error(e)
|
31
30
|
end
|
32
31
|
end
|
33
32
|
|
34
|
-
|
33
|
+
[metadata, body]
|
35
34
|
end
|
36
|
-
|
37
35
|
end
|
38
36
|
end
|
@@ -4,24 +4,22 @@ module Mail2FrontMatter
|
|
4
4
|
require 'mailman'
|
5
5
|
|
6
6
|
class Watcher
|
7
|
-
|
8
7
|
def self.run
|
9
8
|
mail_protocol = Mail2FrontMatter.config[:protocol] || :imap
|
10
9
|
poll_interval = Mail2FrontMatter.config[:interval] || 60
|
11
10
|
|
12
|
-
@receiver = Mail2FrontMatter.config[:receiver]
|
13
|
-
@senders = Mail2FrontMatter.config[:senders]
|
14
|
-
|
15
11
|
Mailman.config.poll_interval = poll_interval
|
16
12
|
Mailman.config.ignore_stdin = true
|
17
13
|
|
18
14
|
Mailman.config.send("#{mail_protocol}=", Mail2FrontMatter.config[:mailman])
|
19
15
|
Mailman.config.logger = Mail2FrontMatter.logger
|
20
16
|
|
17
|
+
Mail2FrontMatter.logger.info("Mail2FrontMatter v#{Mail2FrontMatter::VERSION} is starting...")
|
18
|
+
|
21
19
|
Mailman::Application.run do
|
22
|
-
|
23
|
-
logger = Mailman.config.logger
|
20
|
+
logger = Mail2FrontMatter.logger
|
24
21
|
|
22
|
+
from(Mail2FrontMatter.config[:senders]).to(Mail2FrontMatter.config[:receiver]) do
|
25
23
|
logger.info('parsing message...')
|
26
24
|
parser = Mail2FrontMatter::Parser.new(message)
|
27
25
|
|
@@ -30,9 +28,17 @@ module Mail2FrontMatter
|
|
30
28
|
|
31
29
|
logger.info('saving processed post...')
|
32
30
|
Mail2FrontMatter::Writer.write(metadata, body)
|
31
|
+
|
32
|
+
logger.info('commiting written post and attachments...')
|
33
|
+
Mail2FrontMatter::Committer.commit(metadata, body)
|
34
|
+
|
35
|
+
logger.info('done...')
|
36
|
+
end
|
37
|
+
|
38
|
+
default do
|
39
|
+
logger.error("received and discarded email from unknown address!")
|
33
40
|
end
|
34
41
|
end
|
35
42
|
end
|
36
|
-
|
37
43
|
end
|
38
44
|
end
|
@@ -1,20 +1,19 @@
|
|
1
1
|
|
2
2
|
# Writes YAML FrontMatter & Article Content in ERB
|
3
|
-
#
|
4
|
-
# TODO How do I support other templating solutions here?
|
5
|
-
#
|
6
|
-
#
|
3
|
+
#
|
4
|
+
# TODO: How do I support other templating solutions here?
|
5
|
+
# Same plugin style as processors?
|
6
|
+
# Is processor and writer doing the same thing?
|
7
7
|
# --- probably just let anyone specify the extension.. keep it simple
|
8
|
-
#
|
8
|
+
#
|
9
9
|
module Mail2FrontMatter
|
10
10
|
class Writer
|
11
|
-
|
12
11
|
require 'yaml'
|
13
12
|
require 'active_support/inflector'
|
14
13
|
|
15
14
|
def self.write(metadata, body)
|
16
15
|
# MAPPINGS!
|
17
|
-
#
|
16
|
+
#
|
18
17
|
# Play nice with programs which will read this data
|
19
18
|
# And set sensible defaults as fall throughs
|
20
19
|
|
@@ -22,12 +21,12 @@ module Mail2FrontMatter
|
|
22
21
|
metadata[:title] ||= metadata[:subject]
|
23
22
|
|
24
23
|
# make a sensible standard blog filename unless one is given
|
25
|
-
metadata[:filename] ||= [metadata[:received].strftime(
|
24
|
+
metadata[:filename] ||= [metadata[:received].strftime('%Y-%m-%d'), '-', metadata[:subject].parameterize, '.html.erb'].join
|
25
|
+
metadata[:filepath] ||= File.join(Mail2FrontMatter.config[:data_directory], metadata[:filename])
|
26
26
|
|
27
27
|
data = metadata.to_yaml + "---\n" + body
|
28
28
|
|
29
|
-
File.write(
|
29
|
+
File.write(metadata[:filepath], data)
|
30
30
|
end
|
31
|
-
|
32
31
|
end
|
33
32
|
end
|
data/mail2frontmatter.gemspec
CHANGED
@@ -4,26 +4,27 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
4
|
require 'mail2frontmatter/version'
|
5
5
|
|
6
6
|
Gem::Specification.new do |spec|
|
7
|
-
spec.name =
|
7
|
+
spec.name = 'mail2frontmatter'
|
8
8
|
spec.version = Mail2FrontMatter::VERSION
|
9
|
-
spec.authors = [
|
10
|
-
spec.email = [
|
11
|
-
spec.summary =
|
12
|
-
spec.description = spec.summary +
|
13
|
-
spec.homepage =
|
14
|
-
spec.license =
|
9
|
+
spec.authors = ['Kunal Shah']
|
10
|
+
spec.email = ['me@kunalashah.com']
|
11
|
+
spec.summary = 'email-in for static blogs like Middleman'
|
12
|
+
spec.description = spec.summary + '. Uses Mailman to poll an account. '
|
13
|
+
spec.homepage = 'https://github.com/whistlerbrk/Mail2FrontMatter'
|
14
|
+
spec.license = 'MIT'
|
15
15
|
|
16
16
|
spec.files = `git ls-files -z`.split("\x0")
|
17
17
|
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
18
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
-
spec.require_paths = [
|
19
|
+
spec.require_paths = ['lib']
|
20
20
|
|
21
|
-
spec.add_dependency
|
22
|
-
spec.add_dependency
|
23
|
-
spec.add_dependency
|
21
|
+
spec.add_dependency 'mailman', '~> 0.7.3'
|
22
|
+
spec.add_dependency 'nokogiri', '~> 1.6'
|
23
|
+
spec.add_dependency 'activesupport', '~> 4'
|
24
|
+
spec.add_dependency 'rugged', '~> 0.21'
|
24
25
|
|
25
|
-
spec.add_development_dependency
|
26
|
-
spec.add_development_dependency
|
27
|
-
spec.add_development_dependency
|
28
|
-
spec.add_development_dependency
|
26
|
+
spec.add_development_dependency 'rspec', '~> 3.1'
|
27
|
+
spec.add_development_dependency 'byebug', '~> 3.5'
|
28
|
+
spec.add_development_dependency 'bundler', '~> 1.7'
|
29
|
+
spec.add_development_dependency 'rake', '~> 10.0'
|
29
30
|
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Mail2FrontMatter::Committer, 'committing' do
|
4
|
+
require 'rugged'
|
5
|
+
|
6
|
+
let(:config) { File.join(M2FM_GEM_PATH, 'fixtures', 'mail2frontmatter.simple.yml') }
|
7
|
+
let(:message_one) { Mail::Message.new(File.read(File.join(M2FM_GEM_PATH, 'fixtures', 'attachments.eml'))) }
|
8
|
+
|
9
|
+
it 'should commit new posts' do
|
10
|
+
Mail2FrontMatter.set_config(config) do |config|
|
11
|
+
config[:data_directory] = File.join(M2FM_GEM_PATH, 'spec', 'installation', 'data')
|
12
|
+
config[:media_directory] = File.join(M2FM_GEM_PATH, 'spec', 'installation', 'media')
|
13
|
+
config[:git] = { path: File.join(M2FM_GEM_PATH, 'spec', 'installation') }
|
14
|
+
end
|
15
|
+
|
16
|
+
repo = Rugged::Repository.new(Mail2FrontMatter.config[:git][:path])
|
17
|
+
opening_sha = repo.references['refs/heads/master'].target_id
|
18
|
+
|
19
|
+
parser = Mail2FrontMatter::Parser.new(message_one)
|
20
|
+
Mail2FrontMatter::Writer.write(parser.metadata, parser.body)
|
21
|
+
Mail2FrontMatter::Committer.commit(parser.metadata, parser.body)
|
22
|
+
|
23
|
+
closing_sha = repo.references['refs/heads/master'].target_id
|
24
|
+
|
25
|
+
expect(opening_sha == closing_sha).to be(false)
|
26
|
+
end
|
27
|
+
end
|
data/spec/configuration_spec.rb
CHANGED
@@ -1,42 +1,40 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
describe Mail2FrontMatter,
|
4
|
-
|
3
|
+
describe Mail2FrontMatter, 'configuration' do
|
5
4
|
let(:simple_config) { File.join(M2FM_GEM_PATH, 'fixtures', 'mail2frontmatter.simple.yml') }
|
6
5
|
let(:complex_config) { File.join(M2FM_GEM_PATH, 'fixtures', 'mail2frontmatter.complex.yml') }
|
7
6
|
let(:malformed_config) { File.join(M2FM_GEM_PATH, 'fixtures', 'mail2frontmatter.malformed.yml') }
|
8
7
|
|
9
|
-
it
|
10
|
-
expect
|
8
|
+
it 'should load a configuration by passing a YAML file location' do
|
9
|
+
expect do
|
11
10
|
Mail2FrontMatter.set_config(simple_config)
|
12
|
-
|
11
|
+
end.to_not raise_error
|
13
12
|
end
|
14
13
|
|
15
|
-
it
|
16
|
-
expect
|
17
|
-
Mail2FrontMatter.set_config(
|
18
|
-
|
14
|
+
it 'should load a configuration by passing a hash' do
|
15
|
+
expect do
|
16
|
+
Mail2FrontMatter.set_config(foo: 'bar')
|
17
|
+
end.to_not raise_error
|
19
18
|
end
|
20
19
|
|
21
|
-
it
|
22
|
-
expect
|
20
|
+
it 'should raise an error for other types' do
|
21
|
+
expect do
|
23
22
|
Mail2FrontMatter.set_config([])
|
24
|
-
|
23
|
+
end.to raise_error
|
25
24
|
end
|
26
25
|
|
27
|
-
it
|
28
|
-
expect
|
26
|
+
it 'should fail loading malformed configs' do
|
27
|
+
expect do
|
29
28
|
Mail2FrontMatter.set_config(malformed_config)
|
30
|
-
|
29
|
+
end.to raise_error
|
31
30
|
end
|
32
31
|
|
33
|
-
it
|
32
|
+
it 'should attempt to load the default configuration if nothing is passed' do
|
34
33
|
# this should attempt and fail because there is no ./data/mail2frontmatter.yml
|
35
|
-
expect
|
34
|
+
expect do
|
36
35
|
Mail2FrontMatter.set_config do |config|
|
37
36
|
config[:foo] = 'bar'
|
38
37
|
end
|
39
|
-
|
38
|
+
end.to raise_error(LoadError)
|
40
39
|
end
|
41
|
-
|
42
|
-
end
|
40
|
+
end
|
File without changes
|
File without changes
|
data/spec/parser_spec.rb
CHANGED
@@ -1,43 +1,41 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
describe Mail2FrontMatter::Parser,
|
4
|
-
|
3
|
+
describe Mail2FrontMatter::Parser, 'parsing' do
|
5
4
|
let(:message_one) { Mail::Message.new(File.read(File.join(M2FM_GEM_PATH, 'fixtures', 'attachments.eml'))) }
|
6
5
|
|
7
|
-
it
|
8
|
-
expect
|
6
|
+
it 'should parse HTML email' do
|
7
|
+
expect do
|
9
8
|
Mail2FrontMatter::Parser.new(message_one)
|
10
|
-
|
9
|
+
end.to_not raise_error
|
11
10
|
end
|
12
11
|
|
13
|
-
it
|
12
|
+
it 'should return an html body as a string' do
|
14
13
|
body = Mail2FrontMatter::Parser.new(message_one).body
|
15
14
|
expect(body).to match(/Charlie<br>/)
|
16
15
|
end
|
17
16
|
|
18
|
-
it
|
17
|
+
it 'should return have an email metadata hash with a from key' do
|
19
18
|
from = Mail2FrontMatter::Parser.new(message_one).metadata[:from]
|
20
|
-
expect(from).to eq(
|
19
|
+
expect(from).to eq('Kunal Shah <kunalashokshah@gmail.com>')
|
21
20
|
end
|
22
21
|
|
23
|
-
it
|
22
|
+
it 'should return have an email metadata hash with a to key' do
|
24
23
|
to = Mail2FrontMatter::Parser.new(message_one).metadata[:to]
|
25
|
-
expect(to).to eq(
|
24
|
+
expect(to).to eq('stream@kunalashah.com')
|
26
25
|
end
|
27
26
|
|
28
|
-
it
|
27
|
+
it 'should return have an email metadata hash with a received key' do
|
29
28
|
received = Mail2FrontMatter::Parser.new(message_one).metadata[:received]
|
30
29
|
expect(received.class).to eq(DateTime)
|
31
30
|
end
|
32
31
|
|
33
|
-
it
|
32
|
+
it 'should return have an email metadata hash with a subject key' do
|
34
33
|
subject = Mail2FrontMatter::Parser.new(message_one).metadata[:subject]
|
35
|
-
expect(subject).to eq(
|
34
|
+
expect(subject).to eq('295 Abandoned Elevator Shaft')
|
36
35
|
end
|
37
36
|
|
38
|
-
it
|
37
|
+
it 'should save attachments to disk' do
|
39
38
|
attachment_path = Mail2FrontMatter::Parser.new(message_one).metadata[:attachments].first[1][:filepath]
|
40
39
|
expect(File.exist?(attachment_path)).to eq(true)
|
41
40
|
end
|
42
|
-
|
43
|
-
end
|
41
|
+
end
|
data/spec/preprocessor_spec.rb
CHANGED
@@ -7,56 +7,55 @@ describe Mail2FrontMatter::PreProcessor do
|
|
7
7
|
|
8
8
|
let(:message_one) { Mail::Message.new(File.read(File.join(M2FM_GEM_PATH, 'fixtures', 'attachments.eml'))) }
|
9
9
|
|
10
|
-
let(:invalidly_defined_preprocessor)
|
10
|
+
let(:invalidly_defined_preprocessor) do
|
11
11
|
class MyInvalidProcessor < Mail2FrontMatter::PreProcessor
|
12
12
|
# note, instanced not class
|
13
13
|
def run(metadata, body)
|
14
14
|
# some modification
|
15
|
-
|
15
|
+
[metadata, body]
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
19
19
|
return MyInvalidProcessor
|
20
|
-
|
20
|
+
end
|
21
21
|
|
22
|
-
let(:validly_defined_preprocessor)
|
22
|
+
let(:validly_defined_preprocessor) do
|
23
23
|
class MyValidProcessor < Mail2FrontMatter::PreProcessor
|
24
24
|
def self.run(metadata, body)
|
25
25
|
# some modification
|
26
|
-
|
26
|
+
[metadata, body]
|
27
27
|
end
|
28
28
|
end
|
29
29
|
|
30
30
|
return MyValidProcessor
|
31
|
-
|
32
|
-
|
33
|
-
context "registration" do
|
31
|
+
end
|
34
32
|
|
35
|
-
|
36
|
-
|
33
|
+
context 'registration' do
|
34
|
+
it 'should raise errors for invalid processors' do
|
35
|
+
expect do
|
37
36
|
invalidly_defined_preprocessor.register({})
|
38
|
-
|
37
|
+
end.to raise_error
|
39
38
|
end
|
40
39
|
|
41
|
-
it
|
42
|
-
expect
|
40
|
+
it 'should not raise errors for valid processors' do
|
41
|
+
expect do
|
43
42
|
validly_defined_preprocessor.register({})
|
44
|
-
|
43
|
+
end.to_not raise_error
|
45
44
|
end
|
46
45
|
|
47
|
-
it
|
48
|
-
expect
|
46
|
+
it 'should raise an error when registered without a hash' do
|
47
|
+
expect do
|
49
48
|
validly_defined_preprocessor.register(nil)
|
50
|
-
|
49
|
+
end.to raise_error(ArgumentError)
|
51
50
|
end
|
52
51
|
|
53
|
-
it
|
54
|
-
expect
|
55
|
-
validly_defined_preprocessor.register(
|
56
|
-
|
52
|
+
it 'should not raise an error when registered with a hash' do
|
53
|
+
expect do
|
54
|
+
validly_defined_preprocessor.register(foo: 'bar')
|
55
|
+
end.to_not raise_error
|
57
56
|
end
|
58
57
|
|
59
|
-
it
|
58
|
+
it 'should load preprocessors' do
|
60
59
|
Mail2FrontMatter.set_config(complex_config)
|
61
60
|
processors = Mail2FrontMatter::PreProcessor.processors
|
62
61
|
|
@@ -64,23 +63,23 @@ describe Mail2FrontMatter::PreProcessor do
|
|
64
63
|
expect(processors).to include(Mail2FrontMatter::FakeProcessorWithOptions)
|
65
64
|
end
|
66
65
|
|
67
|
-
it
|
66
|
+
it 'should provide preprocessors with passed options' do
|
68
67
|
Mail2FrontMatter.set_config(complex_config)
|
69
68
|
options = Mail2FrontMatter::FakeProcessorWithOptions.instance_variable_get(:@options)
|
70
69
|
|
71
70
|
expect(options.class).to eq(Hash)
|
72
|
-
expect(options[:foo]).to eq(
|
71
|
+
expect(options[:foo]).to eq('bar')
|
73
72
|
end
|
74
73
|
end
|
75
74
|
|
76
|
-
context
|
77
|
-
it
|
75
|
+
context 'operation' do
|
76
|
+
it 'should continue processing if an individual processor fails' do
|
78
77
|
Mail2FrontMatter.set_config(broken_config)
|
79
78
|
parser = Mail2FrontMatter::Parser.new(message_one)
|
80
79
|
|
81
|
-
expect
|
82
|
-
|
83
|
-
|
80
|
+
expect do
|
81
|
+
Mail2FrontMatter::PreProcessor.process(parser.metadata, parser.body)
|
82
|
+
end.to_not raise_error
|
84
83
|
end
|
85
84
|
end
|
86
85
|
end
|
File without changes
|
data/spec/spec_helper.rb
CHANGED
@@ -1,6 +1,67 @@
|
|
1
1
|
|
2
2
|
M2FM_GEM_PATH = File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
3
|
-
|
3
|
+
$LOAD_PATH << File.join(M2FM_GEM_PATH, 'fixtures')
|
4
4
|
|
5
5
|
require 'yaml'
|
6
|
+
require 'fileutils'
|
6
7
|
require File.join(M2FM_GEM_PATH, 'lib', 'mail2frontmatter')
|
8
|
+
|
9
|
+
module RSpec
|
10
|
+
# remove any data hanging around from spec runs...
|
11
|
+
def self.clean_testbed
|
12
|
+
FileUtils.rm_rf(Dir[File.join(M2FM_GEM_PATH, 'spec', 'remote', '*')])
|
13
|
+
FileUtils.rm_rf(Dir[File.join(M2FM_GEM_PATH, 'spec', 'installation', 'data', '*')])
|
14
|
+
FileUtils.rm_rf(Dir[File.join(M2FM_GEM_PATH, 'spec', 'installation', 'media', '*')])
|
15
|
+
FileUtils.rm_rf(Dir[File.join(M2FM_GEM_PATH, 'spec', 'installation', '.git')])
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
RSpec.configure do |config|
|
20
|
+
config.before(:suite) do
|
21
|
+
RSpec.clean_testbed
|
22
|
+
|
23
|
+
# setup a repo in spec/installation
|
24
|
+
repo = Rugged::Repository.init_at(File.join(M2FM_GEM_PATH, 'spec', 'installation', '.git'))
|
25
|
+
|
26
|
+
# setup another repo in spec/remote
|
27
|
+
Rugged::Repository.init_at(File.join(M2FM_GEM_PATH, 'spec', 'remote'), :bare)
|
28
|
+
|
29
|
+
# add the second repo as the origin of the first
|
30
|
+
repo.remotes.create('origin', File.join(M2FM_GEM_PATH, 'spec', 'remote'))
|
31
|
+
|
32
|
+
index = repo.index
|
33
|
+
|
34
|
+
# stage the blank folders
|
35
|
+
index.add(path: 'data/.gitkeep',
|
36
|
+
oid: (Rugged::Blob.from_workdir repo, 'data/.gitkeep'),
|
37
|
+
mode: 0100644)
|
38
|
+
|
39
|
+
index.add(path: 'media/.gitkeep',
|
40
|
+
oid: (Rugged::Blob.from_workdir repo, 'media/.gitkeep'),
|
41
|
+
mode: 0100644)
|
42
|
+
|
43
|
+
# commit them
|
44
|
+
tree = index.write_tree(repo)
|
45
|
+
index.write
|
46
|
+
|
47
|
+
author = {
|
48
|
+
email: 'sender@example.com',
|
49
|
+
name: 'The Sender',
|
50
|
+
time: Time.now
|
51
|
+
}
|
52
|
+
|
53
|
+
Rugged::Commit.create(repo, author: author,
|
54
|
+
committer: author,
|
55
|
+
message: 'checking in data/media empties',
|
56
|
+
parents: [],
|
57
|
+
tree: tree,
|
58
|
+
update_ref: 'HEAD')
|
59
|
+
|
60
|
+
# push
|
61
|
+
repo.push 'origin', ['refs/heads/master']
|
62
|
+
end
|
63
|
+
|
64
|
+
config.after(:suite) do
|
65
|
+
RSpec.clean_testbed
|
66
|
+
end
|
67
|
+
end
|
data/spec/writer_spec.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Mail2FrontMatter::Writer, 'writing' do
|
4
|
+
let(:config) { File.join(M2FM_GEM_PATH, 'fixtures', 'mail2frontmatter.simple.yml') }
|
5
|
+
let(:message_one) { Mail::Message.new(File.read(File.join(M2FM_GEM_PATH, 'fixtures', 'attachments.eml'))) }
|
6
|
+
|
7
|
+
it 'should write a parse and processed email' do
|
8
|
+
Mail2FrontMatter.set_config(config) do |config|
|
9
|
+
config[:data_directory] = File.join(M2FM_GEM_PATH, 'spec', 'installation', 'data')
|
10
|
+
config[:media_directory] = File.join(M2FM_GEM_PATH, 'spec', 'installation', 'media')
|
11
|
+
end
|
12
|
+
|
13
|
+
parser = Mail2FrontMatter::Parser.new(message_one)
|
14
|
+
metadata, body = Mail2FrontMatter::PreProcessor.process(parser.metadata, parser.body)
|
15
|
+
|
16
|
+
Mail2FrontMatter::Writer.write(metadata, body)
|
17
|
+
|
18
|
+
expect(File.exist?(File.join(Mail2FrontMatter.config[:data_directory], '2009-11-25-295-abandoned-elevator-shaft.html.erb'))).to be(true)
|
19
|
+
expect(File.exist?(File.join(Mail2FrontMatter.config[:media_directory], 'images', 'IMG_0141.JPG'))).to be(true)
|
20
|
+
end
|
21
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mail2frontmatter
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kunal Shah
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2016-04-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: mailman
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
19
|
+
version: 0.7.3
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version:
|
26
|
+
version: 0.7.3
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: nokogiri
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -52,6 +52,20 @@ dependencies:
|
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '4'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rugged
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0.21'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0.21'
|
55
69
|
- !ruby/object:Gem::Dependency
|
56
70
|
name: rspec
|
57
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -108,8 +122,7 @@ dependencies:
|
|
108
122
|
- - "~>"
|
109
123
|
- !ruby/object:Gem::Version
|
110
124
|
version: '10.0'
|
111
|
-
description: '
|
112
|
-
poll an account. '
|
125
|
+
description: 'email-in for static blogs like Middleman. Uses Mailman to poll an account. '
|
113
126
|
email:
|
114
127
|
- me@kunalashah.com
|
115
128
|
executables:
|
@@ -135,6 +148,7 @@ files:
|
|
135
148
|
- fixtures/mail2frontmatter/fake-processor.rb
|
136
149
|
- fixtures/no_attachments.eml
|
137
150
|
- lib/mail2frontmatter.rb
|
151
|
+
- lib/mail2frontmatter/committer.rb
|
138
152
|
- lib/mail2frontmatter/configuration.rb
|
139
153
|
- lib/mail2frontmatter/parser.rb
|
140
154
|
- lib/mail2frontmatter/preprocessor.rb
|
@@ -142,10 +156,15 @@ files:
|
|
142
156
|
- lib/mail2frontmatter/watcher.rb
|
143
157
|
- lib/mail2frontmatter/writer.rb
|
144
158
|
- mail2frontmatter.gemspec
|
159
|
+
- spec/committer_spec.rb
|
145
160
|
- spec/configuration_spec.rb
|
161
|
+
- spec/installation/data/.gitkeep
|
162
|
+
- spec/installation/media/.gitkeep
|
146
163
|
- spec/parser_spec.rb
|
147
164
|
- spec/preprocessor_spec.rb
|
165
|
+
- spec/remote/.gitkeep
|
148
166
|
- spec/spec_helper.rb
|
167
|
+
- spec/writer_spec.rb
|
149
168
|
homepage: https://github.com/whistlerbrk/Mail2FrontMatter
|
150
169
|
licenses:
|
151
170
|
- MIT
|
@@ -166,12 +185,17 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
166
185
|
version: '0'
|
167
186
|
requirements: []
|
168
187
|
rubyforge_project:
|
169
|
-
rubygems_version: 2.
|
188
|
+
rubygems_version: 2.5.1
|
170
189
|
signing_key:
|
171
190
|
specification_version: 4
|
172
|
-
summary:
|
191
|
+
summary: email-in for static blogs like Middleman
|
173
192
|
test_files:
|
193
|
+
- spec/committer_spec.rb
|
174
194
|
- spec/configuration_spec.rb
|
195
|
+
- spec/installation/data/.gitkeep
|
196
|
+
- spec/installation/media/.gitkeep
|
175
197
|
- spec/parser_spec.rb
|
176
198
|
- spec/preprocessor_spec.rb
|
199
|
+
- spec/remote/.gitkeep
|
177
200
|
- spec/spec_helper.rb
|
201
|
+
- spec/writer_spec.rb
|