Skip to content
Open
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
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ options:
-p PLATFORM, --platform PLATFORM
Override the operating system [android, freebsd, linux, netbsd, openbsd, osx, sunos, windows, common]
-l, --list List all available commands for operating system
--verbose, --debug Show detailed troubleshooting output on stderr
-s SOURCE, --source SOURCE
Override the default page source
-c, --color Override color stripping
Expand Down Expand Up @@ -100,6 +101,13 @@ export TLDR_OPTIONS=short
export TLDR_PLATFORM=linux
```

### Troubleshooting

Use `--verbose` or `--debug` to print detailed troubleshooting information to stderr. This can help diagnose cache, source, platform, language, and network fetch issues.

```bash
tldr --verbose tar

### Platform

Determines the platform that tldr will use based on the custom `TLDR_PLATFORM` environment variable or automatically via system platform detection.
Expand Down
20 changes: 20 additions & 0 deletions tests/test_tldr.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,3 +156,23 @@ def test_get_commands(monkeypatch, tmp_path):
result = tldr.get_commands(platforms=["linux"], language=["zh_CN"])

assert "lspci" in result

def test_debug_respects_verbose_flag(capsys, monkeypatch):
monkeypatch.setattr(tldr, "VERBOSE", False)
tldr.debug("hidden")
assert capsys.readouterr().err == ""

monkeypatch.setattr(tldr, "VERBOSE", True)
tldr.debug("visible")
assert capsys.readouterr().err == "[tldr-debug] visible\n"


def test_verbose_flag_outputs_debug_info(monkeypatch, capsys):
monkeypatch.setattr(tldr, "VERBOSE", False)

with mock.patch("sys.argv", ["tldr", "--verbose", "--list"]):
tldr.main()

captured = capsys.readouterr()
assert "[tldr-debug] Verbose output enabled" in captured.err
assert "[tldr-debug] cache_dir=" in captured.err
79 changes: 76 additions & 3 deletions tldr.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,13 @@
__version__ = "3.4.4"
__client_specification__ = "2.3"

VERBOSE = int(os.environ.get('TLDR_VERBOSE', '0')) > 0


def debug(message: str) -> None:
if VERBOSE:
print(f"[tldr-debug] {message}", file=sys.stderr)

REQUEST_HEADERS = {'User-Agent': 'tldr-python-client'}
PAGES_SOURCE_LOCATION = os.environ.get(
'TLDR_PAGES_SOURCE_LOCATION',
Expand Down Expand Up @@ -173,35 +180,76 @@ def get_page_for_platform(
only_use_cache: bool = False,
system_cache: bool = False
) -> str:
debug(
f"Trying command='{command}' platform='{platform}' language='{language}' "
f"only_use_cache={only_use_cache} system_cache={system_cache}"
)

data_downloaded = False

if USE_CACHE and system_cache and get_cache_file_path(command, platform, language, system_cache).is_file():
debug(
f"Loading page from system cache: "
f"{get_cache_file_path(command, platform, language, system_cache)}"
)
data = load_page_from_cache(command, platform, language, system_cache)

elif USE_CACHE and have_recent_cache(command, platform, language):
debug(
f"Loading page from cache: "
f"{get_cache_file_path(command, platform, language)}"
)
data = load_page_from_cache(command, platform, language)

elif only_use_cache:
debug(
f"Cache not found for command='{command}' "
f"platform='{platform}' language='{language}' system_cache={system_cache}"
)
raise CacheNotExist("Cache for {} in {} not Found".format(
command,
platform,
))

else:
page_url = get_page_url(command, platform, remote, language)
debug(f"Fetching page from URL: {page_url}")

try:
data = urlopen(
Request(page_url, headers=REQUEST_HEADERS),
timeout=10,
context=URLOPEN_CONTEXT
).read()
data_downloaded = True
except Exception:

except Exception as err:
debug(f"Fetch failed for {page_url}: {type(err).__name__}: {err}")

if not USE_CACHE:
raise

debug(
f"Falling back to cache: "
f"{get_cache_file_path(command, platform, language)}"
)
data = load_page_from_cache(command, platform, language)

if data is None:
debug(
f"Fallback cache not found for command='{command}' "
f"platform='{platform}' language='{language}'"
)
raise

if data_downloaded and USE_CACHE:
debug(
f"Storing downloaded page to cache: "
f"{get_cache_file_path(command, platform, language)}"
)
store_page_to_cache(data, command, platform, language)
return data.splitlines()

return data.splitlines()

def update_page_for_platform(
command: str,
Expand Down Expand Up @@ -273,6 +321,9 @@ def get_page_for_every_platform(
platforms = platforms + ['common']
if languages is None:
languages = get_language_list()

debug(f"Searching command='{command}' platforms={platforms} languages={languages}")

# only use cache
if USE_CACHE:
result = list()
Expand Down Expand Up @@ -588,7 +639,11 @@ def update_cache(language: Optional[List[str]] = None) -> None:
"Updated cache for language "
f"{language}: {cached} entries"
)
except Exception:
except Exception as err:
debug(
f"Failed to update cache for language '{language}' "
f"from {cache_location}: {type(err).__name__}: {err}"
)
print(
"Error: Unable to update cache for language "
f"{language} from {cache_location}"
Expand Down Expand Up @@ -626,6 +681,13 @@ def create_parser() -> ArgumentParser:
__client_specification__
)
)

parser.add_argument(
'--verbose', '--debug',
default=False,
action='store_true',
help='Show detailed troubleshooting output on stderr'
)

parser.add_argument("--search",
metavar='"KEYWORDS"',
Expand Down Expand Up @@ -717,6 +779,17 @@ def main() -> None:

options = parser.parse_args()

global VERBOSE
VERBOSE = options.verbose or VERBOSE

if VERBOSE:
debug("Verbose output enabled")
debug(f"cache_enabled={USE_CACHE}, network_enabled={USE_NETWORK}, max_cache_age={MAX_CACHE_AGE}")
debug(f"cache_dir={get_cache_dir()}")
debug(f"source={options.source}")
debug(f"platform_option={options.platform}")
debug(f"language_option={options.language}")

if sys.platform == "win32":
import colorama
colorama.init(strip=options.color)
Expand Down