aboutsummaryrefslogtreecommitdiff
blob: 87d7aaca1477f958e2cd8add925588afc253cffd (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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
#!/usr/bin/python

# Copyright 2003-2010 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2


import os
import sys

import gentoolkit.pprinter as pp
from gentoolkit.eclean.pkgindex import PkgIndex


class CleanUp:
    """Performs all cleaning actions to distfiles or package directories.

    @param controller: a progress output/user interaction controller function
                                       which returns a Boolean to control file deletion
                                       or bypassing/ignoring
    """

    def __init__(self, controller, quiet):
        self.controller = controller
        self.quiet = quiet

    def clean_dist(self, clean_dict):
        """Calculate size of each entry for display, prompt user if needed,
        delete files if approved and return the total size of files that
        have been deleted.

        @param clean_dict: dictionary of {'display name':[list of files]}

        @rtype: int
        @return: total size that was cleaned
        """
        file_type = "file"
        clean_size = 0
        # clean all entries one by one; sorting helps reading
        for key in sorted(clean_dict):
            clean_size += self._clean_files(clean_dict[key], key, file_type)
        # return total size of deleted or to delete files
        return clean_size

    def clean_pkgs(self, clean_dict, pkgdir):
        """Calculate size of each entry for display, prompt user if needed,
        delete files if approved and return the total size of files that
        have been deleted.

        @param clean_dict:  dictionary of  {'display name':[list of files]}
        @param metadata: package index of type portage.getbinpkg.PackageIndex()
        @param pkgdir: path to the package directory to be cleaned

        @rtype: int
        @return: total size that was cleaned
        """
        file_type = "binary package"
        clean_size = 0
        # clean all entries one by one; sorting helps reading
        for key in sorted(clean_dict):
            clean_size += self._clean_files(clean_dict[key], key, file_type)

        #  run 'emaint --fix' here
        if clean_size:
            index_control = PkgIndex(self.controller)
            # emaint is not yet importable so call it
            # print a blank line here for separation
            print()
            clean_size += index_control.clean_pkgs_index(self.quiet)
        # return total size of deleted or to delete files
        return clean_size

    def pretend_clean(self, clean_dict):
        """Shortcut function that calculates total space savings
        for the files in clean_dict.

        @param clean_dict: dictionary of {'display name':[list of files]}
        @rtype: integer
        @return: total size that would be cleaned
        """
        file_type = "file"
        clean_size = 0
        # tally all entries one by one; sorting helps reading
        for key in sorted(clean_dict):
            key_size = self._get_size(clean_dict[key])
            self.controller(key_size, key, clean_dict[key], file_type)
            clean_size += key_size
        return clean_size

    def _get_size(self, key):
        """Determine the total size for an entry (may be several files)."""
        key_size = 0
        for file_ in key:
            # print file_
            # get total size for an entry (may be several files, and
            # links don't count
            # ...get its statinfo
            try:
                statinfo = os.stat(file_)
                if statinfo.st_nlink == 1:
                    key_size += statinfo.st_size
            except OSError as er:
                print(pp.error("Could not get stat info for:" + file_), file=sys.stderr)
                print(pp.error("Error: %s" % str(er)), file=sys.stderr)
        return key_size

    def _clean_files(self, files, key, file_type):
        """File removal function."""
        clean_size = 0
        for file_ in files:
            # print file_, type(file_)
            # ...get its statinfo
            try:
                statinfo = os.stat(file_)
            except OSError as er:
                if not os.path.exists(os.readlink(file_)):
                    try:
                        os.remove(file_)
                        print(
                            pp.error("Removed broken symbolic link " + file_),
                            file=sys.stderr,
                        )
                        break
                    except OSError as er:
                        print(
                            pp.error("Error deleting broken symbolic link " + file_),
                            file=sys.stderr,
                        )
                        print(pp.error("Error: %s" % str(er)), file=sys.stderr)
                        break
                else:
                    print(
                        pp.error("Could not get stat info for:" + file_),
                        file=sys.stderr,
                    )
                    print(pp.error("Error: %s" % str(er)), file=sys.stderr)
            if self.controller(statinfo.st_size, key, file_, file_type):
                # ... try to delete it.
                try:
                    os.unlink(file_)
                    # only count size if successfully deleted and not a link
                    if statinfo.st_nlink == 1:
                        clean_size += statinfo.st_size
                        try:
                            os.rmdir(os.path.dirname(file_))
                        except OSError:
                            pass
                except OSError as er:
                    print(pp.error("Could not delete " + file_), file=sys.stderr)
                    print(pp.error("Error: %s" % str(er)), file=sys.stderr)
        return clean_size