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:
@@ -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"
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
20
python/mach/mach/test/providers/definitions.py
Normal file
20
python/mach/mach/test/providers/definitions.py
Normal 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
|
||||||
@@ -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"]
|
||||||
|
|||||||
28
python/mach/mach/test/test_definitions.py
Normal file
28
python/mach/mach/test/test_definitions.py
Normal 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()
|
||||||
@@ -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
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user