本文适用于需要使用两台及以上 Mac 进行办公的用户,且拥有一定限制条件,这些限制是由 Anaconda 自身限制所带来的。

# 前言

台式机一般都是在家里用,笔记本则用于外出携带,桌面和文稿可以由 iCloud 进行同步,代码则交由 GitHub 托管。那么问题就来了,开发环境该如何同步呢?使用 GitHub CodeSpace 构建云端开发环境或者使用 Docker 封装开发环境都是一些可选的解决方案,但总归还是直接在本地来的方便。命令行历史同步同理,在电脑 A 上使用过的命令,在电脑 B 又要输入一遍,有时候记不起来,降低了整体效率。之前其实也饱受该问题的折磨,但也懒得折腾,不过随着天气越来越冷,笔记本的适用范围又扩充到了被窝,终于下定决心来搞定这两个问题。

既然 iCloud 可以同步文件,自然可以同步这些开发环境。本质上命令行历史记录以及开发环境都是一些文件,只需要进行合理设置就可以了。所用的 zsh 就是使用~/.zsh_history 来进行命令行历史的记录的,而 Anaconda 则是安装时候的文件夹。具体思路是这样子,但在实际操作时有一些细微的问题需要处理。

# 命令行历史同步

~/.zsh_history 中的内容举例如下:

: 1606565794:0;cat ~/.zsh_history

前面的是时间戳,后面的是执行的命令。最开始的思路就是写个脚本将不同电脑上的文件进行合并,之后放置于 iCloud 上,将 zsh 的历史记录文件指向 iCloud 上的文件即可,这样还有一个好处,在电脑 A 上使用新的命令之后,在电脑 B 上也可以马上更新,不过这取决于 iCloud 的服务质量,但大部分时间应该都是可以马上响应的。

之后在 GitHub 上发现了一个功能稍加丰富的插件,即 zsh-histdb,原理就是将命令行历史导入 sqlite 数据库,并将 zsh-autosuggestions 的查询指向该数据库,不同的机器之间同步则采用 GitHub 的形式。

# 插件安装

mkdir -p $HOME/.oh-my-zsh/custom/plugins/
git clone https://github.com/larkery/zsh-histdb $HOME/.oh-my-zsh/custom/plugins/zsh-histdb

并在 ~/.zshrc 中添加如下内容:

HISTDB_TABULATE_CMD=(sed -e $'s/\x1f/\t/g')
source $HOME/.oh-my-zsh/custom/plugins/zsh-histdb/sqlite-history.zsh
autoload -Uz add-zsh-hook
_zsh_autosuggest_strategy_histdb_top_here() {
    local query="select commands.argv from
history left join commands on history.command_id = commands.rowid
left join places on history.place_id = places.rowid
where places.dir LIKE '$(sql_escape $PWD)%'
and commands.argv LIKE '$(sql_escape $1)%'
group by commands.argv order by count(*) desc limit 1"
    suggestion=$(_histdb_query "$query")
}
ZSH_AUTOSUGGEST_STRATEGY=histdb_top_here

# 导入命令行历史

go-histdbimportts-histdbimport 是用于导入的工具,根据 Star 数我选择了前者。

安装 go 环境及运行导入命令行历史工具命令如下:

brew install go
go get github.com/drewis/go-histdbimport
go run ~/go/src/github.com/drewis/go-histdbimport/main.go

# 使用

正常使用的时候配合 zsh-autosuggestions 与原本的方式无异,比之前要方便的是可以使用 histdb 来进行历史命令的查看,后面还可以输入关键词进行搜索,比原本更高效一些,还可以使用通配符 %

# 同步数据库

使用 histdb-sync 命令会将~/.histdb 下进行 Git 的初始化,之后再 push 到 GitHub 上即可。我做的有点丑陋,在电脑 A 同步至 GitHub 之后,将电脑 A 的文件夹 AirDrop 给电脑 B,之后同样的方式导入命令行历史记录,再推送至 GitHub,电脑 A 再进行一遍 Fetch 即可。

# iCloud 同步 Anaconda 环境

非常清楚地记得在安装完 Anaconda 之后有一个 conda init 的环节,就是在 shell 配置文件中添加关于 conda 的内容。一开始我以为使用 iCloud 同步 Anaconda 环境非常的简单,只需要将 Anaconda 的安装时候的文件夹移动到 iCloud 上,并将 shell 配置文件中的指向改为 iCloud 上的文件夹即可,但事实并不是这样。

# 失败的尝试

该部分属于失败的尝试,可以直接拉到该小节结尾看总结,节省时间

当我将 Anaconda 文件夹移动到 iCloud 之后,我发现有 10 多个 G 的文件,于是我准备删除一些不用的环境,但是在删完之后发现,命令确实执行成功了,但被删除的环境竟然是原来的 Anaconda 上的,iCloud 上的依然还在,这让我开始有点疑惑了,于是查看 shell 配置文件中关于 conda 部分的内容:

# >>> conda initialize >>>
# !! Contents within this block are managed by 'conda init' !!
__conda_setup="$('/Users/xyzlab/anaconda3/bin/conda' 'shell.zsh' 'hook' 2> /dev/null)"
if [ $? -eq 0 ]; then
    eval "$__conda_setup"
else
    if [ -f "/Users/xyzlab/anaconda3/etc/profile.d/conda.sh" ]; then
        . "/Users/xyzlab/anaconda3/etc/profile.d/conda.sh"
    else
        export PATH="/Users/xyzlab/anaconda3/bin:$PATH"
    fi
fi
unset __conda_setup
# <<< conda initialize <<<

发现两个比较关键的部分,一个是 conda 文件,另一个则是 conda.sh,看着像配置文件,打开这两个文件看看到底有什么问题(只显示关建行):

#!/Users/xyzlab/anaconda3/bin/python
# -*- coding: utf-8 -*-
export CONDA_EXE='/Users/xyzlab/anaconda3/bin/conda'
export _CE_M=''
export _CE_CONDA=''
export CONDA_PYTHON_EXE='/Users/xyzlab/anaconda3/bin/python'

好家伙,发现这两个文件下的路径还是指向原来的 Anaconda 文件夹,所以之前能够正常运行 conda 且能删除原先 Anaconda 文件夹下的环境。

以为通过修改这个路径就可以实现环境同步的时候,我又遇到了一个新的错误,iCloud 所在的路径是

/Users/xyzlab/Library/Mobile Documents/

而 Anaconda 不支持带有空格的路径,我加了转义符或是通过字符串的形式都不行,于是将 iCloud 上的 Anaconda 文件移动到 Mac 上的「文件」文件夹下,这样一来既可以解决路径名称存在空格(桌面其实也可以,但是放在桌面太不优雅了,眼不见为净),又可以解决同步问题。

就当我以为要成功的时候,又遇到了一个错误,问题的出错形式跟上面的类似,也是路径问题,所以如果要实现 Anaconda 的迁移的话差不多需要把整个 bin 文件夹下的路径都修改了,一是工程量太庞大了且容易出错,二是可能会存在一些隐患,比如说没有处理到的问题,在未来某一天就出现了,埋下祸根。

总之直接迁移 Anaconda 文件夹来实现环境的同步实现不了,具体限制跟 Anaconda 自身也有关系,主要是:

  1. Anaconda 安装包会调用当初安装时的路径,且 bin 目录下的文件都会根据当初安装的目录结构进行文件的寻找,在移动之后该条件被破坏,导致 Anaconda 运行失败;
  2. Anaconda 安装路径中不能出现空格,使用转义符也没有效果,而 iCloud 云盘的路径中存在空格。

虽然直接的方法没有,但还是可以使用间接的方法来实现,不说应该也猜到了,就是重新安装一遍 Anaconda 并进行环境的克隆即可。但是,这个方式需要满足以下的条件:

  1. 多台电脑使用者的名称应该一致,如文中使用的用户名称是 xyzlab,则电脑 A,B 都需要使用 xyzlab,这是因为若出现用户名称不一致的情况会导致之前 Anaconda 迁移同样的问题;
  2. 将 Anaconda 安装于「文件」文件夹下,当然也可以安装在桌面,不过太丑了不推荐。

# 成功了(个屁)

最新更新:同步之后会存在莫名其妙的错误,如不能创建环境等,该方法作废。

基于上述的两个条件,在满足了之后只需要将 Anaconda 安装于「文件」文件夹即可,新的 Anaconda 中的环境也可以从原先的 Anaconda 环境中克隆,具体使用如下命令即可:

conda create -n 环境名 --clone 原先环境的路径 # 一般在~/anaconda3/envs/ 环境名称

自此,只需要等待 iCloud 完成同步(经测试会出错) AirDrop 之后,更改对应机器上的 shell 配置文件至「文件」文件夹的 Anaconda 即可。