setup.py 48 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261
  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. '''
  4. The setup script for salt
  5. '''
  6. # pylint: disable=file-perms,ungrouped-imports,wrong-import-order,wrong-import-position,repr-flag-used-in-string
  7. # pylint: disable=3rd-party-local-module-not-gated,resource-leakage
  8. # pylint: disable=C0111,E1101,E1103,F0401,W0611,W0201,W0232,R0201,R0902,R0903
  9. # For Python 2.5. A no-op on 2.6 and above.
  10. from __future__ import absolute_import, print_function, with_statement
  11. import os
  12. import sys
  13. import glob
  14. import time
  15. import operator
  16. import platform
  17. try:
  18. from urllib2 import urlopen
  19. except ImportError:
  20. from urllib.request import urlopen # pylint: disable=no-name-in-module
  21. from datetime import datetime
  22. # pylint: disable=E0611
  23. import distutils.dist
  24. from distutils import log
  25. from distutils.cmd import Command
  26. from distutils.errors import DistutilsArgError
  27. from distutils.command.build import build
  28. from distutils.command.clean import clean
  29. from distutils.command.sdist import sdist
  30. from distutils.command.install_lib import install_lib
  31. from distutils.version import LooseVersion # pylint: disable=blacklisted-module
  32. from ctypes.util import find_library
  33. # pylint: enable=E0611
  34. try:
  35. import zmq
  36. HAS_ZMQ = True
  37. except ImportError:
  38. HAS_ZMQ = False
  39. try:
  40. DATE = datetime.utcfromtimestamp(int(os.environ['SOURCE_DATE_EPOCH']))
  41. except (KeyError, ValueError):
  42. DATE = datetime.utcnow()
  43. # Change to salt source's directory prior to running any command
  44. try:
  45. SETUP_DIRNAME = os.path.dirname(__file__)
  46. except NameError:
  47. # We're most likely being frozen and __file__ triggered this NameError
  48. # Let's work around that
  49. SETUP_DIRNAME = os.path.dirname(sys.argv[0])
  50. if SETUP_DIRNAME != '':
  51. os.chdir(SETUP_DIRNAME)
  52. SETUP_DIRNAME = os.path.abspath(SETUP_DIRNAME)
  53. BOOTSTRAP_SCRIPT_DISTRIBUTED_VERSION = os.environ.get(
  54. # The user can provide a different bootstrap-script version.
  55. # ATTENTION: A tag for that version MUST exist
  56. 'BOOTSTRAP_SCRIPT_VERSION',
  57. # If no bootstrap-script version was provided from the environment, let's
  58. # provide the one we define.
  59. 'v2014.06.21'
  60. )
  61. # Store a reference to the executing platform
  62. IS_WINDOWS_PLATFORM = sys.platform.startswith('win')
  63. if IS_WINDOWS_PLATFORM:
  64. IS_SMARTOS_PLATFORM = False
  65. else:
  66. # os.uname() not available on Windows.
  67. IS_SMARTOS_PLATFORM = os.uname()[0] == 'SunOS' and os.uname()[3].startswith('joyent_')
  68. # Store a reference whether if we're running under Python 3 and above
  69. IS_PY3 = sys.version_info > (3,)
  70. # Use setuptools only if the user opts-in by setting the USE_SETUPTOOLS env var
  71. # Or if setuptools was previously imported (which is the case when using
  72. # 'distribute')
  73. # This ensures consistent behavior but allows for advanced usage with
  74. # virtualenv, buildout, and others.
  75. WITH_SETUPTOOLS = False
  76. if 'USE_SETUPTOOLS' in os.environ or 'setuptools' in sys.modules:
  77. try:
  78. from setuptools import setup
  79. from setuptools.command.develop import develop
  80. from setuptools.command.install import install
  81. from setuptools.command.sdist import sdist
  82. from setuptools.command.egg_info import egg_info
  83. WITH_SETUPTOOLS = True
  84. except ImportError:
  85. WITH_SETUPTOOLS = False
  86. if WITH_SETUPTOOLS is False:
  87. import warnings
  88. # pylint: disable=E0611
  89. from distutils.command.install import install
  90. from distutils.core import setup
  91. # pylint: enable=E0611
  92. warnings.filterwarnings(
  93. 'ignore',
  94. 'Unknown distribution option: \'(extras_require|tests_require|install_requires|zip_safe)\'',
  95. UserWarning,
  96. 'distutils.dist'
  97. )
  98. try:
  99. # Add the esky bdist target if the module is available
  100. # may require additional modules depending on platform
  101. from esky import bdist_esky
  102. # bbfreeze chosen for its tight integration with distutils
  103. import bbfreeze
  104. HAS_ESKY = True
  105. except ImportError:
  106. HAS_ESKY = False
  107. SALT_VERSION = os.path.join(os.path.abspath(SETUP_DIRNAME), 'salt', 'version.py')
  108. SALT_VERSION_HARDCODED = os.path.join(os.path.abspath(SETUP_DIRNAME), 'salt', '_version.py')
  109. SALT_SYSPATHS_HARDCODED = os.path.join(os.path.abspath(SETUP_DIRNAME), 'salt', '_syspaths.py')
  110. SALT_REQS = os.path.join(os.path.abspath(SETUP_DIRNAME), 'requirements', 'base.txt')
  111. SALT_ZEROMQ_REQS = os.path.join(os.path.abspath(SETUP_DIRNAME), 'requirements', 'zeromq.txt')
  112. SALT_RAET_REQS = os.path.join(os.path.abspath(SETUP_DIRNAME), 'requirements', 'raet.txt')
  113. SALT_WINDOWS_REQS = os.path.join(os.path.abspath(SETUP_DIRNAME), 'pkg', 'windows', 'req.txt')
  114. SALT_LONG_DESCRIPTION_FILE = os.path.join(os.path.abspath(SETUP_DIRNAME), 'README.rst')
  115. # Salt SSH Packaging Detection
  116. PACKAGED_FOR_SALT_SSH_FILE = os.path.join(os.path.abspath(SETUP_DIRNAME), '.salt-ssh-package')
  117. PACKAGED_FOR_SALT_SSH = os.path.isfile(PACKAGED_FOR_SALT_SSH_FILE)
  118. # pylint: disable=W0122
  119. exec(compile(open(SALT_VERSION).read(), SALT_VERSION, 'exec'))
  120. # pylint: enable=W0122
  121. # ----- Helper Functions -------------------------------------------------------------------------------------------->
  122. def _parse_op(op):
  123. '''
  124. >>> _parse_op('>')
  125. 'gt'
  126. >>> _parse_op('>=')
  127. 'ge'
  128. >>> _parse_op('=>')
  129. 'ge'
  130. >>> _parse_op('=> ')
  131. 'ge'
  132. >>> _parse_op('<')
  133. 'lt'
  134. >>> _parse_op('<=')
  135. 'le'
  136. >>> _parse_op('==')
  137. 'eq'
  138. >>> _parse_op(' <= ')
  139. 'le'
  140. '''
  141. op = op.strip()
  142. if '>' in op:
  143. if '=' in op:
  144. return 'ge'
  145. else:
  146. return 'gt'
  147. elif '<' in op:
  148. if '=' in op:
  149. return 'le'
  150. else:
  151. return 'lt'
  152. elif '!' in op:
  153. return 'ne'
  154. else:
  155. return 'eq'
  156. def _parse_ver(ver):
  157. '''
  158. >>> _parse_ver("'3.4' # pyzmq 17.1.0 stopped building wheels for python3.4")
  159. '3.4'
  160. >>> _parse_ver('"3.4"')
  161. '3.4'
  162. >>> _parse_ver('"2.6.17"')
  163. '2.6.17'
  164. '''
  165. if '#' in ver:
  166. ver, _ = ver.split('#', 1)
  167. ver = ver.strip()
  168. return ver.strip('\'').strip('"')
  169. def _check_ver(pyver, op, wanted):
  170. '''
  171. >>> _check_ver('2.7.15', 'gt', '2.7')
  172. True
  173. >>> _check_ver('2.7.15', 'gt', '2.7.15')
  174. False
  175. >>> _check_ver('2.7.15', 'ge', '2.7.15')
  176. True
  177. >>> _check_ver('2.7.15', 'eq', '2.7.15')
  178. True
  179. '''
  180. pyver = distutils.version.LooseVersion(pyver)
  181. wanted = distutils.version.LooseVersion(wanted)
  182. if IS_PY3:
  183. if not isinstance(pyver, str):
  184. pyver = str(pyver)
  185. if not isinstance(wanted, str):
  186. wanted = str(wanted)
  187. return getattr(operator, '__{}__'.format(op))(pyver, wanted)
  188. def _parse_requirements_file(requirements_file):
  189. parsed_requirements = []
  190. with open(requirements_file) as rfh:
  191. for line in rfh.readlines():
  192. line = line.strip()
  193. if not line or line.startswith(('#', '-r')):
  194. continue
  195. if IS_WINDOWS_PLATFORM:
  196. if 'libcloud' in line:
  197. continue
  198. if IS_PY3 and 'futures' in line.lower():
  199. # Python 3 already has futures, installing it will only break
  200. # the current python installation whenever futures is imported
  201. continue
  202. try:
  203. pkg, pyverspec = line.rsplit(';', 1)
  204. except ValueError:
  205. pkg, pyverspec = line, ''
  206. pyverspec = pyverspec.strip()
  207. if pyverspec:
  208. _, op, ver = pyverspec.split(' ', 2)
  209. if not _check_ver(platform.python_version(), _parse_op(op), _parse_ver(ver)):
  210. continue
  211. parsed_requirements.append(pkg)
  212. return parsed_requirements
  213. # <---- Helper Functions ---------------------------------------------------------------------------------------------
  214. # ----- Custom Distutils/Setuptools Commands ------------------------------------------------------------------------>
  215. class WriteSaltVersion(Command):
  216. description = 'Write salt\'s hardcoded version file'
  217. user_options = []
  218. def initialize_options(self):
  219. '''
  220. Abstract method that is required to be overwritten
  221. '''
  222. def finalize_options(self):
  223. '''
  224. Abstract method that is required to be overwritten
  225. '''
  226. def run(self):
  227. if not os.path.exists(SALT_VERSION_HARDCODED) or self.distribution.with_salt_version:
  228. # Write the version file
  229. if getattr(self.distribution, 'salt_version_hardcoded_path', None) is None:
  230. print('This command is not meant to be called on it\'s own')
  231. exit(1)
  232. if not self.distribution.with_salt_version:
  233. salt_version = __saltstack_version__ # pylint: disable=undefined-variable
  234. else:
  235. from salt.version import SaltStackVersion
  236. salt_version = SaltStackVersion.parse(self.distribution.with_salt_version)
  237. # pylint: disable=E0602
  238. open(self.distribution.salt_version_hardcoded_path, 'w').write(
  239. INSTALL_VERSION_TEMPLATE.format(
  240. date=DATE,
  241. full_version_info=salt_version.full_info
  242. )
  243. )
  244. # pylint: enable=E0602
  245. class GenerateSaltSyspaths(Command):
  246. description = 'Generate salt\'s hardcoded syspaths file'
  247. def initialize_options(self):
  248. pass
  249. def finalize_options(self):
  250. pass
  251. def run(self):
  252. # Write the syspaths file
  253. if getattr(self.distribution, 'salt_syspaths_hardcoded_path', None) is None:
  254. print('This command is not meant to be called on it\'s own')
  255. exit(1)
  256. # Write the system paths file
  257. open(self.distribution.salt_syspaths_hardcoded_path, 'w').write(
  258. INSTALL_SYSPATHS_TEMPLATE.format(
  259. date=DATE,
  260. root_dir=self.distribution.salt_root_dir,
  261. share_dir=self.distribution.salt_share_dir,
  262. config_dir=self.distribution.salt_config_dir,
  263. cache_dir=self.distribution.salt_cache_dir,
  264. sock_dir=self.distribution.salt_sock_dir,
  265. srv_root_dir=self.distribution.salt_srv_root_dir,
  266. base_file_roots_dir=self.distribution.salt_base_file_roots_dir,
  267. base_pillar_roots_dir=self.distribution.salt_base_pillar_roots_dir,
  268. base_master_roots_dir=self.distribution.salt_base_master_roots_dir,
  269. base_thorium_roots_dir=self.distribution.salt_base_thorium_roots_dir,
  270. logs_dir=self.distribution.salt_logs_dir,
  271. pidfile_dir=self.distribution.salt_pidfile_dir,
  272. spm_formula_path=self.distribution.salt_spm_formula_dir,
  273. spm_pillar_path=self.distribution.salt_spm_pillar_dir,
  274. spm_reactor_path=self.distribution.salt_spm_reactor_dir,
  275. home_dir=self.distribution.salt_home_dir,
  276. )
  277. )
  278. class WriteSaltSshPackagingFile(Command):
  279. description = 'Write salt\'s ssh packaging file'
  280. user_options = []
  281. def initialize_options(self):
  282. '''
  283. Abstract method that is required to be overwritten
  284. '''
  285. def finalize_options(self):
  286. '''
  287. Abstract method that is required to be overwritten
  288. '''
  289. def run(self):
  290. if not os.path.exists(PACKAGED_FOR_SALT_SSH_FILE):
  291. # Write the salt-ssh packaging file
  292. if getattr(self.distribution, 'salt_ssh_packaging_file', None) is None:
  293. print('This command is not meant to be called on it\'s own')
  294. exit(1)
  295. # pylint: disable=E0602
  296. open(self.distribution.salt_ssh_packaging_file, 'w').write('Packaged for Salt-SSH\n')
  297. # pylint: enable=E0602
  298. if WITH_SETUPTOOLS:
  299. class Develop(develop):
  300. user_options = develop.user_options + [
  301. ('write-salt-version', None,
  302. 'Generate Salt\'s _version.py file which allows proper version '
  303. 'reporting. This defaults to False on develop/editable setups. '
  304. 'If WRITE_SALT_VERSION is found in the environment this flag is '
  305. 'switched to True.'),
  306. ('generate-salt-syspaths', None,
  307. 'Generate Salt\'s _syspaths.py file which allows tweaking some '
  308. 'common paths that salt uses. This defaults to False on '
  309. 'develop/editable setups. If GENERATE_SALT_SYSPATHS is found in '
  310. 'the environment this flag is switched to True.'),
  311. ('mimic-salt-install', None,
  312. 'Mimmic the install command when running the develop command. '
  313. 'This will generate salt\'s _version.py and _syspaths.py files. '
  314. 'Generate Salt\'s _syspaths.py file which allows tweaking some '
  315. 'This defaults to False on develop/editable setups. '
  316. 'If MIMIC_INSTALL is found in the environment this flag is '
  317. 'switched to True.')
  318. ]
  319. boolean_options = develop.boolean_options + [
  320. 'write-salt-version',
  321. 'generate-salt-syspaths',
  322. 'mimic-salt-install'
  323. ]
  324. def initialize_options(self):
  325. develop.initialize_options(self)
  326. self.write_salt_version = False
  327. self.generate_salt_syspaths = False
  328. self.mimic_salt_install = False
  329. def finalize_options(self):
  330. develop.finalize_options(self)
  331. if 'WRITE_SALT_VERSION' in os.environ:
  332. self.write_salt_version = True
  333. if 'GENERATE_SALT_SYSPATHS' in os.environ:
  334. self.generate_salt_syspaths = True
  335. if 'MIMIC_SALT_INSTALL' in os.environ:
  336. self.mimic_salt_install = True
  337. if self.mimic_salt_install:
  338. self.write_salt_version = True
  339. self.generate_salt_syspaths = True
  340. def run(self):
  341. if IS_WINDOWS_PLATFORM:
  342. # Download the required DLLs
  343. self.distribution.salt_download_windows_dlls = True
  344. self.run_command('download-windows-dlls')
  345. self.distribution.salt_download_windows_dlls = None
  346. if self.write_salt_version is True:
  347. self.distribution.running_salt_install = True
  348. self.distribution.salt_version_hardcoded_path = SALT_VERSION_HARDCODED
  349. self.run_command('write_salt_version')
  350. if self.generate_salt_syspaths:
  351. self.distribution.salt_syspaths_hardcoded_path = SALT_SYSPATHS_HARDCODED
  352. self.run_command('generate_salt_syspaths')
  353. # Resume normal execution
  354. develop.run(self)
  355. def uri_to_resource(resource_file):
  356. # ## Returns the URI for a resource
  357. # The basic case is that the resource is on saltstack.com
  358. # It could be the case that the resource is cached.
  359. salt_uri = 'https://repo.saltstack.com/windows/dependencies/' + resource_file
  360. if os.getenv('SALTREPO_LOCAL_CACHE') is None:
  361. # if environment variable not set, return the basic case
  362. return salt_uri
  363. if not os.path.isdir(os.getenv('SALTREPO_LOCAL_CACHE')):
  364. # if environment variable is not a directory, return the basic case
  365. return salt_uri
  366. cached_resource = os.path.join(os.getenv('SALTREPO_LOCAL_CACHE'), resource_file)
  367. cached_resource = cached_resource.replace('/', '\\')
  368. if not os.path.isfile(cached_resource):
  369. # if file does not exist, return the basic case
  370. return salt_uri
  371. if os.path.getsize(cached_resource) == 0:
  372. # if file has zero size, return the basic case
  373. return salt_uri
  374. return cached_resource
  375. class DownloadWindowsDlls(Command):
  376. description = 'Download required DLL\'s for windows'
  377. def initialize_options(self):
  378. pass
  379. def finalize_options(self):
  380. pass
  381. def run(self):
  382. if getattr(self.distribution, 'salt_download_windows_dlls', None) is None:
  383. print('This command is not meant to be called on it\'s own')
  384. exit(1)
  385. import pip
  386. # pip has moved many things to `_internal` starting with pip 10
  387. if LooseVersion(pip.__version__) < LooseVersion('10.0'):
  388. from pip.utils.logging import indent_log # pylint: disable=no-name-in-module
  389. else:
  390. from pip._internal.utils.logging import indent_log # pylint: disable=no-name-in-module
  391. platform_bits, _ = platform.architecture()
  392. url = 'https://repo.saltstack.com/windows/dependencies/{bits}/{fname}.dll'
  393. dest = os.path.join(os.path.dirname(sys.executable), '{fname}.dll')
  394. with indent_log():
  395. for fname in ('libeay32', 'libsodium', 'ssleay32', 'msvcr120'):
  396. # See if the library is already on the system
  397. if find_library(fname):
  398. continue
  399. furl = url.format(bits=platform_bits[:2], fname=fname)
  400. fdest = dest.format(fname=fname)
  401. if not os.path.exists(fdest):
  402. log.info('Downloading {0}.dll to {1} from {2}'.format(fname, fdest, furl))
  403. try:
  404. import requests
  405. from contextlib import closing
  406. with closing(requests.get(furl, stream=True)) as req:
  407. if req.status_code == 200:
  408. with open(fdest, 'wb') as wfh:
  409. for chunk in req.iter_content(chunk_size=4096):
  410. if chunk: # filter out keep-alive new chunks
  411. wfh.write(chunk)
  412. wfh.flush()
  413. else:
  414. log.error(
  415. 'Failed to download {0}.dll to {1} from {2}'.format(
  416. fname, fdest, furl
  417. )
  418. )
  419. except ImportError:
  420. req = urlopen(furl)
  421. if req.getcode() == 200:
  422. with open(fdest, 'wb') as wfh:
  423. if IS_PY3:
  424. while True:
  425. chunk = req.read(4096)
  426. if len(chunk) == 0:
  427. break
  428. wfh.write(chunk)
  429. wfh.flush()
  430. else:
  431. while True:
  432. for chunk in req.read(4096):
  433. if not chunk:
  434. break
  435. wfh.write(chunk)
  436. wfh.flush()
  437. else:
  438. log.error(
  439. 'Failed to download {0}.dll to {1} from {2}'.format(
  440. fname, fdest, furl
  441. )
  442. )
  443. class Sdist(sdist):
  444. def make_release_tree(self, base_dir, files):
  445. if self.distribution.ssh_packaging:
  446. self.distribution.salt_ssh_packaging_file = PACKAGED_FOR_SALT_SSH_FILE
  447. self.run_command('write_salt_ssh_packaging_file')
  448. self.filelist.files.append(os.path.basename(PACKAGED_FOR_SALT_SSH_FILE))
  449. if not IS_PY3 and not isinstance(base_dir, str):
  450. # Work around some bad code in distutils which logs unicode paths
  451. # against a str format string.
  452. base_dir = base_dir.encode('utf-8')
  453. sdist.make_release_tree(self, base_dir, files)
  454. # Let's generate salt/_version.py to include in the sdist tarball
  455. self.distribution.running_salt_sdist = True
  456. self.distribution.salt_version_hardcoded_path = os.path.join(
  457. base_dir, 'salt', '_version.py'
  458. )
  459. self.run_command('write_salt_version')
  460. def make_distribution(self):
  461. sdist.make_distribution(self)
  462. if self.distribution.ssh_packaging:
  463. os.unlink(PACKAGED_FOR_SALT_SSH_FILE)
  464. class CloudSdist(Sdist): # pylint: disable=too-many-ancestors
  465. user_options = Sdist.user_options + [
  466. ('download-bootstrap-script', None,
  467. 'Download the latest stable bootstrap-salt.sh script. This '
  468. 'can also be triggered by having `DOWNLOAD_BOOTSTRAP_SCRIPT=1` as an '
  469. 'environment variable.')
  470. ]
  471. boolean_options = Sdist.boolean_options + [
  472. 'download-bootstrap-script'
  473. ]
  474. def initialize_options(self):
  475. Sdist.initialize_options(self)
  476. self.skip_bootstrap_download = True
  477. self.download_bootstrap_script = False
  478. def finalize_options(self):
  479. Sdist.finalize_options(self)
  480. if 'SKIP_BOOTSTRAP_DOWNLOAD' in os.environ:
  481. log('Please stop using \'SKIP_BOOTSTRAP_DOWNLOAD\' and use ' # pylint: disable=not-callable
  482. '\'DOWNLOAD_BOOTSTRAP_SCRIPT\' instead')
  483. if 'DOWNLOAD_BOOTSTRAP_SCRIPT' in os.environ:
  484. download_bootstrap_script = os.environ.get(
  485. 'DOWNLOAD_BOOTSTRAP_SCRIPT', '0'
  486. )
  487. self.download_bootstrap_script = download_bootstrap_script == '1'
  488. def run(self):
  489. if self.download_bootstrap_script is True:
  490. # Let's update the bootstrap-script to the version defined to be
  491. # distributed. See BOOTSTRAP_SCRIPT_DISTRIBUTED_VERSION above.
  492. url = (
  493. 'https://github.com/saltstack/salt-bootstrap/raw/{0}'
  494. '/bootstrap-salt.sh'.format(
  495. BOOTSTRAP_SCRIPT_DISTRIBUTED_VERSION
  496. )
  497. )
  498. deploy_path = os.path.join(
  499. SETUP_DIRNAME,
  500. 'salt',
  501. 'cloud',
  502. 'deploy',
  503. 'bootstrap-salt.sh'
  504. )
  505. log.info(
  506. 'Updating bootstrap-salt.sh.'
  507. '\n\tSource: {0}'
  508. '\n\tDestination: {1}'.format(
  509. url,
  510. deploy_path
  511. )
  512. )
  513. try:
  514. import requests
  515. req = requests.get(url)
  516. if req.status_code == 200:
  517. script_contents = req.text.encode(req.encoding)
  518. else:
  519. log.error(
  520. 'Failed to update the bootstrap-salt.sh script. HTTP '
  521. 'Error code: {0}'.format(
  522. req.status_code
  523. )
  524. )
  525. except ImportError:
  526. req = urlopen(url)
  527. if req.getcode() == 200:
  528. script_contents = req.read()
  529. else:
  530. log.error(
  531. 'Failed to update the bootstrap-salt.sh script. HTTP '
  532. 'Error code: {0}'.format(
  533. req.getcode()
  534. )
  535. )
  536. try:
  537. with open(deploy_path, 'w') as fp_:
  538. fp_.write(script_contents)
  539. except (OSError, IOError) as err:
  540. log.error(
  541. 'Failed to write the updated script: {0}'.format(err)
  542. )
  543. # Let's the rest of the build command
  544. Sdist.run(self)
  545. def write_manifest(self):
  546. # We only need to ship the scripts which are supposed to be installed
  547. dist_scripts = self.distribution.scripts
  548. for script in self.filelist.files[:]:
  549. if not script.startswith('scripts/'):
  550. continue
  551. if script not in dist_scripts:
  552. self.filelist.files.remove(script)
  553. return Sdist.write_manifest(self)
  554. class TestCommand(Command):
  555. description = 'Run tests'
  556. user_options = [
  557. ('runtests-opts=', 'R', 'Command line options to pass to runtests.py')
  558. ]
  559. def initialize_options(self):
  560. self.runtests_opts = None
  561. def finalize_options(self):
  562. '''
  563. Abstract method that is required to be overwritten
  564. '''
  565. def run(self):
  566. from subprocess import Popen
  567. self.run_command('build')
  568. build_cmd = self.get_finalized_command('build_ext')
  569. runner = os.path.abspath('tests/runtests.py')
  570. test_cmd = sys.executable + ' {0}'.format(runner)
  571. if self.runtests_opts:
  572. test_cmd += ' {0}'.format(self.runtests_opts)
  573. print('running test')
  574. test_process = Popen(
  575. test_cmd, shell=True,
  576. stdout=sys.stdout, stderr=sys.stderr,
  577. cwd=build_cmd.build_lib
  578. )
  579. test_process.communicate()
  580. sys.exit(test_process.returncode)
  581. class Clean(clean):
  582. def run(self):
  583. clean.run(self)
  584. # Let's clean compiled *.py[c,o]
  585. for subdir in ('salt', 'tests', 'doc'):
  586. root = os.path.join(os.path.dirname(__file__), subdir)
  587. for dirname, _, _ in os.walk(root):
  588. for to_remove_filename in glob.glob('{0}/*.py[oc]'.format(dirname)):
  589. os.remove(to_remove_filename)
  590. INSTALL_VERSION_TEMPLATE = '''\
  591. # This file was auto-generated by salt's setup
  592. from salt.version import SaltStackVersion
  593. __saltstack_version__ = SaltStackVersion{full_version_info!r}
  594. '''
  595. INSTALL_SYSPATHS_TEMPLATE = '''\
  596. # This file was auto-generated by salt's setup on \
  597. {date:%A, %d %B %Y @ %H:%m:%S UTC}.
  598. ROOT_DIR = {root_dir!r}
  599. SHARE_DIR = {share_dir!r}
  600. CONFIG_DIR = {config_dir!r}
  601. CACHE_DIR = {cache_dir!r}
  602. SOCK_DIR = {sock_dir!r}
  603. SRV_ROOT_DIR= {srv_root_dir!r}
  604. BASE_FILE_ROOTS_DIR = {base_file_roots_dir!r}
  605. BASE_PILLAR_ROOTS_DIR = {base_pillar_roots_dir!r}
  606. BASE_MASTER_ROOTS_DIR = {base_master_roots_dir!r}
  607. BASE_THORIUM_ROOTS_DIR = {base_thorium_roots_dir!r}
  608. LOGS_DIR = {logs_dir!r}
  609. PIDFILE_DIR = {pidfile_dir!r}
  610. SPM_FORMULA_PATH = {spm_formula_path!r}
  611. SPM_PILLAR_PATH = {spm_pillar_path!r}
  612. SPM_REACTOR_PATH = {spm_reactor_path!r}
  613. HOME_DIR = {home_dir!r}
  614. '''
  615. class Build(build):
  616. def run(self):
  617. # Run build.run function
  618. build.run(self)
  619. if getattr(self.distribution, 'with_salt_version', False):
  620. # Write the hardcoded salt version module salt/_version.py
  621. self.distribution.salt_version_hardcoded_path = os.path.join(
  622. self.build_lib, 'salt', '_version.py'
  623. )
  624. self.run_command('write_salt_version')
  625. if getattr(self.distribution, 'running_salt_install', False):
  626. # If our install attribute is present and set to True, we'll go
  627. # ahead and write our install time python modules.
  628. # Write the hardcoded salt version module salt/_version.py
  629. self.run_command('write_salt_version')
  630. # Write the system paths file
  631. self.distribution.salt_syspaths_hardcoded_path = os.path.join(
  632. self.build_lib, 'salt', '_syspaths.py'
  633. )
  634. self.run_command('generate_salt_syspaths')
  635. class Install(install):
  636. def initialize_options(self):
  637. install.initialize_options(self)
  638. def finalize_options(self):
  639. install.finalize_options(self)
  640. def run(self):
  641. # Let's set the running_salt_install attribute so we can add
  642. # _version.py in the build command
  643. self.distribution.running_salt_install = True
  644. self.distribution.salt_version_hardcoded_path = os.path.join(
  645. self.build_lib, 'salt', '_version.py'
  646. )
  647. if IS_WINDOWS_PLATFORM:
  648. # Download the required DLLs
  649. self.distribution.salt_download_windows_dlls = True
  650. self.run_command('download-windows-dlls')
  651. self.distribution.salt_download_windows_dlls = None
  652. # Run install.run
  653. install.run(self)
  654. class InstallLib(install_lib):
  655. def run(self):
  656. executables = [
  657. 'salt/templates/git/ssh-id-wrapper',
  658. 'salt/templates/lxc/salt_tarball',
  659. ]
  660. install_lib.run(self)
  661. # input and outputs match 1-1
  662. inp = self.get_inputs()
  663. out = self.get_outputs()
  664. chmod = []
  665. for idx, inputfile in enumerate(inp):
  666. for executable in executables:
  667. if inputfile.endswith(executable):
  668. chmod.append(idx)
  669. for idx in chmod:
  670. filename = out[idx]
  671. os.chmod(filename, 0o755)
  672. # <---- Custom Distutils/Setuptools Commands -------------------------------------------------------------------------
  673. # ----- Custom Distribution Class ----------------------------------------------------------------------------------->
  674. # We use this to override the package name in case --ssh-packaging is passed to
  675. # setup.py or the special .salt-ssh-package is found
  676. class SaltDistribution(distutils.dist.Distribution):
  677. '''
  678. Just so it's completely clear
  679. Under windows, the following scripts should be installed:
  680. * salt-call
  681. * salt-cp
  682. * salt-minion
  683. * salt-unity
  684. * salt-proxy
  685. When packaged for salt-ssh, the following scripts should be installed:
  686. * salt-call
  687. * salt-run
  688. * salt-ssh
  689. * salt-cloud
  690. Under windows, the following scripts should be omitted from the salt-ssh package:
  691. * salt-cloud
  692. * salt-run
  693. Under *nix, all scripts should be installed
  694. '''
  695. global_options = distutils.dist.Distribution.global_options + [
  696. ('ssh-packaging', None, 'Run in SSH packaging mode'),
  697. ('salt-transport=', None, 'The transport to prepare salt for. Choices are \'zeromq\' '
  698. '\'raet\' or \'both\'. Defaults to \'zeromq\'', 'zeromq')] + [
  699. ('with-salt-version=', None, 'Set a fixed version for Salt instead calculating it'),
  700. # Salt's Paths Configuration Settings
  701. ('salt-root-dir=', None,
  702. 'Salt\'s pre-configured root directory'),
  703. ('salt-share-dir=', None,
  704. 'Salt\'s pre-configured share directory'),
  705. ('salt-config-dir=', None,
  706. 'Salt\'s pre-configured configuration directory'),
  707. ('salt-cache-dir=', None,
  708. 'Salt\'s pre-configured cache directory'),
  709. ('salt-sock-dir=', None,
  710. 'Salt\'s pre-configured socket directory'),
  711. ('salt-srv-root-dir=', None,
  712. 'Salt\'s pre-configured service directory'),
  713. ('salt-base-file-roots-dir=', None,
  714. 'Salt\'s pre-configured file roots directory'),
  715. ('salt-base-pillar-roots-dir=', None,
  716. 'Salt\'s pre-configured pillar roots directory'),
  717. ('salt-base-master-roots-dir=', None,
  718. 'Salt\'s pre-configured master roots directory'),
  719. ('salt-logs-dir=', None,
  720. 'Salt\'s pre-configured logs directory'),
  721. ('salt-pidfile-dir=', None,
  722. 'Salt\'s pre-configured pidfiles directory'),
  723. ('salt-spm-formula-dir=', None,
  724. 'Salt\'s pre-configured SPM formulas directory'),
  725. ('salt-spm-pillar-dir=', None,
  726. 'Salt\'s pre-configured SPM pillar directory'),
  727. ('salt-spm-reactor-dir=', None,
  728. 'Salt\'s pre-configured SPM reactor directory'),
  729. ('salt-home-dir=', None,
  730. 'Salt\'s pre-configured user home directory'),
  731. ]
  732. def __init__(self, attrs=None):
  733. distutils.dist.Distribution.__init__(self, attrs)
  734. self.ssh_packaging = PACKAGED_FOR_SALT_SSH
  735. self.salt_transport = None
  736. # Salt Paths Configuration Settings
  737. self.salt_root_dir = None
  738. self.salt_share_dir = None
  739. self.salt_config_dir = None
  740. self.salt_cache_dir = None
  741. self.salt_sock_dir = None
  742. self.salt_srv_root_dir = None
  743. self.salt_base_file_roots_dir = None
  744. self.salt_base_thorium_roots_dir = None
  745. self.salt_base_pillar_roots_dir = None
  746. self.salt_base_master_roots_dir = None
  747. self.salt_logs_dir = None
  748. self.salt_pidfile_dir = None
  749. self.salt_spm_formula_dir = None
  750. self.salt_spm_pillar_dir = None
  751. self.salt_spm_reactor_dir = None
  752. self.salt_home_dir = None
  753. # Salt version
  754. self.with_salt_version = None
  755. self.name = 'salt-ssh' if PACKAGED_FOR_SALT_SSH else 'salt'
  756. self.salt_version = __version__ # pylint: disable=undefined-variable
  757. self.description = 'Portable, distributed, remote execution and configuration management system'
  758. kwargs = {}
  759. if IS_PY3:
  760. kwargs['encoding'] = 'utf-8'
  761. with open(SALT_LONG_DESCRIPTION_FILE, **kwargs) as f:
  762. self.long_description = f.read()
  763. self.long_description_content_type = 'text/x-rst'
  764. self.author = 'Thomas S Hatch'
  765. self.author_email = 'thatch45@gmail.com'
  766. self.url = 'http://saltstack.org'
  767. self.cmdclass.update({'test': TestCommand,
  768. 'clean': Clean,
  769. 'build': Build,
  770. 'sdist': Sdist,
  771. 'install': Install,
  772. 'write_salt_version': WriteSaltVersion,
  773. 'generate_salt_syspaths': GenerateSaltSyspaths,
  774. 'write_salt_ssh_packaging_file': WriteSaltSshPackagingFile})
  775. if not IS_WINDOWS_PLATFORM:
  776. self.cmdclass.update({'sdist': CloudSdist,
  777. 'install_lib': InstallLib})
  778. if IS_WINDOWS_PLATFORM:
  779. self.cmdclass.update({'download-windows-dlls': DownloadWindowsDlls})
  780. if WITH_SETUPTOOLS:
  781. self.cmdclass.update({'develop': Develop})
  782. self.license = 'Apache Software License 2.0'
  783. self.packages = self.discover_packages()
  784. self.zip_safe = False
  785. if HAS_ESKY:
  786. self.setup_esky()
  787. self.update_metadata()
  788. def update_metadata(self):
  789. for attrname in dir(self):
  790. if attrname.startswith('__'):
  791. continue
  792. attrvalue = getattr(self, attrname, None)
  793. if attrvalue == 0:
  794. continue
  795. if attrname == 'salt_version':
  796. attrname = 'version'
  797. if hasattr(self.metadata, 'set_{0}'.format(attrname)):
  798. getattr(self.metadata, 'set_{0}'.format(attrname))(attrvalue)
  799. elif hasattr(self.metadata, attrname):
  800. try:
  801. setattr(self.metadata, attrname, attrvalue)
  802. except AttributeError:
  803. pass
  804. def discover_packages(self):
  805. modules = []
  806. for root, _, files in os.walk(os.path.join(SETUP_DIRNAME, 'salt')):
  807. if '__init__.py' not in files:
  808. continue
  809. modules.append(os.path.relpath(root, SETUP_DIRNAME).replace(os.sep, '.'))
  810. return modules
  811. # ----- Static Data -------------------------------------------------------------------------------------------->
  812. @property
  813. def _property_classifiers(self):
  814. return ['Programming Language :: Python',
  815. 'Programming Language :: Cython',
  816. 'Programming Language :: Python :: 2.6',
  817. 'Programming Language :: Python :: 2.7',
  818. 'Development Status :: 5 - Production/Stable',
  819. 'Environment :: Console',
  820. 'Intended Audience :: Developers',
  821. 'Intended Audience :: Information Technology',
  822. 'Intended Audience :: System Administrators',
  823. 'License :: OSI Approved :: Apache Software License',
  824. 'Operating System :: POSIX :: Linux',
  825. 'Topic :: System :: Clustering',
  826. 'Topic :: System :: Distributed Computing']
  827. @property
  828. def _property_dependency_links(self):
  829. return ['https://github.com/saltstack/salt-testing/tarball/develop#egg=SaltTesting']
  830. @property
  831. def _property_tests_require(self):
  832. return ['SaltTesting']
  833. # <---- Static Data ----------------------------------------------------------------------------------------------
  834. # ----- Dynamic Data -------------------------------------------------------------------------------------------->
  835. @property
  836. def _property_package_data(self):
  837. package_data = {'salt.templates': ['rh_ip/*.jinja',
  838. 'debian_ip/*.jinja',
  839. 'virt/*.jinja',
  840. 'git/*',
  841. 'lxc/*',
  842. ]}
  843. if not IS_WINDOWS_PLATFORM:
  844. package_data['salt.cloud'] = ['deploy/*.sh']
  845. if not self.ssh_packaging and not PACKAGED_FOR_SALT_SSH:
  846. package_data['salt.daemons.flo'] = ['*.flo']
  847. return package_data
  848. @property
  849. def _property_data_files(self):
  850. # Data files common to all scenarios
  851. data_files = [
  852. ('share/man/man1', ['doc/man/salt-call.1', 'doc/man/salt-run.1']),
  853. ('share/man/man7', ['doc/man/salt.7'])
  854. ]
  855. if self.ssh_packaging or PACKAGED_FOR_SALT_SSH:
  856. data_files[0][1].append('doc/man/salt-ssh.1')
  857. if IS_WINDOWS_PLATFORM:
  858. return data_files
  859. data_files[0][1].append('doc/man/salt-cloud.1')
  860. return data_files
  861. if IS_WINDOWS_PLATFORM:
  862. data_files[0][1].extend(['doc/man/salt-cp.1',
  863. 'doc/man/salt-key.1',
  864. 'doc/man/salt-master.1',
  865. 'doc/man/salt-minion.1',
  866. 'doc/man/salt-proxy.1',
  867. 'doc/man/salt-unity.1'])
  868. return data_files
  869. # *nix, so, we need all man pages
  870. data_files[0][1].extend(['doc/man/salt-api.1',
  871. 'doc/man/salt-cloud.1',
  872. 'doc/man/salt-cp.1',
  873. 'doc/man/salt-key.1',
  874. 'doc/man/salt-master.1',
  875. 'doc/man/salt-minion.1',
  876. 'doc/man/salt-proxy.1',
  877. 'doc/man/spm.1',
  878. 'doc/man/salt.1',
  879. 'doc/man/salt-ssh.1',
  880. 'doc/man/salt-syndic.1',
  881. 'doc/man/salt-unity.1'])
  882. return data_files
  883. @property
  884. def _property_install_requires(self):
  885. install_requires = _parse_requirements_file(SALT_REQS)
  886. if self.salt_transport == 'zeromq':
  887. install_requires += _parse_requirements_file(SALT_ZEROMQ_REQS)
  888. elif self.salt_transport == 'raet':
  889. install_requires += _parse_requirements_file(SALT_RAET_REQS)
  890. if IS_WINDOWS_PLATFORM:
  891. install_requires = _parse_requirements_file(SALT_WINDOWS_REQS)
  892. return install_requires
  893. @property
  894. def _property_extras_require(self):
  895. if self.ssh_packaging:
  896. return {}
  897. return {'RAET': _parse_requirements_file(SALT_RAET_REQS)}
  898. @property
  899. def _property_scripts(self):
  900. # Scripts common to all scenarios
  901. scripts = ['scripts/salt-call', 'scripts/salt-run']
  902. if self.ssh_packaging or PACKAGED_FOR_SALT_SSH:
  903. scripts.append('scripts/salt-ssh')
  904. if IS_WINDOWS_PLATFORM:
  905. return scripts
  906. scripts.extend(['scripts/salt-cloud', 'scripts/spm'])
  907. return scripts
  908. if IS_WINDOWS_PLATFORM:
  909. scripts.extend(['scripts/salt',
  910. 'scripts/salt-cp',
  911. 'scripts/salt-key',
  912. 'scripts/salt-master',
  913. 'scripts/salt-minion',
  914. 'scripts/salt-proxy',
  915. 'scripts/salt-unity'])
  916. return scripts
  917. # *nix, so, we need all scripts
  918. scripts.extend(['scripts/salt',
  919. 'scripts/salt-api',
  920. 'scripts/salt-cloud',
  921. 'scripts/salt-cp',
  922. 'scripts/salt-key',
  923. 'scripts/salt-master',
  924. 'scripts/salt-minion',
  925. 'scripts/salt-ssh',
  926. 'scripts/salt-syndic',
  927. 'scripts/salt-unity',
  928. 'scripts/salt-proxy',
  929. 'scripts/spm'])
  930. return scripts
  931. @property
  932. def _property_entry_points(self):
  933. # console scripts common to all scenarios
  934. scripts = ['salt-call = salt.scripts:salt_call',
  935. 'salt-run = salt.scripts:salt_run']
  936. if self.ssh_packaging or PACKAGED_FOR_SALT_SSH:
  937. scripts.append('salt-ssh = salt.scripts:salt_ssh')
  938. if IS_WINDOWS_PLATFORM:
  939. return {'console_scripts': scripts}
  940. scripts.append('salt-cloud = salt.scripts:salt_cloud')
  941. return {'console_scripts': scripts}
  942. if IS_WINDOWS_PLATFORM:
  943. scripts.extend(['salt = salt.scripts:salt_main',
  944. 'salt-cp = salt.scripts:salt_cp',
  945. 'salt-key = salt.scripts:salt_key',
  946. 'salt-master = salt.scripts:salt_master',
  947. 'salt-minion = salt.scripts:salt_minion',
  948. 'salt-unity = salt.scripts:salt_unity',
  949. 'spm = salt.scripts:salt_spm'])
  950. return {'console_scripts': scripts}
  951. # *nix, so, we need all scripts
  952. scripts.extend(['salt = salt.scripts:salt_main',
  953. 'salt-api = salt.scripts:salt_api',
  954. 'salt-cloud = salt.scripts:salt_cloud',
  955. 'salt-cp = salt.scripts:salt_cp',
  956. 'salt-key = salt.scripts:salt_key',
  957. 'salt-master = salt.scripts:salt_master',
  958. 'salt-minion = salt.scripts:salt_minion',
  959. 'salt-ssh = salt.scripts:salt_ssh',
  960. 'salt-syndic = salt.scripts:salt_syndic',
  961. 'salt-unity = salt.scripts:salt_unity',
  962. 'spm = salt.scripts:salt_spm'])
  963. return {'console_scripts': scripts}
  964. # <---- Dynamic Data ---------------------------------------------------------------------------------------------
  965. # ----- Esky Setup ---------------------------------------------------------------------------------------------->
  966. def setup_esky(self):
  967. opt_dict = self.get_option_dict('bdist_esky')
  968. opt_dict['freezer_module'] = ('setup script', 'bbfreeze')
  969. opt_dict['freezer_options'] = ('setup script', {'includes': self.get_esky_freezer_includes()})
  970. @property
  971. def _property_freezer_options(self):
  972. return {'includes': self.get_esky_freezer_includes()}
  973. def get_esky_freezer_includes(self):
  974. # Sometimes the auto module traversal doesn't find everything, so we
  975. # explicitly add it. The auto dependency tracking especially does not work for
  976. # imports occurring in salt.modules, as they are loaded at salt runtime.
  977. # Specifying includes that don't exist doesn't appear to cause a freezing
  978. # error.
  979. freezer_includes = [
  980. 'zmq.core.*',
  981. 'zmq.utils.*',
  982. 'ast',
  983. 'csv',
  984. 'difflib',
  985. 'distutils',
  986. 'distutils.version',
  987. 'numbers',
  988. 'json',
  989. 'M2Crypto',
  990. 'Cookie',
  991. 'asyncore',
  992. 'fileinput',
  993. 'sqlite3',
  994. 'email',
  995. 'email.mime.*',
  996. 'requests',
  997. 'sqlite3',
  998. ]
  999. if HAS_ZMQ and hasattr(zmq, 'pyzmq_version_info'):
  1000. if HAS_ZMQ and zmq.pyzmq_version_info() >= (0, 14):
  1001. # We're freezing, and when freezing ZMQ needs to be installed, so this
  1002. # works fine
  1003. if 'zmq.core.*' in freezer_includes:
  1004. # For PyZMQ >= 0.14, freezing does not need 'zmq.core.*'
  1005. freezer_includes.remove('zmq.core.*')
  1006. if IS_WINDOWS_PLATFORM:
  1007. freezer_includes.extend([
  1008. 'imp',
  1009. 'win32api',
  1010. 'win32file',
  1011. 'win32con',
  1012. 'win32com',
  1013. 'win32net',
  1014. 'win32netcon',
  1015. 'win32gui',
  1016. 'win32security',
  1017. 'ntsecuritycon',
  1018. 'pywintypes',
  1019. 'pythoncom',
  1020. '_winreg',
  1021. 'wmi',
  1022. 'site',
  1023. 'psutil',
  1024. 'pytz',
  1025. ])
  1026. elif IS_SMARTOS_PLATFORM:
  1027. # we have them as requirements in pkg/smartos/esky/requirements.txt
  1028. # all these should be safe to force include
  1029. freezer_includes.extend([
  1030. 'cherrypy',
  1031. 'dateutils',
  1032. 'pyghmi',
  1033. 'croniter',
  1034. 'mako',
  1035. 'gnupg',
  1036. ])
  1037. elif sys.platform.startswith('linux'):
  1038. freezer_includes.append('spwd')
  1039. try:
  1040. import yum # pylint: disable=unused-variable
  1041. freezer_includes.append('yum')
  1042. except ImportError:
  1043. pass
  1044. elif sys.platform.startswith('sunos'):
  1045. # (The sledgehammer approach)
  1046. # Just try to include everything
  1047. # (This may be a better way to generate freezer_includes generally)
  1048. try:
  1049. from bbfreeze.modulegraph.modulegraph import ModuleGraph
  1050. mgraph = ModuleGraph(sys.path[:])
  1051. for arg in glob.glob('salt/modules/*.py'):
  1052. mgraph.run_script(arg)
  1053. for mod in mgraph.flatten():
  1054. if type(mod).__name__ != 'Script' and mod.filename:
  1055. freezer_includes.append(str(os.path.basename(mod.identifier)))
  1056. except ImportError:
  1057. pass
  1058. # Include C extension that convinces esky to package up the libsodium C library
  1059. # This is needed for ctypes to find it in libnacl which is in turn needed for raet
  1060. # see pkg/smartos/esky/sodium_grabber{.c,_installer.py}
  1061. freezer_includes.extend([
  1062. 'sodium_grabber',
  1063. 'ioflo',
  1064. 'raet',
  1065. 'libnacl',
  1066. ])
  1067. return freezer_includes
  1068. # <---- Esky Setup -----------------------------------------------------------------------------------------------
  1069. # ----- Overridden Methods -------------------------------------------------------------------------------------->
  1070. def parse_command_line(self):
  1071. args = distutils.dist.Distribution.parse_command_line(self)
  1072. if not self.ssh_packaging and PACKAGED_FOR_SALT_SSH:
  1073. self.ssh_packaging = 1
  1074. if self.ssh_packaging:
  1075. self.metadata.name = 'salt-ssh'
  1076. self.salt_transport = 'ssh'
  1077. elif self.salt_transport is None:
  1078. self.salt_transport = 'zeromq'
  1079. if self.salt_transport not in ('zeromq', 'raet', 'both', 'ssh', 'none'):
  1080. raise DistutilsArgError(
  1081. 'The value of --salt-transport needs be \'zeromq\', '
  1082. '\'raet\', \'both\', \'ssh\' or \'none\' not \'{0}\''.format(
  1083. self.salt_transport
  1084. )
  1085. )
  1086. # Setup our property functions after class initialization and
  1087. # after parsing the command line since most are set to None
  1088. # ATTENTION: This should be the last step before returning the args or
  1089. # some of the requirements won't be correctly set
  1090. for funcname in dir(self):
  1091. if not funcname.startswith('_property_'):
  1092. continue
  1093. property_name = funcname.split('_property_', 1)[-1]
  1094. setattr(self, property_name, getattr(self, funcname))
  1095. return args
  1096. # <---- Overridden Methods ---------------------------------------------------------------------------------------
  1097. # <---- Custom Distribution Class ------------------------------------------------------------------------------------
  1098. if __name__ == '__main__':
  1099. setup(distclass=SaltDistribution)