diff --git a/.status b/.status index 584c847..6811ae8 100644 --- a/.status +++ b/.status @@ -1 +1 @@ -active +active \ No newline at end of file diff --git a/Makefile b/Makefile index 62225aa..9f5d2ff 100644 --- a/Makefile +++ b/Makefile @@ -19,6 +19,7 @@ help: #> docs - Generate documentation. docs: lines + cd docs && make dirhtml; cd docs && make html; cd docs && make coverage; open docs/build/coverage/python.txt; diff --git a/docs/Makefile b/docs/Makefile index 23ddba2..c235a09 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -54,7 +54,8 @@ clean: .PHONY: html html: - #./generate_command_signatures.py > source/_command-examples.rst + resrc pkg docs -I ../packages.ini -O rst --no-heading > source/_includes/project-dependencies.rst; + ./generate_command_signatures.py > source/_includes/overlays.rst $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." diff --git a/docs/generate_command_signatures.py b/docs/generate_command_signatures.py index 28fbc20..fbbb8ee 100755 --- a/docs/generate_command_signatures.py +++ b/docs/generate_command_signatures.py @@ -1,12 +1,22 @@ #! /usr/bin/env python +# Imports + from collections import OrderedDict import inspect import sys +# Set path before importing overlays. sys.path.append("../") -from script_tease.mappings import MAPPING +# Import overlays +from scripttease.library.overlays.common import COMMON_MAPPINGS +from scripttease.library.overlays.django import DJANGO_MAPPINGS +from scripttease.library.overlays.pgsql import PGSQL_MAPPINGS +from scripttease.library.overlays.posix import POSIX_MAPPINGS +from scripttease.library.overlays.ubuntu import MAPPINGS as UBUNTU_MAPPINGS + +# Functions # https://stackoverflow.com/a/52003056/241720 @@ -22,44 +32,89 @@ def get_signature(fn): return args, kwargs -keys = list(MAPPING.keys()) -keys.sort() +def print_description(text): + print(text) + print("") -for key in keys: - cls = MAPPING[key] - print(key) - print("." * len(key)) +def print_heading(title): + print(title) + print("=" * len(title)) print("") - extra = cls.get_docs() - if extra is not None: - print(extra) + +def print_mapping(commands, excludes=None): + keys = list(commands.keys()) + keys.sort() + + _excludes = excludes or dict() + + for key in keys: + if key in _excludes: + continue + + func = commands[key] + + docstring = func.__doc__ + if not docstring: + continue + + print(key) + print("-" * len(key)) print("") + for i in docstring.split("\n"): + print(i.strip()) + # print("") - # if cls.__init__.__doc__: - # print(cls.__init__.__doc__) - # print("") + print(".. code-block:: ini") + print("") + print(" [run %s command]" % key) - print(".. code-block:: cfg") - print("") + args, kwargs = get_signature(func) - if cls.__doc__: - print(" [%s]" % cls.__doc__.strip().replace(".", "").lower()) - else: - print(" [run a %s command]" % cls.__name__.lower()) + line = list() + for a in args: + if a != "kwargs": + line.append(a) - args, kwargs = get_signature(cls.__init__) + print(" %s: %s" % (key, " ".join(line))) - line = list() - for a in args: - if a not in ("self", "kwargs"): - line.append(a) + for option, value in kwargs.items(): + if value is True: + _value = "yes" + elif value is False: + _value = "no" + else: + _value = value - print(" %s = %s" % (key, " ".join(line))) + print(" %s: %s" % (option, value)) - for option, value in kwargs.items(): - print(" %s = %s" % (option, value)) + print("") - print("") +# Overlay output. + +print_heading("Common") +print_description("Common commands are available to all overlays.") +print_mapping(COMMON_MAPPINGS) + +print_heading("Django") +print_description("Django commands are available to all overlays.") +print_mapping(DJANGO_MAPPINGS) + +print_heading("Postgres") +print_description("Postgres commands.") +print_mapping(PGSQL_MAPPINGS) + +print_heading("POSIX") +print_description("Posix commands form the basis of overlays for nix platforms.") +print_mapping(POSIX_MAPPINGS) + +exclude_from_ubuntu = COMMON_MAPPINGS.copy() +exclude_from_ubuntu.update(DJANGO_MAPPINGS) +exclude_from_ubuntu.update(PGSQL_MAPPINGS) +exclude_from_ubuntu.update(POSIX_MAPPINGS) +print_heading("Ubuntu") +print_description("The Ubuntu overlay incorporates commands specific to that platform as well as commands from " + "common, Django, Postgres, and POSIX.") +print_mapping(UBUNTU_MAPPINGS, excludes=exclude_from_ubuntu) diff --git a/docs/source/_command-examples.rst b/docs/source/_command-examples.rst deleted file mode 100644 index fdd63ad..0000000 --- a/docs/source/_command-examples.rst +++ /dev/null @@ -1,440 +0,0 @@ -apache.disable_module -..................... - -.. code-block:: ini - - [disable an apache module] - apache.disable_module = module_name - -apache.disable_site -................... - -.. code-block:: ini - - [disable a virtual host] - apache.disable_site = domain_name - -apache.enable_module -.................... - -.. code-block:: ini - - [enable an apache module] - apache.enable_module = module_name - -apache.enable_site -.................. - -.. code-block:: ini - - [enable a virtual host] - apache.enable_site = domain_name - -apache.test -........... - -.. code-block:: ini - - [run an apache config test] - apache: test - -append -...... - -.. code-block:: ini - - [append to a file] - append = path - content = None - -archive -....... - -.. code-block:: ini - - [create an archive file] - archive = from_path - absolute = False - exclude = None - file_name = archive.tgz - strip = 0 - to_path = . - view = False - -certbot -....... - -Alias: ssl - -.. code-block:: ini - - [get new ssl certificate from let's encrypt] - certbot = domain_name - email = None - webroot = None - -copy -.... - -.. code-block:: ini - - [copy a file or directory] - copy = from_path to_path - overwrite = False - recursive = False - -django -...... - -.. code-block:: ini - - [run a django management command] - django = name - -django.dumpdata -............... - -.. code-block:: ini - - [export django fixtures] - django.dumpdata = app_name - file_name = initial - indent = 4 - natural_foreign = False - natural_primary = False - path = None - -django.loaddata -............... - -.. code-block:: ini - - [load django fixtures] - django.loaddata = app_name - file_name = initial - path = None - -extract -....... - -.. code-block:: ini - - [extract an archive] - extract = from_path - absolute = False - exclude = None - file_name = archive.tgz - strip = 0 - to_path = None - view = False - -install -....... - -.. code-block:: ini - - [install a package using apt-get] - apt = package - remove = False - -makedir -....... - -.. code-block:: ini - - [create a directory] - makedir = path - mode = None - recursive = True - -message -....... - -.. code-block:: ini - - [run a message command] - message = output - back_title = Message - dialog = False - height = 15 - width = 100 - -mkdir -..... - -.. code-block:: ini - - [create a directory] - mkdir = path - mode = None - recursive = True - -move -.... - -.. code-block:: ini - - [move a file or directory] - move = from_path to_path - -perms -..... - -.. code-block:: ini - - [set permissions on a file or directory] - perms = path - group = None - mode = None - owner = None - recursive = False - -pg.createdb -........... - -.. code-block:: ini - - [create a postgresql database] - pg.createdb = name - admin_pass = None - admin_user = postgres - host = localhost - owner = None - port = 5432 - template = None - -pg.createuser -............. - -.. code-block:: ini - - [create a postgresql user] - pg.createuser = name - admin_pass = None - admin_user = postgres - host = localhost - password = None - port = 5432 - -pg.db -..... - -.. code-block:: ini - - [create a postgresql database] - pg.db = name - admin_pass = None - admin_user = postgres - host = localhost - owner = None - port = 5432 - template = None - -pg.dropdb -......... - -.. code-block:: ini - - [remove a postgresql database] - pg.dropdb = name - admin_pass = None - admin_user = postgres - host = localhost - port = 5432 - -pg.dropuser -........... - -.. code-block:: ini - - [remove a postgres user] - pg.dropuser = name - admin_pass = None - admin_user = postgres - host = localhost - port = 5432 - -pg.dump -....... - -.. code-block:: ini - - [export a postgres database] - pg.dump = name - admin_pass = None - admin_user = postgres - file_name = None - host = localhost - port = 5432 - -pg.exists -......... - -.. code-block:: ini - - [determine if a postgres database exists] - pg.exists = name - admin_pass = None - admin_user = postgres - host = localhost - port = 5432 - -pip -... - -.. code-block:: ini - - [install a python package using pip] - pip = package - remove = False - upgrade = False - -psql -.... - -.. code-block:: ini - - [execute a psql command] - psql = sql - database = template1 - host = localhost - password = None - port = 5432 - user = postgres - -reload -...... - -.. code-block:: ini - - [reload a service] - reload = service - -remove -...... - -.. code-block:: ini - - [remove a file or directory] - remove = path - force = False - recursive = False - -restart -....... - -.. code-block:: ini - - [restart a service] - restart = service - -rsync -..... - -.. code-block:: ini - - [synchronize files from a local to remote directory] - rsync = source target - delete = False - guess = False - host = None - key_file = None - links = True - port = 22 - recursive = True - user = None - -run -... - -.. code-block:: ini - - [a command to be executed] - run = statement - comment = None - condition = None - cd = None - environments = None - function = None - prefix = None - register = None - shell = None - stop = False - sudo = None - tags = None - -scopy -..... - -.. code-block:: ini - - [copy a file from the local (machine) to the remote host] - scp = from_path to_path - host = None - key_file = None - port = 22 - user = None - -sed -... - -.. code-block:: ini - - [replace text in a file] - sed = path - backup = .b - change = None - delimiter = / - find = None - -start -..... - -.. code-block:: ini - - [start a service] - start = service - -stop -.... - -.. code-block:: ini - - [stop a service] - stop = service - -symlink -....... - -.. code-block:: ini - - [create a symlink] - symlink = source - force = False - target = None - -touch -..... - -.. code-block:: ini - - [touch a file or directory] - touch = path - -virtualenv -.......... - -.. code-block:: ini - - [create a python virtual environment] - virtualenv = name - -write -..... - -.. code-block:: ini - - [write to a file] - write = path - content = None - overwrite = False diff --git a/docs/source/_data/cloc.csv b/docs/source/_data/cloc.csv index 8440089..62b6dfa 100644 --- a/docs/source/_data/cloc.csv +++ b/docs/source/_data/cloc.csv @@ -1,3 +1,3 @@ files,language,blank,comment,code -17,Python,705,569,1156 -17,SUM,705,569,1156 +18,Python,774,700,1285 +18,SUM,774,700,1285 diff --git a/docs/source/_includes/overlays.rst b/docs/source/_includes/overlays.rst new file mode 100644 index 0000000..9ea0ab2 --- /dev/null +++ b/docs/source/_includes/overlays.rst @@ -0,0 +1,1019 @@ +Common +====== + +Common commands are available to all overlays. + +pip +--- + +Use pip to install or uninstall a Python package. + +- name (str): The name of the package. +- op (str): The operation to perform; install, uninstall +- upgrade (bool): Upgrade an installed package. +- venv (str): The name of the virtual environment to load. + + +.. code-block:: ini + + [run pip command] + pip: name + op: install + upgrade: False + venv: None + +run +--- + +Run any statement. + +- statement (str): The statement to be executed. + + +.. code-block:: ini + + [run run command] + run: statement + +virtualenv +---------- + +Create a Python virtual environment. + +- name (str): The name of the environment to create. + + +.. code-block:: ini + + [run virtualenv command] + virtualenv: name + +Django +====== + +Django commands are available to all overlays. + +django +------ + +Run any Django management command. + +- name (str): The name of the management command. +- venv (str): The of the virtual environment to use. + +args are passed as positional arguments, while kwargs are given as switches. + + +.. code-block:: ini + + [run django command] + django: name args + venv: None + +django.check +------------ + +Run the Django check command. + +- venv (str): The of the virtual environment to use. + + +.. code-block:: ini + + [run django.check command] + django.check: + venv: None + +django.collect_static +--------------------- + +Collect static files. + +- venv (str): The of the virtual environment to use. + + +.. code-block:: ini + + [run django.collect_static command] + django.collect_static: + venv: None + +django.dumpdata +--------------- + +Dump data from the database. + +- app_name (str): The name (app label) of the app. ``app_label.ModelName`` may also be given. +- base_path (str): The path under which apps are located in source. +- file_name (str): The file name to which the data will be dumped. +- indent (int): Indentation of the exported fixtures. +- natural_foreign (bool): Use the natural foreign parameter. +- natural_primary (bool): Use the natural primary parameter. +- path (str): The path to the data file. +- venv (str): The of the virtual environment to use. + + +.. code-block:: ini + + [run django.dumpdata command] + django.dumpdata: app_name + base_path: local + file_name: initial + indent: 4 + natural_foreign: False + natural_primary: False + path: None + venv: None + +django.loaddata +--------------- + +Load data into the database. + +- app_name (str): The name (app label) of the app. ``app_label.ModelName`` may also be given. +- base_path (str): The path under which apps are located in source. +- file_name (str): The file name to which the data will be dumped. +- path (str): The path to the data file. +- venv (str): The of the virtual environment to use. + + +.. code-block:: ini + + [run django.loaddata command] + django.loaddata: app_name + base_path: local + file_name: initial + path: None + venv: None + +django.migrate +-------------- + +Apply database migrations. + +- venv (str): The of the virtual environment to use. + + +.. code-block:: ini + + [run django.migrate command] + django.migrate: + venv: None + +Postgres +======== + +Postgres commands. + +pg.client +--------- + +Execute a psql command. + +- sql (str): The SQL to be executed. +- database (str): The database name. +- admin_pass (str): The password for the user with sufficient access privileges to execute the command. +- admin_user (str): The name of the user with sufficient access privileges to execute the command. +- host (str): The database host name or IP address. +- port (int): The port number of the Postgres service running on the host. + + +.. code-block:: ini + + [run pg.client command] + pg.client: sql + database: template1 + host: localhost + password: None + port: 5432 + user: postgres + +pg.createdatabase +----------------- + +Create a PostgreSQL database. + +- name (str): The database name. +- admin_pass (str): The password for the user with sufficient access privileges to execute the command. +- admin_user (str): The name of the user with sufficient access privileges to execute the command. +- host (str): The database host name or IP address. +- owner (str): The owner (user/role name) of the new database. +- port (int): The port number of the Postgres service running on the host. +- template (str): The database template name to use, if any. + + +.. code-block:: ini + + [run pg.createdatabase command] + pg.createdatabase: name + admin_pass: None + admin_user: postgres + host: localhost + owner: None + port: 5432 + template: None + +pg.createdb +----------- + +Create a PostgreSQL database. + +- name (str): The database name. +- admin_pass (str): The password for the user with sufficient access privileges to execute the command. +- admin_user (str): The name of the user with sufficient access privileges to execute the command. +- host (str): The database host name or IP address. +- owner (str): The owner (user/role name) of the new database. +- port (int): The port number of the Postgres service running on the host. +- template (str): The database template name to use, if any. + + +.. code-block:: ini + + [run pg.createdb command] + pg.createdb: name + admin_pass: None + admin_user: postgres + host: localhost + owner: None + port: 5432 + template: None + +pg.createuser +------------- + +Create a PostgreSQL user. + +- name (str): The user name. +- admin_pass (str): The password for the user with sufficient access privileges to execute the command. +- admin_user (str): The name of the user with sufficient access privileges to execute the command. +- host (str): The database host name or IP address. +- port (int): The port number of the Postgres service running on the host. + + +.. code-block:: ini + + [run pg.createuser command] + pg.createuser: name + admin_pass: None + admin_user: postgres + host: localhost + password: None + port: 5432 + +pg.database +----------- + +Create a PostgreSQL database. + +- name (str): The database name. +- admin_pass (str): The password for the user with sufficient access privileges to execute the command. +- admin_user (str): The name of the user with sufficient access privileges to execute the command. +- host (str): The database host name or IP address. +- owner (str): The owner (user/role name) of the new database. +- port (int): The port number of the Postgres service running on the host. +- template (str): The database template name to use, if any. + + +.. code-block:: ini + + [run pg.database command] + pg.database: name + admin_pass: None + admin_user: postgres + host: localhost + owner: None + port: 5432 + template: None + +pg.database_exists +------------------ + +Determine if a Postgres database exists. + +- name (str): The database name. +- admin_pass (str): The password for the user with sufficient access privileges to execute the command. +- admin_user (str): The name of the user with sufficient access privileges to execute the command. +- host (str): The database host name or IP address. +- owner (str): The owner (user/role name) of the new database. +- port (int): The port number of the Postgres service running on the host. + + +.. code-block:: ini + + [run pg.database_exists command] + pg.database_exists: name + admin_pass: None + admin_user: postgres + host: localhost + port: 5432 + +pg.db +----- + +Create a PostgreSQL database. + +- name (str): The database name. +- admin_pass (str): The password for the user with sufficient access privileges to execute the command. +- admin_user (str): The name of the user with sufficient access privileges to execute the command. +- host (str): The database host name or IP address. +- owner (str): The owner (user/role name) of the new database. +- port (int): The port number of the Postgres service running on the host. +- template (str): The database template name to use, if any. + + +.. code-block:: ini + + [run pg.db command] + pg.db: name + admin_pass: None + admin_user: postgres + host: localhost + owner: None + port: 5432 + template: None + +pg.dropdatabase +--------------- + +Remove a PostgreSQL database. + +- name (str): The database name. +- admin_pass (str): The password for the user with sufficient access privileges to execute the command. +- admin_user (str): The name of the user with sufficient access privileges to execute the command. +- host (str): The database host name or IP address. +- port (int): The port number of the Postgres service running on the host. + + +.. code-block:: ini + + [run pg.dropdatabase command] + pg.dropdatabase: name + admin_pass: None + admin_user: postgres + host: localhost + port: 5432 + +pg.dropdb +--------- + +Remove a PostgreSQL database. + +- name (str): The database name. +- admin_pass (str): The password for the user with sufficient access privileges to execute the command. +- admin_user (str): The name of the user with sufficient access privileges to execute the command. +- host (str): The database host name or IP address. +- port (int): The port number of the Postgres service running on the host. + + +.. code-block:: ini + + [run pg.dropdb command] + pg.dropdb: name + admin_pass: None + admin_user: postgres + host: localhost + port: 5432 + +pg.dropuser +----------- + +Remove a Postgres user. + +- name (str): The user name. +- admin_pass (str): The password for the user with sufficient access privileges to execute the command. +- admin_user (str): The name of the user with sufficient access privileges to execute the command. +- host (str): The database host name or IP address. +- port (int): The port number of the Postgres service running on the host. + + +.. code-block:: ini + + [run pg.dropuser command] + pg.dropuser: name + admin_pass: None + admin_user: postgres + host: localhost + port: 5432 + +pg.dump +------- + +Export a Postgres database. + +- name (str): The database name. +- admin_pass (str): The password for the user with sufficient access privileges to execute the command. +- admin_user (str): The name of the user with sufficient access privileges to execute the command. +- file_name (str): The name/path of the export file. Defaults the database name plus ``.sql``. +- host (str): The database host name or IP address. +- port (int): The port number of the Postgres service running on the host. + + +.. code-block:: ini + + [run pg.dump command] + pg.dump: name + admin_pass: None + admin_user: postgres + file_name: None + host: localhost + port: 5432 + +pg.dumpdb +--------- + +Export a Postgres database. + +- name (str): The database name. +- admin_pass (str): The password for the user with sufficient access privileges to execute the command. +- admin_user (str): The name of the user with sufficient access privileges to execute the command. +- file_name (str): The name/path of the export file. Defaults the database name plus ``.sql``. +- host (str): The database host name or IP address. +- port (int): The port number of the Postgres service running on the host. + + +.. code-block:: ini + + [run pg.dumpdb command] + pg.dumpdb: name + admin_pass: None + admin_user: postgres + file_name: None + host: localhost + port: 5432 + +pg.exists +--------- + +Determine if a Postgres database exists. + +- name (str): The database name. +- admin_pass (str): The password for the user with sufficient access privileges to execute the command. +- admin_user (str): The name of the user with sufficient access privileges to execute the command. +- host (str): The database host name or IP address. +- owner (str): The owner (user/role name) of the new database. +- port (int): The port number of the Postgres service running on the host. + + +.. code-block:: ini + + [run pg.exists command] + pg.exists: name + admin_pass: None + admin_user: postgres + host: localhost + port: 5432 + +pg.user +------- + +Create a PostgreSQL user. + +- name (str): The user name. +- admin_pass (str): The password for the user with sufficient access privileges to execute the command. +- admin_user (str): The name of the user with sufficient access privileges to execute the command. +- host (str): The database host name or IP address. +- port (int): The port number of the Postgres service running on the host. + + +.. code-block:: ini + + [run pg.user command] + pg.user: name + admin_pass: None + admin_user: postgres + host: localhost + password: None + port: 5432 + +psql +---- + +Execute a psql command. + +- sql (str): The SQL to be executed. +- database (str): The database name. +- admin_pass (str): The password for the user with sufficient access privileges to execute the command. +- admin_user (str): The name of the user with sufficient access privileges to execute the command. +- host (str): The database host name or IP address. +- port (int): The port number of the Postgres service running on the host. + + +.. code-block:: ini + + [run psql command] + psql: sql + database: template1 + host: localhost + password: None + port: 5432 + user: postgres + +POSIX +===== + +Posix commands form the basis of overlays for nix platforms. + +append +------ + +Append content to a file. + +- path (str): The path to the file. +- content (str): The content to be appended. + + +.. code-block:: ini + + [run append command] + append: path + content: None + +archive +------- + +Create a file archive. + +- from_path (str): The path that should be archived. +- absolute (bool): Set to ``True`` to preserve the leading slash. +- exclude (str): A pattern to be excluded from the archive. +- strip (int): Remove the specified number of leading elements from the path. +- to_path (str): Where the archive should be created. This should *not* include the file name. +- view (bool): View the output of the command as it happens. + + +.. code-block:: ini + + [run archive command] + archive: from_path + absolute: False + exclude: None + file_name: archive.tgz + strip: None + to_path: . + view: False + +certbot +------- + +Get new SSL certificate from Let's Encrypt. + +- domain_name (str): The domain name for which the SSL certificate is requested. +- email (str): The email address of the requester sent to the certificate authority. Required. +- webroot (str): The directory where the challenge file will be created. + + +.. code-block:: ini + + [run certbot command] + certbot: domain_name + email: None + webroot: None + +copy +---- + +Copy a file or directory. + +- from_path (str): The file or directory to be copied. +- to_path (str): The location to which the file or directory should be copied. +- overwrite (bool): Indicates files and directories should be overwritten if they exist. +- recursive (bool): Copy sub-directories. + + +.. code-block:: ini + + [run copy command] + copy: from_path to_path + overwrite: False + recursive: False + +extract +------- + +Extract a file archive. + +- from_path (str): The path that should be archived. +- absolute (bool): Set to ``True`` to preserve the leading slash. +- exclude (str): A pattern to be excluded from the archive. +- strip (int): Remove the specified number of leading elements from the path. +- to_path (str): Where the archive should be extracted. This should *not* include the file name. +- view (bool): View the output of the command as it happens. + + +.. code-block:: ini + + [run extract command] + extract: from_path + absolute: False + exclude: None + strip: None + to_path: None + view: False + +func +---- + +A function that may be used to organize related commands to be called together. +.. code-block:: ini + + [run func command] + func: name + commands: None + comment: None + +mkdir +----- + +Create a directory. + +- path (str): The path to be created. +- mode (int | str): The access permissions of the new directory. +- recursive (bool): Create all directories along the path. + + +.. code-block:: ini + + [run mkdir command] + mkdir: path + mode: None + recursive: True + +move +---- + +Move a file or directory. + +- from_path (str): The current path. +- to_path (str): The new path. + + +.. code-block:: ini + + [run move command] + move: from_path to_path + +perms +----- + +Set permissions on a file or directory. + +- path (str): The path to be changed. +- group (str): The name of the group to be applied. +- mode (int | str): The access permissions of the file or directory. +- owner (str): The name of the user to be applied. +- recursive: Create all directories along the path. + + +.. code-block:: ini + + [run perms command] + perms: path + group: None + mode: None + owner: None + recursive: False + +remove +------ + +Remove a file or directory. + +- path (str): The path to be removed. +- force (bool): Force the removal. +- recursive (bool): Remove all directories along the path. + + +.. code-block:: ini + + [run remove command] + remove: path + force: False + recursive: False + +rename +------ + +Rename a file or directory. + +- from_name (str): The name (or path) of the existing file. +- to_name (str): The name (or path) of the new file. + + +.. code-block:: ini + + [run rename command] + rename: from_name to_name + +rsync +----- + +Synchronize a directory structure. + +- source (str): The source directory. +- target (str): The target directory. +- delete (bool): Indicates target files that exist in source but not in target should be removed. +- exclude (str): The path to an exclude file. +- host (str): The host name or IP address. This causes the command to run over SSH. +- key_file (str): The privacy SSH key (path) for remote connections. User expansion is automatically applied. +- links (bool): Include symlinks in the sync. +- port (int): The SSH port to use for remote connections. +- recursive (bool): Indicates source contents should be recursively synchronized. +- user (str): The user name to use for remote connections. + + +.. code-block:: ini + + [run rsync command] + rsync: source target + delete: False + exclude: None + host: None + key_file: None + links: True + port: 22 + recursive: True + user: None + +scopy +----- + +Copy a file or directory to a remote server. + +- from_path (str): The source directory. +- to_path (str): The target directory. +- host (str): The host name or IP address. Required. +- key_file (str): The privacy SSH key (path) for remote connections. User expansion is automatically applied. +- port (int): The SSH port to use for remote connections. +- user (str): The user name to use for remote connections. + + +.. code-block:: ini + + [run scopy command] + scopy: from_path to_path + host: None + key_file: None + port: 22 + user: None + +sed +--- + +Find and replace text in a file. + +- path (str): The path to the file to be edited. +- backup (str): The backup file extension to use. +- delimiter (str): The pattern delimiter. +- find (str): The old text. Required. +- replace (str): The new text. Required. + + +.. code-block:: ini + + [run sed command] + sed: path + backup: .b + delimiter: / + find: None + replace: None + +ssl +--- + +Get new SSL certificate from Let's Encrypt. + +- domain_name (str): The domain name for which the SSL certificate is requested. +- email (str): The email address of the requester sent to the certificate authority. Required. +- webroot (str): The directory where the challenge file will be created. + + +.. code-block:: ini + + [run ssl command] + ssl: domain_name + email: None + webroot: None + +symlink +------- + +Create a symlink. + +- source (str): The source of the link. +- force (bool): Force the creation of the link. +- target (str): The name or path of the target. Defaults to the base name of the source path. + + +.. code-block:: ini + + [run symlink command] + symlink: source + force: False + target: None + +touch +----- + +Touch a file or directory. + +- path (str): The file or directory to touch. + + +.. code-block:: ini + + [run touch command] + touch: path + +write +----- + +Write to a file. + +- path (str): The file to be written. +- content (str): The content to be written. Note: If omitted, this command is equivalent to ``touch``. + + +.. code-block:: ini + + [run write command] + write: path + content: None + +Ubuntu +====== + +The Ubuntu overlay incorporates commands specific to that platform as well as commands from common, Django, Postgres, and POSIX. + +apache +------ + +Execute an Apache-related command. + +- op (str): The operation to perform; reload, restart, start, stop, test. + + +.. code-block:: ini + + [run apache command] + apache: op + +apache.disable_module +--------------------- + +Disable an Apache module. + +- name (str): The module name. + + +.. code-block:: ini + + [run apache.disable_module command] + apache.disable_module: name + +apache.disable_site +------------------- + +Disable an Apache site. + +- name (str): The domain name. + + +.. code-block:: ini + + [run apache.disable_site command] + apache.disable_site: name + +apache.enable_module +-------------------- + +Enable an Apache module. + +- name (str): The module name. + + +.. code-block:: ini + + [run apache.enable_module command] + apache.enable_module: name + +apache.enable_site +------------------ + +Enable an Apache site. + + + +.. code-block:: ini + + [run apache.enable_site command] + apache.enable_site: name + +install +------- + +Install a system-level package. + +- name (str): The name of the package to install. + + +.. code-block:: ini + + [run install command] + install: name + +reload +------ + +Reload a service. + +- name (str): The service name. + + +.. code-block:: ini + + [run reload command] + reload: name + +restart +------- + +Restart a service. + +- name (str): The service name. + + +.. code-block:: ini + + [run restart command] + restart: name + +start +----- + +Start a service. + +- name (str): The service name. + + +.. code-block:: ini + + [run start command] + start: name + +stop +---- + +Stop a service. + +- name (str): The service name. + + +.. code-block:: ini + + [run stop command] + stop: name + +system +------ + +Perform a system operation. + +- op (str): The operation to perform; reboot, update, upgrade. + + +.. code-block:: ini + + [run system command] + system: op + +template +-------- + +Create a file from a template. + +- source (str): The path to the template file. +- target (str): The path to where the new file should be created. +- backup (bool): Indicates whether a backup should be made if the target file already exists. +- parser (str): The parser to use ``jinja`` (the default) or ``simple``. + + +.. code-block:: ini + + [run template command] + template: source target + backup: True + parser: None + +uninstall +--------- + +Uninstall a system-level package. + +- name (str): The name of the package to uninstall. + + +.. code-block:: ini + + [run uninstall command] + uninstall: name + diff --git a/docs/source/_includes/project-dependencies.rst b/docs/source/_includes/project-dependencies.rst new file mode 100644 index 0000000..7743817 --- /dev/null +++ b/docs/source/_includes/project-dependencies.rst @@ -0,0 +1,17 @@ +Requirements +------------ + +superpython +----------- + + +**URLs** + +- `Source Code `_ + +**Install** + +.. code-block:: bash + + pip install git+https://github.com/develmaycare/superpython; + diff --git a/docs/source/tests.rst b/docs/source/_includes/project-tests.rst similarity index 88% rename from docs/source/tests.rst rename to docs/source/_includes/project-tests.rst index ce80704..30707f7 100644 --- a/docs/source/tests.rst +++ b/docs/source/_includes/project-tests.rst @@ -1,19 +1,15 @@ -***** -Tests -***** - Coverage Requirements -===================== +--------------------- 100% coverage is required for the ``master`` branch. See `current coverage report `_. .. csv-table:: Lines of Code - :file: _data/cloc.csv + :file: ../_data/cloc.csv Set Up for Testing -================== +------------------ Install requirements: @@ -22,7 +18,7 @@ Install requirements: pip install tests/requirements.pip Running Tests -============= +............. .. tip:: You may use the ``tests`` target of the ``Makefile`` to run tests with coverage: @@ -48,7 +44,7 @@ To allow output from print statements within a test method, add the ``-s`` switc python -m pytest -s tests/units/path/to/test.py Reference -========= +--------- - `coverage `_ - `pytest `_ diff --git a/docs/source/commands.rst b/docs/source/commands.rst new file mode 100644 index 0000000..e04a4cd --- /dev/null +++ b/docs/source/commands.rst @@ -0,0 +1,39 @@ +.. _commands: + +******** +Commands +******** + +.. code-block:: text + + usage: tease [-h] [-c] [-C= VARIABLES] [-d] [-D] [-f= FILTERS] [-O= OPTIONS] [-s] [-T= TEMPLATE_LOCATIONS] [-w= OUTPUT_FILE] [-V= VARIABLES_FILE] + [-v] [--version] + [path] + + positional arguments: + path The path to the configuration file. + + optional arguments: + -h, --help show this help message and exit + -c, --color Enable code highlighting for terminal output. + -C= VARIABLES, --context= VARIABLES + Context variables for use in pre-parsing the config and templates. In the form of: name:value + -d, --docs Output documentation instead of code. + -D, --debug Enable debug output. + -f= FILTERS, --filter= FILTERS + Filter the commands in the form of: attribute:value + -O= OPTIONS, --option= OPTIONS + Common command options in the form of: name:value + -s, --script Output commands as a script. + -T= TEMPLATE_LOCATIONS, --template-path= TEMPLATE_LOCATIONS + The location of template files that may be used with the template command. + -w= OUTPUT_FILE, --write= OUTPUT_FILE + Write the output to disk. + -V= VARIABLES_FILE, --variables-file= VARIABLES_FILE + Load variables from a file. + -v Show version number and exit. + --version Show verbose version information and exit. + + NOTES + + This command is used to parse configuration files and output the commands. diff --git a/docs/source/contact.rst b/docs/source/contact.rst new file mode 100644 index 0000000..c6f0e25 --- /dev/null +++ b/docs/source/contact.rst @@ -0,0 +1,27 @@ +.. _contact: + +******* +Contact +******* + +General Contact +=============== + +Please use the `contact form at develmaycare.com`_ to inquire about training, commercial development or support, to +report security issues, and other questions or communications. + +.. _contact form at develmaycare.com: https://develmaycare.com/contact/?product=ScriptTease + +Issue Tracker +============= + +Bugs and feature requests are logged with the `issue tracker`_. Do *not* log security issues here. + +.. _issue tracker: https://github.com/develmaycare/python-scripttease/issues + +Support +======= + +Support inquiries and other questions may be answered on StackOverflow `using the python-scripttease tag`_. + +.. _using the python-scripttease tag: https://stackoverflow.com/questions/tagged/python-scripttease diff --git a/docs/source/getting-started.rst b/docs/source/getting-started.rst new file mode 100644 index 0000000..a89b3d3 --- /dev/null +++ b/docs/source/getting-started.rst @@ -0,0 +1,47 @@ +.. _getting-started: + +*************** +Getting Started +*************** + +System Requirements +=================== + +TODO + +Install +======= + +TODO + +Configuration +============= + +TODO + +Examples +======== + +TODO + +Next Steps +========== + +TODO + +Resources +========= + +TODO + +FAQs +==== + +**Question?** + +Answer. + +Have a question? `Just ask`_! + +.. _Just ask: https://{{ project_domain }}/contact + diff --git a/docs/source/how-to.rst b/docs/source/how-to.rst new file mode 100644 index 0000000..1447201 --- /dev/null +++ b/docs/source/how-to.rst @@ -0,0 +1,110 @@ +.. _how-to: + +****** +How To +****** + +Create a New Command Overlay +============================ + +:ref:`topics-overlays` are used to define the commands supported by a given application, service, or operating system. Commands are defined as a function. + +1) Define a Module +------------------ + +The first step is to create a new module in which functions will be defined. + +.. code-block:: python + + # module_name.py + from ..commands import Command + +For overlays that represent an operating system, the ``command_exists()`` function is required: + +.. code-block:: python + + def command_exists(name): + return name in MAPPINGS + + +2) Define Command Function +-------------------------- + +The purpose of each function is to provide an interface for instantiating a :py:class`scripttease.library.commands.base.Command` instance. The example below is taken from the ``posix`` module. + +.. code-block:: python + + # module_name.py + # ... + + def mkdir(path, mode=None, recursive=True, **kwargs): + """Create a directory. + + - path (str): The path to be created. + - mode (int | str): The access permissions of the new directory. + - recursive (bool): Create all directories along the path. + + """ + kwargs.setdefault("comment", "create directory %s" % path) + + statement = ["mkdir"] + if mode is not None: + statement.append("-m %s" % mode) + + if recursive: + statement.append("-p") + + statement.append(path) + + return Command(" ".join(statement), **kwargs) + +The arguments and any specific keyword arguments are automatically used by the parser, but also serve as a simple interface for programmatic use. + +Each function *must* also accept ``**kwargs`` and should set a default for ``comment`` as above. + +3) Add Functions to the Mapping +------------------------------- + +The final step adds the function to the mapping. This makes it available to the command factory. + +.. code-block:: python + + # module_name.py + # ... + + MAPPINGS = { + 'mkdir': mkdir, + } + +For overlays that represent an operating system, ``MAPPINGS`` is required -- in addition to ``command_exists()`` above. For commands that are specific to service or application, the name of the dictionary may be anything that is appropriate. For example, ``DJANGO_MAPPINGS``. + +Additionally, for an operating system overlay, you may wish to import other mappings and incorporate them into ``MAPPINGS``. + +.. code-block:: python + + # module_name.py + from ..commands import Command + from .common import COMMON_MAPPINGS + from .django import DJANGO_MAPPINGS + from .pgsql import PGSQL_MAPPINGS + + MAPPINGS = { + # ... + } + + MAPPINGS.update(COMMON_MAPPINGS) + MAPPINGS.update(DJANGO_MAPPINGS) + MAPPINGS.update(PGSQL_MAPPINGS) + +Export Commands as a Script +=========================== + +.. code-block:: python + + config = Config("commands.ini") + if not config.load(): + print("Bummer!") + exit() + + script = config.as_script() + print(script) diff --git a/docs/source/index.rst b/docs/source/index.rst index dd31ea4..46ea8ef 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -1,13 +1,23 @@ -Python Script Tease -=================== +Script Tease +============ + +.. raw:: html + +

+ Project Home Page +

.. toctree:: :maxdepth: 2 Introduction - Configuration - Developer Reference - Tests + Getting Started + How To + Commands + Topics + Reference + Project + Contact Indices and tables ================== diff --git a/docs/source/introduction.rst b/docs/source/introduction.rst index 1380e78..494779a 100644 --- a/docs/source/introduction.rst +++ b/docs/source/introduction.rst @@ -4,6 +4,9 @@ Introduction ************ +Overview +======== + Script Tease is a library and command line tool for generating commands programmatically or using configuration files. Concepts @@ -14,9 +17,8 @@ Generating Commands Script Tease may be used in two (2) ways: -1. Using the library to programmatically define commands and export them as command line statements. See - :ref:`developer-reference`. -2. Using the ``tease`` command to generate commands from a configuration file. See :ref:`configuration`. +1. Using the library to programmatically define commands and export them as command line statements. See :ref:`developer-reference`. +2. Using the ``tease`` command to generate commands from a configuration file. See :ref:`topics-configuration`. Overlays -------- @@ -25,3 +27,16 @@ An *overlay* is a set of command meta functions that define the capabilities of .. note:: At present, the only fully defined overlay is for Ubuntu. + +See :ref:`topics-overlays`. + +Terms and Definitions +===================== + +term + Definition. + +License +======= + +Script Tease is released under the BSD 3 clause license. diff --git a/docs/source/project.rst b/docs/source/project.rst new file mode 100644 index 0000000..424e15f --- /dev/null +++ b/docs/source/project.rst @@ -0,0 +1,155 @@ +******* +Project +******* + +Contributing +============ + +We welcome contributions to this and any of `our open source projects`_. There are a number of ways to participate and contribute. See :ref:`contact`. + +.. _our open source projects: https://develmaycare.com/products/ + +Reporting Issues +---------------- + +Perhaps the easiest way to contribute is to submit an issue. If you have found a bug or error in the documentation, please submit a request. See :ref:`contact`. + +.. important:: + Do **not** report security issues using the issue tracker. Instead, send an email to security@develmaycare.com with details on the issue you've discovered. + +Submitting Feature Requests +--------------------------- + +Although we reserve the right to decline new features, we welcome all feature requests. See :ref:`contact`. + +Testing and Quality Control +--------------------------- + +Testing involves using Script Tease in real life or in development. Feel free to report any issues you find, or to improve the unit tests. + +Pull Requests +------------- + +Pull requests are welcome. Such requests should be associated with an issue. We may ignore pull requests that do not have a corresponding issue, so create an issue if one does not already exist. + +Translations +------------ + +TODO: Translations help make Script Tease available to more people around the world. + +Blogging +-------- + +You may help spread awareness of Script Tease by writing blog posts. We are happy to link out to reviews and tutorials from our web site. `Let us know if you've created a blog post`_ that we can share. Be sure to include a link to the post. + +You may also provide us with a guest post to be included on our blog. + +.. _Let us know if you've created a blog post: https://develmaycare.com/contact/?product=ScriptTease + +.. note:: + We reserve the right to proof and approve or decline all content posted on our web site. + +Development +=========== + +TODO + +Setting Up For Development +-------------------------- + +TODO + +Style Guide +----------- + +Script Tease follows `PEP8`_ and (where appropriate) the `Django style guide`_ and `JavaScript Standard Style`_. + +.. _Django style guide: https://docs.djangoproject.com/en/stable/internals/contributing/writing-code/coding-style/ +.. _JavaScript Standard Style: https://standardjs.com +.. _PEP8: https://www.python.org/dev/peps/pep-0008/ + +We *do* make a few exceptions and provide additional guidance which is documented in our `developer docs`_. + +.. _developer docs: https://docs.develmaycare.com/en/developer/ + +Tips for Successful Development +------------------------------- + +TODO + +Getting Help +------------ + +TODO + +Dependencies +============ + +.. include:: _includes/project-dependencies.rst + +Tests +===== + +.. include:: _includes/project-tests.rst + +Releasing +========= + +Versioning +---------- + +Script Tease follows a loose form of `semantic versioning`_. The use of semantic versioning makes it clear when deprecation occurs and backward compatibility is removed. Documented incompatibilities may still exist where deprecation is not feasible (technically or financially). + +.. _semantic versioning: https://semver.org/ + +Cadence +------- + +Prior to the 1.0 release, new features may be released at any time. After the 1.0 release, new features are planned for release every 3 months. Patch-level changes (to fix bugs or security issues) are always released as needed. + +Long-Term Support +----------------- + +Some releases may be designated as long-term support (LTS) releases. Such releases will have security and critical bug fixes applied for 6 months. + +Deprecation Policy +------------------ + +Minor releases may deprecate features from a previous minor release. For example, if a feature is deprecated in release 1.1, it will continue to work in the 1.2 release, though warnings may be raised. However, the deprecated feature may be removed in release 1.3 and may not function as previously expected or will raise errors. + +Major releases may *always* remove deprecated features. + +Patch-level releases *never* remove deprecated features. + +Legal +===== + +.. code-block:: text + + Copyright (c) Pleasant Tents, LLC + + All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, + are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + * Neither the name of Pleasant Tents, LLC nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/docs/source/developer.rst b/docs/source/reference.rst similarity index 100% rename from docs/source/developer.rst rename to docs/source/reference.rst diff --git a/docs/source/configuration.rst b/docs/source/topics-configuration.rst similarity index 73% rename from docs/source/configuration.rst rename to docs/source/topics-configuration.rst index 15c8acd..82d0505 100644 --- a/docs/source/configuration.rst +++ b/docs/source/topics-configuration.rst @@ -1,4 +1,4 @@ -.. _configuration: +.. _topics-configuration: ************* Configuration @@ -40,6 +40,8 @@ Notes regarding this format: - ``yes`` and ``no`` are interpreted as boolean values. - List values, where required, are separated by commas. +.. _topics-configuration-common-parameters: + Common Parameters ----------------- @@ -76,13 +78,6 @@ Example of an "itemized" command: .. note:: Command itemization may vary with the command type. -Available Commands ------------------- - -The following commands instantiate command instances. Each example is shown with the defaults. - -.. include:: _command-examples.rst - Pre-Parsing Command Files as Templates ====================================== @@ -121,34 +116,7 @@ Then with a config instance: Using the Tease Command ======================= -The ``tease`` command may be used to parse a configuration file, providing additional utilities for working with -commands. - -.. code-block:: text - -positional arguments: - path The path to the configuration file. - -optional arguments: - -h, --help show this help message and exit - -c, --color Enable code highlighting for terminal output. - -C= VARIABLES, --context= VARIABLES - Context variables for use in pre-parsing the config and templates. In the form of: name:value - -d, --docs Output documentation instead of code. - -D, --debug Enable debug output. - -f= FILTERS, --filter= FILTERS - Filter the commands in the form of: attribute:value - -O= OPTIONS, --option= OPTIONS - Common command options in the form of: name:value - -s, --script Output commands as a script. - -T= TEMPLATE_LOCATIONS, --template-path= TEMPLATE_LOCATIONS - The location of template files that may be used with the template command. - -w= OUTPUT_FILE, --write= OUTPUT_FILE - Write the output to disk. - -V= VARIABLES_FILE, --variables-file= VARIABLES_FILE - Load variables from a file. - -v Show version number and exit. - --version Show verbose version information and exit. +The ``tease`` command may be used to parse a configuration file, providing additional utilities for working with commands. See :ref:`commands`. The ``path`` argument defaults to ``commands.ini``. diff --git a/docs/source/topics-overlays.rst b/docs/source/topics-overlays.rst new file mode 100644 index 0000000..00b41ab --- /dev/null +++ b/docs/source/topics-overlays.rst @@ -0,0 +1,22 @@ +.. _topics-overlays: + +******* +Overlay +******* + +An overlay is a collection of functions that provide an interface to command creation. + +There are currently three (3) general and re-usable overlays: + +- common +- django +- pgsql + +And two (2) overlays that are specific to operating systems: + +- posix +- ubuntu + +The examples that follow instantiate command instances from an INI file. Each example is shown with the defaults. All commands support a number of :ref:`topics-configuration-common-parameters`. + +.. include:: _includes/overlays.rst diff --git a/docs/source/topics.rst b/docs/source/topics.rst new file mode 100644 index 0000000..bd86579 --- /dev/null +++ b/docs/source/topics.rst @@ -0,0 +1,11 @@ +.. _topics: + +****** +Topics +****** + +.. toctree:: + :maxdepth: 2 + + Configuration + Overlays diff --git a/packages.ini b/packages.ini new file mode 100644 index 0000000..64bed77 --- /dev/null +++ b/packages.ini @@ -0,0 +1,5 @@ +; SuperPython already has many of the required dependencies, including jinja2 and pygments. +[superpython] +comment = Used throughout for its various components and utilities. +scm = https://github.com/develmaycare/superpython +source = https://github.com/develmaycare/superpython diff --git a/requirements.pip b/requirements.pip index 1f4857b..c853276 100644 --- a/requirements.pip +++ b/requirements.pip @@ -1,3 +1 @@ -coverage -django -sphinx \ No newline at end of file +superpython \ No newline at end of file diff --git a/scripttease/library/overlays/common.py b/scripttease/library/overlays/common.py index 045a40b..2496e77 100644 --- a/scripttease/library/overlays/common.py +++ b/scripttease/library/overlays/common.py @@ -8,12 +8,21 @@ __all__ = ( "COMMON_MAPPINGS", "python_pip", "python_virtualenv", + "run", ) # Functions def python_pip(name, op="install", upgrade=False, venv=None, **kwargs): + """Use pip to install or uninstall a Python package. + + - name (str): The name of the package. + - op (str): The operation to perform; install, uninstall + - upgrade (bool): Upgrade an installed package. + - venv (str): The name of the virtual environment to load. + + """ if upgrade: statement = "pip install --upgrade -y %s" % name else: @@ -27,14 +36,31 @@ def python_pip(name, op="install", upgrade=False, venv=None, **kwargs): return Command(statement, **kwargs) -def python_virtualenv(name="python", **kwargs): +def python_virtualenv(name, **kwargs): + """Create a Python virtual environment. + + - name (str): The name of the environment to create. + + """ kwargs.setdefault("comment", "create %s virtual environment" % name) return Command("virtualenv %s" % name, **kwargs) + +def run(statement, **kwargs): + """Run any statement. + + - statement (str): The statement to be executed. + + """ + kwargs.setdefault("comment", "run statement") + return Command(statement, **kwargs) + + # Mappings COMMON_MAPPINGS = { 'pip': python_pip, + 'run': run, 'virtualenv': python_virtualenv, } diff --git a/scripttease/library/overlays/django.py b/scripttease/library/overlays/django.py index 9ceaf32..c45afd5 100644 --- a/scripttease/library/overlays/django.py +++ b/scripttease/library/overlays/django.py @@ -19,6 +19,19 @@ __all__ = ( def _django(name, *args, venv=None, **kwargs): + """Process a django-based command. + + :param name: The name of the management command. + :type name: str + + :param venv: The virtual environment to use. + :type venv: str + + args and kwargs are used to instantiate the command instance. + + This exists because we need ``django()`` to serve as an interface for any management command. + + """ if venv is not None: kwargs['prefix'] = "source %s/bin/activate" % venv @@ -59,6 +72,14 @@ def _django(name, *args, venv=None, **kwargs): def django(name, *args, venv=None, **kwargs): + """Run any Django management command. + + - name (str): The name of the management command. + - venv (str): The of the virtual environment to use. + + args are passed as positional arguments, while kwargs are given as switches. + + """ if name == "check": return django_check(venv=venv, **kwargs) elif name in ("collectstatic", "static"): @@ -70,6 +91,11 @@ def django(name, *args, venv=None, **kwargs): def django_check(venv=None, **kwargs): + """Run the Django check command. + + - venv (str): The of the virtual environment to use. + + """ kwargs.setdefault("comment", "run django checks") kwargs.setdefault("register", "django_checks_out") @@ -77,6 +103,11 @@ def django_check(venv=None, **kwargs): def django_collect_static(venv=None, **kwargs): + """Collect static files. + + - venv (str): The of the virtual environment to use. + + """ kwargs.setdefault("comment", "collect static files") return _django("collectstatic", venv=venv, **kwargs) @@ -84,25 +115,16 @@ def django_collect_static(venv=None, **kwargs): def django_dumpdata(app_name, base_path="local", file_name="initial", indent=4, natural_foreign=False, natural_primary=False, path=None, venv=None, **kwargs): - """Initialize the command. - - :param app_name: The name (app label) of the app. ``app_label.ModelName`` may also be given. - :type app_name: str - - :param file_name: The file name to which the data will be dumped. - :type file_name: str - - :param indent: Indentation of the exported fixtures. - :type indent: int - - :param natural_foreign: Use the natural foreign parameter. - :type natural_foreign: bool + """Dump data from the database. - :param natural_primary: Use the natural primary parameter. - :type natural_primary: bool - - :param path: The path to the data file. - :type path: str + - app_name (str): The name (app label) of the app. ``app_label.ModelName`` may also be given. + - base_path (str): The path under which apps are located in source. + - file_name (str): The file name to which the data will be dumped. + - indent (int): Indentation of the exported fixtures. + - natural_foreign (bool): Use the natural foreign parameter. + - natural_primary (bool): Use the natural primary parameter. + - path (str): The path to the data file. + - venv (str): The of the virtual environment to use. """ kwargs.setdefault("comment", "export fixtures for %s" % app_name) @@ -125,16 +147,13 @@ def django_dumpdata(app_name, base_path="local", file_name="initial", indent=4, def django_loaddata(app_name, base_path="local", file_name="initial", path=None, venv=None, **kwargs): - """Initialize the command. - - :param app_name: The name (app label) of the app. - :type app_name: str - - :param file_name: The file name to which the data will be dumped. - :type file_name: str + """Load data into the database. - :param path: The path to the data file. - :type path: str + - app_name (str): The name (app label) of the app. ``app_label.ModelName`` may also be given. + - base_path (str): The path under which apps are located in source. + - file_name (str): The file name to which the data will be dumped. + - path (str): The path to the data file. + - venv (str): The of the virtual environment to use. """ kwargs.setdefault("comment", "load fixtures for %s" % app_name) @@ -147,6 +166,11 @@ def django_loaddata(app_name, base_path="local", file_name="initial", path=None, def django_migrate(venv=None, **kwargs): + """Apply database migrations. + + - venv (str): The of the virtual environment to use. + + """ kwargs.setdefault("comment", "run django database migrations") return _django("migrate", venv=venv, **kwargs) diff --git a/scripttease/library/overlays/pgsql.py b/scripttease/library/overlays/pgsql.py index 74f470e..4a226bf 100644 --- a/scripttease/library/overlays/pgsql.py +++ b/scripttease/library/overlays/pgsql.py @@ -19,6 +19,25 @@ __all__ = ( def _get_pgsql_command(name, host="localhost", password=None, port=5432, user="postgres"): + """Get a postgres-related command using commonly required parameters. + + :param name: The name of the command. + :type name: str + + :param host: The host name. + :type host: str + + :param password: The password to use. + :type password: str + + :param port: The TCP port number. + :type port: int + + :param user: The user name that will be used to execute the command. + + :rtype: list[str] + + """ a = list() if password: @@ -37,26 +56,13 @@ def pg_create_database(name, admin_pass=None, admin_user="postgres", host="local template=None, **kwargs): """Create a PostgreSQL database. - :param name: The database name. - :type name: str - - :param admin_pass: The password for the user with sufficient access privileges to execute the command. - :type admin_pass: str - - :param admin_user: The name of the user with sufficient access privileges to execute the command. - :type admin_user: str - - :param host: The database host name or IP address. - :type host: str - - :param owner: The owner (user/role name) of the new database. - :type owner: str - - :param port: The port number of the Postgres service running on the host. - :type port: int - - :param template: The database template name to use, if any. - :type template: str + - name (str): The database name. + - admin_pass (str): The password for the user with sufficient access privileges to execute the command. + - admin_user (str): The name of the user with sufficient access privileges to execute the command. + - host (str): The database host name or IP address. + - owner (str): The owner (user/role name) of the new database. + - port (int): The port number of the Postgres service running on the host. + - template (str): The database template name to use, if any. """ _owner = owner or admin_user @@ -79,23 +85,11 @@ def pg_create_database(name, admin_pass=None, admin_user="postgres", host="local def pg_create_user(name, admin_pass=None, admin_user="postgres", host="localhost", password=None, port=5432, **kwargs): """Create a PostgreSQL user. - :param name: The user name. - :type name: str - - :param admin_pass: The password for the user with sufficient access privileges to execute the command. - :type admin_pass: str - - :param admin_user: The name of the user with sufficient access privileges to execute the command. - :type admin_user: str - - :param host: The database host name or IP address. - :type host: str - - :param password: The password for the new user. - :type password: str - - :param port: The port number of the Postgres service running on the host. - :type port: int + - name (str): The user name. + - admin_pass (str): The password for the user with sufficient access privileges to execute the command. + - admin_user (str): The name of the user with sufficient access privileges to execute the command. + - host (str): The database host name or IP address. + - port (int): The port number of the Postgres service running on the host. """ # Postgres commands always run without sudo because the -U may be provided. @@ -116,20 +110,12 @@ def pg_create_user(name, admin_pass=None, admin_user="postgres", host="localhost def pg_database_exists(name, admin_pass=None, admin_user="postgres", host="localhost", port=5432, **kwargs): """Determine if a Postgres database exists. - :param name: The database name. - :type name: str - - :param admin_pass: The password for the user with sufficient access privileges to execute the command. - :type admin_pass: str - - :param admin_user: The name of the user with sufficient access privileges to execute the command. - :type admin_user: str - - :param host: The database host name or IP address. - :type host: str - - :param port: The port number of the Postgres service running on the host. - :type port: int + - name (str): The database name. + - admin_pass (str): The password for the user with sufficient access privileges to execute the command. + - admin_user (str): The name of the user with sufficient access privileges to execute the command. + - host (str): The database host name or IP address. + - owner (str): The owner (user/role name) of the new database. + - port (int): The port number of the Postgres service running on the host. """ # Postgres commands always run without sudo because the -U may be provided. However, sudo may be required for @@ -147,20 +133,11 @@ def pg_database_exists(name, admin_pass=None, admin_user="postgres", host="local def pg_drop_database(name, admin_pass=None, admin_user="postgres", host="localhost", port=5432, **kwargs): """Remove a PostgreSQL database. - :param name: The database name. - :type name: str - - :param admin_pass: The password for the user with sufficient access privileges to execute the command. - :type admin_pass: str - - :param admin_user: The name of the user with sufficient access privileges to execute the command. - :type admin_user: str - - :param host: The database host name or IP address. - :type host: str - - :param port: The port number of the Postgres service running on the host. - :type port: int + - name (str): The database name. + - admin_pass (str): The password for the user with sufficient access privileges to execute the command. + - admin_user (str): The name of the user with sufficient access privileges to execute the command. + - host (str): The database host name or IP address. + - port (int): The port number of the Postgres service running on the host. """ # Postgres commands always run without sudo because the -U may be provided. @@ -176,20 +153,11 @@ def pg_drop_database(name, admin_pass=None, admin_user="postgres", host="localho def pg_drop_user(name, admin_pass=None, admin_user="postgres", host="localhost", port=5432, **kwargs): """Remove a Postgres user. - :param name: The user name. - :type name: str - - :param admin_pass: The password for the user with sufficient access privileges to execute the command. - :type admin_pass: str - - :param admin_user: The name of the user with sufficient access privileges to execute the command. - :type admin_user: str - - :param host: The database host name or IP address. - :type host: str - - :param port: The port number of the Postgres service running on the host. - :type port: int + - name (str): The user name. + - admin_pass (str): The password for the user with sufficient access privileges to execute the command. + - admin_user (str): The name of the user with sufficient access privileges to execute the command. + - host (str): The database host name or IP address. + - port (int): The port number of the Postgres service running on the host. """ # Postgres commands always run without sudo because the -U may be provided. @@ -206,24 +174,12 @@ def pg_dump_database(name, admin_pass=None, admin_user="postgres", file_name=Non **kwargs): """Export a Postgres database. - :param name: The database name. - :type name: str - - :param admin_pass: The password for the user with sufficient access privileges to execute the command. - :type admin_pass: str - - :param admin_user: The name of the user with sufficient access privileges to execute the command. - :type admin_user: str - - :param host: The database host name or IP address. - :type host: str - - :param file_name: The name (including the path, if desired) of the export file. Defaults to the - ``database_name`` plus ".sql" - :type file_name: str - - :param port: The port number of the Postgres service running on the host. - :type port: int + - name (str): The database name. + - admin_pass (str): The password for the user with sufficient access privileges to execute the command. + - admin_user (str): The name of the user with sufficient access privileges to execute the command. + - file_name (str): The name/path of the export file. Defaults the database name plus ``.sql``. + - host (str): The database host name or IP address. + - port (int): The port number of the Postgres service running on the host. """ _file_name = file_name or "%s.sql" % name @@ -243,23 +199,12 @@ def pg_dump_database(name, admin_pass=None, admin_user="postgres", file_name=Non def psql(sql, database="template1", host="localhost", password=None, port=5432, user="postgres", **kwargs): """Execute a psql command. - :param sql: The SQL to be executed. - :type sql: str - - :param database: The database name. - :type database: str - - :param password: The password for the user with sufficient access privileges to execute the command. - :type password: str - - :param host: The database host name or IP address. - :type host: str - - :param port: The port number of the Postgres service running on the host. - :type port: int - - :param user: The name of the user with sufficient access privileges to execute the command. - :type user: str + - sql (str): The SQL to be executed. + - database (str): The database name. + - admin_pass (str): The password for the user with sufficient access privileges to execute the command. + - admin_user (str): The name of the user with sufficient access privileges to execute the command. + - host (str): The database host name or IP address. + - port (int): The port number of the Postgres service running on the host. """ # Postgres commands always run without sudo because the -U may be provided. diff --git a/scripttease/library/overlays/posix.py b/scripttease/library/overlays/posix.py index 95f8339..3190c0c 100644 --- a/scripttease/library/overlays/posix.py +++ b/scripttease/library/overlays/posix.py @@ -20,7 +20,6 @@ __all__ = ( "remove", "rename", "rsync", - "run", "scopy", "sed", "symlink", @@ -35,34 +34,12 @@ def archive(from_path, absolute=False, exclude=None, file_name="archive.tgz", st **kwargs): """Create a file archive. - :param from_path: The path that should be archived. - :type from_path: str - - :param absolute: By default, the leading slash is stripped from each path. Set to ``True`` to preserve the - absolute path. - :type absolute: bool - - :param bzip2: Compress using bzip2. - :type bzip2: bool - - :param exclude: A pattern to be excluded from the archive. - :type exclude: str - - :param format: The command to use for the operation. - :type format: str - - :param gzip: Compress using gzip. - :type gzip: bool - - :param strip: Remove the specified number of leading elements from the path. Paths with fewer elements will be - silently skipped. - :type strip: int - - :param to_path: Where the archive should be created. This should *not* include the file name. - :type to_path: str - - :param view: View the output of the command as it happens. - :type view: bool + - from_path (str): The path that should be archived. + - absolute (bool): Set to ``True`` to preserve the leading slash. + - exclude (str): A pattern to be excluded from the archive. + - strip (int): Remove the specified number of leading elements from the path. + - to_path (str): Where the archive should be created. This should *not* include the file name. + - view (bool): View the output of the command as it happens. """ tokens = ["tar"] @@ -93,14 +70,9 @@ def archive(from_path, absolute=False, exclude=None, file_name="archive.tgz", st def certbot(domain_name, email=None, webroot=None, **kwargs): """Get new SSL certificate from Let's Encrypt. - :param domain_name: The domain name for which the SSL certificate is requested. - :type domain_name: str - - :param email: The email address of the requester sent to the certificate authority. Required. - :type email: str - - :param webroot: The directory where the challenge file will be created. - :type webroot: str + - domain_name (str): The domain name for which the SSL certificate is requested. + - email (str): The email address of the requester sent to the certificate authority. Required. + - webroot (str): The directory where the challenge file will be created. """ _email = email or os.environ.get("SCRIPTTEASE_CERTBOT_EMAIL", None) @@ -122,25 +94,12 @@ def certbot(domain_name, email=None, webroot=None, **kwargs): def extract(from_path, absolute=False, exclude=None, strip=None, to_path=None, view=False, **kwargs): """Extract a file archive. - :param from_path: The path to the archive file. - :type from_path: str - - :param absolute: By default, the leading slash is stripped from each path. Set to ``True`` to preserve the - absolute path. - :type absolute: bool - - :param exclude: A pattern to be excluded from the archive. - :type exclude: str - - :param strip: Remove the specified number of leading elements from the path. Paths with fewer elements will be - silently skipped. - :type strip: int - - :param to_path: Where the archive should be extracted. - :type to_path: str - - :param view: View the output of the command as it happens. - :type view: bool + - from_path (str): The path that should be archived. + - absolute (bool): Set to ``True`` to preserve the leading slash. + - exclude (str): A pattern to be excluded from the archive. + - strip (int): Remove the specified number of leading elements from the path. + - to_path (str): Where the archive should be extracted. This should *not* include the file name. + - view (bool): View the output of the command as it happens. """ _to_path = to_path or "./" @@ -172,11 +131,8 @@ def extract(from_path, absolute=False, exclude=None, strip=None, to_path=None, v def file_append(path, content=None, **kwargs): """Append content to a file. - :param path: The path to the file. - :type path: str - - :param content: The content to be appended. - :type content: str + - path (str): The path to the file. + - content (str): The content to be appended. """ kwargs.setdefault("comment", "append to %s" % path) @@ -187,19 +143,12 @@ def file_append(path, content=None, **kwargs): def file_copy(from_path, to_path, overwrite=False, recursive=False, **kwargs): - """Initialize the command. - - :param from_path: The file or directory to be copied. - :type from_path: str - - :param to_path: The location to which the file or directory should be copied. - :type to_path: str - - :param overwrite: Indicates files and directories should be overwritten if they exist. - :type overwrite: bool + """Copy a file or directory. - :param recursive: Copy sub-directories. - :type recursive: bool + - from_path (str): The file or directory to be copied. + - to_path (str): The location to which the file or directory should be copied. + - overwrite (bool): Indicates files and directories should be overwritten if they exist. + - recursive (bool): Copy sub-directories. """ kwargs.setdefault("comment", "copy %s to %s" % (from_path, to_path)) @@ -220,13 +169,10 @@ def file_copy(from_path, to_path, overwrite=False, recursive=False, **kwargs): def file_write(path, content=None, **kwargs): - """Initialize the command. + """Write to a file. - :param path: The file to be written. - :type path: str - - :param content: The content to be written. Note: If omitted, this command is equivalent to :py:class:`Touch`. - :type content: str + - path (str): The file to be written. + - content (str): The content to be written. Note: If omitted, this command is equivalent to ``touch``. """ _content = content or "" @@ -246,16 +192,11 @@ def file_write(path, content=None, **kwargs): def mkdir(path, mode=None, recursive=True, **kwargs): - """Initialize the command. - - :param path: The path to be created. - :type path: str - - :param mode: The access permissions of the new directory. - :type mode: int | str + """Create a directory. - :param recursive: Create all directories along the path. - :type recursive: bool + - path (str): The path to be created. + - mode (int | str): The access permissions of the new directory. + - recursive (bool): Create all directories along the path. """ kwargs.setdefault("comment", "create directory %s" % path) @@ -273,6 +214,12 @@ def mkdir(path, mode=None, recursive=True, **kwargs): def move(from_path, to_path, **kwargs): + """Move a file or directory. + + - from_path (str): The current path. + - to_path (str): The new path. + + """ kwargs.setdefault("comment", "move %s to %s" % (from_path, to_path)) statement = "mv %s %s" % (from_path, to_path) @@ -280,22 +227,13 @@ def move(from_path, to_path, **kwargs): def perms(path, group=None, mode=None, owner=None, recursive=False, **kwargs): - """Initialize the command. - - :param path: The path to be changed. - :type path: str - - :param group: The name of the group to be applied. - :type group: str - - :param mode: The access permissions of the file or directory. - :type mode: int | str + """Set permissions on a file or directory. - :param owner: The name of the user to be applied. - :type owner: str - - :param recursive: Create all directories along the path. - :type recursive: bool + - path (str): The path to be changed. + - group (str): The name of the group to be applied. + - mode (int | str): The access permissions of the file or directory. + - owner (str): The name of the user to be applied. + - recursive: Create all directories along the path. """ commands = list() @@ -345,16 +283,11 @@ def perms(path, group=None, mode=None, owner=None, recursive=False, **kwargs): def remove(path, force=False, recursive=False, **kwargs): - """Initialize the command. - - :param path: The path to be removed. - :type path: str - - :param force: Force the removal. - :type force: bool + """Remove a file or directory. - :param recursive: Remove all directories along the path. - :type recursive: bool + - path (str): The path to be removed. + - force (bool): Force the removal. + - recursive (bool): Remove all directories along the path. """ kwargs.setdefault("comment", "remove %s" % path) @@ -373,13 +306,10 @@ def remove(path, force=False, recursive=False, **kwargs): def rename(from_name, to_name, **kwargs): - """Rename of a file or directory. + """Rename a file or directory. - :param from_name: The name (or path) of the existing file. - :type from_name: str - - :param to_name: The name (or path) of the new file. - :type to_name: str + - from_name (str): The name (or path) of the existing file. + - to_name (str): The name (or path) of the new file. """ kwargs.setdefault("comment", "rename %s" % from_name) @@ -388,41 +318,21 @@ def rename(from_name, to_name, **kwargs): def rsync(source, target, delete=False, exclude=None, host=None, key_file=None, links=True, port=22, recursive=True, user=None, **kwargs): - """Initialize the command. - - :param source: The source directory. - :type source: str - - :param target: The target directory. - :type target: str - - :param delete: Indicates target files that exist in source but not in target should be removed. - :type delete: bool - - :param exclude: The path to an exclude file. - :type exclude: str - - :param host: The host name or IP address. This causes the command to run over SSH and may require a - ``key_file``, ``port``, and ``user``. - :type host: str - - :param key_file: The path to the private SSH key to use for remove connections. User expansion is - automatically applied. - :type key_file: str - - :param links: Include symlinks in the sync. - :type links: bool - - :param port: The SSH port to use for remote connections. - :type port: int - - :param recursive: Indicates source contents should be recursively synchronized. - :type recursive: bool - - :param user: The user name to use for remote connections. + """Synchronize a directory structure. + + - source (str): The source directory. + - target (str): The target directory. + - delete (bool): Indicates target files that exist in source but not in target should be removed. + - exclude (str): The path to an exclude file. + - host (str): The host name or IP address. This causes the command to run over SSH. + - key_file (str): The privacy SSH key (path) for remote connections. User expansion is automatically applied. + - links (bool): Include symlinks in the sync. + - port (int): The SSH port to use for remote connections. + - recursive (bool): Indicates source contents should be recursively synchronized. + - user (str): The user name to use for remote connections. """ - # :param guess: When ``True``, the ``host``, ``key_file``, and ``user`` will be guessed based on the base name of + # - guess: When ``True``, the ``host``, ``key_file``, and ``user`` will be guessed based on the base name of # the source path. # :type guess: bool # if guess: @@ -434,7 +344,7 @@ def rsync(source, target, delete=False, exclude=None, host=None, key_file=None, # key_file = key_file # user = user - kwargs.setdefault("comment", "copy %s to remote %s" % (source, target)) + kwargs.setdefault("comment", "sync %s with %s" % (source, target)) # rsync -e "ssh -i $(SSH_KEY) -p $(SSH_PORT)" -P -rvzc --delete # $(OUTPUTH_PATH) $(SSH_USER)@$(SSH_HOST):$(UPLOAD_PATH) --cvs-exclude; @@ -478,75 +388,50 @@ def rsync(source, target, delete=False, exclude=None, host=None, key_file=None, return Command(statement, **kwargs) -def run(statement, **kwargs): - """Run any statement.""" - kwargs.setdefault("comment", "run statement") - return Command(statement, **kwargs) - - def scopy(from_path, to_path, host=None, key_file=None, port=22, user=None, **kwargs): - """Initialize the command. + """Copy a file or directory to a remote server. - :param from_path: The source directory. - :type from_path: str + - from_path (str): The source directory. + - to_path (str): The target directory. + - host (str): The host name or IP address. Required. + - key_file (str): The privacy SSH key (path) for remote connections. User expansion is automatically applied. + - port (int): The SSH port to use for remote connections. + - user (str): The user name to use for remote connections. - :param to_path: The target directory. - :type to_path: str - - :param host: The host name or IP address. Required. - :type host: str - - :param key_file: The path to the private SSH key to use for remove connections. User expansion is - automatically applied. - :type key_file: str - - :param port: The SSH port to use for remote connections. - :type port: int - - :param user: The user name to use for remote connections. - - """ - kwargs.setdefault("comment", "copy %s to remote %s" % (from_path, to_path)) + """ + kwargs.setdefault("comment", "copy %s to remote %s" % (from_path, to_path)) - # TODO: What to do to force local versus remote commands? - # kwargs['local'] = True + # TODO: What to do to force local versus remote commands? + # kwargs['local'] = True - kwargs['sudo'] = False + kwargs['sudo'] = False - statement = ["scp"] + statement = ["scp"] - if key_file is not None: - statement.append("-i %s" % key_file) + if key_file is not None: + statement.append("-i %s" % key_file) - statement.append("-P %s" % port) - statement.append(from_path) + statement.append("-P %s" % port) + statement.append(from_path) - if host is not None and user is not None: - statement.append("%s@%s:%s" % (user, host, to_path)) - elif host is not None: - statement.append("%s:%s" % (host, to_path)) - else: - raise ValueError("Host is a required keyword argument.") + if host is not None and user is not None: + statement.append("%s@%s:%s" % (user, host, to_path)) + elif host is not None: + statement.append("%s:%s" % (host, to_path)) + else: + raise ValueError("Host is a required keyword argument.") - return Command(" ".join(statement), **kwargs) + return Command(" ".join(statement), **kwargs) def sed(path, backup=".b", delimiter="/", find=None, replace=None, **kwargs): """Find and replace text in a file. - :param path: The path to the file to be edited. - :type path: str - - :param backup: The backup file extension to use. - :type backup: str - - :param delimiter: The pattern delimiter. - - :param find: The old text. Required. - :type find: str - - :param replace: The new text. Required. - :type replace: str + - path (str): The path to the file to be edited. + - backup (str): The backup file extension to use. + - delimiter (str): The pattern delimiter. + - find (str): The old text. Required. + - replace (str): The new text. Required. """ @@ -568,16 +453,11 @@ def sed(path, backup=".b", delimiter="/", find=None, replace=None, **kwargs): def symlink(source, force=False, target=None, **kwargs): - """Initialize the command. - - :param source: The source of the link. - :type source: str - - :param force: Force the creation of the link. - :type force: bool + """Create a symlink. - :param target: The name or path of the target. Defaults to the base name of the source path. - :type target: str + - source (str): The source of the link. + - force (bool): Force the creation of the link. + - target (str): The name or path of the target. Defaults to the base name of the source path. """ _target = target or os.path.basename(source) @@ -596,10 +476,9 @@ def symlink(source, force=False, target=None, **kwargs): def touch(path, **kwargs): - """Initialize the command. + """Touch a file or directory. - :param path: The file or directory to touch. - :type path: str + - path (str): The file or directory to touch. """ kwargs.setdefault("comment", "touch %s" % path) @@ -643,14 +522,13 @@ POSIX_MAPPINGS = { 'copy': file_copy, 'extract': extract, 'func': Function, - 'function': Function, + # 'function': Function, 'mkdir': mkdir, 'move': move, 'perms': perms, 'remove': remove, 'rename': rename, 'rsync': rsync, - 'run': run, 'scopy': scopy, 'sed': sed, 'ssl': certbot, diff --git a/scripttease/library/overlays/ubuntu.py b/scripttease/library/overlays/ubuntu.py index 9285492..0c74117 100644 --- a/scripttease/library/overlays/ubuntu.py +++ b/scripttease/library/overlays/ubuntu.py @@ -37,10 +37,23 @@ __all__ = ( def command_exists(name): + """Indicates whether a given command exists in this overaly. + + :param name: The name of the command. + :type name: str + + :rtype: bool + + """ return name in MAPPINGS def apache(op, **kwargs): + """Execute an Apache-related command. + + - op (str): The operation to perform; reload, restart, start, stop, test. + + """ if op == "reload": return apache_reload(**kwargs) elif op == "restart": @@ -56,24 +69,43 @@ def apache(op, **kwargs): def apache_disable_module(name, **kwargs): + """Disable an Apache module. + + - name (str): The module name. + + """ kwargs.setdefault("comment", "disable %s apache module" % name) return Command("a2dismod %s" % name, **kwargs) def apache_disable_site(name, **kwargs): + """Disable an Apache site. + + - name (str): The domain name. + + """ kwargs.setdefault("comment", "disable %s apache site" % name) return Command("a2dissite %s" % name, **kwargs) def apache_enable_module(name, **kwargs): + """Enable an Apache module. + + - name (str): The module name. + + """ kwargs.setdefault("comment", "enable %s apache module" % name) return Command("a2enmod %s" % name, **kwargs) def apache_enable_site(name, **kwargs): + """Enable an Apache site. + + + """ kwargs.setdefault("comment", "enable %s apache module" % name) return Command("a2ensite %s" % name, **kwargs) @@ -114,6 +146,11 @@ def apache_test(**kwargs): def service_reload(name, **kwargs): + """Reload a service. + + - name (str): The service name. + + """ kwargs.setdefault("comment", "reload %s service" % name) kwargs.setdefault("register", "%s_reloaded" % name) @@ -121,6 +158,11 @@ def service_reload(name, **kwargs): def service_restart(name, **kwargs): + """Restart a service. + + - name (str): The service name. + + """ kwargs.setdefault("comment", "restart %s service" % name) kwargs.setdefault("register", "%s_restarted" % name) @@ -128,6 +170,11 @@ def service_restart(name, **kwargs): def service_start(name, **kwargs): + """Start a service. + + - name (str): The service name. + + """ kwargs.setdefault("comment", "start %s service" % name) kwargs.setdefault("register", "%s_started" % name) @@ -135,6 +182,11 @@ def service_start(name, **kwargs): def service_stop(name, **kwargs): + """Stop a service. + + - name (str): The service name. + + """ kwargs.setdefault("comment", "stop %s service" % name) kwargs.setdefault("register", "%s_stopped" % name) @@ -142,6 +194,11 @@ def service_stop(name, **kwargs): def system(op, **kwargs): + """Perform a system operation. + + - op (str): The operation to perform; reboot, update, upgrade. + + """ if op == "reboot": return system_reboot(**kwargs) elif op == "update": @@ -153,6 +210,11 @@ def system(op, **kwargs): def system_install(name, **kwargs): + """Install a system-level package. + + - name (str): The name of the package to install. + + """ kwargs.setdefault("comment", "install system package %s" % name) return Command("apt-get install -y %s" % name, **kwargs) @@ -165,6 +227,11 @@ def system_reboot(**kwargs): def system_uninstall(name, **kwargs): + """Uninstall a system-level package. + + - name (str): The name of the package to uninstall. + + """ kwargs.setdefault("comment", "remove system package %s" % name) return Command("apt-get uninstall -y %s" % name, **kwargs) @@ -183,6 +250,14 @@ def system_upgrade(**kwargs): def template(source, target, backup=True, parser=None, **kwargs): + """Create a file from a template. + + - source (str): The path to the template file. + - target (str): The path to where the new file should be created. + - backup (bool): Indicates whether a backup should be made if the target file already exists. + - parser (str): The parser to use ``jinja`` (the default) or ``simple``. + + """ return Template(source, target, backup=backup, parser=parser, **kwargs) diff --git a/scripttease/parsers/utils.py b/scripttease/parsers/utils.py index d92f29f..eb8af52 100644 --- a/scripttease/parsers/utils.py +++ b/scripttease/parsers/utils.py @@ -27,8 +27,8 @@ def filter_commands(commands, environments=None, tags=None): :type environments: list[str] :param tags: Tag names to be matched. - :type tags - :return: + :type tags: list[str] + """ filtered = list() for command in commands: diff --git a/setup.py b/setup.py index 6d66d71..98f19ce 100644 --- a/setup.py +++ b/setup.py @@ -22,9 +22,8 @@ setup( url='https://github.com/develmaycare/python-scripttease', packages=find_packages(exclude=["tests"]), include_package_data=True, + # superpython provides jinja2 and pygments install_requires=[ - "jinja2", - "pygments", "superpython", ], dependency_links=[ @@ -43,6 +42,7 @@ setup( zip_safe=False, tests_require=[ "coverage", + "pytest", ], test_suite='runtests.runtests', entry_points={ diff --git a/tests/test_library_overlays_posix.py b/tests/test_library_overlays_posix.py index 2f0627e..83c2549 100644 --- a/tests/test_library_overlays_posix.py +++ b/tests/test_library_overlays_posix.py @@ -107,6 +107,11 @@ def test_remove(): assert "/path/to/dir" in s +def test_rename(): + c = rename("/path/to/file.txt", "/path/to/renamed.txt") + assert "mv /path/to/file.txt /path/to/renamed.txt" in c.get_statement() + + def test_rsync(): c = rsync( "/path/to/local/",