1# -*- coding: utf-8 -*-
2#
3# Copyright 2007-2011 Brecht Machiels
4# Copyright 2009-2010 Chris Roberts
5# Copyright 2009-2011 Scott McCreary
6# Copyright 2009 Alexander Deynichenko
7# Copyright 2009 HaikuBot (aka RISC)
8# Copyright 2010-2011 Jack Laxson (Jrabbit)
9# Copyright 2011 Ingo Weinhold
10# Copyright 2013 Oliver Tappe
11# Copyright 2016 Jerome Duval
12# Distributed under the terms of the MIT License.
13
14# -- Modules ------------------------------------------------------------------
15
16from multiprocessing import cpu_count
17from optparse import OptionGroup, OptionParser
18
19from .__version__ import __version__
20from .Utils import isCommandAvailable, warn
21
22# -- global options -----------------------------------------------------------
23
24global __Options__
25
26
27# -- getOption ===-------------------------------------------------------------
28
29def getOption(string):
30	"""Fetches an option by name"""
31
32	return getattr(__Options__, string)
33
34
35# -- splitCommaSeparatedList --------------------------------------------------
36
37def setCommaSeparatedList(option, opt, value, parser):
38	setattr(parser.values, option.dest, value.split(','))
39
40
41# -- parseOptions -------------------------------------------------------------
42
43def parseOptions():
44	"""Does command line argument parsing"""
45
46	parser = OptionParser(
47						usage='usage: %prog [options] portname[-portversion]',
48						version='%prog ' + __version__)
49
50	basic_actions = OptionGroup(parser, "Basic Actions", "Basic haikuporter actions")
51
52	basic_actions.add_option('-l', '--list',
53					  action='store_true', dest='list', default=False,
54					  help='list available ports')
55	basic_actions.add_option('--list-packages',
56					  action='store_true', dest='listPackages', default=False,
57					  help='list available packages')
58	basic_actions.add_option('-a', '--about',
59					  action='store_true', dest='about', default=False,
60					  help='show description of the specified port')
61
62	basic_actions.add_option('-s', '--search',
63					  action='store_true', dest='search', default=False,
64					  help='search for a port (regex)')
65	basic_actions.add_option('--search-packages',
66					  action='store_true', dest='searchPackages', default=False,
67					  help='search for a package (regex)')
68	basic_actions.add_option('-E', '--enter-chroot',
69					  action='store_true', dest='enterChroot', default=False,
70					  help="just enter the chroot()-environment, do not build")
71	basic_actions.add_option('--do-bootstrap',
72					  action='store_true', dest='doBootstrap', default=False,
73					  help="build all packages with cyclic dependencies")
74	basic_actions.add_option('-D', '--analyze-dependencies',
75					  action='store_true', dest='analyzeDependencies',
76					  default=False,
77					  help="analyze dependencies between ports and print "
78						"information; no port parameter required")
79	basic_actions.add_option('-c', '--clean',
80					  action='store_true', dest='clean', default=False,
81					  help="clean the working directory of the specified port")
82
83	basic_actions.add_option('--purge',
84					  action='store_true', dest='purge', default=False,
85					  help="clean the working directory and remove downloads "
86					  "of the specified port")
87	basic_actions.add_option('-g', '--get',
88					  action='store_true', dest='get', default=False,
89					  help="get/update the ports tree")
90	basic_actions.add_option('-t', '--tree',
91					  action='store_true', dest='tree', default=False,
92					  help="print out the location of the haikuports source "
93						   "tree")
94	basic_actions.add_option('--lint',
95					  action='store_true', dest='lint', default=False,
96					  help="scan the ports tree for problems")
97	basic_actions.add_option('--list-dependencies', action='store_true',
98		dest='listDependencies', default=False,
99		help='list dependencies of a port')
100	basic_actions.add_option('--build-master', action='store_true', dest='buildMaster',
101		default=False,
102		help='run as build master and delegate builds to builders')
103
104
105	basic_flags = OptionGroup(parser, "Basic Options", "Basic modifications to haikuporter functionality")
106
107	basic_flags.add_option('-o', '--location',
108					  action='store_true', dest='location', default=False,
109					  help="print out the location of a recipe (via search, "
110						   "for scripted editing)")
111
112	basic_flags.add_option('-q', '--quiet',
113					  action='store_true', dest='quiet', default=False,
114					  help="suppress output from build actions")
115	basic_flags.add_option('-v', '--verbose',
116					  action='store_true', dest='verbose', default=False,
117					  help="show why the recipe is broken")
118	basic_flags.add_option('-y', '--yes',
119					  action='store_true', dest='yes', default=False,
120					  help="answer yes to all questions")
121	basic_flags.add_option('-j', '--jobs',
122					  action='store', type="int", dest='jobs', default=cpu_count(),
123					  help="the number of concurrent jobs to build with")
124	basic_flags.add_option('-S', '--strict-policy',
125					  action='store_true', dest='strictPolicy', default=False,
126					  help="require strict packaging policy adherence; "
127						"packaging will fail on any policy violation")
128	basic_flags.add_option('--debug',
129					  action='store_true', dest='debug', default=False,
130					  help="show Python stack traces for fatal errors")
131
132	basic_flags.add_option('-n', '--nopatch',
133					  action='store_false', dest='patch', default=True,
134					  help="don't patch the sources, just download and unpack")
135	basic_flags.add_option('-e', '--extract-patchset',
136					  action='store_true', dest='extractPatchset', default=False,
137					  help='extract current patchset(s) from port source(s)')
138	basic_flags.add_option('-G', '--no-git-repo',
139					  action='store_true', dest='noGitRepo', default=False,
140					  help="don't create git-repo(s) for port source(s)")
141	basic_flags.add_option('-B', '--patch-files-only',
142					  action='store_true', dest='patchFilesOnly',
143					  default=False,
144					  help="don't build the port, just download, unpack and "
145						   "apply patch files; don't call PATCH() though")
146	basic_flags.add_option('-b', '--nobuild',
147					  action='store_false', dest='build', default=True,
148					  help="don't build the port, just download, unpack and "
149						   "patch")
150	basic_flags.add_option('-p', '--nopackage',
151					  action='store_false', dest='package', default=True,
152					  help="don't create package, stop after build")
153	basic_flags.add_option('--all-dependencies',
154					  action='store_true', dest='allDependencies', default=False,
155					  help="build all outdated dependencies for the given port.")
156	basic_flags.add_option('--get-dependencies',
157					  action='store_true', dest='getDependencies', default=False,
158					  help="install all needed dependencies, then build the port")
159	basic_flags.add_option('--update-dependencies',
160					  action='store_true', dest='updateDependencies', default=False,
161					  help="build or update required dependencies (stop on hpkg),"
162							" then build the port")
163	basic_flags.add_option('--missing-dependencies', action='store_true',
164		dest='missingDependencies', default=False, help='build missing direct'
165			' and indirect dependencies, then build the port')
166
167	basic_flags.add_option('--no-source-packages',
168					  action='store_true', dest='noSourcePackages',
169					  default=False,
170					  help="don't create any source packages")
171	basic_flags.add_option('--test',
172					  action='store_true', dest='test', default=False,
173					  help="run tests on resulting binaries")
174	basic_flags.add_option('-C', '--nochroot',
175					  action='store_false', dest='chroot', default=True,
176					  help="build without a chroot()-environment - meant "
177						   "for debugging the build/install process")
178	basic_flags.add_option('-f', '--force',
179					  action='store_true', dest='force', default=False,
180					  help="force to perform the steps (unpack, patch, build)")
181	basic_flags.add_option('-F', '--preserve-flags',
182					  action='store_true', dest='preserveFlags', default=False,
183					  help="don't clear any flags when a changed recipe file "
184						   "is detected")
185
186	basic_flags.add_option('-P', '--portsfile',
187					  action='store', type='string', dest='portsfile',
188					  default='',
189					  help="handle all ports in the given file")
190	basic_flags.add_option('--create-source-packages',
191					  action='store_true',
192					  dest='createSourcePackages',
193					  default=False,
194					  help="build only the (regular) source packages")
195	basic_flags.add_option('--create-source-packages-for-bootstrap',
196					  action='store_true',
197					  dest='createSourcePackagesForBootstrap',
198					  default=False,
199					  help="build only source packages as required by the"
200						   "bootstrap image")
201	basic_flags.add_option('-w', '--why',
202					  action='store', type='string', dest='why',
203					  default='',
204					  help='determine why the given port is pulled in as a '
205						   'dependency of the port to be built')
206
207	basic_flags.add_option('--config',
208					  action='store', type='string', dest='configFile',
209					  default=None,
210					  help='specifies the location of the global config file; '
211						   'the default is "~/config/settings/haikuports.conf"')
212
213	basic_flags.add_option('--print-raw', action='store_true', dest='printRaw',
214		default=False, help='print machine readable output for use by scripts')
215
216	basic_flags.add_option('--print-filenames', action='store_true',
217		dest='printFilenames', default=False, help='print filenames instead of '
218			+ 'package names in package listings and searches')
219
220	basic_flags.add_option('--ignore-messages', action='store_true',
221		dest='ignoreMessages', default=False,
222		help='ignore messages within recipes')
223
224	advanced_flags = OptionGroup(parser, "Advanced Options", "Advanced modifications to haikuporter functionality")
225
226	advanced_flags.add_option('--cross-devel-package',
227					  action='store', type='string', dest='crossDevelPackage',
228					  default=None,
229					  help='path to the cross development package (the actual '
230						   '"sysroot" package); the default (when '
231						   'cross-building at all) is the one to be found in '
232						   '"/boot/system/develop/cross" matching the target '
233						   'architecture')
234	advanced_flags.add_option('--secondary-cross-devel-packages',
235					  action='callback', callback=setCommaSeparatedList,
236					  type='string', dest='secondaryCrossDevelPackages',
237					  default=[],
238					  help='comma-separated list of paths to a secondary cross '
239							'development package (the actual "sysroot" '
240							'package); one path must be specified for each '
241							'configured secondary target architecture '
242							'(specified in the same order)')
243	advanced_flags.add_option('--licenses',
244					  action='store', type='string', dest='licensesDirectory',
245					  default=None,
246					  help='path to the directory containing the well-known '
247						   'licenses; the default is '
248						   '"<systemDir>/data/licenses"')
249	advanced_flags.add_option('--system-mimedb',
250					  action='store', type='string', dest='systemMimeDB',
251					  default=None,
252					  help='path to the directory containing the system '
253						   'MIME DB; the default is "<systemDir>/data/mime_db"')
254	advanced_flags.add_option('--command-mimeset',
255					  action='store', type='string', dest='commandMimeset',
256					  default=None,
257					  help='specifies the "mimeset" command; '
258						   'the default is "mimeset"')
259	advanced_flags.add_option('--command-package',
260					  action='store', type='string', dest='commandPackage',
261					  default=None,
262					  help='specifies the "package" command; '
263						   'the default is "package"')
264	advanced_flags.add_option('--command-package-repo',
265					  action='store', type='string', dest='commandPackageRepo',
266					  default=None,
267					  help='specifies the "package_repo" command; '
268						   'the default is "package_repo"')
269	advanced_flags.add_option('--cross-tools',
270					  action='store', type='string', dest='crossTools',
271					  default=None,
272					  help='specifies the path to the cross-tools directory '
273						   'created by the Haiku build system\'s configure '
274						   'script')
275
276	advanced_flags.add_option('--sourceforge-mirror',
277					  action='store', type='string', dest='sourceforgeMirror',
278					  default=None,
279					  help='mirror to be used for sourceforge')
280	advanced_flags.add_option('--no-system-packages', action='store_true',
281		dest='noSystemPackages', default=False,
282		help='do not use system packages to resolve dependencies')
283
284	advanced_flags.add_option('--repository-update', action='store_true',
285		dest='repositoryUpdate', default=False,
286		help='update dependency infos in the repository')
287	advanced_flags.add_option('--check-repository-consistency', action='store_true',
288		dest='checkRepositoryConsistency', default=False,
289		help='check the consistency of the repository')
290	advanced_flags.add_option('--no-repository-update', action='store_true',
291		dest='noRepositoryUpdate', default=False,
292		help='do not update dependency infos in the repository')
293	advanced_flags.add_option('--no-package-obsoletion', action='store_true',
294		dest='noPackageObsoletion', default=False,
295		help='do not move obsolete packages out of packages dir')
296	advanced_flags.add_option('--prune-package-repository', action='store_true',
297		dest='prunePackageRepository', default=False,
298		help='prune the package repository')
299	advanced_flags.add_option('--create-package-repository', action='store',
300		type='string', dest='createPackageRepository', default=None,
301		help='create a package repository at the given output path')
302	advanced_flags.add_option('--sign-package-repository-privkey-file', action='store',
303		type='string', dest='packageRepositorySignPrivateKeyFile', default=None,
304		help='sign the package repository with the given minisign private key file')
305	advanced_flags.add_option('--sign-package-repository-privkey-pass', action='store',
306		type='string', dest='packageRepositorySignPrivateKeyPass', default=None,
307		help='sign the package repository with the given minisign password')
308	advanced_flags.add_option('--check-package-repository-consistency',
309		action='store_true', dest='checkPackageRepositoryConsistency',
310		default=False, help='check consistency of package repository by'
311			+ ' dependency solving all packages')
312	advanced_flags.add_option('--literal-search-strings', action='store_true',
313		dest='literalSearchStrings', default=False,
314		help='treat search strings as literals instead of as expressions')
315	advanced_flags.add_option('--ports-for-files', action='store_true',
316		dest='portsForFiles', default=False,
317		help='list all ports affected by the supplied list of files')
318	advanced_flags.add_option('--ports-for-packages', action='store_true',
319		dest='portsForPackages', default=False,
320		help='list ports producing the supplied list of packages')
321	advanced_flags.add_option('--active-versions-only', action='store_true',
322		dest='activeVersionsOnly', default=False,
323		help='only check in active versions of ports instead of all ports')
324	advanced_flags.add_option('--check-ports-releases', action='store_true',
325		dest='checkPortsReleases', default=False,
326		help='check for newer releases of ports published upstream')
327
328	buildmaster_flags = OptionGroup(parser, "Build Master Options",
329		"Options only relevant to Haikuporter running in build master mode")
330	buildmaster_flags.add_option('--system-packages-directory', action='store',
331		type='string', dest='systemPackagesDirectory', default=None,
332		help='specifies the directory to be used to look up system packages')
333	buildmaster_flags.add_option('--build-master-output-dir', action='store',
334		type='string', dest='buildMasterOutputDir', default=None,
335		help='specifies where build master output shall be written')
336	buildmaster_flags.add_option('--reporting-uri', action='store', type='string',
337		dest='reportingURI', default=None,
338		help='specifies an optional remote reporting server (ex: mongodb://)')
339	buildmaster_flags.add_option('--local-builders', action='store', type='int',
340		dest='localBuilders', default=0, help='number of local builders (native Haiku only)')
341	buildmaster_flags.add_option('--console', action='store_true', dest='display',
342		default=False,
343		help='display a build master curses console')
344
345	parser.add_option_group(basic_actions)
346	parser.add_option_group(basic_flags)
347	parser.add_option_group(advanced_flags)
348	parser.add_option_group(buildmaster_flags)
349
350	global __Options__
351
352	(__Options__, args) = parser.parse_args()
353
354	# some normalization
355	if (getOption('patchFilesOnly') or not getOption('patch')
356		or getOption('extractPatchset')):
357		setattr(__Options__, 'build', False)
358	if not getOption('build'):
359		setattr(__Options__, 'package', False)
360	if getOption('updateDependencies') or getOption('missingDependencies'):
361		setattr(__Options__, 'allDependencies', True)
362	if getOption('enterChroot'):
363		setattr(__Options__, 'noSourcePackages', True)
364	elif not isCommandAvailable('git'):
365		if not getOption('doBootstrap'):
366			warn("deactivating creation of source packages as 'git' is not "
367				 u"available")
368		setattr(__Options__, 'noSourcePackages', True)
369
370	return (__Options__, args)
371