Mac 下无限试用 Cornerstone!一个 Shell 脚本搞定!立省 $$$79!!!

0 阅读4分钟

背景

Cornerstone 是 macOS 上体验最好的 SVN 客户端之一,但试用期一到就要付费。

研究了一下它的试用机制,发现试用状态存储在一个隐藏的加密缓存文件中:

~/Library/Containers/com.zennaware.cornerstone3/Data/Library/Application Support/com.zennaware.cornerstone3/.hdhhoix5h2sozule6zx7ydxoa75d24gu

该文件具有以下特征:

  • 文件名为随机字符串,每次可能不同
  • 内容为加密的二进制数据,大小约 323 字节
  • 属于隐藏文件(以 . 开头),不会在 Finder 中直接显示

只要在 Cornerstone 每次退出后自动清空该目录,下次启动时试用期即可重置。


方案选型

方案一:Automator 启动器(已排除)

最初思路是创建一个 Automator 应用作为启动器,在打开 Cornerstone 之前先执行清理脚本。

问题:

  1. Automator 应用访问其他应用的沙盒目录(~/Library/Containers/)时,macOS 每次都会弹出权限确认弹窗,无法静默运行。
  2. 将 Automator 启动器固定在 Dock 后,Cornerstone 启动时会在 Dock 中额外显示自身图标,导致同时出现两个图标。

方案二:修改 app 内部可执行文件(已排除)

Cornerstone.app/Contents/MacOS/Cornerstone 重命名为 Cornerstone_real,替换为一个 shell 脚本,在脚本中执行清理后再启动真正的二进制文件。

问题:

修改 app bundle 内容后,代码签名失效,macOS Gatekeeper 拒绝运行,应用直接闪退。使用 codesign --force --deep --sign - 重新签名为 ad-hoc 签名后,部分情况下仍因沙盒权限问题无法正常启动。

方案三:launchd + 进程监控脚本(最终方案)

在应用关闭后执行清理,完全规避启动时的权限和签名问题。使用 launchd 在后台持续运行一个监控脚本,检测到 Cornerstone 进程退出时触发清理操作。


实现步骤

第一步:创建进程监控脚本

cat > ~/cornerstone_watcher.sh << 'EOF'
#!/bin/bash
CACHE_DIR="$HOME/Library/Containers/com.zennaware.cornerstone3/Data/Library/Application Support/com.zennaware.cornerstone3"

was_running=false

while true; do
    if pgrep -x "Cornerstone" > /dev/null; then
        was_running=true
    else
        if [ "$was_running" = true ]; then
            rm -rf "$CACHE_DIR"/.[!.]*
            rm -rf "$CACHE_DIR"/*
            was_running=false
        fi
    fi
    sleep 2
done
EOF

chmod +x ~/cornerstone_watcher.sh

脚本逻辑说明:

关键点说明
pgrep -x "Cornerstone"精确匹配进程名,-x 参数要求全名匹配,避免误伤其他进程
was_running 标志位用于区分"进程从未运行"和"进程刚刚退出"两种状态,确保只在退出时触发清理
.[!.]*匹配隐藏文件,但排除 ...,比 .* 更安全
sleep 2每 2 秒轮询一次,CPU 占用极低
$HOME在 plist 中 ~ 不会被展开,脚本内部使用 $HOME 保证路径正确

第二步:创建 launchd plist 配置文件

将以下内容保存为 ~/Library/LaunchAgents/com.user.cornerstone.cleancache.plist,注意将路径中的用户名替换为实际值:

cat > ~/Library/LaunchAgents/com.user.cornerstone.cleancache.plist << 'EOF'
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>com.user.cornerstone.cleancache</string>
    <key>ProgramArguments</key>
    <array>
        <string>/bin/bash</string>
        <string>/Users/你的用户名/cornerstone_watcher.sh</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
    <key>KeepAlive</key>
    <true/>
</dict>
</plist>
EOF

配置项说明:

Key说明
Labellaunchd Job 的唯一标识符,建议使用反向域名格式
RunAtLoad配置文件加载后立即启动(含开机自启)
KeepAlive脚本退出后自动重启,保证持续监控

⚠️ plist 文件中不支持 ~ 路径展开,ProgramArguments 中必须使用绝对路径。

第三步:加载配置并启动

launchctl load ~/Library/LaunchAgents/com.user.cornerstone.cleancache.plist

验证脚本是否正在运行:

pgrep -fl cornerstone_watcher

输出示例:

7106 /bin/bash /Users/fatto/cornerstone_watcher.sh

有输出则表示监控脚本已在后台运行,重启 Mac 后会自动恢复。


验证效果

  1. 打开 Cornerstone,确认缓存文件已生成:
ls -la ~/Library/Containers/com.zennaware.cornerstone3/Data/Library/Application\ Support/com.zennaware.cornerstone3/
  1. 正常关闭 Cornerstone,等待约 2 秒后再次执行上述命令,确认目录已清空。

注意事项

  • Cornerstone 更新不受影响:本方案不修改 app bundle,更新后无需重新操作。
  • 缓存目录会被完整清空:如果 Cornerstone 在该目录下还存储了其他重要数据(如仓库配置),需要先确认清空范围,必要时改为只删除特定文件。
  • launchd 与 cron 的区别:launchd 是 macOS 推荐的任务调度机制,支持按需启动、依赖管理和日志收集,优于传统 cron。

扩展应用

本方案的核心模式是"进程退出后触发动作",可以推广到其他场景:

  • 应用关闭后自动备份配置文件
  • 应用关闭后清理临时文件或日志
  • 应用关闭后执行数据同步脚本

只需修改脚本中的进程名(pgrep -x 的参数)和要执行的操作即可复用。