#!/usr/bin/env python
''' Search for files using wildcards amd magic '''
import os
from fnmatch import fnmatch
import sys
import argparse
import magic
def cmd_args():
''' returns a argparse namespane '''
parser = argparse.ArgumentParser()
parser.add_argument(
'--root', default='.',
help='Starting point [ defaults to cwd ]')
parser.add_argument(
'--pattern', default='*.*',
help='Pattern to use for matching file names [ Defaults to *.* ]')
parser.add_argument(
'--depth',
default=2**32,
type=int,
help='''
Depth is the number of slashes in the files path ''')
parser.add_argument(
'--links',
default=True,
type=bool,
help='\nFollow links\n')
parser.add_argument(
'--magic',
default=None,
type=str,
help='Filter file by a magic keyword link: image data png')
parser.add_argument(
'--cat',
default=False,
type=bool,
help='Concatenate matched files')
return parser.parse_args()
CMD_ARGS = cmd_args()
def cat(filename):
''' cat(filename) -> file contents'''
if CMD_ARGS.cat:
try:
with open(filename, 'r') as file_object:
print file_object.read()
except IOError:
pass
else:
return filename
def depth_check(link):
'''
This is called on each files path to control depth cutoff.
It works by counting the number of slashes in the links path.
If DEPTH > MAX DEPTH {
EXIT PROGRAM
}
Note: By default max depth is 2**32 aka big ass number
'''
if link.count('/') > CMD_ARGS.depth:
sys.exit()
else:
return link
def aggragate_files(root, dirs, files):
_files = [depth_check(os.path.join(root, filename))
for filename in files if fnmatch(filename, CMD_ARGS.pattern)]
_subfiles = [depth_check(os.path.join(root, filename))
for filename in dirs if fnmatch(filename, CMD_ARGS.pattern)]
return set(_files + _subfiles)
def find():
for root, dirs, files in os.walk(CMD_ARGS.root,
followlinks=CMD_ARGS.links):
handle_files(aggragate_files(root, dirs, files))
def handle_files(files):
for filename in files:
if CMD_ARGS.magic:
meta = magic.from_file(filename)
if meta and CMD_ARGS.magic.lower() in meta.lower():
print cat(filename)
else:
print cat(filename)
if __name__ == '__main__':
find()
My concerns with the the code above:
- Is the code easy to read?
- Does this code honor PEP8?
- Have I made any mistakes in the control-flow?
- Would this code be considered pythonic?
- Are my naming conventions descriptive?
How can I structure this code to make it easy to add features?
For example, where and how should this be hooked in?
def cat(filename):
''' cat(filename) -> file contents'''
if CMD_ARGS.cat:
try:
with open(filename, 'r') as file_object:
print file_object.read()
except IOError:
pass
else:
return filename