flr 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,175 @@
1
+ require 'flr/string_extensions'
2
+
3
+ module Flr
4
+ # 条件检测器,提供检测各种条件是否合法的方法
5
+ class Checker
6
+
7
+ # check_pubspec_file_is_existed(flutter_dir) -> true
8
+ #
9
+ # 检测当前flutter工程目录是否存在pubspec.yaml文件
10
+ # 若存在,返回true
11
+ # 若不存在,则抛出异常
12
+ #
13
+ # === Examples
14
+ #
15
+ # flutter_dir = "~/path/to/flutter_project/pubspec.yaml"
16
+ # Checker.check_pubspec_file_is_existed(flutter_dir)
17
+ #
18
+ def self.check_pubspec_file_is_existed(flutter_dir)
19
+ pubspec_file_path = flutter_dir + "/pubspec.yaml"
20
+
21
+ if File.exist?(pubspec_file_path) == false
22
+ message = <<-MESSAGE
23
+ #{"[x]: #{pubspec_file_path} not found".error_style}
24
+ #{"[*]: please make sure pubspec.yaml is existed in #{flutter_dir}".tips_style}
25
+ MESSAGE
26
+
27
+ raise(message)
28
+ end
29
+
30
+ end
31
+
32
+ # check_flr_config_is_existed(pubspec_config) -> true
33
+ #
34
+ # 检测pubspec.yaml中是否存在flr的配置信息`flr_config`:
35
+ #
36
+ # ``` yaml
37
+ # flr:
38
+ # core_version: 1.0.0
39
+ # dartfmt_line_length: 80
40
+ # assets:
41
+ # fonts:
42
+ # ```
43
+ # 若存在,返回true
44
+ # 若不存在,则抛出异常
45
+ #
46
+ # === Examples
47
+ #
48
+ # pubspec_config = YAML.load(pubspec_file)
49
+ # Checker.check_flr_config_is_existed(pubspec_config)
50
+ #
51
+ def self.check_flr_config_is_existed(pubspec_config)
52
+ flr_config = pubspec_config["flr"]
53
+
54
+ if flr_config.is_a?(Hash) == false
55
+ message = <<-MESSAGE
56
+ #{"[x]: have no flr configuration in pubspec.yaml".error_style}
57
+ #{"[*]: please run \"flr init\" to fix it".tips_style}
58
+ MESSAGE
59
+
60
+ raise(message)
61
+ end
62
+
63
+ return true
64
+ end
65
+
66
+ # check_flr_assets_is_legal(flr_config) -> resource_dir_result_tuple
67
+ #
68
+ # 检测当前flr配置信息中的assets配置是否合法
69
+ # 若合法,返回资源目录结果三元组 resource_dir_result_triplet
70
+ # 若不合法,抛出异常
71
+ #
72
+ # resource_dir_result_tuple = [assets_legal_resource_dir_array, illegal_resource_dir_array, fonts_legal_resource_dir_array]
73
+ #
74
+ #
75
+ # flr的assets配置是用于配置需要flr进行扫描的资源目录,如:
76
+ #
77
+ # ``` yaml
78
+ # flr:
79
+ # core_version: 1.0.0
80
+ # dartfmt_line_length: 80
81
+ # assets:
82
+ # - lib/assets/images
83
+ # - lib/assets/texts
84
+ # fonts:
85
+ # - lib/assets/fonts
86
+ # ```
87
+ #
88
+ # 判断flr的assets配置合法的标准是:assets配置的resource_dir数组中的legal_resource_dir数量大于0。
89
+ #
90
+ # === Examples
91
+ # assets_legal_resource_dir_array = ["lib/assets/images", "lib/assets/texts"]
92
+ # fonts_legal_resource_dir_array = ["lib/assets/fonts"]
93
+ # illegal_resource_dir_array = ["wrong/path/to/non-existed_folder"]
94
+ #
95
+ def self.check_flr_assets_is_legal(flr_config)
96
+ core_version = flr_config["core_version"]
97
+ dartfmt_line_length = flr_config["dartfmt_line_length"]
98
+ assets_resource_dir_array = flr_config["assets"]
99
+ fonts_resource_dir_array = flr_config["fonts"]
100
+
101
+ if assets_resource_dir_array.is_a?(Array) == false
102
+ assets_resource_dir_array = []
103
+ end
104
+
105
+ if fonts_resource_dir_array.is_a?(Array) == false
106
+ fonts_resource_dir_array = []
107
+ end
108
+
109
+ # 移除非法的 resource_dir(nil,空字符串,空格字符串)
110
+ assets_resource_dir_array = assets_resource_dir_array - [nil, "", " "]
111
+ fonts_resource_dir_array = fonts_resource_dir_array - [nil, "", " "]
112
+ # 过滤重复的 resource_dir
113
+ assets_resource_dir_array = assets_resource_dir_array.uniq
114
+ fonts_resource_dir_array = fonts_resource_dir_array.uniq
115
+
116
+
117
+ # 筛选合法的和非法的resource_dir
118
+ assets_legal_resource_dir_array = []
119
+ fonts_legal_resource_dir_array = []
120
+ illegal_resource_dir_array = []
121
+
122
+ assets_resource_dir_array.each do |resource_dir|
123
+ if File.exist?(resource_dir) == true
124
+ assets_legal_resource_dir_array.push(resource_dir)
125
+ else
126
+ illegal_resource_dir_array.push(resource_dir)
127
+ end
128
+ end
129
+
130
+ fonts_resource_dir_array.each do |resource_dir|
131
+ if File.exist?(resource_dir) == true
132
+ fonts_legal_resource_dir_array.push(resource_dir)
133
+ else
134
+ illegal_resource_dir_array.push(resource_dir)
135
+ end
136
+ end
137
+
138
+ legal_resource_dir_array = assets_legal_resource_dir_array + fonts_legal_resource_dir_array
139
+ if legal_resource_dir_array.length <= 0
140
+
141
+ if illegal_resource_dir_array.length > 0
142
+ message = "[!]: warning, found the following resource directory which is not existed: ".warning_style
143
+ illegal_resource_dir_array.each do |resource_dir|
144
+ message = message + "\n" + " - #{resource_dir}".warning_style
145
+ end
146
+ puts(message)
147
+ puts("")
148
+ end
149
+
150
+ message = <<-MESSAGE
151
+ #{"[x]: have no valid resource directories configuration in pubspec.yaml".error_style}
152
+ #{"[*]: please manually configure the resource directories to fix it, for example: ".tips_style}
153
+
154
+ #{"flr:".tips_style}
155
+ #{"core_version: #{core_version}".tips_style}
156
+ #{"dartfmt_line_length: #{dartfmt_line_length}".tips_style}
157
+ #{"# config the image and text resource directories that need to be scanned".tips_style}
158
+ #{"assets:".tips_style}
159
+ #{"- lib/assets/images".tips_style}
160
+ #{"- lib/assets/texts".tips_style}
161
+ #{"# config the font resource directories that need to be scanned".tips_style}
162
+ #{"fonts:".tips_style}
163
+ #{"- lib/assets/fonts".tips_style}
164
+ MESSAGE
165
+
166
+ raise(message)
167
+ end
168
+
169
+ resource_dir_result_tuple = [assets_legal_resource_dir_array, fonts_legal_resource_dir_array, illegal_resource_dir_array]
170
+ return resource_dir_result_tuple
171
+ end
172
+ end
173
+ end
174
+
175
+
@@ -0,0 +1,741 @@
1
+ require 'yaml'
2
+ require 'find'
3
+ require 'listen'
4
+ require 'flr/version'
5
+ require 'flr/string_extensions'
6
+ require 'flr/checker'
7
+ require 'flr/util/file_util'
8
+ require 'flr/util/asset_util'
9
+ require 'flr/util/code_util'
10
+
11
+ # 专有名词简单解释和示例:
12
+ # (详细定义请看 flr-core 项目的文档描述)
13
+ #
14
+ # package_name:flutter工程的package产物的名称,例如“flutter_demo”
15
+ # resource_file:flutter工程的资源文件,例如“lib/assets/images/hot_foot_N.png”、“lib/assets/images/3.0x/hot_foot_N.png”
16
+ # asset:flutter工程的package产物中资源,可当作是工程中的资源文件的映射和声明,例如上述2个资源对于的asset都是“packages/flutter_demo/assets/images/hot_foot_N.png”
17
+ # file_basename:资源的文件名,其定义是“#{file_basename_no_extension}#{file_extname}”,例如“hot_foot_N.png”
18
+ # file_basename_no_extension:资源的不带扩展名的文件名,例如“hot_foot_N”
19
+ # file_extname:资源的扩展名,例如“.png”
20
+ #
21
+ # asset_name:main asset的名称,例如“assets/images/hot_foot_N.png”
22
+ # asset_id:资源ID,其值一般为 file_basename_no_extension
23
+
24
+ module Flr
25
+ class Command
26
+
27
+ # Listen Class Instance
28
+ @@listener = nil
29
+
30
+ # show the version of flr
31
+ def self.version
32
+ version_desc = "Flr version #{Flr::VERSION}\nCoreLogic version #{Flr::CORE_VERSION}"
33
+ puts(version_desc)
34
+ end
35
+
36
+ # get the right version of r_dart_library package based on flutter's version
37
+ # to get more detail, see https://github.com/YK-Unit/r_dart_library#dependency-relationship-table
38
+ def self.get_r_dart_library_version
39
+ r_dart_library_version = "0.1.1"
40
+
41
+ # $ flutter --version
42
+ # Flutter 1.12.13+hotfix.5 • channel stable • https://github.com/flutter/flutter.git
43
+ # Framework • revision 27321ebbad (5 weeks ago) • 2019-12-10 18:15:01 -0800
44
+ # Engine • revision 2994f7e1e6
45
+ # Tools • Dart 2.7.0
46
+ flutter_version_result = `flutter --version`
47
+ if (flutter_version_result.nil? == true || flutter_version_result.empty? == true)
48
+ return r_dart_library_version
49
+ end
50
+
51
+ version_with_hotfix_str = flutter_version_result.split(" ")[1]
52
+ version_without_hotfix_str = version_with_hotfix_str.split("+")[0]
53
+
54
+ if Version.new(version_with_hotfix_str) >= Version.new("1.10.15")
55
+ r_dart_library_version = "0.2.1"
56
+ end
57
+
58
+ return r_dart_library_version
59
+ end
60
+
61
+ # 对 flutter 工程进行初始化
62
+ def self.init
63
+ flutter_project_root_dir = FileUtil.get_cur_flutter_project_root_dir
64
+
65
+ # ----- Step-1 Begin -----
66
+ # 进行环境检测:
67
+ # - 检测当前 flutter 工程根目录是否存在 pubspec.yaml
68
+ #
69
+
70
+ begin
71
+ Checker.check_pubspec_file_is_existed(flutter_project_root_dir)
72
+
73
+ pubspec_file_path = FileUtil.get_pubspec_file_path
74
+
75
+ pubspec_config = FileUtil.load_pubspec_config_from_file(pubspec_file_path)
76
+
77
+ rescue Exception => e
78
+ puts(e.message)
79
+ return
80
+ end
81
+
82
+ # ----- Step-1 End -----
83
+
84
+ puts("init #{flutter_project_root_dir} now...")
85
+
86
+ # ----- Step-2 Begin -----
87
+ # 添加 flr_config 和 r_dart_library 的依赖声明到 pubspec.yaml
88
+ #
89
+
90
+ dependencies_config = pubspec_config["dependencies"]
91
+
92
+ # 添加 flr_config 到 pubspec.yaml
93
+ #
94
+ # flr_config: Flr的配置信息
95
+ # ```yaml
96
+ # flr:
97
+ # core_version: 1.0.0
98
+ # dartfmt_line_length: 80
99
+ # assets: []
100
+ # fonts: []
101
+ # ```
102
+ flr_config = Hash["core_version" => "#{Flr::CORE_VERSION}", "dartfmt_line_length" => Flr::DARTFMT_LINE_LENGTH, "assets" => [], "fonts" => []]
103
+ pubspec_config["flr"] = flr_config
104
+
105
+ # 添加 r_dart_library(https://github.com/YK-Unit/r_dart_library)的依赖声明
106
+ # - 获取正确的库版本
107
+ # - 添加依赖声明
108
+ #
109
+ # r_dart_library的依赖声明:
110
+ # ```yaml
111
+ # r_dart_library:
112
+ # git:
113
+ # url: "https://github.com/YK-Unit/r_dart_library.git"
114
+ # ref: 0.1.1
115
+ # ```
116
+ r_dart_library_version = get_r_dart_library_version
117
+ r_dart_library_config = Hash["git" => Hash["url" => "https://github.com/YK-Unit/r_dart_library.git", "ref" => r_dart_library_version]]
118
+ dependencies_config["r_dart_library"] = r_dart_library_config
119
+ pubspec_config["dependencies"] = dependencies_config
120
+
121
+ puts("add flr configuration into pubspec.yaml done!")
122
+ puts("add dependency \"r_dart_library\"(https://github.com/YK-Unit/r_dart_library) into pubspec.yaml done!")
123
+
124
+ # ----- Step-2 End -----
125
+
126
+ # ----- Step-3 Begin -----
127
+ # 对Flutter配置进行修正,以避免执行获取依赖操作时会失败:
128
+ # - 检测Flutter配置中的assets选项是否是一个非空数组;若不是,则删除assets选项;
129
+ # - 检测Flutter配置中的fonts选项是否是一个非空数组;若不是,则删除fonts选项。
130
+ #
131
+
132
+ flutter_config = pubspec_config["flutter"]
133
+
134
+ flutter_assets = flutter_config["assets"]
135
+ should_rm_flutter_assets_Key = true
136
+ if flutter_assets.is_a?(Array) == true and flutter_assets.empty? == false
137
+ should_rm_flutter_assets_Key = false
138
+ end
139
+ if should_rm_flutter_assets_Key
140
+ flutter_config.delete("assets")
141
+ end
142
+
143
+ flutter_fonts = flutter_config["fonts"]
144
+ should_rm_flutter_fonts_Key = true
145
+ if flutter_fonts.is_a?(Array) == true and flutter_fonts.empty? == false
146
+ should_rm_flutter_fonts_Key = false
147
+ end
148
+ if should_rm_flutter_fonts_Key
149
+ flutter_config.delete("fonts")
150
+ end
151
+
152
+ pubspec_config["flutter"] = flutter_config
153
+
154
+ # ----- Step-3 End -----
155
+
156
+ # 保存 pubspec.yaml
157
+ FileUtil.dump_pubspec_config_to_file(pubspec_config, pubspec_file_path)
158
+
159
+ puts("get dependency \"r_dart_library\" via execute \"flutter pub get\" now ...")
160
+
161
+ # ----- Step-4 Begin -----
162
+ # 调用 flutter 工具,为 flutter 工程获取依赖
163
+
164
+ get_flutter_pub_cmd = "flutter pub get"
165
+ system(get_flutter_pub_cmd)
166
+
167
+ puts("get dependency \"r_dart_library\" done !!!")
168
+
169
+ # ----- Step-4 End -----
170
+
171
+ puts("[√]: init done !!!")
172
+ end
173
+
174
+ # 扫描资源目录,自动为资源添加声明到 pubspec.yaml 和生成 r.g.dart
175
+ def self.generate
176
+
177
+ flutter_project_root_dir = FileUtil.get_cur_flutter_project_root_dir
178
+
179
+ # 警告日志数组
180
+ warning_messages = []
181
+
182
+ # ----- Step-1 Begin -----
183
+ # 进行环境检测;若发现不合法的环境,则抛出异常,终止当前进程:
184
+ # - 检测当前flutter工程根目录是否存在pubspec.yaml
185
+ # - 检测当前pubspec.yaml中是否存在Flr的配置
186
+ # - 检测当前flr_config中的resource_dir配置是否合法:
187
+ # 判断合法的标准是:assets配置或者fonts配置了至少1个legal_resource_dir
188
+ #
189
+
190
+ begin
191
+ Checker.check_pubspec_file_is_existed(flutter_project_root_dir)
192
+
193
+ pubspec_file_path = FileUtil.get_pubspec_file_path
194
+
195
+ pubspec_config = FileUtil.load_pubspec_config_from_file(pubspec_file_path)
196
+
197
+ Checker.check_flr_config_is_existed(pubspec_config)
198
+
199
+ flr_config = pubspec_config["flr"]
200
+
201
+ resource_dir_result_tuple = Checker.check_flr_assets_is_legal(flr_config)
202
+
203
+ rescue Exception => e
204
+ puts(e.message)
205
+ return
206
+ end
207
+
208
+ package_name = pubspec_config["name"]
209
+
210
+ # ----- Step-1 End -----
211
+
212
+ # ----- Step-2 Begin -----
213
+ # 进行核心逻辑版本检测:
214
+ # 检测Flr配置中的核心逻辑版本号和当前工具的核心逻辑版本号是否一致;若不一致,则生成“核心逻辑版本不一致”的警告日志,存放到警告日志数组
215
+
216
+ flr_core_version = flr_config["core_version"]
217
+
218
+ if flr_core_version.nil?
219
+ flr_core_version = "unknown"
220
+ end
221
+
222
+ if flr_core_version != Flr::CORE_VERSION
223
+ message = <<-MESSAGE
224
+ #{"[!]: warning, the core logic version of the configured Flr tool is #{flr_core_version}, while the core logic version of the currently used Flr tool is #{Flr::CORE_VERSION}".warning_style}
225
+ #{"[*]: to fix it, you should make sure that the core logic version of the Flr tool you are currently using is consistent with the configuration".tips_style}
226
+ MESSAGE
227
+
228
+ warning_messages.push(message)
229
+ end
230
+
231
+ # ----- Step-2 End -----
232
+
233
+ # ----- Step-3 Begin -----
234
+ # 获取assets_legal_resource_dir数组、fonts_legal_resource_dir数组和illegal_resource_dir数组:
235
+ # - 从flr_config中的assets配置获取assets_legal_resource_dir数组和assets_illegal_resource_dir数组;
236
+ # - 从flr_config中的fonts配置获取fonts_legal_resource_dir数组和fonts_illegal_resource_dir数组;
237
+ # - 合并assets_illegal_resource_dir数组和fonts_illegal_resource_dir数组为illegal_resource_dir数组‘;若illegal_resource_dir数组长度大于0,则生成“存在非法的资源目录”的警告日志,存放到警告日志数组。
238
+
239
+ # 合法的资源目录数组
240
+ assets_legal_resource_dir_array = resource_dir_result_tuple[0]
241
+ fonts_legal_resource_dir_array = resource_dir_result_tuple[1]
242
+ # 非法的资源目录数组
243
+ illegal_resource_dir_array = resource_dir_result_tuple[2]
244
+
245
+ if illegal_resource_dir_array.length > 0
246
+ message = "[!]: warning, found the following resource directory which is not existed: ".warning_style
247
+ illegal_resource_dir_array.each do |resource_dir|
248
+ message = message + "\n" + " - #{resource_dir}".warning_style
249
+ end
250
+
251
+ warning_messages.push(message)
252
+ end
253
+
254
+ # ----- Step-3 End -----
255
+
256
+ # 扫描资源
257
+ puts("scan assets now ...")
258
+
259
+ # ----- Step-4 Begin -----
260
+ # 扫描assets_legal_resource_dir数组中的legal_resource_dir,输出image_asset数组和illegal_image_file数组:
261
+ # - 创建image_asset数组、illegal_image_file数组;
262
+ # - 遍历assets_legal_resource_dir数组,按照如下处理每个资源目录:
263
+ # - 扫描当前资源目录和其第1级的子目录,查找所有image_file;
264
+ # - 根据legal_resource_file的标准,筛选查找结果生成legal_image_file子数组和illegal_image_file子数组;illegal_image_file子数组合并到illegal_image_file数组;
265
+ # - 根据image_asset的定义,遍历legal_image_file子数组,生成image_asset子数;组;image_asset子数组合并到image_asset数组。
266
+ # - 对image_asset数组做去重处理;
267
+ # - 按照字典顺序对image_asset数组做升序排列(一般使用开发语言提供的默认的sort算法即可);
268
+ # - 输出image_asset数组和illegal_image_file数组。
269
+ #
270
+
271
+ image_asset_array = []
272
+ illegal_image_file_array = []
273
+
274
+ assets_legal_resource_dir_array.each do |resource_dir|
275
+ image_file_result_tuple = FileUtil.find_image_files(resource_dir)
276
+ legal_image_file_subarray = image_file_result_tuple[0]
277
+ illegal_image_file_subarray = image_file_result_tuple[1]
278
+
279
+ illegal_image_file_array += illegal_image_file_subarray
280
+
281
+ image_asset_subarray = AssetUtil.generate_image_assets(legal_image_file_subarray, resource_dir, package_name)
282
+ image_asset_array += image_asset_subarray
283
+ end
284
+
285
+ image_asset_array.uniq!
286
+ image_asset_array.sort!
287
+
288
+ # ----- Step-4 End -----
289
+
290
+ # ----- Step-5 Begin -----
291
+ # 扫描assets_legal_resource_dir数组中的legal_resource_dir,输出text_asset数组和illegal_text_file数组:
292
+ # - 创建text_asset数组、illegal_text_file数组;
293
+ # - 遍历assets_legal_resource_dir数组,按照如下处理每个资源目录:
294
+ # - 扫描当前资源目录和其所有层级的子目录,查找所有text_file;
295
+ # - 根据legal_resource_file的标准,筛选查找结果生成legal_text_file子数组和illegal_text_file子数组;illegal_text_file子数组合并到illegal_text_file数组;
296
+ # - 根据text_asset的定义,遍历legal_text_file子数组,生成text_asset子数组;text_asset子数组合并到text_asset数组。
297
+ # - 对text_asset数组做去重处理;
298
+ # - 按照字典顺序对text_asset数组做升序排列(一般使用开发语言提供的默认的sort算法即可);
299
+ # - 输出text_asset数组和illegal_image_file数组。
300
+ #
301
+
302
+ text_asset_array = []
303
+ illegal_text_file_array = []
304
+
305
+ assets_legal_resource_dir_array.each do |resource_dir|
306
+ text_file_result_tuple = FileUtil.find_text_files(resource_dir)
307
+ legal_text_file_subarray = text_file_result_tuple[0]
308
+ illegal_text_file_subarray = text_file_result_tuple[1]
309
+
310
+ illegal_text_file_array += illegal_text_file_subarray
311
+
312
+ text_asset_subarray = AssetUtil.generate_text_assets(legal_text_file_subarray, resource_dir, package_name)
313
+ text_asset_array += text_asset_subarray
314
+ end
315
+
316
+ text_asset_array.uniq!
317
+ text_asset_array.sort!
318
+
319
+ # ----- Step-5 End -----
320
+
321
+ # ----- Step-6 Begin -----
322
+ # 扫描fonts_legal_resource_dir数组中的legal_resource_dir,输出font_family_config数组、illegal_font_file数组:
323
+ # - 创建font_family_config数组、illegal_font_file数组;
324
+ # - 遍历fonts_legal_resource_dir数组,按照如下处理每个资源目录:
325
+ # - 扫描当前资源目录,获得其第1级子目录数组,并按照字典顺序对数组做升序排列(一般使用开发语言提供的默认的sort算法即可);
326
+ # - 遍历第1级子目录数组,按照如下处理每个子目录:
327
+ # - 获取当前子目录的名称,生成font_family_name;
328
+ # - 扫描当前子目录和其所有子目录,查找所有font_file;
329
+ # - 根据legal_resource_file的标准,筛选查找结果生成legal_font_file数组和illegal_font_file子数组;illegal_font_file子数组合并到illegal_font_file数组;
330
+ # - 据font_asset的定义,遍历legal_font_file数组,生成font_asset_config数组;
331
+ # - 按照字典顺序对生成font_asset_config数组做升序排列(比较asset的值);
332
+ # - 根据font_family_config的定义,为当前子目录组织font_family_name和font_asset_config数组生成font_family_config对象,添加到font_family_config子数组;font_family_config子数组合并到font_family_config数组。
333
+ # - 输出font_family_config数组、illegal_font_file数组;
334
+ # - 按照字典顺序对font_family_config数组做升序排列(比较family的值)。
335
+ #
336
+
337
+ font_family_config_array = []
338
+ illegal_font_file_array = []
339
+
340
+ fonts_legal_resource_dir_array.each do |resource_dir|
341
+ font_family_dir_array = FileUtil.find_top_child_dirs(resource_dir)
342
+
343
+ font_family_dir_array.each do |font_family_dir|
344
+ font_family_name = File.basename(font_family_dir)
345
+
346
+ font_file_result_tuple = FileUtil.find_font_files_in_font_family_dir(font_family_dir)
347
+ legal_font_file_array = font_file_result_tuple[0]
348
+ illegal_font_file_subarray = font_file_result_tuple[1]
349
+
350
+ illegal_font_file_array += illegal_font_file_subarray
351
+
352
+ unless legal_font_file_array.length > 0
353
+ next
354
+ end
355
+
356
+ font_asset_config_array = AssetUtil.generate_font_asset_configs(legal_font_file_array, font_family_dir, package_name)
357
+ font_asset_config_array.sort!{|a, b| a["asset"] <=> b["asset"]}
358
+
359
+ font_family_config = Hash["family" => font_family_name , "fonts" => font_asset_config_array]
360
+ font_family_config_array.push(font_family_config)
361
+ end
362
+ end
363
+
364
+ font_family_config_array.sort!{|a, b| a["family"] <=> b["family"]}
365
+
366
+ # ----- Step-6 End -----
367
+
368
+ puts("scan assets done !!!")
369
+
370
+ # ----- Step-7 Begin -----
371
+ # 检测是否存在illegal_resource_file:
372
+ # - 合并illegal_image_file数组、illegal_text_file数组和illegal_font_file数组为illegal_resource_file数组;
373
+ # - 若illegal_resource_file数组长度大于0,则生成“存在非法的资源文件”的警告日志,存放到警告日志数组。
374
+
375
+ illegal_resource_file_array = illegal_image_file_array + illegal_text_file_array + illegal_font_file_array
376
+ if illegal_resource_file_array.length > 0
377
+ message = "[!]: warning, found the following illegal resource file who's file basename contains illegal characters: ".warning_style
378
+ illegal_resource_file_array.each do |resource_file|
379
+ message = message + "\n" + " - #{resource_file}".warning_style
380
+ end
381
+ message = message + "\n" + "[*]: to fix it, you should only use letters (a-z, A-Z), numbers (0-9), and the other legal characters ('_', '+', '-', '.', '·', '!', '@', '&', '$', '¥') to name the file".tips_style
382
+
383
+ warning_messages.push(message)
384
+ end
385
+
386
+ # ----- Step-7 End -----
387
+
388
+ puts("specify scanned assets in pubspec.yaml now ...")
389
+
390
+ # ----- Step-8 Begin -----
391
+ # 为扫描得到的legal_resource_file添加资源声明到pubspec.yaml:
392
+ # - 合并image_asset数组和text_asset数组为asset数组(image_asset数组元素在前);
393
+ # - 修改pubspec.yaml中flutter-assets配置的值为asset数组;
394
+ # - 修改pubspec.yaml中flutter-fonts配置的值为font_family_config数组。
395
+
396
+ asset_array = image_asset_array + text_asset_array
397
+ if asset_array.length > 0
398
+ pubspec_config["flutter"]["assets"] = asset_array
399
+ else
400
+ pubspec_config["flutter"].delete("assets")
401
+ end
402
+
403
+ if font_family_config_array.length > 0
404
+ pubspec_config["flutter"]["fonts"] = font_family_config_array
405
+ else
406
+ pubspec_config["flutter"].delete("fonts")
407
+ end
408
+
409
+ FileUtil.dump_pubspec_config_to_file(pubspec_config, pubspec_file_path)
410
+
411
+ # ----- Step-8 End -----
412
+
413
+ puts("specify scanned assets in pubspec.yaml done !!!")
414
+
415
+ # ----- Step-9 Begin -----
416
+ # 按照SVG分类,从image_asset数组筛选得到有序的non_svg_image_asset数组和svg_image_asset数组:
417
+ # - 按照SVG分类,从image_asset数组筛选得到non_svg_image_asset数组和svg_image_asset数组;
418
+ # - 按照字典顺序对non_svg_image_asset数组和svg_image_asset数组做升序排列(一般使用开发语言提供的默认的sort算法即可);
419
+ #
420
+
421
+ non_svg_image_asset_array = []
422
+ svg_image_asset_array = []
423
+
424
+ image_asset_array.each do |image_asset|
425
+ file_extname = File.extname(image_asset).downcase
426
+
427
+ if file_extname.eql?(".svg")
428
+ svg_image_asset_array.push(image_asset)
429
+ else
430
+ non_svg_image_asset_array.push(image_asset)
431
+ end
432
+ end
433
+
434
+ non_svg_image_asset_array.sort!
435
+ svg_image_asset_array.sort!
436
+
437
+ # ----- Step-9 End -----
438
+
439
+ puts("generate \"r.g.dart\" now ...")
440
+
441
+ # ----- Step-10 Begin -----
442
+ # 在当前根目录下创建新的r.g.dart文件。
443
+ #
444
+
445
+ r_dart_path = "#{flutter_project_root_dir}/lib/r.g.dart"
446
+ r_dart_file = File.open(r_dart_path, "w")
447
+
448
+ # ----- Step-10 End -----
449
+
450
+ # ----- Step-11 Begin -----
451
+ # 生成 R 类的代码,追加写入r.g.dart
452
+ #
453
+
454
+ g_R_class_code = CodeUtil.generate_R_class(package_name)
455
+ r_dart_file.puts(g_R_class_code)
456
+
457
+ # ----- Step-11 End -----
458
+
459
+ # ----- Step-12 Begin -----
460
+ # 生成 AssetResource 类的代码,追加写入r.g.dart
461
+ #
462
+
463
+ r_dart_file.puts("\n")
464
+ g_AssetResource_class_code = CodeUtil.generate_AssetResource_class(package_name)
465
+ r_dart_file.puts(g_AssetResource_class_code)
466
+
467
+ # ----- Step-12 End -----
468
+
469
+ # ----- Step-13 Begin -----
470
+ # 遍历 non_svg_image_asset 数组,生成 _R_Image_AssetResource 类,追加写入 r.g.dart
471
+ #
472
+
473
+ r_dart_file.puts("\n")
474
+ g__R_Image_AssetResource_class_code = CodeUtil.generate__R_Image_AssetResource_class(non_svg_image_asset_array, package_name)
475
+ r_dart_file.puts(g__R_Image_AssetResource_class_code)
476
+
477
+ # ----- Step-13 End -----
478
+
479
+ # ----- Step-14 Begin -----
480
+ # 遍历 svg_image_asset 数组,生成 _R_Svg_AssetResource 类,追加写入 r.g.dart。
481
+ #
482
+
483
+ r_dart_file.puts("\n")
484
+ g__R_Svg_AssetResource_class_code = CodeUtil.generate__R_Svg_AssetResource_class(svg_image_asset_array, package_name)
485
+ r_dart_file.puts(g__R_Svg_AssetResource_class_code)
486
+
487
+ # ----- Step-14 End -----
488
+
489
+ # ----- Step-15 Begin -----
490
+ # 遍历 text_asset 数组,生成 _R_Image_AssetResource 类,追加写入 r.g.dart
491
+ #
492
+
493
+ r_dart_file.puts("\n")
494
+ g__R_Text_AssetResource_class_code = CodeUtil.generate__R_Text_AssetResource_class(text_asset_array, package_name)
495
+ r_dart_file.puts(g__R_Text_AssetResource_class_code)
496
+
497
+ # ----- Step-15 End -----
498
+
499
+
500
+ # ----- Step-16 Begin -----
501
+ # 遍历non_svg_image_asset数组,生成 _R_Image 类,追加写入 r.g.dart
502
+ #
503
+
504
+ r_dart_file.puts("\n")
505
+ g__R_Image_class_code = CodeUtil.generate__R_Image_class(non_svg_image_asset_array, package_name)
506
+ r_dart_file.puts(g__R_Image_class_code)
507
+
508
+ # ----- Step-16 End -----
509
+
510
+ # ----- Step-17 Begin -----
511
+ # 遍历 svg_image_asset 数组,生成 _R_Svg 类,追加写入 r.g.dart。
512
+ #
513
+
514
+ r_dart_file.puts("\n")
515
+ g__R_Svg_class_code = CodeUtil.generate__R_Svg_class(svg_image_asset_array, package_name)
516
+ r_dart_file.puts(g__R_Svg_class_code)
517
+
518
+ # ----- Step-17 End -----
519
+
520
+ # ----- Step-18 Begin -----
521
+ # 遍历 text_asset 数组,生成 _R_Image 类,追加写入 r.g.dart。
522
+ #
523
+
524
+ r_dart_file.puts("\n")
525
+ g__R_Text_class_code = CodeUtil.generate__R_Text_class(text_asset_array, package_name)
526
+ r_dart_file.puts(g__R_Text_class_code)
527
+
528
+ # ----- Step-18 End -----
529
+
530
+ # ----- Step-19 Begin -----
531
+ # 遍历font_family_config数组,根据下面的模板生成_R_Font_Family类,追加写入r.g.dart。
532
+
533
+ r_dart_file.puts("\n")
534
+ g__R_Font_Family_class_code = CodeUtil.generate__R_FontFamily_class(font_family_config_array, package_name)
535
+ r_dart_file.puts(g__R_Font_Family_class_code)
536
+
537
+ # ----- Step-19 End -----
538
+
539
+ # ----- Step-20 Begin -----
540
+ # 结束操作,保存 r.g.dart
541
+ #
542
+
543
+ r_dart_file.close
544
+ puts("generate \"r.g.dart\" done !!!")
545
+
546
+ # ----- Step-20 End -----
547
+
548
+ # ----- Step-21 Begin -----
549
+ # 调用 flutter 工具对 r.g.dart 进行格式化操作
550
+ #
551
+
552
+ dartfmt_line_length = flr_config["dartfmt_line_length"]
553
+ if dartfmt_line_length.nil? or dartfmt_line_length.is_a?(Integer) == false
554
+ dartfmt_line_length = Flr::DARTFMT_LINE_LENGTH
555
+ end
556
+
557
+ if dartfmt_line_length < Flr::DARTFMT_LINE_LENGTH
558
+ dartfmt_line_length = Flr::DARTFMT_LINE_LENGTH
559
+ end
560
+
561
+ flutter_format_cmd = "flutter format #{r_dart_path} -l #{dartfmt_line_length}"
562
+ puts("execute \"#{flutter_format_cmd}\" now ...")
563
+ system(flutter_format_cmd)
564
+ puts("execute \"#{flutter_format_cmd}\" done !!!")
565
+
566
+ # ----- Step-21 End -----
567
+
568
+ # ----- Step-22 Begin -----
569
+ # 调用flutter工具,为flutter工程获取依赖
570
+ #
571
+
572
+ get_flutter_pub_cmd = "flutter pub get"
573
+ puts("execute \"#{get_flutter_pub_cmd}\" now ...")
574
+ system(get_flutter_pub_cmd)
575
+ puts("execute \"#{get_flutter_pub_cmd}\" done !!!")
576
+
577
+ # ----- Step-22 End -----
578
+
579
+ puts("[√]: generate done !!!")
580
+
581
+ # ----- Step-23 Begin -----
582
+ # 判断警告日志数组是否为空,若不为空,输出所有警告日志
583
+ #
584
+
585
+ if warning_messages.length > 0
586
+ warning_messages.each do |warning_message|
587
+ puts("")
588
+ puts(warning_message)
589
+ end
590
+ end
591
+
592
+ # ----- Step-23 End -----
593
+
594
+ end
595
+
596
+ # 启动一个资源变化监控服务,若检测到有资源变化,就自动执行generate操作;手动输入`Ctrl-C`,可终止当前服务
597
+ def self.start_monitor
598
+
599
+ flutter_project_root_dir = FileUtil.get_cur_flutter_project_root_dir
600
+
601
+ # ----- Step-1 Begin -----
602
+ # 进行环境检测;若发现不合法的环境,则抛出异常,终止当前进程:
603
+ # - 检测当前flutter工程根目录是否存在pubspec.yaml
604
+ # - 检测当前pubspec.yaml中是否存在Flr的配置
605
+ # - 检测当前flr_config中的resource_dir配置是否合法:
606
+ # 判断合法的标准是:assets配置或者fonts配置了至少1个legal_resource_dir
607
+ #
608
+
609
+ begin
610
+ Checker.check_pubspec_file_is_existed(flutter_project_root_dir)
611
+
612
+ pubspec_file_path = FileUtil.get_pubspec_file_path
613
+
614
+ pubspec_config = FileUtil.load_pubspec_config_from_file(pubspec_file_path)
615
+
616
+ Checker.check_flr_config_is_existed(pubspec_config)
617
+
618
+ flr_config = pubspec_config["flr"]
619
+
620
+ resource_dir_result_tuple = Checker.check_flr_assets_is_legal(flr_config)
621
+
622
+ rescue Exception => e
623
+ puts(e.message)
624
+ return
625
+ end
626
+
627
+ package_name = pubspec_config["name"]
628
+
629
+ # ----- Step-1 End -----
630
+
631
+ # ----- Step-2 Begin -----
632
+ # 执行一次 flr generate 操作
633
+ #
634
+
635
+ now_str = Time.now.to_s
636
+ puts("--------------------------- #{now_str} ---------------------------")
637
+ puts("scan assets, specify scanned assets in pubspec.yaml, generate \"r.g.dart\" now ...")
638
+ puts("\n")
639
+ generate
640
+ puts("\n")
641
+ puts("scan assets, specify scanned assets in pubspec.yaml, generate \"r.g.dart\" done !!!")
642
+ puts("---------------------------------------------------------------------------------")
643
+ puts("\n")
644
+
645
+ # ----- Step-2 End -----
646
+
647
+ # ----- Step-3 Begin -----
648
+ # 获取legal_resource_dir数组:
649
+ # - 从flr_config中的assets配置获取assets_legal_resource_dir数组;
650
+ # - 从flr_config中的fonts配置获取fonts_legal_resource_dir数组;
651
+ # - 合并assets_legal_resource_dir数组和fonts_legal_resource_dir数组为legal_resource_dir数组。
652
+ #
653
+
654
+ # 合法的资源目录数组
655
+ assets_legal_resource_dir_array = resource_dir_result_tuple[0]
656
+ fonts_legal_resource_dir_array = resource_dir_result_tuple[1]
657
+
658
+ legal_resource_dir_array = assets_legal_resource_dir_array + fonts_legal_resource_dir_array
659
+
660
+ # 非法的资源目录数组
661
+ illegal_resource_dir_array = resource_dir_result_tuple[2]
662
+
663
+ # ----- Step-3 End -----
664
+
665
+ # ----- Step-4 Begin -----
666
+ # 启动资源监控服务
667
+ # - 启动一个文件监控服务,对 legal_resource_dir 数组中的资源目录进行文件监控
668
+ # - 若服务检测到资源变化(资源目录下的发生增/删/改文件),则执行一次 flr generate 操作
669
+ #
670
+
671
+ now_str = Time.now.to_s
672
+ puts("--------------------------- #{now_str} ---------------------------")
673
+ puts("launch a monitoring service now ...")
674
+ puts("launching ...")
675
+ # stop the monitoring service if exists
676
+ stop_monitor
677
+ puts("launch a monitoring service done !!!")
678
+ puts("the monitoring service is monitoring the following resource directory:")
679
+ legal_resource_dir_array.each do |resource_dir|
680
+ puts(" - #{resource_dir}")
681
+ end
682
+ if illegal_resource_dir_array.length > 0
683
+ puts("")
684
+ puts("[!]: warning, found the following resource directory which is not existed: ".warning_style)
685
+ illegal_resource_dir_array.each do |resource_dir|
686
+ puts(" - #{resource_dir}".warning_style)
687
+ end
688
+ end
689
+ puts("---------------------------------------------------------------------------------")
690
+ puts("\n")
691
+
692
+ # Allow array of directories as input #92
693
+ # https://github.com/guard/listen/pull/92
694
+ @@listener = Listen.to(*legal_resource_dir_array, ignore: [/\.DS_Store/], latency: 0.5, wait_for_delay: 5, relative: true) do |modified, added, removed|
695
+ # for example: 2013-03-30 03:13:14 +0900
696
+ now_str = Time.now.to_s
697
+ puts("--------------------------- #{now_str} ---------------------------")
698
+ puts("modified resource files: #{modified}")
699
+ puts("added resource files: #{added}")
700
+ puts("removed resource files: #{removed}")
701
+ puts("scan assets, specify scanned assets in pubspec.yaml, generate \"r.g.dart\" now ...")
702
+ puts("\n")
703
+ generate
704
+ puts("\n")
705
+ puts("scan assets, specify scanned assets in pubspec.yaml, generate \"r.g.dart\" done !!!")
706
+ puts("---------------------------------------------------------------------------------")
707
+ puts("\n")
708
+ puts("[*]: the monitoring service is monitoring the asset changes, and then auto scan assets, specifies assets and generates \"r.g.dart\" ...".tips_style)
709
+ puts("[*]: you can press \"Ctrl-C\" to terminate it".tips_style)
710
+ puts("\n")
711
+ end
712
+ # not blocking
713
+ @@listener.start
714
+
715
+ # https://ruby-doc.org/core-2.5.0/Interrupt.html
716
+ begin
717
+ puts("[*]: the monitoring service is monitoring the asset changes, and then auto scan assets, specifies assets and generates \"r.g.dart\" ...".tips_style)
718
+ puts("[*]: you can press \"Ctrl-C\" to terminate it".tips_style)
719
+ puts("\n")
720
+ loop {}
721
+ rescue Interrupt => e
722
+ stop_monitor
723
+ puts("")
724
+ puts("[√]: terminate monitor service done !!!")
725
+ end
726
+
727
+ # ----- Step-4 End -----
728
+
729
+ end
730
+
731
+ # 停止资源变化监控服务
732
+ def self.stop_monitor
733
+ if @@listener.nil? == false
734
+ @@listener.stop
735
+ @@listener = nil
736
+ end
737
+ end
738
+
739
+ end
740
+
741
+ end