tagfish 1.0.1
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 +14 -0
 - data/Dockerfile +23 -0
 - data/Gemfile +4 -0
 - data/README.md +178 -0
 - data/Rakefile +39 -0
 - data/bin/tagfish +32 -0
 - data/lib/tagfish.rb +5 -0
 - data/lib/tagfish/api_call.rb +41 -0
 - data/lib/tagfish/docker_api.rb +113 -0
 - data/lib/tagfish/docker_http_auth.rb +31 -0
 - data/lib/tagfish/docker_uri.rb +64 -0
 - data/lib/tagfish/search_command.rb +32 -0
 - data/lib/tagfish/tags.rb +26 -0
 - data/lib/tagfish/tags_command.rb +37 -0
 - data/lib/tagfish/tags_logic.rb +52 -0
 - data/lib/tagfish/tokeniser.rb +37 -0
 - data/lib/tagfish/update/differ.rb +13 -0
 - data/lib/tagfish/update/update_command.rb +31 -0
 - data/lib/tagfish/update/updater.rb +53 -0
 - data/lib/tagfish/update/uri_filters.rb +20 -0
 - data/lib/tagfish/version.rb +3 -0
 - data/logo.jpg +0 -0
 - data/tagfish.gemspec +27 -0
 - metadata +152 -0
 
    
        checksums.yaml
    ADDED
    
    | 
         @@ -0,0 +1,7 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            ---
         
     | 
| 
      
 2 
     | 
    
         
            +
            SHA1:
         
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: 801be00ea36e0cc2c98c535546c45f1025768ca0
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: 9ce46a51783f66f42f9da2f4d5a5cebc6e459fd4
         
     | 
| 
      
 5 
     | 
    
         
            +
            SHA512:
         
     | 
| 
      
 6 
     | 
    
         
            +
              metadata.gz: ad70b423105855d754bed1ad62d9291dbc18ac4ce113e38e3825aa72765d792572767a6f3df90f2c20c0af5677358cc9281f6499dbb49fb303e5ca312740c182
         
     | 
| 
      
 7 
     | 
    
         
            +
              data.tar.gz: 33dbd5a8faf479d8a10364b7980731bb9c1823915d4aab0d08a4ac6d3a018fde857b22c22c950359bce3c2086fb9fd58eb92dafc358bb3580a753b5bc2ce6efe
         
     | 
    
        data/.gitignore
    ADDED
    
    
    
        data/Dockerfile
    ADDED
    
    | 
         @@ -0,0 +1,23 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            FROM alpine:edge
         
     | 
| 
      
 2 
     | 
    
         
            +
            MAINTAINER Clement Labbe <clement.labbe@rea-group.com>
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            RUN apk add --update ruby=2.2.3-r1 \
         
     | 
| 
      
 5 
     | 
    
         
            +
                ruby-dev=2.2.3-r1 \
         
     | 
| 
      
 6 
     | 
    
         
            +
                ruby-io-console=2.2.3-r1 \
         
     | 
| 
      
 7 
     | 
    
         
            +
                diffutils \
         
     | 
| 
      
 8 
     | 
    
         
            +
                linux-headers \
         
     | 
| 
      
 9 
     | 
    
         
            +
                build-base \
         
     | 
| 
      
 10 
     | 
    
         
            +
                ca-certificates=20150426-r3 && \
         
     | 
| 
      
 11 
     | 
    
         
            +
                rm /var/cache/apk/* && \
         
     | 
| 
      
 12 
     | 
    
         
            +
                rm -rf /usr/share/ri
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
            RUN echo -e 'gem: --no-rdoc --no-ri' > /etc/gemrc \
         
     | 
| 
      
 15 
     | 
    
         
            +
                gem update --system 2.4.8 && \
         
     | 
| 
      
 16 
     | 
    
         
            +
                gem install bundler -v 1.10.6 && \
         
     | 
| 
      
 17 
     | 
    
         
            +
                rm -rf /usr/share/ri
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
            COPY pkg/tagfish-latest.gem /cwd/
         
     | 
| 
      
 20 
     | 
    
         
            +
            WORKDIR /cwd
         
     | 
| 
      
 21 
     | 
    
         
            +
            RUN gem install tagfish-latest.gem
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
            ENTRYPOINT ["tagfish"]
         
     | 
    
        data/Gemfile
    ADDED
    
    
    
        data/README.md
    ADDED
    
    | 
         @@ -0,0 +1,178 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # Tagfish 
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            Tagfish is a CLI tool to interact with Docker registries. 
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            Features include:
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
            - List all the tags of a given Docker repository
         
     | 
| 
      
 10 
     | 
    
         
            +
            - Return the most recent explicit tag of a repository
         
     | 
| 
      
 11 
     | 
    
         
            +
            - Update a file with the newest tags
         
     | 
| 
      
 12 
     | 
    
         
            +
            - Search for a repository
         
     | 
| 
      
 13 
     | 
    
         
            +
            - Authenticate by reading native Docker config file 
         
     | 
| 
      
 14 
     | 
    
         
            +
            - Works against hub.docker.com and private registries
         
     | 
| 
      
 15 
     | 
    
         
            +
            - Supports Docker Registry/Distribution API v1 and v2 
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
            To use Tagfish against a registry requiring authentication, you first need to authenticate to the given registry using `docker login <REGISTRY>`.
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
            ## Table of contents
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
            <!-- MarkdownTOC autolink=true bracket=round depth=4 -->
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
            - [Usage](#usage)
         
     | 
| 
      
 24 
     | 
    
         
            +
              - [`tagfish tags`](#tagfish-tags)
         
     | 
| 
      
 25 
     | 
    
         
            +
                - [Example](#example)
         
     | 
| 
      
 26 
     | 
    
         
            +
              - [`tagfish search`](#tagfish-search)
         
     | 
| 
      
 27 
     | 
    
         
            +
                - [Example](#example-1)
         
     | 
| 
      
 28 
     | 
    
         
            +
              - [`tagfish update`](#tagfish-update)
         
     | 
| 
      
 29 
     | 
    
         
            +
                - [Example](#example-2)
         
     | 
| 
      
 30 
     | 
    
         
            +
                - [Official repositories](#official-repositories)
         
     | 
| 
      
 31 
     | 
    
         
            +
            - [Installation](#installation)
         
     | 
| 
      
 32 
     | 
    
         
            +
              - [Gem](#gem)
         
     | 
| 
      
 33 
     | 
    
         
            +
                - [Limitations](#limitations)
         
     | 
| 
      
 34 
     | 
    
         
            +
              - [Docker image](#docker-image)
         
     | 
| 
      
 35 
     | 
    
         
            +
            - [Contributing](#contributing)
         
     | 
| 
      
 36 
     | 
    
         
            +
            - [Licence](#licence)
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
            <!-- /MarkdownTOC -->
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
            ## Usage
         
     | 
| 
      
 42 
     | 
    
         
            +
            The Tagfish CLI tool has different subcommands for interacting with Docker registries.
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
            ### `tagfish tags`
         
     | 
| 
      
 45 
     | 
    
         
            +
            The `tags` subcommands is used to retrieve tags from a given repository:
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
                Usage:
         
     | 
| 
      
 48 
     | 
    
         
            +
                    tagfish tags [OPTIONS] REPOSITORY
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
                Parameters:
         
     | 
| 
      
 51 
     | 
    
         
            +
                    REPOSITORY                    docker repository
         
     | 
| 
      
 52 
     | 
    
         
            +
             
     | 
| 
      
 53 
     | 
    
         
            +
                Options:
         
     | 
| 
      
 54 
     | 
    
         
            +
                    -l, --latest                  only return latest explicitly tagged image
         
     | 
| 
      
 55 
     | 
    
         
            +
                    -s, --short                   only return tag, not full image path
         
     | 
| 
      
 56 
     | 
    
         
            +
                    -h, --help                    print help
         
     | 
| 
      
 57 
     | 
    
         
            +
             
     | 
| 
      
 58 
     | 
    
         
            +
            Where `repository` is a docker repository path, including the docker registry. The tags are returned in alphabetical order.
         
     | 
| 
      
 59 
     | 
    
         
            +
             
     | 
| 
      
 60 
     | 
    
         
            +
            The `--latest` option gets the image ID of the docker image tagged `latest` in the repository, finds a matching image with a tag set manually (e.g: date, version number), and returns that tag. This option will not work if there is no image tagged `latest` in your repository.
         
     | 
| 
      
 61 
     | 
    
         
            +
             
     | 
| 
      
 62 
     | 
    
         
            +
            #### Example
         
     | 
| 
      
 63 
     | 
    
         
            +
            ```
         
     | 
| 
      
 64 
     | 
    
         
            +
            $ tagfish tags alpine
         
     | 
| 
      
 65 
     | 
    
         
            +
            alpine:2.6
         
     | 
| 
      
 66 
     | 
    
         
            +
            alpine:2.7
         
     | 
| 
      
 67 
     | 
    
         
            +
            alpine:3.1
         
     | 
| 
      
 68 
     | 
    
         
            +
            alpine:3.2
         
     | 
| 
      
 69 
     | 
    
         
            +
            alpine:edge
         
     | 
| 
      
 70 
     | 
    
         
            +
            alpine:latest
         
     | 
| 
      
 71 
     | 
    
         
            +
            ```
         
     | 
| 
      
 72 
     | 
    
         
            +
             
     | 
| 
      
 73 
     | 
    
         
            +
            ### `tagfish search`
         
     | 
| 
      
 74 
     | 
    
         
            +
            The `search` command is used to search for a repository in a given registry.
         
     | 
| 
      
 75 
     | 
    
         
            +
             
     | 
| 
      
 76 
     | 
    
         
            +
                Usage:
         
     | 
| 
      
 77 
     | 
    
         
            +
                    tagfish search [OPTIONS] [KEYWORD]
         
     | 
| 
      
 78 
     | 
    
         
            +
             
     | 
| 
      
 79 
     | 
    
         
            +
                Parameters:
         
     | 
| 
      
 80 
     | 
    
         
            +
                    [KEYWORD]                     object to search
         
     | 
| 
      
 81 
     | 
    
         
            +
             
     | 
| 
      
 82 
     | 
    
         
            +
                Options:
         
     | 
| 
      
 83 
     | 
    
         
            +
                    -r, --registry REGISTRY       Docker registry (default: "index.docker.io")
         
     | 
| 
      
 84 
     | 
    
         
            +
                    -h, --help                    print help
         
     | 
| 
      
 85 
     | 
    
         
            +
             
     | 
| 
      
 86 
     | 
    
         
            +
            Note: `search` will not work if the search API is disabled on the registry side. 
         
     | 
| 
      
 87 
     | 
    
         
            +
             
     | 
| 
      
 88 
     | 
    
         
            +
            #### Example
         
     | 
| 
      
 89 
     | 
    
         
            +
            ```
         
     | 
| 
      
 90 
     | 
    
         
            +
            $ tagfish search alpine
         
     | 
| 
      
 91 
     | 
    
         
            +
            alpine
         
     | 
| 
      
 92 
     | 
    
         
            +
            1science/alpine
         
     | 
| 
      
 93 
     | 
    
         
            +
            webhippie/alpine
         
     | 
| 
      
 94 
     | 
    
         
            +
            anapsix/alpine-java
         
     | 
| 
      
 95 
     | 
    
         
            +
            colstrom/alpine
         
     | 
| 
      
 96 
     | 
    
         
            +
            appelgriebsch/alpine
         
     | 
| 
      
 97 
     | 
    
         
            +
            [...]
         
     | 
| 
      
 98 
     | 
    
         
            +
            ```
         
     | 
| 
      
 99 
     | 
    
         
            +
             
     | 
| 
      
 100 
     | 
    
         
            +
            ### `tagfish update`
         
     | 
| 
      
 101 
     | 
    
         
            +
            The `update` subcommand is used to update a file with the latest tags available:
         
     | 
| 
      
 102 
     | 
    
         
            +
             
     | 
| 
      
 103 
     | 
    
         
            +
                Usage:
         
     | 
| 
      
 104 
     | 
    
         
            +
                    tagfish update [OPTIONS] FILE
         
     | 
| 
      
 105 
     | 
    
         
            +
                
         
     | 
| 
      
 106 
     | 
    
         
            +
                Parameters:
         
     | 
| 
      
 107 
     | 
    
         
            +
                    FILE                          file to update
         
     | 
| 
      
 108 
     | 
    
         
            +
                
         
     | 
| 
      
 109 
     | 
    
         
            +
                Options:
         
     | 
| 
      
 110 
     | 
    
         
            +
                    -d, --dry-run                 enable dry run
         
     | 
| 
      
 111 
     | 
    
         
            +
                    --only PATTERN                Only update repositories matching pattern. Wildcards `*` may be used.
         
     | 
| 
      
 112 
     | 
    
         
            +
                    -h, --help                    print help
         
     | 
| 
      
 113 
     | 
    
         
            +
             
     | 
| 
      
 114 
     | 
    
         
            +
            #### Example
         
     | 
| 
      
 115 
     | 
    
         
            +
            ```
         
     | 
| 
      
 116 
     | 
    
         
            +
            $ tagfish update --dry-run Dockerfile
         
     | 
| 
      
 117 
     | 
    
         
            +
            -FROM docker-registry.delivery.realestate.com.au/gpde/ubuntu-ruby2.2:201508191500
         
     | 
| 
      
 118 
     | 
    
         
            +
            +FROM docker-registry.delivery.realestate.com.au/gpde/ubuntu-ruby2.2:201511261833
         
     | 
| 
      
 119 
     | 
    
         
            +
            ```
         
     | 
| 
      
 120 
     | 
    
         
            +
             
     | 
| 
      
 121 
     | 
    
         
            +
            #### Official repositories
         
     | 
| 
      
 122 
     | 
    
         
            +
            `tagfish update` will update repositories such as:
         
     | 
| 
      
 123 
     | 
    
         
            +
            ```
         
     | 
| 
      
 124 
     | 
    
         
            +
            private.registry/namespace/repository:tag
         
     | 
| 
      
 125 
     | 
    
         
            +
            namespace/repository:tag
         
     | 
| 
      
 126 
     | 
    
         
            +
            ```
         
     | 
| 
      
 127 
     | 
    
         
            +
            However, it will not update the tag of official repositories, such as:
         
     | 
| 
      
 128 
     | 
    
         
            +
            ```
         
     | 
| 
      
 129 
     | 
    
         
            +
            ubuntu:tag
         
     | 
| 
      
 130 
     | 
    
         
            +
            ```
         
     | 
| 
      
 131 
     | 
    
         
            +
            This is because updating to a new OS automatically might be something you want to avoid, and because it is hard to match a repository without a namespace.
         
     | 
| 
      
 132 
     | 
    
         
            +
             
     | 
| 
      
 133 
     | 
    
         
            +
            ## Installation
         
     | 
| 
      
 134 
     | 
    
         
            +
            ### Gem
         
     | 
| 
      
 135 
     | 
    
         
            +
            Tagfish is packaged as a Ruby gem. Install it from the command line:
         
     | 
| 
      
 136 
     | 
    
         
            +
             
     | 
| 
      
 137 
     | 
    
         
            +
            ```
         
     | 
| 
      
 138 
     | 
    
         
            +
            $ gem install tagfish
         
     | 
| 
      
 139 
     | 
    
         
            +
            ```
         
     | 
| 
      
 140 
     | 
    
         
            +
             
     | 
| 
      
 141 
     | 
    
         
            +
            #### Limitations
         
     | 
| 
      
 142 
     | 
    
         
            +
            Tagfish requires Ruby 2.2 or newer if the registry you are accessing restricts TLS to v1.2.
         
     | 
| 
      
 143 
     | 
    
         
            +
             
     | 
| 
      
 144 
     | 
    
         
            +
            ### Docker image
         
     | 
| 
      
 145 
     | 
    
         
            +
            Tagfish is released as a Docker image as well, and can be run with:
         
     | 
| 
      
 146 
     | 
    
         
            +
             
     | 
| 
      
 147 
     | 
    
         
            +
            ```
         
     | 
| 
      
 148 
     | 
    
         
            +
            docker run --rm \
         
     | 
| 
      
 149 
     | 
    
         
            +
              -v ~/.docker/config.json:/root/.docker/config.json:ro \
         
     | 
| 
      
 150 
     | 
    
         
            +
              -v ${PWD}:/cwd \
         
     | 
| 
      
 151 
     | 
    
         
            +
              cowbell/tagfish
         
     | 
| 
      
 152 
     | 
    
         
            +
            ```
         
     | 
| 
      
 153 
     | 
    
         
            +
             
     | 
| 
      
 154 
     | 
    
         
            +
            ## Contributing
         
     | 
| 
      
 155 
     | 
    
         
            +
             
     | 
| 
      
 156 
     | 
    
         
            +
            Bug reports and pull requests are welcome on GitHub at https://github.com/realestate-com-au/tagfish .
         
     | 
| 
      
 157 
     | 
    
         
            +
             
     | 
| 
      
 158 
     | 
    
         
            +
            ## Licence
         
     | 
| 
      
 159 
     | 
    
         
            +
             
     | 
| 
      
 160 
     | 
    
         
            +
            Copyright (c) 2015 REA Group Ltd.
         
     | 
| 
      
 161 
     | 
    
         
            +
             
     | 
| 
      
 162 
     | 
    
         
            +
            Permission is hereby granted, free of charge, to any person obtaining a copy
         
     | 
| 
      
 163 
     | 
    
         
            +
            of this software and associated documentation files (the "Software"), to deal
         
     | 
| 
      
 164 
     | 
    
         
            +
            in the Software without restriction, including without limitation the rights
         
     | 
| 
      
 165 
     | 
    
         
            +
            to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
         
     | 
| 
      
 166 
     | 
    
         
            +
            copies of the Software, and to permit persons to whom the Software is
         
     | 
| 
      
 167 
     | 
    
         
            +
            furnished to do so, subject to the following conditions:
         
     | 
| 
      
 168 
     | 
    
         
            +
             
     | 
| 
      
 169 
     | 
    
         
            +
            The above copyright notice and this permission notice shall be included in
         
     | 
| 
      
 170 
     | 
    
         
            +
            all copies or substantial portions of the Software.
         
     | 
| 
      
 171 
     | 
    
         
            +
             
     | 
| 
      
 172 
     | 
    
         
            +
            THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
         
     | 
| 
      
 173 
     | 
    
         
            +
            IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
         
     | 
| 
      
 174 
     | 
    
         
            +
            FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
         
     | 
| 
      
 175 
     | 
    
         
            +
            AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
         
     | 
| 
      
 176 
     | 
    
         
            +
            LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
         
     | 
| 
      
 177 
     | 
    
         
            +
            OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
         
     | 
| 
      
 178 
     | 
    
         
            +
            THE SOFTWARE.
         
     | 
    
        data/Rakefile
    ADDED
    
    | 
         @@ -0,0 +1,39 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require "bundler/gem_tasks"
         
     | 
| 
      
 2 
     | 
    
         
            +
            require "fileutils"
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            spec = Gem::Specification::load(Dir.glob("*.gemspec").first)
         
     | 
| 
      
 5 
     | 
    
         
            +
            gem_file = "pkg/#{spec.name}-#{spec.version}.gem"
         
     | 
| 
      
 6 
     | 
    
         
            +
            docker_uri = "cowbell/#{spec.name}"
         
     | 
| 
      
 7 
     | 
    
         
            +
            tag = "#{spec.version}"
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
            desc "build docker image locally"
         
     | 
| 
      
 10 
     | 
    
         
            +
            task build_docker_image: [:build] do
         
     | 
| 
      
 11 
     | 
    
         
            +
              FileUtils.copy(gem_file, "pkg/tagfish-latest.gem")
         
     | 
| 
      
 12 
     | 
    
         
            +
              sh "docker build -t #{docker_uri}:#{tag} ."
         
     | 
| 
      
 13 
     | 
    
         
            +
              sh "docker tag -f #{docker_uri}:#{tag} #{docker_uri}:latest"
         
     | 
| 
      
 14 
     | 
    
         
            +
              puts "Built image #{docker_uri}"
         
     | 
| 
      
 15 
     | 
    
         
            +
            end
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
            desc "Release docker image"
         
     | 
| 
      
 18 
     | 
    
         
            +
            task release_docker_image: [:build_docker_image] do
         
     | 
| 
      
 19 
     | 
    
         
            +
              sh "docker push #{docker_uri}:#{tag}"
         
     | 
| 
      
 20 
     | 
    
         
            +
              sh "docker push #{docker_uri}:latest"
         
     | 
| 
      
 21 
     | 
    
         
            +
            end
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
            desc "Check for git sync"
         
     | 
| 
      
 24 
     | 
    
         
            +
            task :no_local_changes do
         
     | 
| 
      
 25 
     | 
    
         
            +
              sh "git pull"
         
     | 
| 
      
 26 
     | 
    
         
            +
              sh "git diff HEAD --exit-code"
         
     | 
| 
      
 27 
     | 
    
         
            +
            end
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
            desc "Tag version into git repo"
         
     | 
| 
      
 30 
     | 
    
         
            +
            task git_tag: [:no_local_changes] do
         
     | 
| 
      
 31 
     | 
    
         
            +
              puts "blah"
         
     | 
| 
      
 32 
     | 
    
         
            +
              sh "git tag #{tag}"
         
     | 
| 
      
 33 
     | 
    
         
            +
              sh "git push origin --tags"
         
     | 
| 
      
 34 
     | 
    
         
            +
            end
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
            desc "Release gem and docker image"
         
     | 
| 
      
 37 
     | 
    
         
            +
            task release_all: [:git_tag, :release, :release_docker_image] do
         
     | 
| 
      
 38 
     | 
    
         
            +
              puts "Released all"
         
     | 
| 
      
 39 
     | 
    
         
            +
            end
         
     | 
    
        data/bin/tagfish
    ADDED
    
    | 
         @@ -0,0 +1,32 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            #!/usr/bin/env ruby
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            $LOAD_PATH << File.expand_path("../../lib", __FILE__)
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            require 'clamp'
         
     | 
| 
      
 6 
     | 
    
         
            +
            require 'tagfish/tags_command'
         
     | 
| 
      
 7 
     | 
    
         
            +
            require 'tagfish/update/update_command'
         
     | 
| 
      
 8 
     | 
    
         
            +
            require 'tagfish/search_command'
         
     | 
| 
      
 9 
     | 
    
         
            +
            require "tagfish/version"
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
            module Tagfish
         
     | 
| 
      
 12 
     | 
    
         
            +
              class MainCommand < Clamp::Command
         
     | 
| 
      
 13 
     | 
    
         
            +
                option ["-v", "--version"], :flag, "display version" do
         
     | 
| 
      
 14 
     | 
    
         
            +
                    puts "tagfish-#{Tagfish::VERSION}"
         
     | 
| 
      
 15 
     | 
    
         
            +
                    exit 0
         
     | 
| 
      
 16 
     | 
    
         
            +
                end
         
     | 
| 
      
 17 
     | 
    
         
            +
              end
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
              class MainCommand < Clamp::Command
         
     | 
| 
      
 20 
     | 
    
         
            +
                subcommand "tags", "find tags for a repository", TagsCommand
         
     | 
| 
      
 21 
     | 
    
         
            +
              end
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
              class MainCommand < Clamp::Command
         
     | 
| 
      
 24 
     | 
    
         
            +
                subcommand "update", "inspect files for outdated dependencies", Update::UpdateCommand
         
     | 
| 
      
 25 
     | 
    
         
            +
              end
         
     | 
| 
      
 26 
     | 
    
         
            +
              
         
     | 
| 
      
 27 
     | 
    
         
            +
              class MainCommand < Clamp::Command
         
     | 
| 
      
 28 
     | 
    
         
            +
                subcommand "search", "search a registry for repositories", SearchCommand
         
     | 
| 
      
 29 
     | 
    
         
            +
              end
         
     | 
| 
      
 30 
     | 
    
         
            +
              
         
     | 
| 
      
 31 
     | 
    
         
            +
              MainCommand.run
         
     | 
| 
      
 32 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/tagfish.rb
    ADDED
    
    
| 
         @@ -0,0 +1,41 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Tagfish
         
     | 
| 
      
 2 
     | 
    
         
            +
              class APICall
         
     | 
| 
      
 3 
     | 
    
         
            +
                attr_accessor :uri
         
     | 
| 
      
 4 
     | 
    
         
            +
                attr_accessor :http
         
     | 
| 
      
 5 
     | 
    
         
            +
                attr_accessor :request
         
     | 
| 
      
 6 
     | 
    
         
            +
              
         
     | 
| 
      
 7 
     | 
    
         
            +
                def initialize(uri_string) 
         
     | 
| 
      
 8 
     | 
    
         
            +
                  @uri = URI.parse(uri_string)
         
     | 
| 
      
 9 
     | 
    
         
            +
                  @http = Net::HTTP.new(uri.host, uri.port)
         
     | 
| 
      
 10 
     | 
    
         
            +
                  @http.use_ssl = true if uri.port == 443
         
     | 
| 
      
 11 
     | 
    
         
            +
                  @request = Net::HTTP::Get.new(uri.request_uri)
         
     | 
| 
      
 12 
     | 
    
         
            +
                end
         
     | 
| 
      
 13 
     | 
    
         
            +
                    
         
     | 
| 
      
 14 
     | 
    
         
            +
                def get_json(http_auth=nil)
         
     | 
| 
      
 15 
     | 
    
         
            +
                  begin
         
     | 
| 
      
 16 
     | 
    
         
            +
                    auth(http_auth) if http_auth
         
     | 
| 
      
 17 
     | 
    
         
            +
                    response = http.request(request)
         
     | 
| 
      
 18 
     | 
    
         
            +
                    if response.code == "200"
         
     | 
| 
      
 19 
     | 
    
         
            +
                      return JSON.parse(response.body)
         
     | 
| 
      
 20 
     | 
    
         
            +
                    else
         
     | 
| 
      
 21 
     | 
    
         
            +
                      abort("Call to the registry API failed, the following resource might not exist:\n#{uri.to_s}")
         
     | 
| 
      
 22 
     | 
    
         
            +
                    end
         
     | 
| 
      
 23 
     | 
    
         
            +
                  rescue SocketError
         
     | 
| 
      
 24 
     | 
    
         
            +
                    puts "ERROR: SocketError"
         
     | 
| 
      
 25 
     | 
    
         
            +
                  end
         
     | 
| 
      
 26 
     | 
    
         
            +
                end
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
                def response_code(http_auth=nil)
         
     | 
| 
      
 29 
     | 
    
         
            +
                  auth(http_auth) if http_auth
         
     | 
| 
      
 30 
     | 
    
         
            +
                  begin
         
     | 
| 
      
 31 
     | 
    
         
            +
                    http.request(request).code.to_i
         
     | 
| 
      
 32 
     | 
    
         
            +
                  rescue SocketError
         
     | 
| 
      
 33 
     | 
    
         
            +
                    abort("Call to the registry API failed, the following resource might not exist:\n#{uri.to_s}")
         
     | 
| 
      
 34 
     | 
    
         
            +
                  end
         
     | 
| 
      
 35 
     | 
    
         
            +
                end
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
                def auth(http_auth)
         
     | 
| 
      
 38 
     | 
    
         
            +
                  @request.basic_auth(http_auth.username, http_auth.password)
         
     | 
| 
      
 39 
     | 
    
         
            +
                end
         
     | 
| 
      
 40 
     | 
    
         
            +
              end
         
     | 
| 
      
 41 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,113 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'net/http'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'json'
         
     | 
| 
      
 3 
     | 
    
         
            +
            require 'tagfish/docker_uri'
         
     | 
| 
      
 4 
     | 
    
         
            +
            require 'tagfish/api_call'
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            module Tagfish
         
     | 
| 
      
 7 
     | 
    
         
            +
              class DockerAPI
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                attr_accessor :docker_uri
         
     | 
| 
      
 10 
     | 
    
         
            +
                attr_accessor :api_version
         
     | 
| 
      
 11 
     | 
    
         
            +
                attr_accessor :http_auth
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                def initialize(docker_uri)
         
     | 
| 
      
 14 
     | 
    
         
            +
                  @docker_uri = docker_uri
         
     | 
| 
      
 15 
     | 
    
         
            +
                  retrieve_api_version_and_auth()
         
     | 
| 
      
 16 
     | 
    
         
            +
                end
         
     | 
| 
      
 17 
     | 
    
         
            +
                
         
     | 
| 
      
 18 
     | 
    
         
            +
                def retrieve_api_version_and_auth
         
     | 
| 
      
 19 
     | 
    
         
            +
                  code = try_api('v1')
         
     | 
| 
      
 20 
     | 
    
         
            +
                  if code != 200 
         
     | 
| 
      
 21 
     | 
    
         
            +
                    code = try_api('v2')
         
     | 
| 
      
 22 
     | 
    
         
            +
                  end
         
     | 
| 
      
 23 
     | 
    
         
            +
                  if code == 401
         
     | 
| 
      
 24 
     | 
    
         
            +
                    abort("Authentication failed, please `docker login <REGISTRY>` and try again.")
         
     | 
| 
      
 25 
     | 
    
         
            +
                  elsif code != 200
         
     | 
| 
      
 26 
     | 
    
         
            +
                    abort("API version not recognized")
         
     | 
| 
      
 27 
     | 
    
         
            +
                  end
         
     | 
| 
      
 28 
     | 
    
         
            +
                end
         
     | 
| 
      
 29 
     | 
    
         
            +
                
         
     | 
| 
      
 30 
     | 
    
         
            +
                def try_api(version)
         
     | 
| 
      
 31 
     | 
    
         
            +
                  code = APICall.new(ping_uri(version)).response_code
         
     | 
| 
      
 32 
     | 
    
         
            +
                  if code == 200
         
     | 
| 
      
 33 
     | 
    
         
            +
                    @api_version = version
         
     | 
| 
      
 34 
     | 
    
         
            +
                  elsif code == 401
         
     | 
| 
      
 35 
     | 
    
         
            +
                    code = init_auth(version)
         
     | 
| 
      
 36 
     | 
    
         
            +
                    if code == 200
         
     | 
| 
      
 37 
     | 
    
         
            +
                      @api_version = version
         
     | 
| 
      
 38 
     | 
    
         
            +
                    end
         
     | 
| 
      
 39 
     | 
    
         
            +
                  end
         
     | 
| 
      
 40 
     | 
    
         
            +
                  return code
         
     | 
| 
      
 41 
     | 
    
         
            +
                end
         
     | 
| 
      
 42 
     | 
    
         
            +
                
         
     | 
| 
      
 43 
     | 
    
         
            +
                def init_auth(api_version)
         
     | 
| 
      
 44 
     | 
    
         
            +
                  @http_auth = DockerHttpAuth.new(docker_uri.registry)
         
     | 
| 
      
 45 
     | 
    
         
            +
                  if api_version == 'v2'
         
     | 
| 
      
 46 
     | 
    
         
            +
                    code = APICall.new(ping_v2_uri).response_code(http_auth)
         
     | 
| 
      
 47 
     | 
    
         
            +
                  elsif api_version == 'v1'
         
     | 
| 
      
 48 
     | 
    
         
            +
                    code = APICall.new(ping_v1_uri).response_code(http_auth)
         
     | 
| 
      
 49 
     | 
    
         
            +
                  end
         
     | 
| 
      
 50 
     | 
    
         
            +
                end
         
     | 
| 
      
 51 
     | 
    
         
            +
                
         
     | 
| 
      
 52 
     | 
    
         
            +
                def tags_v1
         
     | 
| 
      
 53 
     | 
    
         
            +
                  APICall.new(tags_v1_uri).get_json(http_auth)
         
     | 
| 
      
 54 
     | 
    
         
            +
                end
         
     | 
| 
      
 55 
     | 
    
         
            +
                
         
     | 
| 
      
 56 
     | 
    
         
            +
                def tags_v2
         
     | 
| 
      
 57 
     | 
    
         
            +
                  APICall.new(tags_v2_uri).get_json(http_auth)
         
     | 
| 
      
 58 
     | 
    
         
            +
                end
         
     | 
| 
      
 59 
     | 
    
         
            +
                
         
     | 
| 
      
 60 
     | 
    
         
            +
                def hash_v2(tag)
         
     | 
| 
      
 61 
     | 
    
         
            +
                  APICall.new(hash_v2_uri(tag)).get_json(http_auth)
         
     | 
| 
      
 62 
     | 
    
         
            +
                end
         
     | 
| 
      
 63 
     | 
    
         
            +
                
         
     | 
| 
      
 64 
     | 
    
         
            +
                def catalog_v2
         
     | 
| 
      
 65 
     | 
    
         
            +
                  APICall.new(catalog_v2_uri).get_json(http_auth)
         
     | 
| 
      
 66 
     | 
    
         
            +
                end
         
     | 
| 
      
 67 
     | 
    
         
            +
                
         
     | 
| 
      
 68 
     | 
    
         
            +
                def search_v1(keyword)
         
     | 
| 
      
 69 
     | 
    
         
            +
                  APICall.new(search_v1_uri(keyword)).get_json(http_auth)
         
     | 
| 
      
 70 
     | 
    
         
            +
                end
         
     | 
| 
      
 71 
     | 
    
         
            +
                
         
     | 
| 
      
 72 
     | 
    
         
            +
                def base_uri
         
     | 
| 
      
 73 
     | 
    
         
            +
                  "#{docker_uri.protocol}#{docker_uri.registry}"
         
     | 
| 
      
 74 
     | 
    
         
            +
                end
         
     | 
| 
      
 75 
     | 
    
         
            +
                
         
     | 
| 
      
 76 
     | 
    
         
            +
                def ping_uri(version)
         
     | 
| 
      
 77 
     | 
    
         
            +
                  if version == 'v1'
         
     | 
| 
      
 78 
     | 
    
         
            +
                    ping_v1_uri
         
     | 
| 
      
 79 
     | 
    
         
            +
                  elsif version == 'v2'
         
     | 
| 
      
 80 
     | 
    
         
            +
                    ping_v2_uri
         
     | 
| 
      
 81 
     | 
    
         
            +
                  end
         
     | 
| 
      
 82 
     | 
    
         
            +
                end
         
     | 
| 
      
 83 
     | 
    
         
            +
                
         
     | 
| 
      
 84 
     | 
    
         
            +
                def ping_v2_uri
         
     | 
| 
      
 85 
     | 
    
         
            +
                  "#{base_uri}/v2/"
         
     | 
| 
      
 86 
     | 
    
         
            +
                end
         
     | 
| 
      
 87 
     | 
    
         
            +
                
         
     | 
| 
      
 88 
     | 
    
         
            +
                def ping_v1_uri
         
     | 
| 
      
 89 
     | 
    
         
            +
                  "#{base_uri}/v1/_ping"
         
     | 
| 
      
 90 
     | 
    
         
            +
                end
         
     | 
| 
      
 91 
     | 
    
         
            +
                
         
     | 
| 
      
 92 
     | 
    
         
            +
                def catalog_v2_uri
         
     | 
| 
      
 93 
     | 
    
         
            +
                  "#{base_uri}/v2/_catalog"
         
     | 
| 
      
 94 
     | 
    
         
            +
                end
         
     | 
| 
      
 95 
     | 
    
         
            +
                
         
     | 
| 
      
 96 
     | 
    
         
            +
                def search_v1_uri(keyword)
         
     | 
| 
      
 97 
     | 
    
         
            +
                  "#{base_uri}/v1/search?q=#{keyword}"  
         
     | 
| 
      
 98 
     | 
    
         
            +
                end
         
     | 
| 
      
 99 
     | 
    
         
            +
                
         
     | 
| 
      
 100 
     | 
    
         
            +
                def tags_v1_uri
         
     | 
| 
      
 101 
     | 
    
         
            +
                  "#{base_uri}/v1/repositories/#{docker_uri.repository}/tags"
         
     | 
| 
      
 102 
     | 
    
         
            +
                end
         
     | 
| 
      
 103 
     | 
    
         
            +
                
         
     | 
| 
      
 104 
     | 
    
         
            +
                def tags_v2_uri
         
     | 
| 
      
 105 
     | 
    
         
            +
                  "#{base_uri}/v2/#{docker_uri.repository}/tags/list"  
         
     | 
| 
      
 106 
     | 
    
         
            +
                end
         
     | 
| 
      
 107 
     | 
    
         
            +
                
         
     | 
| 
      
 108 
     | 
    
         
            +
                def hash_v2_uri(tag)
         
     | 
| 
      
 109 
     | 
    
         
            +
                  "#{base_uri}/v2/#{docker_uri.repository}/manifests/#{tag}"
         
     | 
| 
      
 110 
     | 
    
         
            +
                end
         
     | 
| 
      
 111 
     | 
    
         
            +
                
         
     | 
| 
      
 112 
     | 
    
         
            +
              end
         
     | 
| 
      
 113 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,31 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'json'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'base64'
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            module Tagfish
         
     | 
| 
      
 5 
     | 
    
         
            +
              class DockerHttpAuth
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
                attr_accessor :username
         
     | 
| 
      
 8 
     | 
    
         
            +
                attr_accessor :password
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                def initialize(registry)
         
     | 
| 
      
 11 
     | 
    
         
            +
                   file_path = '~/.docker/config.json'
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                   begin
         
     | 
| 
      
 14 
     | 
    
         
            +
                     config = File.open(File.expand_path(file_path), 'r')
         
     | 
| 
      
 15 
     | 
    
         
            +
                   rescue Exception => e
         
     | 
| 
      
 16 
     | 
    
         
            +
                     abort("Tried to get a SLiP but the file #{file_path} does not exist")
         
     | 
| 
      
 17 
     | 
    
         
            +
                   end
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                   json_config = JSON.parse(config.read())
         
     | 
| 
      
 20 
     | 
    
         
            +
                   config.close()
         
     | 
| 
      
 21 
     | 
    
         
            +
                   if json_config['auths'].length == 0
         
     | 
| 
      
 22 
     | 
    
         
            +
                     @username, @password = nil, nil 
         
     | 
| 
      
 23 
     | 
    
         
            +
                   else
         
     | 
| 
      
 24 
     | 
    
         
            +
                     b64_auth = json_config['auths'][registry]['auth']
         
     | 
| 
      
 25 
     | 
    
         
            +
                     auth = Base64.decode64(b64_auth)
         
     | 
| 
      
 26 
     | 
    
         
            +
                     @username, @password = auth.split(':')
         
     | 
| 
      
 27 
     | 
    
         
            +
                   end
         
     | 
| 
      
 28 
     | 
    
         
            +
                end
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
              end
         
     | 
| 
      
 31 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,64 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'tagfish/docker_http_auth'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'tagfish/docker_api'
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            module Tagfish
         
     | 
| 
      
 5 
     | 
    
         
            +
              class DockerURI
         
     | 
| 
      
 6 
     | 
    
         
            +
                URI_PARSER = %r{
         
     | 
| 
      
 7 
     | 
    
         
            +
                  (https?:\/\/)?                # Optional protocol
         
     | 
| 
      
 8 
     | 
    
         
            +
                  (?:([\w.\-]+\.[\w.\-]+)\/)?   # Optional registry
         
     | 
| 
      
 9 
     | 
    
         
            +
                  ([\w\-]*\/?[\w\-.]+)          # Optional namespace, mandatory repository
         
     | 
| 
      
 10 
     | 
    
         
            +
                  :?                            # Optional delimiter between repository and tag
         
     | 
| 
      
 11 
     | 
    
         
            +
                  ([\w.\-]+)?                   # Optional tag
         
     | 
| 
      
 12 
     | 
    
         
            +
                }x
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                def self.parse(docker_string)
         
     | 
| 
      
 15 
     | 
    
         
            +
                  match = docker_string.match(URI_PARSER)
         
     | 
| 
      
 16 
     | 
    
         
            +
                  new(*match.captures)
         
     | 
| 
      
 17 
     | 
    
         
            +
                end
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                attr_accessor :protocol
         
     | 
| 
      
 20 
     | 
    
         
            +
                attr_accessor :registry
         
     | 
| 
      
 21 
     | 
    
         
            +
                attr_accessor :repository
         
     | 
| 
      
 22 
     | 
    
         
            +
                attr_accessor :tag
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                def initialize(protocol, registry, repository, tag)
         
     | 
| 
      
 25 
     | 
    
         
            +
                  @protocol = protocol
         
     | 
| 
      
 26 
     | 
    
         
            +
                  @registry = registry
         
     | 
| 
      
 27 
     | 
    
         
            +
                  @repository = repository
         
     | 
| 
      
 28 
     | 
    
         
            +
                  @tag = tag
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                  if registry.nil?
         
     | 
| 
      
 31 
     | 
    
         
            +
                    @protocol = "https://"
         
     | 
| 
      
 32 
     | 
    
         
            +
                    @registry = "index.docker.io"
         
     | 
| 
      
 33 
     | 
    
         
            +
                  elsif protocol.nil?
         
     | 
| 
      
 34 
     | 
    
         
            +
                    @protocol = "https://"
         
     | 
| 
      
 35 
     | 
    
         
            +
                  end
         
     | 
| 
      
 36 
     | 
    
         
            +
                end
         
     | 
| 
      
 37 
     | 
    
         
            +
                
         
     | 
| 
      
 38 
     | 
    
         
            +
                def repo_and_tag
         
     | 
| 
      
 39 
     | 
    
         
            +
                  tag.nil? ? "#{repository}" : "#{repository}:#{tag}"
         
     | 
| 
      
 40 
     | 
    
         
            +
                end
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
                def tag?
         
     | 
| 
      
 43 
     | 
    
         
            +
                  not tag.nil?
         
     | 
| 
      
 44 
     | 
    
         
            +
                end
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
                def tagged_latest?
         
     | 
| 
      
 47 
     | 
    
         
            +
                  tag == 'latest'
         
     | 
| 
      
 48 
     | 
    
         
            +
                end
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
                def with_tag(new_tag)
         
     | 
| 
      
 51 
     | 
    
         
            +
                  self.class.new(protocol, registry, repository, new_tag)
         
     | 
| 
      
 52 
     | 
    
         
            +
                end
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
                def to_s
         
     | 
| 
      
 55 
     | 
    
         
            +
                  reg_sep = registry.nil? ? nil : "/"
         
     | 
| 
      
 56 
     | 
    
         
            +
                  tag_sep = tag.nil? ? nil : ":"
         
     | 
| 
      
 57 
     | 
    
         
            +
                  if registry == "index.docker.io"
         
     | 
| 
      
 58 
     | 
    
         
            +
                    "#{repository}#{tag_sep}#{tag}"
         
     | 
| 
      
 59 
     | 
    
         
            +
                  else
         
     | 
| 
      
 60 
     | 
    
         
            +
                    "#{registry}#{reg_sep}#{repository}#{tag_sep}#{tag}"
         
     | 
| 
      
 61 
     | 
    
         
            +
                  end
         
     | 
| 
      
 62 
     | 
    
         
            +
                end
         
     | 
| 
      
 63 
     | 
    
         
            +
              end
         
     | 
| 
      
 64 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,32 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'tagfish/docker_uri'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Tagfish
         
     | 
| 
      
 4 
     | 
    
         
            +
              class SearchCommand < Clamp::Command
         
     | 
| 
      
 5 
     | 
    
         
            +
                parameter "[KEYWORD]", "object to search"
         
     | 
| 
      
 6 
     | 
    
         
            +
                option ["-r", "--registry"], "REGISTRY", "Docker registry", :default => "index.docker.io"
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                def execute
         
     | 
| 
      
 9 
     | 
    
         
            +
                  if not registry and not keyword
         
     | 
| 
      
 10 
     | 
    
         
            +
                    abort("You need to specify a REGISTRY and/or a KEYWORD")
         
     | 
| 
      
 11 
     | 
    
         
            +
                  end
         
     | 
| 
      
 12 
     | 
    
         
            +
                  
         
     | 
| 
      
 13 
     | 
    
         
            +
                  docker_uri = DockerURI.parse(registry + "/" + "dummy")
         
     | 
| 
      
 14 
     | 
    
         
            +
                  docker_api = DockerAPI.new(docker_uri)
         
     | 
| 
      
 15 
     | 
    
         
            +
                  
         
     | 
| 
      
 16 
     | 
    
         
            +
                  if docker_api.api_version == 'v2'
         
     | 
| 
      
 17 
     | 
    
         
            +
                    repos = docker_api.catalog_v2["repositories"]
         
     | 
| 
      
 18 
     | 
    
         
            +
                    if keyword
         
     | 
| 
      
 19 
     | 
    
         
            +
                      repos.select! {|repo| repo.include? keyword}
         
     | 
| 
      
 20 
     | 
    
         
            +
                    end
         
     | 
| 
      
 21 
     | 
    
         
            +
                    repos.each {|repo| puts "#{docker_uri.registry}/#{repo}"} 
         
     | 
| 
      
 22 
     | 
    
         
            +
                  else # 'v1'
         
     | 
| 
      
 23 
     | 
    
         
            +
                    if not keyword
         
     | 
| 
      
 24 
     | 
    
         
            +
                      abort("You need to specify a keyword to search a Registry V1")
         
     | 
| 
      
 25 
     | 
    
         
            +
                    end
         
     | 
| 
      
 26 
     | 
    
         
            +
                    repos_raw = docker_api.search_v1(keyword)
         
     | 
| 
      
 27 
     | 
    
         
            +
                    repos = repos_raw["results"].map {|result| result["name"]}
         
     | 
| 
      
 28 
     | 
    
         
            +
                    puts repos
         
     | 
| 
      
 29 
     | 
    
         
            +
                  end
         
     | 
| 
      
 30 
     | 
    
         
            +
                end
         
     | 
| 
      
 31 
     | 
    
         
            +
              end
         
     | 
| 
      
 32 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/tagfish/tags.rb
    ADDED
    
    | 
         @@ -0,0 +1,26 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'net/http'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'json'
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            module Tagfish
         
     | 
| 
      
 5 
     | 
    
         
            +
              class Tags
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
                def initialize(tags)
         
     | 
| 
      
 8 
     | 
    
         
            +
                  @tags = tags
         
     | 
| 
      
 9 
     | 
    
         
            +
                end
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                def tag_names
         
     | 
| 
      
 12 
     | 
    
         
            +
                  @tags.keys.sort
         
     | 
| 
      
 13 
     | 
    
         
            +
                end
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                def latest_tag
         
     | 
| 
      
 16 
     | 
    
         
            +
                  tag_names.select do |tag_name|
         
     | 
| 
      
 17 
     | 
    
         
            +
                    (@tags[tag_name] == @tags["latest"]) && (tag_name != 'latest')
         
     | 
| 
      
 18 
     | 
    
         
            +
                  end
         
     | 
| 
      
 19 
     | 
    
         
            +
                end
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                def latest_tag_to_s
         
     | 
| 
      
 22 
     | 
    
         
            +
                  latest_tag.empty? ? nil : latest_tag[0]
         
     | 
| 
      
 23 
     | 
    
         
            +
                end
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
              end
         
     | 
| 
      
 26 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,37 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require "tagfish/tags_logic"
         
     | 
| 
      
 2 
     | 
    
         
            +
            require "tagfish/docker_uri"
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            module Tagfish
         
     | 
| 
      
 5 
     | 
    
         
            +
              class TagsCommand < Clamp::Command
         
     | 
| 
      
 6 
     | 
    
         
            +
                parameter "REPOSITORY", "docker repository"
         
     | 
| 
      
 7 
     | 
    
         
            +
                option ["-l", "--latest"], :flag, "only return latest explicitly tagged image"
         
     | 
| 
      
 8 
     | 
    
         
            +
                option ["-s", "--short"], :flag, "only return tag, not full image path"
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                def execute
         
     | 
| 
      
 11 
     | 
    
         
            +
                  tags_only = latest? ? false : true
         
     | 
| 
      
 12 
     | 
    
         
            +
                  
         
     | 
| 
      
 13 
     | 
    
         
            +
                  docker_uri = DockerURI.parse(repository)
         
     | 
| 
      
 14 
     | 
    
         
            +
                  docker_api = DockerAPI.new(docker_uri)
         
     | 
| 
      
 15 
     | 
    
         
            +
                  tags = TagsLogic.find_tags_by_repository(docker_api, tags_only)
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                  begin
         
     | 
| 
      
 18 
     | 
    
         
            +
                   tags_found = latest? ? tags.latest_tag : tags.tag_names
         
     | 
| 
      
 19 
     | 
    
         
            +
                  rescue Exception => e
         
     | 
| 
      
 20 
     | 
    
         
            +
                    puts e.message
         
     | 
| 
      
 21 
     | 
    
         
            +
                    return
         
     | 
| 
      
 22 
     | 
    
         
            +
                  end
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                  if tags_found.size == 0
         
     | 
| 
      
 25 
     | 
    
         
            +
                    puts "ERROR: No image explicitly tagged in this Repository, " +
         
     | 
| 
      
 26 
     | 
    
         
            +
                            "only `latest` tag available."
         
     | 
| 
      
 27 
     | 
    
         
            +
                    return
         
     | 
| 
      
 28 
     | 
    
         
            +
                  end
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                  pretty_tags = tags_found.map do |tag_name|
         
     | 
| 
      
 31 
     | 
    
         
            +
                    short? ? tag_name : docker_uri.with_tag(tag_name).to_s
         
     | 
| 
      
 32 
     | 
    
         
            +
                  end
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
                  puts pretty_tags
         
     | 
| 
      
 35 
     | 
    
         
            +
                end
         
     | 
| 
      
 36 
     | 
    
         
            +
              end
         
     | 
| 
      
 37 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,52 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'json'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'tagfish/tags'
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            module Tagfish
         
     | 
| 
      
 5 
     | 
    
         
            +
              class TagsLogic
         
     | 
| 
      
 6 
     | 
    
         
            +
                def self.find_tags_by_repository(docker_api, tags_only=false)
         
     | 
| 
      
 7 
     | 
    
         
            +
                  if docker_api.api_version == 'v2'
         
     | 
| 
      
 8 
     | 
    
         
            +
                    tags_list = tags_v2(docker_api, tags_only)
         
     | 
| 
      
 9 
     | 
    
         
            +
                  else
         
     | 
| 
      
 10 
     | 
    
         
            +
                    tags_list = tags_v1(docker_api)
         
     | 
| 
      
 11 
     | 
    
         
            +
                  end
         
     | 
| 
      
 12 
     | 
    
         
            +
                  Tagfish::Tags.new(tags_list)
         
     | 
| 
      
 13 
     | 
    
         
            +
                end
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                private
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                def self.tags_v1(docker_api)
         
     | 
| 
      
 18 
     | 
    
         
            +
                  tags_json = docker_api.tags_v1
         
     | 
| 
      
 19 
     | 
    
         
            +
                  tags_v1_api(tags_json)
         
     | 
| 
      
 20 
     | 
    
         
            +
                end
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                def self.tags_v1_api(api_response_data)
         
     | 
| 
      
 23 
     | 
    
         
            +
                  case api_response_data
         
     | 
| 
      
 24 
     | 
    
         
            +
                  when Hash
         
     | 
| 
      
 25 
     | 
    
         
            +
                    api_response_data
         
     | 
| 
      
 26 
     | 
    
         
            +
                  when Array
         
     | 
| 
      
 27 
     | 
    
         
            +
                    api_response_data.reduce({}) do |images, tag|
         
     | 
| 
      
 28 
     | 
    
         
            +
                      images.merge({tag["name"] => tag["layer"]})
         
     | 
| 
      
 29 
     | 
    
         
            +
                    end
         
     | 
| 
      
 30 
     | 
    
         
            +
                  else
         
     | 
| 
      
 31 
     | 
    
         
            +
                    raise "unexpected type #{api_response_data.class}"
         
     | 
| 
      
 32 
     | 
    
         
            +
                  end
         
     | 
| 
      
 33 
     | 
    
         
            +
                end
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
                def self.tags_v2(docker_api, tags_only)
         
     | 
| 
      
 36 
     | 
    
         
            +
                  tags = docker_api.tags_v2["tags"]
         
     | 
| 
      
 37 
     | 
    
         
            +
                  if tags.nil?
         
     | 
| 
      
 38 
     | 
    
         
            +
                    abort("No Tags found for this repository")
         
     | 
| 
      
 39 
     | 
    
         
            +
                  end
         
     | 
| 
      
 40 
     | 
    
         
            +
                  
         
     | 
| 
      
 41 
     | 
    
         
            +
                  tags_with_hashes = tags.inject({}) do |dict, tag|
         
     | 
| 
      
 42 
     | 
    
         
            +
                    if tags_only
         
     | 
| 
      
 43 
     | 
    
         
            +
                      dict[tag] = "dummy_hash"
         
     | 
| 
      
 44 
     | 
    
         
            +
                    else
         
     | 
| 
      
 45 
     | 
    
         
            +
                      dict[tag] = docker_api.hash_v2(tag)["fsLayers"][0]["blobSum"]
         
     | 
| 
      
 46 
     | 
    
         
            +
                    end
         
     | 
| 
      
 47 
     | 
    
         
            +
                    dict
         
     | 
| 
      
 48 
     | 
    
         
            +
                  end
         
     | 
| 
      
 49 
     | 
    
         
            +
                end
         
     | 
| 
      
 50 
     | 
    
         
            +
                
         
     | 
| 
      
 51 
     | 
    
         
            +
              end
         
     | 
| 
      
 52 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,37 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Tagfish
         
     | 
| 
      
 2 
     | 
    
         
            +
              class Tokeniser
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
                class Text < String
         
     | 
| 
      
 5 
     | 
    
         
            +
                  def is_a_uri_token?
         
     | 
| 
      
 6 
     | 
    
         
            +
                    false
         
     | 
| 
      
 7 
     | 
    
         
            +
                  end
         
     | 
| 
      
 8 
     | 
    
         
            +
                end
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                class URI < String
         
     | 
| 
      
 11 
     | 
    
         
            +
                  def is_a_uri_token?
         
     | 
| 
      
 12 
     | 
    
         
            +
                    true
         
     | 
| 
      
 13 
     | 
    
         
            +
                  end
         
     | 
| 
      
 14 
     | 
    
         
            +
                end
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
                def self.tokenise(rest)
         
     | 
| 
      
 17 
     | 
    
         
            +
                  tokens = []
         
     | 
| 
      
 18 
     | 
    
         
            +
                  while true
         
     | 
| 
      
 19 
     | 
    
         
            +
                    match = rest.match /[\w\/:.-]+\/[\w.-]+:[\w.-]+/
         
     | 
| 
      
 20 
     | 
    
         
            +
                    if match.nil?
         
     | 
| 
      
 21 
     | 
    
         
            +
                      tokens << Text.new(rest)
         
     | 
| 
      
 22 
     | 
    
         
            +
                      break
         
     | 
| 
      
 23 
     | 
    
         
            +
                    else
         
     | 
| 
      
 24 
     | 
    
         
            +
                      tokens << Text.new(match.pre_match)
         
     | 
| 
      
 25 
     | 
    
         
            +
                      tokens << URI.new(match.to_s)
         
     | 
| 
      
 26 
     | 
    
         
            +
                      rest = match.post_match
         
     | 
| 
      
 27 
     | 
    
         
            +
                    end
         
     | 
| 
      
 28 
     | 
    
         
            +
                  end
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                  tokens
         
     | 
| 
      
 31 
     | 
    
         
            +
                end
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                def self.dump(tokens)
         
     | 
| 
      
 34 
     | 
    
         
            +
                  tokens.join('')
         
     | 
| 
      
 35 
     | 
    
         
            +
                end
         
     | 
| 
      
 36 
     | 
    
         
            +
              end
         
     | 
| 
      
 37 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,13 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'diffy'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Tagfish
         
     | 
| 
      
 4 
     | 
    
         
            +
              module Update
         
     | 
| 
      
 5 
     | 
    
         
            +
                class Differ
         
     | 
| 
      
 6 
     | 
    
         
            +
                  def self.diff(original_string, updated_string)
         
     | 
| 
      
 7 
     | 
    
         
            +
                    diffy_diff = Diffy::Diff.new(original_string, updated_string, context: 2)
         
     | 
| 
      
 8 
     | 
    
         
            +
                    colour_diff = diffy_diff.to_s(:color).chomp
         
     | 
| 
      
 9 
     | 
    
         
            +
                    colour_diff.empty? ? "Nothing to update here" : colour_diff
         
     | 
| 
      
 10 
     | 
    
         
            +
                  end
         
     | 
| 
      
 11 
     | 
    
         
            +
                end
         
     | 
| 
      
 12 
     | 
    
         
            +
              end
         
     | 
| 
      
 13 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,31 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'tagfish/update/updater'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'tagfish/update/differ'
         
     | 
| 
      
 3 
     | 
    
         
            +
            require 'tagfish/update/uri_filters'
         
     | 
| 
      
 4 
     | 
    
         
            +
            require 'tagfish/tokeniser'
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            module Tagfish
         
     | 
| 
      
 7 
     | 
    
         
            +
              module Update
         
     | 
| 
      
 8 
     | 
    
         
            +
                class UpdateCommand < Clamp::Command
         
     | 
| 
      
 9 
     | 
    
         
            +
                  parameter "FILE", "file to update"
         
     | 
| 
      
 10 
     | 
    
         
            +
                  option ["-d", "--dry-run"], :flag, "enable dry run"
         
     | 
| 
      
 11 
     | 
    
         
            +
                  option "--only", "PATTERN", "Only update repositories matching pattern. Wildcards (*) may be used."
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                  def execute
         
     | 
| 
      
 14 
     | 
    
         
            +
                    filters = [
         
     | 
| 
      
 15 
     | 
    
         
            +
                      URIFilters.must_be_tagged,
         
     | 
| 
      
 16 
     | 
    
         
            +
                      URIFilters.must_not_be_tagged_latest,
         
     | 
| 
      
 17 
     | 
    
         
            +
                      URIFilters.must_match_repository(only)
         
     | 
| 
      
 18 
     | 
    
         
            +
                    ]
         
     | 
| 
      
 19 
     | 
    
         
            +
                    updater = Updater.new(filters)
         
     | 
| 
      
 20 
     | 
    
         
            +
                    original = File.read(file)
         
     | 
| 
      
 21 
     | 
    
         
            +
                    updated = Tokeniser.dump(updater.update(Tokeniser.tokenise(original)))
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                    puts Differ.diff(original, updated)
         
     | 
| 
      
 24 
     | 
    
         
            +
                    
         
     | 
| 
      
 25 
     | 
    
         
            +
                    if not dry_run? 
         
     | 
| 
      
 26 
     | 
    
         
            +
                      File.write(file, updated)
         
     | 
| 
      
 27 
     | 
    
         
            +
                    end
         
     | 
| 
      
 28 
     | 
    
         
            +
                  end
         
     | 
| 
      
 29 
     | 
    
         
            +
                end
         
     | 
| 
      
 30 
     | 
    
         
            +
              end
         
     | 
| 
      
 31 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,53 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'tagfish/tokeniser'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'tagfish/docker_uri'
         
     | 
| 
      
 3 
     | 
    
         
            +
            require 'tagfish/tags_logic'
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            module Tagfish
         
     | 
| 
      
 6 
     | 
    
         
            +
              module Update
         
     | 
| 
      
 7 
     | 
    
         
            +
                class Updater
         
     | 
| 
      
 8 
     | 
    
         
            +
                  def initialize(filters)
         
     | 
| 
      
 9 
     | 
    
         
            +
                    @filters = filters
         
     | 
| 
      
 10 
     | 
    
         
            +
                  end
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                  def update(tokens)
         
     | 
| 
      
 13 
     | 
    
         
            +
                    tokens.map do |token|
         
     | 
| 
      
 14 
     | 
    
         
            +
                      if token.is_a_uri_token?
         
     | 
| 
      
 15 
     | 
    
         
            +
                        update_uri_token(token)
         
     | 
| 
      
 16 
     | 
    
         
            +
                      else
         
     | 
| 
      
 17 
     | 
    
         
            +
                        token
         
     | 
| 
      
 18 
     | 
    
         
            +
                      end
         
     | 
| 
      
 19 
     | 
    
         
            +
                    end
         
     | 
| 
      
 20 
     | 
    
         
            +
                  end
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                  private
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                  def update_uri_token(token)
         
     | 
| 
      
 25 
     | 
    
         
            +
                    original_uri = DockerURI.parse(token)
         
     | 
| 
      
 26 
     | 
    
         
            +
                    if updatable?(original_uri)
         
     | 
| 
      
 27 
     | 
    
         
            +
                      updated_uri = update_uri(original_uri)
         
     | 
| 
      
 28 
     | 
    
         
            +
                      Tokeniser::URI.new(updated_uri.to_s)
         
     | 
| 
      
 29 
     | 
    
         
            +
                    else
         
     | 
| 
      
 30 
     | 
    
         
            +
                      token
         
     | 
| 
      
 31 
     | 
    
         
            +
                    end
         
     | 
| 
      
 32 
     | 
    
         
            +
                  end
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
                  def updatable?(uri)
         
     | 
| 
      
 35 
     | 
    
         
            +
                    @filters.all? do |filter|
         
     | 
| 
      
 36 
     | 
    
         
            +
                      filter.call uri
         
     | 
| 
      
 37 
     | 
    
         
            +
                    end
         
     | 
| 
      
 38 
     | 
    
         
            +
                  end
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
                  def update_uri(docker_uri)
         
     | 
| 
      
 41 
     | 
    
         
            +
                    docker_api = DockerAPI.new(docker_uri)
         
     | 
| 
      
 42 
     | 
    
         
            +
                    tags = TagsLogic.find_tags_by_repository(docker_api)
         
     | 
| 
      
 43 
     | 
    
         
            +
                    newest_tag_name = tags.latest_tag_to_s
         
     | 
| 
      
 44 
     | 
    
         
            +
                    if newest_tag_name.nil?
         
     | 
| 
      
 45 
     | 
    
         
            +
                      docker_uri
         
     | 
| 
      
 46 
     | 
    
         
            +
                    else
         
     | 
| 
      
 47 
     | 
    
         
            +
                      docker_uri.with_tag(newest_tag_name)
         
     | 
| 
      
 48 
     | 
    
         
            +
                    end
         
     | 
| 
      
 49 
     | 
    
         
            +
                  end
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
                end
         
     | 
| 
      
 52 
     | 
    
         
            +
              end
         
     | 
| 
      
 53 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,20 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Tagfish
         
     | 
| 
      
 2 
     | 
    
         
            +
              module Update
         
     | 
| 
      
 3 
     | 
    
         
            +
                class URIFilters
         
     | 
| 
      
 4 
     | 
    
         
            +
                  def self.must_be_tagged
         
     | 
| 
      
 5 
     | 
    
         
            +
                    lambda do |uri| uri.tag? end
         
     | 
| 
      
 6 
     | 
    
         
            +
                  end
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                  def self.must_not_be_tagged_latest
         
     | 
| 
      
 9 
     | 
    
         
            +
                    lambda do |uri| not uri.tagged_latest? end
         
     | 
| 
      
 10 
     | 
    
         
            +
                  end
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                  def self.must_match_repository(pattern)
         
     | 
| 
      
 13 
     | 
    
         
            +
                    starts_with_pattern = "#{pattern}*"
         
     | 
| 
      
 14 
     | 
    
         
            +
                    lambda do |uri| 
         
     | 
| 
      
 15 
     | 
    
         
            +
                      File.fnmatch(starts_with_pattern, uri.with_tag(nil).to_s)
         
     | 
| 
      
 16 
     | 
    
         
            +
                    end
         
     | 
| 
      
 17 
     | 
    
         
            +
                  end
         
     | 
| 
      
 18 
     | 
    
         
            +
                end
         
     | 
| 
      
 19 
     | 
    
         
            +
              end
         
     | 
| 
      
 20 
     | 
    
         
            +
            end
         
     | 
    
        data/logo.jpg
    ADDED
    
    | 
         Binary file 
     | 
    
        data/tagfish.gemspec
    ADDED
    
    | 
         @@ -0,0 +1,27 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # coding: utf-8
         
     | 
| 
      
 2 
     | 
    
         
            +
            lib = File.expand_path('../lib', __FILE__)
         
     | 
| 
      
 3 
     | 
    
         
            +
            $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
         
     | 
| 
      
 4 
     | 
    
         
            +
            require 'tagfish/version'
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            Gem::Specification.new do |spec|
         
     | 
| 
      
 7 
     | 
    
         
            +
              spec.name          = "tagfish"
         
     | 
| 
      
 8 
     | 
    
         
            +
              spec.version       = Tagfish::VERSION
         
     | 
| 
      
 9 
     | 
    
         
            +
              spec.authors       = ["Clement Labbe"]
         
     | 
| 
      
 10 
     | 
    
         
            +
              spec.email         = ["clement.labbe@rea-group.com"]
         
     | 
| 
      
 11 
     | 
    
         
            +
              spec.summary       = %q{Command line utility for docker registries}
         
     | 
| 
      
 12 
     | 
    
         
            +
              spec.description   = "Retrieve repository tags, update dockerfiles, and more!"
         
     | 
| 
      
 13 
     | 
    
         
            +
              spec.homepage      = "https://github.com/realestate-com-au/tagfish"
         
     | 
| 
      
 14 
     | 
    
         
            +
              spec.license       = "MIT"
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
              spec.files         = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
         
     | 
| 
      
 17 
     | 
    
         
            +
              spec.bindir        = "bin"
         
     | 
| 
      
 18 
     | 
    
         
            +
              spec.executables   = ["tagfish"]
         
     | 
| 
      
 19 
     | 
    
         
            +
              spec.require_paths = ["lib"]
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
              spec.add_development_dependency "bundler", "~> 1.10"
         
     | 
| 
      
 22 
     | 
    
         
            +
              spec.add_development_dependency "rake", "~> 10.0"
         
     | 
| 
      
 23 
     | 
    
         
            +
              spec.add_development_dependency "rspec", "~> 3.3.0"
         
     | 
| 
      
 24 
     | 
    
         
            +
              spec.add_dependency "clamp", "~> 1.0.0"
         
     | 
| 
      
 25 
     | 
    
         
            +
              spec.add_dependency "diffy", "~> 3.0.0"
         
     | 
| 
      
 26 
     | 
    
         
            +
              spec.add_dependency "json", "~> 1.8.0"
         
     | 
| 
      
 27 
     | 
    
         
            +
            end
         
     | 
    
        metadata
    ADDED
    
    | 
         @@ -0,0 +1,152 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            --- !ruby/object:Gem::Specification
         
     | 
| 
      
 2 
     | 
    
         
            +
            name: tagfish
         
     | 
| 
      
 3 
     | 
    
         
            +
            version: !ruby/object:Gem::Version
         
     | 
| 
      
 4 
     | 
    
         
            +
              version: 1.0.1
         
     | 
| 
      
 5 
     | 
    
         
            +
            platform: ruby
         
     | 
| 
      
 6 
     | 
    
         
            +
            authors:
         
     | 
| 
      
 7 
     | 
    
         
            +
            - Clement Labbe
         
     | 
| 
      
 8 
     | 
    
         
            +
            autorequire: 
         
     | 
| 
      
 9 
     | 
    
         
            +
            bindir: bin
         
     | 
| 
      
 10 
     | 
    
         
            +
            cert_chain: []
         
     | 
| 
      
 11 
     | 
    
         
            +
            date: 2015-12-15 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.10'
         
     | 
| 
      
 20 
     | 
    
         
            +
              type: :development
         
     | 
| 
      
 21 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 22 
     | 
    
         
            +
              version_requirements: !ruby/object:Gem::Requirement
         
     | 
| 
      
 23 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 24 
     | 
    
         
            +
                - - "~>"
         
     | 
| 
      
 25 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 26 
     | 
    
         
            +
                    version: '1.10'
         
     | 
| 
      
 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.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.3.0
         
     | 
| 
      
 55 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency
         
     | 
| 
      
 56 
     | 
    
         
            +
              name: clamp
         
     | 
| 
      
 57 
     | 
    
         
            +
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
      
 58 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 59 
     | 
    
         
            +
                - - "~>"
         
     | 
| 
      
 60 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 61 
     | 
    
         
            +
                    version: 1.0.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.0
         
     | 
| 
      
 69 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency
         
     | 
| 
      
 70 
     | 
    
         
            +
              name: diffy
         
     | 
| 
      
 71 
     | 
    
         
            +
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
      
 72 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 73 
     | 
    
         
            +
                - - "~>"
         
     | 
| 
      
 74 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 75 
     | 
    
         
            +
                    version: 3.0.0
         
     | 
| 
      
 76 
     | 
    
         
            +
              type: :runtime
         
     | 
| 
      
 77 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 78 
     | 
    
         
            +
              version_requirements: !ruby/object:Gem::Requirement
         
     | 
| 
      
 79 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 80 
     | 
    
         
            +
                - - "~>"
         
     | 
| 
      
 81 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 82 
     | 
    
         
            +
                    version: 3.0.0
         
     | 
| 
      
 83 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency
         
     | 
| 
      
 84 
     | 
    
         
            +
              name: json
         
     | 
| 
      
 85 
     | 
    
         
            +
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
      
 86 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 87 
     | 
    
         
            +
                - - "~>"
         
     | 
| 
      
 88 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 89 
     | 
    
         
            +
                    version: 1.8.0
         
     | 
| 
      
 90 
     | 
    
         
            +
              type: :runtime
         
     | 
| 
      
 91 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 92 
     | 
    
         
            +
              version_requirements: !ruby/object:Gem::Requirement
         
     | 
| 
      
 93 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 94 
     | 
    
         
            +
                - - "~>"
         
     | 
| 
      
 95 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 96 
     | 
    
         
            +
                    version: 1.8.0
         
     | 
| 
      
 97 
     | 
    
         
            +
            description: Retrieve repository tags, update dockerfiles, and more!
         
     | 
| 
      
 98 
     | 
    
         
            +
            email:
         
     | 
| 
      
 99 
     | 
    
         
            +
            - clement.labbe@rea-group.com
         
     | 
| 
      
 100 
     | 
    
         
            +
            executables:
         
     | 
| 
      
 101 
     | 
    
         
            +
            - tagfish
         
     | 
| 
      
 102 
     | 
    
         
            +
            extensions: []
         
     | 
| 
      
 103 
     | 
    
         
            +
            extra_rdoc_files: []
         
     | 
| 
      
 104 
     | 
    
         
            +
            files:
         
     | 
| 
      
 105 
     | 
    
         
            +
            - ".gitignore"
         
     | 
| 
      
 106 
     | 
    
         
            +
            - Dockerfile
         
     | 
| 
      
 107 
     | 
    
         
            +
            - Gemfile
         
     | 
| 
      
 108 
     | 
    
         
            +
            - README.md
         
     | 
| 
      
 109 
     | 
    
         
            +
            - Rakefile
         
     | 
| 
      
 110 
     | 
    
         
            +
            - bin/tagfish
         
     | 
| 
      
 111 
     | 
    
         
            +
            - lib/tagfish.rb
         
     | 
| 
      
 112 
     | 
    
         
            +
            - lib/tagfish/api_call.rb
         
     | 
| 
      
 113 
     | 
    
         
            +
            - lib/tagfish/docker_api.rb
         
     | 
| 
      
 114 
     | 
    
         
            +
            - lib/tagfish/docker_http_auth.rb
         
     | 
| 
      
 115 
     | 
    
         
            +
            - lib/tagfish/docker_uri.rb
         
     | 
| 
      
 116 
     | 
    
         
            +
            - lib/tagfish/search_command.rb
         
     | 
| 
      
 117 
     | 
    
         
            +
            - lib/tagfish/tags.rb
         
     | 
| 
      
 118 
     | 
    
         
            +
            - lib/tagfish/tags_command.rb
         
     | 
| 
      
 119 
     | 
    
         
            +
            - lib/tagfish/tags_logic.rb
         
     | 
| 
      
 120 
     | 
    
         
            +
            - lib/tagfish/tokeniser.rb
         
     | 
| 
      
 121 
     | 
    
         
            +
            - lib/tagfish/update/differ.rb
         
     | 
| 
      
 122 
     | 
    
         
            +
            - lib/tagfish/update/update_command.rb
         
     | 
| 
      
 123 
     | 
    
         
            +
            - lib/tagfish/update/updater.rb
         
     | 
| 
      
 124 
     | 
    
         
            +
            - lib/tagfish/update/uri_filters.rb
         
     | 
| 
      
 125 
     | 
    
         
            +
            - lib/tagfish/version.rb
         
     | 
| 
      
 126 
     | 
    
         
            +
            - logo.jpg
         
     | 
| 
      
 127 
     | 
    
         
            +
            - tagfish.gemspec
         
     | 
| 
      
 128 
     | 
    
         
            +
            homepage: https://github.com/realestate-com-au/tagfish
         
     | 
| 
      
 129 
     | 
    
         
            +
            licenses:
         
     | 
| 
      
 130 
     | 
    
         
            +
            - MIT
         
     | 
| 
      
 131 
     | 
    
         
            +
            metadata: {}
         
     | 
| 
      
 132 
     | 
    
         
            +
            post_install_message: 
         
     | 
| 
      
 133 
     | 
    
         
            +
            rdoc_options: []
         
     | 
| 
      
 134 
     | 
    
         
            +
            require_paths:
         
     | 
| 
      
 135 
     | 
    
         
            +
            - lib
         
     | 
| 
      
 136 
     | 
    
         
            +
            required_ruby_version: !ruby/object:Gem::Requirement
         
     | 
| 
      
 137 
     | 
    
         
            +
              requirements:
         
     | 
| 
      
 138 
     | 
    
         
            +
              - - ">="
         
     | 
| 
      
 139 
     | 
    
         
            +
                - !ruby/object:Gem::Version
         
     | 
| 
      
 140 
     | 
    
         
            +
                  version: '0'
         
     | 
| 
      
 141 
     | 
    
         
            +
            required_rubygems_version: !ruby/object:Gem::Requirement
         
     | 
| 
      
 142 
     | 
    
         
            +
              requirements:
         
     | 
| 
      
 143 
     | 
    
         
            +
              - - ">="
         
     | 
| 
      
 144 
     | 
    
         
            +
                - !ruby/object:Gem::Version
         
     | 
| 
      
 145 
     | 
    
         
            +
                  version: '0'
         
     | 
| 
      
 146 
     | 
    
         
            +
            requirements: []
         
     | 
| 
      
 147 
     | 
    
         
            +
            rubyforge_project: 
         
     | 
| 
      
 148 
     | 
    
         
            +
            rubygems_version: 2.0.14
         
     | 
| 
      
 149 
     | 
    
         
            +
            signing_key: 
         
     | 
| 
      
 150 
     | 
    
         
            +
            specification_version: 4
         
     | 
| 
      
 151 
     | 
    
         
            +
            summary: Command line utility for docker registries
         
     | 
| 
      
 152 
     | 
    
         
            +
            test_files: []
         
     |