falkor 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/.github/ISSUE_TEMPLATE/bug_report.md +21 -0
- data/.github/ISSUE_TEMPLATE/feature_request.md +17 -0
- data/.github/logo.jpg +0 -0
- data/.github/workflows/coverage.yml +24 -0
- data/.github/workflows/lint.yml +19 -0
- data/.github/workflows/tests.yml +22 -0
- data/.gitignore +9 -0
- data/.rubocop.yml +1600 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +14 -0
- data/LICENSE.txt +21 -0
- data/README.md +61 -0
- data/Rakefile +12 -0
- data/bin/console +19 -0
- data/bin/publish +65 -0
- data/bin/setup +8 -0
- data/falkor.gemspec +35 -0
- data/lib/falkor.rb +16 -0
- data/lib/falkor/concerns/installable.rb +50 -0
- data/lib/falkor/concerns/trackable_progress.rb +14 -0
- data/lib/falkor/download.rb +70 -0
- data/lib/falkor/extract/gem.rb +46 -0
- data/lib/falkor/extract/tar_gz.rb +117 -0
- data/lib/falkor/gem.rb +93 -0
- data/lib/falkor/progress.rb +28 -0
- data/lib/falkor/ruby.rb +68 -0
- data/lib/falkor/version.rb +5 -0
- data/lib/falkor/yard/documentation.rb +67 -0
- data/lib/falkor/yard/parser.rb +31 -0
- data/lib/falkor/yard/parser/global_state.rb +24 -0
- metadata +152 -0
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Falkor
|
4
|
+
module Extract
|
5
|
+
class Gem
|
6
|
+
def initialize(file_name)
|
7
|
+
@file_name = file_name
|
8
|
+
end
|
9
|
+
|
10
|
+
def extract
|
11
|
+
::Gem::Package::FileSource.new(file_name).with_read_io do |io|
|
12
|
+
::Gem::Package::TarReader.new(io).each do |entry|
|
13
|
+
next if entry.full_name != "data.tar.gz"
|
14
|
+
|
15
|
+
write_tar_file(entry.read)
|
16
|
+
|
17
|
+
remove_file
|
18
|
+
break # ignore further entries
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
tar_file_name
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
attr_reader :file_name
|
28
|
+
|
29
|
+
def write_tar_file(contents)
|
30
|
+
File.open(tar_file_name, "wb") do |file|
|
31
|
+
file.write contents
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def tar_file_name
|
36
|
+
File.join(
|
37
|
+
File.dirname(file_name), File.basename(file_name, ".gem") + ".tar.gz"
|
38
|
+
)
|
39
|
+
end
|
40
|
+
|
41
|
+
def remove_file
|
42
|
+
FileUtils.rm file_name
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,117 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rubygems/package"
|
4
|
+
require "falkor/concerns/trackable_progress"
|
5
|
+
|
6
|
+
module Falkor
|
7
|
+
module Extract
|
8
|
+
class TarGz
|
9
|
+
include TrackableProgress
|
10
|
+
|
11
|
+
TAR_LONGLINK = "././@LongLink"
|
12
|
+
|
13
|
+
def initialize(file_name, has_root_dir: false)
|
14
|
+
@file_name = file_name
|
15
|
+
@extraction_destination =
|
16
|
+
if has_root_dir
|
17
|
+
File.dirname(file_name)
|
18
|
+
else
|
19
|
+
source_destination
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def extract
|
24
|
+
return source_destination if Dir.exist? source_destination
|
25
|
+
|
26
|
+
FileUtils.mkdir_p extraction_destination
|
27
|
+
|
28
|
+
block = block_given? ? Proc.new : proc {}
|
29
|
+
|
30
|
+
report_progress(:write_each_tarfile, open_file(&:count), &block)
|
31
|
+
FileUtils.rm file_name
|
32
|
+
source_destination
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
attr_reader :file_name, :extraction_destination
|
38
|
+
|
39
|
+
def source_destination
|
40
|
+
@source_destination ||= File.join(
|
41
|
+
File.dirname(file_name), File.basename(file_name, ".tar.gz")
|
42
|
+
)
|
43
|
+
end
|
44
|
+
|
45
|
+
def write_each_tarfile
|
46
|
+
open_file do |tar|
|
47
|
+
current_destination = nil
|
48
|
+
tar.each do |tarfile|
|
49
|
+
current_destination =
|
50
|
+
handle_longlink_or_write(tarfile, current_destination)
|
51
|
+
yield(1)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def open_file
|
57
|
+
File.open(file_name, "rb") do |file|
|
58
|
+
return_value = nil
|
59
|
+
Zlib::GzipReader.wrap(file) do |gz|
|
60
|
+
::Gem::Package::TarReader.new(gz) do |tar|
|
61
|
+
return_value = yield tar
|
62
|
+
end
|
63
|
+
end
|
64
|
+
return_value
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def write_tarfile(tarfile, current_destination)
|
69
|
+
current_destination ||=
|
70
|
+
File.join extraction_destination, tarfile.full_name
|
71
|
+
|
72
|
+
if directory?(tarfile)
|
73
|
+
write_directory(tarfile, current_destination)
|
74
|
+
elsif file?(tarfile)
|
75
|
+
write_file(tarfile, current_destination)
|
76
|
+
elsif tarfile.header.typeflag == "2" # Symlink
|
77
|
+
File.symlink tarfile.header.linkname, current_destination
|
78
|
+
end
|
79
|
+
nil
|
80
|
+
end
|
81
|
+
|
82
|
+
def directory?(file)
|
83
|
+
file.directory? || file.full_name.end_with?("/")
|
84
|
+
end
|
85
|
+
|
86
|
+
def file?(file)
|
87
|
+
file.file? || !file.full_name.end_with?("/")
|
88
|
+
end
|
89
|
+
|
90
|
+
def write_directory(file, dest)
|
91
|
+
File.delete dest if File.file? dest
|
92
|
+
FileUtils.mkdir_p dest, mode: file.header.mode, verbose: false
|
93
|
+
end
|
94
|
+
|
95
|
+
def write_file(file, dest)
|
96
|
+
if File.directory? dest
|
97
|
+
FileUtils.rm_rf dest
|
98
|
+
else
|
99
|
+
FileUtils.mkdir_p(File.dirname(dest))
|
100
|
+
end
|
101
|
+
|
102
|
+
File.open dest, "wb" do |f|
|
103
|
+
f.print file.read
|
104
|
+
end
|
105
|
+
FileUtils.chmod file.header.mode, dest, verbose: false
|
106
|
+
end
|
107
|
+
|
108
|
+
def handle_longlink_or_write(tarfile, dest)
|
109
|
+
if tarfile.full_name == TAR_LONGLINK
|
110
|
+
File.join extraction_destination, tarfile.read.strip
|
111
|
+
else
|
112
|
+
write_tarfile(tarfile, dest)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
data/lib/falkor/gem.rb
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "falkor/concerns/installable"
|
4
|
+
require "gems"
|
5
|
+
|
6
|
+
module Falkor
|
7
|
+
class Gem
|
8
|
+
include Installable
|
9
|
+
|
10
|
+
attr_reader :name, :info, :version, :created_at, :project_uri
|
11
|
+
|
12
|
+
class << self
|
13
|
+
def search(query)
|
14
|
+
return [] if query.nil? || query.empty?
|
15
|
+
|
16
|
+
Gems.search(query).map do |gem|
|
17
|
+
new(**gem.transform_keys(&:to_sym))
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def find(query, version = nil)
|
22
|
+
gem_info =
|
23
|
+
if version.nil?
|
24
|
+
Gems.info(query)
|
25
|
+
else
|
26
|
+
rubygems_v2_info(query, version)
|
27
|
+
end
|
28
|
+
|
29
|
+
new(**gem_info.transform_keys(&:to_sym))
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def rubygems_v2_info(gem_name, version)
|
35
|
+
response = Gems::Client.new.get(
|
36
|
+
"/api/v2/rubygems/#{gem_name}/versions/#{version}.json"
|
37
|
+
)
|
38
|
+
JSON.parse(response)
|
39
|
+
rescue JSON::ParserError
|
40
|
+
{}
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def initialize(**attrs)
|
45
|
+
@name = attrs[:name]
|
46
|
+
@info = attrs[:info]
|
47
|
+
@created_at = attrs[:created_at] && Time.parse(attrs[:created_at])
|
48
|
+
@project_uri = attrs[:homepage_uri]
|
49
|
+
@version = ::Gem::Version.new(attrs[:version])
|
50
|
+
end
|
51
|
+
|
52
|
+
def other_versions
|
53
|
+
@other_versions ||= Gems.versions(name).map do |payload|
|
54
|
+
next if payload["number"] == version
|
55
|
+
|
56
|
+
self.class.new(
|
57
|
+
name: name,
|
58
|
+
info: payload["summary"],
|
59
|
+
version: payload["number"],
|
60
|
+
created_at: payload["created_at"]
|
61
|
+
)
|
62
|
+
end.compact
|
63
|
+
end
|
64
|
+
|
65
|
+
%i(root class method module constant classvariable macro).each do |type|
|
66
|
+
define_method("#{type}_objects") do
|
67
|
+
store.values_for_type(type)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
private
|
72
|
+
|
73
|
+
def file_name
|
74
|
+
"#{name}-#{version}.gem"
|
75
|
+
end
|
76
|
+
|
77
|
+
def url
|
78
|
+
"https://rubygems.org/gems/#{file_name}"
|
79
|
+
end
|
80
|
+
|
81
|
+
def yard_filepath
|
82
|
+
File.join(Dir.pwd, "tmp", File.basename(file_name, ".gem") + ".falkor")
|
83
|
+
end
|
84
|
+
|
85
|
+
def extract(file_path)
|
86
|
+
Falkor::Extract::TarGz.new(
|
87
|
+
Falkor::Extract::Gem.new(file_path).extract
|
88
|
+
).extract do |progress|
|
89
|
+
yield :extracting, progress
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Falkor
|
4
|
+
class Progress
|
5
|
+
def initialize(total)
|
6
|
+
@total = total
|
7
|
+
@current = 0
|
8
|
+
@previous = 0
|
9
|
+
end
|
10
|
+
|
11
|
+
def increment!(amount, description)
|
12
|
+
self.previous, self.current = current, current + amount
|
13
|
+
|
14
|
+
return if percentage(previous) == percentage(current) && !description
|
15
|
+
|
16
|
+
yield percentage(current), description
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
attr_reader :total
|
22
|
+
attr_accessor :current, :previous
|
23
|
+
|
24
|
+
def percentage(amount)
|
25
|
+
(amount.to_f / total * 100).to_i
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
data/lib/falkor/ruby.rb
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "falkor/concerns/installable"
|
4
|
+
|
5
|
+
module Falkor
|
6
|
+
class Ruby
|
7
|
+
class NotFound < StandardError; end
|
8
|
+
|
9
|
+
include Installable
|
10
|
+
|
11
|
+
RELEASES = "https://raw.githubusercontent.com/ruby/www.ruby-lang.org/"\
|
12
|
+
"master/_data/releases.yml"
|
13
|
+
|
14
|
+
class << self
|
15
|
+
def search(query)
|
16
|
+
versions.keys.map do |version|
|
17
|
+
new(version) if version.include? query
|
18
|
+
end.compact
|
19
|
+
end
|
20
|
+
|
21
|
+
alias :find :new
|
22
|
+
|
23
|
+
def versions
|
24
|
+
YAML.
|
25
|
+
load_file(Download.new(RELEASES, "ruby_releases.yml").download {}).
|
26
|
+
select { |release| release.dig("url", "gz") }.
|
27
|
+
map { |release| [release["version"], release.dig("url", "gz")] }.
|
28
|
+
to_h
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def initialize(version)
|
33
|
+
raise NotFound if self.class.versions[version].nil?
|
34
|
+
|
35
|
+
@version = version
|
36
|
+
end
|
37
|
+
|
38
|
+
def other_versions
|
39
|
+
self.class.versions.keys.map do |number|
|
40
|
+
next if number == version
|
41
|
+
|
42
|
+
self.class.new(number)
|
43
|
+
end.compact
|
44
|
+
end
|
45
|
+
|
46
|
+
%i(root class method module constant classvariable macro).each do |type|
|
47
|
+
define_method("#{type}_objects") do
|
48
|
+
store.values_for_type(type)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
attr_reader :version
|
55
|
+
|
56
|
+
def file_name
|
57
|
+
"ruby-#{version}.tar.gz"
|
58
|
+
end
|
59
|
+
|
60
|
+
def url
|
61
|
+
self.class.versions[version]
|
62
|
+
end
|
63
|
+
|
64
|
+
def yard_filepath
|
65
|
+
File.join(Dir.pwd, "tmp", File.basename(file_name, ".tar.gz") + ".falkor")
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "falkor/concerns/trackable_progress"
|
4
|
+
require "falkor/yard/parser"
|
5
|
+
require "yard"
|
6
|
+
|
7
|
+
module Falkor
|
8
|
+
module Yard
|
9
|
+
class Documentation
|
10
|
+
include TrackableProgress
|
11
|
+
|
12
|
+
FILE_GLOB =
|
13
|
+
YARD::Parser::SourceParser::DEFAULT_PATH_GLOB + ["*.c", "ext/**/*.rb"]
|
14
|
+
|
15
|
+
def initialize(source_dir, yardoc_file = ".yardoc")
|
16
|
+
@source_dir = source_dir
|
17
|
+
@yardoc_file = yardoc_file
|
18
|
+
end
|
19
|
+
|
20
|
+
def generate
|
21
|
+
in_source_dir do
|
22
|
+
with_yardoc_file do
|
23
|
+
YARD::Registry.lock_for_writing do
|
24
|
+
report_progress(:parse_files, files.size, &Proc.new)
|
25
|
+
YARD::Registry.save(true)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
yardoc_file
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
attr_accessor :source_dir, :yardoc_file
|
36
|
+
|
37
|
+
def files
|
38
|
+
@files ||=
|
39
|
+
FILE_GLOB.map do |path|
|
40
|
+
path = "#{path}/**/*.{rb,c,cc,cxx,cpp}" if File.directory?(path)
|
41
|
+
path = Dir[path].sort_by { |d| [d.length, d] } if path.include?("*")
|
42
|
+
|
43
|
+
path
|
44
|
+
end.flatten.select { |p| File.file?(p) }
|
45
|
+
end
|
46
|
+
|
47
|
+
def in_source_dir
|
48
|
+
Dir.chdir(source_dir) { yield }
|
49
|
+
end
|
50
|
+
|
51
|
+
def with_yardoc_file
|
52
|
+
YARD::Registry.clear
|
53
|
+
YARD::Logger.instance.io = IO.new(IO.sysopen("/dev/null", "w+"))
|
54
|
+
YARD::Registry.yardoc_file = yardoc_file
|
55
|
+
yield
|
56
|
+
YARD::Registry.yardoc_file = nil
|
57
|
+
YARD::Logger.instance.io = STDOUT
|
58
|
+
end
|
59
|
+
|
60
|
+
def parse_files
|
61
|
+
Parser.new(nil, files).parse do |count, description|
|
62
|
+
yield count, description
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "falkor/yard/parser/global_state"
|
4
|
+
require "yard"
|
5
|
+
|
6
|
+
module Falkor
|
7
|
+
module Yard
|
8
|
+
class Parser
|
9
|
+
attr_accessor :files, :global_state
|
10
|
+
|
11
|
+
def initialize(global_state, files)
|
12
|
+
@global_state = global_state || GlobalState.new(self, 0)
|
13
|
+
|
14
|
+
@files = files.dup
|
15
|
+
end
|
16
|
+
|
17
|
+
def parse
|
18
|
+
global_state.block = Proc.new if block_given?
|
19
|
+
|
20
|
+
until files.empty?
|
21
|
+
file = files.shift
|
22
|
+
YARD::Parser::SourceParser.new(
|
23
|
+
YARD::Parser::SourceParser.parser_type, global_state
|
24
|
+
).parse(file)
|
25
|
+
|
26
|
+
global_state.processed(file)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|