Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to handle configuration files with distutils to respect unixen's FHS?

Suppose we have a program called foo.

If use absolute path:

setup(...,
      data_files=[...,
              ('/etc', ['foo.cfg'])]
)

Then foo$ python setup.py --prefix=/usr/local and we will have /etc/foo.cfg. But we should have /usr/local/etc/foo.cfg instead according to FHS.

What if we use a relative path?

setup(...,
      data_files=[...,
              ('etc', ['foo.cfg'])]
)

Then if we use the default install path, i.e. install to /usr, we will have /usr/etc/foo.cfg. Bad luck again.

So how to do it right?

P.S. To avoid make the problem more complicated, we assume that this program foo cannot run under non unix environment.

like image 409
weakish Avatar asked Jul 24 '10 15:07

weakish


People also ask

Do you need a setup py and setup CFG?

you must have a valid setup.py file apart from setup. cfg and pyproject. toml . You can use the same dummy setup file I shared in the previous section that makes just a single call to the setup() method.

What is setup CFG used for?

The setup.py and setup. cfg files are artefacts of the setuptools module which is designed to help with the packaging process. It is used by pip whose purpose is to install a package either locally or remotely.

Where is distutils CFG?

distutils. cfg | python mingw win32 build | C:\Python27\Lib\distutils · GitHub.

Is setup py deprecated?

With the latest version of setuptools, the python setup.py install command is being deprecated (see https://blog.ganssle.io/articles/2021/10/setup-py-deprecated.html for more info). It is suggested that you can just pip install . to install a package from source, but this does not compile any Cython code.


2 Answers

Sub-classing distutils.command.install.install is not strictly necessary. Instead, data_files could be passed to setup, as per distutils documentation on 'Installing Additional Files'.

e.g.

setup(
    ...
    data_files = [
        (conf_path, ['foo.cfg'])
    ]
)

where conf_path is calculated as per your own requirements. i.e. construct it by testing sys.prefix (instead of self.prefix), like @weakish did above.

like image 136
Alex Leach Avatar answered Nov 17 '22 00:11

Alex Leach


It seems there is no easy way. The problem is that config files are special data files and they deserve special treatment.

So, write our own class:

class myinstall(distutils.command.install.install):
    if self.prefix == '/usr':
        self.conf_prefix = '/etc'
    else:
        self.conf_prefix = self.prefix + '/etc'

    install.finalize_options(self)

    def install_conf(self):
        self.mkpath((self.root or '') + self.conf_prefix)
        for file in self.distribution.conf_files:
        dest = (self.root or '') + self.conf_prefix + '/' +
            os.path.basename(file)
        self.copy_file(file, dest)

    # blah blah blah

Then:

setup(# blah blah blah
  conf_files = ['foo.cfg']
  cmdclass = {'install': myinstall,
      # blah blah blah
  }
)
like image 39
weakish Avatar answered Nov 17 '22 01:11

weakish