前言:最近公司讓我寫個(gè)自動簽名的教程出來,方便后面培訓(xùn)實(shí)習(xí)生,剛開始我也是老老實(shí)實(shí)的寫的,但令我萬萬沒想到的是第一版交出去后,領(lǐng)導(dǎo)直接給我打回來了,說我寫的他看得懂,實(shí)習(xí)生不一定就能看得懂,尤其是讓我把配置開發(fā)環(huán)境這些都要一步一步的寫出來,還要配上貼圖,讓我寫的再詳細(xì)點(diǎn),好吧,盡管心里不愿意,但手上可還是很誠實(shí)的開始寫上了,然后我想,如果按照領(lǐng)導(dǎo)的要求來寫,那的寫到猴年馬月啊,而且寫的越多,說不定到時(shí)候改的也就越多,于是,我就想到了寫個(gè)腳本來自動化配置開發(fā)環(huán)境,說干就干,經(jīng)過一通鼓搗,一個(gè)強(qiáng)大的自動化配置iOS開發(fā)環(huán)境的腳本就誕生了...
這個(gè)腳本支持安裝Homebrew、GPG/GPG2、RVM、Ruby、CocoaPods、SVN(SVN是否安裝請根據(jù)自己實(shí)際需求來決定,不需要的可以注釋掉。)
使用方法,例如將腳本命名為AutoConfig.py, 則終端中直接CD到腳本所在目錄,然后輸入命令 python3 AutoConfig.py,接著按照提示一步一步安裝即可。
在這里給大家推薦幾個(gè)我寫的工具,如果大家覺得不錯(cuò)的話,請給顆鼓勵的小星星哦...
import os
import re
import sys
import subprocess
from shutil import which
# 用戶配置信息
CONFIG = {
'gpg_key': None, # 設(shè)置為 None 以自動生成并獲取GPG key,或者指定 GPG key
'gpg_username': '你的名字',
'gpg_email': 'nn@aliyun.com',
'gpg_comment': 'comment is null',
'gpg_passphrase': 'GPGPWD', # 設(shè)置GPG密鑰的密碼
'ruby_install_version': None, # 設(shè)置為 None 以自動獲取最新版本,或者指定版本號
'homebrew_url_install': 'https://gitee.com/cunkai/HomebrewCN/raw/master/Homebrew.sh',
'homebrew_url_uninstall': 'https://gitee.com/cunkai/HomebrewCN/raw/master/HomebrewUninstall.sh',
'rubygems_source_remove': 'https://rubygems.org/',
'rubygems_source_custom': 'https://gems.ruby-china.com/',
'cocoapods_repo_url': 'https://mirrors.tuna.tsinghua.edu.cn/git/CocoaPods/Specs.git',
'trunk_path': '~/.cocoapods/repos/trunk',
'master_path': '~/.cocoapods/repos/master'
}
# 打印并執(zhí)行命令的函數(shù)
def run_command(command, check=True, description=""):
print(f"{description}")
result = subprocess.run(command, shell=True)
if check and result.returncode != 0:
print(f"{description}時(shí)出錯(cuò): {result.returncode}")
sys.exit(1)
print(f"{description}")
return result
# 詢問并確認(rèn)是否需要安裝指定工具
def check_tool_install(tool=""):
result = input(f"檢測到您目前尚未安裝 {tool}, 是否需要下載并安裝? (y/n): ").strip().lower()
if result == 'y':
return True
else:
return False
# 檢查并安裝 Homebrew
def check_and_install_homebrew():
result = run_command("brew --version", check=False)
if result.returncode == 0:
reinstall = input("檢測到已安裝Homebrew,是否需要卸載后重新安裝最新版本? (y/n): ").strip().lower()
if reinstall == 'y':
run_command(f"/bin/zsh -c \"$(curl -fsSL {CONFIG['homebrew_url_uninstall']})\"", description="卸載 Homebrew")
run_command(f"/bin/zsh -c \"$(curl -fsSL {CONFIG['homebrew_url_install']})\"", description="重新安裝 Homebrew")
else:
if check_tool_install("Homebrew"):
run_command(f"/bin/zsh -c \"$(curl -fsSL {CONFIG['homebrew_url_install']})\"", description="安裝 Homebrew")
# 檢查 Homebrew 是否安裝,若未安裝則不執(zhí)行后續(xù)安裝
def check_homebrew_installed():
try:
run_command("brew --version")
return True
except subprocess.CalledProcessError:
return False
# 檢查并安裝 GPG
def check_and_install_gpg():
if check_homebrew_installed():
result = run_command("gpg2 --version", check=False)
if result.returncode == 0:
reinstall = input("檢測到已安裝gpg2, 是否需要卸載后重新安裝最新版本? (y/n): ").strip().lower()
if reinstall == 'y':
run_command("brew uninstall --force gpg2",description="卸載GPG/GPG2")
install_gpg()
else:
if check_tool_install("GPG"):
install_gpg()
else:
print("Homebrew 未正確安裝,請先安裝 Homebrew")
sys.exit(1)
def install_gpg():
run_command("brew install gnupg gnupg2", description="安裝GPG2")
# 創(chuàng)建符號鏈接
if not which("gpg2"):
print("gpg2 命令不可用,嘗試創(chuàng)建符號鏈接...")
gpg_path = which("gpg")
if gpg_path:
# 創(chuàng)建符號鏈接
run_command(f"ln -s {gpg_path} {gpg_path}2", description="創(chuàng)建符號鏈接")
else:
print("gpg2 未找到,請檢查您的系統(tǒng)環(huán)境")
sys.exit(1)
# 檢查 GPG2 是否安裝成功
if check_gpg_installed():
print("GPG2 安裝成功")
gpg_key = get_gpg_key()
command = f"gpg2 --keyserver hkp://pool.sks-keyservers.net --recv-keys {gpg_key}"
run_command(command, check=False, description=f"設(shè)置 gpg key {gpg_key}")
else:
print("GPG2 安裝失敗,請檢查安裝過程中是否有錯(cuò)誤或網(wǎng)絡(luò)連接是否正常")
sys.exit(1)
def get_gpg_key():
"""
生成并返回新的 GPG 密鑰對的公鑰
"""
if CONFIG['gpg_key']:
return CONFIG['gpg_key']
key_list = get_gpg_key_list()
if len(key_list) >= 2:
gpg_key = f"{key_list[0]} {key_list[1]}"
return gpg_key
key_details = f"""
%echo Generating a basic OpenPGP key
Key-Type: RSA
Key-Length: 2048
Subkey-Type: RSA
Subkey-Length: 2048
Name-Real: {CONFIG['gpg_username']}
Name-Comment: {CONFIG['gpg_comment']}
Name-Email: {CONFIG['gpg_email']}
Expire-Date: 0
Passphrase: {CONFIG['gpg_passphrase']}
%commit
%echo done
"""
# 將密鑰詳情寫入臨時(shí)文件
with open('gpg_key_details.txt', 'w') as f:
f.write(key_details)
# 生成 GPG 密鑰對
run_command("gpg2 --batch --generate-key gpg_key_details.txt", description="生成 GPG 密鑰對")
# 獲取生成的 GPG 密鑰 ID
result = subprocess.run(
["gpg2", "--list-secret-keys", "--keyid-format", "LONG", CONFIG['gpg_email']],
capture_output=True,
text=True
)
key_output = result.stdout
gpg_key_id = None
# 提取 GPG key ID
for line in key_output.split('\n'):
if 'sec' in line and '/' in line:
gpg_key_id = line.split('/')[1].split()[0]
break
if not gpg_key_id:
print("GPG 密鑰生成失敗,請檢查安裝過程中是否有錯(cuò)誤或配置是否正確")
sys.exit(1)
# 導(dǎo)出公鑰
result = subprocess.run(
["gpg2", "--armor", "--export", gpg_key_id],
capture_output=True,
text=True
)
gpg_public_key = result.stdout
if not gpg_public_key:
print("GPG 公鑰導(dǎo)出失敗,請檢查安裝過程中是否有錯(cuò)誤")
sys.exit(1)
# 刪除臨時(shí)文件
os.remove('gpg_key_details.txt')
keys = get_gpg_key_list()
if len(keys) < 2:
# 獲取到的 gpg keys 數(shù)量不足
get_gpg_key()
gpg_key = f"{keys[0]} {keys[1]}"
return gpg_key
# 獲取 gpg key列表
def get_gpg_key_list():
# 查看key列表
list_keys_result = subprocess.run(
["gpg2", "--list-keys"],
capture_output=True,
text=True
)
# 檢查命令執(zhí)行是否成功
if list_keys_result.returncode != 0:
print("獲取gpg keys 失敗")
sys.exit(1)
# 命令輸出
output = list_keys_result.stdout
# 定義一個(gè)正則表達(dá)式來匹配公鑰ID
key_id_pattern = re.compile(r'\s+([A-F0-9]+)\s+')
# 使用正則表達(dá)式查找所有公鑰ID
key_ids = key_id_pattern.findall(output)
return key_ids
# 檢查 GPG 是否安裝,若未安裝則不執(zhí)行后續(xù)安裝
def check_gpg_installed():
try:
run_command("gpg2 --version")
return True
except subprocess.CalledProcessError:
return False
# 檢查并安裝 RVM
def check_and_install_rvm():
if check_gpg_installed():
result = run_command("rvm --version", check=False)
if result.returncode == 0:
reinstall = input("檢測到RVM已安裝,是否需要卸載后重新安裝最新版本? (y/n): ").strip().lower()
if reinstall == 'y':
install_version = get_rvm_version()
commands = [
f"rvm remove {install_version}",
"rvm implode",
"curl -L https://get.rvm.io | bash -s stable"
]
for command in commands:
run_command(command, description=f"執(zhí)行 {command}")
install_rvm()
else:
if check_tool_install("RVM"):
install_rvm()
else:
print("GPG/GPG2 未正確安裝,請先安裝 GPG/GPG2")
sys.exit(1)
# 獲取已安裝的 RVM 的版本號
def get_rvm_version():
result = subprocess.run(
["rvm", "--version"],
capture_output=True,
text=True
)
output = result.stdout.strip()
version_match = re.search(r'\d+\.\d+(\.\d+)?', output)
return version_match.group()
def install_rvm():
"""
安裝 RVM
"""
rvm_commands = [
"curl -sSL https://get.rvm.io | bash -s stable",
"curl -L get.rvm.io | bash -s stable",
"rvm get master"
]
for command in rvm_commands:
run_command(command, description=f"安裝 RVM {command.split()[0]}")
# 檢查并安裝 Ruby
def check_and_install_ruby():
if check_rvm_installed():
result = run_command("ruby --version", check=False)
if result.returncode == 0:
reinstall = input("檢測到Ruby已安裝,是否需要重新安裝最新版本? (y/n): ").strip().lower()
if reinstall == 'y':
install_ruby()
else:
if check_tool_install("Ruby"):
install_ruby()
else:
print("RVM 未正確安裝,請先安裝 RVM")
sys.exit(1)
def check_rvm_installed():
try:
run_command("rvm --version")
return True
except subprocess.CalledProcessError:
return False
def install_ruby():
"""
安裝 Ruby 并設(shè)置默認(rèn)版本
"""
install_version = None
if CONFIG['ruby_install_version'] is None:
install_version = get_latest_ruby_version()
if install_version is None:
print("未找到可用的 Ruby 版本,請輸入您想安裝的 Ruby 版本號: ")
install_version = input("Ruby 版本號: ").strip()
else:
print(f"安裝最新 Ruby 版本: {install_version}")
else:
install_version = CONFIG['ruby_install_version']
print(f"安裝指定 Ruby 版本: {install_version}")
run_command(f"rvm install {install_version}", description=f"安裝 Ruby {install_version}")
run_command(f"rvm use ruby-{install_version} --default", description=f"設(shè)置默認(rèn) Ruby 版本為 {install_version}")
# 獲取 Ruby 最新版本
def get_latest_ruby_version():
"""
自動獲取 RVM 中最新的 Ruby 版本
返回:
str: 最新的 Ruby 版本號,如果獲取失敗則返回 None
"""
print("正在自動獲取 RVM 中最新的 Ruby 版本...")
try:
result = subprocess.run(
["rvm", "list", "known"],
capture_output=True,
text=True
)
output = result.stdout
print("獲取到的 RVM 輸出:\n", output)
# 提取版本號的正則表達(dá)式
version_pattern = re.compile(r'\[ruby-]?(\d+\.\d+\.\d+|\d+\.\d+|\d+)')
versions = version_pattern.findall(output)
def is_valid_version(version):
"""
檢查是否為有效的版本號
"""
try:
tuple(map(int, re.split(r'\D+', version)))
return True
except ValueError:
return False
if versions:
versions = [v for v in versions if is_valid_version(v)]
versions.sort(key=lambda x: tuple(map(int, re.split(r'\D+', x))), reverse=True)
return versions[0] if versions else None
else:
return None
except subprocess.CalledProcessError as e:
print("獲取 Ruby 版本失敗:", e)
return None
# 檢查并安裝 CocoaPods
def check_and_install_cocoapods():
if check_ruby_and_rvm_installed():
result = run_command("pod --version", check=False)
if result.returncode == 0:
reinstall = input("檢測到Cocoapods已安裝,是否需要卸載后重新安裝最新版本? (y/n): ").strip().lower()
if reinstall == 'y':
run_command("sudo gem uninstall cocoapods", description="卸載Cocoapods")
run_command("rm -rf ~/.cocoapods/", description="移除 Cocoapods 緩存")
install_cocoapods()
else:
if check_tool_install("CocoaPods"):
install_cocoapods()
else:
sys.exit(1)
def install_cocoapods():
"""
安裝 CocoaPods
"""
commands = [
f"gem sources --remove {CONFIG['rubygems_source_remove']}",
f"gem sources --add {CONFIG['rubygems_source_custom']}",
"gem sources -l",
"sudo gem install -n /usr/local/bin cocoapods"
]
for command in commands:
run_command(command, description=f"執(zhí)行 {command}")
# 檢查 CocoaPods 是否安裝成功
try:
run_command(["pod", "--version"])
print("CocoaPods 安裝成功")
except subprocess.CalledProcessError:
print("CocoaPods 安裝失敗,請檢查安裝過程中是否有錯(cuò)誤或者網(wǎng)絡(luò)連接是否正常")
sys.exit(1)
# 克隆 CocoaPods 倉庫
repo_url = CONFIG['cocoapods_repo_url']
# 設(shè)置 Trunk 倉庫存儲地址
trunk_path = os.path.expanduser(CONFIG['trunk_path'])
# 檢查 CocoaPods Trunk 倉庫是否已存在
if os.path.isdir(trunk_path):
print(f"Cocoapods倉庫 trunk 已存在,跳過克隆 trunk 步驟")
else:
add_trunk_command = f"git clone {repo_url} {trunk_path}"
cocoapods_warehouse_clone("trunk", add_trunk_command, trunk_path, "克隆 CocoaPods trunk 倉庫")
# 設(shè)置 Master 倉庫存儲地址
master_path = os.path.expanduser(CONFIG['master_path'])
# 檢查 CocoaPods Master 倉庫是否已存在
if os.path.isdir(master_path):
print(f"Cocoapods倉庫 master 已存在,跳過克隆 master 步驟")
else:
add_master_command = f"pod repo add master {repo_url}"
cocoapods_warehouse_clone("master", add_master_command, master_path, "設(shè)置 CocoaPods Master 源")
# Cocoapods 倉庫克隆
def cocoapods_warehouse_clone(warehouse, command, save_path, description):
run_command(command, description=description)
# 檢查 CocoaPods 倉庫是否成功克隆
if not os.path.isdir(save_path):
retry = input(f"CocoaPods {warehouse} 倉庫克隆失敗, 是否重試? (y/n): ").strip().lower()
if retry == 'y':
cocoapods_warehouse_clone(warehouse, command, save_path, description)
else:
print(f"CocoaPods {warehouse} 倉庫克隆失敗,請檢查網(wǎng)絡(luò)連接或倉庫地址是否正確。")
sys.exit(1)
def check_ruby_and_rvm_installed():
"""
檢查 Ruby 和 RVM 是否安裝
"""
rvm_result = run_command("rvm --version", check=False)
if rvm_result.returncode == 0:
ruby_result = run_command("ruby --version", check=False)
if ruby_result.returncode == 0:
return True
else:
print("Ruby 未正確安裝,請先安裝Ruby")
return False
else:
print("RVM 未正確安裝,請先安裝RVM")
return False
# 檢查并安裝 SVN
def check_and_install_svn():
if check_homebrew_installed():
result = run_command("svn --version", check=False)
if result.returncode == 0:
reinstall = input("檢測到SVN已安裝,是否需要卸載后重新安裝最新版本? (y/n): ").strip().lower()
if reinstall == 'y':
run_command("brew uninstall subversion", description="卸載 SVN")
run_command("brew install svn", description="重新安裝 SVN")
else:
if check_tool_install("SVN"):
run_command("brew install svn", description="安裝 SVN")
else:
print("Homebrew 未正確安裝,請先安裝 Homebrew")
sys.exit(1)
def main():
# 安裝 Homebrew
check_and_install_homebrew()
# 安裝 GPG
check_and_install_gpg()
# 安裝 RVM
check_and_install_rvm()
# 安裝 Ruby
check_and_install_ruby()
# 安裝 CocoaPods
check_and_install_cocoapods()
# 安裝 SVN
check_and_install_svn()
print("\niOS開發(fā)環(huán)境已配置(檢查)完畢,可以愉快的擼代碼了...\n")
if __name__ == "__main__":
main()
如您在使用過程中發(fā)現(xiàn)BUG,或有好的意見建議,可發(fā)郵件至aiguanren@icloud.com聯(lián)系我。