Commit 13a7ba5e authored by David Danier's avatar David Danier

Merge branch 'master' into issue/3

parents 33b5fee8 3889190c
stages:
- test
pytest:
image: python:3.7
stage: test
script:
- pip install pipenv
- pipenv install --system --dev
- pytest b5/tests -v
......@@ -13,6 +13,7 @@ packaging = ">=16.0"
[dev-packages]
"e1839a8" = {path = ".", editable = true}
pylint = ">=2.3.1"
pytest = ">=5.3.2"
[requires]
python_version = "3.7"
{
"_meta": {
"hash": {
"sha256": "a99ceb9a5254cf6e388f839064a8116aae8b7d7af794c5db538b4f2adbb7e94d"
"sha256": "4982a583aefa66c8927d063d04b1478775fc813b01f2ce2f5fc60eec504d9a46"
},
"pipfile-spec": 6,
"requires": {
......@@ -113,10 +113,25 @@
],
"version": "==2.3.3"
},
"attrs": {
"hashes": [
"sha256:08a96c641c3a74e44eb59afb61a24f2cb9f4d7188748e76ba4bb5edfa3cb7d1c",
"sha256:f7b7ce16570fe9965acd6d30101a28f62fb4a7f9e926b3bbc9b61f8b04247e72"
],
"version": "==19.3.0"
},
"e1839a8": {
"editable": true,
"path": "."
},
"importlib-metadata": {
"hashes": [
"sha256:bdd9b7c397c273bcc9a11d6629a38487cd07154fa255a467bf704cd2c258e359",
"sha256:f17c015735e1a88296994c0697ecea7e11db24290941983b08c9feb30921e6d8"
],
"markers": "python_version < '3.8'",
"version": "==1.4.0"
},
"isort": {
"hashes": [
"sha256:54da7e92468955c4fceacd0c86bd0ec997b0e1ee80d97f67c35a78b719dccab1",
......@@ -199,6 +214,13 @@
],
"version": "==0.6.1"
},
"more-itertools": {
"hashes": [
"sha256:1a2a32c72400d365000412fe08eb4a24ebee89997c18d3d147544f70f5403b39",
"sha256:c468adec578380b6281a114cb8a5db34eb1116277da92d7c46f904f0b52d3288"
],
"version": "==8.1.0"
},
"packaging": {
"hashes": [
"sha256:aec3fdbb8bc9e4bb65f0634b9f551ced63983a529d6a8931817d52fdd0816ddb",
......@@ -207,6 +229,20 @@
"index": "pypi",
"version": "==20.0"
},
"pluggy": {
"hashes": [
"sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0",
"sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d"
],
"version": "==0.13.1"
},
"py": {
"hashes": [
"sha256:5e27081401262157467ad6e7f851b7aa402c5852dbcb3dae06768434de5752aa",
"sha256:c20fdd83a5dbc0af9efd622bee9a5564e278f6380fffcacc43ba6f43db2813b0"
],
"version": "==1.8.1"
},
"pylint": {
"hashes": [
"sha256:3db5468ad013380e987410a8d6956226963aed94ecb5f9d3a28acca6d9ac36cd",
......@@ -222,6 +258,14 @@
],
"version": "==2.4.6"
},
"pytest": {
"hashes": [
"sha256:6b571215b5a790f9b41f19f3531c53a45cf6bb8ef2988bc1ff9afb38270b25fa",
"sha256:e41d489ff43948babd0fad7ad5e49b8735d5d55e26628a58673c39ff61d95de4"
],
"index": "pypi",
"version": "==5.3.2"
},
"pyyaml": {
"hashes": [
"sha256:059b2ee3194d718896c0ad077dd8c043e5e909d9180f387ce42012662a4946d6",
......@@ -279,11 +323,25 @@
"markers": "implementation_name == 'cpython' and python_version < '3.8'",
"version": "==1.4.0"
},
"wcwidth": {
"hashes": [
"sha256:8fd29383f539be45b20bd4df0dc29c20ba48654a41e661925e612311e9f3c603",
"sha256:f28b3e8a6483e5d49e7f8949ac1a78314e740333ae305b4ba5defd3e74fb37a8"
],
"version": "==0.1.8"
},
"wrapt": {
"hashes": [
"sha256:565a021fd19419476b9362b05eeaa094178de64f8361e44468f9e9d7843901e1"
],
"version": "==1.11.2"
},
"zipp": {
"hashes": [
"sha256:3718b1cbcd963c7d4c5511a8240812904164b7f381b647143a89d3b98f9bcd8e",
"sha256:f06903e9f1f43b12d371004b4ac7b06ab39a44adc747266928ae6debfa7b3335"
],
"version": "==0.6.0"
}
}
}
import argparse
import os
import sys
import termcolor
from .lib.argumentparser import ExecuteArgumentParser
from .exceptions import B5ExecutionError
from .lib.module import load_module
from .lib.state import State
......@@ -11,28 +11,9 @@ from .lib.state import State
def main():
try:
parser = argparse.ArgumentParser(
prog='b5-execute',
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
description='b5-execute is not intended to be called directly!',
)
parser.add_argument(
'--state-file', nargs='?',
dest='state_file',
)
parser.add_argument(
'--module', nargs='?',
dest='module',
)
parser.add_argument(
'--method', nargs='?',
dest='method',
)
parser.add_argument(
'--args', nargs=argparse.REMAINDER,
dest='args'
)
args = parser.parse_args()
parser = ExecuteArgumentParser('b5-execute', 'b5-execute is not intended to be called directly!')
parser.add_arguments()
args = parser.parse()
if not args.state_file or not args.module or not args.method:
raise B5ExecutionError('b5-execute is not intended to be called directly!')
......
import argparse
import os
import shutil
import subprocess
import sys
import termcolor
from .lib.skeleton import Skeleton
from .lib.argumentparser import InitArgumentParser
from .exceptions import B5ExecutionError
......@@ -22,23 +23,9 @@ def _run_cmd(cmd, error='Command execution failed, see above'):
def main():
try:
parser = argparse.ArgumentParser(
prog='b5-init',
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
description='b5-init might be used to setup new projects',
)
parser.add_argument(
'-s', '--skeleton', nargs='?',
dest='skeleton', default='basic'
)
parser.add_argument(
'-b', '--branch', nargs='?',
dest='branch',
)
parser.add_argument(
dest='path'
)
args = parser.parse_args()
parser = InitArgumentParser('b5-init', 'b5-init might be used to setup new projects')
parser.add_arguments()
args = parser.parse()
skeleton = Skeleton(args.skeleton)
branch = args.branch
......
import argparse
from .detect import DETECT
class ArgumentParser:
def __init__(self, prog='b5', description='', formatter_class=argparse.ArgumentDefaultsHelpFormatter):
self.parser = argparse.ArgumentParser(
prog=prog,
formatter_class=formatter_class,
description=description
)
self.defaults = {}
def parse(self, arguments=None, help_as_default=False):
if help_as_default:
if not arguments:
arguments = ['help']
args = self.parser.parse_args(arguments)
for key, value in self.defaults.items():
if not getattr(args, key):
setattr(args, key, value)
return args
def set_default(self, key, value):
self.defaults.update({key: value})
class MainArgumentParser(ArgumentParser):
"""
class for parsing all the b5 command line arguments.
Possible command line argument:
--config -c Path to config (inside run path)
--taskfile -t Path to Taskfile (inside run path)
--project-path -p Project path if not part of parent paths, normally b5 tries to get the project path by itself
--run-path -r Path inside the project b5 will execute in (cd into)
--detect -d Version Control System detection (git or hg)
--shell -s Shell to run the generated script in (should be bash)
--quiet -q Determine if the script should print out stuff
"""
def add_arguments(self):
self.__add_argument_config()
self.__add_argument_taskfile()
self.__add_argument_project_path()
self.__add_argument_run_path()
self.__add_argument_detect()
self.__add_argument_shell()
self.__add_argument_quiet()
self.__add_argument_command()
def __add_argument_config(self):
self.parser.add_argument(
'-c', '--config',
nargs='?',
action='append',
help='Path to config (inside run path)',
dest='configfiles',
)
def __add_argument_taskfile(self):
self.parser.add_argument(
'-t', '--taskfile',
nargs='?',
action='append',
help='Path to Taskfile (inside run path)',
dest='taskfiles',
)
def __add_argument_project_path(self):
self.parser.add_argument(
'-p', '--project-path',
nargs='?',
help='Project path if not part of parent paths, normally b5 tries to get the project path by itself',
dest='project_path',
)
def __add_argument_run_path(self):
self.parser.add_argument(
'-r', '--run-path',
nargs='?',
help='Path inside the project b5 will execute in (cd into)',
dest='run_path',
default='build',
)
def __add_argument_detect(self):
self.parser.add_argument(
'-d', '--detect',
nargs='?',
help='Project detection',
choices=DETECT,
dest='detect',
default='git',
)
def __add_argument_shell(self):
self.parser.add_argument(
'-s', '--shell', nargs='?',
help='Shell to run the generated script in (should be bash)',
dest='shell',
default='/bin/bash',
)
def __add_argument_quiet(self):
self.parser.add_argument(
'-q', '--quiet',
action='store_true',
dest='quiet',
default=False,
)
self.parser.set_defaults()
def __add_argument_command(self):
self.parser.add_argument('command')
self.parser.add_argument('command_args', nargs=argparse.REMAINDER)
class InitArgumentParser(ArgumentParser):
def add_arguments(self):
self.__add_argument_skeleton()
self.__add_argument_branch()
self.__add_argument_path()
def __add_argument_skeleton(self):
self.parser.add_argument(
'-s', '--skeleton',
nargs='?',
dest='skeleton',
default='basic',
)
def __add_argument_branch(self):
self.parser.add_argument(
'-b', '--branch',
nargs='?',
dest='branch',
)
def __add_argument_path(self):
self.parser.add_argument(
dest='path'
)
class ExecuteArgumentParser(ArgumentParser):
def add_arguments(self):
self.__add_argument_state_file()
self.__add_argument_module()
self._add_argument_method()
self.__add_argument_args()
def __add_argument_state_file(self):
self.parser.add_argument(
'--state-file', nargs='?',
dest='state_file',
)
def __add_argument_module(self):
self.parser.add_argument(
'--module', nargs='?',
dest='module',
)
def _add_argument_method(self):
self.parser.add_argument(
'--method', nargs='?',
dest='method',
)
def __add_argument_args(self):
self.parser.add_argument(
'--args',
nargs=argparse.REMAINDER,
dest='args'
)
class TemplateArgumentParser(ArgumentParser):
def add_arguments(self):
self.__add_argument_overwrite()
self.__add_argument_template_file()
self.__add_argument_output_file()
def __add_argument_overwrite(self):
self.parser.add_argument(
'-o', '--overwrite', nargs='?',
help='Control if existing files should be overwritten',
dest='overwrite', default='ask',
choices=['yes', 'if-older', 'no', 'ask', 'ask-if-older']
)
def __add_argument_template_file(self):
self.parser.add_argument('template_file')
def __add_argument_output_file(self):
self.parser.add_argument('output_file', nargs='?')
import argparse
import os
import subprocess
import sys
import termcolor
from .lib.argumentparser import MainArgumentParser
from . import VERSION
from .exceptions import B5ExecutionError
from .lib.config import find_configs
from .lib.config import load_config
from .lib.detect import detect_project_path, DETECT
from .lib.detect import detect_project_path
from .lib.script import StoredScriptSource, construct_script_source, construct_script_run
from .lib.state import State
from .lib.taskfile import find_taskfiles
......@@ -18,58 +18,11 @@ from .lib.taskfile import find_taskfiles
def main():
try:
# Parse all arguments
parser = argparse.ArgumentParser(
prog='b5',
formatter_class=argparse.ArgumentDefaultsHelpFormatter
)
parser.add_argument(
'-q', '--quiet',
action='store_true',
dest='quiet',
)
parser.add_argument(
'-p', '--project-path', nargs='?',
help='Project path if not part of parent paths, normally b5 tries to get the project path by itself',
dest='project_path',
)
parser.add_argument(
'-r', '--run-path', nargs='?',
help='Path inside the project b5 will execute in (cd into)',
dest='run_path', default='build',
)
parser.add_argument(
'-d', '--detect', nargs='?',
help='Project detection',
default='git', choices=DETECT,
dest='detect',
)
parser.add_argument(
'-c', '--config', nargs='?', action='append',
help='Path to config (inside run path)',
dest='configfiles',
)
parser.add_argument(
'-t', '--taskfile', nargs='?', action='append',
help='Path to Taskfile (inside run path)',
dest='taskfiles',
)
parser.add_argument(
'-s', '--shell', nargs='?',
help='Shell to run the generated script in (should be bash)',
dest='shell',
default='/bin/bash',
)
parser.add_argument('command')
parser.add_argument('command_args', nargs=argparse.REMAINDER)
parser.set_defaults(quiet=False)
sys_args = sys.argv[1:]
if not sys_args:
sys_args = ['help']
args = parser.parse_args(args=sys_args)
if args.taskfiles is None:
args.taskfiles = ['~/.b5/Taskfile', 'Taskfile', 'Taskfile.local']
if args.configfiles is None:
args.configfiles = ['~/.b5/config.yml', 'config.yml', 'config.local.yml', 'local.yml']
parser = MainArgumentParser('b5')
parser.add_arguments()
parser.set_default('taskfiles', ['~/.b5/Taskfile', 'Taskfile', 'Taskfile.local'])
parser.set_default('configfiles', ['~/.b5/config.yml', 'config.yml', 'config.local.yml', 'local.yml'])
args = parser.parse(sys.argv[1:], True)
# State vars
state = State(
......
import argparse
import datetime
import os
import sys
import termcolor
import jinja2
from ..lib.argumentparser import TemplateArgumentParser
from .. import VERSION
from . import BaseModule
class TemplateModule(BaseModule):
def execute_render(self, state, sys_args):
parser = argparse.ArgumentParser(
prog='{name}:render'.format(name=self.name),
formatter_class=argparse.ArgumentDefaultsHelpFormatter
)
parser.add_argument(
'-o', '--overwrite', nargs='?',
help='Control if existing files should be overwritten',
dest='overwrite', default='ask',
choices=['yes', 'if-older', 'no', 'ask', 'ask-if-older']
)
parser.add_argument('template_file')
parser.add_argument('output_file', nargs='?')
args = parser.parse_args(args=sys_args)
parser = TemplateArgumentParser('{name}:render'.format(name=self.name))
parser.add_arguments()
args = parser.parse(sys_args)
template_file = os.path.realpath(os.path.join(state.run_path, args.template_file))
output_file = None
......
import unittest
from b5.lib.argumentparser import MainArgumentParser, InitArgumentParser, ExecuteArgumentParser, TemplateArgumentParser
class TestMainArgumentParser(unittest.TestCase):
def setUp(self):
self.parser = MainArgumentParser()
self.parser.add_arguments()
def test_config_file_can_be_set(self):
arguments = self.parser.parse(['--config', 'test.yml', 'test'])
self.assertIn('test.yml', arguments.configfiles)
def test_default_configfiles_will_be_set(self):
self.parser.set_default('configfiles', ['~/.b5/config.yml', 'config.yml', 'config.local.yml', 'local.yml'])
arguments = self.parser.parse(['test'])
self.assertIn('~/.b5/config.yml', arguments.configfiles)
self.assertIn('config.yml', arguments.configfiles)
self.assertIn('config.local.yml', arguments.configfiles)
self.assertIn('local.yml', arguments.configfiles)
def test_taskfile_can_be_set(self):
arguments = self.parser.parse(['--taskfile', 'DifferentTaskFile', 'test'])
self.assertIn('DifferentTaskFile', arguments.taskfiles)
def test_default_taskfiles_will_be_set(self):
self.parser.set_default('taskfiles', ['~/.b5/Taskfile', 'Taskfile', 'Taskfile.local'])
arguments = self.parser.parse(['test'])
self.assertIn('~/.b5/Taskfile', arguments.taskfiles)
self.assertIn('Taskfile', arguments.taskfiles)
self.assertIn('Taskfile.local', arguments.taskfiles)
def test_default_run_path_is_set(self):
arguments = self.parser.parse(['test'])
self.assertEqual('build', arguments.run_path)
def test_run_path_can_be_set(self):
arguments = self.parser.parse(['--run-path', 'not_the_build_folder', 'test'])
self.assertEqual('not_the_build_folder', arguments.run_path)
def test_default_shell_is_set(self):
arguments = self.parser.parse(['test'])
self.assertEqual('/bin/bash', arguments.shell)
def test_shell_can_be_set(self):
arguments = self.parser.parse(['--shell', '/bin/sh', 'test'])
self.assertEqual('/bin/sh', arguments.shell)
def test_detect_default_is_set_to_git(self):
arguments = self.parser.parse(['test'])
self.assertEqual('git', arguments.detect)
def test_detect_can_be_set_to_mercurial(self):
arguments = self.parser.parse(['--detect', 'hg', 'test'])
self.assertEqual('hg', arguments.detect)
def test_quiet_is_false_by_default(self):
arguments = self.parser.parse(['test'])
self.assertFalse(arguments.quiet)
def test_quiet_can_be_set_to_true(self):
arguments = self.parser.parse(['--quiet', 'true', 'test'])
self.assertTrue(arguments.quiet)
class TestInitArgumentParserTest(unittest.TestCase):
def setUp(self):
self.parser = InitArgumentParser()
self.parser.add_arguments()
def test_skeleton_can_be_set(self):
arguments = self.parser.parse(['--skeleton', 'test', 'path'])
self.assertEqual('test', arguments.skeleton)
def test_skeleton_can_be_set_with_shortcut(self):
arguments = self.parser.parse(['-s', 'test', 'path'])
self.assertEqual('test', arguments.skeleton)
def test_skeleton_has_basic_as_default(self):
arguments = self.parser.parse(['path'])
self.assertEqual('basic', arguments.skeleton)
def test_branch_can_be_set(self):
arguments = self.parser.parse(['--branch', 'test', 'path'])
self.assertEqual('test', arguments.branch)
def test_branch_can_be_set_with_shortcut(self):
arguments = self.parser.parse(['-b', 'test', 'path'])
self.assertEqual('test', arguments.branch)
class TestExecuteArgumentParser(unittest.TestCase):
def setUp(self):
self.parser = ExecuteArgumentParser()
self.parser.add_arguments()
def test_state_file_can_be_set(self):
arguments = self.parser.parse(['--state-file', 'test'])
self.assertEqual('test', arguments.state_file)
def test_module_can_be_set(self):
arguments = self.parser.parse(['--module', 'test'])
self.assertEqual('test', arguments.module)
def test_method_can_be_set(self):
arguments = self.parser.parse(['--method', 'test'])
self.assertEqual('test', arguments.method)
def test_args_can_be_set(self):
arguments = self.parser.parse(['--args', 'test'])
self.assertIn('test', arguments.args)
class TestTemplateArgumentParser(unittest.TestCase):
def setUp(self):
self.parser = TemplateArgumentParser()
self.parser.add_arguments()
def test_overwrite_can_be_set(self):
arguments = self.parser.parse(['--overwrite', 'yes', 'template_file', 'output_file'])
self.assertEqual('yes', arguments.overwrite)
def test_overwrite_defaults_to_ask(self):
arguments = self.parser.parse(['template_file', 'output_file'])
self.assertEqual('ask', arguments.overwrite)
def test_template_file_can_be_set(self):
arguments = self.parser.parse(['template_file', 'output_file'])
self.assertEqual('template_file', arguments.template_file)
def test_output_file_can_be_set(self):
arguments = self.parser.parse(['template_file', 'output_file'])
self.assertEqual('output_file', arguments.output_file)
if __name__ == '__main__':