git-pkgs 0.4.0 → 0.5.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 +4 -4
- data/CHANGELOG.md +15 -0
- data/README.md +48 -39
- data/lib/git/pkgs/analyzer.rb +35 -12
- data/lib/git/pkgs/cli.rb +83 -29
- data/lib/git/pkgs/commands/blame.rb +25 -7
- data/lib/git/pkgs/commands/branch.rb +27 -15
- data/lib/git/pkgs/commands/completions.rb +234 -0
- data/lib/git/pkgs/commands/diff.rb +34 -31
- data/lib/git/pkgs/commands/diff_driver.rb +9 -7
- data/lib/git/pkgs/commands/history.rb +0 -7
- data/lib/git/pkgs/commands/hooks.rb +8 -8
- data/lib/git/pkgs/commands/info.rb +65 -1
- data/lib/git/pkgs/commands/init.rb +31 -17
- data/lib/git/pkgs/commands/list.rb +2 -2
- data/lib/git/pkgs/commands/log.rb +5 -12
- data/lib/git/pkgs/commands/show.rb +3 -23
- data/lib/git/pkgs/commands/stale.rb +26 -7
- data/lib/git/pkgs/commands/stats.rb +9 -12
- data/lib/git/pkgs/commands/tree.rb +1 -1
- data/lib/git/pkgs/commands/update.rb +9 -7
- data/lib/git/pkgs/commands/upgrade.rb +4 -4
- data/lib/git/pkgs/config.rb +73 -0
- data/lib/git/pkgs/database.rb +7 -7
- data/lib/git/pkgs/models/commit.rb +19 -0
- data/lib/git/pkgs/output.rb +13 -0
- data/lib/git/pkgs/repository.rb +35 -1
- data/lib/git/pkgs/version.rb +1 -1
- data/lib/git/pkgs.rb +34 -0
- metadata +3 -10
- data/CODE_OF_CONDUCT.md +0 -10
- data/CONTRIBUTING.md +0 -27
- data/Rakefile +0 -8
- data/SECURITY.md +0 -7
- data/benchmark_bulk.rb +0 -167
- data/benchmark_db.rb +0 -138
- data/benchmark_detailed.rb +0 -151
- data/benchmark_full.rb +0 -131
- data/docs/schema.md +0 -129
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "time"
|
|
4
|
-
|
|
5
3
|
module Git
|
|
6
4
|
module Pkgs
|
|
7
5
|
module Commands
|
|
@@ -20,6 +18,7 @@ module Git
|
|
|
20
18
|
Database.connect(repo.git_dir)
|
|
21
19
|
|
|
22
20
|
commits = Models::Commit
|
|
21
|
+
.includes(:dependency_changes)
|
|
23
22
|
.where(has_dependency_changes: true)
|
|
24
23
|
.order(committed_at: :desc)
|
|
25
24
|
|
|
@@ -44,8 +43,8 @@ module Git
|
|
|
44
43
|
|
|
45
44
|
def output_text(commits)
|
|
46
45
|
commits.each do |commit|
|
|
47
|
-
changes = commit.dependency_changes
|
|
48
|
-
changes = changes.
|
|
46
|
+
changes = commit.dependency_changes.to_a
|
|
47
|
+
changes = changes.select { |c| c.ecosystem == @options[:ecosystem] } if @options[:ecosystem]
|
|
49
48
|
next if changes.empty?
|
|
50
49
|
|
|
51
50
|
puts "#{commit.short_sha} #{commit.message&.lines&.first&.strip}"
|
|
@@ -77,8 +76,8 @@ module Git
|
|
|
77
76
|
require "json"
|
|
78
77
|
|
|
79
78
|
data = commits.map do |commit|
|
|
80
|
-
changes = commit.dependency_changes
|
|
81
|
-
changes = changes.
|
|
79
|
+
changes = commit.dependency_changes.to_a
|
|
80
|
+
changes = changes.select { |c| c.ecosystem == @options[:ecosystem] } if @options[:ecosystem]
|
|
82
81
|
|
|
83
82
|
{
|
|
84
83
|
sha: commit.sha,
|
|
@@ -102,12 +101,6 @@ module Git
|
|
|
102
101
|
puts JSON.pretty_generate(data)
|
|
103
102
|
end
|
|
104
103
|
|
|
105
|
-
def parse_time(str)
|
|
106
|
-
Time.parse(str)
|
|
107
|
-
rescue ArgumentError
|
|
108
|
-
error "Invalid date format: #{str}"
|
|
109
|
-
end
|
|
110
|
-
|
|
111
104
|
def parse_options
|
|
112
105
|
options = {}
|
|
113
106
|
|
|
@@ -20,10 +20,10 @@ module Git
|
|
|
20
20
|
Database.connect(repo.git_dir)
|
|
21
21
|
|
|
22
22
|
sha = repo.rev_parse(ref)
|
|
23
|
-
error "Could not resolve '#{ref}'" unless sha
|
|
23
|
+
error "Could not resolve '#{ref}'. Check that the ref exists with 'git rev-parse #{ref}'." unless sha
|
|
24
24
|
|
|
25
|
-
commit =
|
|
26
|
-
error "Commit '#{sha[0..7]}' not
|
|
25
|
+
commit = Models::Commit.find_or_create_from_repo(repo, sha)
|
|
26
|
+
error "Commit '#{sha[0..7]}' not in database. Run 'git pkgs update' to index new commits." unless commit
|
|
27
27
|
|
|
28
28
|
changes = Models::DependencyChange
|
|
29
29
|
.includes(:commit, :manifest)
|
|
@@ -107,26 +107,6 @@ module Git
|
|
|
107
107
|
puts JSON.pretty_generate(data)
|
|
108
108
|
end
|
|
109
109
|
|
|
110
|
-
def find_or_create_commit(repo, sha)
|
|
111
|
-
commit = Models::Commit.find_by(sha: sha) ||
|
|
112
|
-
Models::Commit.where("sha LIKE ?", "#{sha}%").first
|
|
113
|
-
return commit if commit
|
|
114
|
-
|
|
115
|
-
rugged_commit = repo.lookup(sha)
|
|
116
|
-
return nil unless rugged_commit
|
|
117
|
-
|
|
118
|
-
Models::Commit.create!(
|
|
119
|
-
sha: rugged_commit.oid,
|
|
120
|
-
message: rugged_commit.message,
|
|
121
|
-
author_name: rugged_commit.author[:name],
|
|
122
|
-
author_email: rugged_commit.author[:email],
|
|
123
|
-
committed_at: rugged_commit.time,
|
|
124
|
-
has_dependency_changes: false
|
|
125
|
-
)
|
|
126
|
-
rescue Rugged::OdbError
|
|
127
|
-
nil
|
|
128
|
-
end
|
|
129
|
-
|
|
130
110
|
def parse_options
|
|
131
111
|
options = {}
|
|
132
112
|
|
|
@@ -20,7 +20,7 @@ module Git
|
|
|
20
20
|
branch_name = @options[:branch] || repo.default_branch
|
|
21
21
|
branch = Models::Branch.find_by(name: branch_name)
|
|
22
22
|
|
|
23
|
-
error "No analysis found for branch '#{branch_name}'" unless branch&.last_analyzed_sha
|
|
23
|
+
error "No analysis found for branch '#{branch_name}'. Run 'git pkgs init' first." unless branch&.last_analyzed_sha
|
|
24
24
|
|
|
25
25
|
current_commit = Models::Commit.find_by(sha: branch.last_analyzed_sha)
|
|
26
26
|
snapshots = current_commit&.dependency_snapshots&.includes(:manifest) || []
|
|
@@ -34,19 +34,38 @@ module Git
|
|
|
34
34
|
return
|
|
35
35
|
end
|
|
36
36
|
|
|
37
|
+
# Batch fetch all changes for current dependencies
|
|
38
|
+
snapshot_keys = snapshots.map { |s| [s.name, s.manifest_id] }.to_set
|
|
39
|
+
manifest_ids = snapshots.map(&:manifest_id).uniq
|
|
40
|
+
names = snapshots.map(&:name).uniq
|
|
41
|
+
|
|
42
|
+
all_changes = Models::DependencyChange
|
|
43
|
+
.includes(:commit)
|
|
44
|
+
.where(manifest_id: manifest_ids, name: names)
|
|
45
|
+
.to_a
|
|
46
|
+
|
|
47
|
+
# Group by (name, manifest_id) and find latest by committed_at
|
|
48
|
+
latest_by_key = {}
|
|
49
|
+
all_changes.each do |change|
|
|
50
|
+
key = [change.name, change.manifest_id]
|
|
51
|
+
next unless snapshot_keys.include?(key)
|
|
52
|
+
|
|
53
|
+
existing = latest_by_key[key]
|
|
54
|
+
if existing.nil? || change.commit.committed_at > existing.commit.committed_at
|
|
55
|
+
latest_by_key[key] = change
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
37
59
|
# Find last update for each dependency
|
|
38
60
|
outdated_data = []
|
|
61
|
+
now = Time.now
|
|
39
62
|
|
|
40
63
|
snapshots.each do |snapshot|
|
|
41
|
-
last_change =
|
|
42
|
-
.includes(:commit)
|
|
43
|
-
.where(name: snapshot.name, manifest: snapshot.manifest)
|
|
44
|
-
.order("commits.committed_at DESC")
|
|
45
|
-
.first
|
|
64
|
+
last_change = latest_by_key[[snapshot.name, snapshot.manifest_id]]
|
|
46
65
|
|
|
47
66
|
next unless last_change
|
|
48
67
|
|
|
49
|
-
days_since_update = ((
|
|
68
|
+
days_since_update = ((now - last_change.commit.committed_at) / 86400).to_i
|
|
50
69
|
|
|
51
70
|
outdated_data << {
|
|
52
71
|
name: snapshot.name,
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "time"
|
|
4
|
-
|
|
5
3
|
module Git
|
|
6
4
|
module Pkgs
|
|
7
5
|
module Commands
|
|
@@ -93,11 +91,16 @@ module Git
|
|
|
93
91
|
manifests = Models::Manifest.all
|
|
94
92
|
manifests = manifests.where(ecosystem: ecosystem) if ecosystem
|
|
95
93
|
|
|
94
|
+
manifest_ids = manifests.pluck(:id)
|
|
95
|
+
change_counts_query = Models::DependencyChange
|
|
96
|
+
.joins(:commit)
|
|
97
|
+
.where(manifest_id: manifest_ids)
|
|
98
|
+
change_counts_query = change_counts_query.where("commits.committed_at >= ?", since_time) if since_time
|
|
99
|
+
change_counts_query = change_counts_query.where("commits.committed_at <= ?", until_time) if until_time
|
|
100
|
+
change_counts = change_counts_query.group(:manifest_id).count
|
|
101
|
+
|
|
96
102
|
data[:manifests] = manifests.map do |manifest|
|
|
97
|
-
|
|
98
|
-
manifest_changes = manifest_changes.where("commits.committed_at >= ?", since_time) if since_time
|
|
99
|
-
manifest_changes = manifest_changes.where("commits.committed_at <= ?", until_time) if until_time
|
|
100
|
-
{ path: manifest.path, ecosystem: manifest.ecosystem, changes: manifest_changes.count }
|
|
103
|
+
{ path: manifest.path, ecosystem: manifest.ecosystem, changes: change_counts[manifest.id] || 0 }
|
|
101
104
|
end
|
|
102
105
|
|
|
103
106
|
data
|
|
@@ -199,12 +202,6 @@ module Git
|
|
|
199
202
|
end
|
|
200
203
|
end
|
|
201
204
|
|
|
202
|
-
def parse_time(str)
|
|
203
|
-
Time.parse(str)
|
|
204
|
-
rescue ArgumentError
|
|
205
|
-
error "Invalid date format: #{str}"
|
|
206
|
-
end
|
|
207
|
-
|
|
208
205
|
def parse_options
|
|
209
206
|
options = {}
|
|
210
207
|
|
|
@@ -21,7 +21,7 @@ module Git
|
|
|
21
21
|
commit_sha = @options[:commit] || repo.head_sha
|
|
22
22
|
commit = find_commit_with_snapshot(commit_sha, repo)
|
|
23
23
|
|
|
24
|
-
error "No dependency data
|
|
24
|
+
error "No dependency data for commit #{commit_sha[0, 7]}. Run 'git pkgs update' to index new commits." unless commit
|
|
25
25
|
|
|
26
26
|
# Get current snapshots
|
|
27
27
|
snapshots = commit.dependency_snapshots.includes(:manifest)
|
|
@@ -26,7 +26,7 @@ module Git
|
|
|
26
26
|
current_sha = repo.branch_target(branch_name)
|
|
27
27
|
|
|
28
28
|
if since_sha == current_sha
|
|
29
|
-
|
|
29
|
+
info "Already up to date."
|
|
30
30
|
return
|
|
31
31
|
end
|
|
32
32
|
|
|
@@ -50,17 +50,19 @@ module Git
|
|
|
50
50
|
walker = repo.walk(branch_name, since_sha)
|
|
51
51
|
commits = walker.to_a
|
|
52
52
|
total = commits.size
|
|
53
|
+
repo.prefetch_blob_paths(commits)
|
|
54
|
+
|
|
53
55
|
processed = 0
|
|
54
56
|
dependency_commits = 0
|
|
55
57
|
last_position = Models::BranchCommit.where(branch: branch).maximum(:position) || 0
|
|
56
58
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
+
info "Updating branch: #{branch_name}"
|
|
60
|
+
info "Found #{total} new commits"
|
|
59
61
|
|
|
60
62
|
ActiveRecord::Base.transaction do
|
|
61
63
|
commits.each do |rugged_commit|
|
|
62
64
|
processed += 1
|
|
63
|
-
print "\rProcessing commit #{processed}/#{total}..."
|
|
65
|
+
print "\rProcessing commit #{processed}/#{total}..." unless Git::Pkgs.quiet
|
|
64
66
|
|
|
65
67
|
result = analyzer.analyze_commit(rugged_commit, snapshot)
|
|
66
68
|
|
|
@@ -114,9 +116,9 @@ module Git
|
|
|
114
116
|
branch.update(last_analyzed_sha: current_sha)
|
|
115
117
|
end
|
|
116
118
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
119
|
+
info "\nDone!"
|
|
120
|
+
info "Processed #{total} new commits"
|
|
121
|
+
info "Found #{dependency_commits} commits with dependency changes"
|
|
120
122
|
end
|
|
121
123
|
|
|
122
124
|
def parse_options
|
|
@@ -21,13 +21,13 @@ module Git
|
|
|
21
21
|
current = Database::SCHEMA_VERSION
|
|
22
22
|
|
|
23
23
|
if stored >= current
|
|
24
|
-
|
|
24
|
+
info "Database is up to date (version #{current})"
|
|
25
25
|
return
|
|
26
26
|
end
|
|
27
27
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
28
|
+
info "Upgrading database from version #{stored} to #{current}..."
|
|
29
|
+
info "This requires re-indexing the repository."
|
|
30
|
+
info ""
|
|
31
31
|
|
|
32
32
|
# Run init --force
|
|
33
33
|
Init.new(["--force"]).run
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "bibliothecary"
|
|
4
|
+
|
|
5
|
+
module Git
|
|
6
|
+
module Pkgs
|
|
7
|
+
module Config
|
|
8
|
+
# Ecosystems that require remote parsing services - disabled by default
|
|
9
|
+
REMOTE_ECOSYSTEMS = %w[carthage clojars hackage hex swiftpm].freeze
|
|
10
|
+
|
|
11
|
+
# File patterns ignored by default (SBOM formats not supported)
|
|
12
|
+
DEFAULT_IGNORED_FILES = %w[
|
|
13
|
+
cyclonedx.xml
|
|
14
|
+
cyclonedx.json
|
|
15
|
+
*.cdx.xml
|
|
16
|
+
*.cdx.json
|
|
17
|
+
*.spdx
|
|
18
|
+
*.spdx.json
|
|
19
|
+
].freeze
|
|
20
|
+
|
|
21
|
+
def self.ignored_dirs
|
|
22
|
+
@ignored_dirs ||= read_config_list("pkgs.ignoredDirs")
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def self.ignored_files
|
|
26
|
+
@ignored_files ||= read_config_list("pkgs.ignoredFiles")
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def self.ecosystems
|
|
30
|
+
@ecosystems ||= read_config_list("pkgs.ecosystems")
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def self.configure_bibliothecary
|
|
34
|
+
dirs = ignored_dirs
|
|
35
|
+
files = DEFAULT_IGNORED_FILES + ignored_files
|
|
36
|
+
|
|
37
|
+
Bibliothecary.configure do |config|
|
|
38
|
+
config.ignored_dirs += dirs unless dirs.empty?
|
|
39
|
+
config.ignored_files += files
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def self.filter_ecosystem?(platform)
|
|
44
|
+
platform_lower = platform.to_s.downcase
|
|
45
|
+
|
|
46
|
+
# Remote ecosystems are disabled unless explicitly enabled
|
|
47
|
+
if REMOTE_ECOSYSTEMS.include?(platform_lower)
|
|
48
|
+
return !ecosystems.map(&:downcase).include?(platform_lower)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# If no filter configured, allow all non-remote ecosystems
|
|
52
|
+
return false if ecosystems.empty?
|
|
53
|
+
|
|
54
|
+
# Otherwise, only allow explicitly listed ecosystems
|
|
55
|
+
!ecosystems.map(&:downcase).include?(platform_lower)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def self.remote_ecosystem?(platform)
|
|
59
|
+
REMOTE_ECOSYSTEMS.include?(platform.to_s.downcase)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def self.reset!
|
|
63
|
+
@ignored_dirs = nil
|
|
64
|
+
@ignored_files = nil
|
|
65
|
+
@ecosystems = nil
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def self.read_config_list(key)
|
|
69
|
+
`git config --get-all #{key} 2>/dev/null`.split("\n").map(&:strip).reject(&:empty?)
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
data/lib/git/pkgs/database.rb
CHANGED
|
@@ -10,22 +10,21 @@ module Git
|
|
|
10
10
|
SCHEMA_VERSION = 1
|
|
11
11
|
|
|
12
12
|
def self.path(git_dir = nil)
|
|
13
|
-
return
|
|
13
|
+
return Git::Pkgs.db_path if Git::Pkgs.db_path
|
|
14
14
|
|
|
15
15
|
git_dir ||= find_git_dir
|
|
16
16
|
File.join(git_dir, DB_FILE)
|
|
17
17
|
end
|
|
18
18
|
|
|
19
19
|
def self.find_git_dir
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
git_dir = ENV["GIT_DIR"]
|
|
23
|
-
return git_dir if File.directory?(git_dir)
|
|
20
|
+
if Git::Pkgs.git_dir
|
|
21
|
+
return Git::Pkgs.git_dir if File.directory?(Git::Pkgs.git_dir)
|
|
24
22
|
|
|
25
|
-
raise NotInGitRepoError, "GIT_DIR '#{git_dir}' does not exist"
|
|
23
|
+
raise NotInGitRepoError, "GIT_DIR '#{Git::Pkgs.git_dir}' does not exist"
|
|
26
24
|
end
|
|
27
25
|
|
|
28
|
-
|
|
26
|
+
# Start from work_tree if set, otherwise current directory
|
|
27
|
+
dir = Git::Pkgs.work_tree || Dir.pwd
|
|
29
28
|
loop do
|
|
30
29
|
git_dir = File.join(dir, ".git")
|
|
31
30
|
return git_dir if File.directory?(git_dir)
|
|
@@ -59,6 +58,7 @@ module Git
|
|
|
59
58
|
end
|
|
60
59
|
|
|
61
60
|
def self.create_schema(with_indexes: true)
|
|
61
|
+
ActiveRecord::Schema.verbose = false
|
|
62
62
|
ActiveRecord::Schema.define do
|
|
63
63
|
create_table :schema_info, if_not_exists: true do |t|
|
|
64
64
|
t.integer :version, null: false
|
|
@@ -20,6 +20,25 @@ module Git
|
|
|
20
20
|
end
|
|
21
21
|
end
|
|
22
22
|
|
|
23
|
+
def self.find_or_create_from_repo(repo, sha)
|
|
24
|
+
commit = find_by(sha: sha) || where("sha LIKE ?", "#{sha}%").first
|
|
25
|
+
return commit if commit
|
|
26
|
+
|
|
27
|
+
rugged_commit = repo.lookup(sha)
|
|
28
|
+
return nil unless rugged_commit
|
|
29
|
+
|
|
30
|
+
create!(
|
|
31
|
+
sha: rugged_commit.oid,
|
|
32
|
+
message: rugged_commit.message,
|
|
33
|
+
author_name: rugged_commit.author[:name],
|
|
34
|
+
author_email: rugged_commit.author[:email],
|
|
35
|
+
committed_at: rugged_commit.time,
|
|
36
|
+
has_dependency_changes: false
|
|
37
|
+
)
|
|
38
|
+
rescue Rugged::OdbError
|
|
39
|
+
nil
|
|
40
|
+
end
|
|
41
|
+
|
|
23
42
|
def short_sha
|
|
24
43
|
sha[0, 7]
|
|
25
44
|
end
|
data/lib/git/pkgs/output.rb
CHANGED
|
@@ -1,12 +1,25 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "json"
|
|
4
|
+
require "time"
|
|
4
5
|
require_relative "pager"
|
|
5
6
|
|
|
6
7
|
module Git
|
|
7
8
|
module Pkgs
|
|
8
9
|
module Output
|
|
9
10
|
include Pager
|
|
11
|
+
|
|
12
|
+
def parse_time(str)
|
|
13
|
+
Time.parse(str)
|
|
14
|
+
rescue ArgumentError
|
|
15
|
+
error "Invalid date format: #{str}. Use YYYY-MM-DD format."
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Print informational/status message. Suppressed in quiet mode.
|
|
19
|
+
def info(msg)
|
|
20
|
+
puts msg unless Git::Pkgs.quiet
|
|
21
|
+
end
|
|
22
|
+
|
|
10
23
|
# Print error message and exit with code 1.
|
|
11
24
|
# Use for user errors (bad input, invalid refs) and system errors (db missing).
|
|
12
25
|
# When format is :json, outputs JSON to stdout; otherwise outputs text to stderr.
|
data/lib/git/pkgs/repository.rb
CHANGED
|
@@ -8,8 +8,9 @@ module Git
|
|
|
8
8
|
attr_reader :path
|
|
9
9
|
|
|
10
10
|
def initialize(path = nil)
|
|
11
|
-
@path = path ||
|
|
11
|
+
@path = path || Git::Pkgs.git_dir || Git::Pkgs.work_tree || Dir.pwd
|
|
12
12
|
@rugged = Rugged::Repository.new(@path)
|
|
13
|
+
@blob_paths_cache = {}
|
|
13
14
|
end
|
|
14
15
|
|
|
15
16
|
def git_dir
|
|
@@ -62,7 +63,40 @@ module Git
|
|
|
62
63
|
@rugged.lookup(sha)
|
|
63
64
|
end
|
|
64
65
|
|
|
66
|
+
DEFAULT_THREADS = 4
|
|
67
|
+
|
|
68
|
+
def prefetch_blob_paths(commits)
|
|
69
|
+
thread_count = Git::Pkgs.threads || DEFAULT_THREADS
|
|
70
|
+
|
|
71
|
+
# Serial is faster for small repos due to thread overhead
|
|
72
|
+
if commits.size < 1500 || thread_count <= 1
|
|
73
|
+
commits.each { |c| @blob_paths_cache[c.oid] = compute_blob_paths(c) }
|
|
74
|
+
return
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
queue = Queue.new
|
|
78
|
+
mutex = Mutex.new
|
|
79
|
+
|
|
80
|
+
commits.each { |c| queue << c }
|
|
81
|
+
thread_count.times { queue << nil }
|
|
82
|
+
|
|
83
|
+
thread_pool = thread_count.times.map do
|
|
84
|
+
Thread.new do
|
|
85
|
+
while (commit = queue.pop)
|
|
86
|
+
paths = compute_blob_paths(commit)
|
|
87
|
+
mutex.synchronize { @blob_paths_cache[commit.oid] = paths }
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
thread_pool.each(&:join)
|
|
93
|
+
end
|
|
94
|
+
|
|
65
95
|
def blob_paths(rugged_commit)
|
|
96
|
+
@blob_paths_cache[rugged_commit.oid] || compute_blob_paths(rugged_commit)
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def compute_blob_paths(rugged_commit)
|
|
66
100
|
paths = []
|
|
67
101
|
|
|
68
102
|
if rugged_commit.parents.empty?
|
data/lib/git/pkgs/version.rb
CHANGED
data/lib/git/pkgs.rb
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
require_relative "pkgs/version"
|
|
4
4
|
require_relative "pkgs/output"
|
|
5
5
|
require_relative "pkgs/color"
|
|
6
|
+
require_relative "pkgs/config"
|
|
6
7
|
require_relative "pkgs/cli"
|
|
7
8
|
require_relative "pkgs/database"
|
|
8
9
|
require_relative "pkgs/repository"
|
|
@@ -35,11 +36,44 @@ require_relative "pkgs/commands/log"
|
|
|
35
36
|
require_relative "pkgs/commands/upgrade"
|
|
36
37
|
require_relative "pkgs/commands/schema"
|
|
37
38
|
require_relative "pkgs/commands/diff_driver"
|
|
39
|
+
require_relative "pkgs/commands/completions"
|
|
38
40
|
|
|
39
41
|
module Git
|
|
40
42
|
module Pkgs
|
|
41
43
|
class Error < StandardError; end
|
|
42
44
|
class NotInitializedError < Error; end
|
|
43
45
|
class NotInGitRepoError < Error; end
|
|
46
|
+
|
|
47
|
+
class << self
|
|
48
|
+
attr_accessor :quiet, :git_dir, :work_tree, :db_path, :batch_size, :snapshot_interval, :threads
|
|
49
|
+
|
|
50
|
+
def configure_from_env
|
|
51
|
+
@git_dir ||= presence(ENV["GIT_DIR"])
|
|
52
|
+
@work_tree ||= presence(ENV["GIT_WORK_TREE"])
|
|
53
|
+
@db_path ||= presence(ENV["GIT_PKGS_DB"])
|
|
54
|
+
@batch_size ||= int_presence(ENV["GIT_PKGS_BATCH_SIZE"])
|
|
55
|
+
@snapshot_interval ||= int_presence(ENV["GIT_PKGS_SNAPSHOT_INTERVAL"])
|
|
56
|
+
@threads ||= int_presence(ENV["GIT_PKGS_THREADS"])
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def reset_config!
|
|
60
|
+
@quiet = false
|
|
61
|
+
@git_dir = nil
|
|
62
|
+
@work_tree = nil
|
|
63
|
+
@db_path = nil
|
|
64
|
+
@batch_size = nil
|
|
65
|
+
@snapshot_interval = nil
|
|
66
|
+
@threads = nil
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def int_presence(value)
|
|
70
|
+
value && !value.empty? ? value.to_i : nil
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def presence(value)
|
|
74
|
+
value && !value.empty? ? value : nil
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
self.quiet = false
|
|
44
78
|
end
|
|
45
79
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: git-pkgs
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.5.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Andrew Nesbitt
|
|
@@ -75,17 +75,8 @@ extensions: []
|
|
|
75
75
|
extra_rdoc_files: []
|
|
76
76
|
files:
|
|
77
77
|
- CHANGELOG.md
|
|
78
|
-
- CODE_OF_CONDUCT.md
|
|
79
|
-
- CONTRIBUTING.md
|
|
80
78
|
- LICENSE
|
|
81
79
|
- README.md
|
|
82
|
-
- Rakefile
|
|
83
|
-
- SECURITY.md
|
|
84
|
-
- benchmark_bulk.rb
|
|
85
|
-
- benchmark_db.rb
|
|
86
|
-
- benchmark_detailed.rb
|
|
87
|
-
- benchmark_full.rb
|
|
88
|
-
- docs/schema.md
|
|
89
80
|
- exe/git-pkgs
|
|
90
81
|
- lib/git/pkgs.rb
|
|
91
82
|
- lib/git/pkgs/analyzer.rb
|
|
@@ -93,6 +84,7 @@ files:
|
|
|
93
84
|
- lib/git/pkgs/color.rb
|
|
94
85
|
- lib/git/pkgs/commands/blame.rb
|
|
95
86
|
- lib/git/pkgs/commands/branch.rb
|
|
87
|
+
- lib/git/pkgs/commands/completions.rb
|
|
96
88
|
- lib/git/pkgs/commands/diff.rb
|
|
97
89
|
- lib/git/pkgs/commands/diff_driver.rb
|
|
98
90
|
- lib/git/pkgs/commands/history.rb
|
|
@@ -111,6 +103,7 @@ files:
|
|
|
111
103
|
- lib/git/pkgs/commands/upgrade.rb
|
|
112
104
|
- lib/git/pkgs/commands/where.rb
|
|
113
105
|
- lib/git/pkgs/commands/why.rb
|
|
106
|
+
- lib/git/pkgs/config.rb
|
|
114
107
|
- lib/git/pkgs/database.rb
|
|
115
108
|
- lib/git/pkgs/models/branch.rb
|
|
116
109
|
- lib/git/pkgs/models/branch_commit.rb
|
data/CODE_OF_CONDUCT.md
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
# Code of Conduct
|
|
2
|
-
|
|
3
|
-
"git-pkgs" follows [The Ruby Community Conduct Guideline](https://www.ruby-lang.org/en/conduct) in all "collaborative space", which is defined as community communications channels (such as mailing lists, submitted patches, commit comments, etc.):
|
|
4
|
-
|
|
5
|
-
* Participants will be tolerant of opposing views.
|
|
6
|
-
* Participants must ensure that their language and actions are free of personal attacks and disparaging personal remarks.
|
|
7
|
-
* When interpreting the words and actions of others, participants should always assume good intentions.
|
|
8
|
-
* Behaviour which can be reasonably considered harassment will not be tolerated.
|
|
9
|
-
|
|
10
|
-
If you have any concerns about behaviour within this project, please contact us at ["andrewnez@gmail.com"](mailto:"andrewnez@gmail.com").
|
data/CONTRIBUTING.md
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
# Contributing
|
|
2
|
-
|
|
3
|
-
## Setup
|
|
4
|
-
|
|
5
|
-
```bash
|
|
6
|
-
git clone https://github.com/andrew/git-pkgs
|
|
7
|
-
cd git-pkgs
|
|
8
|
-
bin/setup
|
|
9
|
-
```
|
|
10
|
-
|
|
11
|
-
## Running tests
|
|
12
|
-
|
|
13
|
-
```bash
|
|
14
|
-
bundle exec rake test
|
|
15
|
-
```
|
|
16
|
-
|
|
17
|
-
## Pull requests
|
|
18
|
-
|
|
19
|
-
1. Fork the repo
|
|
20
|
-
2. Create a branch
|
|
21
|
-
3. Make your changes
|
|
22
|
-
4. Run tests
|
|
23
|
-
5. Open a PR
|
|
24
|
-
|
|
25
|
-
## Reporting bugs
|
|
26
|
-
|
|
27
|
-
Open an issue with steps to reproduce.
|
data/Rakefile
DELETED