zt 0.1.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/.editorconfig +15 -0
- data/.env.example +1 -0
- data/.gitignore +31 -0
- data/.idea/codeStyles/Project.xml +52 -0
- data/.idea/codeStyles/codeStyleConfig.xml +5 -0
- data/.idea/dbnavigator.xml +454 -0
- data/.idea/inspectionProfiles/Project_Default.xml +13 -0
- data/.idea/markdown-exported-files.xml +8 -0
- data/.idea/markdown-navigator.xml +88 -0
- data/.idea/markdown-navigator/profiles_settings.xml +3 -0
- data/.idea/misc.xml +7 -0
- data/.idea/modules.xml +8 -0
- data/.idea/vcs.xml +6 -0
- data/.idea/workspace.xml +475 -0
- data/.idea/zt.iml +41 -0
- data/.rspec +3 -0
- data/.rubocop.yml +4457 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/.travis.yml +7 -0
- data/.versions.conf +4 -0
- data/CODE_OF_CONDUCT.md +75 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +103 -0
- data/Rakefile +6 -0
- data/bin/console +13 -0
- data/bin/setup +8 -0
- data/exe/zt +4 -0
- data/lib/zt.rb +14 -0
- data/lib/zt/cli.rb +91 -0
- data/lib/zt/conf.rb +97 -0
- data/lib/zt/constants.rb +46 -0
- data/lib/zt/errors.rb +3 -0
- data/lib/zt/errors/conf_errors.rb +26 -0
- data/lib/zt/exporters.rb +32 -0
- data/lib/zt/exporters/_base_exporter.rb +16 -0
- data/lib/zt/exporters/hosts_file_exporter.rb +32 -0
- data/lib/zt/importers.rb +28 -0
- data/lib/zt/importers/_base_importer.rb +44 -0
- data/lib/zt/importers/network_importer.rb +46 -0
- data/lib/zt/importers/node_importer.rb +54 -0
- data/lib/zt/remote_api.rb +39 -0
- data/lib/zt/version.rb +5 -0
- data/zt.gemspec +57 -0
- metadata +259 -0
    
        data/lib/zt/constants.rb
    ADDED
    
    | @@ -0,0 +1,46 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require 'xdg'
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            module Zt
         | 
| 6 | 
            +
              module Constants
         | 
| 7 | 
            +
                ALL_EXPORTERS = %w[
         | 
| 8 | 
            +
                  HostsFileExporter
         | 
| 9 | 
            +
                ].freeze
         | 
| 10 | 
            +
                ALL_IMPORTERS = %w[
         | 
| 11 | 
            +
                  NetworkImporter
         | 
| 12 | 
            +
                  NodeImporter
         | 
| 13 | 
            +
                ].freeze
         | 
| 14 | 
            +
                AUTH_TOKEN_LENGTH = 32
         | 
| 15 | 
            +
                AUTH_TOKEN_REGEX = /^[A-Za-z0-9]+$/.freeze
         | 
| 16 | 
            +
                CONF_DIR = "#{XDG['CONFIG_HOME']}/zt"
         | 
| 17 | 
            +
                CONF_SECTIONS = {
         | 
| 18 | 
            +
                  domains: 'domains.yaml',
         | 
| 19 | 
            +
                  networks: 'networks.yaml',
         | 
| 20 | 
            +
                  nodes: 'nodes.yaml',
         | 
| 21 | 
            +
                  zt: 'zt.conf.yaml'
         | 
| 22 | 
            +
                }.freeze
         | 
| 23 | 
            +
                # noinspection RubyStringKeysInHashInspection
         | 
| 24 | 
            +
                INITIAL_CONF = {
         | 
| 25 | 
            +
                  'nodes.yaml' => {
         | 
| 26 | 
            +
                    'node_id' => {
         | 
| 27 | 
            +
                      'hostname' => 'node-hostname',
         | 
| 28 | 
            +
                      'networks' => %w[network_id_1 network_id_2]
         | 
| 29 | 
            +
                    }
         | 
| 30 | 
            +
                  },
         | 
| 31 | 
            +
                  'networks.yaml' => {
         | 
| 32 | 
            +
                    'network_id' => {
         | 
| 33 | 
            +
                      'name' => 'network_name'
         | 
| 34 | 
            +
                    }
         | 
| 35 | 
            +
                  },
         | 
| 36 | 
            +
                  'domains.yaml' => {
         | 
| 37 | 
            +
                    'network_id' => 'domain-name.zt'
         | 
| 38 | 
            +
                  },
         | 
| 39 | 
            +
                  'zt.conf.yaml' => {
         | 
| 40 | 
            +
                    'manual_pulls' => false,
         | 
| 41 | 
            +
                    'token' => 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX',
         | 
| 42 | 
            +
                    'top_level_domain' => 'zt'
         | 
| 43 | 
            +
                  }
         | 
| 44 | 
            +
                }.freeze
         | 
| 45 | 
            +
              end
         | 
| 46 | 
            +
            end
         | 
    
        data/lib/zt/errors.rb
    ADDED
    
    
| @@ -0,0 +1,26 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Zt
         | 
| 4 | 
            +
              module Errors
         | 
| 5 | 
            +
                # Config does not exist on disk and cannot be created
         | 
| 6 | 
            +
                class ZtConfDiskError < StandardError
         | 
| 7 | 
            +
                  def initialize
         | 
| 8 | 
            +
                    super
         | 
| 9 | 
            +
                  end
         | 
| 10 | 
            +
                end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                # Config exists on disk but cannot be parsed
         | 
| 13 | 
            +
                class ZtConfSyntaxError < StandardError
         | 
| 14 | 
            +
                  def initialize
         | 
| 15 | 
            +
                    super
         | 
| 16 | 
            +
                  end
         | 
| 17 | 
            +
                end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                # Invalid section specifier for config
         | 
| 20 | 
            +
                class ZtConfInvalidSectionError < StandardError
         | 
| 21 | 
            +
                  def initialize
         | 
| 22 | 
            +
                    super
         | 
| 23 | 
            +
                  end
         | 
| 24 | 
            +
                end
         | 
| 25 | 
            +
              end
         | 
| 26 | 
            +
            end
         | 
    
        data/lib/zt/exporters.rb
    ADDED
    
    | @@ -0,0 +1,32 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require 'zt/constants'
         | 
| 4 | 
            +
            require 'zt/exporters/_base_exporter'
         | 
| 5 | 
            +
            require 'zt/exporters/hosts_file_exporter'
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            module Zt
         | 
| 8 | 
            +
              module Exporters
         | 
| 9 | 
            +
                class Exporter
         | 
| 10 | 
            +
                  def initialize(*exporter_names)
         | 
| 11 | 
            +
                    exporter_names = Zt::Constants::ALL_EXPORTERS if exporter_names.empty?
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                    exporter_classes = exporter_names.map { |n| Zt::Exporters.const_get(n) }
         | 
| 14 | 
            +
                    @exporters = exporter_classes.map(&:new)
         | 
| 15 | 
            +
                  end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                  # @return [Array[Hash]] an array of hashes from each exporter
         | 
| 18 | 
            +
                  # The hash is in form { data: Object, mangle: lambda }
         | 
| 19 | 
            +
                  # with the :mangle lambda containing any steps to apply the Object
         | 
| 20 | 
            +
                  # like rewriting /etc/hosts or sending the data elsewhere.
         | 
| 21 | 
            +
                  # NOTE there may be value in attributing each hash to its
         | 
| 22 | 
            +
                  # importer, consider that for later as a Hash[Hash].
         | 
| 23 | 
            +
                  def export
         | 
| 24 | 
            +
                    @exporters.map(&:export)
         | 
| 25 | 
            +
                  end
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                  def export_one_format(format)
         | 
| 28 | 
            +
                    Zt::Exporters::HostsFileExporter.new.export if format == :hosts
         | 
| 29 | 
            +
                  end
         | 
| 30 | 
            +
                end
         | 
| 31 | 
            +
              end
         | 
| 32 | 
            +
            end
         | 
| @@ -0,0 +1,32 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require 'zt/exporters/_base_exporter'
         | 
| 4 | 
            +
            require 'zt/conf'
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            module Zt
         | 
| 7 | 
            +
              module Exporters
         | 
| 8 | 
            +
                class HostsFileExporter < BaseExporter
         | 
| 9 | 
            +
                  def export
         | 
| 10 | 
            +
                    # process the normalised Hash @data and return a String and a Block
         | 
| 11 | 
            +
                    # defining what to do with the String
         | 
| 12 | 
            +
                    conf = Zt::Conf.instance.conf
         | 
| 13 | 
            +
                    output = ''
         | 
| 14 | 
            +
                    conf.nodes.each_key do |node_id|
         | 
| 15 | 
            +
                      node = conf.nodes[node_id]
         | 
| 16 | 
            +
                      node_nets = node[:local][:networks]
         | 
| 17 | 
            +
                      node_nets.each_key do |net_id|
         | 
| 18 | 
            +
                        net_zone = conf.networks[net_id][:local][:dns_zone]
         | 
| 19 | 
            +
                        node_name = node[:remote][:node_name]
         | 
| 20 | 
            +
                        node_addrs = node[:local][:networks][net_id]
         | 
| 21 | 
            +
                        node_addrs.each do |node_addr|
         | 
| 22 | 
            +
                          output += "#{node_addr}\t\t#{node_name}.#{net_zone}\n"
         | 
| 23 | 
            +
                        end
         | 
| 24 | 
            +
                      end
         | 
| 25 | 
            +
                    end
         | 
| 26 | 
            +
                    "# BEGIN zt\n" + output.lines.sort_by do |a|
         | 
| 27 | 
            +
                      a.split[1]
         | 
| 28 | 
            +
                    end.join + "# END zt\n"
         | 
| 29 | 
            +
                  end
         | 
| 30 | 
            +
                end
         | 
| 31 | 
            +
              end
         | 
| 32 | 
            +
            end
         | 
    
        data/lib/zt/importers.rb
    ADDED
    
    | @@ -0,0 +1,28 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require 'zt/constants'
         | 
| 4 | 
            +
            require 'zt/importers/_base_importer'
         | 
| 5 | 
            +
            require 'zt/importers/network_importer'
         | 
| 6 | 
            +
            require 'zt/importers/node_importer'
         | 
| 7 | 
            +
             | 
| 8 | 
            +
            module Zt
         | 
| 9 | 
            +
              module Importers
         | 
| 10 | 
            +
                class Importer
         | 
| 11 | 
            +
                  attr_accessor :importers
         | 
| 12 | 
            +
                  def initialize(networks, nodes, *importer_names)
         | 
| 13 | 
            +
                    importer_names = Zt::Constants::ALL_IMPORTERS if importer_names.empty?
         | 
| 14 | 
            +
                    importer_classes = importer_names.map do |n|
         | 
| 15 | 
            +
                      Zt::Importers.const_get(n)
         | 
| 16 | 
            +
                    end
         | 
| 17 | 
            +
                    @importers = importer_classes.map { |c| c.new(networks, nodes) }
         | 
| 18 | 
            +
                  end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                  # @return [Array[Hash]] an array of hashes from each exporter.
         | 
| 21 | 
            +
                  # NOTE there may be value in attributing each hash to its
         | 
| 22 | 
            +
                  # importer, consider that for later as a Hash[Hash].
         | 
| 23 | 
            +
                  def import
         | 
| 24 | 
            +
                    @importers.map(&:import)
         | 
| 25 | 
            +
                  end
         | 
| 26 | 
            +
                end
         | 
| 27 | 
            +
              end
         | 
| 28 | 
            +
            end
         | 
| @@ -0,0 +1,44 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require 'zt/conf'
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            module Zt
         | 
| 6 | 
            +
              module Importers
         | 
| 7 | 
            +
                class BaseImporter
         | 
| 8 | 
            +
                  attr_accessor :networks
         | 
| 9 | 
            +
                  attr_accessor :nodes
         | 
| 10 | 
            +
                  def initialize(networks, nodes)
         | 
| 11 | 
            +
                    @networks = networks
         | 
| 12 | 
            +
                    @nodes = nodes
         | 
| 13 | 
            +
                  end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                  def import
         | 
| 16 | 
            +
                    abort('import called on non-functional superclass importer')
         | 
| 17 | 
            +
                  end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                  private
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                  def dnsify(input)
         | 
| 22 | 
            +
                    zt_conf = Zt::Conf.instance.conf.zt
         | 
| 23 | 
            +
                    tld_key = 'top_level_domains'
         | 
| 24 | 
            +
                    tld = if zt_conf.key?(tld_key) && !zt_conf[tld_key].empty?
         | 
| 25 | 
            +
                            zt_conf[tld_key]
         | 
| 26 | 
            +
                          else
         | 
| 27 | 
            +
                            'zt'
         | 
| 28 | 
            +
                          end
         | 
| 29 | 
            +
                    clean = input.tr('-', '_')
         | 
| 30 | 
            +
                    clean = clean.gsub(/([\W])/, '-')
         | 
| 31 | 
            +
                    clean = clean.tr('_', '-')
         | 
| 32 | 
            +
                    clean = clean.gsub(/(-+)/, '-')
         | 
| 33 | 
            +
                    clean = "network-#{clean}" unless clean.match?(/^[A-Za-z]/)
         | 
| 34 | 
            +
                    clean = clean.gsub(Regexp.new("-#{tld}$"), '')
         | 
| 35 | 
            +
                    clean.gsub(/(-+)/, '-')
         | 
| 36 | 
            +
                  end
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                  def qualify(zone)
         | 
| 39 | 
            +
                    zt_conf = Zt::Conf.instance.conf.zt
         | 
| 40 | 
            +
                    "#{dnsify(zone)}.#{zt_conf['top_level_domain']}"
         | 
| 41 | 
            +
                  end
         | 
| 42 | 
            +
                end
         | 
| 43 | 
            +
              end
         | 
| 44 | 
            +
            end
         | 
| @@ -0,0 +1,46 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require 'zt/conf'
         | 
| 4 | 
            +
            require 'zt/importers/_base_importer'
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            module Zt
         | 
| 7 | 
            +
              module Importers
         | 
| 8 | 
            +
                class NetworkImporter < BaseImporter
         | 
| 9 | 
            +
                  def import
         | 
| 10 | 
            +
                    output = {}
         | 
| 11 | 
            +
                    # normalise data
         | 
| 12 | 
            +
                    normalised_networks = networks.map do |n|
         | 
| 13 | 
            +
                      {
         | 
| 14 | 
            +
                        network_id: n['id'],
         | 
| 15 | 
            +
                        network_name: n['config']['name'],
         | 
| 16 | 
            +
                        network_description: n['description'],
         | 
| 17 | 
            +
                        network_total_members: n['totalMemberCount'],
         | 
| 18 | 
            +
                        network_authorized_members: n['authorizedMemberCount'],
         | 
| 19 | 
            +
                        network_pending_members:
         | 
| 20 | 
            +
                          (n['totalMemberCount'] - n['authorizedMemberCount'])
         | 
| 21 | 
            +
                      }
         | 
| 22 | 
            +
                    end
         | 
| 23 | 
            +
                    domains_conf = Zt::Conf.instance.conf.domains
         | 
| 24 | 
            +
                    normalised_networks.each do |n|
         | 
| 25 | 
            +
                      zone = if domains_conf.key? n[:network_id]
         | 
| 26 | 
            +
                               if n[:network_id].empty?
         | 
| 27 | 
            +
                                 qualify(n[:network_id])
         | 
| 28 | 
            +
                               else
         | 
| 29 | 
            +
                                 qualify(domains_conf[n[:network_id]])
         | 
| 30 | 
            +
                               end
         | 
| 31 | 
            +
                             else
         | 
| 32 | 
            +
                               qualify(n[:network_name])
         | 
| 33 | 
            +
                             end
         | 
| 34 | 
            +
                      output[n[:network_id]] = {} unless output.key?(n[:network_id])
         | 
| 35 | 
            +
                      output[n[:network_id]][:remote] = n
         | 
| 36 | 
            +
                      output[n[:network_id]][:local] = {
         | 
| 37 | 
            +
                        dns_zone: zone
         | 
| 38 | 
            +
                      }
         | 
| 39 | 
            +
                    end
         | 
| 40 | 
            +
                    {
         | 
| 41 | 
            +
                      networks: output
         | 
| 42 | 
            +
                    }
         | 
| 43 | 
            +
                  end
         | 
| 44 | 
            +
                end
         | 
| 45 | 
            +
              end
         | 
| 46 | 
            +
            end
         | 
| @@ -0,0 +1,54 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require 'zt/importers/_base_importer'
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            module Zt
         | 
| 6 | 
            +
              module Importers
         | 
| 7 | 
            +
                class NodeImporter < BaseImporter
         | 
| 8 | 
            +
                  def import
         | 
| 9 | 
            +
                    output = {}
         | 
| 10 | 
            +
                    hostnames = {}
         | 
| 11 | 
            +
                    memberships = {}
         | 
| 12 | 
            +
                    # normalise data
         | 
| 13 | 
            +
                    nodes.each_key do |network_id|
         | 
| 14 | 
            +
                      net = nodes[network_id]
         | 
| 15 | 
            +
                      normalised_nodes = net.map do |node|
         | 
| 16 | 
            +
                        {
         | 
| 17 | 
            +
                          node_id: node['nodeId'],
         | 
| 18 | 
            +
                          node_name: node['name'],
         | 
| 19 | 
            +
                          node_addr: node['config']['ipAssignments'],
         | 
| 20 | 
            +
                          node_authed: node['config']['authorized']
         | 
| 21 | 
            +
                        }
         | 
| 22 | 
            +
                      end
         | 
| 23 | 
            +
                      normalised_nodes.each do |n|
         | 
| 24 | 
            +
                        hostnames[n[:node_id]] = [] unless hostnames.key?(n[:node_id])
         | 
| 25 | 
            +
                        memberships[n[:node_id]] = [] unless memberships.key?(n[:node_id])
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                        hostnames[n[:node_id]].append(n[:node_name])
         | 
| 28 | 
            +
                        memberships[n[:node_id]].append([network_id, n[:node_addr]])
         | 
| 29 | 
            +
                        n.delete(:node_addr)
         | 
| 30 | 
            +
                        output[n[:node_id]] = {} unless output.key?(n[:node_id])
         | 
| 31 | 
            +
                        output[n[:node_id]][:remote] = n
         | 
| 32 | 
            +
                        output[n[:node_id]][:local] = {}
         | 
| 33 | 
            +
                      end
         | 
| 34 | 
            +
                      output.each_key do |k|
         | 
| 35 | 
            +
                        output[k][:remote][:node_name] = hostnames[k].max_by do |i|
         | 
| 36 | 
            +
                          hostnames[k].count(i)
         | 
| 37 | 
            +
                        end
         | 
| 38 | 
            +
                        memberships[k].each do |m|
         | 
| 39 | 
            +
                          output[k][:local][:networks] = {} unless
         | 
| 40 | 
            +
                            output[k][:local].key? :networks
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                          output[k][:local][:networks][m[0]] = m[1]
         | 
| 43 | 
            +
                        end
         | 
| 44 | 
            +
             | 
| 45 | 
            +
                      end
         | 
| 46 | 
            +
                    end
         | 
| 47 | 
            +
                    {
         | 
| 48 | 
            +
                      nodes: output
         | 
| 49 | 
            +
                    }
         | 
| 50 | 
            +
                  end
         | 
| 51 | 
            +
                end
         | 
| 52 | 
            +
              end
         | 
| 53 | 
            +
            end
         | 
| 54 | 
            +
             | 
| @@ -0,0 +1,39 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require 'httparty'
         | 
| 4 | 
            +
            require 'zt/conf'
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            module Zt
         | 
| 7 | 
            +
              module RemoteAPI
         | 
| 8 | 
            +
                class ZeroTierAPI
         | 
| 9 | 
            +
                  include HTTParty
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                  base_uri 'https://my.zerotier.com/api'
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                  def initialize
         | 
| 14 | 
            +
                    @ztc = Zt::Conf.instance.conf
         | 
| 15 | 
            +
                    # noinspection RubyStringKeysInHashInspection
         | 
| 16 | 
            +
                    @req_opts = {
         | 
| 17 | 
            +
                      headers: {
         | 
| 18 | 
            +
                        'Authorization' => "Bearer #{@ztc.zt['token']}"
         | 
| 19 | 
            +
                      }
         | 
| 20 | 
            +
                    }
         | 
| 21 | 
            +
                  end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                  def networks
         | 
| 24 | 
            +
                    get_parsed('/network')
         | 
| 25 | 
            +
                  end
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                  def network_members(network_id)
         | 
| 28 | 
            +
                    get_parsed("/network/#{network_id}/member")
         | 
| 29 | 
            +
                  end
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                  private
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                  def get_parsed(path)
         | 
| 34 | 
            +
                    self.class.get(path, @req_opts).parsed_response
         | 
| 35 | 
            +
                  end
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                end
         | 
| 38 | 
            +
              end
         | 
| 39 | 
            +
            end
         | 
    
        data/lib/zt/version.rb
    ADDED
    
    
    
        data/zt.gemspec
    ADDED
    
    | @@ -0,0 +1,57 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            lib = File.expand_path('lib', __dir__)
         | 
| 4 | 
            +
            $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
         | 
| 5 | 
            +
            require 'zt/version'
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            Gem::Specification.new do |spec|
         | 
| 8 | 
            +
              spec.name          = 'zt'
         | 
| 9 | 
            +
              spec.version       = Zt::VERSION
         | 
| 10 | 
            +
              spec.authors       = ['Dave Williams']
         | 
| 11 | 
            +
              spec.email         = ['dave@dave.io']
         | 
| 12 | 
            +
             | 
| 13 | 
            +
              spec.summary       = 'ZeroTier administration toolbox'
         | 
| 14 | 
            +
              spec.description   =
         | 
| 15 | 
            +
                'Utilities and glue to make working with ZeroTier networks ' \
         | 
| 16 | 
            +
                'a bit more friendly'
         | 
| 17 | 
            +
              spec.homepage      = 'https://github.com/daveio/zt'
         | 
| 18 | 
            +
              spec.license       = 'MIT'
         | 
| 19 | 
            +
             | 
| 20 | 
            +
             | 
| 21 | 
            +
              if spec.respond_to?(:metadata)
         | 
| 22 | 
            +
                # spec.metadata['allowed_push_host'] =
         | 
| 23 | 
            +
                #   'http://localhost'
         | 
| 24 | 
            +
                spec.metadata['homepage_uri'] = spec.homepage
         | 
| 25 | 
            +
                spec.metadata['source_code_uri'] = 'https://github.com/daveio/zt'
         | 
| 26 | 
            +
                spec.metadata['changelog_uri'] =
         | 
| 27 | 
            +
                  'https://raw.githubusercontent.com/daveio/zt/master/CHANGELOG.md'
         | 
| 28 | 
            +
              else
         | 
| 29 | 
            +
                raise 'RubyGems 2.0 or newer is required to protect ' \
         | 
| 30 | 
            +
                      'against public gem pushes.'
         | 
| 31 | 
            +
              end
         | 
| 32 | 
            +
             | 
| 33 | 
            +
              # Specify which files should be added to the gem when it is released.
         | 
| 34 | 
            +
              # The `git ls-files -z` loads the files in the RubyGem that have been
         | 
| 35 | 
            +
              # added into git.
         | 
| 36 | 
            +
              spec.files = Dir.chdir(File.expand_path(__dir__)) do
         | 
| 37 | 
            +
                `git ls-files -z`.split("\x0").reject do |f|
         | 
| 38 | 
            +
                  f.match(%r{^(test|spec|features)/})
         | 
| 39 | 
            +
                end
         | 
| 40 | 
            +
              end
         | 
| 41 | 
            +
              spec.bindir        = 'exe'
         | 
| 42 | 
            +
              spec.executables   = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
         | 
| 43 | 
            +
              spec.require_paths = ['lib']
         | 
| 44 | 
            +
             | 
| 45 | 
            +
              spec.add_dependency 'httparty', '~> 0.0', '>= 0.10.0'
         | 
| 46 | 
            +
              spec.add_dependency 'thor', '~> 0.0'
         | 
| 47 | 
            +
              spec.add_dependency 'xdg', '~> 2.0'
         | 
| 48 | 
            +
             | 
| 49 | 
            +
              spec.add_development_dependency 'bundler', '~> 2.0'
         | 
| 50 | 
            +
              spec.add_development_dependency 'dotenv', '~> 2.0'
         | 
| 51 | 
            +
              spec.add_development_dependency 'pry', '~> 0.0'
         | 
| 52 | 
            +
              spec.add_development_dependency 'rake', '~> 12.0'
         | 
| 53 | 
            +
              spec.add_development_dependency 'rspec', '~> 3.0'
         | 
| 54 | 
            +
              spec.add_development_dependency 'rubocop', '~> 0.0', '>= 0.49.0'
         | 
| 55 | 
            +
              spec.add_development_dependency 'rubocop-performance', '~> 1.0'
         | 
| 56 | 
            +
              spec.add_development_dependency 'ruby-debug-ide', '~> 0.0'
         | 
| 57 | 
            +
            end
         |