From 6f12c82f076fa7cbb9b0a66e694c75bc763b4181 Mon Sep 17 00:00:00 2001 From: glob Date: Mon, 10 Mar 2025 08:13:03 +0000 Subject: [PATCH] Bug 1951578: remove `mach pastebin`. r=sergesanspaille Adds a new "hidden" argument to mach decorators that allows the command to execute but will not be visible in `mach help`. Removes `mach pastebin` functionality, marks it as "hidden", and displays a notice that pastebin.mozilla.org has been decommissioned. Differential Revision: https://phabricator.services.mozilla.com/D240280 --- python/mach/mach/decorators.py | 4 + python/mach/mach/dispatcher.py | 3 + .../mach/mach/test/providers/definitions.py | 20 ++ python/mach/mach/test/python.toml | 2 + python/mach/mach/test/test_definitions.py | 28 ++ tools/mach_commands.py | 244 +----------------- 6 files changed, 70 insertions(+), 231 deletions(-) create mode 100644 python/mach/mach/test/providers/definitions.py create mode 100644 python/mach/mach/test/test_definitions.py diff --git a/python/mach/mach/decorators.py b/python/mach/mach/decorators.py index ab5f6d294e59..9d9c229c13c9 100644 --- a/python/mach/mach/decorators.py +++ b/python/mach/mach/decorators.py @@ -45,6 +45,8 @@ class _MachCommand: "decl_order", # Whether to disable automatic logging to last_log.json for the command. "no_auto_log", + # Whether to hide this command from help. + "hidden", ) def __init__( @@ -59,6 +61,7 @@ class _MachCommand: virtualenv_name=None, ok_if_tests_disabled=False, no_auto_log=False, + hidden=False, ): self.name = name self.subcommand = subcommand @@ -70,6 +73,7 @@ class _MachCommand: self.argument_group_names = [] self.virtualenv_name = virtualenv_name self.order = order + self.hidden = hidden if ok_if_tests_disabled and category != "testing": raise ValueError( "ok_if_tests_disabled should only be set for " "`testing` mach commands" diff --git a/python/mach/mach/dispatcher.py b/python/mach/mach/dispatcher.py index 9551f89f735b..abc3b646c6f8 100644 --- a/python/mach/mach/dispatcher.py +++ b/python/mach/mach/dispatcher.py @@ -259,6 +259,9 @@ class CommandAction(argparse.Action): for command in sorted(r.commands_by_category[category]): handler = r.command_handlers[command] + if handler.hidden: + continue + # Instantiate a handler class to see if it should be filtered # out for the current context or not. Condition functions can be # applied to the command's decorator. diff --git a/python/mach/mach/test/providers/definitions.py b/python/mach/mach/test/providers/definitions.py new file mode 100644 index 000000000000..05c0189cedc5 --- /dev/null +++ b/python/mach/mach/test/providers/definitions.py @@ -0,0 +1,20 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +from mach.decorators import Command + + +@Command("cmd_default_visible", category="testing") +def run_default_visible(self, command_context): + pass + + +@Command("cmd_not_hidden", category="testing") +def run_not_hidden(self, command_context, hidden=False): + pass + + +@Command("cmd_hidden", category="testing", hidden=True) +def run_hidden(self, command_context): + pass diff --git a/python/mach/mach/test/python.toml b/python/mach/mach/test/python.toml index a2695072bfcc..d27ac2fb5964 100644 --- a/python/mach/mach/test/python.toml +++ b/python/mach/mach/test/python.toml @@ -6,6 +6,8 @@ subsuite = "mach" ["test_conditions.py"] skip-if = ["true"] +["test_definitions.py"] + ["test_config.py"] ["test_decorators.py"] diff --git a/python/mach/mach/test/test_definitions.py b/python/mach/mach/test/test_definitions.py new file mode 100644 index 000000000000..f8b6d3b0d617 --- /dev/null +++ b/python/mach/mach/test/test_definitions.py @@ -0,0 +1,28 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +from pathlib import Path + +from mozunit import main + +from mach.test.conftest import TestBase + + +class TestConditions(TestBase): + """Tests for definitions provided to the @Command decorator.""" + + def _run(self, args): + return self._run_mach(args, Path("definitions.py")) + + def test_help_message(self): + """Test that commands that are hidden do not show up in help.""" + + result, stdout, stderr = self._run(["help"]) + self.assertIn("cmd_default_visible", stdout) + self.assertIn("cmd_not_hidden", stdout) + self.assertNotIn("cmd_hidden", stdout) + + +if __name__ == "__main__": + main() diff --git a/tools/mach_commands.py b/tools/mach_commands.py index 996e11a39126..9c27472ec27f 100644 --- a/tools/mach_commands.py +++ b/tools/mach_commands.py @@ -110,244 +110,26 @@ def busted_file(command_context, against): webbrowser.open_new_tab(uri) -MACH_PASTEBIN_DURATIONS = { - "onetime": "onetime", - "hour": "3600", - "day": "86400", - "week": "604800", - "month": "2073600", -} - -EXTENSION_TO_HIGHLIGHTER = { - ".hgrc": "ini", - "Dockerfile": "docker", - "Makefile": "make", - "applescript": "applescript", - "arduino": "arduino", - "bash": "bash", - "bat": "bat", - "c": "c", - "clojure": "clojure", - "cmake": "cmake", - "coffee": "coffee-script", - "console": "console", - "cpp": "cpp", - "cs": "csharp", - "css": "css", - "cu": "cuda", - "cuda": "cuda", - "dart": "dart", - "delphi": "delphi", - "diff": "diff", - "django": "django", - "docker": "docker", - "elixir": "elixir", - "erlang": "erlang", - "go": "go", - "h": "c", - "handlebars": "handlebars", - "haskell": "haskell", - "hs": "haskell", - "html": "html", - "ini": "ini", - "ipy": "ipythonconsole", - "ipynb": "ipythonconsole", - "irc": "irc", - "j2": "django", - "java": "java", - "js": "js", - "json": "json", - "jsx": "jsx", - "kt": "kotlin", - "less": "less", - "lisp": "common-lisp", - "lsp": "common-lisp", - "lua": "lua", - "m": "objective-c", - "make": "make", - "matlab": "matlab", - "md": "_markdown", - "nginx": "nginx", - "numpy": "numpy", - "patch": "diff", - "perl": "perl", - "php": "php", - "pm": "perl", - "postgresql": "postgresql", - "py": "python", - "rb": "rb", - "rs": "rust", - "rst": "rst", - "sass": "sass", - "scss": "scss", - "sh": "bash", - "sol": "sol", - "sql": "sql", - "swift": "swift", - "tex": "tex", - "typoscript": "typoscript", - "vim": "vim", - "xml": "xml", - "xslt": "xslt", - "yaml": "yaml", - "yml": "yaml", -} - - -def guess_highlighter_from_path(path): - """Return a known highlighter from a given path - - Attempt to select a highlighter by checking the file extension in the mapping - of extensions to highlighter. If that fails, attempt to pass the basename of - the file. Return `_code` as the default highlighter if that fails. - """ - import os - - _name, ext = os.path.splitext(path) - - if ext.startswith("."): - ext = ext[1:] - - if ext in EXTENSION_TO_HIGHLIGHTER: - return EXTENSION_TO_HIGHLIGHTER[ext] - - basename = os.path.basename(path) - - return EXTENSION_TO_HIGHLIGHTER.get(basename, "_code") - - -PASTEMO_MAX_CONTENT_LENGTH = 250 * 1024 * 1024 - -PASTEMO_URL = "https://paste.mozilla.org/api/" +def pastebin_create_parser(): + # Accept all args so they can be promptly ignored. + parser = argparse.ArgumentParser() + parser.add_argument("argv", nargs=argparse.REMAINDER, help=argparse.SUPPRESS) + return parser @Command( "pastebin", category="misc", - description="Command line interface to paste.mozilla.org.", + hidden=True, + parser=pastebin_create_parser, ) -@CommandArgument( - "--list-highlighters", - action="store_true", - help="List known highlighters and exit", -) -@CommandArgument( - "--highlighter", default=None, help="Syntax highlighting to use for paste" -) -@CommandArgument( - "--expires", - default="week", - choices=sorted(MACH_PASTEBIN_DURATIONS.keys()), - help="Expire paste after given time duration (default: %(default)s)", -) -@CommandArgument( - "--verbose", - action="store_true", - help="Print extra info such as selected syntax highlighter", -) -@CommandArgument( - "path", - nargs="?", - default=None, - help="Path to file for upload to paste.mozilla.org", -) -def pastebin(command_context, list_highlighters, highlighter, expires, verbose, path): - """Command line interface to `paste.mozilla.org`. +def pastebin(command_context, argv): + """Obsolete command line interface to `paste.mozilla.org`.""" - Takes either a filename whose content should be pasted, or reads - content from standard input. If a highlighter is specified it will - be used, otherwise the file name will be used to determine an - appropriate highlighter. - """ - - import requests - - def verbose_print(*args, **kwargs): - """Print a string if `--verbose` flag is set""" - if verbose: - print(*args, **kwargs) - - # Show known highlighters and exit. - if list_highlighters: - lexers = set(EXTENSION_TO_HIGHLIGHTER.values()) - print("Available lexers:\n - %s" % "\n - ".join(sorted(lexers))) - return 0 - - # Get a correct expiry value. - try: - verbose_print("Setting expiry from %s" % expires) - expires = MACH_PASTEBIN_DURATIONS[expires] - verbose_print("Using %s as expiry" % expires) - except KeyError: - print( - "%s is not a valid duration.\n" - "(hint: try one of %s)" - % (expires, ", ".join(MACH_PASTEBIN_DURATIONS.keys())) - ) - return 1 - - data = { - "format": "json", - "expires": expires, - } - - # Get content to be pasted. - if path: - verbose_print("Reading content from %s" % path) - try: - with open(path, "r") as f: - content = f.read() - except IOError: - print("ERROR. No such file %s" % path) - return 1 - - lexer = guess_highlighter_from_path(path) - if lexer: - data["lexer"] = lexer - else: - verbose_print("Reading content from stdin") - content = sys.stdin.read() - - # Assert the length of content to be posted does not exceed the maximum. - content_length = len(content) - verbose_print("Checking size of content is okay (%d)" % content_length) - if content_length > PASTEMO_MAX_CONTENT_LENGTH: - print( - "Paste content is too large (%d, maximum %d)" - % (content_length, PASTEMO_MAX_CONTENT_LENGTH) - ) - return 1 - - data["content"] = content - - # Highlight as specified language, overwriting value set from filename. - if highlighter: - verbose_print("Setting %s as highlighter" % highlighter) - data["lexer"] = highlighter - - try: - verbose_print("Sending request to %s" % PASTEMO_URL) - resp = requests.post(PASTEMO_URL, data=data) - - # Error code should always be 400. - # Response content will include a helpful error message, - # so print it here (for example, if an invalid highlighter is - # provided, it will return a list of valid highlighters). - if resp.status_code >= 400: - print("Error code %d: %s" % (resp.status_code, resp.content)) - return 1 - - verbose_print("Pasted successfully") - - response_json = resp.json() - - verbose_print("Paste highlighted as %s" % response_json["lexer"]) - print(response_json["url"]) - - return 0 - except Exception as e: - print("ERROR. Paste failed.") - print("%s" % e) + print( + "pastebin.mozilla.org has been decommissioned.\n" + "Please use your favorite search engine to find alternatives." + ) return 1