pindo 5.0.4 → 5.0.6
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/lib/pindo/base/githelper.rb +1 -1
- data/lib/pindo/client/pgyer_feishu_oauth_cli.rb +313 -0
- data/lib/pindo/client/pgyeruploadclient.rb +275 -153
- data/lib/pindo/command/android/autobuild.rb +121 -0
- data/lib/pindo/command/android/build.rb +113 -0
- data/lib/pindo/command/android/debug.rb +60 -14
- data/lib/pindo/command/android.rb +5 -2
- data/lib/pindo/command/ios/autobuild.rb +6 -0
- data/lib/pindo/command/ios/build.rb +7 -1
- data/lib/pindo/command/unity/apk.rb +69 -6
- data/lib/pindo/command/utils/renewcert.rb +2 -2
- data/lib/pindo/module/android/apk_helper.rb +91 -0
- data/lib/pindo/module/android/base_helper.rb +293 -0
- data/lib/pindo/module/android/build_helper.rb +112 -0
- data/lib/pindo/module/android/gradle_helper.rb +48 -0
- data/lib/pindo/module/android/so_helper.rb +18 -0
- data/lib/pindo/module/build/buildhelper.rb +50 -37
- data/lib/pindo/module/build/unityhelper.rb +16 -16
- data/lib/pindo/module/pgyer/pgyerhelper.rb +14 -11
- data/lib/pindo/module/xcode/xcodehelper.rb +73 -73
- data/lib/pindo/version.rb +1 -1
- metadata +71 -11
| @@ -1,10 +1,10 @@ | |
| 1 | 
            -
             | 
| 2 1 | 
             
            require 'uri'
         | 
| 3 2 | 
             
            require 'json'
         | 
| 4 3 | 
             
            require 'faraday'
         | 
| 5 4 | 
             
            require 'securerandom'
         | 
| 6 5 | 
             
            require 'pindo/base/aeshelper'
         | 
| 7 6 | 
             
            require 'typhoeus'
         | 
| 7 | 
            +
            require 'thread'
         | 
| 8 8 |  | 
| 9 9 | 
             
            module Pindo
         | 
| 10 10 |  | 
| @@ -44,6 +44,13 @@ module Pindo | |
| 44 44 | 
             
                        @pgyer_aes_key = config_json["pgyerapps_aes_key"]
         | 
| 45 45 |  | 
| 46 46 | 
             
                        @token = load_token
         | 
| 47 | 
            +
                        
         | 
| 48 | 
            +
                        # 添加互斥锁用于线程安全
         | 
| 49 | 
            +
                        @upload_eTags_mutex = Mutex.new
         | 
| 50 | 
            +
                        @tasks_queue_mutex = Mutex.new
         | 
| 51 | 
            +
                        @active_tasks_mutex = Mutex.new
         | 
| 52 | 
            +
                        @upload_failed_mutex = Mutex.new  # 为上传失败状态添加互斥锁
         | 
| 53 | 
            +
                        @upload_failed = false
         | 
| 47 54 |  | 
| 48 55 | 
             
                      rescue => error
         | 
| 49 56 | 
             
                          raise Informative,  "PgyerUploadClient 初始化失败!"
         | 
| @@ -72,9 +79,12 @@ module Pindo | |
| 72 79 |  | 
| 73 80 | 
             
                  def upload_file(binary_file:nil, isAttach:false)
         | 
| 74 81 |  | 
| 82 | 
            +
                    raise Informative, "上传文件不能为空" if binary_file.nil? || !File.exist?(binary_file)
         | 
| 83 | 
            +
                    
         | 
| 75 84 | 
             
                    @upload_binary_file = binary_file
         | 
| 76 85 | 
             
                    @file_size = File.size(@upload_binary_file)
         | 
| 77 86 | 
             
                    @progress_bar = PgyerUploadProgressBar.new(upload_total_size:@file_size)
         | 
| 87 | 
            +
                    @upload_failed = false  # 重置上传失败标志
         | 
| 78 88 |  | 
| 79 89 | 
             
                    extension = File.extname(@upload_binary_file)
         | 
| 80 90 | 
             
                    filename = File.basename(@upload_binary_file)
         | 
| @@ -104,135 +114,231 @@ module Pindo | |
| 104 114 |  | 
| 105 115 | 
             
                    upload_result = nil
         | 
| 106 116 |  | 
| 107 | 
            -
                     | 
| 108 | 
            -
             | 
| 109 | 
            -
             | 
| 110 | 
            -
             | 
| 111 | 
            -
             | 
| 112 | 
            -
             | 
| 113 | 
            -
             | 
| 114 | 
            -
             | 
| 115 | 
            -
                       | 
| 116 | 
            -
             | 
| 117 | 
            -
             | 
| 118 | 
            -
             | 
| 119 | 
            -
                       | 
| 120 | 
            -
             | 
| 121 | 
            -
             | 
| 122 | 
            -
             | 
| 123 | 
            -
             | 
| 124 | 
            -
             | 
| 125 | 
            -
             | 
| 126 | 
            -
             | 
| 127 | 
            -
             | 
| 117 | 
            +
                    begin
         | 
| 118 | 
            +
                      file_size_param = 1.00 * @file_size / 1024 /1024
         | 
| 119 | 
            +
                      result_data = post_upload_url_req(upload_path_key:upload_path_key, file_ceil_size:file_size_param.ceil)
         | 
| 120 | 
            +
                      
         | 
| 121 | 
            +
                      if result_data.nil? || !result_data.has_key?("data") || !result_data["data"].has_key?("uploadId")
         | 
| 122 | 
            +
                        raise Informative, "获取上传ID失败,请检查网络或服务器状态"
         | 
| 123 | 
            +
                      end
         | 
| 124 | 
            +
                      
         | 
| 125 | 
            +
                      upload_id = result_data["data"]["uploadId"]
         | 
| 126 | 
            +
                      # 创建统一的任务队列
         | 
| 127 | 
            +
                      @tasks_queue = Queue.new
         | 
| 128 | 
            +
                      @worker_threads = []
         | 
| 129 | 
            +
                      upload_params_list = result_data["data"]["uploadParamsList"]
         | 
| 130 | 
            +
                      upload_item_num = upload_params_list.length
         | 
| 131 | 
            +
                      @expected_parts = upload_item_num  # 保存预期的分片数量
         | 
| 132 | 
            +
                      task_num = upload_item_num
         | 
| 133 | 
            +
                      retry_count = 5
         | 
| 134 | 
            +
                      
         | 
| 135 | 
            +
                      # 合理限制线程数
         | 
| 136 | 
            +
                      if task_num < 2
         | 
| 137 | 
            +
                        task_num = 2
         | 
| 138 | 
            +
                      end
         | 
| 128 139 |  | 
| 129 | 
            -
             | 
| 140 | 
            +
                      if task_num > 30
         | 
| 141 | 
            +
                        task_num = 30
         | 
| 142 | 
            +
                      end
         | 
| 130 143 |  | 
| 144 | 
            +
                      # 根据系统CPU核心数自动调整线程数
         | 
| 145 | 
            +
                      available_cores = Etc.respond_to?(:nprocessors) ? Etc.nprocessors : 4
         | 
| 146 | 
            +
                      task_num = [task_num, available_cores * 2].min
         | 
| 147 | 
            +
                      
         | 
| 148 | 
            +
                      # 设置重试次数并将所有任务加入队列
         | 
| 149 | 
            +
                      upload_params_list.each do |item|
         | 
| 150 | 
            +
                        item["retryCount"] = retry_count
         | 
| 151 | 
            +
                        @tasks_queue.push(item)
         | 
| 152 | 
            +
                      end
         | 
| 131 153 |  | 
| 132 | 
            -
             | 
| 154 | 
            +
                      puts "切分个数: #{upload_item_num}"
         | 
| 155 | 
            +
                      puts "线程个数: #{task_num}"
         | 
| 156 | 
            +
                      puts "重试次数: #{retry_count}"
         | 
| 157 | 
            +
                      puts
         | 
| 158 | 
            +
             | 
| 159 | 
            +
                      Funlog.instance.fancyinfo_start("开始上传...")
         | 
| 160 | 
            +
                      @upload_eTags = []
         | 
| 161 | 
            +
                      @active_tasks = 0  # 跟踪活动任务数量
         | 
| 162 | 
            +
             | 
| 163 | 
            +
                      continuous_upload_data_req(concurrency:task_num)
         | 
| 164 | 
            +
                      
         | 
| 165 | 
            +
                      # 检查上传是否全部成功
         | 
| 166 | 
            +
                      if upload_failed? || @upload_eTags.length != @expected_parts
         | 
| 167 | 
            +
                          upload_result = nil
         | 
| 168 | 
            +
                          Funlog.instance.fancyinfo_error("文件#{@upload_binary_file} 上传失败! 😭😭😭")
         | 
| 169 | 
            +
                          return upload_result
         | 
| 170 | 
            +
                      end
         | 
| 133 171 |  | 
| 134 | 
            -
             | 
| 172 | 
            +
                      result_data = post_upload_finish_req(upload_path_key:upload_path_key, upload_id:upload_id, eTags:@upload_eTags)
         | 
| 135 173 |  | 
| 136 | 
            -
             | 
| 137 | 
            -
             | 
| 138 | 
            -
             | 
| 139 | 
            -
             | 
| 140 | 
            -
             | 
| 141 | 
            -
             | 
| 174 | 
            +
                      if result_data && result_data["code"] == 200
         | 
| 175 | 
            +
                          upload_result = upload_path_key
         | 
| 176 | 
            +
                          Funlog.instance.fancyinfo_success("文件#{@upload_binary_file} 上传成功! 😎😎😎")
         | 
| 177 | 
            +
                      else
         | 
| 178 | 
            +
                          upload_result = nil
         | 
| 179 | 
            +
                          error_msg = result_data && result_data["msg"] ? result_data["msg"] : "未知错误"
         | 
| 180 | 
            +
                          Funlog.instance.fancyinfo_error("文件#{@upload_binary_file} 上传失败: #{error_msg} 😭😭😭")
         | 
| 181 | 
            +
                      end
         | 
| 182 | 
            +
                      
         | 
| 183 | 
            +
                    rescue => e
         | 
| 184 | 
            +
                      upload_result = nil
         | 
| 185 | 
            +
                      Funlog.instance.fancyinfo_error("文件上传过程发生异常: #{e.message} 😭😭😭")
         | 
| 186 | 
            +
                    ensure
         | 
| 187 | 
            +
                      # 确保所有工作线程都被清理
         | 
| 188 | 
            +
                      cleanup_worker_threads
         | 
| 142 189 | 
             
                    end
         | 
| 143 190 |  | 
| 144 191 | 
             
                    return upload_result
         | 
| 145 192 |  | 
| 146 193 | 
             
                  end
         | 
| 147 194 |  | 
| 148 | 
            -
             | 
| 149 | 
            -
                  def  | 
| 150 | 
            -
             | 
| 151 | 
            -
                      for i in 0..@upload_params_list.length-1 do
         | 
| 152 | 
            -
                        @upload_params_list[i]["retryCount"] = retry_count
         | 
| 153 | 
            -
                      end
         | 
| 154 | 
            -
             | 
| 155 | 
            -
                      while @upload_params_list.size > 0
         | 
| 156 | 
            -
                        upload_params_list_temp = []
         | 
| 157 | 
            -
                        #每次最大5个线程上传
         | 
| 158 | 
            -
                        for i in 1..task_num do
         | 
| 159 | 
            -
                          upload_params_list_temp << @upload_params_list.shift
         | 
| 160 | 
            -
                        end
         | 
| 161 | 
            -
                        hydra = Typhoeus::Hydra.new
         | 
| 162 | 
            -
                        while upload_params_list_temp.size > 0
         | 
| 163 | 
            -
                            upload_params_item = upload_params_list_temp.shift
         | 
| 164 | 
            -
                            unless upload_params_item.nil?
         | 
| 165 | 
            -
                                single_task_upload_part_data_req(upload_params_item:upload_params_item, hydra_handle:hydra)
         | 
| 166 | 
            -
                            end
         | 
| 167 | 
            -
                        end
         | 
| 168 | 
            -
                        hydra.run
         | 
| 169 | 
            -
                      end
         | 
| 170 | 
            -
             | 
| 195 | 
            +
                  # 安全地检查上传失败状态
         | 
| 196 | 
            +
                  def upload_failed?
         | 
| 197 | 
            +
                    @upload_failed_mutex.synchronize { @upload_failed }
         | 
| 171 198 | 
             
                  end
         | 
| 172 | 
            -
             | 
| 173 | 
            -
                   | 
| 174 | 
            -
             | 
| 175 | 
            -
                     | 
| 176 | 
            -
                      @ | 
| 199 | 
            +
                  
         | 
| 200 | 
            +
                  # 安全地设置上传失败状态
         | 
| 201 | 
            +
                  def set_upload_failed(error_msg = nil)
         | 
| 202 | 
            +
                    @upload_failed_mutex.synchronize do 
         | 
| 203 | 
            +
                      @upload_failed = true
         | 
| 204 | 
            +
                      Funlog.instance.fancyinfo_error("上传失败: #{error_msg}") if error_msg
         | 
| 177 205 | 
             
                    end
         | 
| 178 | 
            -
             | 
| 179 | 
            -
             | 
| 180 | 
            -
             | 
| 181 | 
            -
             | 
| 206 | 
            +
                  end
         | 
| 207 | 
            +
                  
         | 
| 208 | 
            +
                  # 清理所有工作线程
         | 
| 209 | 
            +
                  def cleanup_worker_threads
         | 
| 210 | 
            +
                    @worker_threads.each do |thread|
         | 
| 211 | 
            +
                      # 尝试安全终止线程
         | 
| 212 | 
            +
                      thread.exit if thread.alive?
         | 
| 182 213 | 
             
                    end
         | 
| 183 | 
            -
             | 
| 184 | 
            -
             | 
| 185 | 
            -
                    return @eTags
         | 
| 214 | 
            +
                    @worker_threads.clear
         | 
| 186 215 | 
             
                  end
         | 
| 187 216 |  | 
| 188 | 
            -
                  def  | 
| 189 | 
            -
             | 
| 217 | 
            +
                  def continuous_upload_data_req(concurrency:1)
         | 
| 218 | 
            +
                      # 初始化活动任务计数和条件变量
         | 
| 219 | 
            +
                      @active_tasks = 0
         | 
| 220 | 
            +
                      @task_complete_cv = ConditionVariable.new
         | 
| 221 | 
            +
                      
         | 
| 222 | 
            +
                      # 初始化连续上传,最多启动concurrency个并发任务
         | 
| 223 | 
            +
                      start_tasks = [concurrency, @tasks_queue.size].min
         | 
| 224 | 
            +
                      start_tasks.times { schedule_next_task }
         | 
| 225 | 
            +
                      
         | 
| 226 | 
            +
                      # 设置超时保护
         | 
| 227 | 
            +
                      timeout_seconds = 300  # 5分钟超时
         | 
| 228 | 
            +
                      start_time = Time.now
         | 
| 229 | 
            +
                      
         | 
| 230 | 
            +
                      # 等待所有任务完成
         | 
| 231 | 
            +
                      @tasks_queue_mutex.synchronize do
         | 
| 232 | 
            +
                          while (@active_tasks > 0 || !@tasks_queue.empty?) && !upload_failed?
         | 
| 233 | 
            +
                              # 添加超时保护
         | 
| 234 | 
            +
                              remaining_time = timeout_seconds - (Time.now - start_time)
         | 
| 235 | 
            +
                              if remaining_time <= 0
         | 
| 236 | 
            +
                                set_upload_failed("上传任务超时")
         | 
| 237 | 
            +
                                break
         | 
| 238 | 
            +
                              end
         | 
| 239 | 
            +
                              
         | 
| 240 | 
            +
                              # 等待任务完成通知,最多等待30秒
         | 
| 241 | 
            +
                              @task_complete_cv.wait(@tasks_queue_mutex, [remaining_time, 30].min)
         | 
| 242 | 
            +
                          end
         | 
| 243 | 
            +
                      end
         | 
| 244 | 
            +
                      
         | 
| 245 | 
            +
                      # 检查所有分片是否都上传成功
         | 
| 246 | 
            +
                      if @upload_eTags.length != @expected_parts && !upload_failed?
         | 
| 247 | 
            +
                          set_upload_failed("部分分片上传失败,已上传#{@upload_eTags.length}/#{@expected_parts}")
         | 
| 248 | 
            +
                      end
         | 
| 249 | 
            +
                  end
         | 
| 250 | 
            +
                  
         | 
| 251 | 
            +
                  def schedule_next_task
         | 
| 252 | 
            +
                      # 检查是否应该停止调度
         | 
| 253 | 
            +
                      return if upload_failed?
         | 
| 254 | 
            +
                      
         | 
| 255 | 
            +
                      # 尝试从队列中获取下一个任务
         | 
| 256 | 
            +
                      @tasks_queue_mutex.synchronize do
         | 
| 257 | 
            +
                          unless @tasks_queue.empty?
         | 
| 258 | 
            +
                              upload_params_item = @tasks_queue.pop
         | 
| 259 | 
            +
                              @active_tasks_mutex.synchronize { @active_tasks += 1 }
         | 
| 260 | 
            +
                              
         | 
| 261 | 
            +
                              # 异步处理任务,不阻塞主线程
         | 
| 262 | 
            +
                              worker_thread = Thread.new do
         | 
| 263 | 
            +
                                  begin
         | 
| 264 | 
            +
                                      process_upload_task(upload_params_item)
         | 
| 265 | 
            +
                                  rescue => e
         | 
| 266 | 
            +
                                      # 捕获并记录任务处理过程中的异常
         | 
| 267 | 
            +
                                      set_upload_failed("处理分片#{upload_params_item["partNo"]}时出错: #{e.message}")
         | 
| 268 | 
            +
                                  ensure
         | 
| 269 | 
            +
                                      # 任务完成后,减少活动任务计数并通知等待线程
         | 
| 270 | 
            +
                                      @active_tasks_mutex.synchronize { @active_tasks -= 1 }
         | 
| 271 | 
            +
                                      
         | 
| 272 | 
            +
                                      # 如果队列不为空,调度下一个任务
         | 
| 273 | 
            +
                                      schedule_next_task if !upload_failed?
         | 
| 274 | 
            +
                                      
         | 
| 275 | 
            +
                                      # 通知等待线程任务已完成
         | 
| 276 | 
            +
                                      @tasks_queue_mutex.synchronize { @task_complete_cv.broadcast }
         | 
| 277 | 
            +
                                  end
         | 
| 278 | 
            +
                              end
         | 
| 279 | 
            +
                              
         | 
| 280 | 
            +
                              # 保存线程引用以便后续清理
         | 
| 281 | 
            +
                              @worker_threads << worker_thread
         | 
| 282 | 
            +
                          end
         | 
| 283 | 
            +
                      end
         | 
| 284 | 
            +
                  end
         | 
| 285 | 
            +
                  
         | 
| 286 | 
            +
                  def process_upload_task(upload_params_item)
         | 
| 190 287 | 
             
                      upload_url = upload_params_item["signedUrl"]
         | 
| 191 288 | 
             
                      part_no = upload_params_item["partNo"]
         | 
| 192 | 
            -
             | 
| 289 | 
            +
                      
         | 
| 193 290 | 
             
                      file_size_ele = 1024 * 1024 * 5  #5M
         | 
| 194 | 
            -
                      start_position = file_size_ele * (part_no -1)
         | 
| 291 | 
            +
                      start_position = file_size_ele * (part_no - 1)
         | 
| 195 292 | 
             
                      if part_no * file_size_ele > @file_size
         | 
| 196 | 
            -
             | 
| 293 | 
            +
                          read_length = @file_size - start_position
         | 
| 197 294 | 
             
                      else
         | 
| 198 | 
            -
             | 
| 295 | 
            +
                          read_length = file_size_ele
         | 
| 199 296 | 
             
                      end
         | 
| 200 | 
            -
             | 
| 297 | 
            +
                      
         | 
| 201 298 | 
             
                      file = File.open(@upload_binary_file, "rb")
         | 
| 202 | 
            -
                       | 
| 203 | 
            -
             | 
| 204 | 
            -
             | 
| 205 | 
            -
             | 
| 206 | 
            -
             | 
| 207 | 
            -
                           | 
| 208 | 
            -
             | 
| 209 | 
            -
             | 
| 299 | 
            +
                      begin
         | 
| 300 | 
            +
                          file.seek(start_position)
         | 
| 301 | 
            +
                          put_data = file.read(read_length)
         | 
| 302 | 
            +
                          
         | 
| 303 | 
            +
                          request = create_req(upload_url:upload_url, body_data:put_data, read_length:read_length)
         | 
| 304 | 
            +
                          
         | 
| 305 | 
            +
                          # 设置上传进度回调
         | 
| 306 | 
            +
                          upload_size_last = 0
         | 
| 307 | 
            +
                          request.on_progress do |dltotal, dlnow, ultotal, ulnow|
         | 
| 308 | 
            +
                              if ulnow && ulnow > upload_size_last
         | 
| 309 | 
            +
                                  upload_size_last = ulnow
         | 
| 310 | 
            +
                                  @progress_bar.update_upload_index(upload_part:part_no, upload_size:ulnow)
         | 
| 311 | 
            +
                                  @progress_bar.update_upload_progress()
         | 
| 312 | 
            +
                              end
         | 
| 210 313 | 
             
                          end
         | 
| 211 | 
            -
             | 
| 212 | 
            -
             | 
| 213 | 
            -
             | 
| 314 | 
            +
                          
         | 
| 315 | 
            +
                          # 设置请求超时
         | 
| 316 | 
            +
                          request.options[:timeout] = 300  # 5分钟超时
         | 
| 317 | 
            +
                          
         | 
| 318 | 
            +
                          # 执行请求并等待完成
         | 
| 319 | 
            +
                          response = request.run
         | 
| 320 | 
            +
                          
         | 
| 321 | 
            +
                          # 处理响应结果
         | 
| 214 322 | 
             
                          if response.success?
         | 
| 215 | 
            -
             | 
| 216 | 
            -
             | 
| 217 | 
            -
             | 
| 218 | 
            -
             | 
| 323 | 
            +
                              @progress_bar.complete_upload_index(upload_part:part_no, complete_size:read_length)
         | 
| 324 | 
            +
                              etag = response.headers["ETag"]
         | 
| 325 | 
            +
                              if etag.nil? || etag.empty?
         | 
| 326 | 
            +
                                raise "服务器返回的ETag为空"
         | 
| 327 | 
            +
                              end
         | 
| 328 | 
            +
                              eTag_item = { partNumber: part_no, tag: etag}
         | 
| 329 | 
            +
                              @upload_eTags_mutex.synchronize { @upload_eTags << eTag_item }
         | 
| 219 330 | 
             
                          else
         | 
| 220 | 
            -
             | 
| 221 | 
            -
             | 
| 222 | 
            -
             | 
| 223 | 
            -
             | 
| 224 | 
            -
             | 
| 225 | 
            -
             | 
| 226 | 
            -
             | 
| 227 | 
            -
                               | 
| 228 | 
            -
                            end
         | 
| 331 | 
            +
                              @progress_bar.delete_upload_index(upload_part:part_no)
         | 
| 332 | 
            +
                              upload_params_item["retryCount"] = upload_params_item["retryCount"] - 1
         | 
| 333 | 
            +
                              if upload_params_item["retryCount"] > 0
         | 
| 334 | 
            +
                                  # 重试任务
         | 
| 335 | 
            +
                                  @tasks_queue_mutex.synchronize { @tasks_queue.push(upload_params_item) }
         | 
| 336 | 
            +
                              else
         | 
| 337 | 
            +
                                  set_upload_failed("文件#{@upload_binary_file} 分片#{part_no}上传失败: HTTP #{response.code}")
         | 
| 338 | 
            +
                              end
         | 
| 229 339 | 
             
                          end
         | 
| 230 | 
            -
                       | 
| 231 | 
            -
             | 
| 232 | 
            -
                      if hydra_handle.nil?
         | 
| 233 | 
            -
                        request.run
         | 
| 234 | 
            -
                      else
         | 
| 235 | 
            -
                        hydra_handle.queue(request)
         | 
| 340 | 
            +
                      ensure
         | 
| 341 | 
            +
                          file.close
         | 
| 236 342 | 
             
                      end
         | 
| 237 343 | 
             
                  end
         | 
| 238 344 |  | 
| @@ -284,26 +390,30 @@ module Pindo | |
| 284 390 | 
             
                          tags:eTags
         | 
| 285 391 | 
             
                      }
         | 
| 286 392 |  | 
| 287 | 
            -
                       | 
| 288 | 
            -
             | 
| 289 | 
            -
             | 
| 290 | 
            -
             | 
| 291 | 
            -
             | 
| 292 | 
            -
             | 
| 293 | 
            -
             | 
| 393 | 
            +
                      begin
         | 
| 394 | 
            +
                        con = HttpClient.create_instance_with_proxy
         | 
| 395 | 
            +
                        res = con.post do |req|
         | 
| 396 | 
            +
                            req.url boss_url
         | 
| 397 | 
            +
                            req.headers['Content-Type'] = 'application/json'
         | 
| 398 | 
            +
                            req.headers['token'] = @token["token"]
         | 
| 399 | 
            +
                            req.body = body_params.to_json
         | 
| 400 | 
            +
                            req.options.timeout = 120  # 设置2分钟超时
         | 
| 401 | 
            +
                        end
         | 
| 294 402 |  | 
| 403 | 
            +
                        result_data = nil
         | 
| 404 | 
            +
                        if !res.body.nil?
         | 
| 405 | 
            +
                            result_data = JSON.parse(res.body)
         | 
| 406 | 
            +
                        end
         | 
| 295 407 |  | 
| 296 | 
            -
             | 
| 297 | 
            -
                       | 
| 298 | 
            -
             | 
| 408 | 
            +
                        return result_data
         | 
| 409 | 
            +
                      rescue => e
         | 
| 410 | 
            +
                        Funlog.instance.fancyinfo_error("完成上传请求失败: #{e.message}")
         | 
| 411 | 
            +
                        return nil
         | 
| 299 412 | 
             
                      end
         | 
| 300 | 
            -
             | 
| 301 | 
            -
                      return  result_data
         | 
| 302 | 
            -
             | 
| 303 413 | 
             
                  end
         | 
| 304 414 |  | 
| 305 415 |  | 
| 306 | 
            -
             | 
| 416 | 
            +
                  def post_upload_url_req(upload_path_key:nil, file_ceil_size:nil)
         | 
| 307 417 |  | 
| 308 418 | 
             
                      boss_url = @baseurl + @request_config["multi_signed_url_upload"]
         | 
| 309 419 |  | 
| @@ -313,22 +423,26 @@ module Pindo | |
| 313 423 | 
             
                          fileSize:file_ceil_size
         | 
| 314 424 | 
             
                      }
         | 
| 315 425 |  | 
| 316 | 
            -
                       | 
| 317 | 
            -
             | 
| 318 | 
            -
             | 
| 319 | 
            -
             | 
| 320 | 
            -
             | 
| 321 | 
            -
             | 
| 322 | 
            -
             | 
| 426 | 
            +
                      begin
         | 
| 427 | 
            +
                        con = HttpClient.create_instance_with_proxy
         | 
| 428 | 
            +
                        res = con.post do |req|
         | 
| 429 | 
            +
                            req.url boss_url
         | 
| 430 | 
            +
                            req.headers['Content-Type'] = 'application/json'
         | 
| 431 | 
            +
                            req.headers['token'] = @token["token"]
         | 
| 432 | 
            +
                            req.body = body_params.to_json
         | 
| 433 | 
            +
                            req.options.timeout = 60  # 设置1分钟超时
         | 
| 434 | 
            +
                        end
         | 
| 323 435 |  | 
| 436 | 
            +
                        result_data = nil
         | 
| 437 | 
            +
                        if !res.body.nil?
         | 
| 438 | 
            +
                            result_data = JSON.parse(res.body)
         | 
| 439 | 
            +
                        end
         | 
| 324 440 |  | 
| 325 | 
            -
             | 
| 326 | 
            -
                       | 
| 327 | 
            -
             | 
| 441 | 
            +
                        return result_data
         | 
| 442 | 
            +
                      rescue => e
         | 
| 443 | 
            +
                        Funlog.instance.fancyinfo_error("获取上传URL失败: #{e.message}")
         | 
| 444 | 
            +
                        return nil
         | 
| 328 445 | 
             
                      end
         | 
| 329 | 
            -
             | 
| 330 | 
            -
                      return  result_data
         | 
| 331 | 
            -
             | 
| 332 446 | 
             
                  end
         | 
| 333 447 |  | 
| 334 448 | 
             
                  class PgyerUploadProgressBar
         | 
| @@ -341,50 +455,58 @@ module Pindo | |
| 341 455 | 
             
                    attr_accessor :is_done
         | 
| 342 456 |  | 
| 343 457 | 
             
                    def initialize(upload_total_size:nil, draw_char:'>')
         | 
| 344 | 
            -
             | 
| 345 | 
            -
             | 
| 346 458 | 
             
                      @upload_total_size = upload_total_size
         | 
| 347 459 | 
             
                      @draw_char = draw_char
         | 
| 348 460 | 
             
                      @last_update_time = (Time.now.to_f * 1000).to_i #毫秒
         | 
| 349 461 |  | 
| 350 462 | 
             
                      @complete_size = 0
         | 
| 351 463 | 
             
                      @update_ing_size = {}
         | 
| 352 | 
            -
             | 
| 353 464 | 
             
                      @is_done = false
         | 
| 465 | 
            +
                      
         | 
| 466 | 
            +
                      # 添加互斥锁来保护进度条更新
         | 
| 467 | 
            +
                      @mutex = Mutex.new
         | 
| 354 468 | 
             
                    end
         | 
| 355 469 |  | 
| 356 470 | 
             
                    def update_upload_index(upload_part:nil, upload_size:nil)
         | 
| 357 | 
            -
                        @ | 
| 471 | 
            +
                        @mutex.synchronize do
         | 
| 472 | 
            +
                            @update_ing_size[upload_part] = upload_size
         | 
| 473 | 
            +
                        end
         | 
| 358 474 | 
             
                    end
         | 
| 359 475 |  | 
| 360 476 | 
             
                    def delete_upload_index(upload_part:nil)
         | 
| 361 | 
            -
                        @ | 
| 477 | 
            +
                        @mutex.synchronize do
         | 
| 478 | 
            +
                            @update_ing_size[upload_part] = 0
         | 
| 479 | 
            +
                        end
         | 
| 362 480 | 
             
                    end
         | 
| 363 481 |  | 
| 364 482 | 
             
                    def complete_upload_index(upload_part:nil, complete_size:nil)
         | 
| 365 | 
            -
                        @ | 
| 366 | 
            -
             | 
| 483 | 
            +
                        @mutex.synchronize do
         | 
| 484 | 
            +
                            @complete_size = @complete_size + complete_size
         | 
| 485 | 
            +
                            @update_ing_size[upload_part] = 0
         | 
| 486 | 
            +
                        end
         | 
| 367 487 | 
             
                    end
         | 
| 368 488 |  | 
| 369 489 | 
             
                    def update_upload_progress()
         | 
| 370 490 | 
             
                        time_now = (Time.now.to_f * 1000).to_i #毫秒
         | 
| 371 491 | 
             
                        if time_now - @last_update_time > 80
         | 
| 372 | 
            -
                            @ | 
| 373 | 
            -
             | 
| 374 | 
            -
             | 
| 375 | 
            -
             | 
| 376 | 
            -
             | 
| 377 | 
            -
             | 
| 378 | 
            -
             | 
| 379 | 
            -
             | 
| 380 | 
            -
             | 
| 381 | 
            -
             | 
| 382 | 
            -
             | 
| 383 | 
            -
             | 
| 384 | 
            -
             | 
| 385 | 
            -
             | 
| 386 | 
            -
             | 
| 387 | 
            -
             | 
| 492 | 
            +
                            @mutex.synchronize do
         | 
| 493 | 
            +
                                @last_update_time = time_now
         | 
| 494 | 
            +
                                total_num = @upload_total_size
         | 
| 495 | 
            +
                                index_num = @complete_size
         | 
| 496 | 
            +
                                @update_ing_size.each do |key, value|
         | 
| 497 | 
            +
                                   index_num = index_num + value
         | 
| 498 | 
            +
                                end
         | 
| 499 | 
            +
             | 
| 500 | 
            +
                                progress_str = sprintf("%.2f", 100.0 * index_num / total_num )
         | 
| 501 | 
            +
                                total_size = sprintf("%.2f", 1.00 * total_num / 1024 /1024 )
         | 
| 502 | 
            +
                                upload_size = sprintf("%.2f", 1.00 * index_num / 1024 /1024 )
         | 
| 503 | 
            +
                                index = 40.0 * index_num / total_num
         | 
| 504 | 
            +
                                upload_message = "已上传:#{upload_size}MB|#{progress_str}\%【" + (@draw_char * (index/1).floor).ljust(40.0, '_') +  "】Total:#{total_size}MB"
         | 
| 505 | 
            +
                                Funlog.instance.fancyinfo_update(upload_message)
         | 
| 506 | 
            +
                                if index_num == total_num && !@is_done
         | 
| 507 | 
            +
                                  @is_done = true
         | 
| 508 | 
            +
                                  Funlog.instance.fancyinfo_success(upload_message)
         | 
| 509 | 
            +
                                end
         | 
| 388 510 | 
             
                            end
         | 
| 389 511 | 
             
                        end
         | 
| 390 512 | 
             
                    end
         | 
| @@ -0,0 +1,121 @@ | |
| 1 | 
            +
            require 'highline/import'
         | 
| 2 | 
            +
            require 'fileutils'
         | 
| 3 | 
            +
            require 'pindo/base/executable'
         | 
| 4 | 
            +
            require 'pindo/module/build/buildhelper'
         | 
| 5 | 
            +
            require 'pindo/module/android/build_helper'
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            module Pindo
         | 
| 8 | 
            +
              class Command
         | 
| 9 | 
            +
                class Android < Command
         | 
| 10 | 
            +
                  class Autobuild < Android
         | 
| 11 | 
            +
                    include Appselect
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                    self.summary = '打包Android工程并发布到蒲公英'
         | 
| 14 | 
            +
                    self.description = <<-DESC
         | 
| 15 | 
            +
                      编译Android包并支持上传到测试平台。
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                      支持功能:
         | 
| 18 | 
            +
                          * 编译Debug/Release包
         | 
| 19 | 
            +
                          * 上传到测试平台
         | 
| 20 | 
            +
                          * 发送测试通知
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                      使用示例:
         | 
| 23 | 
            +
                          $ pindo android autobuild                    # 编译Debug包
         | 
| 24 | 
            +
                          $ pindo android autobuild --release          # 编译Release包
         | 
| 25 | 
            +
                          $ pindo android autobuild --upload           # 编译并上传
         | 
| 26 | 
            +
                          $ pindo android autobuild --send             # 编译上传并发送通知
         | 
| 27 | 
            +
                          $ pindo android autobuild --proj=myapp       # 指定项目名称
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                    DESC
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                    def self.options
         | 
| 32 | 
            +
                      [
         | 
| 33 | 
            +
                        ['--release', '使用release模式构建'],
         | 
| 34 | 
            +
                        ['--proj',   '指定上传到测试平台的项目名称'],
         | 
| 35 | 
            +
                        ['--upload', '上传编译后的apk到测试平台'],
         | 
| 36 | 
            +
                        ['--send',   '上传成功后发送测试通知']
         | 
| 37 | 
            +
                      ].concat(super)
         | 
| 38 | 
            +
                    end
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                    def initialize(argv)
         | 
| 41 | 
            +
                      @args_release_flag = argv.flag?('release', false)
         | 
| 42 | 
            +
                      @args_upload_flag = argv.flag?('upload', false)
         | 
| 43 | 
            +
                      @args_send_flag = argv.flag?('send', false)
         | 
| 44 | 
            +
                      @args_proj_name = argv.option('proj')
         | 
| 45 | 
            +
             | 
| 46 | 
            +
             | 
| 47 | 
            +
                      if @args_send_flag
         | 
| 48 | 
            +
                        @args_upload_flag = true
         | 
| 49 | 
            +
                      end
         | 
| 50 | 
            +
             | 
| 51 | 
            +
                      super
         | 
| 52 | 
            +
                      @additional_args = argv.remainder!
         | 
| 53 | 
            +
                    end
         | 
| 54 | 
            +
             | 
| 55 | 
            +
                    def run
         | 
| 56 | 
            +
                      pindo_project_dir = Dir.pwd
         | 
| 57 | 
            +
                      build_helper = Pindo::BuildHelper.share_instance
         | 
| 58 | 
            +
                      project_type = build_helper.project_type(pindo_project_dir)
         | 
| 59 | 
            +
             | 
| 60 | 
            +
                      args_temp = []
         | 
| 61 | 
            +
                      args_temp << "--proj=#{@args_proj_name}" if @args_proj_name
         | 
| 62 | 
            +
                      args_temp << "--upload" if @args_upload_flag
         | 
| 63 | 
            +
                      args_temp << "--send" if @args_send_flag
         | 
| 64 | 
            +
             | 
| 65 | 
            +
                      case project_type
         | 
| 66 | 
            +
                      when :ios
         | 
| 67 | 
            +
                        puts "iOS 工程, 请使用 pindo ios build"
         | 
| 68 | 
            +
                      when :android
         | 
| 69 | 
            +
                        android_autobuild
         | 
| 70 | 
            +
                      when :unity
         | 
| 71 | 
            +
                        Pindo::Command::Unity::Apk::run(args_temp)
         | 
| 72 | 
            +
                      else
         | 
| 73 | 
            +
                        raise Informative, "当前目录不是工程目录,不能编译"
         | 
| 74 | 
            +
                      end
         | 
| 75 | 
            +
                    end
         | 
| 76 | 
            +
             | 
| 77 | 
            +
                    private
         | 
| 78 | 
            +
             | 
| 79 | 
            +
                    def android_autobuild
         | 
| 80 | 
            +
             | 
| 81 | 
            +
                      pindo_project_dir = Dir.pwd
         | 
| 82 | 
            +
                      build_helper = Pindo::BuildHelper.share_instance
         | 
| 83 | 
            +
             | 
| 84 | 
            +
                      if @args_upload_flag
         | 
| 85 | 
            +
                        build_helper.check_check_and_install_cliff(pindo_project_dir)
         | 
| 86 | 
            +
                        is_need_add_tag,tag_action_parms = build_helper.check_is_need_add_tag?(pindo_project_dir)
         | 
| 87 | 
            +
                        if is_need_add_tag
         | 
| 88 | 
            +
                            Pindo::Command::Dev::Tag::run(tag_action_parms)
         | 
| 89 | 
            +
                        end
         | 
| 90 | 
            +
                      end
         | 
| 91 | 
            +
             | 
| 92 | 
            +
                      app_info_obj = nil
         | 
| 93 | 
            +
                      if @args_upload_flag
         | 
| 94 | 
            +
                          proj_name = @args_proj_name
         | 
| 95 | 
            +
                          app_info_obj = PgyerHelper.share_instace.prepare_upload(working_directory:Dir.pwd, proj_name:proj_name)
         | 
| 96 | 
            +
                      end
         | 
| 97 | 
            +
             | 
| 98 | 
            +
                      android_build_helper = Pindo::AndroidBuildHelper.share_instance
         | 
| 99 | 
            +
                      apk_path = android_build_helper.auto_build_apk(pindo_project_dir, !@args_release_flag)
         | 
| 100 | 
            +
                      ipa_file_upload = Dir.glob(apk_path).max_by {|f| File.mtime(f)}
         | 
| 101 | 
            +
             | 
| 102 | 
            +
                      if !ipa_file_upload.nil? && !app_info_obj.nil?
         | 
| 103 | 
            +
                          description = nil
         | 
| 104 | 
            +
                          result_data = PgyerHelper.share_instace.start_upload(app_info_obj:app_info_obj, ipa_file_upload:ipa_file_upload, description:description)
         | 
| 105 | 
            +
                          if !result_data.nil? && !result_data["data"].nil? && !result_data["data"]["id"].nil?
         | 
| 106 | 
            +
                              msg_data = PgyerHelper.share_instace.make_msg_data(app_info_obj:app_info_obj, app_version_info_obj:result_data["data"])
         | 
| 107 | 
            +
                              PgyerHelper.share_instace.print_app_version_info(msg_data:msg_data)
         | 
| 108 | 
            +
                              if @args_send_flag
         | 
| 109 | 
            +
                                  PgyerHelper.share_instace.send_apptest_wechat_msg(msg_data:msg_data)
         | 
| 110 | 
            +
                              end
         | 
| 111 | 
            +
                          end
         | 
| 112 | 
            +
                      end
         | 
| 113 | 
            +
             | 
| 114 | 
            +
                      system "open #{pindo_project_dir}"
         | 
| 115 | 
            +
             | 
| 116 | 
            +
             | 
| 117 | 
            +
                    end
         | 
| 118 | 
            +
                  end
         | 
| 119 | 
            +
                end
         | 
| 120 | 
            +
              end
         | 
| 121 | 
            +
            end
         |