In response to Issue #108: Added option to copy sheet while not editable.

This commit is contained in:
0rax 2013-10-11 18:32:21 +02:00
parent b6e73539bd
commit fc4b047958
1 changed files with 62 additions and 25 deletions

87
cheat
View File

@ -3,7 +3,7 @@
cheat.py -- cheat allows you to create and view interactive cheatsheets on the cheat.py -- cheat allows you to create and view interactive cheatsheets on the
command-line. It was designed to help remind *nix system command-line. It was designed to help remind *nix system
administrators of options for commands that they use frequently, administrators of options for commands that they use frequently,
but not frequently enough to remember. but not frequently enough to remember.
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -25,9 +25,9 @@ import argparse
import subprocess import subprocess
from textwrap import dedent from textwrap import dedent
DEFAULT_CHEAT_DIR = os.environ.get('DEFAULT_CHEAT_DIR') or \ DEFAULT_CHEAT_DIR = (os.environ.get('DEFAULT_CHEAT_DIR') or
os.path.join(os.path.expanduser('~'), '.cheat') os.path.join(os.path.expanduser('~'), '.cheat'))
USE_PYGMENTS = False USE_PYGMENTS = False
# NOTE remove this check if it is confirmed to work on windows # NOTE remove this check if it is confirmed to work on windows
if os.name == 'posix' and 'CHEATCOLORS' in os.environ: if os.name == 'posix' and 'CHEATCOLORS' in os.environ:
@ -40,8 +40,9 @@ if os.name == 'posix' and 'CHEATCOLORS' in os.environ:
except ImportError: except ImportError:
pass pass
def pretty_print(filename): def pretty_print(filename):
"Applies syntax highlighting to a cheatsheet and writes it to stdout" """Applies syntax highlighting to a cheatsheet and writes it to stdout"""
try: try:
if os.path.splitext(filename)[1]: if os.path.splitext(filename)[1]:
lexer = get_lexer_for_filename(filename) lexer = get_lexer_for_filename(filename)
@ -58,8 +59,9 @@ def pretty_print(filename):
fmt = TerminalFormatter() fmt = TerminalFormatter()
highlight(code, lexer, fmt, sys.stdout) highlight(code, lexer, fmt, sys.stdout)
class CheatSheets(object): class CheatSheets(object):
dirs = None dirs = None
sheets = None sheets = None
@ -67,7 +69,8 @@ class CheatSheets(object):
self.dirs = self.__cheat_directories() self.dirs = self.__cheat_directories()
# verify that we have at least one cheat directory # verify that we have at least one cheat directory
if not self.dirs: if not self.dirs:
error_msg = 'The {default} dir does not exist or the CHEATPATH var is not set.' error_msg = ('The {default} dir does not exist'
' or the CHEATPATH var is not set.')
print >> sys.stderr, error_msg.format(default=DEFAULT_CHEAT_DIR) print >> sys.stderr, error_msg.format(default=DEFAULT_CHEAT_DIR)
exit(1) exit(1)
self.sheets = self.__cheat_files() self.sheets = self.__cheat_files()
@ -91,7 +94,9 @@ class CheatSheets(object):
return default return default
def __cheat_files(self): def __cheat_files(self):
"""Assembles a dictionary of cheatsheets found in the above directories.""" """
Assembles a dictionary of cheatsheets found in the above directories.
"""
cheats = {} cheats = {}
for cheat_dir in reversed(self.dirs): for cheat_dir in reversed(self.dirs):
cheats.update(dict([(cheat, cheat_dir) cheats.update(dict([(cheat, cheat_dir)
@ -103,37 +108,64 @@ class CheatSheets(object):
def edit(self, cheat): def edit(self, cheat):
"""Creates or edits a cheatsheet""" """Creates or edits a cheatsheet"""
# Assert that the EDITOR environment variable is set and that at least 3 # Assert that the EDITOR environment variable is set and that at least
# arguments have been given # 3 arguments have been given
if 'EDITOR' not in os.environ: if 'EDITOR' not in os.environ:
print >> sys.stderr, ('In order to create/edit a cheatsheet you ' print >> sys.stderr, ('In order to create/edit a cheatsheet you '
'must set your EDITOR environment variable to your favorite ' 'must set your EDITOR environment variable '
'editor\'s path.') 'to your favorite editor\'s path.')
exit(1) exit(1)
elif os.environ['EDITOR'] == "": elif os.environ['EDITOR'] == "":
print >> sys.stderr, ('Your EDITOR environment variable is set ' print >> sys.stderr, ('Your EDITOR environment variable is set '
'to nothing, in order to create/edit a cheatsheet your must ' 'to nothing, in order to create/edit a '
'set it to a valid editor\'s path.') 'cheatsheet your must set it to a valid '
'editor\'s path.')
exit(1) exit(1)
else: else:
editor = os.environ['EDITOR'].split() editor = os.environ['EDITOR'].split()
# if the cheatsheet already exists, open it for editing # if the cheatsheet already exists, open it for editing
try: try:
if cheat in sheets.sheets: if cheat in self.sheets:
subprocess.call(editor + [os.path.join(self.sheets[cheat], cheat)]) sheet_path = os.path.join(self.sheets[cheat], cheat)
if os.access(sheet_path, os.W_OK):
subprocess.call(editor + [sheet_path])
else:
print >> sys.stderr, ("Sheet '%s' [%s] is not editable."
% (cheat, sheet_path))
print ('Do you want to '
'copy it to your user cheatsheets directory [%s] '
'before editing ?\nKeep in mind that your sheet '
'will always be used before system-wide one.'
% DEFAULT_CHEAT_DIR)
awn = raw_input('[y/n] ')
if awn != 'y':
print ('Ok, if you want to edit system-wide sheet, '
'please try `cheat -e <cheatsheet>` '
'again with sudo.')
exit(1)
import shutil
new_sheet = os.path.join(DEFAULT_CHEAT_DIR, cheat)
shutil.copy(sheet_path, new_sheet)
subprocess.call(editor + [new_sheet])
# otherwise, create it # otherwise, create it
else: else:
import cheatsheets as cs import cheatsheets as cs
# Attempt to write the new cheatsheet to the user's ~/.cheat dir if it # Attempt to write the new cheatsheet to the user's ~/.cheat
# exists. If it does not exist, attempt to create it. # dir if it exists. If it does not exist, attempt to create it.
if os.access(DEFAULT_CHEAT_DIR, os.W_OK) or os.makedirs(DEFAULT_CHEAT_DIR): if os.access(DEFAULT_CHEAT_DIR, os.W_OK) or os.makedirs(DEFAULT_CHEAT_DIR):
subprocess.call(editor + [os.path.join(DEFAULT_CHEAT_DIR, cheat)]) subprocess.call(editor + [os.path.join(DEFAULT_CHEAT_DIR, cheat)])
# If the directory cannot be created, write to the python package # If the directory cannot be created, write to the python
# directory, though that will likely require the use of sudo # package directory, though that will likely require the use
# of sudo
else: else:
subprocess.call(editor + [os.path.join(cs.cheat_dir, cheat)]) if os.access(sheet_path, os.W_OK):
subprocess.call(editor + [os.path.join(cs.cheat_dir, cheat)])
else:
print >> sys.stderr, ("Couldn't create '%s' cheatsheet."
% cheat)
exit(1)
except OSError, e: except OSError, e:
print >> sys.stderr, ("Could not launch `%s` as your editor : %s" print >> sys.stderr, ("Could not launch `%s` as your editor : %s"
% (editor[0], e.strerror)) % (editor[0], e.strerror))
@ -145,6 +177,7 @@ class CheatSheets(object):
return ('\n'.join(sorted(['%s [%s]' % (key.ljust(max_command), value) return ('\n'.join(sorted(['%s [%s]' % (key.ljust(max_command), value)
for key, value in self.sheets.items()]))) for key, value in self.sheets.items()])))
# Custom action for argparse # Custom action for argparse
class ListDirectories(argparse.Action): class ListDirectories(argparse.Action):
"""List cheat directories and exit""" """List cheat directories and exit"""
@ -152,18 +185,21 @@ class ListDirectories(argparse.Action):
print("\n".join(sheets.dirs)) print("\n".join(sheets.dirs))
parser.exit() parser.exit()
class ListCheatsheets(argparse.Action): class ListCheatsheets(argparse.Action):
"""List cheatsheets and exit""" """List cheatsheets and exit"""
def __call__(self, parser, namespace, values, option_string=None): def __call__(self, parser, namespace, values, option_string=None):
print sheets.list() print sheets.list()
parser.exit() parser.exit()
class EditSheet(argparse.Action): class EditSheet(argparse.Action):
"""If the user wants to edit a cheatsheet""" """If the user wants to edit a cheatsheet"""
def __call__(self, parser, namespace, values, option_string=None): def __call__(self, parser, namespace, values, option_string=None):
sheets.edit(values[0]) sheets.edit(values[0])
parser.exit() parser.exit()
def main(): def main():
global sheets global sheets
@ -177,13 +213,13 @@ def main():
epi = dedent(''' epi = dedent('''
Examples: Examples:
To look up 'tar': To look up 'tar':
cheat tar cheat tar
To create or edit the cheatsheet for 'foo': To create or edit the cheatsheet for 'foo':
cheat -e foo cheat -e foo
To list the directories on the CHEATPATH To list the directories on the CHEATPATH
cheat -d cheat -d
@ -193,7 +229,8 @@ def main():
parser = argparse.ArgumentParser(prog='cheat', parser = argparse.ArgumentParser(prog='cheat',
description=desc, epilog=epi, description=desc, epilog=epi,
formatter_class=argparse.RawDescriptionHelpFormatter) formatter_class=argparse.
RawDescriptionHelpFormatter)
parser_group = parser.add_mutually_exclusive_group() parser_group = parser.add_mutually_exclusive_group()
parser_group.add_argument('sheet', metavar='cheatsheet', parser_group.add_argument('sheet', metavar='cheatsheet',
action='store', type=str, nargs='?', action='store', type=str, nargs='?',