aboutsummaryrefslogtreecommitdiff
blob: fd599761e72216554039a81d9b72cd052e2f2cfd (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
151
152
153
154
155
156
157
158
159
160
161
#!/usr/bin/python

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


from __future__ import print_function


import os
import sys

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


class CleanUp(object):
	"""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):
		self.controller = controller

	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_keys = self._sort_keys(clean_dict)
		clean_size = 0
		# clean all entries one by one
		for key in clean_keys:
			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_keys = self._sort_keys(clean_dict)
		clean_size = 0
		# clean all entries one by one
		for key in clean_keys:
			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.call_emaint()
		# 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_keys = self._sort_keys(clean_dict)
		clean_size = 0
		# tally all entries one by one
		for key in clean_keys:
			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 EnvironmentError 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 _sort_keys(self, clean_dict):
		"""Returns a list of sorted dictionary keys."""
		# sorting helps reading
		clean_keys = sorted(clean_dict)
		return clean_keys

	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 EnvironmentError 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 EnvironmentError 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
				except EnvironmentError 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