<commit_before>require 'mamiya/dsl'
require 'mamiya/logger'

require 'shellwords'

module Mamiya
  class Script < DSL
    class CommandFailed < Exception; end

    add_hook :before_build
    add_hook :prepare_build
    add_hook :build
    add_hook :after_build

    add_hook :before_distribute
    add_hook :after_distribute

    add_hook :before_prepare
    add_hook :prepare
    add_hook :after_prepare

    add_hook :before_finalize
    add_hook :finalize
    add_hook :after_finalize

    add_hook :before_rollback
    add_hook :rollback
    add_hook :after_rollback

    add_hook :package_name, chain: true
    add_hook :package_meta, chain: true

    set_default :application, nil
    set_default :repository, nil
    set_default :ref, nil

    set_default :discover_servers, true
    set_default :on_client_failure, :error # error, warn, ignore

    set_default :build_from, nil
    set_default :build_to, nil
    set_default :package_under, nil
    set_default :exclude_from_package, []
    set_default :dereference_symlinks, true

    set_default :package_to, nil
    set_default :deploy_to, nil
    set_default :prepare_to, nil

    set_default :logger, Mamiya::Logger.new(outputs: [])

    set_default :skip_prepare_build, false

    def run(*args)
      # TODO: Stop when fail
      actual = -> do
        logger = self.logger['RUN']

        logger.info("$ #{args.shelljoin}")

        err_r, err_w = IO.pipe
        out_r, out_w = IO.pipe

        pid = spawn(*args, out: out_w, err: err_w)

        [out_w, err_w].each(&:close)

        buf = ""

        ths = {:debug => out_r, :warn => err_r}.map do |severity, io|
          Thread.new {
            until io.eof?
              str = io.gets
              logger.__send__(severity, str.chomp)
              buf << str
            end
          }.tap { |_| _.abort_on_exception = true }
        end

        pid, status = Process.waitpid2(pid)
        ths.each { |_| _.alive? && _.kill }

        [out_r, err_r].each(&:close)

        raise CommandFailed unless status.success?

        buf
      end

      if defined? Bundler
        Bundler.with_clean_env(&actual)
      else
        actual.call
      end
    end
<commit_msg>Wait IO threads for 3 seconds then kill<commit_after>require 'mamiya/dsl'
require 'mamiya/logger'

require 'shellwords'

module Mamiya
  class Script < DSL
    class CommandFailed < Exception; end

    add_hook :before_build
    add_hook :prepare_build
    add_hook :build
    add_hook :after_build

    add_hook :before_distribute
    add_hook :after_distribute

    add_hook :before_prepare
    add_hook :prepare
    add_hook :after_prepare

    add_hook :before_finalize
    add_hook :finalize
    add_hook :after_finalize

    add_hook :before_rollback
    add_hook :rollback
    add_hook :after_rollback

    add_hook :package_name, chain: true
    add_hook :package_meta, chain: true

    set_default :application, nil
    set_default :repository, nil
    set_default :ref, nil

    set_default :discover_servers, true
    set_default :on_client_failure, :error # error, warn, ignore

    set_default :build_from, nil
    set_default :build_to, nil
    set_default :package_under, nil
    set_default :exclude_from_package, []
    set_default :dereference_symlinks, true

    set_default :package_to, nil
    set_default :deploy_to, nil
    set_default :prepare_to, nil

    set_default :logger, Mamiya::Logger.new(outputs: [])

    set_default :skip_prepare_build, false

    def run(*args)
      # TODO: Stop when fail
      actual = -> do
        logger = self.logger['RUN']

        logger.info("$ #{args.shelljoin}")

        err_r, err_w = IO.pipe
        out_r, out_w = IO.pipe

        pid = spawn(*args, out: out_w, err: err_w)

        [out_w, err_w].each(&:close)

        buf = ""

        ths = {:debug => out_r, :warn => err_r}.map do |severity, io|
          Thread.new {
            until io.eof?
              str = io.gets
              logger.__send__(severity, str.chomp)
              buf << str
            end
          }.tap { |_| _.abort_on_exception = true }
        end

        pid, status = Process.waitpid2(pid)

        begin
          timeout(3) { ths.each(&:join) }
        rescue Timeout::Error
        end
        ths.each { |_| _.alive? && _.kill }

        [out_r, err_r].each(&:close)

        raise CommandFailed unless status.success?

        buf
      end

      if defined? Bundler
        Bundler.with_clean_env(&actual)
      else
        actual.call
      end
    end

{'fraction_non_alphanumeric': 0.08837209302325581, 'fraction_numerical': 0.0008859357696566999, 'mean_word_length': 2.370149253731343, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3265438', 'n_tokens_mistral': 1503, 'n_tokens_neox': 1439, 'n_words': 355}