33 from __future__
import print_function
37 from distutils.spawn
import find_executable
50 Pretty print cmds, ask if they should be run, and if so, runs 53 :param cmds: a list of commands executed one after another, ``list`` 54 :param cwd: (optional) set cwd of command that is executed, ``str`` 55 :returns: ``True`` if cmds were run. 59 return '"%s"'%s
if ' ' in s
else s
60 accepted =
_ask(
'\n'.join([
' '.join([quote(s)
for s
in c])
for c
in cmds]))
67 ask user with provided comment. If user responds with y, return True 69 :param comment: comment, ``str`` 70 :return: ``True`` if user responds with y 72 sys.stdout.write(
"Okay to perform:\n\n%s\n(y/n)?\n"%comment)
74 input = sys.stdin.readline().strip().lower()
75 if input
in [
'y',
'n']:
81 Runs cmds using subprocess.check_call. 83 :param cmds: a list of commands executed one after another, ``list`` 84 :param cwd: (optional) set cwd of command that is executed, ``str`` 88 subprocess.check_call(c, cwd=cwd)
90 subprocess.check_call(c)
93 print(
"""Usage: rosclean <command> 96 \trosclean check\tCheck usage of log files 97 \trosclean purge\tRemove log files 99 sys.exit(getattr(os,
'EX_USAGE', 1))
102 home_dir = rospkg.get_ros_home()
103 log_dir = rospkg.get_log_dir()
104 dirs = [ (log_dir,
'ROS node logs'),
105 (os.path.join(home_dir,
'rosmake'),
'rosmake logs')]
106 return [x
for x
in dirs
if os.path.isdir(x[0])]
110 for d, label
in dirs:
112 print(
"%s %s"%(desc, label))
116 for dirpath, dirnames, filenames
in os.walk(d):
118 fp = os.path.join(dirpath, f)
119 total_size += os.path.getsize(fp)
124 Get human-readable disk usage for directory 126 :param d: directory path, ``str` 127 :returns: human-readable disk usage (du -h), ``str`` 130 if platform.system()
in [
'Linux',
'FreeBSD']:
132 return subprocess.Popen([
'du',
'-sh', d], stdout=subprocess.PIPE).communicate()[0].split()[0]
135 elif platform.system() ==
'Windows':
137 return "Total Size: " + str(total_size) +
" " + d
143 Get disk usage in bytes for directory 144 :param d: directory path, ``str`` 145 :returns: disk usage in bytes (du -b) or (du -A) * 1024, ``int`` 146 :raises: :exc:`CleanupException` If get_disk_usage() cannot be used on this platform 148 if platform.system() ==
'Windows':
154 du = find_executable(
'du')
156 if platform.system() ==
'Linux':
158 elif platform.system() ==
'FreeBSD':
159 cmd = [du,
'-skA', d]
163 if os.path.basename(os.readlink(du)) ==
'busybox':
173 return int(subprocess.Popen(cmd, stdout=subprocess.PIPE).communicate()[0].split()[0]) * unit
179 Get files and directories in specified path sorted by last modified time 180 :param d: directory path, ```str``` 181 :return: a list of files and directories sorted by last modified time (old first), ```list``` 183 files = os.listdir(d)
184 files.sort(key=
lambda f: os.path.getmtime(os.path.join(d, f)))
190 for d, label
in dirs:
192 print(
"Purging %s."%label)
193 cmds = [[
'rm',
'-rf', d]]
198 print(
"PLEASE BE CAREFUL TO VERIFY THE COMMAND BELOW!")
201 print(
"FAILED to execute command", file=sys.stderr)
205 if log_size <= args.size * 1024 * 1024:
206 print(
"Directory size of %s is %d MB which is already below the requested threshold of %d MB."%(label, log_size / 1024 / 1024, args.size))
208 print(
"Purging %s until directory size is at most %d MB (currently %d MB)."%(label, args.size, log_size / 1024 / 1024))
210 print(
"PLEASE BE CAREFUL TO VERIFY THE COMMAND BELOW!")
211 if not _ask(
"Purge some of old logs in %s"%d):
214 if log_size <= args.size * 1024 * 1024:
216 path = os.path.join(d, f)
218 if platform.system() ==
'Windows':
219 cmds = [[
'rd',
'/s',
'/q', path]]
221 cmds = [[
'rm',
'-rf', path]]
225 print(
"FAILED to execute command", file=sys.stderr)
230 parser = argparse.ArgumentParser(prog=
'rosclean')
231 subparsers = parser.add_subparsers()
232 parser_check = subparsers.add_parser(
'check', help=
'Check usage of log files')
233 parser_check.set_defaults(func=_rosclean_cmd_check)
234 parser_purge = subparsers.add_parser(
'purge', help=
'Remove log files')
235 parser_purge.set_defaults(func=_rosclean_cmd_purge)
236 parser_purge.add_argument(
'-y', action=
'store_true', default=
False, help=
'CAUTION: automatically confirms all questions to delete files')
237 parser_purge.add_argument(
'--size', action=
'store', default=
None, type=int, help=
'Maximum total size in MB to keep when deleting old files')
238 args = parser.parse_args(argv[1:])
241 if __name__ ==
'__main__':
def rosclean_main(argv=None)
def _rosclean_cmd_check(args)
def _sort_file_by_oldest(d)
def _get_disk_usage_by_walking_tree(d)
def get_human_readable_disk_usage(d)
def _call(cmds, cwd=None)
def _ask_and_call(cmds, cwd=None)
def _rosclean_cmd_purge(args)