m2m 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,6 @@
1
+ module M2M
2
+ VERSION = "0.2.0"
3
+ NAME = "m2m"
4
+ REPOS = "https://github.com/wvv8oo/m2m"
5
+ HOMEPAGE = "http://m2m.wvv8oo.com/"
6
+ end
@@ -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
@@ -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
@@ -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
@@ -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