pod库自动化部署脚本

前言

咱们平时在作开发的时候,多少会接触到组件化的思想。iOS的组件化通常是经过使用 cocoapods 制成pod库的形式完成的。pod库又分为公开库和私有库两种。好比咱们上传到 github 的就属于公开库,提供别人下载使用。而部署在公司内部的则属于私有库,别人访问不了,使用不到。html

概念

本文主要是讲如何实现自动部署pod脚本的,所以关于pod库相关的概念只会作个简单的介绍,不会作过多的讲解。若是想要有更深刻的了解,能够查阅官方文档git

1. repo

一个 repo 就是至关于一个放置相关 pod 库的索引的仓库。怎么理解?好比咱们在github上制做的公开库,它的 repo 叫什么?叫 trunk,地址是 https://cdn.cocoapods.org/ 。咱们能够直接在本机执行命令: pod repo,将会看到图示。github

截屏2021-08-13 下午2.06.44.png

这个仓库就是存放咱们部署上去的 podspec 文件的。ruby

2. podspec

而一个 podspec 则是用于描述一个pod库,如库结构,版本,源代码地址等。markdown


了解了这两个,那么咱们就能够制做本身的pod库了。less

制做pod库

以制做公开库,提交到 github 为例。提交到trunk的官方文档点我ide

首先你须要现有一个源代码仓库,oop

1. 建立podspec文件

pod spec create yourSpecName.podspec
复制代码

2. 编辑podspec文件

例如podspec文件内容以下,编辑里面的source、source_files等。组件化

Pod::Spec.new do |spec|
  spec.name             = 'Reachability'
  spec.version          = '3.1.0'
  spec.license          = { :type => 'BSD' }
  spec.homepage         = 'https://github.com/tonymillion/Reachability'
  spec.authors          = { 'Tony Million' => 'tonymillion@gmail.com' }
  spec.summary          = 'ARC and GCD Compatible Reachability Class for iOS and macOS.'
  spec.source           = { :git => 'https://github.com/tonymillion/Reachability.git', :tag => 'v3.1.0' }
  spec.source_files     = 'Reachability.h,m'
  spec.framework        = 'SystemConfiguration'
  spec.requires_arc     = true
end
复制代码

3. 提交咱们的源代码

git commit -am 'submit'
git push origin
复制代码

4. 给咱们的pod打tag

注意到podspec是有版本号的概念的,它须要和你pod库,也就是源代码库的tag值是一致的。这样,咱们的cocoapods才能在解析podspec以后,下载到正确版本对应的源代码。ui

git tag 0.0.2

#推送指定tag到远端
git push origin 0.0.2

# 或者推送本地全部tag到远端
# git push origin --tags
复制代码

5. 验证咱们的podspec文件格式是否正确

本地验证:

pod lib lint yourSpecName.podspec --allow-warnings
复制代码

远程验证:

pod spec line yourSpecName.podspec --allow-warnings
复制代码

6. 发布咱们的podspec

pod trunk push yourSpecName.podspec --allow-warnings
复制代码

更新pod库

此时咱们的库中应该已经有一个podspec文件了的,咱们须要作的就是更新它的版本号,若是文件结构有变更,就须要改动 source_files,有添加新的依赖库,那么须要修改 dependency

1. 更新podspec的版本号

打开podspec文件,编辑更新version字段就好,通常采用递增的方式。

1. 为咱们新版本的代码打tag

# 须要先提交代码
git commit -am 'update'
git push origin
git tag 0.0.2
git push origin 0.0.2
# 或 git push origin --tags
复制代码

2. 本地验证新修改的podspec文件是否有问题

这一步在这里骑士能够跳过,通常第一次上传没问题,后面也不会出现问题。

pod lib lint *.podspec
复制代码

3. 部署新版本的podspec

pod trunk push *.podspec
复制代码

脚本实现

脚本使用 ruby 实现的,源码在这

实现的原理其实也是用了更新podspec的步骤,只不过是加了一些配置而已。

使用起来比较简单,将脚本放在在当前的pod根目录下,执行 ruby specpush.rb 便可一键发布。

这里直接贴代码:

#! /usr/bin/ruby

class Color
    def self.natural
        0
    end
    def self.black
        30
    end
    def self.red
        31
    end
    def self.green
        32
    end
    def self.yellow
        33
    end
    def self.blue
        34
    end
    def self.magenta
        35
    end
    def self.cyan
        36
    end
    def self.white
        37
    end
end

def color_text(text, color = Color.natural)
    if color == 0
        return text
    end
    return "\033[#{color}m#{text}\033[0m"
end

def die_log(text)
    puts color_text(text, Color.red)
end

# 拉取最新代码
# if system('git pull --rebase origin') == false
# system('git rebase --abort')
# puts color_text("There is a conflict, please handle it and retry", Color.red)
# return
# end


cur_path = Dir.pwd
push_path = cur_path
relate_dir_path = ''
user_custom_version = true
verify_podspec_format = true
pod_repo_name = 'trunk'
pod_repo_source =
is_static_lib = false

# 检查是否存在 SpecPushFile 文件,若是不存在,那么建立
if not File::exist?(cur_path + '/PodPushFile')
    system('touch PodPushFile')
    File.open(cur_path + '/PodPushFile', 'w+') do |f|
        f.write("#写入*.podspec所在的相对目录,不写默认会在脚本执行的目录下查找 PUSH_DIR_PATH= #是否容许用户自定义版本号,不填或填true将容许用户设置自定义的版本号,而不是自增版本号 USER_CUSTOM_VERSION=true #默认开启验证,能够跳过验证阶段 VERIFY_PODSPEC_FORMAT=true #pod repo的名字,若是是私有库就填私有库的名字 POD_REPO_NAME=trunk #pod repo的源地址 POD_REPO_SOURCE=https://github.com/CocoaPods/Specs #若是这个库是静态库,那么须要设置为true POD_IS_STATIC_LIBRARY=false")
    end
    puts color_text('Create PodPushFile', Color.green)
    puts color_text("First you should modify 'PodPushFile' file and run the script again", Color.white)
    system('open PodPushFile')
    return
end

puts color_text('Parse PodPushFile...', Color.white)
File.open(cur_path + '/PodPushFile') do |f|
    f.each_line do |line|
        key_value = line.split('=')
        key = key_value.first.to_s.gsub("\n", '').gsub(' ','').gsub("\t",'')
        value =
        if key_value.count > 1
            value = key_value.last.to_s.gsub("\n", '').gsub(' ','').gsub("\t",'')
        end
        # puts "key=#{key},value=#{value}"
        if key.to_s == 'PUSH_DIR_PATH' and not value.nil?
            relate_dir_path = value
            push_path = cur_path + '/' + relate_dir_path
        elsif key.to_s == 'USER_CUSTOM_VERSION' and not value.nil?
            user_custom_version = value == 'true'
        elsif key.to_s == 'VERIFY_PODSPEC_FORMAT' and not value.nil?
            verify_podspec_format = value == 'true'
        elsif key.to_s == 'POD_REPO_NAME' and not value.nil?
            pod_repo_name = value.to_s
        elsif key.to_s == 'POD_REPO_SOURCE' and not value.nil?
            pod_repo_source = value
        elsif key.to_s == 'POD_IS_STATIC_LIBRARY' and not value.nil?
            is_static_lib = value == 'true'
        end
    end
end

# puts "Push path is: #{push_path}, relate dir path is: #{relate_dir_path}"

# 搜索podspec路径
podspec_path = ''
find_podspec_reg = (relate_dir_path.length == 0 ? '' : (relate_dir_path + '/')) + '*.podspec'
# puts "Find podspec reg = #{find_podspec_reg}"
Dir::glob(find_podspec_reg) do |f|
    podspec_path = f
end

if podspec_path.length == 0
    puts "Find podspec in current dir"
else
    puts "Find podspec in releate path=#{podspec_path}"
end

if not File::exist?(podspec_path)
    die_log("Can't find any podspec file in path: #{podspec_path}, please modify PodPushFile' PUSH_DIR_PATH(key)")
    return
else
    puts "Find podspec named" + color_text("#{podspec_path}", Color.white)
end

# 在当前podspec目录下新建一个临时 need_delete_temp.podspec 文件
podspec_dir = File.dirname podspec_path
podspec_absolute_path = cur_path + '/' + podspec_path
temp_podspec_path = podspec_dir + '/need_delete_temp.podspec'
temp_podspec_absolute_path = cur_path + '/' + temp_podspec_path

cur_version = ''
# 读取当前podspec文件的版本
File.open(podspec_absolute_path, 'r+') do |f|
    f.each_line do |line|
        # 查找.version
        version_desc = /.*\.version[\s]*=.*/.match line
        if not version_desc.nil?
            cur_version = version_desc.to_s.split('=').last.to_s.gsub("'", '')
            cur_version = cur_version.gsub(' ', '')
            break
        end
    end
end

puts color_text("Current version = ", Color.white) + color_text("#{cur_version}", Color.green)

# 容许自定义版本号
if user_custom_version == true
    puts color_text "Please input pod lib's new version, if there is no input or less than or equal old version, it will be incremented:", Color.white
    input_version = gets.chomp

    # 判断输入的version是否>当前的版本号
    input_v_s = input_version.to_s.split('.')
    cur_v_s = cur_version.split('.')
    # 比较的位置,从最左边开始
    v_index = 0
    # 输入的version是否有效
    input_valid = false
    while v_index < cur_v_s.count && v_index < input_v_s.count do
        if input_v_s[v_index].to_i > cur_v_s[v_index].to_i
            # 说明用户输入的version比当前的大
            input_valid = true
            break
        elsif input_v_s[v_index].to_i == cur_v_s[v_index].to_i
            v_index += 1
        else
            break
        end
    end

    if input_valid == false
        puts color_text "Input invalid version = #{input_version},will auto +1 in last component", Color.natural
    end
end

if not File.exist? temp_podspec_absolute_path
    # system("cp -f #{podspec_path} #{temp_podspec_path}")
    system("touch #{temp_podspec_path}")
end

new_version = ''
git_source = ''
File.open(temp_podspec_absolute_path, 'r+') do |t|
    File.open(podspec_absolute_path) do |f|
        f.each_line do |line|
            # # 查找.version
            # s.version = "0.0.2"
            # 须要注意的是,版本号能够是'',也能够是""
            write_line = line
            version_desc = /.*\.version[\s]*=.*/.match line
            if not version_desc.nil?
                version_coms = version_desc.to_s.split('=')
                if input_valid == true and user_custom_version == true
                    new_version = input_version.to_s
                else
                    version_num = version_coms.last.to_s.gsub("'",'').gsub("\"",'').gsub(' ','')
                    v_s = version_num.split('.')
                    # 处理版本号 0.0.1
                    for i in 0...v_s.count do
                        if i == v_s.count - 1
                            new_version += (v_s[i].to_i + 1).to_s
                        else
                            new_version += (v_s[i].to_s + '.')
                        end
                    end
                end
                puts color_text("New version = ",Color.white) + color_text("#{new_version}", Color.green)
                write_line = version_coms.first.to_s + '=' + " '#{new_version}'" + "\n"
            end
            source_desc = /.*\.source[\s]*=.*/.match line
            if not source_desc.nil?
                source_desc = /:git.*,/.match source_desc.to_s
                source_desc = /'.*'/.match source_desc.to_s
                git_source = source_desc.to_s.gsub("'",'')
                puts "git source is #{git_source}"
            end
            t.write write_line
        end
    end
end

puts color_text("Update version from ",Color.white) + color_text("#{cur_version}",Color.green) + color_text(" to ",Color.white) + color_text("#{new_version}", Color.green)

# 将新数据反写回到原始podspec中
system("cp -f #{temp_podspec_path} #{podspec_path}")
system("rm -f #{temp_podspec_path}")


# 若是本地没有这个repo,那么添加
if system("pod repo | grep #{pod_repo_name}") == false
    puts color_text("Add pod repo named '#{pod_repo_name}' with source: #{pod_repo_source}", Color.white)
    system("pod repo add #{pod_repo_name} #{pod_repo_source}")
end

# 提交代码到远程仓库
puts color_text('Start upload code to remote', Color.white)
system("git commit -am 'update version to #{new_version}'")
if system('git push origin') == false
    die_log('[!] git push code error')
end
system("git tag #{new_version}")
if system('git push origin --tags') == false
    die_log('[!] git push tags error')
    return
end

# 验证podspec格式是否正确
if verify_podspec_format == true
    puts color_text("Start verify podspec '#{podspec_path}'...", Color.white)
    if system("pod lib lint #{podspec_path} --allow-warnings") == false
        die_log("[!] pod spec' format invalid")
        return
    end
end

# 提交pod spec到spec仓库
puts color_text("Start push pod '#{podspec_path}' to remote repo '#{pod_repo_name}'", Color.white)
if pod_repo_name == 'trunk'
    if (is_static_lib == true ? system("pod trunk push #{podspec_path} --allow-warnings --use-libraries") : system("pod trunk push #{podspec_path} --allow-warnings")) == false
        puts "If not timeout, you need to check your 'trunk' account like: 'pod trunk me', and register code is 'pod trunk register <your email> <your name>'"
        return
    end
else
    if (is_static_lib == true ? system("pod repo push #{pod_repo_name} #{podspec_path} --allow-warnings --use-libraries") : system("pod repo push #{pod_repo_name} #{podspec_path} --allow-warnings"))  == false
        return
    end
end
puts color_text("Update success ☕️! Current version = #{new_version}", Color.green)
复制代码

这里提一下 PodPushFile 文件,这个是配置文件,里面有这些配置项:

#写入*.podspec所在的相对目录,不写默认会在脚本执行的目录下查找,若是脚本执行的目录和podspec文件不在同一目录下,那么须要配置下
PUSH_DIR_PATH=


#是否容许用户自定义版本号,不填或填true将容许用户设置自定义的版本号,而不是自增版本号 
USER_CUSTOM_VERSION=true


#默认开启验证,能够跳过验证阶段
VERIFY_PODSPEC_FORMAT=true


#pod repo的名字,若是是私有库就填私有库的名字
POD_REPO_NAME=trunk


#pod repo的源地址,若是是私有仓库,那么填写私有仓库的地址,注意是存放podspec的仓库的地址
POD_REPO_SOURCE=https://github.com/CocoaPods/Specs


#若是这个库是静态库,那么须要设置为true
POD_IS_STATIC_LIBRARY=false
复制代码

若是脚本有任何问题,请评论留言。rubyRepo 这是个人 ruby 仓库地址,里面会不时更新一些有用好玩的 ruby 脚本,喜欢的关注下。

相关文章
相关标签/搜索