m2m 0.2.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 +7 -0
- data/.gitignore +39 -0
- data/Gemfile +11 -0
- data/Gemfile.lock +23 -0
- data/LICENSE +21 -0
- data/README.md +89 -0
- data/bin/console +14 -0
- data/exe/m2m +51 -0
- data/exe/mailer.rb +21 -0
- data/exe/server.rb +21 -0
- data/exe/setup.rb +27 -0
- data/exe/site.rb +37 -0
- data/lib/article.rb +63 -0
- data/lib/compiler.rb +77 -0
- data/lib/generator.rb +176 -0
- data/lib/mailer.rb +235 -0
- data/lib/meta.rb +48 -0
- data/lib/product.rb +6 -0
- data/lib/scan.rb +48 -0
- data/lib/server.rb +18 -0
- data/lib/setup.rb +278 -0
- data/lib/store.rb +113 -0
- data/lib/themes/hyde/static/hyde.css +355 -0
- data/lib/themes/hyde/template/article.mustache +19 -0
- data/lib/themes/hyde/template/home.mustache +15 -0
- data/lib/themes/hyde/template/index.mustache +15 -0
- data/lib/themes/hyde/template/mail.mustache +5 -0
- data/lib/themes/hyde/template/page.mustache +17 -0
- data/lib/themes/hyde/template/partials/footer.mustache +1 -0
- data/lib/themes/hyde/template/partials/head.mustache +6 -0
- data/lib/themes/hyde/template/partials/header.mustache +22 -0
- data/lib/themes/hyde/template/partials/list.mustache +20 -0
- data/lib/toc.rb +55 -0
- data/lib/util.rb +119 -0
- data/m2m.gemspec +40 -0
- metadata +204 -0
data/lib/product.rb
ADDED
data/lib/scan.rb
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
|
2
|
+
require 'pathname'
|
3
|
+
require_relative './util'
|
4
|
+
require_relative './setup'
|
5
|
+
|
6
|
+
class Scan
|
7
|
+
#初始化
|
8
|
+
def initialize()
|
9
|
+
@util = Util.instance
|
10
|
+
@setup = Setup.instance
|
11
|
+
@files = Array.new
|
12
|
+
end
|
13
|
+
|
14
|
+
#返回已经获取的文件列表
|
15
|
+
def files
|
16
|
+
return @files
|
17
|
+
end
|
18
|
+
|
19
|
+
#获取文件
|
20
|
+
def fetch(dir)
|
21
|
+
Dir::entries(dir).each do |filename|
|
22
|
+
#忽略的文件
|
23
|
+
next if @util.is_shadow_file?(filename)
|
24
|
+
|
25
|
+
#检查是否配置文件中所忽略的文件
|
26
|
+
#这里需要用相对路径
|
27
|
+
next if @setup.is_user_ignore_file?(filename)
|
28
|
+
|
29
|
+
file = File::join(dir, filename)
|
30
|
+
#如果是文件夹类型, 则继承查找
|
31
|
+
if(File.ftype(file) == 'directory')
|
32
|
+
self.fetch file
|
33
|
+
next
|
34
|
+
end
|
35
|
+
|
36
|
+
#如果文件扩展名是md, 则加入到files中
|
37
|
+
if @util.is_markdown_file?(filename)
|
38
|
+
current_dir = Pathname.new file
|
39
|
+
@files.push current_dir.relative_path_from(@setup.content_dir)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
#执行
|
45
|
+
def execute()
|
46
|
+
fetch @setup.content_dir
|
47
|
+
end
|
48
|
+
end
|
data/lib/server.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'webrick'
|
2
|
+
require_relative './util'
|
3
|
+
require_relative './setup'
|
4
|
+
|
5
|
+
# class Server < ::Rack::Server
|
6
|
+
# def app
|
7
|
+
# Rack::Directory::new Setup.instance.target_dir
|
8
|
+
# end
|
9
|
+
# end
|
10
|
+
|
11
|
+
class Server
|
12
|
+
def start(port)
|
13
|
+
port = port || 8000
|
14
|
+
root = Setup.instance.target_dir
|
15
|
+
server = WEBrick::HTTPServer.new :Port => port, :DocumentRoot => root
|
16
|
+
server.start
|
17
|
+
end
|
18
|
+
end
|
data/lib/setup.rb
ADDED
@@ -0,0 +1,278 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
require 'singleton'
|
3
|
+
require_relative './util'
|
4
|
+
require_relative './product'
|
5
|
+
|
6
|
+
class Setup
|
7
|
+
include Singleton
|
8
|
+
attr :target_dir, true
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
@util = Util.instance
|
12
|
+
#合并后的配置信息
|
13
|
+
@merge_config = nil
|
14
|
+
#内容目录
|
15
|
+
@content_dir = nil
|
16
|
+
#构建的目标目录
|
17
|
+
@target_dir = nil
|
18
|
+
#邮件的配置
|
19
|
+
@mail_config = nil
|
20
|
+
end
|
21
|
+
|
22
|
+
#读取邮件的配置
|
23
|
+
def mail_config
|
24
|
+
@mail_config = self.get_merged_config['mail'] if not @mail_config
|
25
|
+
@mail_config
|
26
|
+
end
|
27
|
+
|
28
|
+
#最终的构建目录
|
29
|
+
def target_dir
|
30
|
+
dir = @target_dir
|
31
|
+
#已经处理过了
|
32
|
+
return dir if dir.class == Pathname
|
33
|
+
|
34
|
+
#如果没有指定构建目录,则使用配置文件的目录
|
35
|
+
config = self.get_merged_config
|
36
|
+
dir = config['target'] if not dir
|
37
|
+
|
38
|
+
#依然没有获取准确的目录,则使用使用临时目录
|
39
|
+
# dir = File::join(@util.get_temp_dir, @util.project_name) if not dir
|
40
|
+
#如果没有获取构建目录,则在当前目录下,创建一个
|
41
|
+
dir = './m2m-site' if not dir
|
42
|
+
#如果是字符类型,则获取相对于workbench的目录
|
43
|
+
@target_dir = @util.get_merge_path dir if dir.class == String
|
44
|
+
|
45
|
+
@target_dir
|
46
|
+
end
|
47
|
+
|
48
|
+
#获取内容的目录
|
49
|
+
def content_dir
|
50
|
+
if not @content_dir
|
51
|
+
content_dir = self.get_merged_config['content'] || './'
|
52
|
+
@content_dir = @util.get_merge_path(content_dir, @util.workbench)
|
53
|
+
end
|
54
|
+
|
55
|
+
@content_dir
|
56
|
+
end
|
57
|
+
|
58
|
+
#获取配置文件的地址
|
59
|
+
def get_config_file(is_global = true)
|
60
|
+
root = is_global ? @util.get_temp_dir : @util.workbench
|
61
|
+
#全局的配置文件
|
62
|
+
File::join root, @util.config_file
|
63
|
+
end
|
64
|
+
|
65
|
+
#读取配置文件
|
66
|
+
def read(is_global)
|
67
|
+
file = self.get_config_file is_global
|
68
|
+
return {} if not File::exists? file
|
69
|
+
|
70
|
+
#读取配置文件
|
71
|
+
YAML.load IO.read(file)
|
72
|
+
end
|
73
|
+
|
74
|
+
#写入配置文件
|
75
|
+
def write(config, is_global)
|
76
|
+
file = self.get_config_file is_global
|
77
|
+
@util.write_file file, config.to_yaml
|
78
|
+
end
|
79
|
+
|
80
|
+
#读取本地与全局的配置文件,然后合并
|
81
|
+
def get_merged_config
|
82
|
+
return @merge_config if @merge_config
|
83
|
+
|
84
|
+
global_config = self.read true
|
85
|
+
local_config = self.read false
|
86
|
+
@merge_config = global_config.merge local_config
|
87
|
+
@merge_config
|
88
|
+
end
|
89
|
+
|
90
|
+
#是否为用户在配置文件中的忽略的文件
|
91
|
+
def is_user_ignore_file?(file)
|
92
|
+
config = self.get_merged_config
|
93
|
+
ignores = config['ignore']
|
94
|
+
return false if not ignores
|
95
|
+
|
96
|
+
ignores.each { |current|
|
97
|
+
#TODO 这里还需要再增加
|
98
|
+
}
|
99
|
+
|
100
|
+
return false
|
101
|
+
end
|
102
|
+
|
103
|
+
#根据问题的配置文件列表,揭示用户输入
|
104
|
+
def ask_items(items, data)
|
105
|
+
items.each { |item|
|
106
|
+
type = item['type']
|
107
|
+
value = ask(item['ask'], type){|q|
|
108
|
+
q.default = item['default'] if item['default']
|
109
|
+
q.echo = item['echo'] if item['echo']
|
110
|
+
q.validate = item['validate'] if item['validate']
|
111
|
+
q.responses[:not_valid] = item['error'] if item['error']
|
112
|
+
}
|
113
|
+
|
114
|
+
if type == Integer
|
115
|
+
value = value.to_i
|
116
|
+
else
|
117
|
+
value = value.to_s
|
118
|
+
end
|
119
|
+
|
120
|
+
data[item['key']] = value
|
121
|
+
}
|
122
|
+
data
|
123
|
+
end
|
124
|
+
|
125
|
+
#检查邮件的配置
|
126
|
+
def check_mail_setup
|
127
|
+
mail_config = self.get_merged_config['mail']
|
128
|
+
|
129
|
+
return @util.error '请执行[m2m mail --setup]启动配置' if not mail_config
|
130
|
+
|
131
|
+
items = {
|
132
|
+
'smtp_server' => 'STMP服务器',
|
133
|
+
'port' => '端口',
|
134
|
+
'username' => '用户名',
|
135
|
+
'password' => '密码',
|
136
|
+
'from' => '发件人'
|
137
|
+
}
|
138
|
+
|
139
|
+
items.each {|key, desc|
|
140
|
+
@util.error "#{desc}没有配置,请执行[m2m mail --setup]启动配置" if mail_config[key] == ''
|
141
|
+
}
|
142
|
+
end
|
143
|
+
|
144
|
+
#询问用户的信息
|
145
|
+
def ask_mail
|
146
|
+
#获取全局的配置
|
147
|
+
data = self.read true
|
148
|
+
mail_data = data['mail'] || {}
|
149
|
+
|
150
|
+
items = [
|
151
|
+
{
|
152
|
+
'key' => 'smtp_server',
|
153
|
+
'ask' => '请输入您的【SMTP服务器地址】,如smpt.163.com',
|
154
|
+
'default' => mail_data['smtp_server'],
|
155
|
+
'type' => String,
|
156
|
+
'validate' => /(\.[a-zA-Z0-9\-]+){2,}/,
|
157
|
+
'error' => '您的SMTP地址输入不正确,请输入域名或者IP地址'
|
158
|
+
},{
|
159
|
+
'key' => 'port',
|
160
|
+
'ask' => '请输入您的【SMTP端口】,默认为465',
|
161
|
+
'default' => mail_data['port'] || 465,
|
162
|
+
'type' => Integer,
|
163
|
+
'validate' => /^\d+$/,
|
164
|
+
'error' => '您的端口输入不正确,只能输入整数'
|
165
|
+
},{
|
166
|
+
'key' => 'username',
|
167
|
+
'ask' => '请输入您的【邮件帐号】,如mail@example.com',
|
168
|
+
'default' => mail_data['username'],
|
169
|
+
'type' => String,
|
170
|
+
'validate' => /^[a-z0-9]+([._\\-]*[a-z0-9])*@([a-z0-9]+[-a-z0-9]*[a-z0-9]+.){1,63}[a-z0-9]+$/,
|
171
|
+
'error' => '您的邮箱帐号输入不正确'
|
172
|
+
},{
|
173
|
+
'key' => 'from',
|
174
|
+
'ask' => '请输入您的【发件人邮件地址】,如<张三> mail@example.com,如果没有设置,则与邮件帐号一致',
|
175
|
+
'default' => mail_data['from'],
|
176
|
+
'type' => String
|
177
|
+
},{
|
178
|
+
'key' => 'subject',
|
179
|
+
'ask' => '请输入您的【默认邮件主题】,非必填,按回车可以跳过',
|
180
|
+
'default' => mail_data['subject'],
|
181
|
+
'type' => String
|
182
|
+
},{
|
183
|
+
'key' => 'to',
|
184
|
+
'ask' => '请输入您的【默认收件人】,多个以逗号为分隔,非必填,按回车可以跳过',
|
185
|
+
'default' => mail_data['to'],
|
186
|
+
'type' => String
|
187
|
+
},{
|
188
|
+
'key' => 'ssl',
|
189
|
+
'ask' => '请确认【是否启用SSL】,一般465或者587端口都会启用SSL,[y/n]',
|
190
|
+
'default' => mail_data['ssl'] || 'y',
|
191
|
+
'validate' => /^[yn]$/,
|
192
|
+
'error' => '请输入y或者n表示是否启用SSL',
|
193
|
+
'type' => String
|
194
|
+
}
|
195
|
+
]
|
196
|
+
|
197
|
+
mail_data = self.ask_items items, mail_data
|
198
|
+
#设置默认的format
|
199
|
+
mail_data['format'] = '%Y/%m/%d' if mail_data['format'] == ''
|
200
|
+
#没有设置from,则使用username
|
201
|
+
mail_data['from'] = mail_data['username'] if mail_data['from'] == ''
|
202
|
+
|
203
|
+
#填到mail
|
204
|
+
data['mail'] = mail_data
|
205
|
+
|
206
|
+
#写入文件
|
207
|
+
self.write data, true
|
208
|
+
|
209
|
+
#询问密码
|
210
|
+
self.ask_mail_password false
|
211
|
+
|
212
|
+
puts "您的邮件基本信息配置成功,更多配置方式请参考:#{M2M::HOMEPAGE}config.html"
|
213
|
+
end
|
214
|
+
|
215
|
+
#用户输入密码以及加密内容
|
216
|
+
def ask_mail_password(show_success_message = false)
|
217
|
+
data = self.read true
|
218
|
+
mail_data = data['mail'] || {}
|
219
|
+
|
220
|
+
items = [
|
221
|
+
{
|
222
|
+
'key' => 'password',
|
223
|
+
'ask' => '请输入您的【邮箱密码】,邮件密码以加密的方式保存在您本地电脑上',
|
224
|
+
'default' => nil,
|
225
|
+
'echo' => '*',
|
226
|
+
'type' => String,
|
227
|
+
'validate' => /.{1,}/,
|
228
|
+
'error' => '请输入您的邮件密码'
|
229
|
+
},{
|
230
|
+
'key' => 'encrypt_key',
|
231
|
+
'ask' => '请输入您的【加密钥匙】,此钥匙用于解密您的密码,请务必牢记,按回车可以跳过',
|
232
|
+
'default' => nil,
|
233
|
+
'echo' => '*',
|
234
|
+
'type' => String
|
235
|
+
}
|
236
|
+
]
|
237
|
+
|
238
|
+
new_data = {}
|
239
|
+
new_data = self.ask_items items, new_data
|
240
|
+
|
241
|
+
#对密码进行加密
|
242
|
+
password = new_data['password']
|
243
|
+
encrypt_key = new_data['encrypt_key']
|
244
|
+
|
245
|
+
password = @util.encrypt password, encrypt_key
|
246
|
+
mail_data['password'] = password
|
247
|
+
mail_data['safer'] = encrypt_key != ''
|
248
|
+
|
249
|
+
data['mail'] = mail_data
|
250
|
+
self.write data, true
|
251
|
+
|
252
|
+
puts '您的邮件密码配置成功' if show_success_message
|
253
|
+
end
|
254
|
+
|
255
|
+
#配置网站相关的
|
256
|
+
def ask_site
|
257
|
+
data = self.read false
|
258
|
+
site_data = data['site'] || {}
|
259
|
+
|
260
|
+
items = [
|
261
|
+
{
|
262
|
+
'key' => 'title',
|
263
|
+
'ask' => '您的网站标题,如:M2M官方网站,按回车跳过',
|
264
|
+
'default' => site_data['title'],
|
265
|
+
'type' => String
|
266
|
+
},{
|
267
|
+
'key' => 'host',
|
268
|
+
'ask' => '主机地址,如:http://m2m.wvv8oo.com/,按回车跳过',
|
269
|
+
'default' => site_data['host'],
|
270
|
+
'type' => String
|
271
|
+
}
|
272
|
+
]
|
273
|
+
|
274
|
+
data['site'] = self.ask_items items, site_data
|
275
|
+
self.write data, false
|
276
|
+
puts "您的网站配置成功,更多配置方式请参考:#{M2M::HOMEPAGE}config.html"
|
277
|
+
end
|
278
|
+
end
|
data/lib/store.rb
ADDED
@@ -0,0 +1,113 @@
|
|
1
|
+
#缓存数据, 并建立索引
|
2
|
+
|
3
|
+
require_relative './article'
|
4
|
+
require_relative './util'
|
5
|
+
|
6
|
+
class Store
|
7
|
+
def initialize(files)
|
8
|
+
#直接子级的key
|
9
|
+
@children_key = '__children__'
|
10
|
+
#所有后代的key
|
11
|
+
@posterity_key = '__posterity__'
|
12
|
+
#所有文章
|
13
|
+
@article = Article.new
|
14
|
+
|
15
|
+
@data = {
|
16
|
+
#所有文章列表
|
17
|
+
'articles' => self.get_articles(files),
|
18
|
+
#目录树
|
19
|
+
'tree' => {
|
20
|
+
@children_key => Array.new
|
21
|
+
}
|
22
|
+
}
|
23
|
+
|
24
|
+
self.make_tree_index
|
25
|
+
self.sort @data['tree']
|
26
|
+
end
|
27
|
+
|
28
|
+
def tree
|
29
|
+
@data['tree']
|
30
|
+
end
|
31
|
+
|
32
|
+
def articles
|
33
|
+
@data['articles']
|
34
|
+
end
|
35
|
+
|
36
|
+
#从节点数据中, 获取items
|
37
|
+
def get_children(node = @data['tree'])
|
38
|
+
node[@children_key]
|
39
|
+
end
|
40
|
+
|
41
|
+
def is_children_key(key)
|
42
|
+
key == @children_key
|
43
|
+
end
|
44
|
+
|
45
|
+
#获取所有的文章列表
|
46
|
+
#以hash的方式保存, key即是文件路径的md5值
|
47
|
+
def get_articles(files)
|
48
|
+
result = Hash.new
|
49
|
+
|
50
|
+
files.each { | file |
|
51
|
+
article = @article.convert(file)
|
52
|
+
key = article['relative_path_md5']
|
53
|
+
result[key] = article;
|
54
|
+
}
|
55
|
+
|
56
|
+
result
|
57
|
+
end
|
58
|
+
|
59
|
+
#创建树状结构的索引
|
60
|
+
def make_tree_index
|
61
|
+
this = self
|
62
|
+
@data['articles'].each{ |key, article|
|
63
|
+
dir = File::dirname(article['relative_path'])
|
64
|
+
relative_path_md5 = article['relative_path_md5']
|
65
|
+
this.mount_node_to_tree dir, relative_path_md5
|
66
|
+
}
|
67
|
+
end
|
68
|
+
|
69
|
+
#挂到节点上, 如果不在则创建
|
70
|
+
def mount_node_to_tree(path, relative_path_md5)
|
71
|
+
node = @data['tree']
|
72
|
+
|
73
|
+
if path == '.'
|
74
|
+
node[@children_key].push relative_path_md5
|
75
|
+
return
|
76
|
+
end
|
77
|
+
|
78
|
+
path.split('/').each{ |segment|
|
79
|
+
current_node = node[segment]
|
80
|
+
if not current_node
|
81
|
+
current_node = Hash.new()
|
82
|
+
current_node[@children_key] = Array.new
|
83
|
+
node[segment] = current_node
|
84
|
+
end
|
85
|
+
|
86
|
+
node = current_node
|
87
|
+
node[@children_key].push relative_path_md5
|
88
|
+
|
89
|
+
#所有的子级,都要向root插入数据
|
90
|
+
@data['tree'][@children_key].push relative_path_md5
|
91
|
+
}
|
92
|
+
end
|
93
|
+
|
94
|
+
|
95
|
+
#给所有的文件夹排序
|
96
|
+
def sort(node)
|
97
|
+
this = self
|
98
|
+
node.each { | key, current |
|
99
|
+
#items, 需要进行排序
|
100
|
+
if key == @children_key
|
101
|
+
#根据文章的最后修改日期进行排序
|
102
|
+
current.sort! {|left, right|
|
103
|
+
left_article = @data['articles'][left]
|
104
|
+
right_article = @data['articles'][right]
|
105
|
+
right_article['mtime'] <=> left_article['mtime']
|
106
|
+
}
|
107
|
+
else
|
108
|
+
#递归调用进行排序
|
109
|
+
this.sort(current)
|
110
|
+
end
|
111
|
+
}
|
112
|
+
end
|
113
|
+
end
|