vulcan-builder 0.2.4__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
vulcan/__init__.py ADDED
File without changes
@@ -0,0 +1,18 @@
1
+ '''
2
+ Lightweight Python Build Tool
3
+ '''
4
+
5
+ from vulcan.builder.common import nsh, dump, dumps, safe_cd
6
+ from ._vb import task, async_task, main
7
+ import sh
8
+ import pkgutil
9
+
10
+ __path__ = pkgutil.extend_path(__path__, __name__)
11
+
12
+ __all__ = [
13
+ 'task', 'async_task',
14
+ 'main',
15
+ 'nsh', 'sh',
16
+ 'dump', 'dumps',
17
+ 'safe_cd'
18
+ ]
vulcan/builder/_vb.py ADDED
@@ -0,0 +1,384 @@
1
+ """
2
+ Lightweight Python Build Tool
3
+
4
+ """
5
+
6
+ import inspect
7
+ import argparse
8
+ import logging
9
+ import os
10
+ from os import path
11
+ import re
12
+ import importlib.util
13
+ import sys
14
+ import time
15
+ import concurrent.futures
16
+ from vulcan.meta_builder import __version__
17
+ from vulcan.builder.classes import CurrentThreadExecutor
18
+ from vulcan.builder.classes import Task
19
+ # from vulcan.builder.classes import LoggerWrapper
20
+
21
+ _CREDIT_LINE = ("Powered by vb %s "
22
+ "- A Lightweight Python Build Tool." % __version__)
23
+ _LOGGING_FORMAT = "[ %(name)s - %(message)s ]"
24
+ _TASK_PATTERN = re.compile("^([^\\[]+)(\\[([^\\]]*)\\])?$")
25
+ # "^([^\[]+)(\[([^\],=]*(,[^\],=]+)*(,[^\],=]+=[^\],=]+)*)\])?$"
26
+
27
+ thread_pool_executor = concurrent.futures.ThreadPoolExecutor(max_workers=20)
28
+ current_thread_executor = CurrentThreadExecutor()
29
+
30
+
31
+ def load_source(name, filepath):
32
+ """
33
+ Load a build file as a module.
34
+
35
+ Replaces imp.load_source, gone in 3.12, including its handling of a name
36
+ already in sys.modules: the existing module is re-executed in place rather
37
+ than replaced, so references taken before the call stay valid.
38
+ """
39
+ # A build file is free to import the rest of its project by name, and it
40
+ # is not run from a directory Python would have put on the path itself.
41
+ directory = path.dirname(path.abspath(filepath))
42
+ if directory not in sys.path:
43
+ sys.path.insert(0, directory)
44
+
45
+ spec = importlib.util.spec_from_file_location(name, filepath)
46
+ module = sys.modules.get(name)
47
+ if module is None:
48
+ module = importlib.util.module_from_spec(spec)
49
+ sys.modules[name] = module
50
+ spec.loader.exec_module(module)
51
+ return module
52
+
53
+
54
+ def build(args):
55
+ """
56
+ Build the specified module with specified arguments.
57
+
58
+ @type module: module
59
+ @type args: list of arguments
60
+ """
61
+ # Build the command line.
62
+ parser = _create_parser()
63
+
64
+ # No args passed.
65
+ # if not args: #todo: execute default task.
66
+ # parser.print_help()
67
+ # print("\n\n"+_CREDIT_LINE)
68
+ # exit
69
+ # Parse arguments.
70
+ args = parser.parse_args(args)
71
+
72
+ if args.version:
73
+ print('vb %s' % __version__)
74
+ sys.exit(0)
75
+
76
+ # load build file as a module
77
+ if not path.isfile(args.file):
78
+ print("Build file '%s' does not exist. "
79
+ "Please specify a build file\n" % args.file)
80
+ parser.print_help()
81
+ sys.exit(1)
82
+
83
+ module = load_source(path.splitext(
84
+ path.basename(args.file))[0], args.file)
85
+
86
+ # Run task and all its dependencies.
87
+ if args.list_tasks:
88
+ print_tasks(module, args.file)
89
+ elif not args.tasks:
90
+ if not _run_default_task(module):
91
+ parser.print_help()
92
+ print("\n")
93
+ print_tasks(module, args.file)
94
+ else:
95
+ _run_from_task_names(module, args.tasks)
96
+
97
+
98
+ def print_tasks(module, file):
99
+ # Get all tasks.
100
+ tasks = _get_tasks(module)
101
+
102
+ # Build task_list to describe the tasks.
103
+ task_list = "Tasks in build file %s:" % file
104
+ name_width = _get_max_name_length(module)+4
105
+ task_help_format = "\n {0:<%s} {1: ^10} {2}" % name_width
106
+ default = _get_default_task(module)
107
+ for task in sorted(tasks, key=lambda task: task.name):
108
+ attributes = []
109
+ if task.ignored:
110
+ attributes.append('Ignored')
111
+ if task.async_task:
112
+ attributes.append('Async')
113
+ if default and task.name == default.name:
114
+ attributes.append('Default')
115
+
116
+ joined_attributes = ', '.join(attributes)
117
+ task_list += task_help_format.format(task.name,
118
+ ('[{}]'.format(joined_attributes))
119
+ if attributes else '',
120
+ task.doc)
121
+ print(task_list + "\n\n"+_CREDIT_LINE)
122
+
123
+
124
+ def _get_default_task(module):
125
+ matching_tasks = [
126
+ task for name, task in inspect.getmembers(module, Task.is_task)
127
+ if name == "__DEFAULT__"]
128
+ if matching_tasks:
129
+ return matching_tasks[0]
130
+
131
+
132
+ def _run_default_task(module):
133
+ default_task = _get_default_task(module)
134
+ if not default_task:
135
+ return False
136
+
137
+ completed_tasks = dict()
138
+ _run(module, _get_logger(module), default_task, completed_tasks)
139
+ for task in completed_tasks:
140
+ while completed_tasks.get(task).running():
141
+ time.sleep(0.5)
142
+
143
+ return True
144
+
145
+
146
+ def _run_from_task_names(module, task_names):
147
+ """
148
+ @type module: module
149
+ @type task_name: string
150
+ @param task_name: Task name, exactly corresponds to function name.
151
+ """
152
+ # Create logger.
153
+ logger = _get_logger(module)
154
+ all_tasks = _get_tasks(module)
155
+ completed_tasks = dict()
156
+ for task_name in task_names:
157
+ task, args, kwargs = _get_task(module, task_name, all_tasks)
158
+ _run(module, logger, task, completed_tasks, True, args, kwargs)
159
+
160
+ for task in completed_tasks:
161
+ while completed_tasks.get(task).running():
162
+ time.sleep(0.5)
163
+
164
+
165
+ def _get_task(module, name, tasks):
166
+ # Get all tasks.
167
+ match = _TASK_PATTERN.match(name)
168
+ if not match:
169
+ raise Exception("Invalid task argument %s" % name)
170
+ task_name, _, args_str = match.groups()
171
+
172
+ args, kwargs = _parse_args(args_str)
173
+ if hasattr(module, task_name):
174
+ return getattr(module, task_name), args, kwargs
175
+ matching_tasks = [
176
+ task for task in tasks if task.name.startswith(task_name)]
177
+
178
+ if not matching_tasks:
179
+ raise Exception("Invalid task '%s'. Task should be one of %s" %
180
+ (name,
181
+ ', '.join([task.name for task in tasks])))
182
+ if len(matching_tasks) == 1:
183
+ return matching_tasks[0], args, kwargs
184
+ raise Exception("Conflicting matches %s for task %s" % (
185
+ ', '.join([task.name for task in matching_tasks]), task_name
186
+ ))
187
+
188
+
189
+ def _parse_args(args_str):
190
+ args = []
191
+ kwargs = {}
192
+ if not args_str:
193
+ return args, kwargs
194
+ arg_parts = args_str.split(",")
195
+
196
+ for i, part in enumerate(arg_parts):
197
+ if "=" in part:
198
+ key, value = [_str.strip() for _str in part.split("=")]
199
+ if key in kwargs:
200
+ raise Exception("duplicate keyword argument %s" % part)
201
+ kwargs[key] = value
202
+ else:
203
+ if len(kwargs) > 0:
204
+ raise Exception("Non keyword arg %s "
205
+ "cannot follows a keyword arg %s"
206
+ % (part, arg_parts[i - 1]))
207
+ args.append(part.strip())
208
+ return args, kwargs
209
+
210
+
211
+ def _run(
212
+ module,
213
+ logger,
214
+ task,
215
+ completed_tasks,
216
+ from_command_line=False,
217
+ args=None,
218
+ kwargs=None):
219
+ """
220
+ @type module: module
221
+ @type logging: Logger
222
+ @type task: Task
223
+ @type completed_tasts: set Task
224
+ @rtype: set Task
225
+ @return: Updated set of completed tasks after satisfying all dependencies.
226
+ """
227
+ # Satsify dependencies recursively. Maintain set of completed tasks so each
228
+ # task is only performed once.
229
+
230
+ for dependency in task.dependencies:
231
+ _run(module, logger, dependency, completed_tasks)
232
+
233
+ for dependency in task.dependencies:
234
+ if not dependency.ignored:
235
+ while completed_tasks.get(dependency.name).running():
236
+ time.sleep(0.5)
237
+
238
+ # Perform current task, if need to.
239
+ if from_command_line or task.name not in completed_tasks:
240
+
241
+ if task.ignored:
242
+ logger.info("Ignoring task \"{}\"".format(task.name))
243
+ else:
244
+ try:
245
+ if task.async_task:
246
+ executor = thread_pool_executor
247
+ else:
248
+ executor = current_thread_executor
249
+
250
+ task.set_logger(logger)
251
+ running_task = executor.submit(
252
+ task,
253
+ *(args or []),
254
+ **(kwargs or {})
255
+ )
256
+ completed_tasks[task.name] = running_task
257
+ except Exception:
258
+ logger.critical("Error starting task \"{name}\"".format(
259
+ name=task.name))
260
+ logger.critical("Aborting build")
261
+ raise
262
+
263
+ return
264
+
265
+
266
+ def _create_parser():
267
+ """
268
+ @rtype: argparse.ArgumentParser
269
+ """
270
+ parser = argparse.ArgumentParser()
271
+ parser.add_argument(
272
+ "tasks", help="perform specified task and all its dependencies",
273
+ metavar="task", nargs='*')
274
+
275
+ parser.add_argument(
276
+ '-l', '--list-tasks', help="List the tasks",
277
+ action='store_true')
278
+
279
+ parser.add_argument(
280
+ '-v', '--version',
281
+ help="Display the version information",
282
+ action='store_true')
283
+
284
+ parser.add_argument(
285
+ '-f', '--file',
286
+ help=("Build file to read the tasks from. "
287
+ "'build.py' is default value assumed "
288
+ "if this argument is unspecified"),
289
+ metavar="file", default="build.py")
290
+
291
+ return parser
292
+
293
+ # Abbreviate for convenience.
294
+ # task = _TaskDecorator
295
+
296
+
297
+ def task(*dependencies, **options):
298
+ for i, dependency in enumerate(dependencies):
299
+ if not Task.is_task(dependency):
300
+ if inspect.isfunction(dependency):
301
+ # Throw error specific to the most likely form of misuse.
302
+ if i == 0:
303
+ raise Exception("Replace use of @task with @task().")
304
+ else:
305
+ raise Exception("%s is not a task. "
306
+ "Each dependency should be a task."
307
+ % dependency)
308
+ else:
309
+ raise Exception("%s is not a task." % dependency)
310
+
311
+ def decorator(fn):
312
+ return Task(fn, dependencies, options)
313
+ return decorator
314
+
315
+
316
+ def async_task(*dependencies, **options):
317
+ for i, dependency in enumerate(dependencies):
318
+ if not Task.is_task(dependency):
319
+ if inspect.isfunction(dependency):
320
+ # Throw error specific to the most likely form of misuse.
321
+ if i == 0:
322
+ raise Exception("Replace use of @task with @task().")
323
+ else:
324
+ raise Exception("%s is not a task. "
325
+ "Each dependency should be a task."
326
+ % dependency)
327
+ else:
328
+ raise Exception("%s is not a task." % dependency)
329
+
330
+ def decorator(fn):
331
+ return Task(fn, dependencies, options, async_task=True)
332
+ return decorator
333
+
334
+
335
+ def _get_tasks(module):
336
+ """
337
+ Returns all functions marked as tasks.
338
+
339
+ @type module: module
340
+ """
341
+ # Get all functions that are marked as task and pull out the task object
342
+ # from each (name,value) pair.
343
+ return set(
344
+ member[1] for member in inspect.getmembers(module, Task.is_task)
345
+ )
346
+
347
+
348
+ def _get_max_name_length(module):
349
+ """
350
+ Returns the length of the longest task name.
351
+
352
+ @type module: module
353
+ """
354
+ return max([len(task.name) for task in _get_tasks(module)])
355
+
356
+
357
+ def _get_logger(module):
358
+ """
359
+ @type module: module
360
+ @rtype: logging.Logger
361
+ """
362
+
363
+ # Create Logger
364
+ logger = logging.getLogger(os.path.basename(module.__file__))
365
+ logger.setLevel(logging.DEBUG)
366
+
367
+ # Create console handler and set level to debug
368
+ ch = logging.StreamHandler()
369
+ ch.setLevel(logging.DEBUG)
370
+
371
+ # Create formatter
372
+ formatter = logging.Formatter(_LOGGING_FORMAT)
373
+
374
+ # Add formatter to ch
375
+ ch.setFormatter(formatter)
376
+
377
+ # Add ch to logger
378
+ logger.addHandler(ch)
379
+
380
+ return logger
381
+
382
+
383
+ def main():
384
+ build(sys.argv[1:])
@@ -0,0 +1,75 @@
1
+ import inspect
2
+ import time
3
+ from datetime import datetime
4
+ import logging
5
+ from threading import Lock
6
+
7
+
8
+ class Task(object):
9
+
10
+ def __init__(self, func, dependencies, options, **kwargs):
11
+ """
12
+ @type func: 0-ary function
13
+ @type dependencies: list of Task objects
14
+ """
15
+ self.func = func
16
+ self.name = func.__name__
17
+ self.doc = inspect.getdoc(func) or ''
18
+ self.dependencies = dependencies
19
+ self.ignored = bool(options.get('ignore', False))
20
+ self.async_task = kwargs.get('async_task', False)
21
+ self.logger = None
22
+
23
+ def __str__(self):
24
+ return self.name
25
+
26
+ def __call__(self, *args, **kwargs):
27
+ if self.logger:
28
+ if self.async_task:
29
+ self.logger.info("Starting async task \"{}\" in background".format(self.name))
30
+ else:
31
+ self.logger.info("Starting task \"{}\"".format(self.name))
32
+
33
+ t = datetime.now()
34
+
35
+ self.result = self.func.__call__(*args, **kwargs)
36
+
37
+ if self.logger:
38
+ self.logger.info("Completed task \"{task_name}\". Time: {run_time} sec".format(
39
+ task_name=self.name, run_time=(datetime.now() - t).seconds
40
+ )
41
+ )
42
+
43
+ return self.result
44
+
45
+ def set_future(self, future):
46
+ self.future = future
47
+
48
+ def set_logger(self, logger):
49
+ self.logger = logger
50
+
51
+ @classmethod
52
+ def is_task(cls, obj):
53
+ """
54
+ Returns true is an object is a build task.
55
+ """
56
+ return isinstance(obj, cls)
57
+
58
+
59
+ class CurrentThreadExecutor(object):
60
+
61
+ def __init__(self):
62
+ pass
63
+
64
+ def submit(self, task, *args, **kwargs):
65
+ task(*(args or []), **(kwargs or {}))
66
+ return PseudoFutureTask()
67
+
68
+
69
+ class PseudoFutureTask(object):
70
+
71
+ def __init__(self):
72
+ pass
73
+
74
+ def running(self):
75
+ return False
@@ -0,0 +1,53 @@
1
+ from datetime import datetime, date
2
+ import json
3
+ import sys
4
+ import os
5
+ import sh
6
+ import contextlib
7
+
8
+
9
+ def json_serial(obj):
10
+ """JSON serializer for objects not serializable by default json code"""
11
+
12
+ if isinstance(obj, (datetime, date)):
13
+ return obj.isoformat()
14
+ raise TypeError("Type %s not serializable" % type(obj))
15
+
16
+
17
+ def dump(obj):
18
+ print('DUMP: {}'.format(json.dumps(obj, indent=1, default=json_serial)))
19
+
20
+
21
+ def dumps(obj):
22
+ return json.dumps(obj, indent=1, default=json_serial)
23
+
24
+
25
+ @contextlib.contextmanager
26
+ def safe_cd(path):
27
+ starting_directory = os.getcwd()
28
+ try:
29
+ os.chdir(path)
30
+ yield
31
+ finally:
32
+ os.chdir(starting_directory)
33
+
34
+
35
+ # Exr shell overriden methods
36
+
37
+ def print_out(line):
38
+ sys.stdout.write(line)
39
+ sys.stdout.write("\n")
40
+ sys.stdout.flush()
41
+
42
+
43
+ def print_err(line):
44
+ sys.stderr.write(line)
45
+ sys.stderr.write("\n")
46
+ sys.stderr.flush()
47
+
48
+
49
+ nsh = None
50
+ if os.environ.get('TRAVIS', 'false') == 'true':
51
+ nsh = sh(_out=sys.stdout, _err_to_out=True)
52
+ else:
53
+ nsh = sh(_out=sys.stdout, _err_to_out=True, _tty_in=True)
vulcan/meta_builder.py ADDED
@@ -0,0 +1,5 @@
1
+ __version__ = "0.2.4"
2
+ __license__ = "MIT License"
3
+ __website__ = "https://code.exrny.com/opensource/vulcan-builder/"
4
+ __download_url__ = ('https://github.com/exrny/vulcan-builder/archive/'
5
+ '{}.tar.gz'.format(__version__))
@@ -0,0 +1,315 @@
1
+ Metadata-Version: 2.4
2
+ Name: vulcan-builder
3
+ Version: 0.2.4
4
+ Summary: Lightweight Python Build Tool.
5
+ Home-page: https://code.exrny.com/opensource/vulcan-builder/
6
+ Author: Peter Salnikov
7
+ Author-email: opensource@exrny.com
8
+ License: MIT License
9
+ Keywords: devops,build tool
10
+ Classifier: Development Status :: 4 - Beta
11
+ Classifier: Environment :: Console
12
+ Classifier: Intended Audience :: System Administrators
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 2
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Topic :: Software Development :: Build Tools
18
+ License-File: LICENSE.txt
19
+ Requires-Dist: sh<2,>=1
20
+ Dynamic: author
21
+ Dynamic: author-email
22
+ Dynamic: classifier
23
+ Dynamic: description
24
+ Dynamic: home-page
25
+ Dynamic: keywords
26
+ Dynamic: license
27
+ Dynamic: license-file
28
+ Dynamic: requires-dist
29
+ Dynamic: summary
30
+
31
+ |Build Status|
32
+
33
+ Vulcan Builder
34
+ ==============
35
+
36
+ This project is a fork of Pynt by `Raghunandan
37
+ Rao <https://github.com/rags/pynt>`__. We will contribute changes to the
38
+ original rags/pynt repo.
39
+
40
+ Vulcan Builder supports EXR’s applications via a lightweight, concise
41
+ Python DevOps tool. We will develop our own improvements on the initial
42
+ rags/pynt repo here and publish improvements to the original repo.
43
+
44
+ This is an EXR Open Source project.
45
+
46
+ A pynt of Python build.
47
+ =======================
48
+
49
+ Features
50
+ --------
51
+
52
+ - Easy to learn.
53
+ - Build tasks are just python funtions.
54
+ - Manages dependencies between tasks.
55
+ - Automatically generates a command line interface.
56
+ - Rake style param passing to tasks
57
+ - Supports python 2.7 and python 3.x
58
+ - Async tasks
59
+
60
+ Todo Features
61
+ -------------
62
+
63
+ - Additional tasks timing reporting
64
+ - Debug mode
65
+
66
+ Installation
67
+ ------------
68
+
69
+ You can install vulcan-builder from the Python Package Index (PyPI) or
70
+ from source.
71
+
72
+ Using pip
73
+
74
+ .. code:: bash
75
+
76
+ $ pip install vulcan-builder
77
+
78
+ Using easy_install
79
+
80
+ .. code:: bash
81
+
82
+ $ easy_install vulcan-builder
83
+
84
+ Example
85
+ -------
86
+
87
+ The build script is written in pure Python and vulcan-builder takes care
88
+ of managing any dependencies between tasks and generating a command line
89
+ interface.
90
+
91
+ Writing build tasks is really simple, all you need to know is the @task
92
+ decorator. Tasks are just regular Python functions marked with the
93
+ ``@task()`` decorator. Dependencies are specified with ``@task()`` too.
94
+ Tasks can be ignored with the ``@task(ignore=True)``. Disabling a task
95
+ is an useful feature to have in situations where you have one task that
96
+ a lot of other tasks depend on and you want to quickly remove it from
97
+ the dependency chains of all the dependent tasks.
98
+
99
+ **build.py**
100
+ ------------
101
+
102
+ .. code:: python
103
+
104
+
105
+ #!/usr/bin/python
106
+
107
+ import sys
108
+ from vulcan.builder import task
109
+
110
+ @task()
111
+ def clean():
112
+ '''Clean build directory.'''
113
+ print 'Cleaning build directory...'
114
+
115
+ @task(clean)
116
+ def html(target='.'):
117
+ '''Generate HTML.'''
118
+ print 'Generating HTML in directory "%s"' % target
119
+
120
+ @task(clean, ignore=True)
121
+ def images():
122
+ '''Prepare images.'''
123
+ print 'Preparing images...'
124
+
125
+ @task(html,images)
126
+ def start_server(server='localhost', port = '80'):
127
+ '''Start the server'''
128
+ print 'Starting server at %s:%s' % (server, port)
129
+
130
+ @task(start_server) #Depends on task with all optional params
131
+ def stop_server():
132
+ print 'Stopping server....'
133
+
134
+ @task()
135
+ def copy_file(src, dest):
136
+ print 'Copying from %s to %s' % (src, dest)
137
+
138
+ @task()
139
+ def echo(*args,**kwargs):
140
+ print args
141
+ print kwargs
142
+
143
+ # Default task (if specified) is run when no task is specified in the command line
144
+ # make sure you define the variable __DEFAULT__ after the task is defined
145
+ # A good convention is to define it at the end of the module
146
+ # __DEFAULT__ is an optional member
147
+
148
+ __DEFAULT__=start_server
149
+
150
+ **Running vulcan-builder tasks**
151
+ --------------------------------
152
+
153
+ The command line interface and help is automatically generated. Task
154
+ descriptions are extracted from function docstrings.
155
+
156
+ .. code:: bash
157
+
158
+ $ vb -h
159
+ usage: vb [-h] [-l] [-v] [-f file] [task [task ...]]
160
+
161
+ positional arguments:
162
+ task perform specified task and all its dependencies
163
+
164
+ optional arguments:
165
+ -h, --help show this help message and exit
166
+ -l, --list-tasks List the tasks
167
+ -v, --version Display the version information
168
+ -f file, --file file Build file to read the tasks from. Default is
169
+ 'build.py'
170
+
171
+ .. code:: bash
172
+
173
+ $ vb -l
174
+ Tasks in build file ./build.py:
175
+ clean Clean build directory.
176
+ copy_file
177
+ echo
178
+ html Generate HTML.
179
+ images [Ignored] Prepare images.
180
+ start_server [Default] Start the server
181
+ stop_server
182
+
183
+ Powered by vulcan-builder - A Lightweight Python Build Tool.
184
+
185
+ vulcan-builder takes care of dependencies between tasks. In the
186
+ following case start_server depends on clean, html and image generation
187
+ (image task is ignored).
188
+
189
+ .. code:: bash
190
+
191
+ $ vb #Runs the default task start_server. It does exactly what "vb start_server" would do.
192
+ [ example.py - Starting task "clean" ]
193
+ Cleaning build directory...
194
+ [ example.py - Completed task "clean" ]
195
+ [ example.py - Starting task "html" ]
196
+ Generating HTML in directory "."
197
+ [ example.py - Completed task "html" ]
198
+ [ example.py - Ignoring task "images" ]
199
+ [ example.py - Starting task "start_server" ]
200
+ Starting server at localhost:80
201
+ [ example.py - Completed task "start_server" ]
202
+
203
+ The first few characters of the task name is enough to execute the task,
204
+ as long as the partial name is unambigious. You can specify multiple
205
+ tasks to run in the commandline. Again the dependencies are taken taken
206
+ care of.
207
+
208
+ .. code:: bash
209
+
210
+ $ vb cle ht cl
211
+ [ example.py - Starting task "clean" ]
212
+ Cleaning build directory...
213
+ [ example.py - Completed task "clean" ]
214
+ [ example.py - Starting task "html" ]
215
+ Generating HTML in directory "."
216
+ [ example.py - Completed task "html" ]
217
+ [ example.py - Starting task "clean" ]
218
+ Cleaning build directory...
219
+ [ example.py - Completed task "clean" ]
220
+
221
+ The ‘html’ task dependency ‘clean’ is run only once. But clean can be
222
+ explicitly run again later.
223
+
224
+ vb tasks can accept parameters from commandline.
225
+
226
+ .. code:: bash
227
+
228
+ $ vb "copy_file[/path/to/foo, path_to_bar]"
229
+ [ example.py - Starting task "clean" ]
230
+ Cleaning build directory...
231
+ [ example.py - Completed task "clean" ]
232
+ [ example.py - Starting task "copy_file" ]
233
+ Copying from /path/to/foo to path_to_bar
234
+ [ example.py - Completed task "copy_file" ]
235
+
236
+ vb can also accept keyword arguments.
237
+
238
+ .. code:: bash
239
+
240
+ $ vb start[port=8888]
241
+ [ example.py - Starting task "clean" ]
242
+ Cleaning build directory...
243
+ [ example.py - Completed task "clean" ]
244
+ [ example.py - Starting task "html" ]
245
+ Generating HTML in directory "."
246
+ [ example.py - Completed task "html" ]
247
+ [ example.py - Ignoring task "images" ]
248
+ [ example.py - Starting task "start_server" ]
249
+ Starting server at localhost:8888
250
+ [ example.py - Completed task "start_server" ]
251
+
252
+ $ vb echo[hello,world,foo=bar,blah=123]
253
+ [ example.py - Starting task "echo" ]
254
+ ('hello', 'world')
255
+ {'blah': '123', 'foo': 'bar'}
256
+ [ example.py - Completed task "echo" ]
257
+
258
+ **Organizing build scripts**
259
+ ----------------------------
260
+
261
+ You can break up your build files into modules and simple import them
262
+ into your main build file.
263
+
264
+ .. code:: python
265
+
266
+ from deploy_tasks import *
267
+ from test_tasks import functional_tests, report_coverage
268
+
269
+ Contributors/Contributing
270
+ -------------------------
271
+
272
+ - Raghunandan Rao - vulcan-builder is preceded by and forked from
273
+ `pynt <https://github.com/rags/pynt>`__, which was created by
274
+ `Raghunandan Rao <https://github.com/rags/pynt>`__.
275
+ - Calum J. Eadie - pynt is preceded by and forked from
276
+ `microbuild <https://github.com/CalumJEadie/microbuild>`__, which was
277
+ created by `Calum J. Eadie <https://github.com/CalumJEadie>`__.
278
+
279
+ If you want to make changes the repo is at
280
+ https://github.com/exrny/vulcan-builder. You will need
281
+ `pytest <http://www.pytest.org>`__ to run the tests
282
+
283
+ .. code:: bash
284
+
285
+ $ ./vb t
286
+
287
+ It will be great if you can raise a `pull
288
+ request <https://help.github.com/articles/using-pull-requests>`__ once
289
+ you are done.
290
+
291
+ If you find any bugs or need new features please raise a ticket in the
292
+ `issues section <https://github.com/exrny/vulcan-builder/issues>`__ of
293
+ the github repo.
294
+
295
+ License
296
+ -------
297
+
298
+ vulcan-builder is licensed under a `MIT
299
+ license <http://opensource.org/licenses/MIT>`__
300
+
301
+ .. |Build Status| image:: https://travis-ci.org/exrny/vulcan-builder.png?branch=master
302
+ :target: https://travis-ci.org/exrny/vulcan-builder
303
+
304
+ Changes
305
+ =======
306
+
307
+ 0.2.4 - 12/09/2026
308
+ ------------------
309
+
310
+ - Load build files through importlib, as imp is gone in Python 3.12
311
+
312
+ 0.1.0 - 04/02/2018
313
+ ------------------
314
+
315
+ - Initial commit
@@ -0,0 +1,12 @@
1
+ vulcan/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ vulcan/meta_builder.py,sha256=vHDF6LBd-Xit7CjfBIQYhE1RcgGSAZInHrMnX_EBpDA,240
3
+ vulcan/builder/__init__.py,sha256=BiEddRUWhDjgUcIE7vqLG8N1vQKN2kJELn6b8vLPx74,323
4
+ vulcan/builder/_vb.py,sha256=uQTfvO20U2MHxEPAqKUC5-ixkEtXw4kK9hvXEfB5AUw,11528
5
+ vulcan/builder/classes.py,sha256=hYrrWv3zWghcIOOZvO9oZUmgIzWXypd_J5bu4vzi2bw,1864
6
+ vulcan/builder/common.py,sha256=lqzoZNsUMWfqNqj2Yba0jROjnb0T9lvCsyjYb4oTf8Y,1090
7
+ vulcan_builder-0.2.4.dist-info/licenses/LICENSE.txt,sha256=mEH0HA2l6nLLaVo9M63FBbmRy4poRUBc9Xgu5aCt7Zo,1093
8
+ vulcan_builder-0.2.4.dist-info/METADATA,sha256=xCQrdj5-Q8mWTxR79mK14rnfi3bPGDOfibFyV0KqZTA,9003
9
+ vulcan_builder-0.2.4.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
10
+ vulcan_builder-0.2.4.dist-info/entry_points.txt,sha256=aJV6R0DCgfoy9lU0DCCPBD5OVOY3AHpwotmzIX0z994,43
11
+ vulcan_builder-0.2.4.dist-info/top_level.txt,sha256=Wp8Ddga48cqQsqVTlPPjWVCX4e2R_XmTWdEbkQ4y4Hw,7
12
+ vulcan_builder-0.2.4.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (84.0.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ vb = vulcan.builder:main
@@ -0,0 +1,19 @@
1
+ Copyright (C) 2012 Raghunandan Rao
2
+ Copyright (C) 2012 Calum J. Eadie
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
5
+ this software and associated documentation files (the "Software"), to deal in the
6
+ Software without restriction, including without limitation the rights to use, copy,
7
+ modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
8
+ and to permit persons to whom the Software is furnished to do so, subject to the
9
+ following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be included in all
12
+ copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
15
+ INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
16
+ PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
17
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
18
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
19
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1 @@
1
+ vulcan