diff --git a/odoo/cli/cloc.py b/odoo/cli/cloc.py index 30b2dde8305..7c211f05771 100644 --- a/odoo/cli/cloc.py +++ b/odoo/cli/cloc.py @@ -1,33 +1,33 @@ -# -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. import argparse import os import sys import textwrap +from pathlib import Path from odoo.tools import cloc, config from . import Command class Cloc(Command): - """\ - Odoo cloc is a tool to count the number of relevant lines written in - Python, Javascript or XML. This can be used as rough metric for pricing - maintenance of customizations. - - It has two modes of operation, either by providing a path: - - odoo-bin cloc -p module_path - - Or by providing the name of a database: - - odoo-bin cloc --addons-path=dirs -d database - - In the latter mode, only the custom code is accounted for. - """ + """ Count lines of code per modules """ def run(self, args): parser = argparse.ArgumentParser( - prog="%s cloc" % sys.argv[0].split(os.path.sep)[-1], - description=textwrap.dedent(self.__doc__), + prog=f'{Path(sys.argv[0]).name} {self.name}', + description="""\ +Odoo cloc is a tool to count the number of relevant lines written in +Python, Javascript or XML. This can be used as rough metric for pricing +maintenance of customizations. + +It has two modes of operation, either by providing a path: + + odoo-bin cloc -p module_path + +Or by providing the name of a database: + + odoo-bin cloc --addons-path=dirs -d database + +In the latter mode, only the custom code is accounted for. +""", formatter_class=argparse.RawDescriptionHelpFormatter ) parser.add_argument('--database', '-d', dest="database", help="Database name") diff --git a/odoo/cli/command.py b/odoo/cli/command.py index 4b41222a223..79c0036a90a 100644 --- a/odoo/cli/command.py +++ b/odoo/cli/command.py @@ -1,8 +1,8 @@ -from __future__ import print_function +# Part of Odoo. See LICENSE file for full copyright and licensing details. import logging -import sys import os -from os.path import join as joinpath, isdir +import sys +from pathlib import Path import odoo from odoo.modules import get_modules, get_module_path, initialize_sys_path @@ -14,17 +14,27 @@ class Command: cls.name = cls.name or cls.__name__.lower() commands[cls.name] = cls + +ODOO_HELP = """\ +Odoo CLI, use '{odoo_bin} --help' for regular server options. + +Available commands: + {command_list} + +Use '{odoo_bin} --help' for individual command help.""" + class Help(Command): - """Display the list of available commands""" + """ Display the list of available commands """ def run(self, args): - print("Available commands:\n") - names = list(commands) - padding = max([len(k) for k in names]) + 2 - for k in sorted(names): - name = k.ljust(padding, ' ') - doc = (commands[k].__doc__ or '').strip() - print(" %s%s" % (name, doc)) - print("\nUse '%s --help' for individual command help." % sys.argv[0].split(os.path.sep)[-1]) + padding = max([len(cmd) for cmd in commands]) + 2 + command_list = "\n ".join([ + " {}{}".format(name.ljust(padding), (command.__doc__ or "").strip()) + for name, command in sorted(commands.items()) + ]) + print(ODOO_HELP.format( # pylint: disable=bad-builtin + odoo_bin=Path(sys.argv[0]).name, + command_list=command_list + )) def main(): args = sys.argv[1:] @@ -45,7 +55,7 @@ def main(): logging.disable(logging.CRITICAL) initialize_sys_path() for module in get_modules(): - if isdir(joinpath(get_module_path(module), 'cli')): + if (Path(get_module_path(module)) / 'cli').is_dir(): __import__('odoo.addons.' + module) logging.disable(logging.NOTSET) command = args[0] diff --git a/odoo/cli/db.py b/odoo/cli/db.py index b3fe3685781..24a57428f2f 100644 --- a/odoo/cli/db.py +++ b/odoo/cli/db.py @@ -1,10 +1,11 @@ +# Part of Odoo. See LICENSE file for full copyright and licensing details. import argparse import io import urllib.parse +import sys import zipfile from functools import partial from pathlib import Path -from sys import argv, stdout, stderr import requests @@ -13,9 +14,10 @@ from .server import report_configuration from ..service.db import dump_db, exp_drop, exp_db_exist, exp_duplicate_database, exp_rename, restore_db from ..tools import config -eprint = partial(print, file=stderr, flush=True) +eprint = partial(print, file=sys.stderr, flush=True) class Db(Command): + """ Create, drop, dump, load databases """ name = 'db' def run(self, cmdargs): @@ -25,8 +27,8 @@ class Db(Command): all filestore-aware. """ parser = argparse.ArgumentParser( - prog="%s %s" % (Path(argv[0]).name, self.name), - description=self.__doc__ + prog=f'{Path(sys.argv[0]).name} {self.name}', + description=self.__doc__.strip() ) parser.add_argument('-c', '--config') parser.add_argument('-D', '--data-dir') @@ -146,7 +148,7 @@ class Db(Command): def dump(self, args): if args.dump_path == '-': - dump_db(args.database, stdout.buffer) + dump_db(args.database, sys.stdout.buffer) else: with open(args.dump_path, 'wb') as f: dump_db(args.database, f) diff --git a/odoo/cli/deploy.py b/odoo/cli/deploy.py index 8ec95fa3d47..4ecac0f97cb 100644 --- a/odoo/cli/deploy.py +++ b/odoo/cli/deploy.py @@ -1,12 +1,11 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -from __future__ import print_function +# Part of Odoo. See LICENSE file for full copyright and licensing details. import argparse import os import requests import sys import tempfile import zipfile +from pathlib import Path from . import Command @@ -63,7 +62,7 @@ class Deploy(Command): def run(self, cmdargs): parser = argparse.ArgumentParser( - prog="%s deploy" % sys.argv[0].split(os.path.sep)[-1], + prog=f'{Path(sys.argv[0]).name} {self.name}', description=self.__doc__ ) parser.add_argument('path', help="Path of the module to deploy") diff --git a/odoo/cli/genproxytoken.py b/odoo/cli/genproxytoken.py index 2d904c53e47..ed9eb458dd4 100644 --- a/odoo/cli/genproxytoken.py +++ b/odoo/cli/genproxytoken.py @@ -1,8 +1,10 @@ +# Part of Odoo. See LICENSE file for full copyright and licensing details. import argparse import os import secrets import sys import textwrap +from pathlib import Path from passlib.hash import pbkdf2_sha512 @@ -11,8 +13,7 @@ from odoo.tools import config class GenProxyToken(Command): - def __init__(self): - self.command_name = "genproxytoken" + """ Generate and (re)set proxy access token in config file """ def generate_token(self, length=16): token = secrets.token_hex(int(length / 2)) @@ -21,8 +22,8 @@ class GenProxyToken(Command): def run(self, cmdargs): parser = argparse.ArgumentParser( - prog="%s %s" % (sys.argv[0].split(os.path.sep)[-1], self.command_name), - description="Generate and (re)set proxy access token in config file" + prog=f'{Path(sys.argv[0]).name} {self.name}', + description=self.__doc__.strip() ) parser.add_argument('-c', '--config', type=str, help="Specify an alternate config file") parser.add_argument('--token-length', type=int, help="Token Length", default=16) diff --git a/odoo/cli/neutralize.py b/odoo/cli/neutralize.py index 481fc5643ca..d2d1994a6dd 100644 --- a/odoo/cli/neutralize.py +++ b/odoo/cli/neutralize.py @@ -1,9 +1,8 @@ -# -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. - import logging import optparse import sys +from pathlib import Path import odoo @@ -17,6 +16,7 @@ class Neutralize(Command): def run(self, args): parser = odoo.tools.config.parser + parser.prog = f'{Path(sys.argv[0]).name} {self.name}' group = optparse.OptionGroup(parser, "Neutralize", "Neutralize the database specified by the `-d` argument.") group.add_option("--stdout", action="store_true", dest="to_stdout", help="Output the neutralization SQL instead of applying it") diff --git a/odoo/cli/populate.py b/odoo/cli/populate.py index 9dcf669adf1..66ff393047d 100644 --- a/odoo/cli/populate.py +++ b/odoo/cli/populate.py @@ -1,11 +1,11 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -from contextlib import nullcontext -import time +# Part of Odoo. See LICENSE file for full copyright and licensing details. import fnmatch import logging import optparse +import sys +import time +from contextlib import nullcontext +from pathlib import Path from unittest.mock import patch import odoo @@ -14,9 +14,11 @@ _logger = logging.getLogger(__name__) class Populate(Command): + """ Inject fake data inside a database for testing """ def run(self, cmdargs): parser = odoo.tools.config.parser + parser.prog = f'{Path(sys.argv[0]).name} {self.name}' group = optparse.OptionGroup(parser, "Populate Configuration") group.add_option("--size", dest="population_size", help="Populate database with auto-generated data. Value should be the population size: small, medium or large", diff --git a/odoo/cli/scaffold.py b/odoo/cli/scaffold.py index 53d3b8df85a..ea861dffec1 100644 --- a/odoo/cli/scaffold.py +++ b/odoo/cli/scaffold.py @@ -1,10 +1,9 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -from __future__ import print_function +# Part of Odoo. See LICENSE file for full copyright and licensing details. import argparse import os import re import sys +from pathlib import Path import jinja2 @@ -16,7 +15,7 @@ class Scaffold(Command): def run(self, cmdargs): # TODO: bash completion file parser = argparse.ArgumentParser( - prog="%s scaffold" % sys.argv[0].split(os.path.sep)[-1], + prog=f'{Path(sys.argv[0]).name} {self.name}', description=self.__doc__, epilog=self.epilog(), ) diff --git a/odoo/cli/server.py b/odoo/cli/server.py index 7bab9cf598b..2e678cf3b1e 100644 --- a/odoo/cli/server.py +++ b/odoo/cli/server.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. """ @@ -17,6 +16,7 @@ import logging import os import re import sys +from pathlib import Path from psycopg2 import ProgrammingError, errorcodes @@ -175,4 +175,5 @@ def main(args): class Server(Command): """Start the odoo server (default command)""" def run(self, args): + odoo.tools.config.parser.prog = f'{Path(sys.argv[0]).name} {self.name}' main(args) diff --git a/odoo/cli/shell.py b/odoo/cli/shell.py index 3c334bb8a75..7497421a87f 100644 --- a/odoo/cli/shell.py +++ b/odoo/cli/shell.py @@ -1,12 +1,10 @@ -# -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. - -from __future__ import print_function import code import logging import os import signal import sys +from pathlib import Path import odoo from odoo.tools import config @@ -56,6 +54,7 @@ class Shell(Command): supported_shells = ['ipython', 'ptpython', 'bpython', 'python'] def init(self, args): + config.parser.prog = f'{Path(sys.argv[0]).name} {self.name}' config.parse_config(args) odoo.cli.server.report_configuration() odoo.service.server.start(preload=[], stop=True) diff --git a/odoo/cli/start.py b/odoo/cli/start.py index d695f6e4860..274e4bf16ba 100644 --- a/odoo/cli/start.py +++ b/odoo/cli/start.py @@ -1,11 +1,10 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -from __future__ import print_function +# Part of Odoo. See LICENSE file for full copyright and licensing details. import argparse import glob import itertools import os import sys +from pathlib import Path import odoo from . import Command @@ -15,7 +14,7 @@ from odoo.service.db import _create_empty_database, DatabaseExists class Start(Command): - """Quick start the Odoo server for your project""" + """ Quickly start the odoo server with default options """ def get_module_list(self, path): mods = itertools.chain.from_iterable( @@ -25,9 +24,10 @@ class Start(Command): return [mod.split(os.path.sep)[-2] for mod in mods] def run(self, cmdargs): + odoo.tools.config.parser.prog = f'{Path(sys.argv[0]).name} {self.name}' parser = argparse.ArgumentParser( - prog="%s start" % sys.argv[0].split(os.path.sep)[-1], - description=self.__doc__ + prog=f'{Path(sys.argv[0]).name} {self.name}', + description=self.__doc__.strip(), ) parser.add_argument('--path', default=".", help="Directory where your project's modules are stored (will autodetect from current dir)") diff --git a/odoo/cli/tsconfig.py b/odoo/cli/tsconfig.py index 6ff854711f6..fdd79b7fa9f 100644 --- a/odoo/cli/tsconfig.py +++ b/odoo/cli/tsconfig.py @@ -1,19 +1,18 @@ +# Part of Odoo. See LICENSE file for full copyright and licensing details. import argparse import glob import json import os import re import sys +from pathlib import Path from . import Command from odoo.modules.module import MANIFEST_NAMES class TSConfig(Command): - """Generates tsconfig files for javascript code""" - - def __init__(self): - self.command_name = "tsconfig" + """ Generates tsconfig files for javascript code """ def get_module_list(self, path): return [ @@ -35,8 +34,8 @@ class TSConfig(Command): def run(self, cmdargs): parser = argparse.ArgumentParser( - prog="%s %s" % (sys.argv[0].split(os.path.sep)[-1], self.command_name), - description=self.__doc__ + prog=f'{Path(sys.argv[0]).name} {self.name}', + description=self.__doc__.strip() ) parser.add_argument('--addons-path', type=str, nargs=1, dest="paths") args = parser.parse_args(args=cmdargs)