File: setup.py

package info (click to toggle)
python-fsquota 0.1.0%2Bdfsg1-2
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 392 kB
  • sloc: ansic: 2,670; python: 545; makefile: 8
file content (222 lines) | stat: -rw-r--r-- 9,514 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
# ----------------------------------------------------------------------------
# Copyright (C) 1995-2020 T. Zoerner
# ----------------------------------------------------------------------------
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by the
# Free Software Foundation.  (Either version 2 of the GPL, or any later
# version, see http://www.opensource.org/licenses/).
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# ----------------------------------------------------------------------------

from setuptools import setup, Extension
from distutils.command.install import install

import os
import os.path
import sys
import subprocess
import shutil
import re

if sys.version_info[0] != 3:
    print("This script requires Python 3")
    exit()

this_directory = os.path.abspath(os.path.dirname(__file__))
myconfig_h = os.path.join(this_directory, 'myconfig.h')

# ----------------------------------------------------------------------------
# Note most configuration (including compile-switches) is done via includes
# in the hints/ directory. The following only manages source lists and libs
# ----------------------------------------------------------------------------

extrasrc = []
extrainc = []
extradef = []
extralibs = []
extralibdirs = []

#
# Select a configuration header file based on OS & revision
#
if sys.version_info[1] >= 5:
    osr = subprocess.run(['uname', '-rs'], stdout=subprocess.PIPE).stdout.decode('utf-8')
else:  # subprocess.run() does not exist before 3.5
    ps = subprocess.Popen(['uname', '-rs'], stdout=subprocess.PIPE)
    osr = ps.communicate()[0].decode('utf-8')

if   re.match(r"^SunOS 4\.1", osr) : config='sunos_4_1.h'
elif re.match(r"^SunOS 5", osr)    : config='solaris_2.h'
elif re.match(r"^HP-UX (A\.09|B\.10|[BC]\.11)", osr): config='hpux.h'
elif re.match(r"^IRIX 5", osr)     : config='irix_5.h'
elif re.match(r"^IRIX\d* 6", osr)  : config='irix_6.h'
elif re.match(r"^OSF1", osr)       : config='dec_osf.h'
elif re.match(r"^Linux", osr)      : config='linux.h'
elif re.match(r"^AIX", osr)        : config='aix_4_1.h'
elif (re.match(r"^dragonfly", osr, flags=re.IGNORECASE) or
      re.match(r"^Darwin", osr)    or
      re.match(r"^FreeBSD", osr)   or
      re.match(r"^NetBSD", osr)    or
      re.match(r"^OpenBSD", osr))  : config='bsd.h'
else:
    print("FATAL: No appropriate hints found for this OS/revision: \"" + osr + "\"\n" +
          "Please see instructions in file INSTALL", file=sys.stderr)
    exit(1)

config = "hints/" + config
print("Using %s for myconfig.h" % config, file=sys.stderr)

if (    os.path.isfile(myconfig_h)
    and (not os.path.islink(myconfig_h) or not (os.readlink(myconfig_h) == config))):
    print("\nFATAL: myconfig.h already exists.\n\n" +
         "You need to do a \"make clean\" before configuring for a new platform.\n" +
         "If that doesn't help, remove myconfig.h manually.", file=sys.stderr)
    exit(1)


# check whether the Andrew File System (AFS) is installed and running
if os.path.isdir("/afs"):
    df_afs = subprocess.run(['df', '/afs'], stdout=subprocess.PIPE).stdout.decode('utf-8')
    if re.match(r"\nAFS|\(AFS/", df_afs):
        AFSHOME = "/usr/afsws" if os.path.isdir("/usr/afsws") else "/usr"
        extradef += [('AFSQUOTA', 1)]
        extrainc += [AFSHOME+"/include", AFSHOME+"/include/afs"]
        extralibdirs += [AFSHOME+"/lib", AFSHOME+"/lib/afs"]
        extralibs += ["sys", "rx", "rxkad", "lwp"]
        extrasrc += ["src/afsquota.c"]

# check to see if we have a kernel module for the Veritas file system
if re.match(r"^SunOS", osr):
    if os.path.isfile('/usr/include/sys/fs/vx_quota.h'):
        extradef += [('SOLARIS_VXFS', 1)];
        extrasrc += ["src/vxquotactl.c"]
        print("Configured with the VERITAS File System on Solaris", file=sys.stderr)
    else:
        # no warning because newer versions of Solaris have internal VxFS support
        #print("Configured without VxFS support", file=sys.stderr)
        pass

# check whether we are using the NetBSD quota library
match1 = re.match(r"^NetBSD 5\.99\.(\d+)", osr)
match2 = re.match(r"^NetBSD (\d)", osr)
if (   (match1 and (int(match1.group(1)) >= 59))
    or (match2 and (int(match2.group(1)) >= 6))):
    extralibs += ["quota"]

# check whether RPCSVC is included within libc
# - SUN RPC/XDR support was split off from glibc, see:
#   https://lists.fedoraproject.org/archives/list/devel@lists.fedoraproject.org/thread/F2NRCEXDDUF6WWNPSOMXRJS6BPMTEEVJ/
# - in RHEL apparently the rpc/rpc.h header was moved too
# - Debian has libtirpc, but headers and implementation are still in glibc too
#   so there's a risk symbols are resolved from libc while compiling against tirpc headers;
#   therefore we do not use tirpc when rpc headers are present outside tirpc
if re.match(r"^Linux", osr):
    extrasrc += ["src/linuxapi.c"]

    if os.path.isdir('/usr/include/tirpc') and not os.path.isfile('/usr/include/rpc/rpc.h'):
        print("Configured to use tirpc library instead of rpcsvc", file=sys.stderr)
        extrainc  += ["/usr/include/tirpc"]
        extralibs += ["tirpc"]
    else:
        if not os.path.isfile('/usr/include/rpc/rpc.h'):
            print("WARNING: Header file /usr/include/rpc/rpc.h not present on this system.\n" +
                  "         Likely compilation will fail. Recommend to either install package\n" +
                  "         \"libtirpc-dev\", or disable RPC (network file system) support by\n" +
                  "         adding the following switch to myconfig.h:\n" +
                  "         #define NO_RPC\n", file=sys.stderr)
        extralibs += ["rpcsvc"]

# ----------------------------------------------------------------------------

class MyClean(install):
    cwd = os.path.abspath(os.path.dirname(__file__))
    def rmfile(self, apath):
        p = os.path.join(MyClean.cwd, apath)
        if os.path.isfile(p):
            os.remove(p)
    def rmtree(self, apath):
        p = os.path.join(MyClean.cwd, apath)
        if os.path.isdir(p):
            shutil.rmtree(p)
    def run(self):
        # files created by configuration stage
        self.rmfile('myconfig.h')
        # files created by build stage
        self.rmtree('build')
        # files created by test stage
        self.rmtree('FsQuota.egg-info')
        self.rmtree('__pycache__')
        for name in os.listdir(MyClean.cwd):
            if re.match(r"^.*\.so$", name):
                os.remove(os.path.join(MyClean.cwd, name))
        self.rmfile('core')
        # files created by sdist stage
        self.rmtree('dist')

# ----------------------------------------------------------------------------
# Finally execute the setup command

with open(os.path.join(this_directory, 'doc/README.rst'), encoding='utf-8') as fh:
    long_description = fh.read()
with open(os.path.join(this_directory, 'doc/FsQuota.rst'), encoding='utf-8') as fh:
    api_doc = fh.read()
    match = re.match(r"[\x00-\xff]*?(?=^SYNOPSIS$)", api_doc, re.MULTILINE)
    if match:
        long_description += "\n\n" + api_doc[match.end():]
    else:
        print("ERROR: Failed to find SYNOPSIS in FsQuota.rst", file=sys.stderr)

if not os.path.isfile(myconfig_h):
    os.symlink(config, myconfig_h)

# Enable work-around for bugs in PyStructSequence_NewType (i.e. for
# creating named tuples in C module; causing crash in GC:
# "Fatal Python error: type_traverse() called for non-heap type")
# Known issue: https://bugs.python.org/issue28709 - fixed in 3.8
if (sys.version_info[0] == 3) and (sys.version_info[1] < 8):
    extradef += [('NAMED_TUPLE_GC_BUG', 1)]

ext = Extension('FsQuota',
                sources       = ['src/FsQuota.c'] + extrasrc,
                include_dirs  = ['.'] + extrainc,
                define_macros = extradef,
                libraries     = extralibs,
                library_dirs  = extralibdirs,
                #undef_macros  = ["NDEBUG"]   # for debug build only
               )

setup(name='FsQuota',
      version='0.1.0',
      description='Interface to file system quotas on UNIX platforms',
      long_description=long_description,
      long_description_content_type="text/x-rst",
      author='T. Zoerner',
      author_email='tomzo@users.sourceforge.net',
      url='https://github.com/tomzox/Python-Quota',
      license = "GNU GPLv2+",
      classifiers=[
          'Development Status :: 4 - Beta',
          "Programming Language :: C",
          "Programming Language :: Python :: 3",
          'Topic :: System :: Filesystems',
          'Topic :: System :: Systems Administration',
          'Intended Audience :: Developers',
          'Intended Audience :: System Administrators',
          "Operating System :: POSIX :: Linux",
          "Operating System :: POSIX :: BSD",
          "Operating System :: POSIX :: AIX",
          "Operating System :: POSIX :: HP-UX",
          "Operating System :: POSIX :: IRIX",
          "Operating System :: POSIX :: SunOS/Solaris",
          "License :: OSI Approved :: GNU General Public License v2 or later (GPLv2+)"
         ],
      keywords="file-system, quota, quotactl, mtab, getmntent",
      platforms=['posix'],
      ext_modules=[ext],
      cmdclass={'clean': MyClean},
      python_requires='>=3.2',
     )