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
This commit is contained in:
glob
2025-03-10 08:13:03 +00:00
parent 663dde8838
commit 6f12c82f07
6 changed files with 70 additions and 231 deletions

View File

@@ -45,6 +45,8 @@ class _MachCommand:
"decl_order", "decl_order",
# Whether to disable automatic logging to last_log.json for the command. # Whether to disable automatic logging to last_log.json for the command.
"no_auto_log", "no_auto_log",
# Whether to hide this command from help.
"hidden",
) )
def __init__( def __init__(
@@ -59,6 +61,7 @@ class _MachCommand:
virtualenv_name=None, virtualenv_name=None,
ok_if_tests_disabled=False, ok_if_tests_disabled=False,
no_auto_log=False, no_auto_log=False,
hidden=False,
): ):
self.name = name self.name = name
self.subcommand = subcommand self.subcommand = subcommand
@@ -70,6 +73,7 @@ class _MachCommand:
self.argument_group_names = [] self.argument_group_names = []
self.virtualenv_name = virtualenv_name self.virtualenv_name = virtualenv_name
self.order = order self.order = order
self.hidden = hidden
if ok_if_tests_disabled and category != "testing": if ok_if_tests_disabled and category != "testing":
raise ValueError( raise ValueError(
"ok_if_tests_disabled should only be set for " "`testing` mach commands" "ok_if_tests_disabled should only be set for " "`testing` mach commands"

View File

@@ -259,6 +259,9 @@ class CommandAction(argparse.Action):
for command in sorted(r.commands_by_category[category]): for command in sorted(r.commands_by_category[category]):
handler = r.command_handlers[command] handler = r.command_handlers[command]
if handler.hidden:
continue
# Instantiate a handler class to see if it should be filtered # Instantiate a handler class to see if it should be filtered
# out for the current context or not. Condition functions can be # out for the current context or not. Condition functions can be
# applied to the command's decorator. # applied to the command's decorator.

View File

@@ -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

View File

@@ -6,6 +6,8 @@ subsuite = "mach"
["test_conditions.py"] ["test_conditions.py"]
skip-if = ["true"] skip-if = ["true"]
["test_definitions.py"]
["test_config.py"] ["test_config.py"]
["test_decorators.py"] ["test_decorators.py"]

View File

@@ -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()

View File

@@ -110,244 +110,26 @@ def busted_file(command_context, against):
webbrowser.open_new_tab(uri) webbrowser.open_new_tab(uri)
MACH_PASTEBIN_DURATIONS = { def pastebin_create_parser():
"onetime": "onetime", # Accept all args so they can be promptly ignored.
"hour": "3600", parser = argparse.ArgumentParser()
"day": "86400", parser.add_argument("argv", nargs=argparse.REMAINDER, help=argparse.SUPPRESS)
"week": "604800", return parser
"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/"
@Command( @Command(
"pastebin", "pastebin",
category="misc", category="misc",
description="Command line interface to paste.mozilla.org.", hidden=True,
parser=pastebin_create_parser,
) )
@CommandArgument( def pastebin(command_context, argv):
"--list-highlighters", """Obsolete command line interface to `paste.mozilla.org`."""
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`.
Takes either a filename whose content should be pasted, or reads print(
content from standard input. If a highlighter is specified it will "pastebin.mozilla.org has been decommissioned.\n"
be used, otherwise the file name will be used to determine an "Please use your favorite search engine to find alternatives."
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)
return 1 return 1