plankton 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 924852b6e6ac3d2396454fbc0e818eb5fc0e48a2
4
+ data.tar.gz: b31fe7ee33fe2cb7e4564ee98cc667d7a2420a81
5
+ SHA512:
6
+ metadata.gz: c456af3fd3d450c7535a832cf6748be03c365952c4abe7969d611d8da4a08aa3282ea44eacdc3d8d28ad140f0f9d71f1b434aa7bf3d488c349b18a5b3fa067ae
7
+ data.tar.gz: 6b160737e421771a0a3ad0799c203b01f956d1d6eea73f848309d5eabbf6709f4e5ae3c7df507e96145b8a1ca1460c16e05625d3e608541c54abee6dc10ef729
data/.gitignore ADDED
@@ -0,0 +1,14 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/*
7
+ !/doc/assets/
8
+ /pkg/
9
+ /spec/reports/
10
+ /tmp/
11
+ /*.gem
12
+
13
+ # rspec failure tracking
14
+ .rspec_status
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.4.2
5
+ before_install: gem install bundler -v 1.15.1
@@ -0,0 +1,74 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ In the interest of fostering an open and welcoming environment, we as
6
+ contributors and maintainers pledge to making participation in our project and
7
+ our community a harassment-free experience for everyone, regardless of age, body
8
+ size, disability, ethnicity, gender identity and expression, level of experience,
9
+ nationality, personal appearance, race, religion, or sexual identity and
10
+ orientation.
11
+
12
+ ## Our Standards
13
+
14
+ Examples of behavior that contributes to creating a positive environment
15
+ include:
16
+
17
+ * Using welcoming and inclusive language
18
+ * Being respectful of differing viewpoints and experiences
19
+ * Gracefully accepting constructive criticism
20
+ * Focusing on what is best for the community
21
+ * Showing empathy towards other community members
22
+
23
+ Examples of unacceptable behavior by participants include:
24
+
25
+ * The use of sexualized language or imagery and unwelcome sexual attention or
26
+ advances
27
+ * Trolling, insulting/derogatory comments, and personal or political attacks
28
+ * Public or private harassment
29
+ * Publishing others' private information, such as a physical or electronic
30
+ address, without explicit permission
31
+ * Other conduct which could reasonably be considered inappropriate in a
32
+ professional setting
33
+
34
+ ## Our Responsibilities
35
+
36
+ Project maintainers are responsible for clarifying the standards of acceptable
37
+ behavior and are expected to take appropriate and fair corrective action in
38
+ response to any instances of unacceptable behavior.
39
+
40
+ Project maintainers have the right and responsibility to remove, edit, or
41
+ reject comments, commits, code, wiki edits, issues, and other contributions
42
+ that are not aligned to this Code of Conduct, or to ban temporarily or
43
+ permanently any contributor for other behaviors that they deem inappropriate,
44
+ threatening, offensive, or harmful.
45
+
46
+ ## Scope
47
+
48
+ This Code of Conduct applies both within project spaces and in public spaces
49
+ when an individual is representing the project or its community. Examples of
50
+ representing a project or community include using an official project e-mail
51
+ address, posting via an official social media account, or acting as an appointed
52
+ representative at an online or offline event. Representation of a project may be
53
+ further defined and clarified by project maintainers.
54
+
55
+ ## Enforcement
56
+
57
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
58
+ reported by contacting the project team at hermann.mayer92@gmail.com. All
59
+ complaints will be reviewed and investigated and will result in a response that
60
+ is deemed necessary and appropriate to the circumstances. The project team is
61
+ obligated to maintain confidentiality with regard to the reporter of an incident.
62
+ Further details of specific enforcement policies may be posted separately.
63
+
64
+ Project maintainers who do not follow or enforce the Code of Conduct in good
65
+ faith may face temporary or permanent repercussions as determined by other
66
+ members of the project's leadership.
67
+
68
+ ## Attribution
69
+
70
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71
+ available at [http://contributor-covenant.org/version/1/4][version]
72
+
73
+ [homepage]: http://contributor-covenant.org
74
+ [version]: http://contributor-covenant.org/version/1/4/
data/Dockerfile ADDED
@@ -0,0 +1,17 @@
1
+ FROM alpine:3.6
2
+ MAINTAINER Hermann Mayer <hermann.mayer92@gmail.com>
3
+
4
+ COPY . /app
5
+ WORKDIR /app
6
+
7
+ RUN apk add --update \
8
+ ruby ruby-dev ruby-bundler ruby-json \
9
+ libstdc++ tzdata bash ca-certificates \
10
+ build-base git \
11
+ && \
12
+ bundle install --clean --deployment --without development \
13
+ && \
14
+ apk del libstdc++ tzdata bash build-base
15
+
16
+ ENTRYPOINT /usr/bin/bundle exec exe/plankton
17
+ CMD help
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "https://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in plankton.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2017 Hermann Mayer
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/Makefile ADDED
@@ -0,0 +1,65 @@
1
+ MAKEFLAGS += --warn-undefined-variables -j1
2
+ SHELL := bash
3
+ .SHELLFLAGS := -eu -o pipefail -c
4
+ .DEFAULT_GOAL := all
5
+ .DELETE_ON_ERROR:
6
+ .SUFFIXES:
7
+ .PHONY: shell install test
8
+
9
+ GEM ?= gem
10
+ GIT ?= git
11
+ RAKE ?= rake
12
+
13
+ BIN_DIR ?= bin
14
+
15
+ DOCKER_IMAGE ?= jack12816/plankton
16
+ DOCKER_VERSION ?= $(shell $(GIT) describe)
17
+
18
+ all:
19
+ # Plankton
20
+ #
21
+ # install Install the dependencies
22
+ # shell Start an interactive shell session
23
+ # test Run the whole test suite
24
+ #
25
+ # release Alias to release-minor
26
+ # release-major Release a major version
27
+ # release-minor Release a minor version
28
+ # release-patch Release a patch version
29
+ #
30
+ # build Build the Docker image
31
+ # publish Push the Docker image
32
+
33
+ install:
34
+ # Install the dependencies
35
+ @$(BIN_DIR)/setup
36
+
37
+ shell:
38
+ # Start an interactive shell session
39
+ @$(BIN_DIR)/console
40
+
41
+ test: install
42
+ # Run the whole test suite
43
+ @$(RAKE) spec
44
+
45
+ build:
46
+ # Build the Docker image
47
+ @$(DOCKER) build -t $(DOCKER_IMAGE):$(DOCKER_VERSION) .
48
+
49
+ publish:
50
+ # Push the Docker image
51
+ @$(DOCKER) push $(DOCKER_IMAGE):$(DOCKER_VERSION)
52
+
53
+ release: release-minor
54
+
55
+ release-major:
56
+ # Release a major version
57
+ @$(GEM) bump --commit --tag --release --version major
58
+
59
+ release-minor:
60
+ # Release a minor version
61
+ @$(GEM) bump --commit --tag --release --version minor
62
+
63
+ release-patch:
64
+ # Release a patch version
65
+ @$(GEM) bump --commit --tag --release --version patch
data/README.md ADDED
@@ -0,0 +1,231 @@
1
+ ![Plankton](doc/assets/project.png)
2
+
3
+ Plankton is a commandline interface for private Docker Registries (v2). It
4
+ supports the anonymous usage as well as the HTTP Basic and Token
5
+ Authentication. With the help of Plankton you can interact with tags (list, get
6
+ details, remove, cleanup with keep n latest). It is great for automating CI/CD
7
+ deployments and save memory at the end.
8
+
9
+ - [Installation](#installation)
10
+ - [Local](#local)
11
+ - [Docker](#docker)
12
+ - [Usage](#usage)
13
+ - [Environment](#environment)
14
+ - [Listing tags](#listing-tags)
15
+ - [Tag details](#tag-details)
16
+ - [Delete a tag](#delete-a-tag)
17
+ - [Cleanup tags](#cleanup-tags)
18
+ - [Development](#development)
19
+ - [Contributing](#contributing)
20
+ - [License](#license)
21
+ - [Code of Conduct](#code-of-conduct)
22
+
23
+ ## Installation
24
+
25
+ ### Local
26
+
27
+ Install it yourself as:
28
+
29
+ ```bash
30
+ $ gem install plankton
31
+ ```
32
+
33
+ ### Docker
34
+
35
+ There is a Docker image available as
36
+ [jack12816/plankton](https://hub.docker.com/r/jack12816/plankton/). Just pull
37
+ it and use it like that:
38
+
39
+ ```bash
40
+ # Pull the latest Plankton version
41
+ $ docker pull jack12816/plankton
42
+ # Ask Plankton for help
43
+ $ docker run --rm jack12816/plankton help
44
+ # Use Plankton even with environment variables
45
+ $ docker run --rm \
46
+ -e REGISTRY_CLI_HOSTNAME=your.registry.tld \
47
+ jack12816/plankton tags
48
+ ```
49
+
50
+ ## Usage
51
+
52
+ ### Environment
53
+
54
+ You can pass `--hostname`, `--username` and `--password` commandline options
55
+ to Plankton or use the following environment variables:
56
+
57
+ ```bash
58
+ export REGISTRY_CLI_HOSTNAME=
59
+ export REGISTRY_CLI_USERNAME=
60
+ export REGISTRY_CLI_PASSWORD=
61
+ ```
62
+
63
+ The commandline options take precedence over the environment variables.
64
+
65
+ ### Listing tags
66
+
67
+ You can list all tags of a given repository at your Docker Registry. By default
68
+ it will print some handy details (created at date (ISO 8601), layer size). If
69
+ you do not care about these additional information or you want to speed up the
70
+ command, just disable them by passing the `--no-details` option.
71
+
72
+ ```bash
73
+ Usage:
74
+ plankton tags REPO
75
+
76
+ Options:
77
+ -l, [--limit=N] # How many tags to fetch (maximum)
78
+ # Default: 20
79
+ -d, [--details], [--no-details] # Display details (created at date, full layer size)
80
+ # Default: true
81
+ ```
82
+
83
+ A common output looks like this:
84
+
85
+ ```bash
86
+ $ plankton tags apps/fancy
87
+
88
+ Image tag Created at Size
89
+ 1.3.0 2017-09-24T16:36:00+00:00 273.27 MiB
90
+ 1.2.1 2017-09-24T16:32:56+00:00 273.27 MiB
91
+ 1.2.0 2017-09-24T16:31:53+00:00 273.27 MiB
92
+ 1.1.0 2017-09-24T16:31:12+00:00 273.27 MiB
93
+ ```
94
+
95
+ The tags are ordered to show the latest created first.
96
+
97
+ ### Tag details
98
+
99
+ With the help of Plankton it is easy to retreive some details about a tag. Just
100
+ specify the repository and the tag name and you will get something like this:
101
+
102
+ ```bash
103
+ Usage:
104
+ plankton tag REPO TAG
105
+ ```
106
+
107
+ ```bash
108
+ $ plankton tag apps/fancy 1.0.0
109
+
110
+ Tag: 1.0.0
111
+ Digest: sha256:4fdcb19e157a55eaf1254ef9923216127cb95560b9c0a6e94ae48ac2cefb6674
112
+ Created at: 2017-09-24T16:36:00+00:00
113
+ Layers: 8
114
+ sha256:d93a2d7cc901177e87182b2003d50fb3ffd5be3eb698f39f5c862264efe6ee99 (50.16 MiB)
115
+ sha256:15a33158a1367c7c4103c89ae66e8f4fdec4ada6a39d4648cf254b32296d6668 (18.37 MiB)
116
+ sha256:f67323742a64d3540e24632f6d77dfb02e72301c00d1e9a3c28e0ef15478fff9 (41.23 MiB)
117
+ sha256:c4b45e832c38de44fbab83d5fcf9cbf66d069a51e6462d89ccc050051f25926d (128.45 MiB)
118
+ sha256:c1d1736737e7ea666709bec11741051fbba7c8f896d17570c82c978413cb3312 (205.00 B)
119
+ sha256:f3fd5681b6bafafd7d45041c29f1df202777ca906f7f01db58556feb177e6dfc (34.42 MiB)
120
+ sha256:ac9eb90ae6f5320100f26741b82ae30d40c407b1f6d0a4974da70bd67da9ab74 (661.22 KiB)
121
+ sha256:aa1e7b8285a7a366476ba71fdfb27b13712415310a063a0c41283326f5aecdbf (164.00 B)
122
+ Total layer size: 273.27 MiB
123
+ Image:
124
+ Author: Hermann Mayer <hermann.mayer92@gmail.com>
125
+ Operating system: linux
126
+ Architecture: amd64
127
+ Docker version: 17.07.0-ce
128
+ Dockerfile:
129
+ Steps: 22
130
+ ```
131
+
132
+ ### Delete a tag
133
+
134
+ The `rmtag` operation takes care of deleting a specific tag. This requires a
135
+ Docker Registry with the [enabled delete storage
136
+ option](https://docs.docker.com/registry/configuration/#delete). By default
137
+ Plankton will ask you for interactive feedback to confirm the operation. You
138
+ can make use of the `--no-confirm` option to overcome this on automated usage.
139
+
140
+ ```bash
141
+ Usage:
142
+ plankton rmtag REPO TAG
143
+
144
+ Options:
145
+ [--confirm], [--no-confirm] # User interaction is required
146
+ # Default: true
147
+ ```
148
+
149
+ ```bash
150
+ $ plankton rmtag apps/fancy 1.1.0
151
+
152
+ Delete apps/fancy:1.1.0? [yes, no] yes
153
+ Tag 1.1.0 was successfully deleted.
154
+ ```
155
+
156
+ ### Cleanup tags
157
+
158
+ The `cleanup` operation will delete all "old" tags from a repository. You can
159
+ configure it to delete all the tags, or keep the last n tags. This requires a
160
+ Docker Registry with the [enabled delete storage
161
+ option](https://docs.docker.com/registry/configuration/#delete). By default
162
+ Plankton will ask you for interactive feedback to confirm the operation. You
163
+ can make use of the `--no-confirm` option to overcome this on automated usage.
164
+ You can specify how many tags should stay by passing the `--keep` options. It
165
+ defaults to 3.
166
+
167
+ ```bash
168
+ Usage:
169
+ plankton cleanup REPO
170
+
171
+ Options:
172
+ -k, [--keep=N] # How many tags to keep
173
+ # Default: 3
174
+ [--confirm], [--no-confirm] # User interaction is required
175
+ # Default: true
176
+ ```
177
+
178
+ A common output looks like this:
179
+
180
+ ```bash
181
+ $ plankton cleanup apps/fancy
182
+
183
+ Tags to keep: 3 (819.81 MiB)
184
+ Image tag Created at Size
185
+ 1.3.0 2017-09-24T16:36:00+00:00 273.27 MiB
186
+ 1.2.1 2017-09-24T16:32:56+00:00 273.27 MiB
187
+ 1.2.0 2017-09-24T16:31:53+00:00 273.27 MiB
188
+ 1.1.0 2017-09-24T16:31:12+00:00 273.27 MiB
189
+
190
+ Tags to delete: 1 (273.27 MiB)
191
+ Image tag Created at Size
192
+ 1.1.0 2017-09-24T16:31:12+00:00 273.27 MiB
193
+
194
+ Registry: https://your.registry.tld
195
+ Repository: apps/fancy
196
+ Tags to keep: 3
197
+
198
+ Cleanup apps/fancy (1 tags)? [yes, no] yes
199
+
200
+ Deleted 1.1.0 (freed 273.27 MiB)
201
+ ```
202
+
203
+ ## Development
204
+
205
+ After checking out the repo, run `make install` to install dependencies. Then,
206
+ run `make test` to run the tests. You can also run `make shell` for an
207
+ interactive prompt that will allow you to experiment.
208
+
209
+ To install this gem onto your local machine, run `bundle exec rake install`. To
210
+ release a new version, update the version number in `version.rb`, and then run
211
+ `bundle exec rake release`, which will create a git tag for the version, push
212
+ git commits and tags, and push the `.gem` file to
213
+ [rubygems.org](https://rubygems.org).
214
+
215
+ ## Contributing
216
+
217
+ Bug reports and pull requests are welcome on GitHub at
218
+ https://github.com/Jack12816/plankton. This project is intended to be a safe,
219
+ welcoming space for collaboration, and contributors are expected to adhere to
220
+ the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
221
+
222
+ ## License
223
+
224
+ The gem is available as open source under the terms of the [MIT
225
+ License](http://opensource.org/licenses/MIT).
226
+
227
+ ## Code of Conduct
228
+
229
+ Everyone interacting in the Plankton project’s codebases, issue trackers, chat
230
+ rooms and mailing lists is expected to follow the [code of
231
+ conduct](https://github.com/Jack12816/plankton/blob/master/CODE_OF_CONDUCT.md).
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "plankton"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+ gem install gem-release
Binary file
@@ -0,0 +1,82 @@
1
+ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
2
+ <!-- Created with Inkscape (http://www.inkscape.org/) -->
3
+
4
+ <svg
5
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
6
+ xmlns:cc="http://creativecommons.org/ns#"
7
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
8
+ xmlns:svg="http://www.w3.org/2000/svg"
9
+ xmlns="http://www.w3.org/2000/svg"
10
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
11
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
12
+ width="120"
13
+ height="120"
14
+ id="svg13095"
15
+ version="1.1"
16
+ inkscape:version="0.92.2 5c3e80d, 2017-08-06"
17
+ sodipodi:docname="logo.svg"
18
+ inkscape:export-filename="/home/jack/Desktop/X/Projects/Coding/Ruby/plankton/doc/assets/logo.png"
19
+ inkscape:export-xdpi="400"
20
+ inkscape:export-ydpi="400">
21
+ <defs
22
+ id="defs13097" />
23
+ <sodipodi:namedview
24
+ id="base"
25
+ pagecolor="#ffffff"
26
+ bordercolor="#666666"
27
+ borderopacity="1.0"
28
+ inkscape:pageopacity="0.0"
29
+ inkscape:pageshadow="2"
30
+ inkscape:zoom="2.8"
31
+ inkscape:cx="34.720256"
32
+ inkscape:cy="39.813015"
33
+ inkscape:document-units="px"
34
+ inkscape:current-layer="layer1"
35
+ showgrid="false"
36
+ inkscape:window-width="1916"
37
+ inkscape:window-height="1031"
38
+ inkscape:window-x="0"
39
+ inkscape:window-y="47"
40
+ inkscape:window-maximized="0"
41
+ fit-margin-top="0"
42
+ fit-margin-left="0"
43
+ fit-margin-right="0"
44
+ fit-margin-bottom="0" />
45
+ <metadata
46
+ id="metadata13100">
47
+ <rdf:RDF>
48
+ <cc:Work
49
+ rdf:about="">
50
+ <dc:format>image/svg+xml</dc:format>
51
+ <dc:type
52
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
53
+ <dc:title></dc:title>
54
+ </cc:Work>
55
+ </rdf:RDF>
56
+ </metadata>
57
+ <g
58
+ inkscape:label="Layer 1"
59
+ inkscape:groupmode="layer"
60
+ id="layer1"
61
+ transform="translate(-86.730051,-1032.3142)">
62
+ <flowRoot
63
+ xml:space="preserve"
64
+ id="flowRoot5209"
65
+ style="font-style:normal;font-weight:normal;line-height:0.01%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none"
66
+ transform="translate(-435.44948,-151.19697)"><flowRegion
67
+ id="flowRegion5211"
68
+ style="font-family:sans-serif"><rect
69
+ id="rect5213"
70
+ width="123.23861"
71
+ height="86.873116"
72
+ x="-62.629459"
73
+ y="42.209637"
74
+ style="font-family:sans-serif" /></flowRegion><flowPara
75
+ id="flowPara5215"
76
+ style="font-size:40px;line-height:1.25;font-family:sans-serif">rhetorical raptorrhetorical raptorR</flowPara></flowRoot> <path
77
+ style="fill:#000000;fill-opacity:1;stroke:none"
78
+ d="m 153.71417,1057.3205 c -0.7761,0.3663 -1.57061,0.7787 -2.36592,1.237 -3.98604,2.2973 -5.34454,6.1145 -5.74892,7.6671 -0.79221,-0.1281 -1.52039,-0.052 -2.16252,0.2533 -0.67282,0.3197 -1.21045,0.8696 -1.61857,1.6157 -1.55813,-0.685 -5.27487,-1.903 -9.43482,-0.316 -0.85768,0.3272 -1.67894,0.6832 -2.45322,1.0533 -4.18145,1.9985 -7.01086,4.3675 -7.01086,4.3675 0,0 -22.75625,15.5152 -30.378548,20.4395 -1.22635,0.7923 -1.48529,1.1298 -2.34824,1.4447 -0.89777,0.3276 -2.83529,0.4199 -2.83529,0.4199 0,0 1.97977,0.5328 2.976609,0.427 0.48039,-0.051 0.61236,0 1.17481,-0.2567 0,0 1.45778,4.8625 2.59345,7.1246 1.707261,3.4005 6.278049,9.534 6.278049,9.534 0,0 -3.642969,-6.4322 -4.979919,-9.8628 -0.95216,-2.4432 -2.24464,-7.5559 -2.24464,-7.5559 0,0 25.000349,-17.3014 34.341479,-22.7596 7.47634,-4.3687 11.99968,-2.3938 13.50818,-1.4307 -0.14921,0.9976 -0.18827,2.1358 -0.12587,3.3828 -1.44837,0.3241 -5.83161,1.4805 -7.55398,3.9637 -2.07648,2.9938 -2.13382,3.6392 -2.13382,3.6392 0,0 0.16906,-0.4103 2.24554,-3.4041 1.68186,-2.4248 5.9088,-3.5886 7.45535,-3.9439 0.008,0.1284 0.0168,0.2574 0.0268,0.388 -0.90929,0.338 -3.04447,1.1639 -3.91676,1.8299 -1.18727,0.9066 -2.86488,3.4463 -2.86488,3.4463 0,0 1.79313,-2.3571 2.9766,-3.2112 0.84613,-0.6106 2.85396,-1.417 3.82685,-1.7917 0.0122,0.1412 0.0259,0.283 0.0406,0.4265 -0.94753,0.3835 -3.84406,1.6525 -5.4332,3.4331 -1.91398,2.1447 -2.76104,7.0757 -2.76104,7.0757 0,0 0.95878,-4.6959 2.87276,-6.8406 1.54635,-1.7327 4.32732,-2.9785 5.35063,-3.3984 0.0117,0.1057 0.0207,0.2104 0.0337,0.3172 -0.85914,0.4706 -2.76791,1.5634 -3.47041,2.3428 -1.30711,1.4501 -2.80604,5.1428 -2.80604,5.1428 0,0 1.61804,-3.5182 2.91775,-4.9078 0.69055,-0.7382 2.50217,-1.794 3.39852,-2.295 0.0351,0.2668 0.0718,0.5359 0.11478,0.81 -0.75372,0.2804 -2.40708,0.9396 -2.95382,1.5253 -1.62453,1.7405 -2.27948,4.8999 -2.76031,6.5846 0.48082,-1.6847 1.26289,-4.6729 2.87203,-6.3495 0.53481,-0.5572 2.10044,-1.1986 2.88597,-1.4976 0.0489,0.2977 0.10212,0.6001 0.16016,0.9055 -0.6439,0.2184 -1.81464,0.6539 -2.18395,1.0514 -0.94694,1.0194 -1.4282,3.9207 -1.4282,3.9207 0,0 0.61102,-2.7311 1.53992,-3.6856 0.36588,-0.376 1.46714,-0.7975 2.11976,-1.0254 0.009,0.042 0.02,0.084 0.0283,0.1261 -0.54762,0.1732 -1.31681,0.448 -1.57294,0.698 -0.69065,0.6739 -1.09415,2.6813 -1.09415,2.6813 0,0 0.53348,-1.8349 1.20587,-2.4463 0.25474,-0.2316 0.97449,-0.4934 1.51415,-0.67 0.79565,3.8373 2.27711,8.2211 4.40129,12.6908 4.70826,9.9069 11.07853,17.1003 15.53469,18.0306 0.30856,0.5234 4.11122,7.0164 4.76855,10.0622 0.68493,3.1736 2.08681,7.1084 2.44584,10.7743 0.17447,1.7815 -0.14921,5.3707 -0.14921,5.3707 0,0 0.75044,-2.5497 0.88312,-3.8644 0.13013,-1.2895 0.0319,-3.0437 -0.0914,-3.8873 -0.36575,-2.5022 1.32899,6.0751 2.54118,8.9188 0.9729,2.2826 2.89603,5.3593 3.75338,6.4293 0,0 -1.93819,-4.3722 -2.68683,-6.6389 -1.95023,-5.9049 -4.65012,-18.0748 -4.65012,-18.0748 0,0 7.7349,9.777 11.08176,15.0181 1.28478,2.012 3.45084,6.2759 3.45084,6.2759 -0.28816,-1.3405 -1.45937,-4.7747 -2.61472,-6.9704 -1.4395,-2.7358 -7.01978,-9.4664 -5.31071,-7.6027 0.57624,0.6283 1.87439,1.8124 2.95648,2.5258 1.1031,0.7274 3.554,1.7557 3.554,1.7557 0,0 -2.98742,-2.0157 -4.25852,-3.276 -2.61573,-2.5934 -4.78127,-6.1652 -6.80953,-8.7005 -1.94971,-2.4371 -4.58523,-9.5078 -4.78947,-10.0568 2.08759,-4.0474 0.53316,-13.5257 -4.17202,-23.4262 -2.12432,-4.4699 -4.58741,-8.3872 -7.0606,-11.4269 0.49132,-0.3144 1.18552,-0.7251 1.53085,-0.7771 0.89868,-0.1353 2.65457,0.6116 2.65457,0.6116 0,0 -1.80753,-0.9566 -2.76629,-0.8467 -0.36086,0.041 -1.0952,0.4863 -1.58788,0.8087 -0.0272,-0.034 -0.0559,-0.067 -0.0835,-0.1 0.59719,-0.3665 1.65803,-0.979 2.18705,-1.0259 1.32674,-0.1174 3.83387,1.1318 3.83387,1.1318 0,0 -2.5572,-1.4573 -3.94559,-1.3668 -0.54613,0.036 -1.65984,0.6922 -2.24447,1.0566 -0.20144,-0.2393 -0.40157,-0.4724 -0.60267,-0.6997 0.73496,-0.4237 2.26084,-1.2532 3.03511,-1.3163 2.3162,-0.1889 5.13067,1.09 6.74054,1.7811 -1.60988,-0.6911 -4.47682,-2.1767 -6.85226,-2.0162 -0.80857,0.055 -2.40745,0.9451 -3.09951,1.3515 -0.18456,-0.2055 -0.37157,-0.4057 -0.55555,-0.6005 0.96114,-0.3826 2.96377,-1.1407 3.97713,-1.2102 1.89821,-0.1303 5.64795,0.8369 5.64795,0.8369 0,0 -3.80981,-1.1697 -5.75969,-1.072 -1.05773,0.053 -3.15461,0.8664 -4.05948,1.2358 -0.0745,-0.077 -0.15041,-0.1507 -0.22468,-0.2264 0.97075,-0.5279 3.73512,-1.9218 6.06542,-2.0271 2.87154,-0.1297 7.11815,2.0925 7.11815,2.0925 0,0 -4.35833,-2.4572 -7.22988,-2.3276 -2.39397,0.1081 -5.25136,1.578 -6.14448,2.0692 -0.10213,-0.102 -0.20331,-0.2023 -0.30504,-0.3008 0.9105,-0.5201 2.84382,-1.5882 3.85731,-1.8602 1.4096,-0.3783 4.36963,-0.2801 4.36963,-0.2801 0,0 -3.02868,-0.3031 -4.48136,0.045 -1.07668,0.258 -3.11069,1.4166 -3.94373,1.9058 -0.0946,-0.09 -0.18797,-0.1755 -0.28216,-0.2621 1.25176,-0.9729 4.86793,-3.5479 7.81942,-3.32 3.6326,0.2806 4.05384,0.4104 4.05384,0.4104 0,0 -0.53296,-0.3649 -4.16556,-0.6455 -3.02386,-0.2335 -6.73697,2.4666 -7.89886,3.3803 -0.96007,-0.865 -1.89871,-1.5698 -2.79419,-2.0897 0.15998,-1.6733 1.3515,-6.5786 9.6513,-9.6884 10.13111,-3.7959 39.33207,-12.249 39.33207,-12.249 0,0 3.14802,4.2308 4.44117,6.5121 1.81569,3.203 4.50434,10.0842 4.50434,10.0842 0,0 -1.86919,-7.4174 -3.42772,-10.8886 -1.03672,-2.3091 -3.88637,-6.5101 -3.88637,-6.5101 0.55079,-0.2767 0.59801,-0.4085 0.94091,-0.7488 0.71155,-0.7061 1.55041,-2.574 1.55041,-2.574 0,0 -1.30054,1.4422 -2.1215,1.9313 -0.78917,0.4703 -1.21068,0.4562 -2.59943,0.9067 -8.6317,2.8004 -35.03068,10.6506 -35.03068,10.6506 0,0 -3.62539,0.6943 -7.81561,2.6742 z"
79
+ id="path8989"
80
+ inkscape:connector-curvature="0" />
81
+ </g>
82
+ </svg>
Binary file
Binary file
data/exe/plankton ADDED
@@ -0,0 +1,82 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'thor'
4
+ require 'tty-table'
5
+ require 'filesize'
6
+ require 'recursive-open-struct'
7
+ require 'plankton'
8
+
9
+ class App < Thor
10
+ class_option :hostname,
11
+ desc: 'The Docker Registry to work with',
12
+ required: false,
13
+ aliases: '-h',
14
+ type: :string
15
+ class_option :username,
16
+ desc: 'The username for authentication',
17
+ aliases: '-u',
18
+ type: :string
19
+ class_option :password,
20
+ desc: 'The password for authentication',
21
+ aliases: '-p',
22
+ type: :string
23
+ class_option :confirm,
24
+ desc: 'User interaction is required',
25
+ type: :boolean,
26
+ default: true
27
+ class_option :verbose,
28
+ desc: 'Be verbose while processing',
29
+ aliases: '-v',
30
+ type: :boolean,
31
+ default: false
32
+
33
+ no_commands do
34
+ include Plankton::EnvVars
35
+ include Plankton::Helpers
36
+ alias_method :orig_help, :help
37
+ end
38
+
39
+ def help(command = nil, subcommand = false)
40
+ orig_help(command, subcommand)
41
+ puts
42
+ puts <<~ENV
43
+ Environment:
44
+ REGISTRY_CLI_HOSTNAME # Specify the Docker Registry hostame
45
+ # --username takes precedence over the env var
46
+ REGISTRY_CLI_USERNAME # The username for authentication
47
+ # --hostname takes precedence over the env var
48
+ REGISTRY_CLI_PASSWORD # The password for authentication
49
+ # --password takes precedence over the env var
50
+ ENV
51
+ puts
52
+ end
53
+
54
+ include Plankton::Command::Tags
55
+ include Plankton::Command::Tag
56
+ include Plankton::Command::Rmtag
57
+ include Plankton::Command::Cleanup
58
+ end
59
+
60
+ def error_with_help(err)
61
+ puts err
62
+ puts 'Command aborted.'
63
+ puts
64
+ App.new.help
65
+ exit 1
66
+ end
67
+
68
+ begin
69
+ ENV['THOR_DEBUG'] = '1'
70
+ App.start(ARGV)
71
+ rescue Interrupt => e
72
+ puts "\n\n"
73
+ puts 'Command aborted.'
74
+ exit 1
75
+ rescue Thor::UndefinedCommandError => e
76
+ rescue Thor::InvocationError => e
77
+ error_with_help(e)
78
+ rescue Plankton::EnvVarNotFoundError => e
79
+ error_with_help("#{e.message} was not found.")
80
+ rescue RestClient::Forbidden => e
81
+ error_with_help("Authentication failed. (#{e.message})")
82
+ end
@@ -0,0 +1,53 @@
1
+ module Plankton::Command::Cleanup
2
+ def self.included(base)
3
+ base.class_eval do
4
+ option :keep,
5
+ desc: 'How many tags to keep',
6
+ default: 3,
7
+ aliases: '-k',
8
+ type: :numeric
9
+ desc 'cleanup REPO', 'Cleanup a given repository'
10
+ def cleanup(repo)
11
+ tags = registry.tags(repo: repo, limit: 200, details: true)
12
+ tags = tags.sort_by { |t| t.created_at }.reverse
13
+
14
+ if tags.size.zero?
15
+ puts 'No tags found. Nothing to do.'
16
+ exit
17
+ end
18
+
19
+ tags_to_delete = tags.drop(opts.keep)
20
+ tags_to_keep = tags.first(opts.keep)
21
+
22
+ puts ["\n", "Tags to keep:", opts.keep,
23
+ "(#{total_size(tags_to_keep)})"].join(' ')
24
+ detailed_tags_table(tags_to_keep)
25
+ puts ["\n", "Tags to delete:", tags_to_delete.size,
26
+ "(#{total_size(tags_to_delete)})"].join(' ')
27
+ detailed_tags_table(tags_to_delete)
28
+
29
+ if tags_to_delete.size.zero?
30
+ puts 'No tags need to cleaned.'
31
+ exit
32
+ end
33
+
34
+ if confirm?
35
+ puts
36
+ puts " Registry: #{hostname}"
37
+ puts " Repository: #{repo}"
38
+ puts " Tags to keep: #{opts.keep}"
39
+ puts
40
+ answer = ask("Cleanup #{repo} (#{tags_to_delete.size} tags)?",
41
+ limited_to: ['yes', 'no'])
42
+ exit if answer == 'no'
43
+ end
44
+ puts
45
+
46
+ tags_to_delete.each do |tag|
47
+ registry.rmtag(repo: repo, tag: tag.tag)
48
+ puts "Deleted #{tag.tag} (freed #{pretty_size(tag.layer_size)})"
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,18 @@
1
+ module Plankton::Command::Rmtag
2
+ def self.included(base)
3
+ base.class_eval do
4
+ desc 'rmtag REPO TAG', 'Delete a given tag'
5
+ def rmtag(repo, tag)
6
+ if confirm?
7
+ answer = ask("Delete #{repo}:#{tag}?", limited_to: ['yes', 'no'])
8
+ exit if answer == 'no'
9
+ end
10
+ registry.rmtag(repo: repo, tag: tag)
11
+ puts "Tag #{tag} was successfully deleted."
12
+ rescue RestClient::NotFound => e
13
+ puts "Tag #{tag} was not found. (#{e.message})"
14
+ exit 1
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,28 @@
1
+ module Plankton::Command::Tag
2
+ def self.included(base)
3
+ base.class_eval do
4
+ desc 'tag REPO TAG', 'All the details of of a given tag'
5
+ def tag(repo, tag)
6
+ tag = registry.tag(repo: repo, tag: tag)
7
+ puts "Tag: #{tag.tag}"
8
+ puts "Digest: #{tag.digest}"
9
+ puts "Created at: #{tag.created_at}"
10
+ puts "Layers: #{tag.manifest.layers.size}"
11
+ tag.manifest.layers.each do |layer|
12
+ puts " #{layer.digest} (#{pretty_size(layer.size)})"
13
+ end
14
+ puts "Total layer size: #{pretty_size(tag.layer_size)}"
15
+ puts "Image:"
16
+ puts " Author: #{tag.config.author}"
17
+ puts " Operating system: #{tag.config.os}"
18
+ puts " Architecture: #{tag.config.architecture}"
19
+ puts " Docker version: #{tag.config.docker_version}"
20
+ puts "Dockerfile:"
21
+ puts " Steps: #{tag.config.history.size}"
22
+ rescue RestClient::NotFound => e
23
+ puts "Tag #{tag} was not found. (#{e.message})"
24
+ exit 1
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,31 @@
1
+ module Plankton::Command::Tags
2
+ def self.included(base)
3
+ base.class_eval do
4
+ option :limit,
5
+ desc: 'How many tags to fetch (maximum)',
6
+ default: 20,
7
+ aliases: '-l',
8
+ type: :numeric
9
+ option :details,
10
+ desc: 'Display details (created at date, full layer size)',
11
+ default: true,
12
+ aliases: '-d',
13
+ type: :boolean
14
+ desc 'tags REPO', 'List all tags of a given repository'
15
+ def tags(repo)
16
+ if opts.details
17
+ tags = registry.tags(repo: repo,
18
+ details: true,
19
+ limit: opts.limit)
20
+ detailed_tags_table(tags)
21
+ else
22
+ tags = registry.tags(repo: repo, limit: opts.limit)
23
+ tags.each do |tag|
24
+ puts tag
25
+ end
26
+ end
27
+ puts 'No tags found.' if tags.size.zero?
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,40 @@
1
+ module Plankton
2
+ module EnvVars
3
+ def hostname
4
+ host = (ENV.fetch('REGISTRY_CLI_HOSTNAME', nil) || opts.hostname)
5
+ if host.nil? || host == 'hostname'
6
+ raise EnvVarNotFoundError, 'Docker Registry hostname'
7
+ end
8
+ host = host.dup.prepend('https://') unless %r{^https?://} =~ host
9
+ host.gsub(%r{/*$}, '').strip
10
+ end
11
+
12
+ def username
13
+ user = (ENV.fetch('REGISTRY_CLI_USERNAME', nil) || opts.username)
14
+ return nil if user.nil?
15
+ user.gsub(%r{/*$}, '').strip
16
+ end
17
+
18
+ def username?
19
+ !username.nil?
20
+ end
21
+
22
+ def password
23
+ pass = (ENV.fetch('REGISTRY_CLI_PASSWORD', nil) || opts.password)
24
+ return nil if pass.nil?
25
+ pass.gsub(%r{/*$}, '').strip
26
+ end
27
+
28
+ def password?
29
+ !password.nil?
30
+ end
31
+
32
+ def verbose?
33
+ opts.verbose
34
+ end
35
+
36
+ def confirm?
37
+ opts.confirm
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,40 @@
1
+ module Plankton
2
+ module Helpers
3
+ def opts
4
+ @opts_struct ||= RecursiveOpenStruct.new(options)
5
+ end
6
+
7
+ def registry
8
+ unless username? || password?
9
+ return @registry ||= DockerRegistry2.connect(hostname,
10
+ verbose: verbose?)
11
+ end
12
+ @registry ||= DockerRegistry2.connect(hostname,
13
+ verbose: verbose?,
14
+ user: username,
15
+ password: password)
16
+ end
17
+
18
+ def pretty_size(bytes)
19
+ Filesize.from("#{bytes} B").pretty
20
+ end
21
+
22
+ def detailed_tags_table(tags)
23
+ return if tags.size.zero?
24
+ headers = ['Image tag', 'Created at', 'Size']
25
+ tags = tags.sort_by { |t| t.created_at }.reverse
26
+ rows = tags.map do |tag|
27
+ [
28
+ tag.tag,
29
+ tag.created_at.to_s,
30
+ pretty_size(tag.layer_size)
31
+ ]
32
+ end
33
+ puts TTY::Table.new(headers, rows).render(:basic)
34
+ end
35
+
36
+ def total_size(tags)
37
+ pretty_size(tags.reduce(0) { |sum, t| sum + t.layer_size })
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,133 @@
1
+ # Monkey patch the DockerRegistry2::Registry issues away.
2
+ #
3
+ # Things that are broken by default:
4
+ # * pull
5
+ #
6
+ # Things that are not ideal:
7
+ # * Tons of round trips while auth probing (again, and again, and again..)
8
+ # * Tons of round trips to always get a "fresh" JWT token
9
+ # * Performance
10
+ #
11
+ # See: https://docs.docker.com/registry/spec/api
12
+ # See: https://github.com/gitlabhq/gitlabhq/tree/v10.0.0/lib/container_registry
13
+ class DockerRegistry2::Registry
14
+ # All these methods are useful, but needs some improvements
15
+ # from outer space.
16
+ alias_method :orig_initialize, :initialize
17
+ alias_method :orig_rmtag, :rmtag
18
+ alias_method :orig_authenticate_bearer, :authenticate_bearer
19
+ alias_method :orig_do_basic_req, :do_basic_req
20
+ alias_method :orig_do_bearer_req, :do_bearer_req
21
+ alias_method :orig_doreq, :doreq
22
+
23
+ # @param [#to_s] base_uri Docker registry base URI
24
+ # @param [Hash] options Client options
25
+ # @option options [#to_s] :user User name for basic authentication
26
+ # @option options [#to_s] :password Password for basic authentication
27
+ def initialize(uri, options = {})
28
+ @verbose = options.key?(:verbose) ? options[:verbose] : false
29
+ orig_initialize(uri, options)
30
+ end
31
+
32
+ # Speed up processing, by memorizing the JWT token
33
+ # for the given header.
34
+ def authenticate_bearer(header)
35
+ @token ||= {}
36
+ @token[header] ||= orig_authenticate_bearer(header)
37
+ end
38
+
39
+ # Save the auth type as basic, when the very first (ping)
40
+ # request was successful.
41
+ def do_basic_req(type, url, stream = nil)
42
+ res = orig_do_basic_req(type, url, stream)
43
+ @auth ||= :basic
44
+ res
45
+ end
46
+
47
+ # Save the auth type as bearer, when the very first (ping)
48
+ # request was successful.
49
+ def do_bearer_req(type, url, header, stream = nil)
50
+ res = orig_do_bearer_req(type, url, header, stream)
51
+ @auth ||= :bearer
52
+ @header = header
53
+ res
54
+ end
55
+
56
+ # # Speed up the system by memorize the probed auth type.
57
+ def doreq(type, url, stream = nil)
58
+ puts "[#{type.upcase}] #{@base_uri}#{url}" if @verbose
59
+ return orig_do_basic_req(type, url, stream) if @auth == :basic
60
+ return orig_do_bearer_req(type, url, @header, stream) if @auth == :bearer
61
+ orig_doreq(type, url, stream)
62
+ rescue DockerRegistry2::RegistryAuthenticationException
63
+ orig_doreq(type, url, stream)
64
+ end
65
+
66
+ # Do it the same way as the original, but return a OpenStruct
67
+ # because its easy to work with.
68
+ def manifest(repo:, tag:)
69
+ res = doget("/v2/#{repo}/manifests/#{tag}")
70
+ digest = res.headers[:docker_content_digest]
71
+ res = RecursiveOpenStruct.new(JSON.parse(res), recurse_over_arrays: true)
72
+ res.digest = digest
73
+ res
74
+ end
75
+
76
+ # Download a blob to a opened IO handle.
77
+ def blob(repo, digest, file)
78
+ doreq('get', "/v2/#{repo}/blobs/#{digest}", file)
79
+ end
80
+
81
+ # Pull all layers of a given tag.
82
+ def pull(repo:, tag:, dir:)
83
+ # make sure the directory exists
84
+ FileUtils::mkdir_p(dir)
85
+ # pull each of the layers
86
+ manifest(repo: repo, tag: tag).layers.each do |layer|
87
+ # make sure the layer does not exist first
88
+ unless File.file? "#{dir}/#{layer.digest}"
89
+ blob(repo, layer.digest, File.new("#{dir}/#{layer.digest}", 'w+'))
90
+ end
91
+ end
92
+ end
93
+
94
+ # Fetch details about a tag.
95
+ def tag(repo:, tag:)
96
+ # Create new string IO handle
97
+ config_input = StringIO.new
98
+ # Download the manifest for the tag
99
+ manifest = manifest(repo: repo, tag: tag)
100
+ # Download the config blob for the tag
101
+ blob(repo, manifest.config.digest, config_input)
102
+ # Parse the JSON input
103
+ config = RecursiveOpenStruct.new(JSON.parse(config_input.string))
104
+ created = DateTime.parse(config.created)
105
+ layer_size = manifest.layers.reduce(0) { |sum, l| sum + l.size }
106
+ # Pass back all the detailed information
107
+ OpenStruct.new(tag: tag,
108
+ digest: manifest.digest,
109
+ created_at: created,
110
+ layer_size: layer_size,
111
+ config: config,
112
+ manifest: manifest)
113
+ end
114
+
115
+ # Fetch all tags of a repository, with the possibility to fetch
116
+ # all their details as well.
117
+ def tags(repo:, details: false, limit: 20)
118
+ unless details
119
+ res = JSON.parse(doget("/v2/#{repo}/tags/list?n=#{limit}"))
120
+ return RecursiveOpenStruct.new(res).tags || []
121
+ end
122
+ tags(repo: repo).map { |tag| tag(repo: repo, tag: tag) }
123
+ end
124
+
125
+ # Sometimes it is handy do delete a tag by its name, sometimes it is
126
+ # handy to delete a tag by its digest. The digest variant is faster due
127
+ # no lookup have to be done.
128
+ def rmtag(repo:, tag: nil, digest: nil)
129
+ raise 'No tag or digest was given' if tag.nil? && digest.nil?
130
+ return orig_rmtag(repo, tag) unless tag.nil?
131
+ dodelete("/v2/#{repo}/manifests/#{digest}").code
132
+ end
133
+ end
@@ -0,0 +1,3 @@
1
+ module Plankton
2
+ VERSION = "0.0.1"
3
+ end
data/lib/plankton.rb ADDED
@@ -0,0 +1,19 @@
1
+ require 'stringio'
2
+ require 'recursive-open-struct'
3
+ require 'docker_registry2'
4
+
5
+ module Plankton
6
+ class EnvVarNotFoundError < StandardError; end
7
+
8
+ module Command; end
9
+ end
10
+
11
+ require 'plankton/version'
12
+ require 'plankton/monkey_patches'
13
+ require 'plankton/env_vars'
14
+ require 'plankton/helpers'
15
+
16
+ require 'plankton/commands/tag'
17
+ require 'plankton/commands/tags'
18
+ require 'plankton/commands/rmtag'
19
+ require 'plankton/commands/cleanup'
data/plankton.gemspec ADDED
@@ -0,0 +1,43 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "plankton/version"
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'plankton'
8
+ spec.version = Plankton::VERSION
9
+ spec.authors = ['Hermann Mayer']
10
+ spec.email = ['hermann.mayer92@gmail.com']
11
+
12
+ spec.summary = %q{A commandline interface to private Docker Registries}
13
+ spec.description = %q{A commandline interface to private Docker Registries}
14
+ spec.homepage = 'https://github.com/Jack12816/plankton'
15
+ spec.license = 'MIT'
16
+
17
+ # Prevent pushing this gem to RubyGems.org. To allow pushes either set the
18
+ # 'allowed_push_host' to allow pushing to a single host or delete this
19
+ # section to allow pushing to any host.
20
+ if spec.respond_to?(:metadata)
21
+ spec.metadata['allowed_push_host'] = "https://rubygems.org"
22
+ else
23
+ raise 'RubyGems 2.0 or newer is required to protect against ' \
24
+ 'public gem pushes.'
25
+ end
26
+
27
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
28
+ f.match(%r{^(test|spec|features)/})
29
+ end
30
+ spec.bindir = 'exe'
31
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
32
+ spec.require_paths = ['lib']
33
+
34
+ spec.add_development_dependency 'bundler', '~> 1.15'
35
+ spec.add_development_dependency 'rake', '~> 10.0'
36
+ spec.add_development_dependency 'rspec', '~> 3.0'
37
+
38
+ spec.add_runtime_dependency 'recursive-open-struct', '~> 1.0'
39
+ spec.add_runtime_dependency 'docker_registry2', '~> 1.0'
40
+ spec.add_runtime_dependency 'thor', '~> 0.20'
41
+ spec.add_runtime_dependency 'tty-table', '~> 0.8'
42
+ spec.add_runtime_dependency 'filesize', '~> 0.1'
43
+ end
metadata ADDED
@@ -0,0 +1,185 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: plankton
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Hermann Mayer
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2017-09-24 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.15'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.15'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: recursive-open-struct
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '1.0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '1.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: docker_registry2
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '1.0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '1.0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: thor
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '0.20'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '0.20'
97
+ - !ruby/object:Gem::Dependency
98
+ name: tty-table
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '0.8'
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '0.8'
111
+ - !ruby/object:Gem::Dependency
112
+ name: filesize
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '0.1'
118
+ type: :runtime
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '0.1'
125
+ description: A commandline interface to private Docker Registries
126
+ email:
127
+ - hermann.mayer92@gmail.com
128
+ executables:
129
+ - plankton
130
+ extensions: []
131
+ extra_rdoc_files: []
132
+ files:
133
+ - ".gitignore"
134
+ - ".rspec"
135
+ - ".travis.yml"
136
+ - CODE_OF_CONDUCT.md
137
+ - Dockerfile
138
+ - Gemfile
139
+ - LICENSE.txt
140
+ - Makefile
141
+ - README.md
142
+ - Rakefile
143
+ - bin/console
144
+ - bin/setup
145
+ - doc/assets/logo.png
146
+ - doc/assets/logo.svg
147
+ - doc/assets/project.png
148
+ - doc/assets/project.xcf
149
+ - exe/plankton
150
+ - lib/plankton.rb
151
+ - lib/plankton/commands/cleanup.rb
152
+ - lib/plankton/commands/rmtag.rb
153
+ - lib/plankton/commands/tag.rb
154
+ - lib/plankton/commands/tags.rb
155
+ - lib/plankton/env_vars.rb
156
+ - lib/plankton/helpers.rb
157
+ - lib/plankton/monkey_patches.rb
158
+ - lib/plankton/version.rb
159
+ - plankton.gemspec
160
+ homepage: https://github.com/Jack12816/plankton
161
+ licenses:
162
+ - MIT
163
+ metadata:
164
+ allowed_push_host: https://rubygems.org
165
+ post_install_message:
166
+ rdoc_options: []
167
+ require_paths:
168
+ - lib
169
+ required_ruby_version: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - ">="
172
+ - !ruby/object:Gem::Version
173
+ version: '0'
174
+ required_rubygems_version: !ruby/object:Gem::Requirement
175
+ requirements:
176
+ - - ">="
177
+ - !ruby/object:Gem::Version
178
+ version: '0'
179
+ requirements: []
180
+ rubyforge_project:
181
+ rubygems_version: 2.6.13
182
+ signing_key:
183
+ specification_version: 4
184
+ summary: A commandline interface to private Docker Registries
185
+ test_files: []