setup.py 47 KB

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