m-git 2.5.4
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/LICENSE +21 -0
 - data/README.md +85 -0
 - data/lib/m-git.rb +66 -0
 - data/lib/m-git/argv.rb +170 -0
 - data/lib/m-git/argv/opt.rb +38 -0
 - data/lib/m-git/argv/opt_list.rb +71 -0
 - data/lib/m-git/argv/parser.rb +66 -0
 - data/lib/m-git/base_command.rb +271 -0
 - data/lib/m-git/command/add.rb +41 -0
 - data/lib/m-git/command/branch.rb +90 -0
 - data/lib/m-git/command/checkout.rb +106 -0
 - data/lib/m-git/command/clean.rb +64 -0
 - data/lib/m-git/command/commit.rb +84 -0
 - data/lib/m-git/command/config.rb +202 -0
 - data/lib/m-git/command/delete.rb +99 -0
 - data/lib/m-git/command/fetch.rb +32 -0
 - data/lib/m-git/command/forall.rb +81 -0
 - data/lib/m-git/command/info.rb +74 -0
 - data/lib/m-git/command/init.rb +324 -0
 - data/lib/m-git/command/log.rb +73 -0
 - data/lib/m-git/command/merge.rb +381 -0
 - data/lib/m-git/command/pull.rb +364 -0
 - data/lib/m-git/command/push.rb +311 -0
 - data/lib/m-git/command/rebase.rb +348 -0
 - data/lib/m-git/command/reset.rb +31 -0
 - data/lib/m-git/command/self.rb +223 -0
 - data/lib/m-git/command/stash.rb +189 -0
 - data/lib/m-git/command/status.rb +135 -0
 - data/lib/m-git/command/sync.rb +327 -0
 - data/lib/m-git/command/tag.rb +67 -0
 - data/lib/m-git/command_manager.rb +24 -0
 - data/lib/m-git/error.rb +20 -0
 - data/lib/m-git/foundation.rb +25 -0
 - data/lib/m-git/foundation/constants.rb +107 -0
 - data/lib/m-git/foundation/dir.rb +25 -0
 - data/lib/m-git/foundation/duration_recorder.rb +92 -0
 - data/lib/m-git/foundation/git_message_parser.rb +50 -0
 - data/lib/m-git/foundation/lock.rb +32 -0
 - data/lib/m-git/foundation/loger.rb +129 -0
 - data/lib/m-git/foundation/mgit_config.rb +222 -0
 - data/lib/m-git/foundation/operation_progress_manager.rb +139 -0
 - data/lib/m-git/foundation/timer.rb +74 -0
 - data/lib/m-git/foundation/utils.rb +361 -0
 - data/lib/m-git/hooks_manager.rb +96 -0
 - data/lib/m-git/manifest.rb +181 -0
 - data/lib/m-git/manifest/cache_manager.rb +44 -0
 - data/lib/m-git/manifest/internal.rb +182 -0
 - data/lib/m-git/manifest/light_repo.rb +108 -0
 - data/lib/m-git/manifest/light_repo_generator.rb +87 -0
 - data/lib/m-git/manifest/linter.rb +153 -0
 - data/lib/m-git/open_api.rb +427 -0
 - data/lib/m-git/open_api/script_download_info.rb +37 -0
 - data/lib/m-git/output/output.rb +461 -0
 - data/lib/m-git/plugin_manager.rb +112 -0
 - data/lib/m-git/repo.rb +133 -0
 - data/lib/m-git/repo/status.rb +481 -0
 - data/lib/m-git/repo/sync_helper.rb +254 -0
 - data/lib/m-git/template.rb +9 -0
 - data/lib/m-git/template/local_manifest.rb +27 -0
 - data/lib/m-git/template/manifest_hook.rb +28 -0
 - data/lib/m-git/template/post_download_hook.rb +29 -0
 - data/lib/m-git/template/post_hook.rb +31 -0
 - data/lib/m-git/template/pre_exec_hook.rb +31 -0
 - data/lib/m-git/template/pre_hook.rb +29 -0
 - data/lib/m-git/template/pre_push_hook.rb +32 -0
 - data/lib/m-git/version.rb +6 -0
 - data/lib/m-git/workspace.rb +648 -0
 - data/lib/m-git/workspace/path_helper.rb +56 -0
 - data/lib/m-git/workspace/workspace_helper.rb +159 -0
 - data/m-git +1 -0
 - data/mgit +19 -0
 - metadata +218 -0
 
| 
         @@ -0,0 +1,348 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            #coding=utf-8
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module MGit
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
              # @!scope 类似 git rebase
         
     | 
| 
      
 6 
     | 
    
         
            +
              #
         
     | 
| 
      
 7 
     | 
    
         
            +
              class Rebase < BaseCommand
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                PROGRESS_STAGE = {
         
     | 
| 
      
 10 
     | 
    
         
            +
                  :new_start          => 0,
         
     | 
| 
      
 11 
     | 
    
         
            +
                  :did_pull_config    => 1,
         
     | 
| 
      
 12 
     | 
    
         
            +
                  :did_refresh_config => 2,
         
     | 
| 
      
 13 
     | 
    
         
            +
                  :did_pull_sub       => 3
         
     | 
| 
      
 14 
     | 
    
         
            +
                }.freeze
         
     | 
| 
      
 15 
     | 
    
         
            +
                PROGRESS_STAGE_KEY = 'progress_stage'
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                PROGRESS_AUTO = 'auto_exec'
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                OPT_LIST = {
         
     | 
| 
      
 20 
     | 
    
         
            +
                  :pull      => '--pull'
         
     | 
| 
      
 21 
     | 
    
         
            +
                }.freeze
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                def options
         
     | 
| 
      
 24 
     | 
    
         
            +
                  [
         
     | 
| 
      
 25 
     | 
    
         
            +
                      ARGV::Opt.new(OPT_LIST[:pull], info:'可选参数,指定后在合并仓库前会拉取远程分支更新代码,如:"mgit rabase --pull"。', type: :boolean)
         
     | 
| 
      
 26 
     | 
    
         
            +
                  ].concat(super)
         
     | 
| 
      
 27 
     | 
    
         
            +
                end
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                def execute(argv)
         
     | 
| 
      
 30 
     | 
    
         
            +
                  return if do_abort(argv)
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
                  check_master_rebase(argv)
         
     | 
| 
      
 33 
     | 
    
         
            +
                  Workspace.check_branch_consistency
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
                  Output.puts_start_cmd
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
                  config_repo = generate_config_repo
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
                  if mgit_try_to_continue?
         
     | 
| 
      
 40 
     | 
    
         
            +
                    # 不处于中间态禁止执行
         
     | 
| 
      
 41 
     | 
    
         
            +
                    Foundation.help!("当前并不处于操作中间态,无法进行continue操作!") if !OperationProgressManager.is_in_progress?(Workspace.root, __progress_type)
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
                    # 读取指令缓存失败禁止执行
         
     | 
| 
      
 44 
     | 
    
         
            +
                    context, _ = OperationProgressManager.load_context(Workspace.root, __progress_type)
         
     | 
| 
      
 45 
     | 
    
         
            +
                    Foundation.help!("缓存指令读取失败,continue无法继续进行,请重新执行完整指令。") if context.nil? || !context.validate?
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
                    # 分支不匹配禁止执行
         
     | 
| 
      
 48 
     | 
    
         
            +
                    Foundation.help!("当前主仓库所在分支跟上次操作时所在分支(#{context.branch})不一致,请切换后重试。") if config_repo.status_checker.current_branch(use_cache:true) != context.branch
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
                    if !context.repos.nil?
         
     | 
| 
      
 51 
     | 
    
         
            +
                      Output.puts_processing_message("加载上次即将操作的子仓库...")
         
     | 
| 
      
 52 
     | 
    
         
            +
                      Workspace.update_all_repos(context.repos)
         
     | 
| 
      
 53 
     | 
    
         
            +
                    end
         
     | 
| 
      
 54 
     | 
    
         
            +
             
     | 
| 
      
 55 
     | 
    
         
            +
                    cmd = context.cmd
         
     | 
| 
      
 56 
     | 
    
         
            +
                    opts = context.opts
         
     | 
| 
      
 57 
     | 
    
         
            +
                    config_error = continue_execute(cmd, opts, config_repo, context.other[PROGRESS_STAGE_KEY], context.other[PROGRESS_AUTO])
         
     | 
| 
      
 58 
     | 
    
         
            +
                    if config_error
         
     | 
| 
      
 59 
     | 
    
         
            +
                      Output.puts_fail_block([config_repo.name], "主仓库操作失败:#{config_error}")
         
     | 
| 
      
 60 
     | 
    
         
            +
                      return
         
     | 
| 
      
 61 
     | 
    
         
            +
                    end
         
     | 
| 
      
 62 
     | 
    
         
            +
                  else
         
     | 
| 
      
 63 
     | 
    
         
            +
                    # 处于中间态则提示
         
     | 
| 
      
 64 
     | 
    
         
            +
                    if OperationProgressManager.is_in_progress?(Workspace.root, __progress_type)
         
     | 
| 
      
 65 
     | 
    
         
            +
                      if Output.continue_with_user_remind?("当前处于操作中间态,建议取消操作并执行\"mgit merge --continue\"继续操作未完成仓库。\n    继续执行将清除中间态并重新操作所有仓库,是否取消?")
         
     | 
| 
      
 66 
     | 
    
         
            +
                        Output.puts_cancel_message
         
     | 
| 
      
 67 
     | 
    
         
            +
                        return
         
     | 
| 
      
 68 
     | 
    
         
            +
                      end
         
     | 
| 
      
 69 
     | 
    
         
            +
                    end
         
     | 
| 
      
 70 
     | 
    
         
            +
             
     | 
| 
      
 71 
     | 
    
         
            +
                    cmd = argv.cmd
         
     | 
| 
      
 72 
     | 
    
         
            +
                    opts = argv.git_opts
         
     | 
| 
      
 73 
     | 
    
         
            +
             
     | 
| 
      
 74 
     | 
    
         
            +
                    # 优先操作配置仓库
         
     | 
| 
      
 75 
     | 
    
         
            +
                    config_error = rebase_config_repo(cmd, opts, config_repo, argv.opt_list.did_set_opt?(OPT_LIST[:pull]))
         
     | 
| 
      
 76 
     | 
    
         
            +
                    if config_error
         
     | 
| 
      
 77 
     | 
    
         
            +
                      Output.puts_fail_block([config_repo.name], "主仓库操作失败:#{config_error}")
         
     | 
| 
      
 78 
     | 
    
         
            +
                      return
         
     | 
| 
      
 79 
     | 
    
         
            +
                    end
         
     | 
| 
      
 80 
     | 
    
         
            +
                  end
         
     | 
| 
      
 81 
     | 
    
         
            +
             
     | 
| 
      
 82 
     | 
    
         
            +
                  do_repos = []
         
     | 
| 
      
 83 
     | 
    
         
            +
                  dirty_repos = []
         
     | 
| 
      
 84 
     | 
    
         
            +
                  detached_repos = []
         
     | 
| 
      
 85 
     | 
    
         
            +
                  no_tracking_repos = []
         
     | 
| 
      
 86 
     | 
    
         
            +
             
     | 
| 
      
 87 
     | 
    
         
            +
                  Output.puts_processing_message("检查各仓库状态...")
         
     | 
| 
      
 88 
     | 
    
         
            +
                  Workspace.serial_enumerate_with_progress(all_repos) { |repo|
         
     | 
| 
      
 89 
     | 
    
         
            +
                    next if !config_repo.nil? && repo.name == config_repo.name
         
     | 
| 
      
 90 
     | 
    
         
            +
             
     | 
| 
      
 91 
     | 
    
         
            +
                    status = repo.status_checker.status
         
     | 
| 
      
 92 
     | 
    
         
            +
                    branch_status = repo.status_checker.branch_status
         
     | 
| 
      
 93 
     | 
    
         
            +
             
     | 
| 
      
 94 
     | 
    
         
            +
                    if status == Repo::Status::GIT_REPO_STATUS[:clean] &&
         
     | 
| 
      
 95 
     | 
    
         
            +
                      branch_status != Repo::Status::GIT_BRANCH_STATUS[:detached] &&
         
     | 
| 
      
 96 
     | 
    
         
            +
                      branch_status != Repo::Status::GIT_BRANCH_STATUS[:no_tracking]
         
     | 
| 
      
 97 
     | 
    
         
            +
                      do_repos.push(repo)
         
     | 
| 
      
 98 
     | 
    
         
            +
                    else
         
     | 
| 
      
 99 
     | 
    
         
            +
                      if status == Repo::Status::GIT_REPO_STATUS[:dirty]
         
     | 
| 
      
 100 
     | 
    
         
            +
                        dirty_repos.push(repo)
         
     | 
| 
      
 101 
     | 
    
         
            +
                      end
         
     | 
| 
      
 102 
     | 
    
         
            +
                      if branch_status == Repo::Status::GIT_BRANCH_STATUS[:detached]
         
     | 
| 
      
 103 
     | 
    
         
            +
                        detached_repos.push(repo)
         
     | 
| 
      
 104 
     | 
    
         
            +
                      elsif branch_status == Repo::Status::GIT_BRANCH_STATUS[:no_tracking]
         
     | 
| 
      
 105 
     | 
    
         
            +
                        no_tracking_repos.push(repo)
         
     | 
| 
      
 106 
     | 
    
         
            +
                      end
         
     | 
| 
      
 107 
     | 
    
         
            +
                    end
         
     | 
| 
      
 108 
     | 
    
         
            +
                  }
         
     | 
| 
      
 109 
     | 
    
         
            +
                  Output.puts_success_message("检查完成!\n")
         
     | 
| 
      
 110 
     | 
    
         
            +
             
     | 
| 
      
 111 
     | 
    
         
            +
                  if dirty_repos.length > 0 || no_tracking_repos.length > 0 || detached_repos.length > 0
         
     | 
| 
      
 112 
     | 
    
         
            +
                    remind_repos = []
         
     | 
| 
      
 113 
     | 
    
         
            +
                    remind_repos.push(['有本地改动', dirty_repos.map { |e| e.name }])
         
     | 
| 
      
 114 
     | 
    
         
            +
                    remind_repos.push(['未追踪远程分支(建议:mgit branch -u origin/<branch>)', no_tracking_repos.map { |e| e.name }]) if no_tracking_repos.length > 0
         
     | 
| 
      
 115 
     | 
    
         
            +
                    remind_repos.push(['HEAD游离,当前不在任何分支上', detached_repos.map { |e| e.name }]) if detached_repos.length > 0
         
     | 
| 
      
 116 
     | 
    
         
            +
                    Output.interact_with_multi_selection_combined_repos(remind_repos, "以上仓库状态异常", ['a: 跳过并继续', 'b: 强制执行', 'c: 终止']) { |input|
         
     | 
| 
      
 117 
     | 
    
         
            +
                      if input == 'b'
         
     | 
| 
      
 118 
     | 
    
         
            +
                        do_repos += dirty_repos
         
     | 
| 
      
 119 
     | 
    
         
            +
                        do_repos += detached_repos
         
     | 
| 
      
 120 
     | 
    
         
            +
                        do_repos += no_tracking_repos
         
     | 
| 
      
 121 
     | 
    
         
            +
                        do_repos.uniq! { |repo| repo.name }
         
     | 
| 
      
 122 
     | 
    
         
            +
                      elsif input == 'c' || input != 'a'
         
     | 
| 
      
 123 
     | 
    
         
            +
                        Output.puts_cancel_message
         
     | 
| 
      
 124 
     | 
    
         
            +
                        return
         
     | 
| 
      
 125 
     | 
    
         
            +
                      end
         
     | 
| 
      
 126 
     | 
    
         
            +
                    }
         
     | 
| 
      
 127 
     | 
    
         
            +
                  end
         
     | 
| 
      
 128 
     | 
    
         
            +
             
     | 
| 
      
 129 
     | 
    
         
            +
                  if do_repos.length == 0
         
     | 
| 
      
 130 
     | 
    
         
            +
                    Output.puts_remind_message("没有仓库需要执行rebase指令!") if config_repo.nil?
         
     | 
| 
      
 131 
     | 
    
         
            +
                  else
         
     | 
| 
      
 132 
     | 
    
         
            +
                    Output.puts_processing_message("开始rebase子仓库...")
         
     | 
| 
      
 133 
     | 
    
         
            +
                    _, error_repos = Workspace.execute_git_cmd_with_repos(cmd, opts, do_repos)
         
     | 
| 
      
 134 
     | 
    
         
            +
                  end
         
     | 
| 
      
 135 
     | 
    
         
            +
             
     | 
| 
      
 136 
     | 
    
         
            +
                  Output.puts_succeed_cmd("#{cmd} #{opts}") if config_error.nil? || error_repos.empty?
         
     | 
| 
      
 137 
     | 
    
         
            +
             
     | 
| 
      
 138 
     | 
    
         
            +
                  # 清除中间态
         
     | 
| 
      
 139 
     | 
    
         
            +
                  OperationProgressManager.remove_progress(Workspace.root, __progress_type)
         
     | 
| 
      
 140 
     | 
    
         
            +
                end
         
     | 
| 
      
 141 
     | 
    
         
            +
             
     | 
| 
      
 142 
     | 
    
         
            +
                # 合并主仓库
         
     | 
| 
      
 143 
     | 
    
         
            +
                #
         
     | 
| 
      
 144 
     | 
    
         
            +
                # @param cmd [String] 合并指令
         
     | 
| 
      
 145 
     | 
    
         
            +
                #
         
     | 
| 
      
 146 
     | 
    
         
            +
                # @param opts [String] 合并参数
         
     | 
| 
      
 147 
     | 
    
         
            +
                #
         
     | 
| 
      
 148 
     | 
    
         
            +
                # @param repo [Repo] 配置仓库对象
         
     | 
| 
      
 149 
     | 
    
         
            +
                #
         
     | 
| 
      
 150 
     | 
    
         
            +
                # @param exec_repos [Array<Repo>] 本次操作的所有仓库(含配置仓库)
         
     | 
| 
      
 151 
     | 
    
         
            +
                #
         
     | 
| 
      
 152 
     | 
    
         
            +
                def rebase_config_repo(cmd, opts, repo, auto_update)
         
     | 
| 
      
 153 
     | 
    
         
            +
                  return if repo.nil?
         
     | 
| 
      
 154 
     | 
    
         
            +
                  branch_status = repo.status_checker.branch_status
         
     | 
| 
      
 155 
     | 
    
         
            +
                  if branch_status == Repo::Status::GIT_BRANCH_STATUS[:detached]
         
     | 
| 
      
 156 
     | 
    
         
            +
                    remind_config_repo_fail("主仓库\"#{repo.name}\"HEAD游离,当前不在任何分支上,无法执行!")
         
     | 
| 
      
 157 
     | 
    
         
            +
                  elsif branch_status == Repo::Status::GIT_BRANCH_STATUS[:no_tracking]
         
     | 
| 
      
 158 
     | 
    
         
            +
                    remind_config_repo_fail("主仓库\"#{repo.name}\"未跟踪对应远程分支,无法执行!(需要执行'mgit branch -u origin/<branch>')")
         
     | 
| 
      
 159 
     | 
    
         
            +
                  elsif repo.status_checker.status == Repo::Status::GIT_REPO_STATUS[:dirty]
         
     | 
| 
      
 160 
     | 
    
         
            +
                    remind_config_repo_fail("主仓库\"#{repo.name}\"有改动,无法执行\"#{cmd}\"!")
         
     | 
| 
      
 161 
     | 
    
         
            +
                  else
         
     | 
| 
      
 162 
     | 
    
         
            +
                    return continue_execute(cmd, opts, repo, PROGRESS_STAGE[:new_start], auto_update)
         
     | 
| 
      
 163 
     | 
    
         
            +
                  end
         
     | 
| 
      
 164 
     | 
    
         
            +
                end
         
     | 
| 
      
 165 
     | 
    
         
            +
             
     | 
| 
      
 166 
     | 
    
         
            +
                def continue_execute(cmd, opts, repo, check_point, auto_update)
         
     | 
| 
      
 167 
     | 
    
         
            +
             
     | 
| 
      
 168 
     | 
    
         
            +
                  # 现场信息
         
     | 
| 
      
 169 
     | 
    
         
            +
                  exec_subrepos = all_repos(except_config:true)
         
     | 
| 
      
 170 
     | 
    
         
            +
                  is_all = Workspace.is_all_exec_sub_repos?(exec_subrepos)
         
     | 
| 
      
 171 
     | 
    
         
            +
                  context = OperationProgressContext.new(__progress_type)
         
     | 
| 
      
 172 
     | 
    
         
            +
                  context.cmd = cmd
         
     | 
| 
      
 173 
     | 
    
         
            +
                  context.opts = opts
         
     | 
| 
      
 174 
     | 
    
         
            +
                  context.repos = is_all ? nil : exec_subrepos.map { |e| e.name } # nil表示操作所有子仓库
         
     | 
| 
      
 175 
     | 
    
         
            +
                  context.branch = repo.status_checker.current_branch(use_cache:true)
         
     | 
| 
      
 176 
     | 
    
         
            +
             
     | 
| 
      
 177 
     | 
    
         
            +
                  # 更新主仓库
         
     | 
| 
      
 178 
     | 
    
         
            +
                  update_config_repo(repo, context, auto_update) if check_point < PROGRESS_STAGE[:did_pull_config]
         
     | 
| 
      
 179 
     | 
    
         
            +
             
     | 
| 
      
 180 
     | 
    
         
            +
                  if check_point < PROGRESS_STAGE[:did_refresh_config]
         
     | 
| 
      
 181 
     | 
    
         
            +
                    # 操作主仓库
         
     | 
| 
      
 182 
     | 
    
         
            +
                    config_error = exec_config_repo(repo, cmd, opts)
         
     | 
| 
      
 183 
     | 
    
         
            +
                    return config_error if config_error
         
     | 
| 
      
 184 
     | 
    
         
            +
                    # 更新配置表
         
     | 
| 
      
 185 
     | 
    
         
            +
                    refresh_config(repo, context, auto_update)
         
     | 
| 
      
 186 
     | 
    
         
            +
                  end
         
     | 
| 
      
 187 
     | 
    
         
            +
             
     | 
| 
      
 188 
     | 
    
         
            +
                  if check_point < PROGRESS_STAGE[:did_pull_sub]
         
     | 
| 
      
 189 
     | 
    
         
            +
                    # 如果本次操作所有子仓库,则再次获取所有子仓库(因为配置表可能已经更新,子仓库列表也有更新,此处获取的仓库包含:已有的子仓库 + 合并后新下载仓库 + 从缓存弹出的仓库)
         
     | 
| 
      
 190 
     | 
    
         
            +
                    exec_subrepos = all_repos(except_config:true) if context.repos.nil?
         
     | 
| 
      
 191 
     | 
    
         
            +
                    # 更新子仓库
         
     | 
| 
      
 192 
     | 
    
         
            +
                    update_subrepos(exec_subrepos, context, auto_update)
         
     | 
| 
      
 193 
     | 
    
         
            +
                  end
         
     | 
| 
      
 194 
     | 
    
         
            +
             
     | 
| 
      
 195 
     | 
    
         
            +
                  config_error
         
     | 
| 
      
 196 
     | 
    
         
            +
                end
         
     | 
| 
      
 197 
     | 
    
         
            +
             
     | 
| 
      
 198 
     | 
    
         
            +
                def update_config_repo(repo, context, auto)
         
     | 
| 
      
 199 
     | 
    
         
            +
                  if auto || Output.continue_with_user_remind?("即将合并主仓库,是否先拉取远程代码更新?")
         
     | 
| 
      
 200 
     | 
    
         
            +
                    Output.puts_processing_message("正在更新主仓库...")
         
     | 
| 
      
 201 
     | 
    
         
            +
                    success, output = repo.execute_git_cmd('pull', '')
         
     | 
| 
      
 202 
     | 
    
         
            +
                    if !success
         
     | 
| 
      
 203 
     | 
    
         
            +
                      context.other = {
         
     | 
| 
      
 204 
     | 
    
         
            +
                        PROGRESS_STAGE_KEY => PROGRESS_STAGE[:did_pull_config],
         
     | 
| 
      
 205 
     | 
    
         
            +
                        PROGRESS_AUTO => auto
         
     | 
| 
      
 206 
     | 
    
         
            +
                      }
         
     | 
| 
      
 207 
     | 
    
         
            +
                      OperationProgressManager.trap_into_progress(Workspace.root, context)
         
     | 
| 
      
 208 
     | 
    
         
            +
                      show_progress_error("主仓库更新失败", "#{output}")
         
     | 
| 
      
 209 
     | 
    
         
            +
                    else
         
     | 
| 
      
 210 
     | 
    
         
            +
                      Output.puts_success_message("更新成功!\n")
         
     | 
| 
      
 211 
     | 
    
         
            +
                    end
         
     | 
| 
      
 212 
     | 
    
         
            +
                  end
         
     | 
| 
      
 213 
     | 
    
         
            +
                end
         
     | 
| 
      
 214 
     | 
    
         
            +
             
     | 
| 
      
 215 
     | 
    
         
            +
                def exec_config_repo(repo, cmd, opts)
         
     | 
| 
      
 216 
     | 
    
         
            +
                  error = nil
         
     | 
| 
      
 217 
     | 
    
         
            +
                  Output.puts_processing_message("开始操作主仓库...")
         
     | 
| 
      
 218 
     | 
    
         
            +
                  success, output = repo.execute_git_cmd(cmd, opts)
         
     | 
| 
      
 219 
     | 
    
         
            +
                  if success
         
     | 
| 
      
 220 
     | 
    
         
            +
                    Output.puts_success_message("操作成功!\n")
         
     | 
| 
      
 221 
     | 
    
         
            +
                  else
         
     | 
| 
      
 222 
     | 
    
         
            +
                    Output.puts_fail_message("操作失败!\n")
         
     | 
| 
      
 223 
     | 
    
         
            +
                    error = output
         
     | 
| 
      
 224 
     | 
    
         
            +
                  end
         
     | 
| 
      
 225 
     | 
    
         
            +
                  error
         
     | 
| 
      
 226 
     | 
    
         
            +
                end
         
     | 
| 
      
 227 
     | 
    
         
            +
             
     | 
| 
      
 228 
     | 
    
         
            +
                # 刷新配置表
         
     | 
| 
      
 229 
     | 
    
         
            +
                def refresh_config(repo, context, auto)
         
     | 
| 
      
 230 
     | 
    
         
            +
                  begin
         
     | 
| 
      
 231 
     | 
    
         
            +
                    Workspace.update_config(strict_mode:false) { |missing_repos|
         
     | 
| 
      
 232 
     | 
    
         
            +
                      if missing_repos.length > 0
         
     | 
| 
      
 233 
     | 
    
         
            +
                        # 这里分支引导仅根据主仓库来进行,如果使用all_repos来作为引导
         
     | 
| 
      
 234 
     | 
    
         
            +
                        # 基准,可能不准确(因为all_repos可能包含merge分支已有的本地
         
     | 
| 
      
 235 
     | 
    
         
            +
                        # 仓库,而这些仓库所在分支可能五花八门,数量也可能多于处于正确
         
     | 
| 
      
 236 
     | 
    
         
            +
                        # 分支的仓库)。
         
     | 
| 
      
 237 
     | 
    
         
            +
                        success_missing_repos = Workspace.guide_to_checkout_branch(missing_repos, [repo], append_message:"拒绝该操作本次执行将忽略以上仓库")
         
     | 
| 
      
 238 
     | 
    
         
            +
                        all_repos.concat(success_missing_repos)
         
     | 
| 
      
 239 
     | 
    
         
            +
                        # success_missing_repos包含新下载的和当前分支已有的新仓库,其中已有仓库包含在@all_repos内,需要去重
         
     | 
| 
      
 240 
     | 
    
         
            +
                        all_repos.uniq! { |repo| repo.name }
         
     | 
| 
      
 241 
     | 
    
         
            +
                      end
         
     | 
| 
      
 242 
     | 
    
         
            +
                    }
         
     | 
| 
      
 243 
     | 
    
         
            +
                    refresh_context(context)
         
     | 
| 
      
 244 
     | 
    
         
            +
                  rescue Error => e
         
     | 
| 
      
 245 
     | 
    
         
            +
                    if e.type == MGIT_ERROR_TYPE[:config_generate_error]
         
     | 
| 
      
 246 
     | 
    
         
            +
                      context.other = {
         
     | 
| 
      
 247 
     | 
    
         
            +
                        PROGRESS_STAGE_KEY => PROGRESS_STAGE[:did_refresh_config],
         
     | 
| 
      
 248 
     | 
    
         
            +
                        PROGRESS_AUTO => auto
         
     | 
| 
      
 249 
     | 
    
         
            +
                      }
         
     | 
| 
      
 250 
     | 
    
         
            +
             
     | 
| 
      
 251 
     | 
    
         
            +
                      OperationProgressManager.trap_into_progress(Workspace.root, context)
         
     | 
| 
      
 252 
     | 
    
         
            +
                      show_progress_error("配置表生成失败", "#{e.msg}")
         
     | 
| 
      
 253 
     | 
    
         
            +
                    end
         
     | 
| 
      
 254 
     | 
    
         
            +
                  end
         
     | 
| 
      
 255 
     | 
    
         
            +
                end
         
     | 
| 
      
 256 
     | 
    
         
            +
             
     | 
| 
      
 257 
     | 
    
         
            +
                def update_subrepos(subrepos, context, auto)
         
     | 
| 
      
 258 
     | 
    
         
            +
                  if auto || Output.continue_with_user_remind?("即将合并子仓库,是否先拉取远程代码更新?")
         
     | 
| 
      
 259 
     | 
    
         
            +
                    Output.puts_processing_message("正在更新子仓库...")
         
     | 
| 
      
 260 
     | 
    
         
            +
                    _, error_repos = Workspace.execute_git_cmd_with_repos('pull', '', subrepos)
         
     | 
| 
      
 261 
     | 
    
         
            +
                    if error_repos.length > 0
         
     | 
| 
      
 262 
     | 
    
         
            +
                      context.other = {
         
     | 
| 
      
 263 
     | 
    
         
            +
                        PROGRESS_STAGE_KEY => PROGRESS_STAGE[:did_pull_sub],
         
     | 
| 
      
 264 
     | 
    
         
            +
                        PROGRESS_AUTO => auto
         
     | 
| 
      
 265 
     | 
    
         
            +
                      }
         
     | 
| 
      
 266 
     | 
    
         
            +
                      OperationProgressManager.trap_into_progress(Workspace.root, context)
         
     | 
| 
      
 267 
     | 
    
         
            +
                      show_progress_error("子仓库更新失败", "见上述输出")
         
     | 
| 
      
 268 
     | 
    
         
            +
                    else
         
     | 
| 
      
 269 
     | 
    
         
            +
                      Output.puts_success_message("更新成功!\n")
         
     | 
| 
      
 270 
     | 
    
         
            +
                    end
         
     | 
| 
      
 271 
     | 
    
         
            +
                  end
         
     | 
| 
      
 272 
     | 
    
         
            +
                end
         
     | 
| 
      
 273 
     | 
    
         
            +
             
     | 
| 
      
 274 
     | 
    
         
            +
                def refresh_context(context)
         
     | 
| 
      
 275 
     | 
    
         
            +
                  exec_subrepos = all_repos(except_config:true)
         
     | 
| 
      
 276 
     | 
    
         
            +
                  is_all = Workspace.is_all_exec_sub_repos?(exec_subrepos)
         
     | 
| 
      
 277 
     | 
    
         
            +
                  context.repos = is_all ? nil : exec_subrepos.map { |e| e.name } # nil表示操作所有子仓库
         
     | 
| 
      
 278 
     | 
    
         
            +
                end
         
     | 
| 
      
 279 
     | 
    
         
            +
             
     | 
| 
      
 280 
     | 
    
         
            +
                def remind_config_repo_fail(msg)
         
     | 
| 
      
 281 
     | 
    
         
            +
                  Output.puts_fail_message(msg)
         
     | 
| 
      
 282 
     | 
    
         
            +
                  return if Output.continue_with_user_remind?("是否继续操作其余仓库?")
         
     | 
| 
      
 283 
     | 
    
         
            +
                  Output.puts_cancel_message
         
     | 
| 
      
 284 
     | 
    
         
            +
                  exit
         
     | 
| 
      
 285 
     | 
    
         
            +
                end
         
     | 
| 
      
 286 
     | 
    
         
            +
             
     | 
| 
      
 287 
     | 
    
         
            +
                def check_master_rebase(argv)
         
     | 
| 
      
 288 
     | 
    
         
            +
                  opt_arr = argv.git_opts(raw:false)
         
     | 
| 
      
 289 
     | 
    
         
            +
                  opt_arr.each { |opts|
         
     | 
| 
      
 290 
     | 
    
         
            +
                    Foundation.help!("当前版本不支持\"-i\"或\"--interactive\"参数,请重试。") if ['-i','--interactive'].include?(opts.first)
         
     | 
| 
      
 291 
     | 
    
         
            +
                  }
         
     | 
| 
      
 292 
     | 
    
         
            +
                end
         
     | 
| 
      
 293 
     | 
    
         
            +
             
     | 
| 
      
 294 
     | 
    
         
            +
                def do_abort(argv)
         
     | 
| 
      
 295 
     | 
    
         
            +
                  return false unless argv.git_opts.include?('--abort')
         
     | 
| 
      
 296 
     | 
    
         
            +
                  Output.puts_start_cmd
         
     | 
| 
      
 297 
     | 
    
         
            +
                  OperationProgressManager.remove_progress(Workspace.root, __progress_type)
         
     | 
| 
      
 298 
     | 
    
         
            +
                  do_repos = all_repos.select { |repo| repo.status_checker.is_in_rebase_progress? }
         
     | 
| 
      
 299 
     | 
    
         
            +
             
     | 
| 
      
 300 
     | 
    
         
            +
                  if do_repos.length > 0
         
     | 
| 
      
 301 
     | 
    
         
            +
                    append_message = ",另有#{all_repos.length - do_repos.length}个仓库无须操作" if do_repos.length < all_repos.length
         
     | 
| 
      
 302 
     | 
    
         
            +
                    Output.puts_processing_block(do_repos.map { |e| e.name }, "开始操作以上仓库#{append_message}...")
         
     | 
| 
      
 303 
     | 
    
         
            +
                    _, error_repos = Workspace.execute_git_cmd_with_repos(argv.cmd, argv.git_opts, do_repos)
         
     | 
| 
      
 304 
     | 
    
         
            +
                    Output.puts_succeed_cmd(argv.absolute_cmd) if error_repos.length == 0
         
     | 
| 
      
 305 
     | 
    
         
            +
                  else
         
     | 
| 
      
 306 
     | 
    
         
            +
                    Output.puts_success_message("没有仓库需要操作!")
         
     | 
| 
      
 307 
     | 
    
         
            +
                  end
         
     | 
| 
      
 308 
     | 
    
         
            +
             
     | 
| 
      
 309 
     | 
    
         
            +
                  true
         
     | 
| 
      
 310 
     | 
    
         
            +
                end
         
     | 
| 
      
 311 
     | 
    
         
            +
             
     | 
| 
      
 312 
     | 
    
         
            +
                def show_progress_error(summary, detail)
         
     | 
| 
      
 313 
     | 
    
         
            +
                  error = "#{summary} 已进入操作中间态。
         
     | 
| 
      
 314 
     | 
    
         
            +
             
     | 
| 
      
 315 
     | 
    
         
            +
            原因:
         
     | 
| 
      
 316 
     | 
    
         
            +
              #{detail}
         
     | 
| 
      
 317 
     | 
    
         
            +
             
     | 
| 
      
 318 
     | 
    
         
            +
            可选:
         
     | 
| 
      
 319 
     | 
    
         
            +
              - 使用\"mgit rebase --continue\"继续变基。
         
     | 
| 
      
 320 
     | 
    
         
            +
              - 使用\"mgit rebase --abort\"取消变基。"
         
     | 
| 
      
 321 
     | 
    
         
            +
                  Foundation.help!(error, title:'暂停')
         
     | 
| 
      
 322 
     | 
    
         
            +
                end
         
     | 
| 
      
 323 
     | 
    
         
            +
             
     | 
| 
      
 324 
     | 
    
         
            +
                def enable_repo_selection
         
     | 
| 
      
 325 
     | 
    
         
            +
                  true
         
     | 
| 
      
 326 
     | 
    
         
            +
                end
         
     | 
| 
      
 327 
     | 
    
         
            +
             
     | 
| 
      
 328 
     | 
    
         
            +
                def enable_continue_operation
         
     | 
| 
      
 329 
     | 
    
         
            +
                  true
         
     | 
| 
      
 330 
     | 
    
         
            +
                end
         
     | 
| 
      
 331 
     | 
    
         
            +
             
     | 
| 
      
 332 
     | 
    
         
            +
                def self.description
         
     | 
| 
      
 333 
     | 
    
         
            +
                  "重新将提交应用到其他基点,该命令不执行lock的仓库。"
         
     | 
| 
      
 334 
     | 
    
         
            +
                end
         
     | 
| 
      
 335 
     | 
    
         
            +
             
     | 
| 
      
 336 
     | 
    
         
            +
                def self.usage
         
     | 
| 
      
 337 
     | 
    
         
            +
                  "mgit rebase [<git-rebase-option>] [(--mrepo|--el-mrepo) <repo>...] [--help]\nmgit rebase --continue\nmgit rebase --abort"
         
     | 
| 
      
 338 
     | 
    
         
            +
                end
         
     | 
| 
      
 339 
     | 
    
         
            +
             
     | 
| 
      
 340 
     | 
    
         
            +
                private
         
     | 
| 
      
 341 
     | 
    
         
            +
             
     | 
| 
      
 342 
     | 
    
         
            +
                def __progress_type
         
     | 
| 
      
 343 
     | 
    
         
            +
                  OperationProgressManager::PROGRESS_TYPE[:rebase]
         
     | 
| 
      
 344 
     | 
    
         
            +
                end
         
     | 
| 
      
 345 
     | 
    
         
            +
             
     | 
| 
      
 346 
     | 
    
         
            +
              end
         
     | 
| 
      
 347 
     | 
    
         
            +
             
     | 
| 
      
 348 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,31 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            #coding=utf-8
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module MGit
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
              # @!scope 类似 git reset
         
     | 
| 
      
 6 
     | 
    
         
            +
              #
         
     | 
| 
      
 7 
     | 
    
         
            +
              class Reset < BaseCommand
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                def execute(argv)
         
     | 
| 
      
 10 
     | 
    
         
            +
                  Workspace.check_branch_consistency
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                  Output.puts_start_cmd
         
     | 
| 
      
 13 
     | 
    
         
            +
                  _, error_repos = Workspace.execute_git_cmd_with_repos(argv.cmd, argv.git_opts, all_repos)
         
     | 
| 
      
 14 
     | 
    
         
            +
                  Output.puts_succeed_cmd(argv.absolute_cmd) if error_repos.length == 0
         
     | 
| 
      
 15 
     | 
    
         
            +
                end
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                def enable_repo_selection
         
     | 
| 
      
 18 
     | 
    
         
            +
                  true
         
     | 
| 
      
 19 
     | 
    
         
            +
                end
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                def self.description
         
     | 
| 
      
 22 
     | 
    
         
            +
                  "将当前HEAD指针还原到指定状态。"
         
     | 
| 
      
 23 
     | 
    
         
            +
                end
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                def self.usage
         
     | 
| 
      
 26 
     | 
    
         
            +
                  "mgit reset [<git-reset-option>] [(--mrepo|--el-mrepo) <repo>...] [--help]"
         
     | 
| 
      
 27 
     | 
    
         
            +
                end
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
              end
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,223 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            #coding=utf-8
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module MGit
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
              # 该指令用于不带指令的输入:mgit --help,用于执行mgit的一级参数(如"mgit --help"的"--help")
         
     | 
| 
      
 6 
     | 
    
         
            +
              #
         
     | 
| 
      
 7 
     | 
    
         
            +
              class Self < BaseCommand
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                HELP_INTRODUCTION = <<INTRO
         
     | 
| 
      
 10 
     | 
    
         
            +
            #{Output.info_title("Description:")}
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                 mgit是多仓库管理工具,通过将git指令作用到多个仓库,实现批量的版本管理功能
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                 更多介绍:https://github.com/baidu/mgit
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
            INTRO
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                OPT_LIST = {
         
     | 
| 
      
 19 
     | 
    
         
            +
                  :all            =>  '--all',
         
     | 
| 
      
 20 
     | 
    
         
            +
                  :all_s          =>  '-a',
         
     | 
| 
      
 21 
     | 
    
         
            +
                  :list           =>  '--list',
         
     | 
| 
      
 22 
     | 
    
         
            +
                  :list_s         =>  '-l',
         
     | 
| 
      
 23 
     | 
    
         
            +
                  :size           =>  '--size',
         
     | 
| 
      
 24 
     | 
    
         
            +
                  :size_s         =>  '-s',
         
     | 
| 
      
 25 
     | 
    
         
            +
                  :version        =>  '--version',
         
     | 
| 
      
 26 
     | 
    
         
            +
                  :version_s      =>  '-v',
         
     | 
| 
      
 27 
     | 
    
         
            +
                  :workspace      =>  '--workspace',
         
     | 
| 
      
 28 
     | 
    
         
            +
                  :workspace_s    =>  '-w'
         
     | 
| 
      
 29 
     | 
    
         
            +
                }.freeze
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
                def options
         
     | 
| 
      
 32 
     | 
    
         
            +
                  return [
         
     | 
| 
      
 33 
     | 
    
         
            +
                      ARGV::Opt.new(OPT_LIST[:list], short_key:OPT_LIST[:list_s], info:"显示MGit管理的仓库。", type: :boolean),
         
     | 
| 
      
 34 
     | 
    
         
            +
                      ARGV::Opt.new(OPT_LIST[:size], short_key:OPT_LIST[:size_s], info:"显示MGit管理的仓库的磁盘占用量。", type: :boolean),
         
     | 
| 
      
 35 
     | 
    
         
            +
                      ARGV::Opt.new(OPT_LIST[:all], short_key:OPT_LIST[:all_s], info:"指定操作所有定义在manifest内的仓库,可配合-l合并使用: \"mgit -al\"。", type: :boolean),
         
     | 
| 
      
 36 
     | 
    
         
            +
                      ARGV::Opt.new(OPT_LIST[:version], short_key:OPT_LIST[:version_s], info:"显示当前MGit版本。", type: :boolean),
         
     | 
| 
      
 37 
     | 
    
         
            +
                      ARGV::Opt.new(OPT_LIST[:workspace], short_key:OPT_LIST[:workspace_s], info:"显示当前MGit工程管理根目录(.mgit所在目录)。", type: :boolean)
         
     | 
| 
      
 38 
     | 
    
         
            +
                  ].concat(super)
         
     | 
| 
      
 39 
     | 
    
         
            +
                end
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
                def validate(argv)
         
     | 
| 
      
 42 
     | 
    
         
            +
                  Foundation.help!("输入非法参数:#{argv.git_opts}。请通过\"mgit --help\"查看用法。") if argv.git_opts.length > 0
         
     | 
| 
      
 43 
     | 
    
         
            +
                end
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
                def prepare
         
     | 
| 
      
 46 
     | 
    
         
            +
                  Workspace.setup_multi_repo_root
         
     | 
| 
      
 47 
     | 
    
         
            +
                  Workspace.setup_config
         
     | 
| 
      
 48 
     | 
    
         
            +
                end
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
                # --- 覆写,不需要预设操作 ---
         
     | 
| 
      
 51 
     | 
    
         
            +
                def pre_exec
         
     | 
| 
      
 52 
     | 
    
         
            +
                end
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
                def post_exec
         
     | 
| 
      
 55 
     | 
    
         
            +
                end
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
                def usage(argv)
         
     | 
| 
      
 58 
     | 
    
         
            +
                  show_help(argv)
         
     | 
| 
      
 59 
     | 
    
         
            +
                end
         
     | 
| 
      
 60 
     | 
    
         
            +
                # -------------------------
         
     | 
| 
      
 61 
     | 
    
         
            +
             
     | 
| 
      
 62 
     | 
    
         
            +
                def execute(argv)
         
     | 
| 
      
 63 
     | 
    
         
            +
                  # 如果存在多余(透传)指令则报错
         
     | 
| 
      
 64 
     | 
    
         
            +
                  extra_opt_str = argv.git_opts
         
     | 
| 
      
 65 
     | 
    
         
            +
                  if extra_opt_str.length > 0
         
     | 
| 
      
 66 
     | 
    
         
            +
                    Output.puts_fail_message("输入无效参数:#{extra_opt_str}\n")
         
     | 
| 
      
 67 
     | 
    
         
            +
                    show_help(argv)
         
     | 
| 
      
 68 
     | 
    
         
            +
                    exit
         
     | 
| 
      
 69 
     | 
    
         
            +
                  end
         
     | 
| 
      
 70 
     | 
    
         
            +
             
     | 
| 
      
 71 
     | 
    
         
            +
                  argv.enumerate_valid_opts { |opt|
         
     | 
| 
      
 72 
     | 
    
         
            +
                    if opt.key == OPT_LIST[:list] || opt.key == OPT_LIST[:list_s]
         
     | 
| 
      
 73 
     | 
    
         
            +
                      show_all_repos(argv)
         
     | 
| 
      
 74 
     | 
    
         
            +
                      return
         
     | 
| 
      
 75 
     | 
    
         
            +
                    elsif opt.key == OPT_LIST[:size] || opt.key == OPT_LIST[:size_s]
         
     | 
| 
      
 76 
     | 
    
         
            +
                      show_repo_size
         
     | 
| 
      
 77 
     | 
    
         
            +
                      return
         
     | 
| 
      
 78 
     | 
    
         
            +
                    elsif opt.key == OPT_LIST[:version] || opt.key == OPT_LIST[:version_s]
         
     | 
| 
      
 79 
     | 
    
         
            +
                      show_version
         
     | 
| 
      
 80 
     | 
    
         
            +
                      return
         
     | 
| 
      
 81 
     | 
    
         
            +
                    elsif opt.key == OPT_LIST[:workspace] || opt.key == OPT_LIST[:workspace_s]
         
     | 
| 
      
 82 
     | 
    
         
            +
                      show_workspace
         
     | 
| 
      
 83 
     | 
    
         
            +
                      return
         
     | 
| 
      
 84 
     | 
    
         
            +
                    end
         
     | 
| 
      
 85 
     | 
    
         
            +
                  }
         
     | 
| 
      
 86 
     | 
    
         
            +
             
     | 
| 
      
 87 
     | 
    
         
            +
                  # 无任何参数传入时显示帮助
         
     | 
| 
      
 88 
     | 
    
         
            +
                  show_help(argv)
         
     | 
| 
      
 89 
     | 
    
         
            +
                end
         
     | 
| 
      
 90 
     | 
    
         
            +
             
     | 
| 
      
 91 
     | 
    
         
            +
                def show_help(argv)
         
     | 
| 
      
 92 
     | 
    
         
            +
                  head_space = '    '
         
     | 
| 
      
 93 
     | 
    
         
            +
                  middle_space = '   '
         
     | 
| 
      
 94 
     | 
    
         
            +
             
     | 
| 
      
 95 
     | 
    
         
            +
                  output =  HELP_INTRODUCTION # "#{Output.info_title("Description:")}\n\n#{head_space}mgit是多仓库管理工具,通过将git指令作用到多个仓库,实现批量的版本管理功能。"
         
     | 
| 
      
 96 
     | 
    
         
            +
                  output += "#{Output.info_title("Usage:")}\n\n#{head_space}$ #{Output.green_message("mgit <mgit_options>")}\n"
         
     | 
| 
      
 97 
     | 
    
         
            +
                  output += "#{head_space}$ #{Output.green_message("mgit <command> [<command_option>...] [<value>...]")}\n\n"
         
     | 
| 
      
 98 
     | 
    
         
            +
             
     | 
| 
      
 99 
     | 
    
         
            +
                  # mgit options
         
     | 
| 
      
 100 
     | 
    
         
            +
                  output += "#{Output.info_title("MGit Option:")}\n\n"
         
     | 
| 
      
 101 
     | 
    
         
            +
                  divider = ", "
         
     | 
| 
      
 102 
     | 
    
         
            +
                  longest_opt = argv.opt_list.opts.max_by { |e| "#{Output.blue_message("#{e.key}#{divider + e.short_key if !e.short_key.nil?}")}".length }
         
     | 
| 
      
 103 
     | 
    
         
            +
                  max_opt_length = "#{longest_opt.short_key + divider + longest_opt.key}".length
         
     | 
| 
      
 104 
     | 
    
         
            +
                  mgit_option_info = ''
         
     | 
| 
      
 105 
     | 
    
         
            +
                  argv.opt_list.opts.each { |opt|
         
     | 
| 
      
 106 
     | 
    
         
            +
                    key = "#{opt.short_key + divider + opt.key}"
         
     | 
| 
      
 107 
     | 
    
         
            +
                    mgit_option_info += "#{head_space}#{Output.blue_message(key)}#{' ' * (max_opt_length - key.length + middle_space.length)}#{argv.info(opt.key)}\n"
         
     | 
| 
      
 108 
     | 
    
         
            +
                  }
         
     | 
| 
      
 109 
     | 
    
         
            +
                  output += mgit_option_info + "\n"
         
     | 
| 
      
 110 
     | 
    
         
            +
             
     | 
| 
      
 111 
     | 
    
         
            +
                  # subcommand
         
     | 
| 
      
 112 
     | 
    
         
            +
                  output += "#{Output.info_title("Command:")}\n\n"
         
     | 
| 
      
 113 
     | 
    
         
            +
                  cmd_header = '+ '
         
     | 
| 
      
 114 
     | 
    
         
            +
                  cmd_info = ''
         
     | 
| 
      
 115 
     | 
    
         
            +
             
     | 
| 
      
 116 
     | 
    
         
            +
                  max_cmd_length = Output.blue_message(cmd_header + CommandManager.commands.keys.max_by { |e| e.length }.to_s).length
         
     | 
| 
      
 117 
     | 
    
         
            +
                  CommandManager.commands.keys.sort.each { |cmd_name|
         
     | 
| 
      
 118 
     | 
    
         
            +
                    next if cmd_name == self.class.cmd
         
     | 
| 
      
 119 
     | 
    
         
            +
                    cls_name = CommandManager.commands[cmd_name]
         
     | 
| 
      
 120 
     | 
    
         
            +
                    cmd_name = Output.green_message(cmd_header + cmd_name.downcase.to_s)
         
     | 
| 
      
 121 
     | 
    
         
            +
                    cmd_info += "#{head_space}#{cmd_name}#{' ' * (max_cmd_length - cmd_name.length + middle_space.length)}#{cls_name.description}\n"
         
     | 
| 
      
 122 
     | 
    
         
            +
                  }
         
     | 
| 
      
 123 
     | 
    
         
            +
                  output += cmd_info + "\n"
         
     | 
| 
      
 124 
     | 
    
         
            +
                  output += "#{Output.info_title("Command Option:")}\n\n#{head_space}请通过[ mgit <command> --help ]查看。\n\n"
         
     | 
| 
      
 125 
     | 
    
         
            +
                  output += "#{Output.info_title("Version:")}\n\n#{head_space}#{MGit::VERSION}\n"
         
     | 
| 
      
 126 
     | 
    
         
            +
             
     | 
| 
      
 127 
     | 
    
         
            +
                  puts output
         
     | 
| 
      
 128 
     | 
    
         
            +
                end
         
     | 
| 
      
 129 
     | 
    
         
            +
             
     | 
| 
      
 130 
     | 
    
         
            +
                def show_all_repos(argv)
         
     | 
| 
      
 131 
     | 
    
         
            +
                  prepare
         
     | 
| 
      
 132 
     | 
    
         
            +
             
     | 
| 
      
 133 
     | 
    
         
            +
                  list_all = argv.opt_list.did_set_opt?(OPT_LIST[:all])
         
     | 
| 
      
 134 
     | 
    
         
            +
                  existing_repos, missing_repos = prepare_repos(with_excluded:list_all)
         
     | 
| 
      
 135 
     | 
    
         
            +
             
     | 
| 
      
 136 
     | 
    
         
            +
                  list = {}
         
     | 
| 
      
 137 
     | 
    
         
            +
                  if existing_repos.length > 0
         
     | 
| 
      
 138 
     | 
    
         
            +
                    existing_repos.sort_by { |e| e.name }.each { |light_repo|
         
     | 
| 
      
 139 
     | 
    
         
            +
                      dir = File.join("<ROOT>", File.dirname(light_repo.path)).bold
         
     | 
| 
      
 140 
     | 
    
         
            +
                      list[dir] = [] if list[dir].nil?
         
     | 
| 
      
 141 
     | 
    
         
            +
                      list[dir].push(light_repo.name)
         
     | 
| 
      
 142 
     | 
    
         
            +
                    }
         
     | 
| 
      
 143 
     | 
    
         
            +
                  end
         
     | 
| 
      
 144 
     | 
    
         
            +
             
     | 
| 
      
 145 
     | 
    
         
            +
                  if missing_repos.length > 0
         
     | 
| 
      
 146 
     | 
    
         
            +
                    list['本地缺失'.bold] = missing_repos.sort_by { |e| e.name }.map { |e| e.name }
         
     | 
| 
      
 147 
     | 
    
         
            +
                  end
         
     | 
| 
      
 148 
     | 
    
         
            +
             
     | 
| 
      
 149 
     | 
    
         
            +
                  list_array = []
         
     | 
| 
      
 150 
     | 
    
         
            +
                  list.each { |dir, list|
         
     | 
| 
      
 151 
     | 
    
         
            +
                    list_array.push([dir.bold, list])
         
     | 
| 
      
 152 
     | 
    
         
            +
                  }
         
     | 
| 
      
 153 
     | 
    
         
            +
             
     | 
| 
      
 154 
     | 
    
         
            +
                  puts Output.generate_table_combination(list_array, separator:'|')
         
     | 
| 
      
 155 
     | 
    
         
            +
                  if list_all
         
     | 
| 
      
 156 
     | 
    
         
            +
                    message = "共统计#{existing_repos.length + missing_repos.length}个仓库。"
         
     | 
| 
      
 157 
     | 
    
         
            +
                  else
         
     | 
| 
      
 158 
     | 
    
         
            +
                    message = "mgit目前共管理#{existing_repos.length + missing_repos.length}个仓库。"
         
     | 
| 
      
 159 
     | 
    
         
            +
                  end
         
     | 
| 
      
 160 
     | 
    
         
            +
                  Output.puts_remind_message(message)
         
     | 
| 
      
 161 
     | 
    
         
            +
                  Output.puts_fail_message("有#{missing_repos.length}个仓库本地缺失!") if missing_repos.length > 0
         
     | 
| 
      
 162 
     | 
    
         
            +
                end
         
     | 
| 
      
 163 
     | 
    
         
            +
             
     | 
| 
      
 164 
     | 
    
         
            +
                def show_repo_size
         
     | 
| 
      
 165 
     | 
    
         
            +
                  prepare
         
     | 
| 
      
 166 
     | 
    
         
            +
                  Workspace.setup_all_repos
         
     | 
| 
      
 167 
     | 
    
         
            +
                  Output.puts_processing_message("开始计算...")
         
     | 
| 
      
 168 
     | 
    
         
            +
                  repo_size = {}
         
     | 
| 
      
 169 
     | 
    
         
            +
                  mutex = Mutex.new
         
     | 
| 
      
 170 
     | 
    
         
            +
                  task_count = 0
         
     | 
| 
      
 171 
     | 
    
         
            +
                  Output.update_progress(all_repos.length, task_count)
         
     | 
| 
      
 172 
     | 
    
         
            +
                  Workspace.concurrent_enumerate(all_repos) { |repo|
         
     | 
| 
      
 173 
     | 
    
         
            +
                    success, output = repo.execute("du -sh #{repo.path}")
         
     | 
| 
      
 174 
     | 
    
         
            +
                    mutex.lock
         
     | 
| 
      
 175 
     | 
    
         
            +
                    if success
         
     | 
| 
      
 176 
     | 
    
         
            +
                      repo_size[repo.name] = output&.strip
         
     | 
| 
      
 177 
     | 
    
         
            +
                    end
         
     | 
| 
      
 178 
     | 
    
         
            +
                    task_count += 1
         
     | 
| 
      
 179 
     | 
    
         
            +
                    Output.update_progress(all_repos.length, task_count)
         
     | 
| 
      
 180 
     | 
    
         
            +
                    mutex.unlock
         
     | 
| 
      
 181 
     | 
    
         
            +
                  }
         
     | 
| 
      
 182 
     | 
    
         
            +
                  Output.puts_success_message("计算完成。")
         
     | 
| 
      
 183 
     | 
    
         
            +
             
     | 
| 
      
 184 
     | 
    
         
            +
                  display_size = repo_size.sort_by { |k,v| k}.map { |e| e.last }
         
     | 
| 
      
 185 
     | 
    
         
            +
                  Output.puts_remind_block(display_size, "共统计#{repo_size.length}个仓库。")
         
     | 
| 
      
 186 
     | 
    
         
            +
                end
         
     | 
| 
      
 187 
     | 
    
         
            +
             
     | 
| 
      
 188 
     | 
    
         
            +
                def prepare_repos(with_excluded:false)
         
     | 
| 
      
 189 
     | 
    
         
            +
                  existing_repos = []
         
     | 
| 
      
 190 
     | 
    
         
            +
                  missing_repos = []
         
     | 
| 
      
 191 
     | 
    
         
            +
                  Workspace.config.light_repos.each { |light_repo|
         
     | 
| 
      
 192 
     | 
    
         
            +
                    if with_excluded || !light_repo.mgit_excluded
         
     | 
| 
      
 193 
     | 
    
         
            +
                      repo_exist = Repo.is_git_repo?(light_repo.abs_dest(Workspace.root))
         
     | 
| 
      
 194 
     | 
    
         
            +
                      if repo_exist
         
     | 
| 
      
 195 
     | 
    
         
            +
                        existing_repos.push(light_repo)
         
     | 
| 
      
 196 
     | 
    
         
            +
                      else
         
     | 
| 
      
 197 
     | 
    
         
            +
                        missing_repos.push(light_repo)
         
     | 
| 
      
 198 
     | 
    
         
            +
                      end
         
     | 
| 
      
 199 
     | 
    
         
            +
                    end
         
     | 
| 
      
 200 
     | 
    
         
            +
                  }
         
     | 
| 
      
 201 
     | 
    
         
            +
                  return existing_repos, missing_repos
         
     | 
| 
      
 202 
     | 
    
         
            +
                end
         
     | 
| 
      
 203 
     | 
    
         
            +
             
     | 
| 
      
 204 
     | 
    
         
            +
                def show_workspace
         
     | 
| 
      
 205 
     | 
    
         
            +
                  root = Workspace.multi_repo_root_path
         
     | 
| 
      
 206 
     | 
    
         
            +
                  if root.nil?
         
     | 
| 
      
 207 
     | 
    
         
            +
                    Output.puts_fail_message("当前不在任何多仓库目录下!")
         
     | 
| 
      
 208 
     | 
    
         
            +
                  else
         
     | 
| 
      
 209 
     | 
    
         
            +
                    puts root
         
     | 
| 
      
 210 
     | 
    
         
            +
                  end
         
     | 
| 
      
 211 
     | 
    
         
            +
                end
         
     | 
| 
      
 212 
     | 
    
         
            +
             
     | 
| 
      
 213 
     | 
    
         
            +
                def show_version
         
     | 
| 
      
 214 
     | 
    
         
            +
                  puts MGit::VERSION
         
     | 
| 
      
 215 
     | 
    
         
            +
                end
         
     | 
| 
      
 216 
     | 
    
         
            +
             
     | 
| 
      
 217 
     | 
    
         
            +
                def enable_short_basic_option
         
     | 
| 
      
 218 
     | 
    
         
            +
                  return true
         
     | 
| 
      
 219 
     | 
    
         
            +
                end
         
     | 
| 
      
 220 
     | 
    
         
            +
             
     | 
| 
      
 221 
     | 
    
         
            +
              end
         
     | 
| 
      
 222 
     | 
    
         
            +
             
     | 
| 
      
 223 
     | 
    
         
            +
            end
         
     |