Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

set file permissions in setup.py file

I created a python software install with setup.py . In this software I use data files (XML file) when I install these xml file using setup.py then these files save with other files in /usr/lib/python2.7/site_packages/XYZ . But file permission set to these files (XML Files) rwx------ means only super user(root) can read these file I want to change the file permission of XML files as rwxr----- means current user can also read that file. How do I change the data files permission.

like image 409
Arjun Jain Avatar asked May 09 '11 05:05

Arjun Jain


3 Answers

The correct way to do it would be to override the install command, here is how to do it.

First in the beginning of your setup.py add the following imports:

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

Then you need to create a callable command class, here is an example where I create a command class that installs a script and makes sure that it's only executable for root (The are other ways to that in python. For example you can always exit the script, if you UID is not 0.) I am also using another import here:

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)

Now the class is created. I notify the installer that upon seeing install in the command line this class should be invoked:

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

I hope this answer helps.

like image 179
oz123 Avatar answered Nov 05 '22 21:11

oz123


I use setup.py to build RPMs of all kinds. The solution is a little different for me. I also think that it's more robust for two reasons:

  1. I can override the permissions of a file explicitly
  2. I don't need to know the uid and gid of the user. Instead I can use plain text.

here is a working example

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='[email protected]',
      url='https://www.python.org/sigs/distutils-sig/',
      data_files=data_files,
      cmdclass={'bdist_rpm':bdist_rpm}
     )

Let me explain what's going on in more detail. RPMs are built from a SPEC file. bdist_rpm builds a SPEC file. In a SPEC file, you can select the permissions and ownership of a file by supplying the %attr option.

In the example to make test.sh executable and owned by user 'sri' I would add %attr(755, sri, sri) to the end of the SPEC file.

So when I override the behavior of bdist_rpm._make_spec_file all I'm doing is adding a line for each file that I want to override the permissions on.

The full SPEC file from this example would be:

%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 <[email protected]>
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
like image 37
shrewmouse Avatar answered Nov 05 '22 22:11

shrewmouse


Solution Without Editing setup.py

If you just want to install an existing package without editing its setup.py, then try

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

Solution By Editing setup.py

If editing the setup.py file is an option, a quick-and-dirty fix is to add this to the top of the 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', '.'])

This will work on Linux, but perhaps not on other OSes. If you need to support other OSes, or only want to change permissions on the installed files, then replace the chmod call with something more sophisticated like in this other answer.

Explanation

I had problems with setup.py install creating folders that were only readable by root, in addition to copying files with so that htey were only readable by root. It turns out the permissions on folders created by setup.py were determined by my umask, and I believe the permissions on files copied by setup.py are preserved, but I'm less sure about this.

Normative Statement :)

I think it should be the responsibility of setup.py install to use sane defaults -- for example, when I use apt to install software it ignores my umask as it should.

like image 1
ntc2 Avatar answered Nov 05 '22 22:11

ntc2