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.
@@ -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