<commit_before># encoding: UTF-8

require 'json'
require 'rest'
require 'netrc'

module Pod
  class Command
    class Trunk < Command
      self.abstract_command = true
      self.summary = 'Interact with the CocoaPods API (e.g. publishing new specs)'

      SCHEME_AND_HOST = ENV['TRUNK_SCHEME_AND_HOST'] || 'https://trunk.cocoapods.org'
      BASE_URL = "#{SCHEME_AND_HOST}/api/v1"

      class Register < Trunk
        self.summary = 'Manage sessions'
        self.description = <<-DESC
          Register a new account, or create a new session.

          If this is your first registration, both an `EMAIL` address and your
          `NAME` are required. If you've already registered with trunk, you may
          omit the `NAME` (unless you would like to change it).

          It is recommended that you provide a description of the session, so
          that it will be easier to identify later on. For instance, when you
          would like to clean-up your sessions. A common example is to specify
          the location where the machine, that you are using the session for, is
          physically located.

          Examples:

              $ pod trunk register <EMAIL> '<NAME>' --description='Personal Laptop'
              $ pod trunk register <EMAIL> --description='Work Laptop'
              $ pod trunk register <EMAIL>
        DESC

        self.arguments = [
          ['EMAIL', :required],
          ['NAME',  :optional],
        ]

        def self.options
          [
            ['--description=DESCRIPTION', 'An arbitrary description to ' \
                                          'easily identify your session ' \
                                          'later on.']
          ].concat(super)
        end

        def initialize(argv)
          @session_description = argv.option('description')
          @email, @name = argv.shift_argument, argv.shift_argument
          super
        end

        def validate!
          super
          unless @email
            help! 'Specify at least your email address.'
          end
        end

        def run
          body = {
            'email' => @email,
            'name' => @name,
            'description' => @session_description
          }.to_json
          json = json(request_path(:post, "sessions", body, default_headers))
          save_token(json['token'])
          # TODO UI.notice inserts an empty line :/
          puts '[!] Please verify the session by clicking the link in the ' \
               "verification email that has been sent to #{@email}".yellow
        end

        def save_token(token)
          netrc['trunk.cocoapods.org'] = @email, token
          netrc.save
        end
      end

      class Me < Trunk
        self.summary = 'Display information about your sessions'
        self.description = <<-DESC
          Includes information about your registration, followed by all your
          sessions.

          These are your current session, other valid sessions, unverified
          sessions, and expired sessions.
        DESC

        def validate!
          super
          unless token
            help! 'You need to register a session first.'
          end
        end

        def run
          json = json(request_path(:get, "sessions", auth_headers))
          UI.labeled 'Name', json['name']
          UI.labeled 'Email', json['email']
          UI.labeled 'Since', formatted_time(json['created_at'])

          sessions = json['sessions'].map do |session|
            hash = {
              :created_at => formatted_time(session['created_at']),
              :valid_until => formatted_time(session['valid_until']),
              :created_from_ip => session['created_from_ip'],
              :description => session['description']
            }
            if Time.parse(session['valid_until']) <= Time.now.utc
              hash[:color] = :red
            elsif session['verified']
              hash[:color] = session['current'] ? :cyan : :green
            else
              hash[:color] = :yellow
              hash[:valid_until] = 'Unverified'
            end
            hash
          end

          columns = [:created_at, :valid_until, :created_from_ip, :description].map do |key|
            find_max_size(sessions, key)
          end

          sessions = sessions.map do |session|
            created_at      = session[:created_at].ljust(columns[0])
            valid_until     = session[:valid_until].rjust(columns[1])
            created_from_ip = session[:created_from_ip].ljust(columns[2])
            description     = session[:description]
            msg = "#{created_at} - #{valid_until}. IP: #{created_from_ip}"
            msg << " Description: #{description}" if description
            msg.send(session[:color])
          end

          UI.labeled 'Sessions', sessions
        end

        private

        def find_max_size(sessions, key)
          sessions.map { |s| (s[key] || '').size }.max
        end

        class CleanSessions < Me
          self.summary = 'Remove sessions'
          self.description = <<-DESC
            By default this will clean-up your sessions by removing expired and
            unverified sessions.

            To remove all your sessions, except for the one you are currently
            using, specify the `--all` flag.
          DESC

          def self.options
            [
              ['--all', 'Removes all your sessions, except for the current one'],
            ].concat(super)
          end

          def initialize(argv)
            @remove_all = argv.flag?('all', false)
            super
          end

          def validate!
            super
            unless token
              help! 'You need to register a session first.'
            end
          end

          def run
            path = @remove_all ? 'sessions/all' : 'sessions'
            request_path(:delete, path, auth_headers)
          end
        end
      end

      class AddOwner < Trunk
        self.summary = 'Add an owner to a pod'
        self.description = <<-DESC
          An ‘owner’ is a registered user whom is allowed to make changes to a
          pod, such as pushing new versions and adding other ‘owners’.
        DESC

        self.arguments = [
          ['POD',         :required],
          ['OWNER-EMAIL', :required],
        ]

        def initialize(argv)
          @pod, @email = argv.shift_argument, argv.shift_argument
          super
        end

        def validate!
          super
          unless token
            help! 'You need to register a session first.'
          end
          unless @pod && @email
            help! 'Specify the pod name and the new owner’s email address.'
          end
        end

        def run
          body = { 'email' => @email }.to_json
          json = json(request_path(:patch, "pods/#{@pod}/owners", body, auth_headers))
          UI.labeled 'Owners', json.map { |o| "#{o['name']} <#{o['email']}>" }
        end
      end

      class Push < Trunk
        self.summary = 'Publish a podspec'
        self.description = <<-DESC
          By publishing a podspec you make this available to all users of the
          ‘master’ spec-repo.

          Before pushing the podspec to cocoapods.org, this will perform a local
          lint of the podspec, including a build of the library. However, it
          remains *your* responsibility to ensure that the published podspec
          will actually work for your users. Thus it is recommended that you
          *first* try to use the podspec to integrate the library into your demo
          and/or real application.

          If this is the first time you publish a spec for this pod, you will
          automatically be registered as the ‘owner’ of this pod. (Note that
          ‘owner’ in this case implies a person that is allowed to publish new
          versions and add other ‘owners’, not necessarily the library author.)
        DESC

        self.arguments = [['PATH', :required]]

        def self.options
          [
            ["--allow-warnings", "Allows push even if there are lint warnings"],
          ].concat(super)
        end

        def initialize(argv)
          @allow_warnings = argv.flag?('allow-warnings')
          @path = argv.shift_argument
          super
        end

        def validate!
          super
          unless token
            help! 'You need to register a session first.'
          end
          unless @path
            help! 'Specify the path to the podspec file.'
          end
          unless File.exist?(@path) && !File.directory?(@path)
            help! 'No podspec found at the specified path.'
          end
        end

        def run
          validate_podspec

          response = request_path(:post, "pods", spec.to_json, auth_headers)
          url = response.headers['location'].first
          json = json(request_url(:get, url, default_headers))

          UI.labeled 'Data URL', json['data_url']
          messages = json['messages'].map do |entry|
            at, message = entry.to_a.flatten
            "#{formatted_time(at)}: #{message}"
          end
          UI.labeled 'Log messages', messages
        end

        private

        def spec
          @spec ||= Pod::Specification.from_file(@path)
        rescue Informative # TODO: this should be a more specific error
          raise Informative, 'Unable to interpret the specified path as a ' \
                             'podspec.'
        end

        # Performs a full lint against the podspecs.
        #
        # TODO: Currently copied verbatim from `pod push`.
        def validate_podspec
          UI.puts 'Validating podspec'.yellow
          validator = Validator.new(spec)
          validator.only_errors = @allow_warnings
          begin
            validator.validate
          rescue Exception<commit_msg>Don't try to wrap the data URL, which breaks it.<commit_after># encoding: UTF-8

require 'json'
require 'rest'
require 'netrc'

module Pod
  class Command
    class Trunk < Command
      self.abstract_command = true
      self.summary = 'Interact with the CocoaPods API (e.g. publishing new specs)'

      SCHEME_AND_HOST = ENV['TRUNK_SCHEME_AND_HOST'] || 'https://trunk.cocoapods.org'
      BASE_URL = "#{SCHEME_AND_HOST}/api/v1"

      class Register < Trunk
        self.summary = 'Manage sessions'
        self.description = <<-DESC
          Register a new account, or create a new session.

          If this is your first registration, both an `EMAIL` address and your
          `NAME` are required. If you've already registered with trunk, you may
          omit the `NAME` (unless you would like to change it).

          It is recommended that you provide a description of the session, so
          that it will be easier to identify later on. For instance, when you
          would like to clean-up your sessions. A common example is to specify
          the location where the machine, that you are using the session for, is
          physically located.

          Examples:

              $ pod trunk register <EMAIL> '<NAME>' --description='Personal Laptop'
              $ pod trunk register <EMAIL> --description='Work Laptop'
              $ pod trunk register <EMAIL>
        DESC

        self.arguments = [
          ['EMAIL', :required],
          ['NAME',  :optional],
        ]

        def self.options
          [
            ['--description=DESCRIPTION', 'An arbitrary description to ' \
                                          'easily identify your session ' \
                                          'later on.']
          ].concat(super)
        end

        def initialize(argv)
          @session_description = argv.option('description')
          @email, @name = argv.shift_argument, argv.shift_argument
          super
        end

        def validate!
          super
          unless @email
            help! 'Specify at least your email address.'
          end
        end

        def run
          body = {
            'email' => @email,
            'name' => @name,
            'description' => @session_description
          }.to_json
          json = json(request_path(:post, "sessions", body, default_headers))
          save_token(json['token'])
          # TODO UI.notice inserts an empty line :/
          puts '[!] Please verify the session by clicking the link in the ' \
               "verification email that has been sent to #{@email}".yellow
        end

        def save_token(token)
          netrc['trunk.cocoapods.org'] = @email, token
          netrc.save
        end
      end

      class Me < Trunk
        self.summary = 'Display information about your sessions'
        self.description = <<-DESC
          Includes information about your registration, followed by all your
          sessions.

          These are your current session, other valid sessions, unverified
          sessions, and expired sessions.
        DESC

        def validate!
          super
          unless token
            help! 'You need to register a session first.'
          end
        end

        def run
          json = json(request_path(:get, "sessions", auth_headers))
          UI.labeled 'Name', json['name']
          UI.labeled 'Email', json['email']
          UI.labeled 'Since', formatted_time(json['created_at'])

          sessions = json['sessions'].map do |session|
            hash = {
              :created_at => formatted_time(session['created_at']),
              :valid_until => formatted_time(session['valid_until']),
              :created_from_ip => session['created_from_ip'],
              :description => session['description']
            }
            if Time.parse(session['valid_until']) <= Time.now.utc
              hash[:color] = :red
            elsif session['verified']
              hash[:color] = session['current'] ? :cyan : :green
            else
              hash[:color] = :yellow
              hash[:valid_until] = 'Unverified'
            end
            hash
          end

          columns = [:created_at, :valid_until, :created_from_ip, :description].map do |key|
            find_max_size(sessions, key)
          end

          sessions = sessions.map do |session|
            created_at      = session[:created_at].ljust(columns[0])
            valid_until     = session[:valid_until].rjust(columns[1])
            created_from_ip = session[:created_from_ip].ljust(columns[2])
            description     = session[:description]
            msg = "#{created_at} - #{valid_until}. IP: #{created_from_ip}"
            msg << " Description: #{description}" if description
            msg.send(session[:color])
          end

          UI.labeled 'Sessions', sessions
        end

        private

        def find_max_size(sessions, key)
          sessions.map { |s| (s[key] || '').size }.max
        end

        class CleanSessions < Me
          self.summary = 'Remove sessions'
          self.description = <<-DESC
            By default this will clean-up your sessions by removing expired and
            unverified sessions.

            To remove all your sessions, except for the one you are currently
            using, specify the `--all` flag.
          DESC

          def self.options
            [
              ['--all', 'Removes all your sessions, except for the current one'],
            ].concat(super)
          end

          def initialize(argv)
            @remove_all = argv.flag?('all', false)
            super
          end

          def validate!
            super
            unless token
              help! 'You need to register a session first.'
            end
          end

          def run
            path = @remove_all ? 'sessions/all' : 'sessions'
            request_path(:delete, path, auth_headers)
          end
        end
      end

      class AddOwner < Trunk
        self.summary = 'Add an owner to a pod'
        self.description = <<-DESC
          An ‘owner’ is a registered user whom is allowed to make changes to a
          pod, such as pushing new versions and adding other ‘owners’.
        DESC

        self.arguments = [
          ['POD',         :required],
          ['OWNER-EMAIL', :required],
        ]

        def initialize(argv)
          @pod, @email = argv.shift_argument, argv.shift_argument
          super
        end

        def validate!
          super
          unless token
            help! 'You need to register a session first.'
          end
          unless @pod && @email
            help! 'Specify the pod name and the new owner’s email address.'
          end
        end

        def run
          body = { 'email' => @email }.to_json
          json = json(request_path(:patch, "pods/#{@pod}/owners", body, auth_headers))
          UI.labeled 'Owners', json.map { |o| "#{o['name']} <#{o['email']}>" }
        end
      end

      class Push < Trunk
        self.summary = 'Publish a podspec'
        self.description = <<-DESC
          By publishing a podspec you make this available to all users of the
          ‘master’ spec-repo.

          Before pushing the podspec to cocoapods.org, this will perform a local
          lint of the podspec, including a build of the library. However, it
          remains *your* responsibility to ensure that the published podspec
          will actually work for your users. Thus it is recommended that you
          *first* try to use the podspec to integrate the library into your demo
          and/or real application.

          If this is the first time you publish a spec for this pod, you will
          automatically be registered as the ‘owner’ of this pod. (Note that
          ‘owner’ in this case implies a person that is allowed to publish new
          versions and add other ‘owners’, not necessarily the library author.)
        DESC

        self.arguments = [['PATH', :required]]

        def self.options
          [
            ["--allow-warnings", "Allows push even if there are lint warnings"],
          ].concat(super)
        end

        def initialize(argv)
          @allow_warnings = argv.flag?('allow-warnings')
          @path = argv.shift_argument
          super
        end

        def validate!
          super
          unless token
            help! 'You need to register a session first.'
          end
          unless @path
            help! 'Specify the path to the podspec file.'
          end
          unless File.exist?(@path) && !File.directory?(@path)
            help! 'No podspec found at the specified path.'
          end
        end

        def run
          validate_podspec

          response = request_path(:post, "pods", spec.to_json, auth_headers)
          url = response.headers['location'].first
          json = json(request_url(:get, url, default_headers))

          # Using UI.labeled here is dangerous, as it wraps the URL and indents
          # it, which breaks the URL when you try to copy-paste it.
          $stdout.puts "  - Data URL: #{json['data_url']}"

          messages = json['messages'].map do |entry|
            at, message = entry.to_a.flatten
            "#{formatted_time(at)}: #{message}"
          end
          UI.labeled 'Log messages', messages
        end

        private

        def spec
          @spec ||= Pod::Specification.from_file(@path)
        rescue Informative # TODO: this should be a more specific error
          raise Informative, 'Unable to interpret the specified path as a ' \
                             'podspec.'
        end

        # Performs a full lint against the podspecs.
        #
        # TODO: Currently copied verbatim from `pod push`.
        def validate_podspec
          UI.puts 'Validating podspec'.yellow
          validator = Validator.new(spec)
          validator.only_errors = @allow_warnings
          begin
            validator.validate
          rescue Exception
{'fraction_non_alphanumeric': 0.08746165065633958, 'fraction_numerical': 0.0005029422119398481, 'mean_word_length': 1.695770065075922, 'pattern_counts': {'":': 0, '<': 51, '<?xml version=': 0, '>': 29, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 8, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2098536', 'n_tokens_mistral': 5139, 'n_tokens_neox': 4990, 'n_words': 1755}