headdesk 0.10.0 → 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9067a4b373fd01b502fd6cb77fafc2bd1c60e9d18aef42390832e855bf6437e8
4
- data.tar.gz: 3eccbb70deffe105e84a5ae0bfd6aecf8977ae9d9399665863570681fa92933a
3
+ metadata.gz: 1cb06518f9ed0ec0293c645af5598133a19791c575093359b56cf87e787233de
4
+ data.tar.gz: 6a0bd907a2c18c63098029cb30956c8ebe903529b34738cf61a2b1b61d3b0983
5
5
  SHA512:
6
- metadata.gz: 046264add67d0b39f07a5d57eb95372fd5b0ba5278443c17768aade9932a3c2a868454f25a239df242644f61b4ec766370aed860ef8944a64012c8de6726dace
7
- data.tar.gz: eac8f28b1aa2ddc80bb30369f9b384dc2c6928a611720b16b914705498d448feaa10e66a90cf19c98e646f64d17595f33df2d3d24e2468f2eeeb3249c0082f87
6
+ metadata.gz: bf63bee2c75af483978333022c08fcdcdd61d3abab31f979445ef2766287baf9a750d3303e9538358d29c7152ea44e76a8a0aadd429cf8a671f7b4b6c4ef0f00
7
+ data.tar.gz: 20d878b5cf28dbe13ad88b838143a9da3ca62ee3693b39db205c2975f3edecc3f1e81ca9ef1657c1efa9052446e299c59bcd50c9672d6dcf7655637b097c73a5
data/.reek.yml CHANGED
@@ -5,6 +5,8 @@ detectors:
5
5
  - 'apk.resources'
6
6
  - 'Thor::Base.shell'
7
7
  - 'CLI.command_help'
8
+ - 'exit'
8
9
  TooManyStatements:
9
10
  exclude:
10
11
  - 'Headdesk::Checks'
12
+ - 'Headdesk::CliCommands'
data/Gemfile CHANGED
@@ -4,8 +4,5 @@ source 'https://rubygems.org'
4
4
 
5
5
  git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
6
6
 
7
- gem 'reek'
8
- gem 'rubocop'
9
-
10
7
  # Specify your gem's dependencies in headdesk.gemspec
11
8
  gemspec
data/Gemfile.lock CHANGED
@@ -26,6 +26,7 @@ GEM
26
26
  thread_safe (~> 0.3, >= 0.3.1)
27
27
  diff-lcs (1.3)
28
28
  equalizer (0.0.11)
29
+ gem-release (2.0.1)
29
30
  gems (1.1.1)
30
31
  json
31
32
  ice_nine (0.11.2)
@@ -37,7 +38,7 @@ GEM
37
38
  mini_portile2 (~> 2.4.0)
38
39
  oily_png (1.2.1)
39
40
  chunky_png (~> 1.3.7)
40
- parallel (1.12.1)
41
+ parallel (1.13.0)
41
42
  parser (2.5.3.0)
42
43
  ast (~> 2.4.0)
43
44
  powerpack (0.1.2)
@@ -63,7 +64,7 @@ GEM
63
64
  diff-lcs (>= 1.2.0, < 2.0)
64
65
  rspec-support (~> 3.8.0)
65
66
  rspec-support (3.8.0)
66
- rubocop (0.62.0)
67
+ rubocop (0.63.1)
67
68
  jaro_winkler (~> 1.5.1)
68
69
  parallel (~> 1.10)
69
70
  parser (>= 2.5, != 2.5.1.1)
@@ -86,11 +87,12 @@ PLATFORMS
86
87
 
87
88
  DEPENDENCIES
88
89
  bundler (~> 2.0)
90
+ gem-release (~> 2.0)
89
91
  headdesk!
90
92
  rake (~> 10.0)
91
- reek
93
+ reek (~> 5.0)
92
94
  rspec (~> 3.8)
93
- rubocop
95
+ rubocop (~> 0)
94
96
 
95
97
  BUNDLED WITH
96
98
  2.0.1
data/headdesk.gemspec CHANGED
@@ -17,15 +17,6 @@ Gem::Specification.new do |spec|
17
17
 
18
18
  spec.post_install_message = 'For breaking change announcements...'
19
19
 
20
- # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
21
- # to allow pushing to a single host or delete this section to allow pushing to any host.
22
- # if spec.respond_to?(:metadata)
23
- # spec.metadata['allowed_push_host'] = "TODO: Set to 'http://mygemserver.com'"
24
- # else
25
- # raise 'RubyGems 2.0 or newer is required to protect against ' \
26
- # 'public gem pushes.'
27
- # end
28
-
29
20
  # Specify which files should be added to the gem when it is released.
30
21
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
31
22
  spec.files = Dir.chdir(File.expand_path(__dir__)) do
@@ -36,8 +27,11 @@ Gem::Specification.new do |spec|
36
27
  spec.require_paths = ['lib']
37
28
 
38
29
  spec.add_development_dependency 'bundler', '~> 2.0'
30
+ spec.add_development_dependency 'gem-release', '~> 2.0'
39
31
  spec.add_development_dependency 'rake', '~> 10.0'
32
+ spec.add_development_dependency 'reek', '~> 5.0'
40
33
  spec.add_development_dependency 'rspec', '~> 3.8'
34
+ spec.add_development_dependency 'rubocop', '~> 0'
41
35
 
42
36
  spec.add_dependency 'awesome_print', '~> 1.8'
43
37
  spec.add_dependency 'gems', '~> 1.1'
data/lib/headdesk/cli.rb CHANGED
@@ -1,114 +1,24 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'tmpdir'
4
3
  require 'thor'
5
4
  require 'headdesk'
6
5
  require 'awesome_print'
7
6
 
7
+ Dir[File.dirname(__FILE__) + '/cli_commands/*.rb'].each { |file| require file }
8
+
8
9
  module Headdesk
9
10
  #
10
11
  # headdesk CLI
11
12
  #
12
- # :reek:TooManyStatements
13
13
  class CLI < Thor
14
14
  no_commands do
15
- def print_update_message
16
- STDOUT.puts format("\e[36m%s\e[0m", "Latest version is #{Headdesk::Versions.latest_version}, please run 'bundle update headdesk'")
17
- end
18
- end
19
-
20
- desc 'unpack FILE [DESTINATION]', 'Unpack an APK or IPA to [DESTINATION] or to the current directory'
21
- method_option :analyze, type: :boolean, aliases: '-a'
22
- def unpack(file, destination = nil)
23
- # Make sure the input file exists
24
- unless File.exist?(file)
25
- STDERR.puts "Could not find: #{file}"
26
- CLI.command_help(Thor::Base.shell.new, 'unpack')
27
- return 1
28
- end
29
-
30
- # Make sure destination exists, if specified
31
- unless !destination || Dir.exist?(destination)
32
- STDERR.puts "Could not find destination path: #{destination}"
33
- CLI.command_help(Thor::Base.shell.new, 'unpack')
34
- return 1
35
- end
36
-
37
- begin
38
- stdout = nil
39
- output_path = destination
40
-
41
- if !destination
42
- # Output to tempdir, then copy to cwd if no destination specified
43
- Dir.mktmpdir do |tmp_dir|
44
- output_path = tmp_dir
45
- stdout = Headdesk::ApkTool.unpack_to(file, tmp_dir)
46
- FileUtils.cp_r("#{tmp_dir}/.", Dir.pwd)
47
- end
48
- else
49
- stdout = Headdesk::ApkTool.unpack_to(file, destination)
50
- end
51
-
52
- # analyze if requested
53
- Headdesk::Analyze.at(output_path) if options[:analyze]
54
- rescue CliError => cli_err
55
- STDERR.puts cli_err.message
56
- CLI.command_help(Thor::Base.shell.new, 'unpack')
57
- return 1
58
- rescue StandardError => rb_err
59
- STDERR.puts err.message.red
60
- STDERR.puts err.backtrace.ai
61
- return 1
15
+ def print_update_message(stream = STDERR)
16
+ stream.puts "Latest version is #{Headdesk::Versions.latest_version}, please run 'bundle update headdesk'".red
62
17
  end
63
18
  end
64
19
 
65
- desc 'analyze [FILE]', 'Analyze an APK or IPA'
66
- method_option :path, type: :string
67
- method_option :json, type: :boolean
68
- def analyze(file = nil)
69
- # Make sure input file exsts, if specified
70
- unless !file || File.exist?(file)
71
- STDERR.puts "Could not find input file: #{file}"
72
- CLI.command_help(Thor::Base.shell.new, 'analyze')
73
- return 1
74
- end
75
-
76
- # Unpack APK if needed
77
- path = options[:path]
78
- tmp_dir = nil
79
- if file
80
- path = tmp_dir = Dir.mktmpdir
81
- Headdesk::ApkTool.unpack_to(file, tmp_dir)
82
- end
83
-
84
- # Make sure path exists
85
- unless Dir.exist?(path)
86
- STDERR.puts "Could not find path: #{path}"
87
- CLI.command_help(Thor::Base.shell.new, 'analyze')
88
- return 1
89
- end
90
-
91
- # analyze
92
- begin
93
- report = Headdesk::Analyze.at(path)
94
-
95
- if options[:json]
96
- STDOUT.puts report.to_json
97
- else
98
- STDOUT.puts report.to_s
99
- print_update_message unless Headdesk::Versions.latest_version?
100
- end
101
- rescue CliError => cli_err
102
- STDERR.puts cli_err.message
103
- CLI.command_help(Thor::Base.shell.new, 'analyze')
104
- return 1
105
- rescue StandardError => err
106
- STDERR.puts err.message.red
107
- STDERR.puts err.backtrace.ai
108
- return 1
109
- end
110
- ensure
111
- FileUtils.remove_entry(tmp_dir) if tmp_dir
20
+ Headdesk::CliCommand.each do |cmd|
21
+ include cmd
112
22
  end
113
23
  end
114
24
  end
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'thor'
4
+ require 'headdesk'
5
+ require 'tmpdir'
6
+
7
+ module Headdesk
8
+ module CliCommands
9
+ #
10
+ # Analyze an APK/IPA file
11
+ #
12
+ module Analyze
13
+ include Headdesk::CliCommand
14
+
15
+ def self.included(thor)
16
+ thor.class_eval do
17
+ desc 'analyze [FILE]', 'Analyze an APK or IPA'
18
+ method_option :path, type: :string
19
+ method_option :json, type: :boolean
20
+ def analyze(file = nil)
21
+ # Make sure input file exsts, if specified
22
+ unless !file || File.exist?(file)
23
+ STDERR.puts "Could not find input file: #{file}"
24
+ CLI.command_help(Thor::Base.shell.new, 'analyze')
25
+ exit 1
26
+ end
27
+
28
+ # Unpack APK if needed
29
+ path = options[:path]
30
+ tmp_dir = nil
31
+ if file
32
+ path = tmp_dir = Dir.mktmpdir
33
+ Headdesk::ApkTool.unpack_to(file, tmp_dir)
34
+ end
35
+
36
+ # Make sure path exists
37
+ unless Dir.exist?(path)
38
+ STDERR.puts "Could not find path: #{path}"
39
+ CLI.command_help(Thor::Base.shell.new, 'analyze')
40
+ exit 1
41
+ end
42
+
43
+ # analyze
44
+ begin
45
+ report = Headdesk::Analyze.at(path)
46
+
47
+ if options[:json]
48
+ STDOUT.puts report.to_json
49
+ else
50
+ STDOUT.puts report.to_s
51
+ CLI.print_update_message unless Headdesk::Versions.latest_version?
52
+ end
53
+ rescue CliError => cli_err
54
+ STDERR.puts cli_err.message
55
+ CLI.command_help(Thor::Base.shell.new, 'analyze')
56
+ exit 1
57
+ rescue StandardError => err
58
+ STDERR.puts err.message.red
59
+ STDERR.puts err.backtrace.ai
60
+ exit 1
61
+ end
62
+ ensure
63
+ FileUtils.remove_entry(tmp_dir) if tmp_dir
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,79 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'thor'
4
+ require 'headdesk'
5
+ require 'English'
6
+
7
+ module Headdesk
8
+ module CliCommands
9
+ #
10
+ # Find out which JAR/AAR is bringing in symbols
11
+ #
12
+ module Blame
13
+ include Headdesk::CliCommand
14
+
15
+ def self.included(thor)
16
+ thor.class_eval do
17
+ desc 'blame SYMBOL [PATH]', 'Recursivly search for JARs and AARs which define a given symbol.'
18
+ method_option :json, type: :boolean
19
+ def blame(in_symbol, path = '.')
20
+ unless Dir.exist?(path)
21
+ STDERR.puts "Could not find path: #{path}"
22
+ CLI.command_help(Thor::Base.shell.new, 'blame')
23
+ exit 1
24
+ end
25
+
26
+ symbol_matcher = /(.*)(#{Regexp.escape(in_symbol.tr('.', '/'))})([^\.]*)?(\.class)?/
27
+
28
+ # Match inside JAR files
29
+ jar_matches = {}
30
+ Dir[File.join(path, '**', '*.jar')].each do |jar|
31
+ stdout = `jar -tf #{jar}`
32
+ exit $CHILD_STATUS.to_i unless $CHILD_STATUS.success?
33
+
34
+ matches = Blame.match_lines(stdout, symbol_matcher)
35
+ jar_matches[jar] = matches unless matches.empty?
36
+ end
37
+
38
+ # Match inside AAR files
39
+ aar_matches = {}
40
+ Dir[File.join(path, '**', '*.aar')].each do |aar|
41
+ stdout = `unzip -p -j #{aar} classes.jar | jar -t`
42
+ exit $CHILD_STATUS.to_i unless $CHILD_STATUS.success?
43
+
44
+ matches = Blame.match_lines(stdout, symbol_matcher)
45
+ aar_matches[aar] = matches unless matches.empty?
46
+ end
47
+
48
+ # JSON output if requested
49
+ if options[:json]
50
+ STDOUT.puts({ jar: jar_matches, aar: aar_matches }.to_json)
51
+ exit 0
52
+ end
53
+
54
+ # Pretty output
55
+ all_matches = jar_matches.merge(aar_matches)
56
+ all_matches.each do |package, symbols|
57
+ STDOUT.puts '📦 ' + package
58
+ symbols.each do |match|
59
+ STDOUT.puts " ↳ #{match[0]}#{match[1].green}#{match[2].chomp('.') if match[2]}"
60
+ end
61
+ end
62
+
63
+ CLI.print_update_message unless Headdesk::Versions.latest_version?
64
+
65
+ exit !all_matches.empty?
66
+ end
67
+ end
68
+ end
69
+
70
+ def self.match_lines(stdout, matcher)
71
+ stdout.lines
72
+ .each(&:strip!)
73
+ .map { |line| matcher.match(line) }
74
+ .compact
75
+ .map { |match| match.captures.map { |capture| capture.tr('/', '.') if capture } }
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'thor'
4
+ require 'headdesk'
5
+ require 'tmpdir'
6
+
7
+ module Headdesk
8
+ module CliCommands
9
+ #
10
+ # Unpack an APK/IPA
11
+ #
12
+ module Unpack
13
+ include Headdesk::CliCommand
14
+
15
+ def self.included(thor)
16
+ thor.class_eval do
17
+ desc 'unpack FILE [DESTINATION]', 'Unpack an APK or IPA to [DESTINATION] or to the current directory'
18
+ method_option :analyze, type: :boolean, aliases: '-a'
19
+ def unpack(file, destination = nil)
20
+ # Make sure the input file exists
21
+ unless File.exist?(file)
22
+ STDERR.puts "Could not find: #{file}"
23
+ CLI.command_help(Thor::Base.shell.new, 'unpack')
24
+ exit 1
25
+ end
26
+
27
+ # Make sure destination exists, if specified
28
+ unless !destination || Dir.exist?(destination)
29
+ STDERR.puts "Could not find destination path: #{destination}"
30
+ CLI.command_help(Thor::Base.shell.new, 'unpack')
31
+ exit 1
32
+ end
33
+
34
+ begin
35
+ stdout = nil
36
+ output_path = destination
37
+
38
+ if !destination
39
+ # Output to tempdir, then copy to cwd if no destination specified
40
+ Dir.mktmpdir do |tmp_dir|
41
+ output_path = tmp_dir
42
+ stdout = Headdesk::ApkTool.unpack_to(file, tmp_dir)
43
+ FileUtils.cp_r("#{tmp_dir}/.", Dir.pwd)
44
+ end
45
+ else
46
+ stdout = Headdesk::ApkTool.unpack_to(file, destination)
47
+ end
48
+
49
+ # analyze if requested
50
+ Headdesk::Analyze.at(output_path) if options[:analyze]
51
+
52
+ CLI.print_update_message unless Headdesk::Versions.latest_version?
53
+ rescue CliError => cli_err
54
+ STDERR.puts cli_err.message
55
+ CLI.command_help(Thor::Base.shell.new, 'unpack')
56
+ exit 1
57
+ rescue StandardError => rb_err
58
+ STDERR.puts err.message.red
59
+ STDERR.puts err.backtrace.ai
60
+ exit 1
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'thor'
4
+ require 'headdesk'
5
+
6
+ module Headdesk
7
+ module CliCommands
8
+ #
9
+ # Print/compare version
10
+ #
11
+ module Version
12
+ include Headdesk::CliCommand
13
+
14
+ def self.included(thor)
15
+ thor.class_eval do
16
+ map %w[--version] => :__version
17
+ desc '--version [COMPARE_VERSION]', 'Print, and optionally compare version.'
18
+ long_desc <<~LONGDESC
19
+ `--version` will print the version to STDOUT, and if a newer version is available it will print out an update message to STDERR.
20
+
21
+ You can optionally specify a version number as a second argument, in which case will compare the current version with that version exit with code 1 if the current version is less than the provided version. It will exit with code 0 if the current version is less than, or equal to the provided version.
22
+ LONGDESC
23
+ def __version(cmp_version = nil)
24
+ STDOUT.puts Headdesk::VERSION
25
+ print_update_message unless Headdesk::Versions.latest_version?
26
+
27
+ exit (Headdesk::Versions.version <=> Gem::Version.new(cmp_version)) > 0 if cmp_version
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Headdesk
4
+ VERSION = '0.11.0'
4
5
  APKTOOL_VERSION = '2.3.4'
5
- VERSION = '0.10.0'
6
6
  end
@@ -7,6 +7,10 @@ module Headdesk
7
7
  # Version information from RubyGems.org
8
8
  #
9
9
  class Versions
10
+ def self.version
11
+ Gem::Version.new(VERSION)
12
+ end
13
+
10
14
  def self.versions
11
15
  Gems.versions('headdesk').collect do |version|
12
16
  Gem::Version.new(version['number'])
data/lib/headdesk.rb CHANGED
@@ -22,4 +22,20 @@ module Headdesk
22
22
  #
23
23
  class CliError < StandardError
24
24
  end
25
+
26
+ #
27
+ # Helper for CLI command modules
28
+ #
29
+ module CliCommand
30
+ extend Enumerable
31
+
32
+ def self.each(&block)
33
+ @commands.each(&block)
34
+ end
35
+
36
+ def self.included(cmd)
37
+ @commands ||= []
38
+ @commands << cmd
39
+ end
40
+ end
25
41
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: headdesk
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.10.0
4
+ version: 0.11.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Pat Wilson
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-01-21 00:00:00.000000000 Z
11
+ date: 2019-02-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -24,6 +24,20 @@ dependencies:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '2.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: gem-release
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '2.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '2.0'
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: rake
29
43
  requirement: !ruby/object:Gem::Requirement
@@ -38,6 +52,20 @@ dependencies:
38
52
  - - "~>"
39
53
  - !ruby/object:Gem::Version
40
54
  version: '10.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: reek
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '5.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '5.0'
41
69
  - !ruby/object:Gem::Dependency
42
70
  name: rspec
43
71
  requirement: !ruby/object:Gem::Requirement
@@ -52,6 +80,20 @@ dependencies:
52
80
  - - "~>"
53
81
  - !ruby/object:Gem::Version
54
82
  version: '3.8'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rubocop
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
55
97
  - !ruby/object:Gem::Dependency
56
98
  name: awesome_print
57
99
  requirement: !ruby/object:Gem::Requirement
@@ -169,6 +211,10 @@ files:
169
211
  - lib/headdesk/checks/teak/caching.rb
170
212
  - lib/headdesk/checks/teak/teak.rb
171
213
  - lib/headdesk/cli.rb
214
+ - lib/headdesk/cli_commands/analyze.rb
215
+ - lib/headdesk/cli_commands/blame.rb
216
+ - lib/headdesk/cli_commands/unpack.rb
217
+ - lib/headdesk/cli_commands/version.rb
172
218
  - lib/headdesk/data/facebook_sdk_versions.yaml
173
219
  - lib/headdesk/descriptionator.rb
174
220
  - lib/headdesk/descriptionator/resources.rb