【问题标题】:set file permissions in setup.py file在 setup.py 文件中设置文件权限
【发布时间】:2025-11-26 11:10:01
【问题描述】:

我使用 setup.py 创建了一个 python 软件安装。在这个软件中,当我使用 setup.py 安装这些 xml 文件时,我使用数据文件(XML 文件),然后这些文件与 /usr/lib/python2.7/site_packages/XYZ 中的其他文件一起保存。但是文件权限设置为这些文件(XML 文件)rwx------ 意味着只有超级用户(root)可以读取这些文件我想将 XML 文件的文件权限更改为rwxr----- 意味着当前用户也可以读取该文件。如何更改数据文件权限。

【问题讨论】:

    标签: python setup.py


    【解决方案1】:

    正确的做法是覆盖install 命令,这里是如何做到的。

    首先在您的setup.py 开头添加以下导入:

    from setuptools.command.install import install
    from distutils import log # needed for outputting information messages 
    

    然后你需要创建一个可调用的命令类,这里是一个示例,我创建了一个命令类,它安装一个脚本并确保它只对root 可执行(在 python 中还有其他方法。例如如果您的 UID 不为 0,您可以随时退出脚本。) 我也在这里使用另一个导入:

    from setuptools.command.install_scripts import install_scripts
    
    class OverrideInstall(install):
    
        def run(self):
            uid, gid = 0, 0
            mode = 0700
            install.run(self) # calling install.run(self) insures that everything that happened previously still happens, so the installation does not break! 
            # here we start with doing our overriding and private magic ..
            for filepath in self.get_outputs():
                if self.install_scripts in filepath:
                    log.info("Overriding setuptools mode of scripts ...")
                    log.info("Changing ownership of %s to uid:%s gid %s" %
                             (filepath, uid, gid))
                    os.chown(filepath, uid, gid)
                    log.info("Changing permissions of %s to %s" %
                             (filepath, oct(mode)))
                    os.chmod(filepath, mode)
    

    现在该类已创建。我通知安装程序,在命令行中看到 install 时应该调用这个类:

    setup(
          # keep
          # all the previous keywords you had ...
          # add
          cmdclass={'install': OverrideInstall}
          ) 
    

    我希望这个答案会有所帮助。

    【讨论】:

    • 这个方法是覆盖一切还是只允许设置权限?
    • 如代码所示,它将首先运行通常的安装过程,然后更改权限。
    • 很好,正是我所需要的
    • 从 ipython 运行 os.chown 如果没有以 root 权限运行(就像命令行中的 chown 一样)会失败。这似乎是 linux 内核中的一个安全功能......所以这意味着如果 pip install 由普通用户运行,那么文件将被安装,然后在调用 os.chown 时引发异常。不确定这会对包安装状态产生什么影响。
    【解决方案2】:

    我使用setup.py 来构建各种RPM。解决方案对我来说有点不同。我还认为它更强大有两个原因:

    1. 我可以显式覆盖文件的权限
    2. 我不需要知道用户的uid和gid。相反,我可以使用纯文本。

    这是一个工作示例

    from distutils.core import setup
    import distutils.command.bdist_rpm
    import distutils.command.install
    
    version='13'
    
    data_files = [
        ('/usr/share/blah', ['README', 'test.sh']),
    ]
    
    permissions = [
        ('/usr/share/blah', 'test.sh', '(755, sri, sri)'),
    ]
    
    class bdist_rpm(distutils.command.bdist_rpm.bdist_rpm):
    
        def _make_spec_file(self):
            spec = distutils.command.bdist_rpm.bdist_rpm._make_spec_file(self)
            for path, files , perm in permissions:
    
                ##
                # Add a line to the SPEC file to change the permissions of a
                # specific file upon install.
                #
                # example:
                #   %attr(666, root, root) path/file
                #
                spec.extend(['%attr{} {}/{}'.format(perm, path, files)])
    
            return spec
    
    
    setup(name='sri-testme',
          version=version,
          description='This is garganbe and is only used to test the permision flag behavior',
          author='Chris Gembarowski',
          author_email='chrisg@summationresearch.com',
          url='https://www.python.org/sigs/distutils-sig/',
          data_files=data_files,
          cmdclass={'bdist_rpm':bdist_rpm}
         )
    

    让我更详细地解释发生了什么。 RPM 是从 SPEC 文件构建的。 bdist_rpm 构建一个 SPEC 文件。在 SPEC 文件中,您可以通过提供 %attr 选项来选择文件的权限和所有权。

    在使 test.sh 可执行并归用户“sri”所有的示例中,我将在 SPEC 文件的末尾添加 %attr(755, sri, sri)

    因此,当我覆盖 bdist_rpm._make_spec_file 的行为时,我所做的就是为每个要覆盖权限的文件添加一行。

    此示例中的完整 SPEC 文件为:

    %define name sri-testme
    %define version 13
    %define unmangled_version 13
    %define release 1
    
    Summary: This is garganbe and is only used to test the permision flag behavior
    Name: %{name}
    Version: %{version}
    Release: %{release}
    Source0: %{name}-%{unmangled_version}.tar.gz
    License: UNKNOWN
    Group: Development/Libraries
    BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-buildroot
    Prefix: %{_prefix}
    BuildArch: noarch
    Vendor: Chris Gembarowski <chrisg@summationresearch.com>
    Url: https://www.python.org/sigs/distutils-sig/
    
    %description
    UNKNOWN
    
    %prep
    %setup -n %{name}-%{unmangled_version}
    
    %build
    python setup.py build
    
    %install
    python setup.py install -O1 --root=$RPM_BUILD_ROOT --record=INSTALLED_FILES
    
    %clean
    rm -rf $RPM_BUILD_ROOT
    
    %post
    ##
    # sri will be turned on in the run-once script instead of here
    #
    
    
    %preun
    #!/bin/bash
    
    
    
    %files -f INSTALLED_FILES
    %defattr(-,root,root)
    %attr(755, sri, sri) /usr/share/blah/test.sh
    

    【讨论】:

      【解决方案3】:

      无需编辑的解决方案setup.py

      如果您只想安装现有软件包而不编辑其setup.py,请尝试

      sudo sh -c 'umask 0; \
          python setup.py install --installed files.txt && \
          xargs chmod -R a+rX < files.txt'
      

      编辑解决方案setup.py

      如果编辑setup.py 文件是一个选项,一个快速而简单的解决方法是将其添加到setup.py 的顶部:

      import os, subprocess
      # Set a reasonable umask.
      os.umask(0o022)
      # Make all local files readable and all directories listable.
      subprocess.call(['chmod', '-R', 'a+rX', '.'])
      

      这适用于 Linux,但可能不适用于其他操作系统。如果您需要支持其他操作系统,或者只想更改已安装文件的权限,请将chmod 调用替换为更复杂的调用,例如this other answer

      说明

      我在 setup.py install 创建只能由 root 读取的文件夹时遇到问题,除了复制文件以使 htey 只能由 root 读取。原来setup.py创建的文件夹的权限是由我的umask决定的,我相信setup.py复制的文件的权限被保留了,但我不太确定。

      规范性声明:)

      我认为setup.py install 应该有责任使用合理的默认值——例如,当我使用apt 安装软件时,它应该会忽略我的umask

      【讨论】:

        【解决方案4】:

        以 root 身份登录,并在 shell 中输入:

        chmod 744 你的文件名

        【讨论】:

        • 如果是出于部署目的,要求用户以root身份登录以修补部署是最糟糕的想法
        • 我不希望用户在使用 setup.py 文件安装此软件时手动执行此操作,然后软件会自动执行此操作
        • 不能在发布前设置权限吗?
        • @Bruce 这不是用于部署目的我不希望用户以 root 身份登录来使用这个软件
        • 我已经尝试过这种方法,但是当我使用 setup.py 文件安装时,我会自动更改文件权限