Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
372 changes: 314 additions & 58 deletions doc/PREPROD_COMMANDS.md

Large diffs are not rendered by default.

1,895 changes: 991 additions & 904 deletions poetry.lock

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions preprod/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,6 @@
"""
The `preprod` package provides tools for managing pre-production and production scripts.
It includes core functionalities, common utilities, and version information.
"""
from .version import __version__, __versiondate__, __versiondatetime__
from .commons import epilog
353 changes: 287 additions & 66 deletions preprod/commons.py

Large diffs are not rendered by default.

59 changes: 53 additions & 6 deletions preprod/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@
_=str


"""
This module provides the core functionality for the preprod command-line tool,
including argument parsing, action execution, and logging.
"""
def concurrent_log(title, stdout=None, stderr=None):
"""
Logs messages concurrently to a project-specific log file in /tmp/.
Expand All @@ -25,7 +29,7 @@ def concurrent_log(title, stdout=None, stderr=None):
Parameters:
- title (str): The main log message.
- stdout (str, optional): Standard output to log.
- stderr (str, optional): Standard error to log.
- stderr (str, optional): Standard error captured from a command, if any.
"""
def parse_std(std):
arr=std.split("\n")
Expand All @@ -45,11 +49,24 @@ def parse_std(std):
f.write(commons.red(" STDERR\n"))
f.write(parse_std(stderr))

## If arguments is None, launches with sys.argc parameters. Entry point is toomanyfiles:main
## You can call with main(['--pretend']). It's equivalento to os.system('program --pretend')
## @param arguments is an array with parser arguments. For example: ['--argument','9'].
def main(arguments=None):
"""
The main entry point for the preprod application.

Parses command-line arguments, validates project and action, and executes
the specified action script. It also handles 'pretend' and 'edit' modes.

Parameters:
arguments (list, optional): A list of strings representing command-line
arguments. If None, `sys.argv` is used.
Example: `['--pretend', 'myproject', 'myaction']`.
This allows programmatic invocation similar to `os.system('program --pretend')`.
"""
global lock
# `lock` is a multiprocessing.Lock used for ensuring exclusive access
# to the log file during concurrent logging operations. It's initialized
# globally here because `concurrent_log` is called from various places
# and needs a shared lock instance.
lock=Lock()

global args
Expand All @@ -61,6 +78,10 @@ def main(arguments=None):
parser.add_argument('project', nargs='?', default=None, help=_("Project identification"), action='store')
parser.add_argument('action', nargs='?', default=None, help=_("Action identification"), action='store')

# `args` is a global variable storing the parsed command-line arguments.
# It's made global to be accessible by functions like `concurrent_log`
# which need access to `args.project` and `args.action` for context.
# This avoids passing `args` explicitly to every function.
args=parser.parse_args(arguments)

commons.check_repository_path(verbose=True)
Expand All @@ -71,22 +92,30 @@ def main(arguments=None):

# Checks for project and action parameters
if args.project is None and args.action is None:
# If no project or action is specified, list all available projects
# and their actions, then exit. This serves as a default behavior
# for simply running `preprod`.
list_repository()
exit(1)

print(commons.yellow(_("Reading repository from '{0}'").format(repository_path)))

dpa=commons.dictionary_project_actions()
if not args.project in dpa:
# If the specified project is not found, inform the user and exit.
print(commons.red(_("Project '{0}' wasn't found en repository. Found projects: {1}").format(args.project, commons.green(str(list(dpa.keys()))))))
exit(2)

if args.action is None:
# If a project is specified but no action, list available actions
# for that project and exit.
print(commons.red(_("Available actions for project '{0}': {1}").format(args.project, commons.green(str(dpa[args.project])))))
exit(3)


if not args.action in dpa[args.project]:
# If the specified action is not found within the project, inform
# the user and exit.
print(commons.red(_("Project '{0}' hasn't '{1}' action. Found actions: {2}").format(args.project, args.action, commons.green(str(dpa[args.project])))))
exit(4)

Expand All @@ -100,11 +129,16 @@ def main(arguments=None):
else:
editor_command = 'vi' # Fallback to vi if no other editor found or EDITOR env var not set

# Open the action file in the determined editor.
system(f"{editor_command} {action_path}")
exit(0) # Exit after editing

if args.project is not None and args.action is not None:
start=datetime.now()
# Read the action commands from the specified action file.
# These commands are expected to be Python code.
# The `with open(...)` ensures the file is properly closed.
# The `action_path` is constructed from the repository, project, and action names.
with open(action_path) as f:
action_commands=f.read()

Expand All @@ -114,14 +148,18 @@ def main(arguments=None):
import sys
sys.path.append("{repository_path}")
import repository_commons
{action_commands}
""" + action_commands + """
"""
if args.pretend:
# In pretend mode, print the commands that would be executed
# without actually running them.
print(commons.white(_("Pretending project '{0}' and action '{1}':").format(args.project, args.action)))
print("________________________________")
print(commands)
print("________________________________")
else:
# Execute the combined Python commands. This includes importing
# `preprod_commons` and `repository_commons` for use within the action script.
print(commons.white(_("Executing project '{0}' and action '{1}'").format(args.project, args.action)))
exec(commands)
print(commons.white(_("Executed project '{0}' and action '{1}' took {2}").format(args.project, args.action, datetime.now()-start)))
Expand All @@ -130,7 +168,9 @@ def main(arguments=None):
def create():
"""
Initializes a new preprod repository.

This function sets up the basic directory structure for preprod,
creates a sample project ('foo') with a 'start' action, and
generates a `repository_commons.py` file with a sample function.
Creates the necessary directory structure and a sample project/action
along with a `repository_commons.py` file.
"""
Expand All @@ -141,17 +181,20 @@ def create():
if commons.check_repository_path():
print(_("Repository already created in {}").format(commons.repository_path()))
exit(6)
# Determine the repository path based on user privileges (root or normal user).
rp=commons.repository_path()

makedirs(f"{rp}/foo/")

# Create a sample `repository_commons.py` file.
with open(f"{rp}/repository_commons.py", "w") as f:
f.write("""def foo():
print("This is the ouput of foo_function in repostory commons")
""")


with open(f"{rp}/foo/start", "w") as f:
# Create a sample action file 'start' within the 'foo' project.
f.write("""print("This is foo project and start action")
if preprod_commons.is_root():
print("I'm root")
Expand All @@ -165,6 +208,10 @@ def list_repository():
"""
Lists all available preprod projects and their actions in the repository.

It first checks if the repository path exists, then retrieves a dictionary
mapping project names to a list of their actions. The output is sorted
alphabetically by project name and displayed in a user-friendly format
with color coding.
Prints a formatted output of the discovered projects and actions.
"""
commons.check_repository_path(verbose=True)
Expand Down
20 changes: 0 additions & 20 deletions preprod/locale/en.po

This file was deleted.

Binary file removed preprod/locale/en/LC_MESSAGES/preprod.mo
Binary file not shown.
52 changes: 42 additions & 10 deletions preprod/locale/es.po
Original file line number Diff line number Diff line change
@@ -1,24 +1,27 @@
# Spanish translations for PACKAGE package
# Traducciones al español para el paquete PACKAGE.
# Copyright (C) 2015 THE PACKAGE'S COPYRIGHT HOLDER
# Copyright (C) 2024 Mariano Muñoz
# This file is distributed under the same license as the PACKAGE package.
#
# root <turulomio@yahoo.es>, 2015, 2020.
# Mariano Muñoz <turulomio@yahoo.es>, 2024.
msgid ""
msgstr ""
"Project-Id-Version: TooManyFiles\n"
"Project-Id-Version: preprod\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-04-13 10:04+0200\n"
"PO-Revision-Date: 2020-04-03 08:54+0200\n"
"Last-Translator: trabajo <turulomio@yahoo.es>\n"
"Language-Team: Spanish <kde-i18n-doc@kde.org>\n"
"POT-Creation-Date: 2026-02-26 08:23+0100\n"
"PO-Revision-Date: 2024-07-30 10:00+0200\n"
"Last-Translator: Mariano Muñoz <turulomio@yahoo.es>\n"
"Language-Team: Spanish <turulomio@yahoo.es>\n"
"Language: es\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Generator: Lokalize 19.12.3\n"

msgid "Developed by Mariano Muñoz {}-{}"
msgstr "Desarrollado por Mariano Muñoz {}-{}"

msgid "Press a key to continue..."
msgstr "Pulsa una tecla para continuar..."

Expand Down Expand Up @@ -116,17 +119,43 @@ msgstr "Cambiando '{0}' a propietario {1}:{2}"

#, python-brace-format
msgid "Changing directories permissions to {0} and files to {1}"
msgstr ""
msgstr "Cambiando permisos de directorios a {0} y ficheros a {1}"

#, python-brace-format
msgid "Invoking preprod action '{0}' for project '{1}'"
msgstr "Invocando acción preprod '{0}' para el proyecto '{1}'"

msgid "Developed by Mariano Muñoz 2023-{}"
msgstr "Desarrollado por Mariano Muñoz 2023-{}"
msgid " (pretend mode)"
msgstr " (modo simulación)"

msgid " - Succeeded"
msgstr " - Éxito"

#, python-brace-format
msgid " - Failed with exit code {0}"
msgstr " - Falló con código de salida {0}"

#, python-brace-format
msgid " - Failed with unexpected error: {0}"
msgstr " - Falló con error inesperado: {0}"

#, python-brace-format
msgid "Sleeping for {0} seconds"
msgstr "Durmiendo durante {0} segundos"

#, python-brace-format
msgid "Creating file '{0}'"
msgstr "Creando fichero '{0}'"

msgid "Preprod manager"
msgstr "Gestor Preprod"

msgid "Prints action code without running it"
msgstr "Muestra el código de la acción sin ejecutarlo"

msgid "Opens the action file in the default console editor"
msgstr "Abre el fichero de acción en el editor de consola por defecto"

msgid "Project identification"
msgstr "Identificación del proyecto"

Expand Down Expand Up @@ -168,6 +197,9 @@ msgstr "El repositorio ya está creado en {}"
msgid "Reading repository from {0} and listing available preprod scripts"
msgstr "Leyendo el repositorio desde {0} y listando los scripts disponibles de preprod"

#~ msgid "Developed by Mariano Muñoz 2023-{}"
#~ msgstr "Desarrollado por Mariano Muñoz 2023-{}"

#, python-brace-format
#~ msgid "Creating file '{filename}'"
#~ msgstr "Creando fichero '{filename}'"
Binary file modified preprod/locale/es/LC_MESSAGES/preprod.mo
Binary file not shown.
33 changes: 31 additions & 2 deletions preprod/locale/preprod.pot
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-04-13 10:04+0200\n"
"POT-Creation-Date: 2026-02-26 08:23+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
Expand All @@ -17,6 +17,9 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"

msgid "Developed by Mariano Muñoz {}-{}"
msgstr ""

msgid "Press a key to continue..."
msgstr ""

Expand Down Expand Up @@ -116,7 +119,30 @@ msgstr ""
msgid "Changing directories permissions to {0} and files to {1}"
msgstr ""

msgid "Developed by Mariano Muñoz 2023-{}"
#, python-brace-format
msgid "Invoking preprod action '{0}' for project '{1}'"
msgstr ""

msgid " (pretend mode)"
msgstr ""

msgid " - Succeeded"
msgstr ""

#, python-brace-format
msgid " - Failed with exit code {0}"
msgstr ""

#, python-brace-format
msgid " - Failed with unexpected error: {0}"
msgstr ""

#, python-brace-format
msgid "Sleeping for {0} seconds"
msgstr ""

#, python-brace-format
msgid "Creating file '{0}'"
msgstr ""

msgid "Preprod manager"
Expand All @@ -125,6 +151,9 @@ msgstr ""
msgid "Prints action code without running it"
msgstr ""

msgid "Opens the action file in the default console editor"
msgstr ""

msgid "Project identification"
msgstr ""

Expand Down
Loading