且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

通过Python setuptools获取远程git分支

更新时间:2023-12-05 14:30:52

我正在深入研究setuptools实现( https://github.com/jaraco/setuptools 保留最新的镜像以方便浏览),它看起来像我一样发现问题在哪里。如果我们看一下负责下载package_index.py中定义的git repos的函数:

  def _download_git(self,url,filename) :
filename = filename.split('#',1)[0]
url,rev = self._vcs_split_rev_from_url(url,pop_prefix = True)

self.info 做git克隆从%s到%s,url,filename)
os.system(git clone --quiet%s%s%(url,filename))

如果rev不是None:
self.info(检出%s,rev)
os.system((cd%s&&&git checkout --quiet%s)% (
文件名,
rev,
))

返回文件名

我们可以看到它首先将其克隆到某个目录(通常是系统临时文件),然后是cd git checkout分支。不幸的是,最近我不得不在Windows上工作,我讨厌这个问题(长期Arch Linux!),并且这个checkout命令的问题在于该系统上的cd不会自动切换驱动器。所以如果你的软件包位于另一个分区/驱动器而不是你的临时目录中,它就不会起作用。我检查了将它改正为:

 (cd / d%s&&&git checkout --quiet%s)

解决了这个问题。尽管这是系统特定的,所以我们(可能)不想让PR去setuptools家伙修改它。相反,我所做的是在我的包文件夹中创建一个临时目录,并添加

  import tempfile 
tempfile.tempdir = os.getcwd()+\\temp\\

到我的设置。 py,它临时更改easy_install的临时目录。这是因为我知道setuptools使用easy_install,而easy_install使用tempfile来获取临时目录的位置。这是一个很好的解决方案,我坚持使用它,但为了传播信息,我还要提到另一件我正在尝试创建的临时系统别名cd到cd / d。在Windows上,这是doskey命令。不幸的是,这是一个本地命令,不会传播到使用os.system()创建的子进程。全局设置这样的别名虽然是一种痛苦,你不想修改潜在用户的系统注册表来实现它。


I've been sitting on this for a while now and here is the question. Do you know if I'm able to reference a git branch in setup.py in any way? Is '@' sign supposed to do that? Or is it used solely for tags and commits? Here is an example of what I was trying to do.

# setup.py
...
install_requires=['Django==1.5.11']
dependency_links=['git+https://github.com/django-nonrel/django.git@nonrel-1.5#egg=Django-1.5.11']
...
#python setup.py develop
running develop
running egg_info
...
Processing dependencies for mypackage
Searching for Django==1.5.11
Best match: Django 1.5.11
Doing git clone from https://github.com/django-nonrel/django.git to c:\users\my_user_name\appdata\local\temp\easy_install-ci3vh1\django.git@nonrel-1.5
Checking out nonrel-1.5
fatal: Not a git repository (or any of the parent directories): .git

Above works without a problem when I'm not referencing any branch:

git+https://github.com/django-nonrel/django.git#egg=Django

And when I run it with pip:

pip install git+https://github.com/django-nonrel/django.git@nonrel-1.5

I included the package name for purpose, so you can look at their git repo setup. I'm not asking for the alternative ways of installing packages from git, as I'm aware of them. Just if it is possible to reference a branch in setup.py. Thanks in advance.

I was digging down through the setuptools implementation (https://github.com/jaraco/setuptools keeps an up-to-date mirror for ease of browsing) and it looks like I've found where the problem is. If we look at the function responsible for downloading git repos defined in package_index.py:

    def _download_git(self, url, filename):
    filename = filename.split('#',1)[0]
    url, rev = self._vcs_split_rev_from_url(url, pop_prefix=True)

    self.info("Doing git clone from %s to %s", url, filename)
    os.system("git clone --quiet %s %s" % (url, filename))

    if rev is not None:
        self.info("Checking out %s", rev)
        os.system("(cd %s && git checkout --quiet %s)" % (
            filename,
            rev,
        ))

    return filename

we can see it's first cloning it to some directory (usually system temp) and then "cd git checkout" 'ing the branch. Unfortunately recently I'm forced to work on Windows, which I hate (long live Arch Linux!), and the problem with this checkout command is that cd on this system doesn't automatically switch the drive. So it's not going to work if your package is located on the other partition/drive than your temp directory. I checked that correcting it to:

(cd /d %s && git checkout --quiet %s)

solves the problem. This is system specific though, so we (probably) don't want to do PR to setuptools guys to modify it. Instead what I did was to create a temp directory in my package folder and add

import tempfile
tempfile.tempdir=os.getcwd()+"\\temp\\"

to my setup.py, which temporary changes the temp directory of easy_install. That's because I know that setuptools uses easy_install and that easy_install uses tempfile to obtain the location of temp dir. This is a good solution and I'm sticking with it, but for the sake of spreading information, I'd also mention that another thing I was trying was to create a temporary system alias for "cd" to "cd /d". On windows this is the doskey command. Unfortunately this is a local command and doesn't spread to subprocesses created with os.system(). Setting such alias globally though is a pain and you don't want to modify system registry of potential users to achieve that.