Skip to content
GitLab
Explore
Sign in
Register
Primary navigation
Search or go to…
Project
D
Deep clean
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Package registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
GitLab community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
nimrod
Deep clean
Commits
6077b711
Commit
6077b711
authored
3 years ago
by
nimrod
Browse files
Options
Downloads
Patches
Plain Diff
Implementation.
parent
bdc134d6
No related branches found
No related tags found
No related merge requests found
Pipeline
#2874
failed
3 years ago
Stage: .pre
Stage: build
Stage: test
Changes
1
Pipelines
1
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
deepclean/__main__.py
+164
-2
164 additions, 2 deletions
deepclean/__main__.py
with
164 additions
and
2 deletions
deepclean/__main__.py
+
164
−
2
View file @
6077b711
"""
Clean old versions of Docker images.
"""
"""
Clean old versions of Docker images.
"""
import
argparse
import
argparse
import
re
import
docker
# pylint: disable=import-error,useless-suppression
from
.
import
__version__
def
image_date
(
image
):
"""
Return the creation date of the image.
"""
return
image
.
history
()[
0
][
"
Created
"
]
def
include
(
images
,
includes
,
verbose
):
"""
Return only the images that match the regexes in the includes list.
"""
regexes
=
[
re
.
compile
(
r
)
for
r
in
includes
]
included_images
=
{}
for
Id
,
image
in
images
.
items
():
# noqa: N806 pylint: disable=invalid-name
for
tag
in
image
.
tags
:
for
r
in
regexes
:
# pylint: disable=invalid-name
if
r
.
match
(
tag
):
if
verbose
:
print
(
f
"
Including image
{
Id
}
.
"
)
included_images
[
Id
]
=
image
break
return
included_images
def
exclude
(
images
,
excludes
,
verbose
):
"""
Return the images that don
'
t match the regexes in the excludes list.
"""
remaining_images
=
images
.
copy
()
regexes
=
[
re
.
compile
(
r
)
for
r
in
excludes
]
# pylint: disable=invalid-name
for
(
Id
,
image
)
in
images
.
items
():
# noqa: N806
for
tag
in
image
.
tags
:
for
r
in
regexes
:
if
r
.
match
(
tag
):
if
verbose
:
print
(
f
"
Excluding image
{
Id
}
.
"
)
remaining_images
.
pop
(
Id
)
break
return
remaining_images
def
not_in_use
(
client
,
images
,
verbose
):
"""
Return the images that aren
'
t in use by containers right now.
"""
in_use_images
=
[
c
.
image
.
id
for
c
in
client
.
containers
.
list
()]
not_in_use_images
=
images
.
copy
()
# pylint: disable=invalid-name
for
Id
in
in_use_images
:
# noqa: N806
if
verbose
:
print
(
f
"
Image
{
Id
}
is in use, ignoring.
"
)
not_in_use_images
.
pop
(
Id
)
return
not_in_use_images
def
normalize_names
(
images_by_name
):
"""
Normalize the different Docker hub registry names.
"""
copy_of_images
=
{
k
:
v
[:]
for
k
,
v
in
images_by_name
.
items
()}
for
name
in
images_by_name
.
keys
():
if
name
.
startswith
(
"
registry.hub.docker.com
"
):
new_name
=
name
.
replace
(
"
registry.hub.docker.com
"
,
"
docker.io
"
,
1
)
if
new_name
in
copy_of_images
:
copy_of_images
[
new_name
]
=
list
(
set
(
copy_of_images
[
name
]
+
copy_of_images
[
new_name
])
)
copy_of_images
[
new_name
].
sort
(
key
=
image_date
,
reverse
=
True
)
else
:
copy_of_images
[
new_name
]
=
copy_of_images
[
name
]
copy_of_images
.
pop
(
name
)
return
copy_of_images
def
deepclean
(
includes
=
None
,
excludes
=
None
,
verbose
=
False
,
dry_run
=
False
):
# noqa: MC0001
"""
Clean old versions of Docker images.
"""
client
=
docker
.
from_env
()
images
=
{
i
.
id
:
i
for
i
in
client
.
images
.
list
()}
images
=
not_in_use
(
client
,
images
,
verbose
)
if
includes
:
images
=
include
(
images
,
includes
,
verbose
)
if
excludes
:
images
=
exclude
(
images
,
excludes
,
verbose
)
# First we build a dictionary with the image name as key and the value is
# an empty list that later will contain the images that have that name.
images_by_name
=
{
name
.
split
(
"
:
"
)[
0
]:
[]
for
image
in
images
.
values
()
for
name
in
image
.
tags
}
# Now we're populating the list of images for each image name.
# We keep the list of images sorted from most recent to least.
for
image
in
images
.
values
():
for
tag
in
image
.
tags
:
name
=
tag
.
split
(
"
:
"
)[
0
]
images_by_name
[
name
].
append
(
image
)
images_by_name
[
name
].
sort
(
key
=
image_date
,
reverse
=
True
)
images_by_name
=
normalize_names
(
images_by_name
)
# noqa: LPY101
for
name
in
images_by_name
.
keys
():
kept
=
images_by_name
[
name
][
0
].
id
if
kept
in
images
:
if
verbose
:
print
(
f
"
Keeping
{
kept
}
, the latest image for
{
name
}
.
"
)
images
.
pop
(
kept
)
# Now we've removed the images that are in use, kept the included ones,
# removed the excluded ones and the latest image for each name. We're left
# with images that are meant for deletion.
# pylint: disable=invalid-name
for
Id
in
images
.
keys
():
# noqa: N806
if
dry_run
:
print
(
f
"
Would have removed image
{
Id
}
.
"
)
else
:
print
(
f
"
Removing image
{
Id
}
.
"
)
client
.
image
.
remove
(
Id
)
def
main
():
def
main
():
"""
Main entrypoint.
"""
# noqa: D401
"""
The main entrypoint.
"""
epilog
=
(
"
Regular Docker environment variables (like DOCKER_HOST) can be used.
"
"
-i and -e can be used multiple times.
"
)
parser
=
argparse
.
ArgumentParser
(
parser
=
argparse
.
ArgumentParser
(
description
=
__doc__
,
description
=
__doc__
,
epilog
=
epilog
,
)
parser
.
add_argument
(
"
-i
"
,
"
--include
"
,
help
=
"
Regular expression of images to exclusively prune.
"
,
action
=
"
append
"
,
)
parser
.
add_argument
(
"
-e
"
,
"
--exclude
"
,
help
=
"
Regular expression of images to ignore.
"
,
action
=
"
append
"
,
)
parser
.
add_argument
(
"
-v
"
,
"
--verbose
"
,
help
=
"
Verbose output
"
,
action
=
"
store_true
"
)
parser
.
add_argument
(
"
-V
"
,
"
--version
"
,
action
=
"
version
"
,
version
=
f
"
deepclean version
{
__version__
}
"
,
)
parser
.
add_argument
(
"
-d
"
,
"
--dry-run
"
,
help
=
"
Dry-run, don
'
t delete
"
,
action
=
"
store_true
"
)
)
args
=
parser
.
parse_args
()
args
=
parser
.
parse_args
()
print
(
args
)
try
:
deepclean
(
includes
=
args
.
include
,
excludes
=
args
.
exclude
,
verbose
=
args
.
verbose
,
dry_run
=
args
.
dry_run
,
)
except
Exception
as
ex
:
# noqa: PIE786 pylint: disable=broad-except
parser
.
error
(
str
(
ex
))
if
__name__
==
"
__main__
"
:
if
__name__
==
"
__main__
"
:
...
...
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment