squared 0.4.5 → 0.4.7
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 +4 -4
- data/CHANGELOG.md +83 -0
- data/README.ruby.md +44 -37
- data/lib/squared/common/class.rb +2 -5
- data/lib/squared/common/format.rb +6 -2
- data/lib/squared/common/shell.rb +4 -4
- data/lib/squared/common/system.rb +2 -2
- data/lib/squared/common/utils.rb +8 -2
- data/lib/squared/config.rb +3 -3
- data/lib/squared/version.rb +1 -1
- data/lib/squared/workspace/application.rb +9 -9
- data/lib/squared/workspace/project/base.rb +134 -211
- data/lib/squared/workspace/project/docker.rb +59 -53
- data/lib/squared/workspace/project/git.rb +161 -156
- data/lib/squared/workspace/project/node.rb +60 -34
- data/lib/squared/workspace/project/python.rb +141 -88
- data/lib/squared/workspace/project/ruby.rb +87 -71
- data/lib/squared/workspace/project/support/class.rb +197 -0
- data/lib/squared/workspace/project/support.rb +3 -0
- data/lib/squared/workspace/project.rb +1 -0
- data/lib/squared/workspace/series.rb +1 -1
- metadata +4 -2
| @@ -1,9 +1,5 @@ | |
| 1 1 | 
             
            # frozen_string_literal: true
         | 
| 2 2 |  | 
| 3 | 
            -
            require 'date'
         | 
| 4 | 
            -
            require 'time'
         | 
| 5 | 
            -
            require 'digest'
         | 
| 6 | 
            -
             | 
| 7 3 | 
             
            module Squared
         | 
| 8 4 | 
             
              module Workspace
         | 
| 9 5 | 
             
                module Git
         | 
| @@ -116,6 +112,9 @@ module Squared | |
| 116 112 | 
             
                  end
         | 
| 117 113 |  | 
| 118 114 | 
             
                  def rev_clear(name)
         | 
| 115 | 
            +
                    if Dir.exist?(name) && (proj = find(name))
         | 
| 116 | 
            +
                      name = proj.name
         | 
| 117 | 
            +
                    end
         | 
| 119 118 | 
             
                    rev_write if rev_entry(name, 'revision', val: '', create: false)
         | 
| 120 119 | 
             
                  end
         | 
| 121 120 |  | 
| @@ -138,7 +137,7 @@ module Squared | |
| 138 137 | 
             
                  private
         | 
| 139 138 |  | 
| 140 139 | 
             
                  def rev_timenow
         | 
| 141 | 
            -
                     | 
| 140 | 
            +
                    Time.now.utc.strftime('%s%L').to_i
         | 
| 142 141 | 
             
                  end
         | 
| 143 142 | 
             
                end
         | 
| 144 143 | 
             
                Application.include Git
         | 
| @@ -160,11 +159,12 @@ module Squared | |
| 160 159 | 
             
                        show: %w[s exit-code histogram].freeze
         | 
| 161 160 | 
             
                      }.freeze,
         | 
| 162 161 | 
             
                      fetch: {
         | 
| 163 | 
            -
                        base: %w[multiple progress P|prune-tags refetch stdin u|update-head-ok | 
| 162 | 
            +
                        base: %w[multiple progress P|prune-tags refetch stdin u|update-head-ok
         | 
| 164 163 | 
             
                                 recurse-submodules-default=b].freeze,
         | 
| 165 164 | 
             
                        pull: %w[4 6 n t a|append atomic dry-run f|force k|keep n|negotiate-only prefetch p|prune q|quiet
         | 
| 166 165 | 
             
                                 set-upstream unshallow update-shallow v|verbose deepen=i depth=i j|jobs=i negotiation-tip=q
         | 
| 167 | 
            -
                                 refmap=q o|server-option=q shallow-exclude=e shallow-since= | 
| 166 | 
            +
                                 recurse-submodules=v refmap=q o|server-option=q shallow-exclude=e shallow-since=v
         | 
| 167 | 
            +
                                 upload-pack=q].freeze
         | 
| 168 168 | 
             
                      }.freeze,
         | 
| 169 169 | 
             
                      log: {
         | 
| 170 170 | 
             
                        base: %w[all all-match alternate-refs author-date-order basic-regexp bisect boundary cherry cherry-mark
         | 
| @@ -196,7 +196,7 @@ module Squared | |
| 196 196 | 
             
                                   X|exclude-from=p exclude-per-directory=p format=q with-tree=q].freeze,
         | 
| 197 197 | 
             
                      ls_remote: %w[exit-code get-url q|quiet o|server-option=q symref sort=q upload-pack=q].freeze,
         | 
| 198 198 | 
             
                      mv: %w[k f|force n|dry-run v|verbose].freeze,
         | 
| 199 | 
            -
                      pull: %w[e n allow-unrelated-histories ff-only S|gpg-sign=qq log=i r|rebase= | 
| 199 | 
            +
                      pull: %w[e n allow-unrelated-histories ff-only S|gpg-sign=qq log=i r|rebase=v? s|strategy=b
         | 
| 200 200 | 
             
                               X|strategy-option=b].freeze,
         | 
| 201 201 | 
             
                      merge: %w[e n allow-unrelated-histories ff-only m=q q|quiet v|verbose cleanup=b F|file=p S|gpg-sign=qq
         | 
| 202 202 | 
             
                                into-name=e log=i s|strategy=b X|strategy-option=b].freeze,
         | 
| @@ -325,7 +325,7 @@ module Squared | |
| 325 325 | 
             
                      'rev' => %i[commit branch output parseopt build].freeze,
         | 
| 326 326 | 
             
                      'show' => %i[format oneline textconv].freeze,
         | 
| 327 327 | 
             
                      'stash' => %i[push pop apply drop clear list].freeze,
         | 
| 328 | 
            -
                      'tag' => %i[add delete list].freeze
         | 
| 328 | 
            +
                      'tag' => %i[add sign delete list].freeze
         | 
| 329 329 | 
             
                    })
         | 
| 330 330 |  | 
| 331 331 | 
             
                    def initialize(*, **)
         | 
| @@ -388,7 +388,7 @@ module Squared | |
| 388 388 | 
             
                                    refs = param_guard(action, flag, args: args.to_a)
         | 
| 389 389 | 
             
                                    tag(flag, refs: refs)
         | 
| 390 390 | 
             
                                  end
         | 
| 391 | 
            -
                                when :add
         | 
| 391 | 
            +
                                when :add, :sign
         | 
| 392 392 | 
             
                                  format_desc action, flag, 'name,message?,commit?'
         | 
| 393 393 | 
             
                                  task flag, [:name, :message, :commit] do |_, args|
         | 
| 394 394 | 
             
                                    name = param_guard(action, flag, args: args, key: :name)
         | 
| @@ -519,7 +519,7 @@ module Squared | |
| 519 519 | 
             
                                  end
         | 
| 520 520 | 
             
                                when :delete
         | 
| 521 521 | 
             
                                  format_desc action, flag, '(^~)name+'
         | 
| 522 | 
            -
                                  task flag | 
| 522 | 
            +
                                  task flag do |_, args|
         | 
| 523 523 | 
             
                                    refs = param_guard(action, flag, args: args.to_a)
         | 
| 524 524 | 
             
                                    branch(flag, refs: refs)
         | 
| 525 525 | 
             
                                  end
         | 
| @@ -686,27 +686,28 @@ module Squared | |
| 686 686 | 
             
                    end
         | 
| 687 687 |  | 
| 688 688 | 
             
                    def depend(*, **)
         | 
| 689 | 
            -
                      workspace.rev_clear | 
| 689 | 
            +
                      workspace.rev_clear(name)
         | 
| 690 690 | 
             
                      super
         | 
| 691 691 | 
             
                    end
         | 
| 692 692 |  | 
| 693 693 | 
             
                    def clean(*, **)
         | 
| 694 | 
            -
                      workspace.rev_clear | 
| 694 | 
            +
                      workspace.rev_clear(name)
         | 
| 695 695 | 
             
                      super
         | 
| 696 696 | 
             
                    end
         | 
| 697 697 |  | 
| 698 698 | 
             
                    def pull(flag = nil, opts = [], sync: invoked_sync?('pull', flag), remote: nil)
         | 
| 699 | 
            -
                      cmd, opts = git_session('pull',  | 
| 699 | 
            +
                      cmd, opts = git_session('pull', opts: opts)
         | 
| 700 700 | 
             
                      if flag == :rebase
         | 
| 701 | 
            -
                        cmd << '-- | 
| 701 | 
            +
                        cmd << '--rebase'
         | 
| 702 702 | 
             
                      elsif (val = option('rebase', ignore: false))
         | 
| 703 703 | 
             
                        cmd << case val
         | 
| 704 | 
            -
                               when '0'
         | 
| 704 | 
            +
                               when '0', 'false'
         | 
| 705 705 | 
             
                                 '--no-rebase'
         | 
| 706 706 | 
             
                               else
         | 
| 707 707 | 
             
                                 VAL_GIT[:rebase][:value].include?(val) ? basic_option('rebase', val) : '--rebase'
         | 
| 708 708 | 
             
                               end
         | 
| 709 709 | 
             
                      end
         | 
| 710 | 
            +
                      cmd << '--autostash' if option('autostash')
         | 
| 710 711 | 
             
                      append_pull(opts, OPT_GIT[:pull] + OPT_GIT[:fetch][:pull],
         | 
| 711 712 | 
             
                                  no: OPT_GIT[:no][:pull] + OPT_GIT[:no][:fetch][:pull], remote: remote, flag: flag)
         | 
| 712 713 | 
             
                      source(sync: sync, sub: if verbose
         | 
| @@ -724,15 +725,15 @@ module Squared | |
| 724 725 | 
             
                      cmd, opts = git_session('rebase', opts: opts)
         | 
| 725 726 | 
             
                      case flag
         | 
| 726 727 | 
             
                      when :branch
         | 
| 727 | 
            -
                         | 
| 728 | 
            -
                        case  | 
| 728 | 
            +
                        op = OptionPartition.new(opts, OPT_GIT[:rebase], cmd, project: self, no: OPT_GIT[:no][:rebase])
         | 
| 729 | 
            +
                        case op.size
         | 
| 729 730 | 
             
                        when 0
         | 
| 730 731 | 
             
                          append_head
         | 
| 731 732 | 
             
                        when 1, 2
         | 
| 732 | 
            -
                           | 
| 733 | 
            +
                          op.append(delim: true)
         | 
| 733 734 | 
             
                        else
         | 
| 734 | 
            -
                           | 
| 735 | 
            -
             | 
| 735 | 
            +
                          op.append(op.pop(2), delim: true)
         | 
| 736 | 
            +
                            .clear(pass: false)
         | 
| 736 737 | 
             
                        end
         | 
| 737 738 | 
             
                      when :onto
         | 
| 738 739 | 
             
                        return unless upstream
         | 
| @@ -751,10 +752,10 @@ module Squared | |
| 751 752 |  | 
| 752 753 | 
             
                    def fetch(flag = nil, opts = [], sync: invoked_sync?('fetch', flag), remote: nil)
         | 
| 753 754 | 
             
                      cmd, opts = git_session('fetch', opts: opts)
         | 
| 754 | 
            -
                       | 
| 755 | 
            -
             | 
| 756 | 
            -
                       | 
| 757 | 
            -
             | 
| 755 | 
            +
                      append_pull(opts, collect_hash(OPT_GIT[:fetch]), no: collect_hash(OPT_GIT[:no][:fetch]), remote: remote,
         | 
| 756 | 
            +
                                                                       flag: flag)
         | 
| 757 | 
            +
                      cmd << '--all' if !remote && !session_arg?('multiple') && option('all')
         | 
| 758 | 
            +
                      cmd << '--verbose' if verbose && !session_arg?('quiet')
         | 
| 758 759 | 
             
                      source(sync: sync, **threadargs)
         | 
| 759 760 | 
             
                    end
         | 
| 760 761 |  | 
| @@ -783,25 +784,25 @@ module Squared | |
| 783 784 | 
             
                    def stash(flag = nil, opts = [], sync: invoked_sync?('stash', flag))
         | 
| 784 785 | 
             
                      if flag
         | 
| 785 786 | 
             
                        cmd, opts = git_session('stash', flag, opts: opts)
         | 
| 786 | 
            -
                         | 
| 787 | 
            +
                        op = OptionPartition.new(opts, OPT_GIT[:stash][:common] + OPT_GIT[:stash].fetch(flag, []), cmd,
         | 
| 788 | 
            +
                                                 project: self)
         | 
| 787 789 | 
             
                        case flag
         | 
| 788 790 | 
             
                        when :push
         | 
| 789 | 
            -
                          append_pathspec  | 
| 791 | 
            +
                          append_pathspec op.extras
         | 
| 790 792 | 
             
                        when :pop, :apply, :drop
         | 
| 791 | 
            -
                          unless  | 
| 792 | 
            -
                             | 
| 793 | 
            -
                             | 
| 793 | 
            +
                          unless op.empty?
         | 
| 794 | 
            +
                            op << shell_escape(op.pop)
         | 
| 795 | 
            +
                            op.clear
         | 
| 794 796 | 
             
                          end
         | 
| 795 797 | 
             
                        when :clear
         | 
| 796 | 
            -
                          if confirm("Remove #{sub_style('all', styles: theme[:active])}  | 
| 798 | 
            +
                          if confirm("Remove #{sub_style('all', styles: theme[:active])} stash entries? [y/N] ", 'N')
         | 
| 797 799 | 
             
                            source(stdout: true)
         | 
| 798 800 | 
             
                          end
         | 
| 799 801 | 
             
                          return
         | 
| 800 802 | 
             
                        when :list
         | 
| 801 803 | 
             
                          out, banner, from = source(io: true)
         | 
| 802 804 | 
             
                          print_item banner
         | 
| 803 | 
            -
                           | 
| 804 | 
            -
                          list_result(ret, 'objects', from: from)
         | 
| 805 | 
            +
                          list_result(write_lines(out), 'objects', from: from)
         | 
| 805 806 | 
             
                          return
         | 
| 806 807 | 
             
                        end
         | 
| 807 808 | 
             
                      else
         | 
| @@ -861,18 +862,19 @@ module Squared | |
| 861 862 | 
             
                      sha = git_spawn('rev-parse --verify HEAD').first.to_s.chomp
         | 
| 862 863 | 
             
                      return if sha.empty?
         | 
| 863 864 |  | 
| 864 | 
            -
                      args = []
         | 
| 865 865 | 
             
                      kwargs = kwargs.key?(:include) || kwargs.key?(:exclude) ? statusargs.() : @revbuild || {}
         | 
| 866 866 | 
             
                      case flag
         | 
| 867 867 | 
             
                      when :build
         | 
| 868 | 
            -
                         | 
| 869 | 
            -
                         | 
| 868 | 
            +
                        op = OptionPartition.new(opts, OPT_GIT[:status], project: self)
         | 
| 869 | 
            +
                        op.clear(append: true)
         | 
| 870 | 
            +
                        args = op.to_a
         | 
| 870 871 | 
             
                      else
         | 
| 872 | 
            +
                        args = []
         | 
| 871 873 | 
             
                        args << basic_option('untracked-files', flag) if (flag = option('untracked-files', prefix: 'git'))
         | 
| 872 874 | 
             
                        args << basic_option('ignore-submodules', flag) if (flag = option('ignore-submodules', prefix: 'git'))
         | 
| 873 875 | 
             
                        args << basic_option('ignored', flag) if (flag = option('ignored', prefix: 'git'))
         | 
| 874 876 | 
             
                      end
         | 
| 875 | 
            -
                      if (cur = workspace.rev_entry(name)) && cur['revision'] == sha
         | 
| 877 | 
            +
                      if (cur = workspace.rev_entry(name)) && cur['revision'] == sha && !env('REVBUILD_FORCE')
         | 
| 876 878 | 
             
                        files = status_digest(*args, **kwargs)
         | 
| 877 879 | 
             
                        if cur['files'].size == files.size && cur['files'].find { |key, val| files[key] != val }.nil?
         | 
| 878 880 | 
             
                          if verbose
         | 
| @@ -901,13 +903,14 @@ module Squared | |
| 901 903 | 
             
                      cmd, opts = git_session('reset', opts: opts)
         | 
| 902 904 | 
             
                      case flag
         | 
| 903 905 | 
             
                      when :commit, :index
         | 
| 904 | 
            -
                         | 
| 906 | 
            +
                        op = OptionPartition.new(opts, OPT_GIT[:reset] + VAL_GIT[:reset], cmd,
         | 
| 907 | 
            +
                                                 project: self, no: OPT_GIT[:no][:reset])
         | 
| 905 908 | 
             
                        if flag == :commit
         | 
| 906 | 
            -
                           | 
| 907 | 
            -
             | 
| 909 | 
            +
                          op.append(commit, delim: true)
         | 
| 910 | 
            +
                            .clear(pass: false)
         | 
| 908 911 | 
             
                          ref = false
         | 
| 909 912 | 
             
                        else
         | 
| 910 | 
            -
                          (refs ||= []).concat( | 
| 913 | 
            +
                          (refs ||= []).concat(op.extras)
         | 
| 911 914 | 
             
                        end
         | 
| 912 915 | 
             
                      when :mode
         | 
| 913 916 | 
             
                        return unless VAL_GIT[:reset].include?(mode)
         | 
| @@ -919,8 +922,6 @@ module Squared | |
| 919 922 | 
             
                        end
         | 
| 920 923 | 
             
                      when :patch
         | 
| 921 924 | 
             
                        cmd << '--patch'
         | 
| 922 | 
            -
                      else
         | 
| 923 | 
            -
                        return
         | 
| 924 925 | 
             
                      end
         | 
| 925 926 | 
             
                      unless ref == false
         | 
| 926 927 | 
             
                        append_commit(ref, head: true)
         | 
| @@ -949,13 +950,13 @@ module Squared | |
| 949 950 | 
             
                      when :detach
         | 
| 950 951 | 
             
                        cmd << '--detach' << commit
         | 
| 951 952 | 
             
                      else
         | 
| 952 | 
            -
                         | 
| 953 | 
            +
                        op = OptionPartition.new(opts, OPT_GIT[:checkout], cmd, project: self, no: OPT_GIT[:no][:checkout])
         | 
| 953 954 | 
             
                        if flag == :commit
         | 
| 954 | 
            -
                           | 
| 955 | 
            -
             | 
| 955 | 
            +
                          op.append(commit, delim: true)
         | 
| 956 | 
            +
                            .clear(pass: false)
         | 
| 956 957 | 
             
                        else
         | 
| 957 958 | 
             
                          append_head
         | 
| 958 | 
            -
                          append_pathspec  | 
| 959 | 
            +
                          append_pathspec op.extras
         | 
| 959 960 | 
             
                        end
         | 
| 960 961 | 
             
                      end
         | 
| 961 962 | 
             
                      source
         | 
| @@ -964,12 +965,13 @@ module Squared | |
| 964 965 | 
             
                    def tag(flag, opts = [], refs: [], message: nil, commit: nil)
         | 
| 965 966 | 
             
                      cmd, opts = git_session('tag', opts: opts)
         | 
| 966 967 | 
             
                      case flag
         | 
| 967 | 
            -
                      when :add
         | 
| 968 | 
            -
                        if option('sign')
         | 
| 968 | 
            +
                      when :add, :sign
         | 
| 969 | 
            +
                        if flag == :sign || option('sign')
         | 
| 969 970 | 
             
                          cmd << '--sign'
         | 
| 970 971 | 
             
                        elsif !session_arg?('s', 'sign', 'u', 'local-user')
         | 
| 971 972 | 
             
                          cmd << '--annotate'
         | 
| 972 973 | 
             
                        end
         | 
| 974 | 
            +
                        cmd << '--force' if option('force')
         | 
| 973 975 | 
             
                        if !commit && message && (sha = commithash(message))
         | 
| 974 976 | 
             
                          commit = sha
         | 
| 975 977 | 
             
                        else
         | 
| @@ -978,12 +980,11 @@ module Squared | |
| 978 980 | 
             
                        append_value refs
         | 
| 979 981 | 
             
                        append_head commit
         | 
| 980 982 | 
             
                      when :list
         | 
| 981 | 
            -
                        cmd << '--list'
         | 
| 982 | 
            -
                        grep = option_sanitize(opts, OPT_GIT[:tag], no: OPT_GIT[:no][:tag]).first
         | 
| 983 | 
            +
                        op = OptionPartition.new(opts, OPT_GIT[:tag], cmd << '--list', project: self, no: OPT_GIT[:no][:tag])
         | 
| 983 984 | 
             
                        out, banner, from = source(io: true)
         | 
| 984 985 | 
             
                        print_item banner
         | 
| 985 | 
            -
                        ret = write_lines(out, grep:  | 
| 986 | 
            -
                        list_result(ret, 'tags', from: from, grep:  | 
| 986 | 
            +
                        ret = write_lines(out, grep: op.extras)
         | 
| 987 | 
            +
                        list_result(ret, 'tags', from: from, grep: op.extras)
         | 
| 987 988 | 
             
                        return
         | 
| 988 989 | 
             
                      when :delete
         | 
| 989 990 | 
             
                        cmd << '--delete'
         | 
| @@ -996,55 +997,56 @@ module Squared | |
| 996 997 |  | 
| 997 998 | 
             
                    def logx(flag, opts = [], range: [], index: [])
         | 
| 998 999 | 
             
                      cmd, opts = git_session('log', opts: opts)
         | 
| 999 | 
            -
                       | 
| 1000 | 
            +
                      op = OptionPartition.new(opts, collect_hash(OPT_GIT[:log]), cmd,
         | 
| 1001 | 
            +
                                               project: self, no: collect_hash(OPT_GIT[:no][:log]))
         | 
| 1000 1002 | 
             
                      case flag
         | 
| 1001 1003 | 
             
                      when :between, :contain
         | 
| 1002 | 
            -
                         | 
| 1004 | 
            +
                        op << shell_quote(range.join(flag == :between ? '..' : '...'))
         | 
| 1003 1005 | 
             
                      else
         | 
| 1004 | 
            -
                         | 
| 1006 | 
            +
                        op.merge(index)
         | 
| 1005 1007 | 
             
                      end
         | 
| 1006 1008 | 
             
                      append_nocolor
         | 
| 1007 | 
            -
                      append_pathspec  | 
| 1009 | 
            +
                      append_pathspec op.extras
         | 
| 1008 1010 | 
             
                      source(exception: false)
         | 
| 1009 1011 | 
             
                    end
         | 
| 1010 1012 |  | 
| 1011 1013 | 
             
                    def diff(flag, opts = [], refs: [], branch: nil, range: [], index: [])
         | 
| 1012 1014 | 
             
                      cmd, opts = git_session('diff', opts: opts)
         | 
| 1013 | 
            -
                       | 
| 1014 | 
            -
             | 
| 1015 | 
            +
                      op = OptionPartition.new(opts, collect_hash(OPT_GIT[:diff]) + OPT_GIT[:log][:diff], cmd,
         | 
| 1016 | 
            +
                                               project: self, no: OPT_GIT[:no][:log][:diff])
         | 
| 1015 1017 | 
             
                      case flag
         | 
| 1016 1018 | 
             
                      when :files, :view, :between, :contain
         | 
| 1017 | 
            -
                         | 
| 1019 | 
            +
                        op.delete('--cached')
         | 
| 1018 1020 | 
             
                      end
         | 
| 1019 1021 | 
             
                      append_nocolor
         | 
| 1020 1022 | 
             
                      if flag == :files
         | 
| 1021 | 
            -
                         | 
| 1023 | 
            +
                        op << '--no-index'
         | 
| 1022 1024 | 
             
                        append_pathspec(refs, parent: true)
         | 
| 1023 1025 | 
             
                      else
         | 
| 1024 1026 | 
             
                        case flag
         | 
| 1025 1027 | 
             
                        when :view
         | 
| 1026 | 
            -
                           | 
| 1027 | 
            -
                           | 
| 1028 | 
            +
                          op << '--merge-base' if option('merge-base')
         | 
| 1029 | 
            +
                          op << shell_quote(range.first, quote: true) << shell_quote(range.last, quote: true)
         | 
| 1028 1030 | 
             
                        when :between, :contain
         | 
| 1029 | 
            -
                           | 
| 1030 | 
            -
                           | 
| 1031 | 
            +
                          op.delete('--merge-base')
         | 
| 1032 | 
            +
                          op << shell_quote(range.join(flag == :between ? '..' : '...'))
         | 
| 1031 1033 | 
             
                        else
         | 
| 1032 | 
            -
                           | 
| 1033 | 
            -
                           | 
| 1034 | 
            +
                          op << '--merge-base' if option('merge-base')
         | 
| 1035 | 
            +
                          op << shell_quote(branch) if branch
         | 
| 1034 1036 | 
             
                          if !index.empty?
         | 
| 1035 | 
            -
                            if  | 
| 1037 | 
            +
                            if op.arg?('cached')
         | 
| 1036 1038 | 
             
                              raise_error("one commit only: #{index.join(', ')}", hint: '--cached') if index.size > 1
         | 
| 1037 | 
            -
                               | 
| 1039 | 
            +
                              op << index.first
         | 
| 1038 1040 | 
             
                            else
         | 
| 1039 | 
            -
                               | 
| 1041 | 
            +
                              op.merge(index)
         | 
| 1040 1042 | 
             
                            end
         | 
| 1041 1043 | 
             
                          elsif (n = option('index', ignore: false))
         | 
| 1042 | 
            -
                             | 
| 1044 | 
            +
                            op << "HEAD~#{n}"
         | 
| 1043 1045 | 
             
                          end
         | 
| 1044 1046 | 
             
                        end
         | 
| 1045 | 
            -
                        append_pathspec  | 
| 1047 | 
            +
                        append_pathspec op.extras
         | 
| 1046 1048 | 
             
                      end
         | 
| 1047 | 
            -
                      source(exception:  | 
| 1049 | 
            +
                      source(exception: op.arg?('exit-code'))
         | 
| 1048 1050 | 
             
                    end
         | 
| 1049 1051 |  | 
| 1050 1052 | 
             
                    def commit(flag, *, refs: [], message: nil, pass: false)
         | 
| @@ -1119,10 +1121,10 @@ module Squared | |
| 1119 1121 | 
             
                      cmd, opts = git_session('merge', opts: opts)
         | 
| 1120 1122 | 
             
                      case flag
         | 
| 1121 1123 | 
             
                      when :commit, :'no-commit'
         | 
| 1122 | 
            -
                         | 
| 1123 | 
            -
                        raise_error 'no branch/commit' if  | 
| 1124 | 
            -
                         | 
| 1125 | 
            -
                        append_commit(* | 
| 1124 | 
            +
                        op = OptionPartition.new(opts, OPT_GIT[:merge], cmd, project: self, no: OPT_GIT[:no][:merge])
         | 
| 1125 | 
            +
                        raise_error 'no branch/commit' if op.empty?
         | 
| 1126 | 
            +
                        op << "--#{flag}" << '--'
         | 
| 1127 | 
            +
                        append_commit(*op.extras)
         | 
| 1126 1128 | 
             
                      else
         | 
| 1127 1129 | 
             
                        return unless VAL_GIT[:merge][:send].include?(command)
         | 
| 1128 1130 |  | 
| @@ -1138,7 +1140,7 @@ module Squared | |
| 1138 1140 | 
             
                      when :create
         | 
| 1139 1141 | 
             
                        if (arg = option('track', ignore: false))
         | 
| 1140 1142 | 
             
                          cmd << case arg
         | 
| 1141 | 
            -
                                 when '0'
         | 
| 1143 | 
            +
                                 when '0', 'false'
         | 
| 1142 1144 | 
             
                                   '--no-track'
         | 
| 1143 1145 | 
             
                                 when 'direct', 'inherit'
         | 
| 1144 1146 | 
             
                                   basic_option('track', arg)
         | 
| @@ -1151,7 +1153,7 @@ module Squared | |
| 1151 1153 | 
             
                        return unless ref
         | 
| 1152 1154 |  | 
| 1153 1155 | 
             
                        if ref.start_with?('^')
         | 
| 1154 | 
            -
                          cmd << '--unset-upstream' << shell_escape( | 
| 1156 | 
            +
                          cmd << '--unset-upstream' << shell_escape(ref[1..-1])
         | 
| 1155 1157 | 
             
                          target = nil
         | 
| 1156 1158 | 
             
                          stdout = true
         | 
| 1157 1159 | 
             
                        else
         | 
| @@ -1179,14 +1181,16 @@ module Squared | |
| 1179 1181 | 
             
                        cmd << '--edit-description'
         | 
| 1180 1182 | 
             
                      when :current
         | 
| 1181 1183 | 
             
                        cmd << '--show-current'
         | 
| 1184 | 
            +
                        source(banner: verbosetype > 1, stdout: true)
         | 
| 1185 | 
            +
                        return
         | 
| 1182 1186 | 
             
                      when :list
         | 
| 1183 | 
            -
                         | 
| 1184 | 
            -
             | 
| 1185 | 
            -
                         | 
| 1187 | 
            +
                        op = OptionPartition.new(opts, OPT_GIT[:branch], cmd << '--list',
         | 
| 1188 | 
            +
                                                 project: self, no: OPT_GIT[:no][:branch], single: /^v+$/)
         | 
| 1189 | 
            +
                        op.each { |val| op << shell_quote(val) }
         | 
| 1186 1190 | 
             
                        out, banner, from = source(io: true)
         | 
| 1187 1191 | 
             
                        print_item banner
         | 
| 1188 1192 | 
             
                        ret = write_lines(out, sub: [
         | 
| 1189 | 
            -
                          { pat: /^(\*\s+)(\S+)( | 
| 1193 | 
            +
                          { pat: /^(\*\s+)(\S+)(.*)$/, styles: color(:green), index: 2 },
         | 
| 1190 1194 | 
             
                          { pat: %r{^(\s*)(remotes/\S+)(.*)$}, styles: color(:red), index: 2 }
         | 
| 1191 1195 | 
             
                        ])
         | 
| 1192 1196 | 
             
                        list_result(ret, 'branches', from: from)
         | 
| @@ -1229,9 +1233,9 @@ module Squared | |
| 1229 1233 | 
             
                    end
         | 
| 1230 1234 |  | 
| 1231 1235 | 
             
                    def restore(flag, opts = [])
         | 
| 1232 | 
            -
                      opts = git_session('restore', "--#{flag}", opts: opts) | 
| 1233 | 
            -
                       | 
| 1234 | 
            -
                      append_pathspec( | 
| 1236 | 
            +
                      cmd, opts = git_session('restore', "--#{flag}", opts: opts)
         | 
| 1237 | 
            +
                      op = OptionPartition.new(opts, OPT_GIT[:restore], cmd, project: self, no: OPT_GIT[:no][:restore])
         | 
| 1238 | 
            +
                      append_pathspec(op.extras, pass: false)
         | 
| 1235 1239 | 
             
                      source(sync: false, stderr: true)
         | 
| 1236 1240 | 
             
                    end
         | 
| 1237 1241 |  | 
| @@ -1240,11 +1244,10 @@ module Squared | |
| 1240 1244 | 
             
                      case flag
         | 
| 1241 1245 | 
             
                      when :textconv
         | 
| 1242 1246 | 
             
                        cmd << '--textconv'
         | 
| 1243 | 
            -
                        files | 
| 1244 | 
            -
             | 
| 1245 | 
            -
             | 
| 1246 | 
            -
             | 
| 1247 | 
            -
                        append_value files
         | 
| 1247 | 
            +
                        append_value(files.map { |val| Dir[val] }
         | 
| 1248 | 
            +
                                          .flatten
         | 
| 1249 | 
            +
                                          .select { |val| projectpath?(val) }
         | 
| 1250 | 
            +
                                          .map! { |val| shell_quote("HEAD:#{val}") })
         | 
| 1248 1251 | 
             
                        source(banner: false)
         | 
| 1249 1252 | 
             
                        return
         | 
| 1250 1253 | 
             
                      when :oneline
         | 
| @@ -1262,13 +1265,14 @@ module Squared | |
| 1262 1265 | 
             
                          end
         | 
| 1263 1266 | 
             
                        end
         | 
| 1264 1267 | 
             
                      end
         | 
| 1265 | 
            -
                       | 
| 1266 | 
            -
             | 
| 1267 | 
            -
             | 
| 1268 | 
            -
             | 
| 1268 | 
            +
                      op = OptionPartition.new(opts, OPT_GIT[:show] + OPT_GIT[:diff][:show] + OPT_GIT[:log][:diff], cmd,
         | 
| 1269 | 
            +
                                               project: self,
         | 
| 1270 | 
            +
                                               no: OPT_GIT[:no][:show] + collect_hash(OPT_GIT[:no][:log], pass: [:base]))
         | 
| 1271 | 
            +
                      unless val == 'oneline' && op.arg?('abbrev-commit')
         | 
| 1272 | 
            +
                        op << basic_option('abbrev', val) if (val = option('abbrev')) && val.to_i > 0
         | 
| 1269 1273 | 
             
                        banner = true
         | 
| 1270 1274 | 
             
                      end
         | 
| 1271 | 
            -
                       | 
| 1275 | 
            +
                      op.append(delim: true)
         | 
| 1272 1276 | 
             
                      source(exception: false, banner: banner)
         | 
| 1273 1277 | 
             
                    end
         | 
| 1274 1278 |  | 
| @@ -1287,60 +1291,60 @@ module Squared | |
| 1287 1291 | 
             
                        cmd << '--abbrev-ref'
         | 
| 1288 1292 | 
             
                        append_commit(ref, head: true)
         | 
| 1289 1293 | 
             
                      else
         | 
| 1290 | 
            -
                         | 
| 1291 | 
            -
                         | 
| 1294 | 
            +
                        op = OptionPartition.new(opts, OPT_GIT[:rev_parse][flag], cmd, project: self)
         | 
| 1295 | 
            +
                        op.append(escape: op.arg?('sq-quote'))
         | 
| 1292 1296 | 
             
                      end
         | 
| 1293 | 
            -
                      source(banner:  | 
| 1297 | 
            +
                      source(banner: verbosetype > 1)
         | 
| 1294 1298 | 
             
                    end
         | 
| 1295 1299 |  | 
| 1296 1300 | 
             
                    def ls_remote(flag, opts = [], remote: nil)
         | 
| 1297 1301 | 
             
                      cmd, opts = git_session('ls-remote', '--refs', opts: opts)
         | 
| 1298 1302 | 
             
                      cmd << "--#{flag}" unless flag == :remote
         | 
| 1299 | 
            -
                       | 
| 1300 | 
            -
                       | 
| 1303 | 
            +
                      op = OptionPartition.new(opts, OPT_GIT[:ls_remote], cmd, project: self)
         | 
| 1304 | 
            +
                      op << shell_quote(remote) if remote
         | 
| 1301 1305 | 
             
                      out, banner, from = source(io: true)
         | 
| 1302 1306 | 
             
                      print_item banner
         | 
| 1303 | 
            -
                      ret = write_lines(out, grep:  | 
| 1304 | 
            -
                      list_result(ret, flag.to_s, from: from, grep:  | 
| 1307 | 
            +
                      ret = write_lines(out, grep: op.extras)
         | 
| 1308 | 
            +
                      list_result(ret, flag.to_s, from: from, grep: op.extras)
         | 
| 1305 1309 | 
             
                    end
         | 
| 1306 1310 |  | 
| 1307 1311 | 
             
                    def ls_files(flag, opts = [])
         | 
| 1308 | 
            -
                      opts = git_session('ls-files', "--#{flag}", opts: opts) | 
| 1309 | 
            -
                       | 
| 1312 | 
            +
                      cmd, opts = git_session('ls-files', "--#{flag}", opts: opts)
         | 
| 1313 | 
            +
                      op = OptionPartition.new(opts, OPT_GIT[:ls_files], cmd, project: self)
         | 
| 1310 1314 | 
             
                      out, banner, from = source(io: true)
         | 
| 1311 1315 | 
             
                      print_item banner
         | 
| 1312 | 
            -
                      ret = write_lines(out, grep:  | 
| 1313 | 
            -
                      list_result(ret, 'files', from: from, grep:  | 
| 1316 | 
            +
                      ret = write_lines(out, grep: op.extras)
         | 
| 1317 | 
            +
                      list_result(ret, 'files', from: from, grep: op.extras)
         | 
| 1314 1318 | 
             
                    end
         | 
| 1315 1319 |  | 
| 1316 1320 | 
             
                    def git(flag, opts = [])
         | 
| 1317 1321 | 
             
                      cmd, opts = git_session(flag, opts: opts)
         | 
| 1318 | 
            -
                       | 
| 1322 | 
            +
                      op = OptionPartition.new(opts, OPT_GIT[flag], cmd, project: self, no: OPT_GIT[:no][flag])
         | 
| 1319 1323 | 
             
                      sync = false
         | 
| 1320 1324 | 
             
                      stderr = true
         | 
| 1321 1325 | 
             
                      case flag
         | 
| 1322 1326 | 
             
                      when :clean
         | 
| 1323 | 
            -
                        refs = projectmap( | 
| 1327 | 
            +
                        refs = projectmap(op.extras)
         | 
| 1324 1328 | 
             
                        unless refs.empty?
         | 
| 1325 | 
            -
                           | 
| 1326 | 
            -
                           | 
| 1329 | 
            +
                          op << '--'
         | 
| 1330 | 
            +
                          op.merge(refs)
         | 
| 1327 1331 | 
             
                        end
         | 
| 1328 1332 | 
             
                        sync = true
         | 
| 1329 1333 | 
             
                        stderr = false
         | 
| 1330 1334 | 
             
                      when :revert
         | 
| 1331 | 
            -
                        if VAL_GIT[:rebase][:send].any? { |val|  | 
| 1332 | 
            -
                           | 
| 1333 | 
            -
                        elsif  | 
| 1335 | 
            +
                        if VAL_GIT[:rebase][:send].any? { |val| op.arg?(val) }
         | 
| 1336 | 
            +
                          op.clear
         | 
| 1337 | 
            +
                        elsif op.empty?
         | 
| 1334 1338 | 
             
                          raise_error 'no commit given'
         | 
| 1335 1339 | 
             
                        else
         | 
| 1336 | 
            -
                          append_commit(* | 
| 1340 | 
            +
                          append_commit(*op.extras)
         | 
| 1337 1341 | 
             
                        end
         | 
| 1338 1342 | 
             
                      when :mv
         | 
| 1339 | 
            -
                        refs = projectmap( | 
| 1343 | 
            +
                        refs = projectmap(op.extras)
         | 
| 1340 1344 | 
             
                        raise_error 'no source/destination' unless refs.size > 1
         | 
| 1341 | 
            -
                         | 
| 1345 | 
            +
                        op.merge(refs)
         | 
| 1342 1346 | 
             
                      when :rm
         | 
| 1343 | 
            -
                        append_pathspec( | 
| 1347 | 
            +
                        append_pathspec(op.extras, expect: true)
         | 
| 1344 1348 | 
             
                      end
         | 
| 1345 1349 | 
             
                      source(sync: sync, stderr: stderr)
         | 
| 1346 1350 | 
             
                    end
         | 
| @@ -1471,15 +1475,13 @@ module Squared | |
| 1471 1475 | 
             
                      glob = kwargs.fetch(:include, [])
         | 
| 1472 1476 | 
             
                      pass = kwargs.fetch(:exclude, [])
         | 
| 1473 1477 | 
             
                      ret = {}
         | 
| 1474 | 
            -
                      git_spawn('status -s --porcelain', *args, stdout: false)
         | 
| 1475 | 
            -
                         | 
| 1476 | 
            -
                        . | 
| 1477 | 
            -
             | 
| 1478 | 
            -
             | 
| 1479 | 
            -
             | 
| 1480 | 
            -
             | 
| 1481 | 
            -
                          ret[file] = algorithm.hexdigest(File.read(basepath(file)))
         | 
| 1482 | 
            -
                        end
         | 
| 1478 | 
            +
                      git_spawn('status -s --porcelain', *args, stdout: false).first.each do |line|
         | 
| 1479 | 
            +
                        next unless (file = line[/^[A-Z ?!]{3}"?(.+?)"?$/, 1])
         | 
| 1480 | 
            +
                        next if !glob.empty? && glob.none? { |val| File.fnmatch?(val, file, File::FNM_DOTMATCH) }
         | 
| 1481 | 
            +
                        next if !pass.empty? && pass.any? { |val| File.fnmatch?(val, file, File::FNM_DOTMATCH) }
         | 
| 1482 | 
            +
             | 
| 1483 | 
            +
                        ret[file] = algorithm.hexdigest(File.read(basepath(file)))
         | 
| 1484 | 
            +
                      end
         | 
| 1483 1485 | 
             
                      ret
         | 
| 1484 1486 | 
             
                    end
         | 
| 1485 1487 |  | 
| @@ -1487,43 +1489,44 @@ module Squared | |
| 1487 1489 | 
             
                      source(git_output(*cmd), io: true, banner: false, stdout: stdout)
         | 
| 1488 1490 | 
             
                    end
         | 
| 1489 1491 |  | 
| 1490 | 
            -
                    def append_pull(opts, list, target: @session,  | 
| 1491 | 
            -
                       | 
| 1492 | 
            -
                       | 
| 1493 | 
            -
                      out = []
         | 
| 1492 | 
            +
                    def append_pull(opts, list, target: @session, flag: nil, no: nil, remote: nil)
         | 
| 1493 | 
            +
                      target << '--force' if option('force', target: target)
         | 
| 1494 | 
            +
                      append_submodules(target: target)
         | 
| 1494 1495 | 
             
                      refspec = []
         | 
| 1495 | 
            -
                       | 
| 1496 | 
            -
                       | 
| 1497 | 
            -
                        if opt =~  | 
| 1496 | 
            +
                      op = OptionPartition.new(opts, remote ? list + ['refspec=v'] : list, target, project: self, no: no)
         | 
| 1497 | 
            +
                      op.each do |opt|
         | 
| 1498 | 
            +
                        if opt =~ op.values
         | 
| 1498 1499 | 
             
                          case $1
         | 
| 1499 1500 | 
             
                          when 'rebase'
         | 
| 1500 | 
            -
                             | 
| 1501 | 
            +
                            op << basic_option($1, $2) if VAL_GIT[:rebase][:value].include?($2)
         | 
| 1501 1502 | 
             
                          when 'shallow-since'
         | 
| 1502 1503 | 
             
                            next unless (val = Date.parse($2))
         | 
| 1503 1504 |  | 
| 1504 | 
            -
                             | 
| 1505 | 
            +
                            op << quote_option($1, val.strftime('%F %T'))
         | 
| 1505 1506 | 
             
                          when 'recurse-submodules'
         | 
| 1506 | 
            -
                             | 
| 1507 | 
            +
                            op << basic_option($1, $2) unless op.arg?('recurse-submodules')
         | 
| 1507 1508 | 
             
                          when 'refspec'
         | 
| 1508 1509 | 
             
                            refspec << shell_escape($2, quote: true)
         | 
| 1509 1510 | 
             
                          end
         | 
| 1511 | 
            +
                        elsif op.arg?('--multiple')
         | 
| 1512 | 
            +
                          op.found << opt
         | 
| 1510 1513 | 
             
                        else
         | 
| 1511 | 
            -
                           | 
| 1514 | 
            +
                          op.errors << opt
         | 
| 1512 1515 | 
             
                        end
         | 
| 1513 1516 | 
             
                      end
         | 
| 1514 1517 | 
             
                      if remote
         | 
| 1515 | 
            -
                         | 
| 1516 | 
            -
                        if (val = option('refspec', strict: true))
         | 
| 1517 | 
            -
                           | 
| 1518 | 
            +
                        op.append(remote, delim: true)
         | 
| 1519 | 
            +
                        if (val = option('refspec', target: target, strict: true))
         | 
| 1520 | 
            +
                          op.append(*split_escape(val))
         | 
| 1518 1521 | 
             
                        else
         | 
| 1519 | 
            -
                           | 
| 1522 | 
            +
                          op.merge(refspec)
         | 
| 1520 1523 | 
             
                        end
         | 
| 1521 | 
            -
                         | 
| 1522 | 
            -
                      elsif  | 
| 1523 | 
            -
                         | 
| 1524 | 
            -
                         | 
| 1524 | 
            +
                        op.delete('--all')
         | 
| 1525 | 
            +
                      elsif op.arg?('--multiple')
         | 
| 1526 | 
            +
                        op.swap.merge(op.map! { |opt| shell_escape(opt, quote: true) })
         | 
| 1527 | 
            +
                        return
         | 
| 1525 1528 | 
             
                      end
         | 
| 1526 | 
            -
                       | 
| 1529 | 
            +
                      op.clear(errors: true, subject: flag.to_s) if flag
         | 
| 1527 1530 | 
             
                    end
         | 
| 1528 1531 |  | 
| 1529 1532 | 
             
                    def append_commit(*val, target: @session, head: false)
         | 
| @@ -1536,10 +1539,10 @@ module Squared | |
| 1536 1539 | 
             
                    end
         | 
| 1537 1540 |  | 
| 1538 1541 | 
             
                    def append_pathspec(files = [], target: @session, expect: false, parent: false, pass: true)
         | 
| 1539 | 
            -
                      if session_arg?('pathspec-from-file')
         | 
| 1542 | 
            +
                      if session_arg?('pathspec-from-file', target: target)
         | 
| 1540 1543 | 
             
                        option_clear files
         | 
| 1541 1544 | 
             
                      else
         | 
| 1542 | 
            -
                        if files.empty? && (val = option('pathspec'))
         | 
| 1545 | 
            +
                        if files.empty? && (val = option('pathspec', target: target))
         | 
| 1543 1546 | 
             
                          files = split_escape(val)
         | 
| 1544 1547 | 
             
                        end
         | 
| 1545 1548 | 
             
                        files = projectmap(files, parent: parent, pass: pass)
         | 
| @@ -1562,7 +1565,7 @@ module Squared | |
| 1562 1565 | 
             
                    end
         | 
| 1563 1566 |  | 
| 1564 1567 | 
             
                    def append_submodules(from = nil, target: @session)
         | 
| 1565 | 
            -
                      return unless (val = option('recurse-submodules', ignore: false))
         | 
| 1568 | 
            +
                      return unless (val = option('recurse-submodules', target: target, ignore: false))
         | 
| 1566 1569 |  | 
| 1567 1570 | 
             
                      if from == :clone
         | 
| 1568 1571 | 
             
                        projectmap(split_escape(val)).each do |path|
         | 
| @@ -1571,7 +1574,7 @@ module Squared | |
| 1571 1574 | 
             
                        target
         | 
| 1572 1575 | 
             
                      else
         | 
| 1573 1576 | 
             
                        target << case val
         | 
| 1574 | 
            -
                                  when 'no', '0'
         | 
| 1577 | 
            +
                                  when 'no', '0', 'false'
         | 
| 1575 1578 | 
             
                                    '--no-recurse-submodules'
         | 
| 1576 1579 | 
             
                                  when 'yes', 'on-demand'
         | 
| 1577 1580 | 
             
                                    "--recurse-submodules#{from == :reset ? '' : "=#{val}"}"
         | 
| @@ -1585,9 +1588,9 @@ module Squared | |
| 1585 1588 | 
             
                      dir = worktree ? ["--work-tree=#{shell_quote(path)}", "--git-dir=#{shell_quote(gitpath)}"] : []
         | 
| 1586 1589 | 
             
                      return session('git', *dir, *cmd, **kwargs) unless opts
         | 
| 1587 1590 |  | 
| 1588 | 
            -
                       | 
| 1589 | 
            -
                      ret = session('git', * | 
| 1590 | 
            -
                      [ret,  | 
| 1591 | 
            +
                      op = OptionPartition.new(opts, OPT_GIT[:common], dir, project: self)
         | 
| 1592 | 
            +
                      ret = session('git', *op.to_a, *cmd, **kwargs)
         | 
| 1593 | 
            +
                      [ret, op.extras]
         | 
| 1591 1594 | 
             
                    end
         | 
| 1592 1595 |  | 
| 1593 1596 | 
             
                    def git_output(*cmd, **kwargs)
         | 
| @@ -1595,13 +1598,15 @@ module Squared | |
| 1595 1598 | 
             
                    end
         | 
| 1596 1599 |  | 
| 1597 1600 | 
             
                    def dryrun?(*, target: @session, **)
         | 
| 1598 | 
            -
                       | 
| 1601 | 
            +
                      return false unless target
         | 
| 1602 | 
            +
             | 
| 1603 | 
            +
                      target.include?('--dry-run')
         | 
| 1599 1604 | 
             
                    end
         | 
| 1600 1605 |  | 
| 1601 1606 | 
             
                    def quiet?(target: @session)
         | 
| 1602 1607 | 
             
                      return false unless target
         | 
| 1603 1608 |  | 
| 1604 | 
            -
                      target.include?('--quiet') || (target.include?('-q') && target.first == 'git')
         | 
| 1609 | 
            +
                      target.include?('--quiet') || (target.include?('-q') && stripext(target.first) == 'git')
         | 
| 1605 1610 | 
             
                    end
         | 
| 1606 1611 |  | 
| 1607 1612 | 
             
                    def gitpath
         |