m2m 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,176 @@
1
+ #生成全站
2
+ require 'fileutils'
3
+
4
+ require_relative './scan'
5
+ require_relative './compiler'
6
+ require_relative './util'
7
+ require_relative './store'
8
+ require_relative './setup'
9
+
10
+ class Generator
11
+ def initialize
12
+ @util = Util.instance
13
+ @setup = Setup.instance
14
+
15
+ #删除目标目录
16
+ FileUtils.rmtree @setup.target_dir
17
+
18
+ #扫描文件
19
+ scan = Scan.new
20
+ scan.execute
21
+
22
+ #存储文件
23
+ @store = Store.new scan.files
24
+
25
+ @compiler = Compiler.new
26
+ @page_size = @setup.get_merged_config['page_size'] || 10
27
+ @page_size = 10 if @page_size.class != Integer
28
+
29
+ self.generate_articles
30
+ self.copy_theme_resource
31
+ #复制文件有问题
32
+ self.copy_workbench_resource
33
+ self.generate_home
34
+ self.generate_all_index @store.tree, '', true
35
+ puts 'Done...'
36
+ end
37
+
38
+ #创建首页
39
+ def generate_home
40
+ children = @store.get_children(@store.tree)
41
+ self.generate_index children, 1, 'home', ''
42
+ end
43
+
44
+ #创建所有的索引页, 如果有文件夹, 则根据配置创建文件夹中的索引页
45
+ #不会创建首页的index
46
+ def generate_all_index(node, dir, ignore_first_index)
47
+ this = self
48
+
49
+ #创建children的所有索引
50
+ children = @store.get_children node
51
+ page_count = (children.length.to_f / @page_size).ceil
52
+
53
+ #生成此文件夹下的所有索引页
54
+ (1..page_count).each { |page_index|
55
+ #忽略第一页的索引, 一般是首页的情况下
56
+ next if page_index == 1 and ignore_first_index
57
+
58
+ # puts dir, page_index
59
+ this.generate_index children, page_index, 'index', dir
60
+ }
61
+
62
+ #遍历所有的文件夹节点, 递归调用
63
+ node.each { |key, sub_node|
64
+ if not @store.is_children_key(key)
65
+ parent_dir = dir + key + '/'
66
+ this.generate_all_index sub_node, parent_dir, false
67
+ end
68
+ }
69
+ end
70
+
71
+ #创建所有文章页
72
+ def generate_articles
73
+ @store.articles.each { |key, article|
74
+ relative_url = article['relative_url']
75
+
76
+ data = {
77
+ 'article' => article
78
+ }
79
+ self.compiler(relative_url, 'article', data)
80
+ }
81
+ end
82
+
83
+ #创建索引页, 包括首页以及子目录的索引页
84
+ def generate_index(children, page_index, template_name, dir)
85
+ articles = []
86
+ start_index = page_index * @page_size - @page_size
87
+ end_index = start_index + @page_size
88
+ #总页数
89
+ page_count = (children.length.to_f / @page_size).ceil
90
+
91
+ path = dir + (page_index == 1 ? 'index.html' : "page-#{page_index}.html")
92
+
93
+ children[start_index..end_index].each { |current|
94
+ articles.push @store.articles[current]
95
+ }
96
+
97
+
98
+
99
+ data = {
100
+ 'articles' => articles,
101
+ 'nav' => self.get_nav(page_index, page_count)
102
+ }
103
+
104
+ self.compiler path, template_name, data
105
+ end
106
+
107
+ #处理上一页下一页
108
+ def get_nav(page_index, page_count)
109
+ nav = {}
110
+ #上一页
111
+ if(page_index == 2)
112
+ nav['previous'] = 'index.html'
113
+ elsif(page_index > 2)
114
+ nav['previous'] = "page-#{page_index - 1}.html"
115
+ end
116
+
117
+ #下一页
118
+ if(page_index < page_count)
119
+ nav['next'] = "page-#{page_index + 1}.html"
120
+ end
121
+
122
+ #以后要处理总的分页信息
123
+
124
+ nav
125
+ end
126
+
127
+ #编译模板
128
+ def compiler(filename, template_name, data)
129
+ data['product'] = @util.get_product
130
+ data['root/relative_path'] = @util.get_relative_dot(filename)
131
+
132
+ @compiler.execute template_name, data, true, filename
133
+ end
134
+
135
+ #复制theme中的资源到目录
136
+ def copy_theme_resource
137
+ this = self
138
+ theme_dir = @compiler.theme_dir
139
+
140
+ Dir::entries(theme_dir).each{ |filename|
141
+ #忽略掉以.开头的
142
+ next if (/^\.|(template)/i =~ filename) != nil
143
+
144
+ this.copy File::join(theme_dir, filename), filename
145
+ }
146
+ end
147
+
148
+ #复制文件到目标
149
+ def copy(source, filename)
150
+ target = File::join @setup.target_dir, filename
151
+
152
+ FileUtils.cp_r source, target
153
+ end
154
+
155
+ #复制工作目录的所有资源, 除忽略/.md/配置文件以外的
156
+ def copy_workbench_resource
157
+ this = self
158
+ Dir::entries(@util.workbench).each{ |filename|
159
+ #忽略掉以.开头的, 以及markdown文件, 还有用户忽略的文件
160
+ next if @util.is_shadow_file?(filename) or
161
+ @util.is_markdown_file?(filename) or
162
+ @util.local_theme_dir == filename or
163
+ @setup.is_user_ignore_file?(filename)
164
+
165
+ #当前的路径
166
+ current_path = @util.get_merge_path filename, @util.workbench
167
+
168
+ #build和内容退出
169
+ next if @setup.target_dir === current_path or
170
+ @setup.content_dir === current_path or
171
+ @util.is_config_file? current_path
172
+
173
+ this.copy File::join(@util.workbench, filename), filename
174
+ }
175
+ end
176
+ end
@@ -0,0 +1,235 @@
1
+ #将markdown发送为邮件
2
+ require 'mail'
3
+ require_relative './scan'
4
+ require_relative './compiler'
5
+ require_relative './util'
6
+ require_relative './store'
7
+ require_relative './setup'
8
+
9
+ class Mailer
10
+ def initialize
11
+ @util = Util.instance
12
+ @mail_config = Setup.instance.get_merged_config['mail']
13
+ #检查邮件的配置信息
14
+ Setup.instance.check_mail_setup
15
+
16
+ #扫描所有文件
17
+ scan = Scan.new
18
+ scan.execute
19
+
20
+ @store = Store.new scan.files
21
+ @compiler = Compiler.new
22
+ end
23
+
24
+ #添加附件, 并返回替换后的body
25
+ def add_pictures(mail, article, body)
26
+ images = body.scan(/<img.+src=["'](.+?)['"]/i)
27
+ return body if images.length == 0
28
+
29
+ root = Pathname.new File::dirname(article['file'])
30
+ #去重,并去掉非相对路径的
31
+ list = Hash.new
32
+ images.each { | line |
33
+ image = line[0]
34
+ next if not /^[\.\/]/ =~ image
35
+
36
+ #将全路径作为key,达到去重的效果
37
+ file = (root + Pathname.new(image)).to_s
38
+ list[file] = image
39
+ }
40
+
41
+ #遍历所有图片,添加到附件
42
+ list.each do |file, src|
43
+ mail.add_file file
44
+ cid = mail.attachments.last.cid
45
+ body = body.gsub(src, 'CID:' + cid)
46
+ end
47
+
48
+ body
49
+ end
50
+
51
+ #添加邮件的主体内容,包括body/处理附件等
52
+ def add_content(mail, article)
53
+ #获取body的内容
54
+ data = {
55
+ "article" => article
56
+ }
57
+ body = @compiler.execute 'mail', data, false
58
+ body = body + self.get_ad
59
+
60
+ #分析出图片列表
61
+ body = self.add_pictures mail, article, body
62
+
63
+ #添加邮件的HTML内容
64
+ mail.html_part = Mail::Part.new do
65
+ content_type 'text/html; charset=UTF-8'
66
+ body body
67
+ end
68
+ end
69
+
70
+ #获取用户的密码,如果用户使用了密码进行加密,则提示用户输入密钥
71
+ def get_password
72
+ safer = @mail_config['safer']
73
+ password = @mail_config['password']
74
+
75
+ encrypt_key = nil
76
+ if safer
77
+ message = "请输入加密您密码的钥匙"
78
+ encript_key = ask(message, String){|q|
79
+ q.echo = '*'
80
+ }
81
+ end
82
+
83
+ @util.decrypt password, encript_key
84
+ end
85
+
86
+ #设置邮件的默认配置
87
+ def set_mail_defaults
88
+ smtp_server = @mail_config['smtp_server']
89
+ port = @mail_config['port']
90
+ username = @mail_config['username']
91
+ ssl = @mail_config['ssl'] == 'y'
92
+ password = self.get_password
93
+
94
+ #配置邮件参数
95
+ Mail.defaults do
96
+ delivery_method :smtp, {
97
+ :address => smtp_server,
98
+ :port => port,
99
+ :user_name => username,
100
+ :password => password,
101
+ :ssl => ssl,
102
+ :enable_starttls_auto => true
103
+ }
104
+ end
105
+ end
106
+
107
+ #添加广告
108
+ def get_ad()
109
+ <<EOF
110
+ <div class="product" style="background-color: rgba(204, 204, 204, 0.26);padding: 4px 10px; text-align: right; font-size: 12px;">
111
+ 本邮件由
112
+ <a href="https://github.com/wvv8oo/m2m" target="_blank">m2m</a>
113
+ 根据Markdown自动转换并发送
114
+ </div>
115
+ EOF
116
+ end
117
+
118
+ #获取邮件接收人
119
+ def get_to(to, article)
120
+ meta = article['meta']
121
+
122
+ #优先取meta中的to
123
+ to = meta['to'] if not to and meta['to']
124
+ #如果meta没有to,且用户也没有指定to,则使用
125
+ to = @mail_config['to'] if not to
126
+ #依然没有找到收件人
127
+ return @util.error '邮件接收人无效,可使用-a参数指定收件人' if not to
128
+
129
+ to = [to] if to.class == String
130
+ to
131
+ end
132
+
133
+ #获取将要发送的markdown文件
134
+ def get_article(md_file)
135
+ items = @store.get_children()
136
+ return @util.error '没有找到任何的Markdown文件' if items.length == 0
137
+
138
+ #如果用户没有指定, 则取最新的
139
+ return @store.articles[items[0]] if not md_file
140
+
141
+ special_article = nil
142
+ index = 0
143
+ begin
144
+ key = items[index]
145
+ article = @store.articles[key]
146
+ file = article['file']
147
+ relative_path = @util.get_relative_path file, @util.workbench
148
+
149
+ special_article = article if relative_path == md_file
150
+
151
+
152
+ index += 1
153
+ end while special_article == nil and index < items.length
154
+
155
+ @util.error "当前目录下未找到Markdown文件 => #{md_file}" if not special_article
156
+ return special_article
157
+ end
158
+
159
+ #优先读取用户指定的,然后读取文章中指定的subject,再读取配置文件中的
160
+ def get_subject(subject, article)
161
+ meta = article['meta']
162
+ #读取文章中mate的,如果在命令行没有指定主题
163
+ subject = meta['subject'] if not subject and meta['subject']
164
+
165
+ #文章中没有,则使用配置文件中的
166
+ subject = @mail_config['subject'] if not subject
167
+
168
+ #配置文件也没有,则使用title,article无论如何都会有title的
169
+ subject = meta['title'] if not subject
170
+
171
+ self.covert_date_macro subject
172
+ end
173
+
174
+ def get_from
175
+ from = @mail_config['from']
176
+ from = @mail_config['account'] if not from
177
+ from
178
+ end
179
+
180
+ #将标题中的日期宏,转换为对应的日期
181
+ def covert_date_macro(subject)
182
+ format = @mail_config['format'] || '%Y-%m-%d'
183
+ subject = subject.gsub('$now', Date.today.strftime(format))
184
+ subject = subject.gsub('$last_week', (Date.today - 7).strftime(format))
185
+ subject
186
+ end
187
+
188
+ #警示用户,由用户确定是否发送
189
+ def alarm(relative_path, subject, to)
190
+ puts "您确定要发送这封邮件吗?"
191
+ puts "邮件标题:#{subject}"
192
+ puts "Markdown:#{relative_path}"
193
+ puts "收件人:#{to}"
194
+ puts ""
195
+
196
+ #提示用户是否需要发送
197
+ result = ask("确认发送请按y或者回车,取消请按其它键", lambda { |yn| yn.downcase[0] == ?y or yn == ''})
198
+
199
+ @util.error '您中止了邮件的发送' if not result
200
+ end
201
+
202
+ #发送邮件
203
+ def send(to, md_file, subject, silent = false)
204
+ article = self.get_article md_file
205
+
206
+ from = self.get_from
207
+ to = self.get_to to, article
208
+ subject = self.get_subject subject, article
209
+
210
+ relative_path = @util.get_relative_path article['file'], @util.workbench
211
+
212
+ #配置邮件信息
213
+ self.set_mail_defaults
214
+
215
+ #警示用户是否需要发送
216
+ self.alarm relative_path, subject, to if not silent
217
+
218
+ #创建一个mail的实例,以后再添加附件和html内容
219
+ mail = Mail.new do
220
+ from from
221
+ to to
222
+ subject subject
223
+ end
224
+
225
+ self.add_content mail, article
226
+
227
+ # @util.write_file './send.log', mail.parts.last.decoded
228
+ mail.deliver
229
+
230
+ puts "恭喜,您的邮件发送成功"
231
+ puts "邮件标题:#{subject}"
232
+ puts "Markdown:#{relative_path}"
233
+ puts "收件人:#{to}"
234
+ end
235
+ end
@@ -0,0 +1,48 @@
1
+ #分析meta值
2
+ # http://pythonhosted.org/Markdown/extensions/meta_data.html
3
+
4
+ class Meta
5
+ def initialize
6
+
7
+ end
8
+
9
+ #分析meta的部分
10
+ def analysis_meta(original)
11
+ return nil if not original
12
+
13
+ result = Hash.new
14
+ list = original.split(/[\r\n?]/)
15
+
16
+ # 提取meta值
17
+ list.each{ |line|
18
+ next if line == ''
19
+ next if (/^(\w+):(.+)/i =~ line) == nil
20
+
21
+ key = $1.lstrip.rstrip
22
+ value = $2.lstrip.rstrip
23
+
24
+ result[key] = value
25
+ }
26
+
27
+ result
28
+ end
29
+
30
+ #分析内容
31
+ def analysis(original)
32
+ result = Hash.new
33
+
34
+ pattern = /(\s+)?<!\-\-(.+?)\-\->(.+)?/m
35
+ matches = pattern.match(original)
36
+
37
+ #如果没有匹配到, 则body就是完整的original
38
+ if matches == nil
39
+ result['body'] = original
40
+ return result
41
+ end
42
+
43
+ #获取body内容
44
+ result['body'] = $3
45
+ result['meta'] = self.analysis_meta $2
46
+ result
47
+ end
48
+ end