repo与git(二)repo源码简析

个人邮箱:[email protected]

接下来我们对照着官网提供的下载android源码的过程来看一下使用repo的步骤:

http://source.android.com/source/downloading.html


$ curl https://dl-ssl.google.com/dl/googlesource/git-repo/repo > ~/bin/repo
$ chmod a+x ~/bin/repo
$ repo init -u https://android.googlesource.com/platform/manifest

第一句就是从官网上下载repo,到~/bin文件,该路径已经被提前加入到环境变量中了。这样就可以在任何路径下运行repo了。成功后显示:


    

在进入文件后我们看到了repo就在那里了,如果要运行还需要更改成可执行可执行权限。其实它就是一个几百行的shell脚本,其实这并不是真正的repo,而只是一个bootstrap,这个shell脚本虽然是以shell文法开头,但是内容却全部是python语法,据说这就是这个脚本的神奇之处,我们简要分析。

忽略掉部分注释:

magic='—calling-python-from-/bin/sh--' 
"""exec" python -E "$0" "$@" """#$magic" 
if __name__ == '__main__': 
  import sys 
  if sys.argv[-1] == '#%s' % magic: 
    del sys.argv[-1] 
del magic

      这个部分可谓是repo脚本很有技巧的地方。也就实现了从shellpython过渡。因为shellpython的执行机制有些不同,首先,执行shell时候,是出现错误再停止,而python是保证语法正确才能执行。而上面的代码,在两种脚本中都是正确的语法。

     (1) 在shell中代码是这样的:

magic='—calling-python-from-/bin/sh--'

"""exec" python -E "$0" "$@"  """#$magic"

                 2个"等于空,$0等于脚本名repo,$@为参数(比如init)

               而其语法等效:

exec python -E repo  init #—calling-python-from-/bin/sh--

     (2)在python中代码是这样的:

magic='—calling-python-from-/bin/sh--'

"""exec"python -E "$0" "$@" """#$magic"

                三个"相当于单纯的字符串,#后为注释
                其语法等效于:

magic='—calling-python-from-/bin/sh--'



     而后exec进入到pythonshellexec是创建新进程取代当前进程,并将数据、堆、栈全部转交,PID不变,接下来就全部都是python的活了。于是乎,这里有一个疑问了,repo为什么不直接使用python,而是要先使用shell过度呢?这个问题说实话,个人也不太了解。

     在网上也只是找到一个外文的解释如下,实际上也不算解释,这只是一个在linux/unix上执行Python的一种方法而已,方法的话就不需要什么理由了。

http://effbot.org/pyfaq/how-do-i-make-a-python-script-executable-on-unix.htm 

   接下来我们详细分析repo脚本中,在文章最初时的时候,下载的repobootstrap是在~/bin/路径下,这部分代码会在你在不同目录每次敲入repo init的时候调用,通过网络去加载服务器上的完整的repo文件。如下是,repo init之后的.repo的完整的树形图,所以repo的bootstrap要拷贝一份出来下文好好研究一下。


.repo
└── repo
    ├── color.py
    ├── color.pyc
    ├── command.py
    ├── command.pyc
    ├── COPYING
    ├── docs
    │   └── manifest-format.txt
    ├── editor.py
    ├── editor.pyc
    ├── error.py
    ├── error.pyc
    ├── git_command.py
    ├── git_command.pyc
    ├── git_config.py
    ├── git_config.pyc
    ├── git_refs.py
    ├── git_refs.pyc
    ├── git_ssh
    ├── hooks
    │   ├── commit-msg
    │   └── pre-auto-gc
    ├── main.py
    ├── main.pyc
    ├── manifest_xml.py
    ├── manifest_xml.pyc
    ├── pager.py
    ├── pager.pyc
    ├── progress.py
    ├── progress.pyc
    ├── project.py
    ├── project.pyc
    ├── repo
    ├── repoc
    ├── subcmds
    │   ├── abandon.py
    │   ├── abandon.pyc
    │   ├── branches.py
    │   ├── branches.pyc
    │   ├── checkout.py
    │   ├── checkout.pyc
    │   ├── cherry_pick.py
    │   ├── cherry_pick.pyc
    │   ├── diff.py
    │   ├── diff.pyc
    │   ├── download.py
    │   ├── download.pyc
    │   ├── forall.py
    │   ├── forall.pyc
    │   ├── grep.py
    │   ├── grep.pyc
    │   ├── help.py
    │   ├── help.pyc
    │   ├── __init__.py
    │   ├── init.py
    │   ├── __init__.pyc
    │   ├── init.pyc
    │   ├── list.py
    │   ├── list.pyc
    │   ├── manifest.py
    │   ├── manifest.pyc
    │   ├── overview.py
    │   ├── overview.pyc
    │   ├── prune.py
    │   ├── prune.pyc
    │   ├── rebase.py
    │   ├── rebase.pyc
    │   ├── selfupdate.py
    │   ├── selfupdate.pyc
    │   ├── smartsync.py
    │   ├── smartsync.pyc
    │   ├── stage.py
    │   ├── stage.pyc
    │   ├── start.py
    │   ├── start.pyc
    │   ├── status.py
    │   ├── status.pyc
    │   ├── sync.py
    │   ├── sync.pyc
    │   ├── upload.py
    │   ├── upload.pyc
    │   ├── version.py
    │   └── version.pyc
    ├── SUBMITTING_PATCHES
    ├── tests
    │   ├── fixtures
    │   │   └── test.gitconfig
    │   └── test_git_config.py
    ├── trace.py
    └── trace.pyc

你可能感兴趣的:(repo与git(二)repo源码简析)