kscript 0.1.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/Gemfile +3 -0
- data/LICENSE +21 -0
- data/README.md +169 -0
- data/Rakefile +35 -0
- data/bin/kscript +6 -0
- data/kscript.gemspec +45 -0
- data/lib/kscript/banner.rb +12 -0
- data/lib/kscript/base.rb +50 -0
- data/lib/kscript/cli.rb +184 -0
- data/lib/kscript/logger.rb +94 -0
- data/lib/kscript/plugins/kk_apnic_utils.rb +87 -0
- data/lib/kscript/plugins/kk_cleaner_utils.rb +83 -0
- data/lib/kscript/plugins/kk_es_fingerprint_utils.rb +92 -0
- data/lib/kscript/plugins/kk_ffmpeg_utils.rb +140 -0
- data/lib/kscript/plugins/kk_ip_utils.rb +90 -0
- data/lib/kscript/plugins/kk_jenkins_utils.rb +143 -0
- data/lib/kscript/plugins/kk_kibana_utils.rb +237 -0
- data/lib/kscript/plugins/kk_lvm_utils.rb +200 -0
- data/lib/kscript/plugins/kk_optimize_utils.rb +85 -0
- data/lib/kscript/plugins/kk_portscan_utils.rb +90 -0
- data/lib/kscript/plugins/kk_projscan_utils.rb +90 -0
- data/lib/kscript/plugins/kk_rename_utils.rb +82 -0
- data/lib/kscript/plugins/kk_sh_utils.rb +112 -0
- data/lib/kscript/plugins/kk_syscheck_utils.rb +82 -0
- data/lib/kscript/plugins/kk_top_utils.rb +74 -0
- data/lib/kscript/plugins/kk_usd_utils.rb +71 -0
- data/lib/kscript/plugins/kk_wg_acl_utils.rb +95 -0
- data/lib/kscript/plugins/kk_wg_pass_utils.rb +50 -0
- data/lib/kscript/plugins.rb +32 -0
- data/lib/kscript/utils.rb +64 -0
- data/lib/kscript/version.rb +10 -0
- data/lib/kscript.rb +43 -0
- metadata +130 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: aa60e97dd2e5ebd0282945488335f81226666cc547f74608eb5b6d04370eec69
|
4
|
+
data.tar.gz: 628577d54846ee750cf65e648bb13bce7c286182b49ef52813edb551b182a6f2
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 79c677939e03109beac01c935773433218d95b663f7a4fea56980d3e6dbfc652eaadec7ed37ce1da38e77089cd6ff7524631e46a7dda71744e3868d8badf1734
|
7
|
+
data.tar.gz: f29744a4e376a0476f91ee3a5788cd713f7a5c333114a3e4ef3616f5b3cb45783cceaca02b5798b2bf88c3038a28c50fe168d9e08c4700c31a5c3fd48376687c
|
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2021 kevin197011
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,169 @@
|
|
1
|
+
# kscript
|
2
|
+
```
|
3
|
+
______ _____ _____
|
4
|
+
___ /________________________(_)_________ /_
|
5
|
+
__ //_/_ ___/ ___/_ ___/_ /___ __ \\ __/
|
6
|
+
_ ,< _(__ )/ /__ _ / _ / __ /_/ / /_
|
7
|
+
/_/|_| /____/ \\___/ /_/ /_/ _ .___/\\__/
|
8
|
+
/_/
|
9
|
+
```
|
10
|
+
|
11
|
+
A collection of Ruby utility scripts for various system administration and development tasks.
|
12
|
+
|
13
|
+
[](https://rubygems.org/gems/kscript)
|
14
|
+
[](https://github.com/kevin197011/kscript/actions/workflows/gem-push.yml)
|
15
|
+
|
16
|
+
## Installation
|
17
|
+
|
18
|
+
### Gem install (recommended)
|
19
|
+
|
20
|
+
```bash
|
21
|
+
gem install kscript
|
22
|
+
```
|
23
|
+
|
24
|
+
Or from local source:
|
25
|
+
|
26
|
+
```bash
|
27
|
+
git clone https://github.com/kevin197011/kscript.git
|
28
|
+
cd kscript
|
29
|
+
gem build kscript.gemspec
|
30
|
+
gem install ./kscript-*.gem
|
31
|
+
```
|
32
|
+
|
33
|
+
### Bundler (for development)
|
34
|
+
|
35
|
+
```bash
|
36
|
+
git clone https://github.com/kevin197011/kscript.git
|
37
|
+
cd kscript
|
38
|
+
bundle install
|
39
|
+
```
|
40
|
+
|
41
|
+
## Usage
|
42
|
+
|
43
|
+
Most scripts can be executed directly via command line after gem install:
|
44
|
+
|
45
|
+
```bash
|
46
|
+
kscript SCRIPT_NAME [args]
|
47
|
+
```
|
48
|
+
|
49
|
+
Or, for legacy usage via curl:
|
50
|
+
|
51
|
+
```bash
|
52
|
+
curl -sSL https://raw.githubusercontent.com/kevin197011/kscript/main/bin/SCRIPT_NAME.rb | ruby
|
53
|
+
```
|
54
|
+
|
55
|
+
## Available Scripts
|
56
|
+
|
57
|
+
### System Tools
|
58
|
+
- `mac-top-usage.rb` - Display top CPU and memory usage processes on macOS
|
59
|
+
- `port-scanner.rb` - Multi-threaded port scanner
|
60
|
+
- `mouse-simulator.rb` - Simulate mouse movement to prevent system idle
|
61
|
+
- `source-cleaner.rb` - Clean up old source code versions
|
62
|
+
- `ffmpeg-installer.rb` - FFmpeg installation script for Linux systems
|
63
|
+
|
64
|
+
### Network Tools
|
65
|
+
- `ip-api.rb` - Query IP geolocation information (supports auto-detecting public IP)
|
66
|
+
- `apnic-ip-range.rb` - Fetch IP ranges from APNIC database
|
67
|
+
- `wireguard-acl.rb` - Configure WireGuard firewall access control
|
68
|
+
- `wireguard-password.rb` - Generate WireGuard password hashes
|
69
|
+
|
70
|
+
### Development Tools
|
71
|
+
- `shell-helper.rb` - Quick shell command reference tool
|
72
|
+
- `rename.rb` - Batch rename files using regular expressions
|
73
|
+
- `jenkins-job-manager.rb` - Manage Jenkins jobs (export/import)
|
74
|
+
- `kibana-utils.rb` - Kibana management utilities
|
75
|
+
|
76
|
+
### Windows Specific
|
77
|
+
- `windows-font-enhancer.rb` - Enhance Windows font rendering (macOS-like)
|
78
|
+
|
79
|
+
### Infrastructure Tools
|
80
|
+
- `elastic-cert-fingerprint.rb` - Generate Elasticsearch certificate fingerprints
|
81
|
+
- `lvm-mounter.rb` - LVM volume creation and mounting utility
|
82
|
+
|
83
|
+
## Examples
|
84
|
+
|
85
|
+
1. Query IP geolocation:
|
86
|
+
```bash
|
87
|
+
# Query specific IP
|
88
|
+
curl -sSL https://raw.githubusercontent.com/kevin197011/kscript/main/bin/ip-api.rb | ruby 8.8.8.8
|
89
|
+
|
90
|
+
# Query your public IP
|
91
|
+
curl -sSL https://raw.githubusercontent.com/kevin197011/kscript/main/bin/ip-api.rb | ruby
|
92
|
+
```
|
93
|
+
|
94
|
+
2. View system resource usage:
|
95
|
+
```bash
|
96
|
+
curl -sSL https://raw.githubusercontent.com/kevin197011/kscript/main/bin/mac-top-usage.rb | ruby
|
97
|
+
```
|
98
|
+
|
99
|
+
3. Scan ports:
|
100
|
+
```bash
|
101
|
+
curl -sSL https://raw.githubusercontent.com/kevin197011/kscript/main/bin/port-scanner.rb | ruby
|
102
|
+
```
|
103
|
+
|
104
|
+
## Dependencies
|
105
|
+
|
106
|
+
Required gems:
|
107
|
+
```ruby
|
108
|
+
gem 'http'
|
109
|
+
gem 'rubocop'
|
110
|
+
```
|
111
|
+
|
112
|
+
## License
|
113
|
+
|
114
|
+
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
115
|
+
|
116
|
+
## Contributing
|
117
|
+
|
118
|
+
1. Fork it
|
119
|
+
2. Create your feature branch (`git checkout -b feature/my-new-feature`)
|
120
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
121
|
+
4. Push to the branch (`git push origin feature/my-new-feature`)
|
122
|
+
5. Create new Pull Request
|
123
|
+
|
124
|
+
## Unified CLI Usage
|
125
|
+
|
126
|
+
After gem install, you can use the unified kk command:
|
127
|
+
|
128
|
+
```bash
|
129
|
+
kk <command> [args...]
|
130
|
+
|
131
|
+
# List all available tools
|
132
|
+
kk --help
|
133
|
+
|
134
|
+
# Example: scan ports
|
135
|
+
kk port-scanner 192.168.1.1
|
136
|
+
|
137
|
+
# Example: check macOS system
|
138
|
+
kk mac-sys-check
|
139
|
+
```
|
140
|
+
|
141
|
+
Each subcommand supports --help for its own usage.
|
142
|
+
|
143
|
+
## Global Configuration
|
144
|
+
|
145
|
+
You can set global options for all kk tools in `~/.kscriptrc` (YAML format):
|
146
|
+
|
147
|
+
```yaml
|
148
|
+
log_level: debug
|
149
|
+
trace_id: my-global-trace
|
150
|
+
```
|
151
|
+
|
152
|
+
- These settings will be used by default for all commands unless overridden by CLI options or environment variables.
|
153
|
+
|
154
|
+
## Shell Completion 自动补全
|
155
|
+
|
156
|
+
kscript 现已支持 zsh 和 bash 的命令自动补全,且**安装后首次运行会自动为你部署补全脚本**,无需手动操作。
|
157
|
+
|
158
|
+
- **zsh 补全脚本路径**:`~/.zsh/completions/_kscript`
|
159
|
+
- **bash 补全脚本路径**:`~/.bash_completion.d/kscript`
|
160
|
+
|
161
|
+
如需手动重新生成补全脚本,可运行:
|
162
|
+
|
163
|
+
```bash
|
164
|
+
kscript completion zsh > ~/.zsh/completions/_kscript
|
165
|
+
kscript completion bash > ~/.bash_completion.d/kscript
|
166
|
+
```
|
167
|
+
|
168
|
+
> 每次升级或新增命令后,补全脚本也会自动更新。
|
169
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright (c) 2025 kk
|
4
|
+
#
|
5
|
+
# This software is released under the MIT License.
|
6
|
+
# https://opensource.org/licenses/MIT
|
7
|
+
|
8
|
+
require 'time'
|
9
|
+
require 'rake'
|
10
|
+
require 'bundler/gem_tasks'
|
11
|
+
|
12
|
+
task default: %w[push]
|
13
|
+
|
14
|
+
task :push do
|
15
|
+
system <<-SHELL
|
16
|
+
rubocop -A
|
17
|
+
git update-index --chmod=+x push
|
18
|
+
git add .
|
19
|
+
git commit -m "Update #{Time.now}"
|
20
|
+
git pull
|
21
|
+
git push origin main
|
22
|
+
SHELL
|
23
|
+
end
|
24
|
+
|
25
|
+
# 其他自定义任务可在此添加
|
26
|
+
task :dev do
|
27
|
+
sh <<-SHELL
|
28
|
+
gem uninstall kscript -aIx
|
29
|
+
gem build kscript.gemspec
|
30
|
+
gem install kscript-*.gem
|
31
|
+
kscript help
|
32
|
+
kscript list
|
33
|
+
kscript version
|
34
|
+
SHELL
|
35
|
+
end
|
data/bin/kscript
ADDED
data/kscript.gemspec
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'lib/kscript/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = 'kscript'
|
7
|
+
spec.version = Kscript::VERSION
|
8
|
+
spec.authors = ['Kk']
|
9
|
+
spec.email = ['kevin197011@outlook.com']
|
10
|
+
|
11
|
+
spec.summary = 'A collection of Ruby utility scripts for sysadmin and development.'
|
12
|
+
spec.description = 'Kscript provides a set of handy Ruby scripts for system administration, development, and automation.'
|
13
|
+
spec.homepage = 'https://github.com/kevin197011/kscript'
|
14
|
+
spec.license = 'MIT'
|
15
|
+
|
16
|
+
spec.required_ruby_version = '>= 3.0.0'
|
17
|
+
|
18
|
+
spec.files = Dir.chdir(__dir__) do
|
19
|
+
files = `git ls-files -z`.split("\x0")
|
20
|
+
files.select! do |f|
|
21
|
+
f =~ %r{^(lib/|bin/kscript|README|LICENSE|Rakefile|Gemfile|kscript\.gemspec)}
|
22
|
+
end
|
23
|
+
files
|
24
|
+
end
|
25
|
+
spec.bindir = 'bin'
|
26
|
+
spec.executables = ['kscript']
|
27
|
+
spec.require_paths = ['lib']
|
28
|
+
|
29
|
+
# Runtime dependencies
|
30
|
+
spec.add_dependency 'http', '>= 4.0', '< 6.0'
|
31
|
+
spec.add_dependency 'thor', '1.3.2'
|
32
|
+
|
33
|
+
# Development dependencies
|
34
|
+
spec.add_development_dependency 'rubocop', '~> 1.0'
|
35
|
+
spec.metadata['rubygems_mfa_required'] = 'true'
|
36
|
+
|
37
|
+
# spec.extensions = ['ext/install.rb'] # 已移除,防止 native extension build 错误
|
38
|
+
|
39
|
+
spec.post_install_message = <<~MSG
|
40
|
+
[kscript] Shell completion is available!
|
41
|
+
To enable shell completion for your shell, please run:
|
42
|
+
ruby ext/install.rb
|
43
|
+
Or see README for more details.
|
44
|
+
MSG
|
45
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kscript
|
4
|
+
BANNER = <<~BANNER
|
5
|
+
______ _____ _____
|
6
|
+
___ /________________________(_)_________ /_
|
7
|
+
__ //_/_ ___/ ___/_ ___/_ /___ __ \\ __/
|
8
|
+
_ ,< _(__ )/ /__ _ / _ / __ /_/ / /_
|
9
|
+
/_/|_| /____/ \\___/ /_/ /_/ _ .___/\\__/
|
10
|
+
/_/
|
11
|
+
BANNER
|
12
|
+
end
|
data/lib/kscript/base.rb
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'kscript'
|
4
|
+
|
5
|
+
module Kscript
|
6
|
+
# Base class for all kscript scripts
|
7
|
+
class Base
|
8
|
+
attr_reader :logger
|
9
|
+
|
10
|
+
def initialize(service: nil, log_level: nil, trace_id: nil)
|
11
|
+
config = defined?(Kscript::Utils::Config) ? Kscript::Utils::Config.load : nil
|
12
|
+
log_level ||= config&.log_level || ENV['KSCRIPT_LOG_LEVEL'] || :info
|
13
|
+
trace_id ||= config&.trace_id || ENV['KSCRIPT_TRACE_ID']
|
14
|
+
@trace_id = trace_id
|
15
|
+
@logger = Kscript::Logger.new(service: service || self.class.name, level: log_level)
|
16
|
+
@logger.set_human_output(human_output?)
|
17
|
+
end
|
18
|
+
|
19
|
+
# 通用工具方法可在此扩展
|
20
|
+
def with_error_handling
|
21
|
+
yield
|
22
|
+
rescue StandardError => e
|
23
|
+
logger.error("Unhandled error: #{e.class} - #{e.message}", error: e.class.name, backtrace: e.backtrace&.first(5))
|
24
|
+
exit(1)
|
25
|
+
end
|
26
|
+
|
27
|
+
# 提供 trace_id 给 logger
|
28
|
+
def logger
|
29
|
+
@logger.define_singleton_method(:default_trace_id) { @trace_id } if @trace_id
|
30
|
+
@logger
|
31
|
+
end
|
32
|
+
|
33
|
+
# 自动注册所有 Kscript::Base 的子类为插件
|
34
|
+
def self.inherited(subclass)
|
35
|
+
name = subclass.name.split('::').last
|
36
|
+
if name.start_with?('Kk') && name.end_with?('Utils')
|
37
|
+
cmd = name[2..-6] # 去掉 Kk 和 Utils
|
38
|
+
# 转 snake_case
|
39
|
+
cmd = cmd.gsub(/([A-Z])/, '_\1').downcase.sub(/^_/, '').sub(/_$/, '')
|
40
|
+
Kscript::Plugin.register(cmd.to_sym, subclass)
|
41
|
+
end
|
42
|
+
super if defined?(super)
|
43
|
+
end
|
44
|
+
|
45
|
+
# 判断是否为人性化输出模式(无 --log/--log-level 参数且 ENV['LOG'] 未设置)
|
46
|
+
def human_output?
|
47
|
+
!(ARGV.include?('--log') || ARGV.include?('--log-level') || ENV['LOG'])
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
data/lib/kscript/cli.rb
ADDED
@@ -0,0 +1,184 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'kscript'
|
4
|
+
require 'io/console'
|
5
|
+
require 'kscript/banner'
|
6
|
+
require 'thor'
|
7
|
+
|
8
|
+
module Kscript
|
9
|
+
class CLI < Thor
|
10
|
+
class_option :log_level, type: :string, desc: 'Set log level (debug, info, warn, error, fatal)',
|
11
|
+
aliases: '--log-level'
|
12
|
+
class_option :log, type: :boolean, desc: 'Enable structured log output', default: false
|
13
|
+
|
14
|
+
def self.banner(command, _namespace = nil, _subcommand = false)
|
15
|
+
"kscript #{command.usage}" if command.respond_to?(:usage)
|
16
|
+
end
|
17
|
+
|
18
|
+
desc 'version', 'Show kscript version'
|
19
|
+
map %w[--version -v] => :version
|
20
|
+
def version
|
21
|
+
puts Kscript::BANNER
|
22
|
+
puts color('─' * 80, 90)
|
23
|
+
require 'kscript/version'
|
24
|
+
puts "kscript version: #{Kscript::VERSION}"
|
25
|
+
end
|
26
|
+
|
27
|
+
desc 'list', 'List all available commands'
|
28
|
+
def list
|
29
|
+
puts Kscript::BANNER
|
30
|
+
puts color('─' * 80, 90)
|
31
|
+
plugin_infos = Kscript::PluginLoader.plugin_infos
|
32
|
+
grouped = plugin_infos.group_by { |info| info[:group] || 'other' }
|
33
|
+
group_colors = %w[36 32 35 34 33 31 90 37]
|
34
|
+
group_names = grouped.keys.sort
|
35
|
+
group_names.each_with_index do |group, idx|
|
36
|
+
color_code = group_colors[idx % group_colors.size]
|
37
|
+
group_label = color("[#{group.capitalize}]", color_code)
|
38
|
+
puts group_label
|
39
|
+
puts color('─' * 80, 90)
|
40
|
+
grouped[group].each do |info|
|
41
|
+
command = info[:name].to_s.sub(/^kk_/, '')
|
42
|
+
desc = info[:description] || ''
|
43
|
+
usage = info[:class].respond_to?(:usage) ? info[:class].usage : nil
|
44
|
+
arguments = info[:class].respond_to?(:arguments) ? info[:class].arguments : nil
|
45
|
+
author = info[:class].respond_to?(:author) ? info[:class].author : nil
|
46
|
+
print " #{green(command.ljust(16))}"
|
47
|
+
print gray(desc)
|
48
|
+
puts
|
49
|
+
if usage && !usage.to_s.strip.empty?
|
50
|
+
usage.to_s.split("\n").each_with_index do |line, idx|
|
51
|
+
prefix = idx.zero? ? gray(' usage:') : gray(' ')
|
52
|
+
puts "#{prefix} #{cyan(line.strip)}"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
puts gray(" args: #{arguments}") if arguments && !arguments.to_s.strip.empty?
|
56
|
+
puts gray(" by: #{author}") if author && !author.to_s.strip.empty?
|
57
|
+
puts gray(" #{'-' * 60}")
|
58
|
+
end
|
59
|
+
puts
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
# 动态注册所有插件为子命令
|
64
|
+
reserved = if defined?(Thor::Util::THOR_RESERVED_WORDS)
|
65
|
+
Thor::Util::THOR_RESERVED_WORDS.map(&:to_s)
|
66
|
+
else
|
67
|
+
%w[shell help start version list exit invoke method_missing]
|
68
|
+
end
|
69
|
+
Kscript::PluginLoader.plugin_infos.each do |info|
|
70
|
+
orig_command = info[:name].to_s.sub(/^kk_/, '')
|
71
|
+
# shell -> sh
|
72
|
+
command = orig_command == 'shell' ? 'sh' : orig_command
|
73
|
+
command = reserved.include?(command) ? "#{command}_cmd" : command
|
74
|
+
klass = info[:class]
|
75
|
+
desc command,
|
76
|
+
(info[:description] || 'No description') + (reserved.include?(orig_command) ? " (original: #{orig_command})" : '')
|
77
|
+
define_method(command) do |*args|
|
78
|
+
puts Kscript::BANNER
|
79
|
+
puts color('─' * 80, 90)
|
80
|
+
begin
|
81
|
+
instance = klass.new(*args)
|
82
|
+
instance.run
|
83
|
+
rescue ArgumentError => e
|
84
|
+
warn "Argument error: #{e.message}"
|
85
|
+
puts "Usage: kscript #{command} #{klass.respond_to?(:arguments) ? klass.arguments : '[args...]'}"
|
86
|
+
exit 1
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
desc 'completion SHELL', 'Generate shell completion script (zsh or bash)'
|
92
|
+
def completion(shell = 'zsh', capture: false)
|
93
|
+
commands = %w[version help
|
94
|
+
list] + Kscript::PluginLoader.plugin_infos.map do |info|
|
95
|
+
cmd = info[:name].to_s.sub(/^kk_/, '')
|
96
|
+
cmd = 'sh' if cmd == 'shell'
|
97
|
+
cmd
|
98
|
+
end
|
99
|
+
output = StringIO.new
|
100
|
+
case shell
|
101
|
+
when 'zsh'
|
102
|
+
output.puts "#compdef kscript\n"
|
103
|
+
output.puts '_kscript() {'
|
104
|
+
output.puts ' local -a commands'
|
105
|
+
output.puts ' commands=('
|
106
|
+
commands.each do |cmd|
|
107
|
+
output.puts " '#{cmd}:kscript command'"
|
108
|
+
end
|
109
|
+
output.puts ' )'
|
110
|
+
output.puts " _describe 'command' commands"
|
111
|
+
output.puts '}'
|
112
|
+
output.puts 'compdef _kscript kscript'
|
113
|
+
when 'bash'
|
114
|
+
output.puts '_kscript_completions() {'
|
115
|
+
output.puts " COMPREPLY=($(compgen -W \"#{commands.join(' ')}\" -- \"${COMP_WORDS[1]}\"))"
|
116
|
+
output.puts '}'
|
117
|
+
output.puts 'complete -F _kscript_completions kscript'
|
118
|
+
else
|
119
|
+
output.puts "Unsupported shell: #{shell}. Only 'zsh' and 'bash' are supported."
|
120
|
+
return capture ? output.string : (puts output.string)
|
121
|
+
end
|
122
|
+
capture ? output.string : (puts output.string)
|
123
|
+
end
|
124
|
+
|
125
|
+
no_commands do
|
126
|
+
def color(str, code)
|
127
|
+
"\e[#{code}m#{str}\e[0m"
|
128
|
+
end
|
129
|
+
|
130
|
+
def cyan(str)
|
131
|
+
color(str, 36)
|
132
|
+
end
|
133
|
+
|
134
|
+
def green(str)
|
135
|
+
color(str, 32)
|
136
|
+
end
|
137
|
+
|
138
|
+
def gray(str)
|
139
|
+
color(str, 90)
|
140
|
+
end
|
141
|
+
|
142
|
+
def bold(str)
|
143
|
+
color(str, 1)
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
# Thor help 美化
|
148
|
+
def self.exit_on_failure?
|
149
|
+
true
|
150
|
+
end
|
151
|
+
|
152
|
+
def help(*_args)
|
153
|
+
puts Kscript::BANNER
|
154
|
+
puts color('─' * 80, 90)
|
155
|
+
# 只展示主命令(version、help、list)
|
156
|
+
Kscript::PluginLoader.plugin_infos.select do |info|
|
157
|
+
info[:name].to_s.sub(/^kk_/, '')
|
158
|
+
false # 不输出插件命令
|
159
|
+
end
|
160
|
+
# 只输出主命令
|
161
|
+
puts bold('Available commands:')
|
162
|
+
puts green(' version'.ljust(16)) + gray('Show kscript version')
|
163
|
+
puts green(' help'.ljust(16)) + gray('Describe available commands or one specific command')
|
164
|
+
puts green(' list'.ljust(16)) + gray('List all available commands')
|
165
|
+
puts
|
166
|
+
puts bold('Options:')
|
167
|
+
puts gray(' --log-level, [--log-level=LOG_LEVEL] # Set log level (debug, info, warn, error, fatal)')
|
168
|
+
puts gray(' [--log], [--no-log], [--skip-log] # Enable structured log output')
|
169
|
+
puts gray(' --log # Enable structured log output')
|
170
|
+
puts gray(' # Default: false')
|
171
|
+
puts
|
172
|
+
puts gray("Use 'kscript list' to see all business subcommands.")
|
173
|
+
nil
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
# CLI 启动时自动检测并安装 shell 补全脚本
|
179
|
+
begin
|
180
|
+
require_relative 'utils'
|
181
|
+
Kscript::Utils::Config.ensure_completion_installed
|
182
|
+
rescue StandardError => e
|
183
|
+
warn "[kscript] Shell completion auto-install failed: #{e.message}"
|
184
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kscript
|
4
|
+
# Structured logger for all scripts
|
5
|
+
class Logger
|
6
|
+
LEVELS = %i[debug info warn error fatal unknown].freeze
|
7
|
+
|
8
|
+
# 极客风格终端输出
|
9
|
+
COLORS = {
|
10
|
+
info: "\e[32m", # green
|
11
|
+
warn: "\e[33m", # yellow
|
12
|
+
error: "\e[31m", # red
|
13
|
+
debug: "\e[90m", # gray
|
14
|
+
reset: "\e[0m"
|
15
|
+
}.freeze
|
16
|
+
|
17
|
+
def initialize(service: 'kscript', level: :info, out: $stdout, human_output: nil)
|
18
|
+
@service = service
|
19
|
+
@logger = ::Logger.new(out)
|
20
|
+
@logger.level = ::Logger.const_get(level.to_s.upcase)
|
21
|
+
@human_output = human_output
|
22
|
+
end
|
23
|
+
|
24
|
+
# 允许外部设置输出模式
|
25
|
+
def set_human_output(val)
|
26
|
+
@human_output = val
|
27
|
+
end
|
28
|
+
|
29
|
+
def human_output?
|
30
|
+
@human_output == true
|
31
|
+
end
|
32
|
+
|
33
|
+
def log_mode?
|
34
|
+
@human_output == false
|
35
|
+
end
|
36
|
+
|
37
|
+
LEVELS.each do |level|
|
38
|
+
define_method(level) do |message, context = {}|
|
39
|
+
if human_output?
|
40
|
+
puts "[#{level.to_s.upcase}] #{message} #{context.map { |k, v| "#{k}=#{v}" }.join(' ')}".strip
|
41
|
+
else
|
42
|
+
log(level, message, context)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def log(level, message, context = {})
|
48
|
+
trace_id = context[:trace_id] || (respond_to?(:default_trace_id) ? default_trace_id : nil) || SecureRandom.hex(8)
|
49
|
+
entry = {
|
50
|
+
timestamp: Time.now.utc.iso8601,
|
51
|
+
level: level.to_s.upcase,
|
52
|
+
service: @service,
|
53
|
+
message: message,
|
54
|
+
trace_id: trace_id,
|
55
|
+
context: context.reject { |k, _| k == :trace_id }
|
56
|
+
}
|
57
|
+
@logger.send(level, entry.to_json)
|
58
|
+
end
|
59
|
+
|
60
|
+
# 极客风格终端输出
|
61
|
+
def klog(level, message, context = {})
|
62
|
+
if human_output?
|
63
|
+
puts "[#{level.to_s.upcase}] #{message} #{context.map { |k, v| "#{k}=#{v}" }.join(' ')}".strip
|
64
|
+
else
|
65
|
+
ts = Time.now.strftime('%Y-%m-%d %H:%M:%S')
|
66
|
+
lvl = level.to_s.upcase
|
67
|
+
svc = @service || 'kscript'
|
68
|
+
trace = context[:trace_id] || (respond_to?(:default_trace_id) ? default_trace_id : nil) || '-'
|
69
|
+
color = COLORS[level] || COLORS[:info]
|
70
|
+
ctx_str = context.reject { |k, _| k == :trace_id }.map { |k, v| "#{k}=#{v}" }.join(' ')
|
71
|
+
line = "[#{ts}] [#{lvl}] [#{svc}] [#{trace}] #{message}"
|
72
|
+
line += " | #{ctx_str}" unless ctx_str.empty?
|
73
|
+
$stdout.puts "#{color}#{line}#{COLORS[:reset]}"
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
# 便捷方法
|
78
|
+
def kinfo(msg, ctx = {})
|
79
|
+
klog(:info, msg, ctx)
|
80
|
+
end
|
81
|
+
|
82
|
+
def kwarn(msg, ctx = {})
|
83
|
+
klog(:warn, msg, ctx)
|
84
|
+
end
|
85
|
+
|
86
|
+
def kerror(msg, ctx = {})
|
87
|
+
klog(:error, msg, ctx)
|
88
|
+
end
|
89
|
+
|
90
|
+
def kdebug(msg, ctx = {})
|
91
|
+
klog(:debug, msg, ctx)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|