docker-tags 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +39 -0
- data/.rubocop.yml +1 -0
- data/.rubocop_todo.yml +119 -0
- data/Gemfile +8 -0
- data/Gemfile.lock +42 -0
- data/LICENSE +21 -0
- data/README.md +100 -0
- data/Rakefile +11 -0
- data/bin/docker-tags +12 -0
- data/docker-tags.gemspec +24 -0
- data/lib/dockertags.rb +23 -0
- data/lib/dockertags/cli.rb +106 -0
- data/lib/dockertags/commands.rb +173 -0
- data/lib/dockertags/db.rb +48 -0
- data/lib/dockertags/log.rb +20 -0
- data/lib/dockertags/utils.rb +15 -0
- data/lib/dockertags/version.rb +6 -0
- metadata +118 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: 4baa52c3feb752ff98b2621f7f6eb9e10df82093
|
|
4
|
+
data.tar.gz: 08b3a7866cfe1dd611e3b056d805a951c47b5bba
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: e68d86489751589dfac9ebdb71650e42eb5b608dbe77ee083bb478df5b458db1eaf2e339e378d2eaa6e458e10637e0e387dd2652ab7ae18b175d99748bda8b81
|
|
7
|
+
data.tar.gz: ca4c9c9499a975df3b854de9cb217a5d4284afa1a8e85e087cf94b313c8e9dbe6a8ab63d566ebedb6ad4b017a3688bba4183f095d3aaae04efed9e89386c48e0
|
data/.gitignore
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
*.gem
|
|
2
|
+
*.rbc
|
|
3
|
+
/.config
|
|
4
|
+
/coverage/
|
|
5
|
+
/InstalledFiles
|
|
6
|
+
/pkg/
|
|
7
|
+
/spec/reports/
|
|
8
|
+
/spec/examples.txt
|
|
9
|
+
/test/tmp/
|
|
10
|
+
/test/version_tmp/
|
|
11
|
+
/tmp/
|
|
12
|
+
|
|
13
|
+
## Specific to RubyMotion:
|
|
14
|
+
.dat*
|
|
15
|
+
.repl_history
|
|
16
|
+
build/
|
|
17
|
+
|
|
18
|
+
## Documentation cache and generated files:
|
|
19
|
+
/.yardoc/
|
|
20
|
+
/_yardoc/
|
|
21
|
+
/doc/
|
|
22
|
+
/rdoc/
|
|
23
|
+
|
|
24
|
+
## Environment normalization:
|
|
25
|
+
/.bundle/
|
|
26
|
+
/vendor/bundle
|
|
27
|
+
/lib/bundler/man/
|
|
28
|
+
|
|
29
|
+
# for a library or gem, you might want to ignore these files since the code is
|
|
30
|
+
# intended to run in multiple environments; otherwise, check them in:
|
|
31
|
+
# Gemfile.lock
|
|
32
|
+
# .ruby-version
|
|
33
|
+
# .ruby-gemset
|
|
34
|
+
|
|
35
|
+
# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
|
|
36
|
+
.rvmrc
|
|
37
|
+
|
|
38
|
+
*~
|
|
39
|
+
*.db
|
data/.rubocop.yml
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
inherit_from: .rubocop_todo.yml
|
data/.rubocop_todo.yml
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# This configuration was generated by
|
|
2
|
+
# `rubocop --auto-gen-config`
|
|
3
|
+
# on 2016-01-29 16:38:45 +0100 using RuboCop version 0.36.0.
|
|
4
|
+
# The point is for the user to remove these configuration records
|
|
5
|
+
# one by one as the offenses are removed from the code base.
|
|
6
|
+
# Note that changes in the inspected code, or installation of new
|
|
7
|
+
# versions of RuboCop, may require this file to be generated again.
|
|
8
|
+
|
|
9
|
+
# Offense count: 1
|
|
10
|
+
# Cop supports --auto-correct.
|
|
11
|
+
# Configuration parameters: IgnoreEmptyBlocks.
|
|
12
|
+
Lint/UnusedBlockArgument:
|
|
13
|
+
Exclude:
|
|
14
|
+
- 'lib/dockertags/cli.rb'
|
|
15
|
+
|
|
16
|
+
# Offense count: 3
|
|
17
|
+
Metrics/AbcSize:
|
|
18
|
+
Max: 33
|
|
19
|
+
|
|
20
|
+
# Offense count: 12
|
|
21
|
+
# Configuration parameters: AllowHeredoc, AllowURI, URISchemes.
|
|
22
|
+
# URISchemes: http, https
|
|
23
|
+
Metrics/LineLength:
|
|
24
|
+
Max: 122
|
|
25
|
+
|
|
26
|
+
# Offense count: 3
|
|
27
|
+
# Configuration parameters: CountComments.
|
|
28
|
+
Metrics/MethodLength:
|
|
29
|
+
Max: 25
|
|
30
|
+
|
|
31
|
+
# Offense count: 1
|
|
32
|
+
# Configuration parameters: CountComments.
|
|
33
|
+
Metrics/ModuleLength:
|
|
34
|
+
Max: 112
|
|
35
|
+
|
|
36
|
+
# Offense count: 1
|
|
37
|
+
Style/AccessorMethodName:
|
|
38
|
+
Exclude:
|
|
39
|
+
- 'lib/dockertags/commands.rb'
|
|
40
|
+
|
|
41
|
+
# Offense count: 1
|
|
42
|
+
# Cop supports --auto-correct.
|
|
43
|
+
Style/AlignArray:
|
|
44
|
+
Exclude:
|
|
45
|
+
- 'docker-tags.gemspec'
|
|
46
|
+
|
|
47
|
+
# Offense count: 2
|
|
48
|
+
Style/ClassVars:
|
|
49
|
+
Exclude:
|
|
50
|
+
- 'lib/dockertags.rb'
|
|
51
|
+
|
|
52
|
+
# Offense count: 2
|
|
53
|
+
# Cop supports --auto-correct.
|
|
54
|
+
# Configuration parameters: SingleLineConditionsOnly.
|
|
55
|
+
Style/ConditionalAssignment:
|
|
56
|
+
Exclude:
|
|
57
|
+
- 'lib/dockertags/commands.rb'
|
|
58
|
+
|
|
59
|
+
# Offense count: 6
|
|
60
|
+
Style/Documentation:
|
|
61
|
+
Exclude:
|
|
62
|
+
- 'spec/**/*'
|
|
63
|
+
- 'test/**/*'
|
|
64
|
+
- 'lib/dockertags.rb'
|
|
65
|
+
- 'lib/dockertags/cli.rb'
|
|
66
|
+
- 'lib/dockertags/commands.rb'
|
|
67
|
+
- 'lib/dockertags/db.rb'
|
|
68
|
+
- 'lib/dockertags/log.rb'
|
|
69
|
+
- 'lib/dockertags/utils.rb'
|
|
70
|
+
|
|
71
|
+
# Offense count: 2
|
|
72
|
+
# Cop supports --auto-correct.
|
|
73
|
+
# Configuration parameters: MaxLineLength.
|
|
74
|
+
Style/IfUnlessModifier:
|
|
75
|
+
Exclude:
|
|
76
|
+
- 'lib/dockertags.rb'
|
|
77
|
+
- 'lib/dockertags/commands.rb'
|
|
78
|
+
|
|
79
|
+
# Offense count: 3
|
|
80
|
+
# Cop supports --auto-correct.
|
|
81
|
+
Style/MutableConstant:
|
|
82
|
+
Exclude:
|
|
83
|
+
- 'lib/dockertags/db.rb'
|
|
84
|
+
- 'lib/dockertags/version.rb'
|
|
85
|
+
|
|
86
|
+
# Offense count: 1
|
|
87
|
+
# Cop supports --auto-correct.
|
|
88
|
+
# Configuration parameters: EnforcedStyle, MinBodyLength, SupportedStyles.
|
|
89
|
+
# SupportedStyles: skip_modifier_ifs, always
|
|
90
|
+
Style/Next:
|
|
91
|
+
Exclude:
|
|
92
|
+
- 'lib/dockertags/commands.rb'
|
|
93
|
+
|
|
94
|
+
# Offense count: 2
|
|
95
|
+
# Cop supports --auto-correct.
|
|
96
|
+
Style/RedundantBegin:
|
|
97
|
+
Exclude:
|
|
98
|
+
- 'lib/dockertags/db.rb'
|
|
99
|
+
|
|
100
|
+
# Offense count: 1
|
|
101
|
+
# Cop supports --auto-correct.
|
|
102
|
+
# Configuration parameters: AllowAsExpressionSeparator.
|
|
103
|
+
Style/Semicolon:
|
|
104
|
+
Exclude:
|
|
105
|
+
- 'lib/dockertags/commands.rb'
|
|
106
|
+
|
|
107
|
+
# Offense count: 1
|
|
108
|
+
# Cop supports --auto-correct.
|
|
109
|
+
# Configuration parameters: EnforcedStyle, SupportedStyles.
|
|
110
|
+
# SupportedStyles: space, no_space
|
|
111
|
+
Style/SpaceBeforeBlockBraces:
|
|
112
|
+
Enabled: false
|
|
113
|
+
|
|
114
|
+
# Offense count: 3
|
|
115
|
+
# Cop supports --auto-correct.
|
|
116
|
+
# Configuration parameters: EnforcedStyle, SupportedStyles, ConsistentQuotesInMultiline.
|
|
117
|
+
# SupportedStyles: single_quotes, double_quotes
|
|
118
|
+
Style/StringLiterals:
|
|
119
|
+
Enabled: false
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
PATH
|
|
2
|
+
remote: .
|
|
3
|
+
specs:
|
|
4
|
+
dockertags (0.0.1)
|
|
5
|
+
commander (~> 4.3)
|
|
6
|
+
faraday
|
|
7
|
+
sqlite3
|
|
8
|
+
|
|
9
|
+
GEM
|
|
10
|
+
remote: https://rubygems.org/
|
|
11
|
+
specs:
|
|
12
|
+
ast (2.2.0)
|
|
13
|
+
commander (4.3.5)
|
|
14
|
+
highline (~> 1.7.2)
|
|
15
|
+
faraday (0.9.2)
|
|
16
|
+
multipart-post (>= 1.2, < 3)
|
|
17
|
+
highline (1.7.8)
|
|
18
|
+
multipart-post (2.0.0)
|
|
19
|
+
parser (2.3.0.2)
|
|
20
|
+
ast (~> 2.2)
|
|
21
|
+
powerpack (0.1.1)
|
|
22
|
+
rainbow (2.1.0)
|
|
23
|
+
rake (10.4.2)
|
|
24
|
+
rubocop (0.36.0)
|
|
25
|
+
parser (>= 2.3.0.0, < 3.0)
|
|
26
|
+
powerpack (~> 0.1)
|
|
27
|
+
rainbow (>= 1.99.1, < 3.0)
|
|
28
|
+
ruby-progressbar (~> 1.7)
|
|
29
|
+
ruby-progressbar (1.7.5)
|
|
30
|
+
sqlite3 (1.3.10)
|
|
31
|
+
|
|
32
|
+
PLATFORMS
|
|
33
|
+
ruby
|
|
34
|
+
|
|
35
|
+
DEPENDENCIES
|
|
36
|
+
bundler (~> 1.3)
|
|
37
|
+
dockertags!
|
|
38
|
+
rake
|
|
39
|
+
rubocop
|
|
40
|
+
|
|
41
|
+
BUNDLED WITH
|
|
42
|
+
1.10.6
|
data/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2016 Jasper Lievisse Adriaanse <j@jasper.la>
|
|
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 all
|
|
13
|
+
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 THE
|
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
# docker-tags
|
|
2
|
+
|
|
3
|
+
Track latest tags for Docker images.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
Run from a git clone:
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
git clone https://github.com/jasperla/docker-tags
|
|
11
|
+
bundle install --path vendor/bundle
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
or install the gem:
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
gem install docker-tags
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Usage
|
|
21
|
+
|
|
22
|
+
All the commands for `docker-tags` take a `--db /path/to/db`
|
|
23
|
+
argument to select the SQLite database. Bu default
|
|
24
|
+
`$PWD/docker-tags.db` is used.
|
|
25
|
+
|
|
26
|
+
### Initialize the database
|
|
27
|
+
|
|
28
|
+
This creates an empty database and creates the needed tables:
|
|
29
|
+
|
|
30
|
+
```
|
|
31
|
+
docker-tags initdb
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### Follow and unfollow an image
|
|
35
|
+
|
|
36
|
+
In order to start tracking the tags for an image, we have to start
|
|
37
|
+
following it:
|
|
38
|
+
|
|
39
|
+
```
|
|
40
|
+
docker-tags follow jasperla/docker-go-cross
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
In order to stop tracking, run the same command but with `unfollow`.
|
|
44
|
+
|
|
45
|
+
### Show latest tag
|
|
46
|
+
|
|
47
|
+
```
|
|
48
|
+
docker-tags latest jasperla/docker-go-cross
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
This will return a JSON hash for this particular image:
|
|
52
|
+
|
|
53
|
+
```
|
|
54
|
+
{
|
|
55
|
+
"jasperla/docker-go-cross": {
|
|
56
|
+
"image": "jasperla/docker-go-cross",
|
|
57
|
+
"layer": "c2c017e1",
|
|
58
|
+
"tag": "latest"
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
In this case there is only one tag, `latest` (which is otherwise
|
|
64
|
+
filtered). If we follow more images, we can run `latest` without any
|
|
65
|
+
arguments and the latest tags for all images will be displayed.
|
|
66
|
+
|
|
67
|
+
### Report
|
|
68
|
+
|
|
69
|
+
To generate a report based on the new tags that were pushed to the
|
|
70
|
+
Docker Hub since the last time `latest` or `report` were ran:
|
|
71
|
+
|
|
72
|
+
```
|
|
73
|
+
docker-tags report jasperla/docker-go-cross
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Just like `latest`, `report` will also work without any arguments.
|
|
77
|
+
|
|
78
|
+
### Dump all known tags
|
|
79
|
+
|
|
80
|
+
Essentially a SQL to JSON conversion of the database:
|
|
81
|
+
|
|
82
|
+
```
|
|
83
|
+
docker-tags dump
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## ToDo
|
|
87
|
+
|
|
88
|
+
- tests and docs (oh the irony)
|
|
89
|
+
|
|
90
|
+
## Copyright and license
|
|
91
|
+
|
|
92
|
+
MIT, please see the LICENSE file.
|
|
93
|
+
|
|
94
|
+
## Contributing
|
|
95
|
+
|
|
96
|
+
1. Fork it
|
|
97
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
|
98
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
|
99
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
|
100
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
data/bin/docker-tags
ADDED
data/docker-tags.gemspec
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
$LOAD_PATH.push File.expand_path('../lib', __FILE__)
|
|
2
|
+
require 'dockertags/version'
|
|
3
|
+
|
|
4
|
+
Gem::Specification.new do |s|
|
|
5
|
+
s.name = 'docker-tags'
|
|
6
|
+
s.version = DockerTags::VERSION
|
|
7
|
+
s.authors = ['Jasper Lievisse Adriaanse'],
|
|
8
|
+
s.email = ['jasper@humppa.nl']
|
|
9
|
+
s.homepage = "https://github.com/jasperla/docker-tags"
|
|
10
|
+
s.summary = 'Track tags of Docker images.'
|
|
11
|
+
s.description = 'Track and report tags of followed Docker images.'
|
|
12
|
+
|
|
13
|
+
s.required_ruby_version = '>= 1.9.3'
|
|
14
|
+
s.files = `git ls-files`.split("\n")
|
|
15
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
|
16
|
+
s.executables = s.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
|
17
|
+
s.require_paths = ['lib']
|
|
18
|
+
|
|
19
|
+
s.add_runtime_dependency 'commander', '~> 4.3'
|
|
20
|
+
s.add_runtime_dependency 'faraday'
|
|
21
|
+
s.add_runtime_dependency 'sqlite3'
|
|
22
|
+
|
|
23
|
+
s.add_development_dependency 'bundler', '~> 1.3'
|
|
24
|
+
end
|
data/lib/dockertags.rb
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Copyright (c) 2016 Jasper Lievisse Adriaanse <j@jasper.la>
|
|
2
|
+
# See LICENSE for details
|
|
3
|
+
|
|
4
|
+
require 'dockertags/version'
|
|
5
|
+
require 'dockertags/log'
|
|
6
|
+
require 'dockertags/db'
|
|
7
|
+
require 'dockertags/utils'
|
|
8
|
+
require 'dockertags/cli'
|
|
9
|
+
require 'dockertags/commands'
|
|
10
|
+
|
|
11
|
+
module DockerTags
|
|
12
|
+
unless defined? @@database_path
|
|
13
|
+
@@database_path = 'docker-tags.db'
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def self.database_path
|
|
17
|
+
@@database_path
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def self.database_path=(path)
|
|
21
|
+
@@database_path = path
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# Copyright (c) 2016 Jasper Lievisse Adriaanse <j@jasper.la>
|
|
2
|
+
# See LICENSE for details
|
|
3
|
+
|
|
4
|
+
require 'commander/import'
|
|
5
|
+
|
|
6
|
+
module DockerTags
|
|
7
|
+
class Cli
|
|
8
|
+
program :name, 'Docker Tags'
|
|
9
|
+
program :version, DockerTags::VERSION
|
|
10
|
+
program :description, 'Stay notified of new image tags'
|
|
11
|
+
|
|
12
|
+
default_command :report
|
|
13
|
+
|
|
14
|
+
command :report do |c|
|
|
15
|
+
c.syntax = 'docker-tag-notify report [options]'
|
|
16
|
+
c.description = 'Report of any new tags, correlating layers'
|
|
17
|
+
c.option '--image NAME', String, 'Name of image to follow'
|
|
18
|
+
c.option '--db /path/to/dtn.db', String, 'path to database'
|
|
19
|
+
c.action do |args, options|
|
|
20
|
+
options.default image: args[0]
|
|
21
|
+
options.default db: DockerTags.database_path
|
|
22
|
+
|
|
23
|
+
DockerTags.database_path = options.db
|
|
24
|
+
|
|
25
|
+
DockerTags::Log.warn("Ignoring arguments #{args[1..-1]}") if args.length > 1
|
|
26
|
+
DockerTags::Commands.report(options.image)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
command :latest do |c|
|
|
31
|
+
c.syntax = 'docker-tag-notify latest [options]'
|
|
32
|
+
c.description = 'Get the "latest" tag/aliases'
|
|
33
|
+
c.option '--image NAME', String, 'Name of image to follow'
|
|
34
|
+
c.option '--db /path/to/dtn.db', String, 'path to database'
|
|
35
|
+
c.action do |args, options|
|
|
36
|
+
options.default image: args[0]
|
|
37
|
+
options.default db: DockerTags.database_path
|
|
38
|
+
|
|
39
|
+
DockerTags.database_path = options.db
|
|
40
|
+
|
|
41
|
+
DockerTags::Log.warn("Ignoring arguments #{args[1..-1]}") if args.length > 1
|
|
42
|
+
DockerTags::Commands.latest(options.image)
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
command :follow do |c|
|
|
47
|
+
c.syntax = 'docker-tag-notify follow <image>'
|
|
48
|
+
c.description = 'Track a new image and add current known tags to the db'
|
|
49
|
+
c.option '--image NAME', String, 'Name of image to follow'
|
|
50
|
+
c.option '--db /path/to/dtn.db', String, 'path to database'
|
|
51
|
+
c.action do |args, options|
|
|
52
|
+
options.default image: args[0]
|
|
53
|
+
options.default db: DockerTags.database_path
|
|
54
|
+
|
|
55
|
+
DockerTags.database_path = options.db
|
|
56
|
+
|
|
57
|
+
DockerTags::Log.warn("Ignoring arguments #{args[1..-1]}") if args.length > 1
|
|
58
|
+
DockerTags::Log.err("Invalid image name: '#{options.image}'") unless DockerTags::Utils.valid_image?(options.image)
|
|
59
|
+
DockerTags::Commands.follow(options.image)
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
command :unfollow do |c|
|
|
64
|
+
c.syntax = 'docker-tag-notify unfollow <image>'
|
|
65
|
+
c.description = 'Stop tracking an image and purge it from the db'
|
|
66
|
+
c.option '--image NAME', String, 'Name of image to stop following'
|
|
67
|
+
c.option '--db /path/to/dtn.db', String, 'path to database'
|
|
68
|
+
c.action do |args, options|
|
|
69
|
+
options.default image: args[0]
|
|
70
|
+
options.default db: DockerTags.database_path
|
|
71
|
+
|
|
72
|
+
DockerTags.database_path = options.db
|
|
73
|
+
|
|
74
|
+
DockerTags::Log.warn("Ignoring arguments #{args[1..-1]}") if args.length > 1
|
|
75
|
+
DockerTags::Log.err("Invalid image name: '#{options.image}'") unless DockerTags::Utils.valid_image?(options.image)
|
|
76
|
+
DockerTags::Commands.unfollow(options.image)
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
command :initdb do |c|
|
|
81
|
+
c.syntax = 'docker-tag-notify init [options]'
|
|
82
|
+
c.description = 'Setup and initialize the database'
|
|
83
|
+
c.option '--db /path/to/dtn.db', String, 'path to database'
|
|
84
|
+
c.action do |args, options|
|
|
85
|
+
options.default db: DockerTags.database_path
|
|
86
|
+
|
|
87
|
+
DockerTags.database_path = options.db
|
|
88
|
+
|
|
89
|
+
DockerTags::Commands.initdb
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
command :dump do |c|
|
|
94
|
+
c.syntax = 'docker-tag-notify dump [options]'
|
|
95
|
+
c.description = 'Print the full database contents'
|
|
96
|
+
c.option '--db /path/to/dtn.db', String, 'path to database'
|
|
97
|
+
c.action do |_, options|
|
|
98
|
+
options.default db: DockerTags.database_path
|
|
99
|
+
|
|
100
|
+
DockerTags.database_path = options.db
|
|
101
|
+
|
|
102
|
+
DockerTags::Commands.dump
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
end
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
# Copyright (c) 2016 Jasper Lievisse Adriaanse <j@jasper.la>
|
|
2
|
+
# See LICENSE for details
|
|
3
|
+
|
|
4
|
+
require 'faraday'
|
|
5
|
+
require 'json'
|
|
6
|
+
|
|
7
|
+
module DockerTags
|
|
8
|
+
module Commands
|
|
9
|
+
def self.follow(image)
|
|
10
|
+
dbh = DockerTags::Db.new
|
|
11
|
+
|
|
12
|
+
# There can only be one.
|
|
13
|
+
r = dbh.query "SELECT name FROM images WHERE name = '#{image}'"
|
|
14
|
+
if r.size > 0
|
|
15
|
+
DockerTags::Log.err("Already following image '#{image}'")
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
dbh.query "INSERT INTO images VALUES('#{image}', '')"
|
|
19
|
+
dbh.close
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def self.unfollow(image)
|
|
23
|
+
dbh = DockerTags::Db.new
|
|
24
|
+
dbh.query "DELETE FROM images WHERE name = '#{image}'"
|
|
25
|
+
dbh.query "DELETE FROM tags WHERE image = '#{image}'"
|
|
26
|
+
|
|
27
|
+
n = dbh.changes
|
|
28
|
+
puts "Succesfully removed #{n - 1} tags for #{image}" if n > 0
|
|
29
|
+
dbh.close
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def self.initdb
|
|
33
|
+
dbh = DockerTags::Db.new
|
|
34
|
+
|
|
35
|
+
dbh.query DockerTags::Db::CREATE_IMAGES_TABLE
|
|
36
|
+
dbh.query DockerTags::Db::CREATE_TAGS_TABLE
|
|
37
|
+
|
|
38
|
+
dbh.close
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def self.dump
|
|
42
|
+
dbh = DockerTags::Db.new
|
|
43
|
+
|
|
44
|
+
data = {}
|
|
45
|
+
data[:images] = dbh.query 'SELECT * FROM images'
|
|
46
|
+
data[:tags] = dbh.query 'SELECT * FROM tags'
|
|
47
|
+
|
|
48
|
+
puts JSON.pretty_generate(data)
|
|
49
|
+
dbh.close
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def self.get_images
|
|
53
|
+
dbh = DockerTags::Db.new false
|
|
54
|
+
|
|
55
|
+
r = dbh.query('SELECT name FROM images')
|
|
56
|
+
|
|
57
|
+
images = []
|
|
58
|
+
r.each { |i| images << i[0] }
|
|
59
|
+
dbh.close
|
|
60
|
+
|
|
61
|
+
images
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def self.report(image)
|
|
65
|
+
if image.nil? || image == ''
|
|
66
|
+
images = get_images
|
|
67
|
+
else
|
|
68
|
+
images = [image]
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
result = {}
|
|
72
|
+
images.each do |i|
|
|
73
|
+
new_tags = sync_tags(i)
|
|
74
|
+
if new_tags.size > 0
|
|
75
|
+
r = { image => { tags: [] } }
|
|
76
|
+
new_tags.each do |t|
|
|
77
|
+
r[image][:tags] << {
|
|
78
|
+
tag: t['name'],
|
|
79
|
+
layer: t['layer']
|
|
80
|
+
}
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
result[i] = r
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
puts JSON.pretty_generate(result)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def self.latest(image)
|
|
91
|
+
if image.nil? || image == ''
|
|
92
|
+
image_names = get_images
|
|
93
|
+
else
|
|
94
|
+
image_names = [image]
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
latest_images = {}
|
|
98
|
+
image_names.each do |i|
|
|
99
|
+
sync_tags(i)
|
|
100
|
+
|
|
101
|
+
dbh = DockerTags::Db.new
|
|
102
|
+
rows = dbh.query "SELECT latest FROM images WHERE name = '#{i}'"
|
|
103
|
+
latest_layer = rows[0]['latest']
|
|
104
|
+
|
|
105
|
+
rows = dbh.query "SELECT tag, layer FROM tags WHERE layer = '#{latest_layer}' AND tag != 'latest'"
|
|
106
|
+
dbh.close
|
|
107
|
+
|
|
108
|
+
image_result = {
|
|
109
|
+
image: i,
|
|
110
|
+
layer: latest_layer,
|
|
111
|
+
tag: []
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
# Image only has the 'latest' tag, do display it in that case.
|
|
115
|
+
if rows.empty?
|
|
116
|
+
image_result[:tag] = 'latest'
|
|
117
|
+
else
|
|
118
|
+
rows.each { |t| image_result[:tag] << t['tag'] }
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
latest_images[i] = image_result
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
puts JSON.pretty_generate(latest_images)
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def self.sync_tags(image)
|
|
128
|
+
conn = Faraday.new(url: 'https://registry.hub.docker.com/v1') do |faraday|
|
|
129
|
+
faraday.request :url_encoded
|
|
130
|
+
faraday.adapter Faraday.default_adapter
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
resp = conn.get "repositories/#{image}/tags"
|
|
134
|
+
status = resp.status
|
|
135
|
+
|
|
136
|
+
if status == 404
|
|
137
|
+
DockerTags::Log.err("Could not find image '#{image}' on Docker Hub")
|
|
138
|
+
elsif status != 200
|
|
139
|
+
DockerTags::Log.err("Could not retrieve tags for '#{image}' (error: #{status})")
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
all_tags = JSON.parse(resp.body)
|
|
143
|
+
|
|
144
|
+
dbh = DockerTags::Db.new
|
|
145
|
+
|
|
146
|
+
# Now get all the existing tags for this image
|
|
147
|
+
current_tags = dbh.query "SELECT tag AS name, layer AS layer FROM tags WHERE image = '#{image}'"
|
|
148
|
+
|
|
149
|
+
# prune the results
|
|
150
|
+
current_tags.each { |t| t.delete(0); t.delete(1) }
|
|
151
|
+
|
|
152
|
+
# Compare the existing tags with what we've just fetched.
|
|
153
|
+
# Save the result of the difference and return that later.
|
|
154
|
+
new_tags = all_tags - current_tags
|
|
155
|
+
|
|
156
|
+
# Finish by inserting the list of new tags.
|
|
157
|
+
new_tags.each do |t|
|
|
158
|
+
dbh.query "INSERT INTO tags VALUES('#{t['name']}','#{t['layer']}','#{image}')"
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
latest = all_tags.select { |t| t['name'] == 'latest' }
|
|
162
|
+
if latest.size > 0
|
|
163
|
+
# Set the latest layer
|
|
164
|
+
dbh.query "UPDATE images SET latest = '#{latest[0]['layer']}' WHERE name = '#{image}'"
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
dbh.close
|
|
168
|
+
|
|
169
|
+
# Return the hash of differences for #report to handle
|
|
170
|
+
new_tags
|
|
171
|
+
end
|
|
172
|
+
end
|
|
173
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# Copyright (c) 2016 Jasper Lievisse Adriaanse <j@jasper.la>
|
|
2
|
+
# See LICENSE for details
|
|
3
|
+
|
|
4
|
+
require 'sqlite3'
|
|
5
|
+
|
|
6
|
+
module DockerTags
|
|
7
|
+
class Db
|
|
8
|
+
CREATE_IMAGES_TABLE = %{
|
|
9
|
+
CREATE TABLE IF NOT EXISTS images (
|
|
10
|
+
name varchar(30),
|
|
11
|
+
latest varchar(16)
|
|
12
|
+
);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
CREATE_TAGS_TABLE = %{
|
|
16
|
+
CREATE TABLE IF NOT EXISTS tags (
|
|
17
|
+
tag varchar(30),
|
|
18
|
+
layer varchar(8),
|
|
19
|
+
image varchar(16)
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
def initialize(as_hash = true)
|
|
24
|
+
begin
|
|
25
|
+
@dbh = SQLite3::Database.new DockerTags.database_path
|
|
26
|
+
@dbh.results_as_hash = as_hash
|
|
27
|
+
rescue SQLite3::Exception => e
|
|
28
|
+
DockerTags::Log.sql_err(e, __method__)
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def query(query)
|
|
33
|
+
begin
|
|
34
|
+
@dbh.execute(query)
|
|
35
|
+
rescue SQLite3::Exception => e
|
|
36
|
+
DockerTags::Log.sql_err(e, __method__)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def close
|
|
41
|
+
@dbh.close if @dbh
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def changes
|
|
45
|
+
@dbh.changes
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Copyright (c) 2016 Jasper Lievisse Adriaanse <j@jasper.la>
|
|
2
|
+
# See LICENSE for details
|
|
3
|
+
|
|
4
|
+
module DockerTags
|
|
5
|
+
module Log
|
|
6
|
+
def self.warn(str)
|
|
7
|
+
puts "WARN: #{str}"
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def self.err(str)
|
|
11
|
+
puts "ERROR: #{str}"
|
|
12
|
+
exit
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def self.sql_err(e, m)
|
|
16
|
+
puts "An SQLite error occured in #{m}: #{e}"
|
|
17
|
+
exit
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Copyright (c) 2016 Jasper Lievisse Adriaanse <j@jasper.la>
|
|
2
|
+
# See LICENSE for details
|
|
3
|
+
|
|
4
|
+
module DockerTags
|
|
5
|
+
module Utils
|
|
6
|
+
# basic image name validation. cannot be empty of contain spaces
|
|
7
|
+
def self.valid_image?(name)
|
|
8
|
+
if name.nil? || name.empty? || (name.length != name.sub(/\s*/, "").length)
|
|
9
|
+
nil
|
|
10
|
+
else
|
|
11
|
+
true
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: docker-tags
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Jasper Lievisse Adriaanse
|
|
8
|
+
- jasper@humppa.nl
|
|
9
|
+
autorequire:
|
|
10
|
+
bindir: bin
|
|
11
|
+
cert_chain: []
|
|
12
|
+
date: 2016-01-31 00:00:00.000000000 Z
|
|
13
|
+
dependencies:
|
|
14
|
+
- !ruby/object:Gem::Dependency
|
|
15
|
+
name: commander
|
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
|
17
|
+
requirements:
|
|
18
|
+
- - "~>"
|
|
19
|
+
- !ruby/object:Gem::Version
|
|
20
|
+
version: '4.3'
|
|
21
|
+
type: :runtime
|
|
22
|
+
prerelease: false
|
|
23
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
24
|
+
requirements:
|
|
25
|
+
- - "~>"
|
|
26
|
+
- !ruby/object:Gem::Version
|
|
27
|
+
version: '4.3'
|
|
28
|
+
- !ruby/object:Gem::Dependency
|
|
29
|
+
name: faraday
|
|
30
|
+
requirement: !ruby/object:Gem::Requirement
|
|
31
|
+
requirements:
|
|
32
|
+
- - ">="
|
|
33
|
+
- !ruby/object:Gem::Version
|
|
34
|
+
version: '0'
|
|
35
|
+
type: :runtime
|
|
36
|
+
prerelease: false
|
|
37
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
38
|
+
requirements:
|
|
39
|
+
- - ">="
|
|
40
|
+
- !ruby/object:Gem::Version
|
|
41
|
+
version: '0'
|
|
42
|
+
- !ruby/object:Gem::Dependency
|
|
43
|
+
name: sqlite3
|
|
44
|
+
requirement: !ruby/object:Gem::Requirement
|
|
45
|
+
requirements:
|
|
46
|
+
- - ">="
|
|
47
|
+
- !ruby/object:Gem::Version
|
|
48
|
+
version: '0'
|
|
49
|
+
type: :runtime
|
|
50
|
+
prerelease: false
|
|
51
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
52
|
+
requirements:
|
|
53
|
+
- - ">="
|
|
54
|
+
- !ruby/object:Gem::Version
|
|
55
|
+
version: '0'
|
|
56
|
+
- !ruby/object:Gem::Dependency
|
|
57
|
+
name: bundler
|
|
58
|
+
requirement: !ruby/object:Gem::Requirement
|
|
59
|
+
requirements:
|
|
60
|
+
- - "~>"
|
|
61
|
+
- !ruby/object:Gem::Version
|
|
62
|
+
version: '1.3'
|
|
63
|
+
type: :development
|
|
64
|
+
prerelease: false
|
|
65
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
66
|
+
requirements:
|
|
67
|
+
- - "~>"
|
|
68
|
+
- !ruby/object:Gem::Version
|
|
69
|
+
version: '1.3'
|
|
70
|
+
description: Track and report tags of followed Docker images.
|
|
71
|
+
email:
|
|
72
|
+
- jasper@humppa.nl
|
|
73
|
+
executables:
|
|
74
|
+
- docker-tags
|
|
75
|
+
extensions: []
|
|
76
|
+
extra_rdoc_files: []
|
|
77
|
+
files:
|
|
78
|
+
- ".gitignore"
|
|
79
|
+
- ".rubocop.yml"
|
|
80
|
+
- ".rubocop_todo.yml"
|
|
81
|
+
- Gemfile
|
|
82
|
+
- Gemfile.lock
|
|
83
|
+
- LICENSE
|
|
84
|
+
- README.md
|
|
85
|
+
- Rakefile
|
|
86
|
+
- bin/docker-tags
|
|
87
|
+
- docker-tags.gemspec
|
|
88
|
+
- lib/dockertags.rb
|
|
89
|
+
- lib/dockertags/cli.rb
|
|
90
|
+
- lib/dockertags/commands.rb
|
|
91
|
+
- lib/dockertags/db.rb
|
|
92
|
+
- lib/dockertags/log.rb
|
|
93
|
+
- lib/dockertags/utils.rb
|
|
94
|
+
- lib/dockertags/version.rb
|
|
95
|
+
homepage: https://github.com/jasperla/docker-tags
|
|
96
|
+
licenses: []
|
|
97
|
+
metadata: {}
|
|
98
|
+
post_install_message:
|
|
99
|
+
rdoc_options: []
|
|
100
|
+
require_paths:
|
|
101
|
+
- lib
|
|
102
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
103
|
+
requirements:
|
|
104
|
+
- - ">="
|
|
105
|
+
- !ruby/object:Gem::Version
|
|
106
|
+
version: 1.9.3
|
|
107
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
108
|
+
requirements:
|
|
109
|
+
- - ">="
|
|
110
|
+
- !ruby/object:Gem::Version
|
|
111
|
+
version: '0'
|
|
112
|
+
requirements: []
|
|
113
|
+
rubyforge_project:
|
|
114
|
+
rubygems_version: 2.4.5.1
|
|
115
|
+
signing_key:
|
|
116
|
+
specification_version: 4
|
|
117
|
+
summary: Track tags of Docker images.
|
|
118
|
+
test_files: []
|