squared 0.0.1
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/LICENSE +11 -0
- data/README.md +1347 -0
- data/README.ruby.md +50 -0
- data/lib/squared/common/class.rb +18 -0
- data/lib/squared/common/format.rb +151 -0
- data/lib/squared/common/shell.rb +40 -0
- data/lib/squared/common/system.rb +55 -0
- data/lib/squared/common/task.rb +27 -0
- data/lib/squared/common.rb +66 -0
- data/lib/squared/config.rb +240 -0
- data/lib/squared/repo/project/base.rb +357 -0
- data/lib/squared/repo/project/git.rb +521 -0
- data/lib/squared/repo/project/node.rb +394 -0
- data/lib/squared/repo/project/python.rb +104 -0
- data/lib/squared/repo/project/ruby.rb +277 -0
- data/lib/squared/repo/project.rb +49 -0
- data/lib/squared/repo/workspace.rb +427 -0
- data/lib/squared/repo.rb +39 -0
- data/lib/squared/version.rb +5 -0
- data/lib/squared.rb +13 -0
- data/squared.gemspec +29 -0
- metadata +95 -0
data/README.ruby.md
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
# squared 0.1
|
2
|
+
|
3
|
+
* [source](https://github.com/anpham6/squared)
|
4
|
+
* [manifest](https://github.com/anpham6/squared-repo)
|
5
|
+
* [docs](https://squared.readthedocs.io)
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
```sh
|
10
|
+
gem install squared
|
11
|
+
```
|
12
|
+
|
13
|
+
## Prerequisites
|
14
|
+
|
15
|
+
* Ruby 2.4+
|
16
|
+
* Python 3.6+
|
17
|
+
* [Repo](https://source.android.com/docs/setup/reference/repo)
|
18
|
+
|
19
|
+
```sh
|
20
|
+
mkdir -p ~/.bin
|
21
|
+
PATH="${HOME}/.bin:${PATH}"
|
22
|
+
curl https://storage.googleapis.com/git-repo-downloads/repo > ~/.bin/repo
|
23
|
+
chmod a+rx ~/.bin/repo
|
24
|
+
```
|
25
|
+
|
26
|
+
## Example - Rakefile
|
27
|
+
|
28
|
+
```ruby
|
29
|
+
require "squared"
|
30
|
+
|
31
|
+
Repo::Workspace
|
32
|
+
.new("squared")
|
33
|
+
.repo("https://github.com/anpham6/squared-repo", "nightly")
|
34
|
+
.add(:pathname, run: "rake compile", copy: "rake install", clean: "rake clean", ref: :ruby, group: "default") # Ruby
|
35
|
+
.add(:optparse, group: "default")
|
36
|
+
.add(:emc, "e-mc", copy: { from: "publish", into: "@e-mc", also: [:pir] }) # Node
|
37
|
+
.add(:pir, "pi-r", copy: { from: "publish", into: "@pi-r" })
|
38
|
+
.add(:squared)
|
39
|
+
.build(parallel: %i[pull fetch rebase copy clean])
|
40
|
+
```
|
41
|
+
|
42
|
+
## Usage
|
43
|
+
|
44
|
+
```sh
|
45
|
+
rake -T
|
46
|
+
```
|
47
|
+
|
48
|
+
## LICENSE
|
49
|
+
|
50
|
+
BSD 3-Clause
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Squared
|
4
|
+
module Common
|
5
|
+
class JoinSet < ::Set
|
6
|
+
def initialize(data = [], delim: ' ')
|
7
|
+
super(data.compact)
|
8
|
+
@delim = delim
|
9
|
+
end
|
10
|
+
|
11
|
+
def done
|
12
|
+
ret = to_a.map!(&:to_s).reject(&:empty?).join(@delim)
|
13
|
+
clear
|
14
|
+
ret
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,151 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Squared
|
4
|
+
module Common
|
5
|
+
module Format
|
6
|
+
def emphasize(val, title: nil, cols: nil, sub: nil)
|
7
|
+
n = 0
|
8
|
+
if title
|
9
|
+
title = title.to_s
|
10
|
+
n = title.size
|
11
|
+
end
|
12
|
+
if val.is_a?(::Array)
|
13
|
+
lines = val
|
14
|
+
else
|
15
|
+
lines = val.to_s.lines.map(&:chomp)
|
16
|
+
lines[0] = "#{val.class}: #{lines.first}" if (err = val.is_a?(::StandardError))
|
17
|
+
end
|
18
|
+
n = cols || [n, lines.max_by(&:size).size].max
|
19
|
+
if $stdout.tty?
|
20
|
+
require 'io/console'
|
21
|
+
(n = [n, $stdout.winsize[1] - 4].min) rescue nil
|
22
|
+
end
|
23
|
+
bord = '-' * (n + 4)
|
24
|
+
write = ->(line) { err ? warn(line) : puts(line) }
|
25
|
+
sub = as_a(sub)
|
26
|
+
pr = lambda do |line|
|
27
|
+
s = line.ljust(n)
|
28
|
+
sub.each { |h| s = sub_style(s, **h) }
|
29
|
+
"| #{s} |"
|
30
|
+
end
|
31
|
+
write.(bord)
|
32
|
+
if title
|
33
|
+
write.(pr.(title))
|
34
|
+
write.(bord)
|
35
|
+
end
|
36
|
+
lines.each { |line| write.(pr.(line)) }
|
37
|
+
write.(bord)
|
38
|
+
end
|
39
|
+
|
40
|
+
def sub_style(val, *args, pat: nil, styles: nil, index: 1)
|
41
|
+
return val unless ENV['NO_COLOR'].to_s.empty?
|
42
|
+
|
43
|
+
if pat && index != 0
|
44
|
+
return val unless (data = pat.match(val))
|
45
|
+
|
46
|
+
ret = index == -1 ? data.to_a[1..-1] : data[index]
|
47
|
+
else
|
48
|
+
ret = val
|
49
|
+
index = 0
|
50
|
+
end
|
51
|
+
wrap = ->(s, n) { "\x1B[#{n.join(';')}m#{s}\x1B[0m" }
|
52
|
+
code = []
|
53
|
+
args.concat(as_a(styles)).each_with_index do |type, i|
|
54
|
+
next unless type
|
55
|
+
|
56
|
+
if index == -1
|
57
|
+
s = ret[i]
|
58
|
+
next ret[i] = '' if s.nil?
|
59
|
+
else
|
60
|
+
s = ret
|
61
|
+
end
|
62
|
+
case (t = type.to_sym)
|
63
|
+
when :bold
|
64
|
+
s = "\x1B[1m#{s}\x1B[22m"
|
65
|
+
when :italic
|
66
|
+
s = "\x1B[3m#{s}\x1B[23m"
|
67
|
+
when :underline
|
68
|
+
s = "\x1B[4m#{s}\x1B[24m"
|
69
|
+
else
|
70
|
+
if (c = get(:colors)[t])
|
71
|
+
if index == -1
|
72
|
+
s = wrap.(s, [c])
|
73
|
+
else
|
74
|
+
code << c
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
if index == -1
|
79
|
+
ret[i] = s
|
80
|
+
else
|
81
|
+
ret = s
|
82
|
+
end
|
83
|
+
end
|
84
|
+
return ret.join if index == -1
|
85
|
+
|
86
|
+
ret = wrap.(ret, code) unless code.empty?
|
87
|
+
return ret unless data
|
88
|
+
|
89
|
+
out = +''
|
90
|
+
data.to_a.each_with_index do |group, i|
|
91
|
+
next if i == 0
|
92
|
+
|
93
|
+
if i == index
|
94
|
+
out << ret
|
95
|
+
elsif !group.nil?
|
96
|
+
out << group
|
97
|
+
end
|
98
|
+
end
|
99
|
+
out
|
100
|
+
end
|
101
|
+
|
102
|
+
def check_style(iter, empty: true)
|
103
|
+
ret = []
|
104
|
+
colors = get(:colors)
|
105
|
+
as_a(iter).each do |val|
|
106
|
+
case (val = val.to_sym)
|
107
|
+
when :bold, :italic, :underline
|
108
|
+
ret << val
|
109
|
+
else
|
110
|
+
ret << val if colors.key?(val)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
!empty && ret.empty? ? nil : ret
|
114
|
+
end
|
115
|
+
|
116
|
+
def log_title(level, color: true)
|
117
|
+
level = if level.is_a?(::Numeric)
|
118
|
+
case level
|
119
|
+
when Logger::DEBUG
|
120
|
+
:debug
|
121
|
+
when Logger::INFO
|
122
|
+
:info
|
123
|
+
when Logger::WARN
|
124
|
+
:warn
|
125
|
+
when Logger::ERROR
|
126
|
+
:error
|
127
|
+
when Logger::FATAL
|
128
|
+
:fatal
|
129
|
+
else
|
130
|
+
:unknown
|
131
|
+
end
|
132
|
+
else
|
133
|
+
level.to_s.downcase.to_sym
|
134
|
+
end
|
135
|
+
val = get(:logger)[level] || get(:logger)[level = :unknown]
|
136
|
+
level = +level.to_s.upcase
|
137
|
+
case level
|
138
|
+
when 'WARN', 'ERROR', 'FATAL'
|
139
|
+
level += '!'
|
140
|
+
end
|
141
|
+
color ? sub_style(level, *val) : level
|
142
|
+
end
|
143
|
+
|
144
|
+
def log_message(level, *args, subject: nil, hint: nil, color: true)
|
145
|
+
msg = [log_title(level, color: color)]
|
146
|
+
msg << (color ? sub_style(subject, :underline) : subject) if subject
|
147
|
+
message(msg.join(' '), *args, hint: hint)
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Squared
|
4
|
+
module Common
|
5
|
+
module Shell
|
6
|
+
def shell_escape(val)
|
7
|
+
return val if ::Rake::Win32.windows?
|
8
|
+
|
9
|
+
Shellwords.escape(val)
|
10
|
+
end
|
11
|
+
|
12
|
+
def shell_quote(val, force: true)
|
13
|
+
ret = val.to_s.strip
|
14
|
+
return ret if (!force && !ret.include?(' ')) || /(?:^|=)(["']).+\1$/m.match?(ret)
|
15
|
+
|
16
|
+
::Rake::Win32.windows? ? "\"#{double_quote(ret)}\"" : "'#{single_quote(ret)}'"
|
17
|
+
end
|
18
|
+
|
19
|
+
def single_quote(val)
|
20
|
+
val.gsub("'", "'\\\\''")
|
21
|
+
end
|
22
|
+
|
23
|
+
def double_quote(val)
|
24
|
+
val.gsub(/(?<!\\)"/, '\\"')
|
25
|
+
end
|
26
|
+
|
27
|
+
def split_escape(val, char: ',')
|
28
|
+
val.split(/\s*(?<!\\)#{char}\s*/)
|
29
|
+
end
|
30
|
+
|
31
|
+
def trailing_slash(val)
|
32
|
+
val.to_s.chomp(::File::SEPARATOR) + ::File::SEPARATOR
|
33
|
+
end
|
34
|
+
|
35
|
+
def sanitize_args(*opts)
|
36
|
+
opts.map { |val| val.include?(' ') ? shell_quote(val) : shell_escape(val) }.join(' ')
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Squared
|
4
|
+
module Common
|
5
|
+
module System
|
6
|
+
def shell(*cmd, **kwargs)
|
7
|
+
if /^2\.[0-5]\./.match?(RUBY_VERSION)
|
8
|
+
exception = kwargs.delete(:exception)
|
9
|
+
ret = system(*cmd, **kwargs)
|
10
|
+
raise $?.to_s if !ret && exception
|
11
|
+
|
12
|
+
ret
|
13
|
+
else
|
14
|
+
system(*cmd, **kwargs)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def copy_d(src, dest, glob: ['**/*'], create: false, verbose: true)
|
19
|
+
raise message(src, dest, hint: 'not found') if !create && !dest.exist?
|
20
|
+
|
21
|
+
subdir = []
|
22
|
+
files = 0
|
23
|
+
dest.mkpath if create
|
24
|
+
as_a(glob).each do |val|
|
25
|
+
Dir.glob(src.join(val)) do |path|
|
26
|
+
ent = Pathname.new(path)
|
27
|
+
next if ent.directory?
|
28
|
+
|
29
|
+
target = dest.join(ent.relative_path_from(src))
|
30
|
+
dir = target.dirname
|
31
|
+
if !subdir.include?(dir.to_s)
|
32
|
+
dir.mkpath
|
33
|
+
subdir << dir.to_s
|
34
|
+
end
|
35
|
+
copy_f ent, target
|
36
|
+
files += 1
|
37
|
+
end
|
38
|
+
end
|
39
|
+
puts message(dest.realpath, subdir.size.to_s, files.to_s) if verbose
|
40
|
+
end
|
41
|
+
|
42
|
+
def copy_f(src, dest, overwrite: true, verbose: false)
|
43
|
+
if !overwrite
|
44
|
+
path = Pathname.new(dest)
|
45
|
+
if path.directory?
|
46
|
+
src = as_a(src).reject { |val| path.join(File.basename(val)).exist? }
|
47
|
+
elsif path.exist?
|
48
|
+
return
|
49
|
+
end
|
50
|
+
end
|
51
|
+
FileUtils.cp(src, dest, verbose: verbose)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Squared
|
4
|
+
module Common
|
5
|
+
module Task
|
6
|
+
def collect_args(args, *keys)
|
7
|
+
ret = []
|
8
|
+
return ret unless args.is_a?(::Rake::TaskArguments)
|
9
|
+
|
10
|
+
keys.each { |key| ret << args[key] if args[key] }
|
11
|
+
ret += args.extras
|
12
|
+
end
|
13
|
+
|
14
|
+
def invoke(name, *args, exception: true)
|
15
|
+
::Rake::Task[name].invoke(*args)
|
16
|
+
rescue StandardError => e
|
17
|
+
raise if exception
|
18
|
+
|
19
|
+
warn e
|
20
|
+
end
|
21
|
+
|
22
|
+
def invoked?(name)
|
23
|
+
::Rake::Task.tasks.any? { |item| item.already_invoked && item.name == name.to_s }
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'pathname'
|
4
|
+
require 'shellwords'
|
5
|
+
require 'logger'
|
6
|
+
require 'set'
|
7
|
+
require 'rake'
|
8
|
+
|
9
|
+
module Squared
|
10
|
+
module Common
|
11
|
+
VAR = {
|
12
|
+
project: {},
|
13
|
+
logger: {
|
14
|
+
unknown: %i[cyan],
|
15
|
+
fatal: %i[white bold red!],
|
16
|
+
error: %i[red bold],
|
17
|
+
warn: %i[yellow bold],
|
18
|
+
info: %i[blue],
|
19
|
+
debug: %i[green]
|
20
|
+
},
|
21
|
+
colors: {
|
22
|
+
black: '30',
|
23
|
+
red: '31',
|
24
|
+
green: '32',
|
25
|
+
yellow: '33',
|
26
|
+
blue: '34',
|
27
|
+
magenta: '35',
|
28
|
+
cyan: '36',
|
29
|
+
white: '37',
|
30
|
+
black!: '40',
|
31
|
+
red!: '41',
|
32
|
+
green!: '42',
|
33
|
+
yellow!: '43',
|
34
|
+
blue!: '44',
|
35
|
+
magenta!: '45',
|
36
|
+
cyan!: '46',
|
37
|
+
white!: '47'
|
38
|
+
}.freeze
|
39
|
+
}
|
40
|
+
private_constant :VAR
|
41
|
+
|
42
|
+
def get(key)
|
43
|
+
VAR[key.is_a?(::String) ? key.to_sym : key]
|
44
|
+
end
|
45
|
+
|
46
|
+
def set(key, val)
|
47
|
+
VAR[key.is_a?(::String) ? key.to_sym : key] = val
|
48
|
+
end
|
49
|
+
|
50
|
+
def message(*args, hint: nil)
|
51
|
+
args.reject(&:empty?).join(' => ') + (hint ? " (#{hint})" : '')
|
52
|
+
end
|
53
|
+
|
54
|
+
def as_a(obj)
|
55
|
+
return [] if obj.nil?
|
56
|
+
|
57
|
+
obj.is_a?(::Array) ? obj : [obj]
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
require_relative 'common/class'
|
63
|
+
require_relative 'common/format'
|
64
|
+
require_relative 'common/shell'
|
65
|
+
require_relative 'common/system'
|
66
|
+
require_relative 'common/task'
|
@@ -0,0 +1,240 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Squared
|
4
|
+
module Config
|
5
|
+
class Viewer
|
6
|
+
include Common
|
7
|
+
include Format
|
8
|
+
include Task
|
9
|
+
include ::Rake::DSL
|
10
|
+
|
11
|
+
class << self
|
12
|
+
include Common::Format
|
13
|
+
|
14
|
+
attr_reader :styles
|
15
|
+
|
16
|
+
def style(name, *args)
|
17
|
+
args = check_style(args)
|
18
|
+
styles[name.to_sym]&.clear&.concat(args)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
@styles = {
|
23
|
+
banner: %i[blue],
|
24
|
+
key: %i[bold],
|
25
|
+
value: %i[green],
|
26
|
+
string: %i[yellow],
|
27
|
+
hash: %i[green black!],
|
28
|
+
array: %i[blue black!],
|
29
|
+
number: %i[magenta],
|
30
|
+
undefined: %i[red italic]
|
31
|
+
}.freeze
|
32
|
+
|
33
|
+
attr_reader :main, :project, :name
|
34
|
+
|
35
|
+
def initialize(main = 'package', project: nil, name: nil)
|
36
|
+
if project
|
37
|
+
@project = get(:project)[project.to_sym]
|
38
|
+
@required = true
|
39
|
+
end
|
40
|
+
@name = (name || @project&.name)&.to_s
|
41
|
+
unless @name
|
42
|
+
msg, hint = project ? [project, 'not found'] : %w[name missing]
|
43
|
+
warn log_message(:warn, msg, subject: 'Config::Viewer', hint: hint, color: !pipe?)
|
44
|
+
@required = true
|
45
|
+
end
|
46
|
+
@main = main
|
47
|
+
@include = {}
|
48
|
+
end
|
49
|
+
|
50
|
+
def build
|
51
|
+
return unless enabled?
|
52
|
+
|
53
|
+
namespace @name do
|
54
|
+
namespace :view do
|
55
|
+
if @include['json'] && !::Rake::Task.task_defined?("#{@name}:view:json")
|
56
|
+
desc format_desc('json')
|
57
|
+
task :json, [:keys] do |_, args|
|
58
|
+
require 'json'
|
59
|
+
read_keys JSON, 'json', args.keys, args.extras
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
if @include['yaml'] && !::Rake::Task.task_defined?("#{@name}:view:yaml")
|
64
|
+
desc format_desc('yaml', 'yml')
|
65
|
+
task :yaml, [:keys] do |_, args|
|
66
|
+
require 'yaml'
|
67
|
+
read_keys YAML, 'yaml', args.keys, args.extras, 'yml', 'yaml'
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def add(type, gem: nil, parse: nil, ext: [], opts: {}, command: nil, file: nil)
|
75
|
+
type = type.to_s
|
76
|
+
if parse && enabled?
|
77
|
+
require(gem || type)
|
78
|
+
obj = eval(parse)
|
79
|
+
ext = as_a(ext)
|
80
|
+
namespace @name do
|
81
|
+
desc format_desc(ext.first || type, command: command)
|
82
|
+
namespace(command || :view) do
|
83
|
+
task type, [:keys] do |_, args|
|
84
|
+
if file
|
85
|
+
read_keys obj, type, file.to_s, collect_args(args, :keys), *ext
|
86
|
+
else
|
87
|
+
read_keys obj, type, args.keys, args.extras, *ext
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
rescue LoadError, NameError
|
94
|
+
self
|
95
|
+
else
|
96
|
+
@include[type] = opts
|
97
|
+
self
|
98
|
+
end
|
99
|
+
|
100
|
+
def also(path, type = nil, name: nil, gem: nil, parse: nil, opts: {})
|
101
|
+
return self unless (file = base_path(path)).exist?
|
102
|
+
|
103
|
+
ext = chop_extname(file).downcase
|
104
|
+
name ||= file.basename.to_s.chomp(".#{ext}")
|
105
|
+
type = (type || ext).to_s
|
106
|
+
if !parse
|
107
|
+
case type
|
108
|
+
when 'json'
|
109
|
+
parse = 'JSON'
|
110
|
+
when 'yaml', 'yml'
|
111
|
+
type = 'yaml'
|
112
|
+
parse = 'YAML'
|
113
|
+
end
|
114
|
+
end
|
115
|
+
add(type, gem: gem, parse: parse, ext: ext, opts: opts, command: name, file: file)
|
116
|
+
end
|
117
|
+
|
118
|
+
def enabled?
|
119
|
+
!@required || !!@project&.enabled?
|
120
|
+
end
|
121
|
+
|
122
|
+
protected
|
123
|
+
|
124
|
+
def read_keys(reader, type, file, keys, *ext)
|
125
|
+
path = base_path(file)
|
126
|
+
fmt = chop_extname(file)
|
127
|
+
ext << type if ext.empty?
|
128
|
+
if path.exist? && path.basename.to_s.include?('.')
|
129
|
+
raise ArgumentError, message(file, fmt, hint: 'invalid') unless ext.include?(fmt)
|
130
|
+
else
|
131
|
+
if ext.include?(fmt)
|
132
|
+
alt = file
|
133
|
+
file = nil
|
134
|
+
ext[0] = fmt
|
135
|
+
else
|
136
|
+
keys.unshift(file)
|
137
|
+
alt = "#{@main}.{#{ext.join(',')}}"
|
138
|
+
alt = @project.base_path(alt) if @project
|
139
|
+
file = Dir[alt].first
|
140
|
+
end
|
141
|
+
if !file
|
142
|
+
raise ArgumentError, message(reader.name, "#{File.basename(alt, '.*')}.#{ext.first}", hint: 'not found')
|
143
|
+
end
|
144
|
+
end
|
145
|
+
doc = if reader.respond_to?(:load_file)
|
146
|
+
reader.load_file(file, **@include[type])
|
147
|
+
else
|
148
|
+
reader.parse(File.read(file), **@include[type])
|
149
|
+
end
|
150
|
+
lines = print_keys(type, doc, keys)
|
151
|
+
return unless lines
|
152
|
+
|
153
|
+
title = Pathname.new(file)
|
154
|
+
.realpath
|
155
|
+
.to_s
|
156
|
+
.sub(/^#{Regexp.escape(Dir.pwd + ::File::SEPARATOR)}/, '')
|
157
|
+
sub = if pipe?
|
158
|
+
nil
|
159
|
+
else
|
160
|
+
[
|
161
|
+
{ pat: /^([^:]+|(?<! ):(?! ))+$/, styles: Viewer.styles[:banner] },
|
162
|
+
{ pat: /^(.*?)(<[^>]+>)(.+)$/m, styles: Viewer.styles[:undefined], index: 2 },
|
163
|
+
{ pat: /^(.+)( : (?!undefined))(.+)$/m, styles: Viewer.styles[:key] },
|
164
|
+
{ pat: /^(.+)( : )(-?[\d.]+)(\s*)$/m, styles: Viewer.styles[:number], index: 3 },
|
165
|
+
{ pat: /^(.+)( : ")(.+)("\s*)$/m, styles: Viewer.styles[:string], index: 3 },
|
166
|
+
{ pat: /^(.+)( : \{)(.+)(\}\s*)$/m, styles: Viewer.styles[:hash], index: 3 },
|
167
|
+
{ pat: /^(.+)( : \[)(.+)(\]\s*)$/m, styles: Viewer.styles[:array], index: 3 },
|
168
|
+
{ pat: /^(.+)( : (?!undefined))([^"\[{].*)$/m, styles: Viewer.styles[:value], index: 3 }
|
169
|
+
]
|
170
|
+
end
|
171
|
+
emphasize(lines, title: title, sub: sub)
|
172
|
+
end
|
173
|
+
|
174
|
+
def print_keys(type, data, keys)
|
175
|
+
out = []
|
176
|
+
pad = 0
|
177
|
+
symbolize = @include[type][:symbolize_names]
|
178
|
+
keys.each do |key|
|
179
|
+
begin
|
180
|
+
items = key.split('.')
|
181
|
+
items = items.map(&:to_sym) if symbolize
|
182
|
+
val = data.dig(*items)
|
183
|
+
if val.nil?
|
184
|
+
val = data
|
185
|
+
items.each do |name|
|
186
|
+
raise name unless val.is_a?(::Hash) && val.key?(name)
|
187
|
+
|
188
|
+
val = val[name]
|
189
|
+
end
|
190
|
+
end
|
191
|
+
rescue StandardError
|
192
|
+
val = Regexp.escape($!.message)
|
193
|
+
key = key.sub(/(#{val})\.|\.(#{val})|(#{val})/) do
|
194
|
+
s = "<#{$3 || $2 || $1}>"
|
195
|
+
if $3
|
196
|
+
s
|
197
|
+
else
|
198
|
+
$2 ? ".#{s}" : "#{s}."
|
199
|
+
end
|
200
|
+
end
|
201
|
+
out << [key, 'undefined']
|
202
|
+
else
|
203
|
+
out << [key, val.inspect]
|
204
|
+
end
|
205
|
+
pad = key.size if key.size > pad
|
206
|
+
end
|
207
|
+
if pipe?
|
208
|
+
out = out.map do |item|
|
209
|
+
val = item.last
|
210
|
+
val.start_with?('"') && val.end_with?('"') ? val[1..-2] : val
|
211
|
+
end
|
212
|
+
puts out.join("\n")
|
213
|
+
else
|
214
|
+
out.map { |item| "#{item.first.ljust(pad)} : #{item.last}" }
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
def base_path(file)
|
219
|
+
@project ? @project.base_path(file) : Pathname.new(file).realdirpath
|
220
|
+
end
|
221
|
+
|
222
|
+
def format_desc(type, alt = nil, command: nil)
|
223
|
+
message(@name, command || 'view', "#{type}[#{command.nil? ? "file?=#{@main}.#{alt || type}," : ''}keys*]")
|
224
|
+
end
|
225
|
+
|
226
|
+
def chop_extname(file)
|
227
|
+
File.extname(file).sub('.', '')
|
228
|
+
end
|
229
|
+
|
230
|
+
def pipe?
|
231
|
+
return @project.workspace.pipe? if @project
|
232
|
+
|
233
|
+
val = ENV['PIPE_OUT']
|
234
|
+
!val.nil? && !val.empty? && val != '0'
|
235
|
+
end
|
236
|
+
end
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
Viewer = Squared::Config::Viewer
|