lhj-tools 0.1.3 → 0.1.7

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.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/lib/lhj/action/sh_helper.rb +138 -0
  3. data/lib/lhj/command/config/info.rb +47 -0
  4. data/lib/lhj/command/config.rb +11 -0
  5. data/lib/lhj/command/file_path.rb +20 -0
  6. data/lib/lhj/command/head_import.rb +19 -3
  7. data/lib/lhj/command/http.rb +14 -0
  8. data/lib/lhj/command/init.rb +2 -2
  9. data/lib/lhj/command/local/fetch.rb +1 -1
  10. data/lib/lhj/command/local/filter.rb +1 -1
  11. data/lib/lhj/command/local/local.rb +1 -1
  12. data/lib/lhj/command/local/local_upload.rb +1 -1
  13. data/lib/lhj/command/local/micro_service.rb +1 -1
  14. data/lib/lhj/command/oss/del.rb +18 -5
  15. data/lib/lhj/command/oss/list.rb +6 -2
  16. data/lib/lhj/command/oss/upload.rb +9 -5
  17. data/lib/lhj/command/refactor_rename.rb +18 -2
  18. data/lib/lhj/command/rename_image.rb +48 -8
  19. data/lib/lhj/command/sync_pod_repo.rb +138 -0
  20. data/lib/lhj/command/trans.rb +1 -1
  21. data/lib/lhj/command/yapi.rb +15 -14
  22. data/lib/lhj/command.rb +33 -0
  23. data/lib/lhj/tools/version.rb +1 -1
  24. data/lib/lhj/tools.rb +1 -0
  25. data/lib/lhj/tree/directory_renderer.rb +45 -0
  26. data/lib/lhj/tree/hash_walker.rb +70 -0
  27. data/lib/lhj/tree/node.rb +90 -0
  28. data/lib/lhj/tree/number_renderer.rb +30 -0
  29. data/lib/lhj/tree/path_walker.rb +107 -0
  30. data/lib/lhj/tree/tree.rb +112 -0
  31. data/lib/lhj/ui/errors/lhj_common_error.rb +19 -0
  32. data/lib/lhj/ui/errors/lhj_crash.rb +11 -0
  33. data/lib/lhj/ui/errors/lhj_error.rb +25 -0
  34. data/lib/lhj/ui/errors/lhj_exception.rb +19 -0
  35. data/lib/lhj/ui/errors/lhj_shell_error.rb +11 -0
  36. data/lib/lhj/ui/errors.rb +1 -0
  37. data/lib/lhj/ui/implementations/shell.rb +148 -0
  38. data/lib/lhj/ui/interface.rb +205 -0
  39. data/lib/lhj/ui/ui.rb +26 -0
  40. metadata +77 -2
@@ -0,0 +1,112 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'node'
4
+ require_relative 'directory_renderer'
5
+ require_relative 'number_renderer'
6
+ require_relative 'hash_walker'
7
+ require_relative 'path_walker'
8
+
9
+ module Lhj
10
+ class Tree
11
+ # @api public
12
+ def self.[](data)
13
+ new(data)
14
+ end
15
+
16
+ # The list of nodes in this tree.
17
+ attr_reader :nodes
18
+
19
+ # Create a Tree
20
+ #
21
+ # @param [String,Dir,Hash] data
22
+ #
23
+ # @api public
24
+ def initialize(data = nil, options = {}, &block)
25
+ @data = data ? data.dup.freeze : nil
26
+ @walker = select_walker.new(options)
27
+ @nodes = []
28
+
29
+ if @data
30
+ @walker.traverse(data)
31
+ @nodes = @walker.nodes
32
+ end
33
+
34
+ @nodes_stack = []
35
+
36
+ instance_eval(&block) if block_given?
37
+
38
+ freeze
39
+ end
40
+
41
+ # Add node to this tree.
42
+ #
43
+ # @param [Symbol,String] name
44
+ # the name for the node
45
+ #
46
+ # @param [Node, LeafNode] type
47
+ # the type of node to add
48
+ #
49
+ # @example
50
+ # TTY::Tree.new do
51
+ # node '...' do
52
+ # node '...'
53
+ # end
54
+ # end
55
+ #
56
+ # @api public
57
+ def node(name, type = Node, &block)
58
+ parent = @nodes_stack.empty? ? Node::ROOT : @nodes_stack.last
59
+ level = [0, @nodes_stack.size - 1].max
60
+ prefix = ':pipe' * level
61
+ if parent.class == LeafNode
62
+ prefix = ':space' * level
63
+ end
64
+ node = type.new(name, parent.full_path, prefix, @nodes_stack.size)
65
+ @nodes << node
66
+
67
+ return unless block_given?
68
+
69
+ @nodes_stack << node
70
+ if block.arity.zero?
71
+ instance_eval(&block)
72
+ else
73
+ instance_eval(&(->(*_args) { block[node] }))
74
+ end
75
+ @nodes_stack.pop
76
+ end
77
+
78
+ # Add leaf node
79
+ #
80
+ # @api public
81
+ def leaf(name, &block)
82
+ node(name, LeafNode, &block)
83
+ end
84
+
85
+ # @api public
86
+ def render(options = {})
87
+ as = options.delete(:as) || :dir
88
+ renderer = select_renderer(as).new(nodes, options)
89
+ renderer.render
90
+ end
91
+
92
+ private
93
+
94
+ # @api private
95
+ def select_walker
96
+ if @data.is_a?(Hash) || @data.nil?
97
+ HashWalker
98
+ else
99
+ @data ||= Dir.pwd
100
+ PathWalker
101
+ end
102
+ end
103
+
104
+ def select_renderer(as)
105
+ case as
106
+ when :dir, :directory then DirectoryRenderer
107
+ when :num, :number then NumberRenderer
108
+ end
109
+ end
110
+ end
111
+ end
112
+
@@ -0,0 +1,19 @@
1
+ require_relative 'lhj_exception'
2
+
3
+ module Lhj
4
+ class Interface
5
+ # Super class for exception types that we do not want to record
6
+ # explicitly as crashes or user errors
7
+ class LhjCommonException < LhjException; end
8
+
9
+ # Raised when there is a build failure in xcodebuild
10
+ class LhjBuildFailure < LhjCommonException; end
11
+
12
+ # Raised when a test fails when being run by tools such as scan or snapshot
13
+ class LhjTestFailure < LhjCommonException; end
14
+
15
+ # Raise this type of exception when a failure caused by a third party
16
+ # dependency (i.e. xcodebuild, gradle, slather) happens.
17
+ class LhjDependencyCausedException < LhjCommonException; end
18
+ end
19
+ end
@@ -0,0 +1,11 @@
1
+ require_relative 'lhj_exception'
2
+
3
+ module Lhj
4
+ class Interface
5
+ class LhjCrash < LhjException
6
+ def prefix
7
+ '[LHJ_CRASH]'
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,25 @@
1
+ require_relative 'lhj_exception'
2
+
3
+ module Lhj
4
+ class Interface
5
+ class LhjError < LhjException
6
+ attr_reader :show_github_issues
7
+ attr_reader :error_info
8
+
9
+ def initialize(show_github_issues: false, error_info: nil)
10
+ @show_github_issues = show_github_issues
11
+ @error_info = error_info
12
+ end
13
+
14
+ def prefix
15
+ '[USER_ERROR]'
16
+ end
17
+ end
18
+ end
19
+ end
20
+
21
+ class Exception
22
+ # def fastlane_should_report_metrics?
23
+ # return false
24
+ # end
25
+ end
@@ -0,0 +1,19 @@
1
+ module Lhj
2
+ class Interface
3
+ class LhjException < StandardError
4
+ def prefix
5
+ '[LHJ_EXCEPTION]'
6
+ end
7
+
8
+ def caused_by_calling_ui_method?(method_name: nil)
9
+ return false if backtrace.nil? || backtrace[0].nil? || method_name.nil?
10
+ first_frame = backtrace[0]
11
+ if first_frame.include?(method_name) && first_frame.include?('interface.rb')
12
+ true
13
+ else
14
+ false
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,11 @@
1
+ require_relative 'lhj_exception'
2
+
3
+ module Lhj
4
+ class Interface
5
+ class LhjShellError < LhjException
6
+ def prefix
7
+ '[SHELL_ERROR]'
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1 @@
1
+ Dir[File.dirname(__FILE__) + "/errors/*.rb"].each { |f| require_relative f }
@@ -0,0 +1,148 @@
1
+ require_relative '../interface'
2
+
3
+ module Lhj
4
+ # Shell is the terminal output of things
5
+ # For documentation for each of the methods open `interface.rb`
6
+ class Shell < Interface
7
+
8
+ def log
9
+ return @log if @log
10
+
11
+ $stdout.sync = true
12
+
13
+ # if !ENV.key?('DEBUG')
14
+ # $stdout.puts("Logging disabled while running tests. Force them by setting the DEBUG environment variable")
15
+ # @log ||= Logger.new(nil) # don't show any logs when running tests
16
+ # else
17
+ @log ||= Logger.new($stdout)
18
+ # end
19
+
20
+ @log.formatter = proc do |severity, datetime, progname, msg|
21
+ "#{format_string(datetime, severity)}#{msg}\n"
22
+ end
23
+
24
+ @log
25
+ end
26
+
27
+ def format_string(datetime = Time.now, severity = "")
28
+ return "[#{datetime.strftime('%H:%M:%S')}]: "
29
+ end
30
+
31
+ #####################################################
32
+ # @!group Messaging: show text to the user
33
+ #####################################################
34
+
35
+ def error(message)
36
+ log.error(message.to_s.red)
37
+ end
38
+
39
+ def important(message)
40
+ log.warn(message.to_s.yellow)
41
+ end
42
+
43
+ def success(message)
44
+ log.info(message.to_s.green)
45
+ end
46
+
47
+ def message(message)
48
+ log.info(message.to_s)
49
+ end
50
+
51
+ def deprecated(message)
52
+ log.error(message.to_s.deprecated)
53
+ end
54
+
55
+ def command(message)
56
+ log.info("$ #{message}".cyan)
57
+ end
58
+
59
+ def command_output(message)
60
+ actual = (encode_as_utf_8_if_possible(message).split("\r").last || "") # as clearing the line will remove the `>` and the time stamp
61
+ actual.split("\n").each do |msg|
62
+ prefix = msg.include?("▸") ? "" : "▸ "
63
+ log.info(prefix + "" + msg.magenta)
64
+ end
65
+ end
66
+
67
+ def verbose(message)
68
+ log.debug(message.to_s)
69
+ end
70
+
71
+ def header(message)
72
+ success(message)
73
+ end
74
+
75
+ def content_error(content, error_line)
76
+ error_line = error_line.to_i
77
+ return unless error_line > 0
78
+
79
+ contents = content.split(/\r?\n/).map(&:chomp)
80
+
81
+ start_line = error_line - 2 < 1 ? 1 : error_line - 2
82
+ end_line = error_line + 2 < contents.length ? error_line + 2 : contents.length
83
+
84
+ Range.new(start_line, end_line).each do |line|
85
+ str = line == error_line ? " => " : " "
86
+ str << line.to_s.rjust(Math.log10(end_line) + 1)
87
+ str << ":\t#{contents[line - 1]}"
88
+ error(str)
89
+ end
90
+ end
91
+
92
+ #####################################################
93
+ # @!group Errors: Inputs
94
+ #####################################################
95
+
96
+ def interactive?
97
+ interactive = true
98
+ interactive = false if $stdout.isatty == false
99
+ interactive = false if Helper.ci?
100
+ return interactive
101
+ end
102
+
103
+ def input(message)
104
+ verify_interactive!(message)
105
+ ask("#{format_string}#{message.to_s.yellow}").to_s.strip
106
+ end
107
+
108
+ def confirm(message)
109
+ verify_interactive!(message)
110
+ agree("#{format_string}#{message.to_s.yellow} (y/n)", true)
111
+ end
112
+
113
+ def select(message, options)
114
+ verify_interactive!(message)
115
+
116
+ important(message)
117
+ choose(*options)
118
+ end
119
+
120
+ def password(message)
121
+ verify_interactive!(message)
122
+
123
+ ask("#{format_string}#{message.to_s.yellow}") do |q|
124
+ q.whitespace = :chomp
125
+ q.echo = "*"
126
+ end
127
+ end
128
+
129
+ private
130
+
131
+ def encode_as_utf_8_if_possible(message)
132
+ return message if message.valid_encoding?
133
+
134
+ # genstrings outputs UTF-16, so we should try to use this encoding if it turns out to be valid
135
+ test_message = message.dup
136
+ return message.encode(Encoding::UTF_8, Encoding::UTF_16) if test_message.force_encoding(Encoding::UTF_16).valid_encoding?
137
+
138
+ # replace any invalid with empty string
139
+ message.encode(Encoding::UTF_8, invalid: :replace)
140
+ end
141
+
142
+ def verify_interactive!(message)
143
+ return if interactive?
144
+ important(message)
145
+ crash!("Could not retrieve response as fastlane runs in non-interactive mode")
146
+ end
147
+ end
148
+ end
@@ -0,0 +1,205 @@
1
+ require_relative 'errors'
2
+
3
+ module Lhj
4
+ # Abstract super class
5
+ class Interface
6
+ #####################################################
7
+ # @!group Messaging: show text to the user
8
+ #####################################################
9
+
10
+ # Level Error: Can be used to show additional error
11
+ # information before actually raising an exception
12
+ # or can be used to just show an error from which
13
+ # fastlane can recover (much magic)
14
+ #
15
+ # By default those messages are shown in red
16
+ def error(_message)
17
+ not_implemented(__method__)
18
+ end
19
+
20
+ # Level Important: Can be used to show warnings to the user
21
+ # not necessarily negative, but something the user should
22
+ # be aware of.
23
+ #
24
+ # By default those messages are shown in yellow
25
+ def important(_message)
26
+ not_implemented(__method__)
27
+ end
28
+
29
+ # Level Success: Show that something was successful
30
+ #
31
+ # By default those messages are shown in green
32
+ def success(_message)
33
+ not_implemented(__method__)
34
+ end
35
+
36
+ # Level Message: Show a neutral message to the user
37
+ #
38
+ # By default those messages shown in white/black
39
+ def message(_message)
40
+ not_implemented(__method__)
41
+ end
42
+
43
+ # Level Deprecated: Show that a particular function is deprecated
44
+ #
45
+ # By default those messages shown in strong blue
46
+ def deprecated(_message)
47
+ not_implemented(__method__)
48
+ end
49
+
50
+ # Level Command: Print out a terminal command that is being
51
+ # executed.
52
+ #
53
+ # By default those messages shown in cyan
54
+ def command(_message)
55
+ not_implemented(__method__)
56
+ end
57
+
58
+ # Level Command Output: Print the output of a command with
59
+ # this method
60
+ #
61
+ # By default those messages shown in magenta
62
+ def command_output(_message)
63
+ not_implemented(__method__)
64
+ end
65
+
66
+ # Level Verbose: Print out additional information for the
67
+ # users that are interested. Will only be printed when
68
+ # FastlaneCore::Globals.verbose? = true
69
+ #
70
+ # By default those messages are shown in white
71
+ def verbose(_message)
72
+ not_implemented(__method__)
73
+ end
74
+
75
+ # Print a header = a text in a box
76
+ # use this if this message is really important
77
+ def header(_message)
78
+ not_implemented(__method__)
79
+ end
80
+
81
+ # Print lines of content around specific line where
82
+ # failed to parse.
83
+ #
84
+ # This message will be shown as error
85
+ def content_error(content, error_line)
86
+ not_implemented(__method__)
87
+ end
88
+
89
+ #####################################################
90
+ # @!group Errors: Inputs
91
+ #####################################################
92
+
93
+ # Is is possible to ask the user questions?
94
+ def interactive?
95
+ not_implemented(__method__)
96
+ end
97
+
98
+ # get a standard text input (single line)
99
+ def input(_message)
100
+ not_implemented(__method__)
101
+ end
102
+
103
+ # A simple yes or no question
104
+ def confirm(_message)
105
+ not_implemented(__method__)
106
+ end
107
+
108
+ # Let the user select one out of x items
109
+ # return value is the value of the option the user chose
110
+ def select(_message, _options)
111
+ not_implemented(__method__)
112
+ end
113
+
114
+ # Password input for the user, text field shouldn't show
115
+ # plain text
116
+ def password(_message)
117
+ not_implemented(__method__)
118
+ end
119
+
120
+ #####################################################
121
+ # @!group Abort helper methods
122
+ #####################################################
123
+
124
+ # Pass an exception to this method to exit the program
125
+ # using the given exception
126
+ # Use this method instead of user_error! if this error is
127
+ # unexpected, e.g. an invalid server response that shouldn't happen
128
+ def crash!(exception)
129
+ raise LhjCrash.new, exception.to_s
130
+ end
131
+
132
+ # Use this method to exit the program because of an user error
133
+ # e.g. app doesn't exist on the given Developer Account
134
+ # or invalid user credentials
135
+ # or scan tests fail
136
+ # This will show the error message, but doesn't show the full
137
+ # stack trace
138
+ # Basically this should be used when you actively catch the error
139
+ # and want to show a nice error message to the user
140
+ def user_error!(error_message, options = {})
141
+ raise LhjError.new(show_github_issues: options[:show_github_issues], error_info: options[:error_info]), error_message.to_s
142
+ end
143
+
144
+ # Use this method to exit the program because of a shell command
145
+ # failure -- the command returned a non-zero response. This does
146
+ # not specify the nature of the error. The error might be from a
147
+ # programming error, a user error, or an expected error because
148
+ # the user of the Fastfile doesn't have their environment set up
149
+ # properly. Because of this, when these errors occur, it means
150
+ # that the caller of the shell command did not adequate error
151
+ # handling and the caller error handling should be improved.
152
+ def shell_error!(error_message, options = {})
153
+ raise LhjShellError.new(options), error_message.to_s
154
+ end
155
+
156
+ # Use this method to exit the program because of a build failure
157
+ # that's caused by the source code of the user. Example for this
158
+ # is that gym will fail when the code doesn't compile or because
159
+ # settings for the project are incorrect.
160
+ # By using this method we'll have more accurate results about
161
+ # fastlane failures
162
+ def build_failure!(error_message, options = {})
163
+ raise LhjBuildFailure.new(options), error_message.to_s
164
+ end
165
+
166
+ # Use this method to exit the program because of a test failure
167
+ # that's caused by the source code of the user. Example for this
168
+ # is that scan will fail when the tests fail.
169
+ # By using this method we'll have more accurate results about
170
+ # fastlane failures
171
+ def test_failure!(error_message)
172
+ raise LhjTestFailure.new, error_message
173
+ end
174
+
175
+ # Use this method to exit the program because of terminal state
176
+ # that is neither the fault of fastlane, nor a problem with the
177
+ # user's input. Using this method instead of user_error! will
178
+ # avoid tracking this outcome as a fastlane failure.
179
+ #
180
+ # e.g. tests ran successfully, but no screenshots were found
181
+ #
182
+ # This will show the message, but hide the full stack trace.
183
+ def abort_with_message!(message)
184
+ raise LhjCommonException.new, message
185
+ end
186
+
187
+ #####################################################
188
+ # @!group Helpers
189
+ #####################################################
190
+ def not_implemented(method_name)
191
+ require_relative 'ui'
192
+ UI.user_error!("Current UI '#{self}' doesn't support method '#{method_name}'")
193
+ end
194
+
195
+ def to_s
196
+ self.class.name.split('::').last
197
+ end
198
+ end
199
+ end
200
+
201
+ class String
202
+ def deprecated
203
+ self.bold.blue
204
+ end
205
+ end
data/lib/lhj/ui/ui.rb ADDED
@@ -0,0 +1,26 @@
1
+ module Lhj
2
+ class UI
3
+ class << self
4
+ attr_accessor(:ui_object)
5
+
6
+ def ui_object
7
+ require_relative 'implementations/shell'
8
+ @ui_object ||= Shell.new
9
+ end
10
+
11
+ def method_missing(method_sym, *args, &_block)
12
+ # not using `responds` because we don't care about methods like .to_s and so on
13
+ require_relative 'interface'
14
+ interface_methods = Lhj::Interface.instance_methods - Object.instance_methods
15
+ UI.user_error!("Unknown method '#{method_sym}', supported #{interface_methods}") unless interface_methods.include?(method_sym)
16
+
17
+ self.ui_object.send(method_sym, *args)
18
+ end
19
+ end
20
+ end
21
+ end
22
+
23
+ # Import all available implementations
24
+ Dir[File.dirname(__FILE__) + '/implementations/*.rb'].each do |file|
25
+ require_relative file
26
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lhj-tools
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.1.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - lihaijian
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-01-20 00:00:00.000000000 Z
11
+ date: 2022-01-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: claide
@@ -118,6 +118,60 @@ dependencies:
118
118
  - - "~>"
119
119
  - !ruby/object:Gem::Version
120
120
  version: '2.8'
121
+ - !ruby/object:Gem::Dependency
122
+ name: tty-spinner
123
+ requirement: !ruby/object:Gem::Requirement
124
+ requirements:
125
+ - - ">="
126
+ - !ruby/object:Gem::Version
127
+ version: 0.8.0
128
+ - - "<"
129
+ - !ruby/object:Gem::Version
130
+ version: 1.0.0
131
+ type: :runtime
132
+ prerelease: false
133
+ version_requirements: !ruby/object:Gem::Requirement
134
+ requirements:
135
+ - - ">="
136
+ - !ruby/object:Gem::Version
137
+ version: 0.8.0
138
+ - - "<"
139
+ - !ruby/object:Gem::Version
140
+ version: 1.0.0
141
+ - !ruby/object:Gem::Dependency
142
+ name: colored
143
+ requirement: !ruby/object:Gem::Requirement
144
+ requirements:
145
+ - - ">="
146
+ - !ruby/object:Gem::Version
147
+ version: '0'
148
+ type: :runtime
149
+ prerelease: false
150
+ version_requirements: !ruby/object:Gem::Requirement
151
+ requirements:
152
+ - - ">="
153
+ - !ruby/object:Gem::Version
154
+ version: '0'
155
+ - !ruby/object:Gem::Dependency
156
+ name: excon
157
+ requirement: !ruby/object:Gem::Requirement
158
+ requirements:
159
+ - - ">="
160
+ - !ruby/object:Gem::Version
161
+ version: 0.71.0
162
+ - - "<"
163
+ - !ruby/object:Gem::Version
164
+ version: 1.0.0
165
+ type: :runtime
166
+ prerelease: false
167
+ version_requirements: !ruby/object:Gem::Requirement
168
+ requirements:
169
+ - - ">="
170
+ - !ruby/object:Gem::Version
171
+ version: 0.71.0
172
+ - - "<"
173
+ - !ruby/object:Gem::Version
174
+ version: 1.0.0
121
175
  - !ruby/object:Gem::Dependency
122
176
  name: faraday-cookie_jar
123
177
  requirement: !ruby/object:Gem::Requirement
@@ -218,8 +272,13 @@ extra_rdoc_files: []
218
272
  files:
219
273
  - README.md
220
274
  - bin/lhj
275
+ - lib/lhj/action/sh_helper.rb
221
276
  - lib/lhj/command.rb
277
+ - lib/lhj/command/config.rb
278
+ - lib/lhj/command/config/info.rb
279
+ - lib/lhj/command/file_path.rb
222
280
  - lib/lhj/command/head_import.rb
281
+ - lib/lhj/command/http.rb
223
282
  - lib/lhj/command/init.rb
224
283
  - lib/lhj/command/local/fetch.rb
225
284
  - lib/lhj/command/local/filter.rb
@@ -233,6 +292,7 @@ files:
233
292
  - lib/lhj/command/refactor_rename.rb
234
293
  - lib/lhj/command/rename_image.rb
235
294
  - lib/lhj/command/reverse_import.rb
295
+ - lib/lhj/command/sync_pod_repo.rb
236
296
  - lib/lhj/command/template.rb
237
297
  - lib/lhj/command/trans.rb
238
298
  - lib/lhj/command/view.rb
@@ -244,6 +304,21 @@ files:
244
304
  - lib/lhj/helper/trans_helper.rb
245
305
  - lib/lhj/tools.rb
246
306
  - lib/lhj/tools/version.rb
307
+ - lib/lhj/tree/directory_renderer.rb
308
+ - lib/lhj/tree/hash_walker.rb
309
+ - lib/lhj/tree/node.rb
310
+ - lib/lhj/tree/number_renderer.rb
311
+ - lib/lhj/tree/path_walker.rb
312
+ - lib/lhj/tree/tree.rb
313
+ - lib/lhj/ui/errors.rb
314
+ - lib/lhj/ui/errors/lhj_common_error.rb
315
+ - lib/lhj/ui/errors/lhj_crash.rb
316
+ - lib/lhj/ui/errors/lhj_error.rb
317
+ - lib/lhj/ui/errors/lhj_exception.rb
318
+ - lib/lhj/ui/errors/lhj_shell_error.rb
319
+ - lib/lhj/ui/implementations/shell.rb
320
+ - lib/lhj/ui/interface.rb
321
+ - lib/lhj/ui/ui.rb
247
322
  homepage:
248
323
  licenses:
249
324
  - MIT