Skip to content

Commit aab1eb6

Browse files
committed
bin/lkp: add subcommand to view monitor/setup/test
Signed-off-by: Philip Li <philip.li@intel.com>
1 parent 3bd9c34 commit aab1eb6

4 files changed

Lines changed: 227 additions & 15 deletions

File tree

bin/lkp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,12 @@ case "$lkp_command" in
3535
'merge') lkp_command='merge-remote-result' ;;
3636
'run-monitor') lkp_command='run-local-monitor.sh' ;;
3737
'stop-monitor') TMP=/tmp/lkp $LKP_SRC/bin/event/wakeup default-monitors; exit $? ;;
38+
'monitor'|'setup'|'test'|'daemon')
39+
exec "$LKP_SRC/bin/lkp-programs" "$lkp_command" "$@"
40+
;;
41+
'path'|'depends')
42+
exec "$LKP_SRC/bin/lkp-programs" "$lkp_command" "$@"
43+
;;
3844
'run')
3945
if echo "$*" | grep '\.sh$' >/dev/null; then
4046
lkp_command='run-local.sh'
@@ -55,7 +61,7 @@ try_run()
5561
try_run2()
5662
{
5763
local subdir="$1"
58-
local path="$(find "$LKP_SRC/$subdir" -name "$lkp_command" -type f)"
64+
local path="$(find "$LKP_SRC/$subdir" -name "$lkp_command" -print -quit | head -n 1)"
5965
shift
6066

6167
[ -x "$path" ] && exec "$path" $lkp_args "$@"

bin/lkp-programs

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
#!/usr/bin/env ruby
2+
3+
LKP_SRC = ENV['LKP_SRC'] || File.expand_path('..', __dir__)
4+
5+
require "#{LKP_SRC}/lib/programs"
6+
require 'yaml'
7+
8+
command = ARGV.shift
9+
subcommand = ARGV.shift
10+
11+
def list_programs(type, verbose)
12+
programs = case type
13+
when 'setup'
14+
LKP::Programs.all_setups
15+
when 'test'
16+
LKP::Programs.all_tests
17+
when 'monitor'
18+
LKP::Programs.all_monitors
19+
when 'daemon'
20+
LKP::Programs.all_daemons
21+
end.sort.uniq
22+
23+
if verbose
24+
programs.each do |prog|
25+
meta = LKP::Programs.find_meta(prog)
26+
desc = ''
27+
if meta
28+
begin
29+
yaml = YAML.load_file(meta)
30+
desc = " - #{yaml['short_description'].to_s.strip.split("\n").first}" if yaml && yaml['short_description']
31+
rescue StandardError
32+
nil
33+
end
34+
end
35+
printf("%-20s %s\n", prog, desc)
36+
end
37+
else
38+
puts programs
39+
end
40+
end
41+
42+
def find_program_path(type, program)
43+
if type
44+
case type
45+
when 'setup'
46+
LKP::Programs.find_setup(program)
47+
when 'test'
48+
LKP::Programs.find_runner(program)
49+
when 'monitor'
50+
LKP::Programs.find_monitor(program)
51+
when 'daemon'
52+
LKP::Programs.find_daemon(program)
53+
end
54+
else
55+
LKP::Programs.find_runner(program) ||
56+
LKP::Programs.find_setup(program) ||
57+
LKP::Programs.find_monitor(program) ||
58+
LKP::Programs.find_daemon(program)
59+
end
60+
end
61+
62+
if command == 'path'
63+
target = subcommand
64+
path = find_program_path(nil, target)
65+
if path
66+
puts path
67+
exit 0
68+
else
69+
warn "lkp path #{target}: no executable path found"
70+
exit 1
71+
end
72+
elsif command == 'depends'
73+
target = subcommand
74+
depends_file = LKP::Programs.find_depends_file(target)
75+
if depends_file
76+
puts File.read(depends_file)
77+
exit 0
78+
else
79+
warn "lkp depends #{target}: no dependencies documented"
80+
exit 1
81+
end
82+
elsif ['ls'].include?(subcommand)
83+
verbose = ARGV.include?('-v') || ARGV.include?('--verbose')
84+
list_programs(command, verbose)
85+
exit 0
86+
elsif ['path'].include?(subcommand)
87+
target = ARGV.shift
88+
path = find_program_path(command, target)
89+
if path
90+
puts path
91+
exit 0
92+
else
93+
warn "lkp #{command} path #{target}: no executable path found"
94+
exit 1
95+
end
96+
elsif ['depends'].include?(subcommand)
97+
target = ARGV.shift
98+
depends_file = LKP::Programs.find_depends_file(target)
99+
if depends_file
100+
puts File.read(depends_file)
101+
exit 0
102+
else
103+
warn "lkp #{command} depends #{target}: no dependencies documented"
104+
exit 1
105+
end
106+
elsif [nil, 'help', '--help', '-h'].include?(subcommand)
107+
puts "Usage: lkp #{command} <command> [options]"
108+
puts ''
109+
puts 'Commands:'
110+
puts " ls [-v|--verbose] List all available #{command}s"
111+
puts " path <program> Print the absolute path to the #{command} executable"
112+
puts " depends <program> Print package dependencies required for #{command}"
113+
puts ' <program> --help Show meta.yaml for <program>'
114+
exit 0
115+
elsif ARGV.include?('--help') || ARGV.include?('-h')
116+
meta_file = LKP::Programs.find_meta(subcommand)
117+
if meta_file
118+
puts File.read(meta_file)
119+
exit 0
120+
else
121+
warn "lkp #{command} #{subcommand}: no meta.yaml found"
122+
exit 1
123+
end
124+
else
125+
warn "lkp #{command}: unknown command/program '#{subcommand}'"
126+
warn "See 'lkp #{command} help' for usage."
127+
exit 1
128+
end

lib/programs.rb

Lines changed: 55 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,23 +9,51 @@ class Programs
99
PROGRAMS_ROOT = File.join(LKP_SRC, 'programs').freeze
1010

1111
class << self
12+
def collect_programs(lkp_src_pattern, programs_pattern, executable_only: false)
13+
lkp_files = Dir["#{LKP_SRC}/#{lkp_src_pattern}"]
14+
prog_files = Dir["#{PROGRAMS_ROOT}/#{programs_pattern}"]
15+
16+
if executable_only
17+
lkp_files.select! { |p| File.file?(p) && File.executable?(p) }
18+
prog_files.select! { |p| File.file?(p) && File.executable?(p) }
19+
end
20+
21+
(lkp_files || []).map { |path| File.basename(path) } + (prog_files || []).map { |path| path.split('/')[-2] }
22+
end
23+
24+
def find_executable(program, lkp_dir, *prog_names)
25+
[
26+
*prog_names.map { |n| "#{PROGRAMS_ROOT}/#{program}/#{n}" },
27+
"#{LKP_SRC}/#{lkp_dir}/#{program}"
28+
].find { |file| File.exist?(file) }
29+
end
30+
1231
def all_stats
13-
Dir["#{LKP_SRC}/stats/**/*"].map { |path| File.basename path } +
14-
Dir["#{PROGRAMS_ROOT}/*/parse"].map { |path| path.split('/')[-2] }
32+
collect_programs('stats/**/*', '*/parse')
1533
end
1634

1735
alias all_parser_names all_stats
1836

1937
def all_tests
20-
Dir["#{LKP_SRC}/tests/**/*"].map { |path| File.basename path } +
21-
Dir["#{PROGRAMS_ROOT}/*/run"].map { |path| path.split('/')[-2] }
38+
collect_programs('tests/**/*', '*/run')
2239
end
2340

2441
alias all_runner_names all_tests
2542

43+
def all_monitors
44+
collect_programs('monitors/*', '*/{monitor,no-stdout-monitor,one-shot-monitor}', executable_only: true)
45+
end
46+
47+
def all_setups
48+
collect_programs('setup/**/*', '*/setup', executable_only: true)
49+
end
50+
51+
def all_daemons
52+
collect_programs('daemon/**/*', '*/daemon', executable_only: true)
53+
end
54+
2655
def all_tests_and_daemons
27-
all_tests + Dir["#{LKP_SRC}/daemon/**/*"].map { |path| File.basename path } +
28-
Dir["#{PROGRAMS_ROOT}/*/daemon"].map { |path| path.split('/')[-2] }
56+
all_tests + all_daemons
2957
end
3058

3159
def all_tests_set
@@ -36,18 +64,31 @@ def all_metas
3664
Dir["#{LKP_SRC}/tests/*.yaml"] + Dir["#{PROGRAMS_ROOT}/*/meta.yaml"]
3765
end
3866

39-
def find_parser(program)
67+
def find_meta(program)
4068
[
41-
"#{PROGRAMS_ROOT}/#{program}/parse",
42-
"#{LKP_SRC}/stats/#{program}"
43-
].find { |file| File.exist? file }
69+
"#{PROGRAMS_ROOT}/#{program}/meta.yaml",
70+
"#{LKP_SRC}/tests/#{program}.yaml"
71+
].find { |file| File.exist?(file) }
72+
end
73+
74+
def find_parser(program)
75+
find_executable(program, 'stats', 'parse')
76+
end
77+
78+
def find_setup(program)
79+
find_executable(program, 'setup', 'setup')
80+
end
81+
82+
def find_monitor(program)
83+
find_executable(program, 'monitors', 'monitor', 'no-stdout-monitor', 'one-shot-monitor')
84+
end
85+
86+
def find_daemon(program)
87+
find_executable(program, 'daemon', 'daemon')
4488
end
4589

4690
def find_runner(program)
47-
[
48-
"#{PROGRAMS_ROOT}/#{program}/run",
49-
"#{LKP_SRC}/tests/#{program}"
50-
].find { |file| File.exist? file }
91+
find_executable(program, 'tests', 'run')
5192
end
5293

5394
# program: turbostat, turbostat-dev

spec/programs_spec.rb

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,14 @@
2121

2222
# Regular daemon
2323
FileUtils.touch("#{@lkp_src}/daemon/olddaemon")
24+
FileUtils.chmod(0o755, "#{@lkp_src}/daemon/olddaemon")
25+
FileUtils.chmod(0o755, "#{@lkp_src}/daemon/olddaemon")
2426

2527
# Program daemon (the bug reproduction case)
2628
FileUtils.mkdir_p("#{@lkp_src}/programs/newdaemon")
2729
FileUtils.touch("#{@lkp_src}/programs/newdaemon/daemon")
30+
FileUtils.chmod(0o755, "#{@lkp_src}/programs/newdaemon/daemon")
31+
FileUtils.chmod(0o755, "#{@lkp_src}/programs/newdaemon/daemon")
2832
end
2933

3034
before do
@@ -55,4 +59,37 @@
5559
expect(described_class.all_tests_and_daemons).to include('newdaemon')
5660
end
5761
end
62+
63+
describe '.collect_programs' do
64+
it 'returns mapped lkp_files and prog_files' do
65+
res = described_class.collect_programs('tests/*', '*/run')
66+
expect(res).to include('mytest', 'progtest')
67+
end
68+
69+
it 'filters non-executable files if executable_only is true' do
70+
FileUtils.mkdir_p("#{@lkp_src}/custom")
71+
FileUtils.touch("#{@lkp_src}/custom/exe_file")
72+
FileUtils.chmod(0o755, "#{@lkp_src}/custom/exe_file")
73+
FileUtils.touch("#{@lkp_src}/custom/non_exe_file")
74+
75+
FileUtils.mkdir_p("#{@lkp_src}/programs/custom_prog")
76+
FileUtils.touch("#{@lkp_src}/programs/custom_prog/custom_run")
77+
FileUtils.chmod(0o755, "#{@lkp_src}/programs/custom_prog/custom_run")
78+
79+
FileUtils.mkdir_p("#{@lkp_src}/programs/bad_prog")
80+
FileUtils.touch("#{@lkp_src}/programs/bad_prog/custom_run")
81+
82+
res = described_class.collect_programs('custom/*', '*/custom_run', executable_only: true)
83+
84+
expect(res).to include('exe_file', 'custom_prog')
85+
expect(res).not_to include('non_exe_file', 'bad_prog')
86+
end
87+
end
88+
89+
describe '.find_executable' do
90+
it 'finds an executable dynamically' do
91+
path = described_class.find_executable('progtest', 'tests', 'run')
92+
expect(path).to end_with('programs/progtest/run')
93+
end
94+
end
5895
end

0 commit comments

Comments
 (0)