pax_global_header00006660000000000000000000000064131242055110014504gustar00rootroot0000000000000052 comment=1235ad1d7cc2bd2aa16feab536d0004ec0dd478a tldr.py-0.7.0/000077500000000000000000000000001312420551100131045ustar00rootroot00000000000000tldr.py-0.7.0/.gitignore000066400000000000000000000016351312420551100151010ustar00rootroot00000000000000# User specified #################### # virtualenv folder venv/ venv33/ # pycharm .idea/ # temp folder temp/ # database *.db # Belows are from https://github.com/github/gitignore/blob/master/Python.gitignore #################### # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] # C extensions *.so # Distribution / packaging .Python env/ build/ develop-eggs/ dist/ downloads/ eggs/ lib/ lib64/ parts/ sdist/ var/ *.egg-info/ .installed.cfg *.egg # PyInstaller # Usually these files are written by a python script from a template # before PyInstaller builds the exe, so as to inject date/other infos into it. *.manifest *.spec # Installer logs pip-log.txt pip-delete-this-directory.txt # Unit test / coverage reports htmlcov/ .tox/ .coverage .cache nosetests.xml coverage.xml # Translations *.mo *.pot # Django stuff: *.log # Sphinx documentation docs/_build/ docs/_static/ # PyBuilder target/ tldr.py-0.7.0/.travis.yml000066400000000000000000000004051312420551100152140ustar00rootroot00000000000000language: python python: - "2.7" - "3.3" - "3.4" - "3.5" install: - pip install codecov - pip install -r dev-requirements.txt - pip install -e . script: - make test after_success: - codecov notifications: email: false tldr.py-0.7.0/ChangeLog.md000066400000000000000000000011671312420551100152620ustar00rootroot000000000000002017.06.26 v0.7.0 - support the new syntax, #22 2017.05.07 v0.6.0 - support search commands in other platforms, #20 2016.01.14 v0.5.0 - support locate the command page, #11 2016.01.12 v0.4.0 - support custom the configuration file via `TLDR_CONFIG_DIR`, #9 2016.01.05 v0.3.0 - support rebuild the index(#8), and rebuild the index after updating - improve tests, #12 2015.10.21 v0.2.0 - python3.x support - add tests and code coverage - return parsed lines instead of print them directly - improve error output when detect unsupported color 2015.09.22 v0.1.1 - fix the update command 2015.09.10 v0.1.0 - first public release tldr.py-0.7.0/LICENSE000066400000000000000000000020611312420551100141100ustar00rootroot00000000000000The MIT License (MIT) Copyright (c) 2015 lord63 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. tldr.py-0.7.0/MANIFEST.in000066400000000000000000000000411312420551100146350ustar00rootroot00000000000000include README.md include LICENSEtldr.py-0.7.0/Makefile000066400000000000000000000003201312420551100145370ustar00rootroot00000000000000test: @echo "Run the real tests."; @py.test --cov-report term-missing --cov=tldr/ --flake8 -vs tests/ tldr/; create: @python setup.py sdist bdist_wheel upload: @python setup.py sdist bdist_wheel upload tldr.py-0.7.0/README.rst000066400000000000000000000120741312420551100145770ustar00rootroot00000000000000tldr.py ======= |Latest Version| |Build Status| |Coverage Status| |Python Versions| Yet another python client for `tldr `__. Intro ----- tldr.py is a python client for `tldr `__: simplified and community-driven man pages. Instead of the long man pages: .. figure:: https://cloud.githubusercontent.com/assets/5268051/10731428/5b5fd2fc-7c30-11e5-8cb1-4a3a24218ede.jpeg :alt: tar-man-page tldr will give you several simple yet powerful examples: .. figure:: https://cloud.githubusercontent.com/assets/5268051/10731475/95df13fc-7c30-11e5-97d8-8090b6146208.jpeg :alt: tar-tldr-page The command examples are not good? Don't worry, you can set up your own 'tldr'! They are just markdown files and you can modify them at your ease. Don't forget to Share them with the community! One more thing, tldr is just a simple version for the man page, it's **NOT** an alternative. Sometimes, you should read the man pages patiently ;) Features highlight ------------------ - use local file, fast. - support custom the output color. - support fetch the latest tldr pages. - support rebuild the index. Install ------- :: $ (sudo) pip install tldr.py Usage ----- Initialize ~~~~~~~~~~ - firstly, clone the tldr repo to somewhere(e.g. ~/code/tldr). We will use it when we look for a command usage. :: $ cd ~/code $ git clone git@github.com:tldr-pages/tldr.git - then, init the configuration file, the default location for the configuration file is your home directory, you can use the ``TLDR_CONFIG_DIR`` environment variable to point it to another folder(e.g. $HOME/.config) :: $ tldr init Input the tldr repo path(absolute path): (e.g. /home/lord63/code/tldr/) Input your platform(linux, osx or sunos): (e.g. linux) Initializing the config file at ~/.tldrrc and you configuration file should look like this: :: colors: command: cyan description: blue usage: green platform: linux repo_directory: /home/lord63/code/tldr Don't worry about the ``colors`` option, it is for the output when you look for a command, you can custom it by yourself.(Note that the color should be in ['black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white']) - finally, build the index. Tldr.py will find the command via the index.json. After a new fresh clone or when you add some new pages, remember to rebuild the index. :: $ tldr reindex Rebuild the index. Use tldr ~~~~~~~~ look for a command usage: :: $ tldr find {{command}} check for updates(so that we can get the latest man pages): :: $ tldr update rebuild the index.json after you add some new pages: :: $ tldr reindex locate the command man page: :: $ tldr locate {{command}} Or you can use ``tldr --help`` to get the help message. FAQ --- Q: I want to add some custom command usages to a command, how to do it? A: Find the location of the command page; add the command usages; done. Q: I want to add some custom command pages, how? A: Add the comand pages to the right folder(e.g. /tldrrepo/pages/linux); rebuild the index; done. Q: I don't like the default color theme, how to change it? A: Edit the tldr configuration file at ``~/.tldrrc``; modify the color until you're happy with it. Q: I faided to update the tldr pages, why? A: Actually, ``tldr.py`` just tries to pull the latest tldr pages for you, no magic behinds it. So the reason why you faided to update is that ``tldr.py`` failed to pull the latest upstream, check the failing output and you may know the reason, e.g. you make some changes and haven't commit them yet. You can pull the pages by hand so you can have a better control on it. Q: Why use the git repo instead of the assets packaged by the official? A: In fact, you can use the offical assets if you want, download the assets and extract it somewhere, but ``tldr.py`` don't support update it using ``tldr update``. Use a git repo, you can: - do the version control, yeah, use git. - better for customization, just edit the pages and add new pages, they belongs to you. You can even maintain your own 'tldr'. If use the official assets, you'll always get the latest pages. Contributing ------------ - It sucks? Why not help me improve it? Let me know the bad things. - Want a new feature? Feel free to file an issue for a feature request. - Find a bug? Open an issue please, or it's better if you can send me a pull request. Contributions are always welcome at any time! :sparkles: :cake: :sparkles: License ------- MIT. .. |Latest Version| image:: http://img.shields.io/pypi/v/tldr.py.svg :target: https://pypi.python.org/pypi/tldr.py .. |Build Status| image:: https://travis-ci.org/lord63/tldr.py.svg :target: https://travis-ci.org/lord63/tldr.py .. |Coverage Status| image:: https://codecov.io/github/lord63/tldr.py/coverage.svg?branch=master :target: https://codecov.io/github/lord63/tldr.py?branch=master .. |Python Versions| image:: https://img.shields.io/pypi/pyversions/tldr.py.svg tldr.py-0.7.0/dev-requirements.txt000066400000000000000000000001061312420551100171410ustar00rootroot00000000000000click PyYaml pytest >= 2.8 pytest-flake8 pytest-cov mock >= 1.3.0 tox tldr.py-0.7.0/setup.cfg000066400000000000000000000000341312420551100147220ustar00rootroot00000000000000[bdist_wheel] universal = 1 tldr.py-0.7.0/setup.py000066400000000000000000000022751312420551100146240ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- from setuptools import setup import tldr with open('README.rst') as f: long_description = f.read() setup( name='tldr.py', version=tldr.__version__, description='A python client for tldr: simplified and community-driven man pages.', long_description=long_description, url='https://github.com/lord63/tldr.py', author='lord63', author_email='lord63.j@gmail.com', license='MIT', classifiers=[ 'Development Status :: 4 - Beta', 'Operating System :: POSIX', 'Operating System :: POSIX :: Linux', 'License :: OSI Approved :: MIT License', 'Programming Language :: Python :: 2', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.3', 'Programming Language :: Python :: 3.4', 'Programming Language :: Python :: 3.5', ], keywords='tldr cli man command usage', packages=['tldr'], install_requires=[ 'click>=5.0', 'PyYAML>=3.11', ], include_package_data=True, entry_points={ 'console_scripts':[ 'tldr=tldr.cli:cli'] } ) tldr.py-0.7.0/tests/000077500000000000000000000000001312420551100142465ustar00rootroot00000000000000tldr.py-0.7.0/tests/basic.py000066400000000000000000000032411312420551100157010ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- from __future__ import absolute_import import os from os import path import unittest from click.testing import CliRunner from tldr import cli import mock ROOT = path.dirname(path.realpath(__file__)) class BasicTestCase(unittest.TestCase): def setUp(self): self.repo_dir = path.join(ROOT, 'mock_tldr') self.config_path = path.join(self.repo_dir, '.tldrrc') os.environ['TLDR_CONFIG_DIR'] = self.repo_dir self.runner = CliRunner() self.call_init_command() def tearDown(self): if path.exists(self.config_path): os.remove(self.config_path) def call_init_command(self, repo_dir=path.join(ROOT, 'mock_tldr'), platform='linux'): with mock.patch('click.prompt', side_effect=[repo_dir, platform]): result = self.runner.invoke(cli.init) return result def call_update_command(self): with mock.patch('tldr.cli.build_index', return_value=None): result = self.runner.invoke(cli.update) return result def call_find_command(self, command_name, platform): command_args = ( [command_name, '--on', platform] if platform else [command_name]) result = self.runner.invoke(cli.find, command_args) return result def call_reindex_command(self): result = self.runner.invoke(cli.reindex) return result def call_locate_command(self, command_name, platform): command_args = ( [command_name, '--on', platform] if platform else [command_name]) result = self.runner.invoke(cli.locate, command_args) return result tldr.py-0.7.0/tests/mock_tldr/000077500000000000000000000000001312420551100162245ustar00rootroot00000000000000tldr.py-0.7.0/tests/mock_tldr/pages/000077500000000000000000000000001312420551100173235ustar00rootroot00000000000000tldr.py-0.7.0/tests/mock_tldr/pages/common/000077500000000000000000000000001312420551100206135ustar00rootroot00000000000000tldr.py-0.7.0/tests/mock_tldr/pages/common/tldr.md000066400000000000000000000001701312420551100221000ustar00rootroot00000000000000# tldr > Simplified man pages - get typical usages of a command (hint: this is how you got here!) `tldr {{command}}` tldr.py-0.7.0/tests/mock_tldr/pages/index.json000066400000000000000000000165211312420551100213320ustar00rootroot00000000000000{"commands":[{"name":"ab","platform":["common"]},{"name":"ack","platform":["common"]},{"name":"ag","platform":["common"]},{"name":"airport","platform":["osx"]},{"name":"alias","platform":["common"]},{"name":"apropos","platform":["common"]},{"name":"apt-get","platform":["linux"]},{"name":"aptitude","platform":["linux"]},{"name":"ar","platform":["common"]},{"name":"awk","platform":["common"]},{"name":"base64","platform":["linux"]},{"name":"brew","platform":["osx"]},{"name":"bundle","platform":["common"]},{"name":"caffeinate","platform":["osx"]},{"name":"cal","platform":["common"]},{"name":"cat","platform":["common"]},{"name":"cd","platform":["common"]},{"name":"chmod","platform":["common"]},{"name":"chown","platform":["common"]},{"name":"chsh","platform":["common"]},{"name":"cksum","platform":["common"]},{"name":"convert","platform":["common"]},{"name":"cp","platform":["common"]},{"name":"curl","platform":["common"]},{"name":"cut","platform":["common"]},{"name":"date","platform":["common"]},{"name":"deluser","platform":["common"]},{"name":"df","platform":["common"]},{"name":"diff","platform":["common"]},{"name":"dig","platform":["common"]},{"name":"diskutil","platform":["osx"]},{"name":"dpkg","platform":["linux"]},{"name":"drush","platform":["common"]},{"name":"drutil","platform":["osx"]},{"name":"du","platform":["linux","osx"]},{"name":"echo","platform":["common"]},{"name":"electrum","platform":["common"]},{"name":"emerge","platform":["linux"]},{"name":"env","platform":["common"]},{"name":"exiftool","platform":["common"]},{"name":"fdupes","platform":["common"]},{"name":"ffmpeg","platform":["common"]},{"name":"find","platform":["common"]},{"name":"findmnt","platform":["linux"]},{"name":"firewall-cmd","platform":["linux"]},{"name":"free","platform":["linux"]},{"name":"fswebcam","platform":["common"]},{"name":"gcc","platform":["common"]},{"name":"gem","platform":["common"]},{"name":"gifsicle","platform":["common"]},{"name":"git","platform":["common"]},{"name":"git-add","platform":["common"]},{"name":"git-branch","platform":["common"]},{"name":"git-checkout","platform":["common"]},{"name":"git-clone","platform":["common"]},{"name":"git-commit","platform":["common"]},{"name":"git-diff","platform":["common"]},{"name":"git-init","platform":["common"]},{"name":"git-log","platform":["common"]},{"name":"git-merge","platform":["common"]},{"name":"git-push","platform":["common"]},{"name":"git-remote","platform":["common"]},{"name":"git-stash","platform":["common"]},{"name":"git-status","platform":["common"]},{"name":"gpg","platform":["common"]},{"name":"grep","platform":["common"]},{"name":"gzip","platform":["common"]},{"name":"handbrakecli","platform":["common"]},{"name":"haxelib","platform":["common"]},{"name":"head","platform":["linux","osx"]},{"name":"iconv","platform":["common"]},{"name":"iostat","platform":["linux"]},{"name":"ip","platform":["linux"]},{"name":"ipcs","platform":["common"]},{"name":"journalctl","platform":["linux"]},{"name":"kill","platform":["common"]},{"name":"less","platform":["common"]},{"name":"ln","platform":["common"]},{"name":"locate","platform":["linux","osx"]},{"name":"ls","platform":["common"]},{"name":"lsof","platform":["common"]},{"name":"man","platform":["common"]},{"name":"md5","platform":["osx"]},{"name":"md5sum","platform":["linux"]},{"name":"mdadm","platform":["linux"]},{"name":"mkdir","platform":["common"]},{"name":"more","platform":["common"]},{"name":"mount","platform":["common"]},{"name":"mp4box","platform":["common"]},{"name":"mtr","platform":["common"]},{"name":"mv","platform":["common"]},{"name":"mysql","platform":["common"]},{"name":"mysqldump","platform":["common"]},{"name":"nc","platform":["common"]},{"name":"netstat","platform":["linux"]},{"name":"networksetup","platform":["osx"]},{"name":"nmap","platform":["common"]},{"name":"node","platform":["common"]},{"name":"nohup","platform":["common"]},{"name":"npm","platform":["common"]},{"name":"open","platform":["osx"]},{"name":"pacman","platform":["linux"]},{"name":"passwd","platform":["common"]},{"name":"patch","platform":["common"]},{"name":"pbcopy","platform":["osx"]},{"name":"pbpaste","platform":["osx"]},{"name":"pgrep","platform":["common"]},{"name":"php","platform":["common"]},{"name":"ping","platform":["common"]},{"name":"pip","platform":["common"]},{"name":"play","platform":["common"]},{"name":"prctl","platform":["sunos"]},{"name":"prstat","platform":["sunos"]},{"name":"ps","platform":["common"]},{"name":"psql","platform":["common"]},{"name":"pushd","platform":["common"]},{"name":"pwd","platform":["common"]},{"name":"qlmanage","platform":["osx"]},{"name":"redis-cli","platform":["common"]},{"name":"rename","platform":["common"]},{"name":"rm","platform":["common"]},{"name":"rmdir","platform":["common"]},{"name":"route","platform":["osx"]},{"name":"rsync","platform":["common"]},{"name":"salt","platform":["common"]},{"name":"salt-call","platform":["common"]},{"name":"salt-key","platform":["common"]},{"name":"salt-run","platform":["common"]},{"name":"say","platform":["osx"]},{"name":"scp","platform":["common"]},{"name":"screen","platform":["common"]},{"name":"sed","platform":["common"]},{"name":"sha1sum","platform":["linux"]},{"name":"sha224sum","platform":["linux"]},{"name":"sha256sum","platform":["linux"]},{"name":"sha384sum","platform":["linux"]},{"name":"sha512sum","platform":["linux"]},{"name":"shuf","platform":["linux"]},{"name":"shutdown","platform":["linux","osx"]},{"name":"sort","platform":["common"]},{"name":"sox","platform":["common"]},{"name":"split","platform":["common"]},{"name":"srm","platform":["common"]},{"name":"ss","platform":["linux"]},{"name":"ssh","platform":["common"]},{"name":"sshfs","platform":["common"]},{"name":"strace","platform":["linux"]},{"name":"sudo","platform":["common"]},{"name":"svcadm","platform":["sunos"]},{"name":"svccfg","platform":["sunos"]},{"name":"svcs","platform":["sunos"]},{"name":"svn","platform":["common"]},{"name":"sw_vers","platform":["osx"]},{"name":"sysctl","platform":["osx"]},{"name":"system_profiler","platform":["osx"]},{"name":"systemctl","platform":["linux"]},{"name":"systemsetup","platform":["osx"]},{"name":"tail","platform":["common"]},{"name":"tar","platform":["common"]},{"name":"tcpdump","platform":["common"]},{"name":"tcpflow","platform":["linux"]},{"name":"tee","platform":["common"]},{"name":"telnet","platform":["common"]},{"name":"time","platform":["common"]},{"name":"tldr","platform":["common"]},{"name":"tmux","platform":["common"]},{"name":"touch","platform":["common"]},{"name":"tr","platform":["common"]},{"name":"traceroute","platform":["common"]},{"name":"tree","platform":["common"]},{"name":"umount","platform":["common"]},{"name":"uname","platform":["common"]},{"name":"unzip","platform":["common"]},{"name":"useradd","platform":["common"]},{"name":"userdel","platform":["common"]},{"name":"usermod","platform":["common"]},{"name":"wacaw","platform":["osx"]},{"name":"wall","platform":["linux"]},{"name":"watch","platform":["linux"]},{"name":"wc","platform":["common"]},{"name":"wget","platform":["common"]},{"name":"which","platform":["common"]},{"name":"wpa_cli","platform":["linux"]},{"name":"xargs","platform":["linux"]},{"name":"xctool","platform":["osx"]},{"name":"xed","platform":["osx"]},{"name":"xsltproc","platform":["osx"]},{"name":"yes","platform":["common"]},{"name":"zbarimg","platform":["common"]},{"name":"zfs","platform":["common"]},{"name":"zip","platform":["common"]},{"name":"zpool","platform":["common"]}]}tldr.py-0.7.0/tests/mock_tldr/pages/linux/000077500000000000000000000000001312420551100204625ustar00rootroot00000000000000tldr.py-0.7.0/tests/mock_tldr/pages/linux/du.md000066400000000000000000000006451312420551100214210ustar00rootroot00000000000000# du > Estimate file space usage - get a sum of the total size of a file/folder in human readable units `du -sh {{file/directory}}` - list file sizes of a directory and any subdirectories in KB `du -k {{file/directory}}` - get recursively, individual file/folder sizes in human readable form `du -ah {{directory}}` - list the KB sizes of directories for N levels below the specified directory `du --max-depth=N` tldr.py-0.7.0/tests/mock_tldr/pages/linux/tcpflow.md000066400000000000000000000002231312420551100224570ustar00rootroot00000000000000# tcpflow > Capture TCP traffic for debugging and analysis - Show all data on the given interface and port `tcpflow -c -i {{eth0}} port {{80}}` tldr.py-0.7.0/tests/mock_tldr/pages/osx/000077500000000000000000000000001312420551100201345ustar00rootroot00000000000000tldr.py-0.7.0/tests/mock_tldr/pages/osx/airport.md000066400000000000000000000004471312420551100221430ustar00rootroot00000000000000# airport > Wireless network configuration utility. - Show current wireless status information: `airport -I` - Sniff wireless traffic on channel 1: `airport sniff {{1}}` - Scan for available wireless networks: `airport -s` - Disassociate from current airport network: `sudo airport -z` tldr.py-0.7.0/tests/mock_tldr/pages/osx/du.md000066400000000000000000000006611312420551100210710ustar00rootroot00000000000000# du > Estimate file space usage - get a sum of the total size of a file/folder in human readable units `du -sh {{file/directory}}` - list file sizes of a directory and any subdirectories in KB `du -k {{file/directory}}` - get recursively, individual file/folder sizes in human readable form `du -ah {{directory}}` - list the KB sizes of directories for N levels below the specified directory `du -k -depth=1 {{directory}}` tldr.py-0.7.0/tests/test_config.py000066400000000000000000000033411312420551100171250ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- from __future__ import absolute_import import mock from tldr.config import get_config from basic import BasicTestCase class TestConfig(BasicTestCase): def test_config_not_exist(self): with mock.patch('os.path.exists', side_effect=[False, True]): self._assert_exception_message( ("Can't find config file at: {0}. You may use `tldr init` to " "init the config file.").format(self.config_path) ) def test_invalid_yaml_file(self): with mock.patch('io.open', mock.mock_open(read_data="%YAML:1.0\nname:jhon")): self._assert_exception_message( "The config file is not a valid YAML file." ) def test_unsupported_color_in_config(self): mock_config = { 'colors': { 'command': 'indigo', 'description': 'cyan', 'usage': 'green' }, 'platform': 'linux', 'repo_directory': self.repo_dir } with mock.patch('yaml.safe_load', return_value=mock_config): self._assert_exception_message( "Unsupported colors in config file: indigo." ) def test_repo_directory_not_exist(self): with mock.patch('os.path.exists', side_effect=[True, False]): self._assert_exception_message( "Can't find the tldr repo, check the `repo_directory` " "setting in config file." ) def _assert_exception_message(self, expected_message): with self.assertRaises(SystemExit) as error: get_config() assert error.exception.args[0] == expected_message tldr.py-0.7.0/tests/test_find.py000066400000000000000000000041771312420551100166100ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- from __future__ import absolute_import from basic import BasicTestCase class TestFind(BasicTestCase): def test_find_tldr_in_common(self): self._assert_command_output( 'tldr', ('\n Simplified man pages\n\n- get typical usages of a command ' '(hint: this is how you got here!)\n\n tldr {{command}}\n\n') ) def test_find_tcpflow_in_linux(self): self._assert_command_output( 'tcpflow', ('\n Capture TCP traffic for debugging and analysis\n\n' '- Show all data on the given interface and port\n\n' ' tcpflow -c -i {{eth0}} port {{80}}\n\n') ) def test_find_airport_on_maxos(self): self._assert_command_output( 'airport', ('\n Wireless network configuration utility.\n\n' '- Show current wireless status information:\n\n' ' airport -I\n\n' '- Sniff wireless traffic on channel 1:\n\n' ' airport sniff {{1}}\n\n' '- Scan for available wireless networks:\n\n' ' airport -s\n\n' '- Disassociate from current airport network:\n\n' ' sudo airport -z\n\n'), 'osx' ) def test_can_not_find_something(self): self._assert_command_output( 'yoooooooooooooo', ("Sorry, we don't support command: yoooooooooooooo right now.\n" "You can file an issue or send a PR on github:\n" " https://github.com/tldr-pages/tldr\n") ) def test_find_command_do_not_support_your_platform(self): self._assert_command_output( 'airport', ('Sorry, command airport is not supported on your platform.\n' 'You can file an issue or send a PR on github:\n' ' https://github.com/tldr-pages/tldr\n') ) def _assert_command_output(self, command_name, expected_output, platform=''): result = self.call_find_command(command_name, platform) assert result.output == expected_output tldr.py-0.7.0/tests/test_init.py000066400000000000000000000025371312420551100166310ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- from __future__ import absolute_import import io import os from os import path import yaml from basic import BasicTestCase class TestInit(BasicTestCase): def test_init(self): assert path.exists(self.config_path) expected_config = { 'colors': { 'command': 'cyan', 'description': 'blue', 'usage': 'green' }, 'platform': 'linux', 'repo_directory': self.repo_dir } with io.open(self.config_path, encoding='utf-8') as f: config = yaml.safe_load(f) assert expected_config == config def test_wrong_platform_input(self): result = self.call_init_command() assert result.output == ( "There is already a config file exists, skip initializing it.\n" ) def test_bad_repo_location(self): os.remove(self.config_path) result = self.call_init_command(repo_dir='/notexist') assert result.exception.args[0] == ( "Repo path not exist, clone it first." ) def test_back_platform_input(self): os.remove(self.config_path) result = self.call_init_command(platform='myos') assert result.exception.args[0] == ( "Platform should be in linux, osx or sunos." ) tldr.py-0.7.0/tests/test_locate.py000066400000000000000000000005521312420551100171300ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- from __future__ import absolute_import from os import path from basic import BasicTestCase class TestLocate(BasicTestCase): def test_common_command(self): assert (self.call_locate_command('tldr', platform='').output.strip() == path.join(self.repo_dir, 'pages', 'common', 'tldr.md')) tldr.py-0.7.0/tests/test_parse.py000066400000000000000000000035101312420551100167700ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- from __future__ import absolute_import import unittest import mock from tldr.parser import parse_page class TestParse(unittest.TestCase): def test_parse_page(self): mock_page = ( '#node\n\n' '> Main node command\n\n' '- Call an interactive node shell\n\n' '`node`\n\n' '- Execute node on a JS file\n\n' '`node {{FILENAME}}.js`\n\n' ) self._assert_mock_read(mock_page) def test_parse_new_syntax_page(self): mock_page = ( 'node\n' '====\n\n' '> Main node command\n\n' 'Call an interactive node shell\n\n' ' node\n\n' 'Execute node on a JS file\n\n' ' node {{FILENAME}}.js\n\n' ) self._assert_mock_read(mock_page) def _assert_mock_read(self, page_content): mock_config = { 'colors': { 'command': 'cyan', 'description': 'blue', 'usage': 'green' }, 'platform': 'linux', 'repo_directory': '/tmp/tldr' } expected_result = ( '\n' '\x1b[0m\x1b[34m Main node command\n' '\x1b[0m\n\x1b[0m\x1b[32m- Call an interactive node shell' '\n\x1b[0m\n\x1b[0m\x1b[36m node\n' '\x1b[0m\n\x1b[0m\x1b[32m- Execute node on a JS file\n' '\x1b[0m\n\x1b[0m\x1b[36m node {{FILENAME}}.js\n' '\x1b[0m\n\x1b[0m' ) with mock.patch('tldr.parser.get_config', return_value=mock_config): with mock.patch('io.open', mock.mock_open(read_data=page_content)): result = parse_page('/repo_directory/pages/common/node.md') assert ''.join(result) == expected_result tldr.py-0.7.0/tests/test_reindex.py000066400000000000000000000025321312420551100173170ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- from __future__ import absolute_import import os from os import path import shutil from basic import BasicTestCase class TestReindex(BasicTestCase): def setUp(self): super(TestReindex, self).setUp() # Add a new page. self.page_path = path.join(self.repo_dir, 'pages') self.new_page = path.join(self.page_path, 'linux', 'blabla.md') shutil.copy(path.join(self.page_path, 'linux', 'tcpflow.md'), self.new_page) # Backup the index.json. shutil.copy(path.join(self.page_path, 'index.json'), path.join(self.page_path, 'index_bak.json')) def tearDown(self): super(TestReindex, self).tearDown() if path.exists(self.new_page): os.remove(self.new_page) # Restore the index.json. if path.exists(path.join(self.page_path, 'index_bak.json')): shutil.move(path.join(self.page_path, 'index_bak.json'), path.join(self.page_path, 'index.json')) def test_reindex(self): before_reindex = self.call_find_command('blabla', platform='') assert 'Sorry' in before_reindex.output self.call_reindex_command() after_reindex = self.call_find_command('blabla', platform='') assert 'tcpflow' in after_reindex.output tldr.py-0.7.0/tests/test_update.py000066400000000000000000000017521312420551100171460ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- from __future__ import absolute_import import mock from basic import BasicTestCase class TestUpdate(BasicTestCase): def test_update_available(self): mock_different_sha1 = [ '8f82e7445fef6cc83c2e02b82df5f92fe0a909c6', 'a4013ab1b14812624bbddf96feb1bfa2b03564f6' ] self._assert_update_info(mock_different_sha1, 'Updating...') def test_no_need_for_update(self): mock_same_sha1 = [ '8f82e7445fef6cc83c2e02b82df5f92fe0a909c6', '8f82e7445fef6cc83c2e02b82df5f92fe0a909c6' ] self._assert_update_info(mock_same_sha1, 'No need for updates.') def _assert_update_info(self, mock_sha1, expected_message): with mock.patch('subprocess.check_output', side_effect=mock_sha1): with mock.patch('subprocess.check_call', side_effect=[0, 0]): result = self.call_update_command() assert expected_message in result.output tldr.py-0.7.0/tldr/000077500000000000000000000000001312420551100140515ustar00rootroot00000000000000tldr.py-0.7.0/tldr/__init__.py000066400000000000000000000006401312420551100161620ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- """ tldr.py ~~~~~~ A python client for tldr: simplified and community-driven man pages. :copyright: (c) 2015 by lord63. :license: MIT, see LICENSE for more details. """ __title__ = "tldr.py" __version__ = "0.7.0" __author__ = "lord63" __homepage__ = "https://github.com/lord63/tldr.py" __license__ = "MIT" __copyright__ = "Copyright 2015 lord63" tldr.py-0.7.0/tldr/cli.py000066400000000000000000000132401312420551100151720ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- from __future__ import absolute_import import io import json from operator import itemgetter import os from os import path import subprocess import sys import click import yaml from tldr import __version__ from tldr.config import get_config from tldr.parser import parse_page def parse_man_page(command, platform): """Parse the man page and return the parsed lines.""" page_path = find_page_location(command, platform) output_lines = parse_page(page_path) return output_lines def find_page_location(command, specified_platform): """Find the command man page in the pages directory.""" repo_directory = get_config()['repo_directory'] default_platform = get_config()['platform'] command_platform = ( specified_platform if specified_platform else default_platform) with io.open(path.join(repo_directory, 'pages/index.json'), encoding='utf-8') as f: index = json.load(f) command_list = [item['name'] for item in index['commands']] if command not in command_list: sys.exit( ("Sorry, we don't support command: {0} right now.\n" "You can file an issue or send a PR on github:\n" " https://github.com/tldr-pages/tldr").format(command)) supported_platforms = index['commands'][ command_list.index(command)]['platform'] if command_platform in supported_platforms: platform = command_platform elif 'common' in supported_platforms: platform = 'common' else: platform = '' if not platform: sys.exit( ("Sorry, command {0} is not supported on your platform.\n" "You can file an issue or send a PR on github:\n" " https://github.com/tldr-pages/tldr").format(command)) page_path = path.join(path.join(repo_directory, 'pages'), path.join(platform, command + '.md')) return page_path def build_index(): repo_directory = get_config()['repo_directory'] index_path = path.join(repo_directory, 'pages', 'index.json') page_path = path.join(repo_directory, 'pages') tree_generator = os.walk(page_path) folders = next(tree_generator)[1] commands, new_index = {}, {} for folder in folders: pages = next(tree_generator)[2] for page in pages: command_name = path.splitext(page)[0] if command_name not in commands: commands[command_name] = {'name': command_name, 'platform': [folder]} else: commands[command_name]['platform'].append(folder) command_list = [item[1] for item in sorted(commands.items(), key=itemgetter(0))] new_index['commands'] = command_list with open(index_path, mode='w') as f: json.dump(new_index, f) @click.group(context_settings={'help_option_names': ('-h', '--help')}) @click.version_option(__version__, '-V', '--version', message='%(version)s') def cli(): """A python client for tldr: simplified and community-driven man pages.""" pass # pragma: no cover @cli.command() @click.argument('command') @click.option('--on', type=click.Choice(['linux', 'osx', 'sunos']), help='the specified platform.') def find(command, on): """Find the command usage.""" output_lines = parse_man_page(command, on) click.echo(''.join(output_lines)) @cli.command() def update(): """Update to the latest pages.""" repo_directory = get_config()['repo_directory'] os.chdir(repo_directory) click.echo("Check for updates...") local = subprocess.check_output('git rev-parse master'.split()).strip() remote = subprocess.check_output( 'git ls-remote https://github.com/tldr-pages/tldr/ HEAD'.split() ).split()[0] if local != remote: click.echo("Updating...") subprocess.check_call('git checkout master'.split()) subprocess.check_call('git pull --rebase'.split()) build_index() click.echo("Update to the latest and rebuild the index.") else: click.echo("No need for updates.") @cli.command() def init(): """Init config file.""" default_config_path = path.join( (os.environ.get('TLDR_CONFIG_DIR') or path.expanduser('~')), '.tldrrc') if path.exists(default_config_path): click.echo("There is already a config file exists, " "skip initializing it.") else: repo_path = click.prompt("Input the tldr repo path(absolute path)") if not path.exists(repo_path): sys.exit("Repo path not exist, clone it first.") platform = click.prompt("Input your platform(linux, osx or sunos)") if platform not in ['linux', 'osx', 'sunos']: sys.exit("Platform should be in linux, osx or sunos.") colors = { "description": "blue", "usage": "green", "command": "cyan" } config = { "repo_directory": repo_path, "colors": colors, "platform": platform } with open(default_config_path, 'w') as f: f.write(yaml.safe_dump(config, default_flow_style=False)) click.echo("Initializing the config file at {0}".format( default_config_path)) @cli.command() def reindex(): """Rebuild the index.""" build_index() click.echo('Rebuild the index.') @cli.command() @click.argument('command') @click.option('--on', type=click.Choice(['linux', 'osx', 'sunos']), help='the specified platform.') def locate(command, on): """Locate the command's man page.""" location = find_page_location(command, on) click.echo(location) tldr.py-0.7.0/tldr/config.py000066400000000000000000000024001312420551100156640ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- from __future__ import absolute_import import io import os from os import path import sys import yaml def get_config(): """Get the configurations from .tldrrc and return it as a dict.""" config_path = path.join( (os.environ.get('TLDR_CONFIG_DIR') or path.expanduser('~')), '.tldrrc') if not path.exists(config_path): sys.exit("Can't find config file at: {0}. You may use `tldr init` " "to init the config file.".format(config_path)) with io.open(config_path, encoding='utf-8') as f: try: config = yaml.safe_load(f) except yaml.scanner.ScannerError: sys.exit("The config file is not a valid YAML file.") supported_colors = ['black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white'] if not set(config['colors'].values()).issubset(set(supported_colors)): sys.exit("Unsupported colors in config file: {0}.".format( ', '.join(set(config['colors'].values()) - set(supported_colors)))) if not path.exists(config['repo_directory']): sys.exit("Can't find the tldr repo, check the `repo_directory` " "setting in config file.") return config tldr.py-0.7.0/tldr/parser.py000066400000000000000000000026541312420551100157260ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- from __future__ import absolute_import import io import click from tldr.config import get_config def parse_page(page): """Parse the command man page.""" colors = get_config()['colors'] with io.open(page, encoding='utf-8') as f: lines = f.readlines() output_lines = [] for line in lines[1:]: if is_headline(line): continue elif is_description(line): output_lines.append(click.style(line.replace('>', ' '), fg=colors['description'])) elif is_old_usage(line): output_lines.append(click.style(line, fg=colors['usage'])) elif is_code_example(line): line = ' ' + line if line.startswith('`') else line[2:] output_lines.append(click.style(line.replace('`', ''), fg=colors['command'])) elif is_line_break(line): output_lines.append(click.style(line)) else: output_lines.append(click.style('- ' + line, fg=colors['usage'])) return output_lines def is_headline(line): return line.startswith(('#', '=')) def is_description(line): return line.startswith('>') def is_old_usage(line): return line.startswith('-') def is_code_example(line): return line.startswith(('`', ' ')) def is_line_break(line): return line.startswith("\n") tldr.py-0.7.0/tox.ini000066400000000000000000000006551312420551100144250ustar00rootroot00000000000000# Tox (http://tox.testrun.org/) is a tool for running tests # in multiple virtualenvs. This configuration file will run the # test suite on all supported python versions. To use it, "pip install tox" # and then run "tox" from this directory. [tox] envlist = py27, py33, py34, py35 [testenv] commands = py.test --cov-report term-missing --cov={envsitepackagesdir}/tldr --pep8 -vs tests/ tldr/ deps = -rdev-requirements.txt