aboutsummaryrefslogtreecommitdiffstats
path: root/Library/Homebrew/cask/lib/hbc/cli/cleanup.rb
blob: 356162db552e28d4ba9d42bec7e587133aaa5008 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
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
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
module Hbc
  class CLI
    class Cleanup < AbstractCommand
      OUTDATED_DAYS = 10
      OUTDATED_TIMESTAMP = Time.now - (60 * 60 * 24 * OUTDATED_DAYS)

      def self.help
        "cleans up cached downloads and tracker symlinks"
      end

      def self.needs_init?
        true
      end

      attr_reader :cache_location

      def initialize(*args, cache_location: Hbc.cache)
        super(*args)
        @cache_location = Pathname.new(cache_location)
      end

      def run
        remove_cache_files(*args)
      end

      def cache_files
        return [] unless cache_location.exist?
        cache_location.children
                      .map(&method(:Pathname))
                      .reject(&method(:outdated?))
      end

      def outdated?(file)
        outdated_only? && file && file.stat.mtime > OUTDATED_TIMESTAMP
      end

      def incomplete?(file)
        file.extname == ".incomplete"
      end

      def cache_incompletes
        cache_files.select(&method(:incomplete?))
      end

      def cache_completes
        cache_files.reject(&method(:incomplete?))
      end

      def disk_cleanup_size
        cache_files.map(&:disk_usage).inject(:+)
      end

      def remove_cache_files(*tokens)
        message = "Removing cached downloads"
        message.concat " for #{tokens.join(", ")}" unless tokens.empty?
        message.concat " older than #{OUTDATED_DAYS} days old" if outdated_only?
        ohai message

        deletable_cache_files = if tokens.empty?
          cache_files
        else
          start_withs = tokens.map { |token| "#{token}--" }

          cache_files.select do |path|
            path.basename.to_s.start_with?(*start_withs)
          end
        end

        delete_paths(deletable_cache_files)
      end

      def delete_paths(paths)
        cleanup_size = 0
        processed_files = 0
        paths.each do |item|
          next unless item.exist?
          processed_files += 1

          begin
            LockFile.new(item.basename).with_lock do
              puts item
              item_size = File.size?(item)
              cleanup_size += item_size unless item_size.nil?
              item.unlink
            end
          rescue OperationInProgressError
            puts "skipping: #{item} is locked"
            next
          end
        end

        if processed_files.zero?
          puts "Nothing to do"
        else
          disk_space = disk_usage_readable(cleanup_size)
          ohai "This operation has freed approximately #{disk_space} of disk space."
        end
      end
    end
  end
end