Class: Autoproj::CLI::Git

Inherits:
InspectionTool
  • Object
show all
Defined in:
lib/autoproj/cli/git.rb

Constant Summary collapse

MATCH_ALL =
proc { true }
MATCH_NONE =
proc { }

Instance Method Summary collapse

Instance Method Details

#author_stats(authors, options = Hash.new) ⇒ Object



43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/autoproj/cli/git.rb', line 43

def author_stats(authors, options = Hash.new)
    git_packages = resolve_selected_git_packages([])

    include_filter =
        if options[:include]
            Regexp.new(options[:include], Regexp::IGNORECASE)
        else
            MATCH_ALL
        end

    exclude_filter =
        if options[:exclude]
            Regexp.new(options[:exclude], Regexp::IGNORECASE)
        else
            MATCH_NONE
        end


    stats = compute_stats(git_packages, "--use-mailmap", *authors.map { |a| "--author=#{a}" }) do |pkg, filename|
        if (include_filter === filename) && !(exclude_filter === filename)
            pkg.name
        end
    end
    display_stats(stats)
end

#authors(options = Hash.new) ⇒ Object



20
21
22
23
24
25
26
27
28
29
30
31
32
# File 'lib/autoproj/cli/git.rb', line 20

def authors(options = Hash.new)
    packages = resolve_selected_git_packages([])
    all_lines = run_parallel(packages) do |pkg, _|
        pkg.importer.run_git(pkg, 'shortlog', '-s', '-e')
    end.flatten

    all_authors = Set.new
    all_lines.each do |line|
        match = /^\s*\d+\s+(.+)$/.match(line)
        all_authors << match[1] if match
    end
    puts all_authors.to_a.sort.join("\n")
end

#cleanup(user_selection, options = Hash.new) ⇒ Object



8
9
10
11
12
13
14
15
# File 'lib/autoproj/cli/git.rb', line 8

def cleanup(user_selection, options = Hash.new)
    git_packages = resolve_selected_git_packages(user_selection)
    run_parallel(git_packages) do |pkg, i|
        cleanup_package(pkg, " [#{i}/#{git_packages.size}]",
                        local: options[:local],
                        remove_obsolete_remotes: options[:remove_obsolete_remotes])
    end
end

#cleanup_package(pkg, progress, options = Hash.new) ⇒ Object



118
119
120
121
122
123
124
125
126
127
128
129
# File 'lib/autoproj/cli/git.rb', line 118

def cleanup_package(pkg, progress, options = Hash.new)
    git_clean_invalid_refs(pkg, progress)
    if options[:remove_obsolete_remotes]
        git_remove_obsolete_remotes(pkg, progress)
    end
    if !options[:local]
        git_remote_prune(pkg, progress)
    end

    git_gc(pkg, progress)
    git_repack(pkg, progress)
end

#compute_stats(packages, *log_options) ⇒ Object



165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
# File 'lib/autoproj/cli/git.rb', line 165

def compute_stats(packages, *log_options)
    all_runs = run_parallel(packages) do |pkg, _|
        lines = pkg.importer.run_git(
            pkg, 'log', *log_options, '--pretty=tformat:', '--numstat')
        [pkg, lines]
    end

    all_runs.each_with_object(Hash.new) do |(pkg, lines), stats|
        lines.each do |l|
            match = /^\s*(\d+)\s+(\d+)\s+(.*)/.match(l)
            if match && (key = yield(pkg, match[3]))
                key_stats = (stats[key] ||= [0, 0])
                key_stats[0] += Integer(match[1])
                key_stats[1] += Integer(match[2])
            end
        end
    end
end

#display_stats(stats, io: STDOUT) ⇒ Object



184
185
186
187
188
189
190
191
192
193
194
195
# File 'lib/autoproj/cli/git.rb', line 184

def display_stats(stats, io: STDOUT)
    total_p, total_m = 0, 0
    stats.keys.sort.each do |text|
        p, m = stats[text]
        total_p += p
        total_m += m
        unless p == 0 && m == 0
            io.puts format("+%6i -%6i %s", p, m, text)
        end
    end
    io.puts format("+%6i -%6i %s", total_p, total_m, "Total")
end

#extension_stats(options = Hash.new) ⇒ Object



34
35
36
37
38
39
40
41
# File 'lib/autoproj/cli/git.rb', line 34

def extension_stats(options = Hash.new)
    git_packages = resolve_selected_git_packages([])

    stats = compute_stats(git_packages) do |pkg, filename|
        File.extname(filename)
    end
    display_stats(stats)
end

#git_all_remotes(pkg) ⇒ Object



90
91
92
93
94
95
96
97
# File 'lib/autoproj/cli/git.rb', line 90

def git_all_remotes(pkg)
    pkg.importer.run_git(pkg, 'config', '--list').
        map do |line|
            if match = /remote\.(.*)\.url=/.match(line)
                match[1]
            end
        end.compact.to_set
end

#git_clean_invalid_refs(pkg, progress) ⇒ Object



69
70
71
72
73
74
75
76
# File 'lib/autoproj/cli/git.rb', line 69

def git_clean_invalid_refs(pkg, progress)
    output = pkg.importer.run_git_bare(pkg, 'show-ref')
    output.each do |line|
        if m = line.match(/error: (.*) does not point to a valid object!/)
            pkg.importer.run_git_bare(pkg, 'update-ref', '-d', m[1])
        end
    end
end

#git_gc(pkg, progress) ⇒ Object



78
79
80
81
82
# File 'lib/autoproj/cli/git.rb', line 78

def git_gc(pkg, progress)
    pkg.progress_start "gc %s#{progress}", done_message: "gc %s#{progress}" do
        pkg.importer.run_git_bare(pkg, 'gc')
    end
end

#git_remote_prune(pkg, progress) ⇒ Object



99
100
101
102
103
# File 'lib/autoproj/cli/git.rb', line 99

def git_remote_prune(pkg, progress)
    pkg.progress_start "pruning %s#{progress}", done_message: "pruned %s#{progress}" do
        pkg.importer.run_git(pkg, 'fetch', '-p')
    end
end

#git_remove_obsolete_remotes(pkg, progress) ⇒ Object



105
106
107
108
109
110
111
112
113
114
115
116
# File 'lib/autoproj/cli/git.rb', line 105

def git_remove_obsolete_remotes(pkg, progress)
    remotes = git_all_remotes(pkg)
    pkg.importer.each_configured_remote do |remote_name, _|
        remotes.delete(remote_name)
    end

    remotes.each do |remote_name|
        pkg.progress_start "removing remote %s/#{remote_name}#{progress}", done_message: "removed remote %s/#{remote_name}#{progress}" do
            pkg.importer.run_git(pkg, 'remote', 'rm', remote_name)
        end
    end
end

#git_repack(pkg, progress) ⇒ Object



84
85
86
87
88
# File 'lib/autoproj/cli/git.rb', line 84

def git_repack(pkg, progress)
    pkg.progress_start "repack %s#{progress}", done_message: "repack %s#{progress}" do
        pkg.importer.run_git_bare(pkg, 'repack', '-adl')
    end
end

#resolve_selected_git_packages(user_selection) ⇒ Object



131
132
133
134
135
136
137
138
139
140
# File 'lib/autoproj/cli/git.rb', line 131

def resolve_selected_git_packages(user_selection)
    initialize_and_load
    source_packages, * =
        finalize_setup(user_selection,
                       non_imported_packages: :ignore)
    source_packages.map do |pkg_name|
        pkg = ws.manifest.find_autobuild_package(pkg_name)
        pkg if pkg.importer.kind_of?(Autobuild::Git)
    end.compact
end

#run_parallel(objects, &block) ⇒ Object



142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
# File 'lib/autoproj/cli/git.rb', line 142

def run_parallel(objects, &block)
    pool = Concurrent::FixedThreadPool.new(4)
    futures = objects.each_with_index.map do |obj, i|
        Concurrent::Future.execute(executor: pool) do
            begin
                result = yield(obj, i)
                [result, nil]
            rescue Autobuild::SubcommandFailed => e
                Autoproj.error "failed: #{e.message}"
                [nil, e]
            end
        end
    end
    result   = futures.each(&:execute).map(&:value!).compact
    failures = result.map(&:last).compact
    result.map(&:first)
rescue Interrupt => interrupt
ensure
    pool.shutdown if pool
    Autobuild::Reporting.report_finish_on_error(
        failures || [], on_package_failures: :raise, interrupted_by: interrupt)
end