Commit 9ec71bed authored by Ryan Pavlik's avatar Ryan Pavlik

Reorganize and add setuptools script.

parent 88e418cb
#!/usr/bin/python3 -i
# -*- coding: utf-8 -*-
#
# Copyright (c) 2018 Collabora, Ltd.
#
# SPDX-License-Identifier: BSL-1.0
from .boilerplate_run import BoilerplateOutput, BoilerplateRun
from .find_paths import find_paths
#!/usr/bin/python3
#!/usr/bin/python3 -i
# -*- coding: utf-8 -*-
#
# Copyright (c) 2018 Collabora, Ltd.
......@@ -10,66 +10,77 @@
# Purpose: Generates a .cpp and .h file with the given stem,
# containing the expected default/boilerplate contents
import argparse
import file_boilerplate.filters
from file_boilerplate.find_paths import find_paths
from .filters import do_prefix_block, do_make_identifier, do_c_block_comment, do_cpp_line_comment
from .find_paths import find_paths
from jinja2 import Environment, FileSystemLoader
from jinja2.utils import Markup
from uuid import uuid4
from re import sub
from sys import exit
import subprocess
from datetime import date
from os.path import exists
import subprocess # to get author from Git
from re import sub # for guid include guard
from uuid import uuid4 # for guid include guard
class BoilerplateOutput(object):
def __init__(self, fn, data):
self.fn = fn
self.data = data
def __str__(self):
return '\n'.join(['Filename: ' + self.fn, 'Contents:', self.data])
def write(self, force=False):
if exists(self.fn):
if force:
print("Overwriting {} ...".format(self.fn))
else:
print('Error: {} already exists (and not forcing)! Not overwriting...'.format(
self.fn))
return False
else:
print("Generating {} ...".format(self.fn))
# Write the output
with open(self.fn, 'w', encoding='utf-8') as f:
f.write(self.data)
return True
def make_guid_include_guard(fn):
guid = str(uuid4()).upper().replace('-','_')
guid = str(uuid4()).upper().replace('-', '_')
raw_include_guard = "INCLUDED_{fn}_GUID_{guid}".format(fn=fn, guid=guid)
# Try to make a valid C preprocessor identifier:
# Convert "bad" characters to _
return sub(r"[-./]", '_', raw_include_guard)
def make_author():
return '{name} <{email}>'.format(
name=subprocess.getoutput('git config user.name'),
email=subprocess.getoutput('git config user.email'))
def make_year():
return date.today().year
def do_make_guid():
return str(uuid4()).upper()
def make_environment():
env = Environment(keep_trailing_newline=True, autoescape=False, loader=FileSystemLoader(find_paths()))
env = Environment(keep_trailing_newline=True,
autoescape=False, loader=FileSystemLoader(find_paths()))
env.globals['year'] = make_year()
env.globals['author'] = make_author()
env.filters['prefix_block'] = file_boilerplate.filters.do_prefix_block
env.filters['make_identifier'] = file_boilerplate.filters.do_make_identifier
env.filters['prefix_block'] = do_prefix_block
env.filters['make_identifier'] = do_make_identifier
env.globals['make_guid'] = do_make_guid
env.filters['c_block_comment'] = file_boilerplate.filters.do_c_block_comment
env.filters['cpp_line_comment'] = file_boilerplate.filters.do_cpp_line_comment
env.filters['c_block_comment'] = do_c_block_comment
env.filters['cpp_line_comment'] = do_cpp_line_comment
return env
class BoilerplateOutput(object):
def __init__(self, fn, data):
self.fn = fn
self.data = data
def __str__(self):
return '\n'.join(['Filename: ' + self.fn, 'Contents:', self.data])
def write(self, force=False):
if exists(self.fn):
if force:
print("Overwriting {} ...".format(self.fn))
else:
print('Error: {} already exists (and not forcing)! Not overwriting...'.format(self.fn))
return False
else:
print("Generating {} ...".format(self.fn))
# Write the output
with open(self.fn, 'w', encoding='utf-8') as f:
f.write(self.data)
return True
class BoilerplateRun(object):
def __init__(self):
self.env = make_environment()
......@@ -79,32 +90,8 @@ class BoilerplateRun(object):
def render(self, stem, ext):
env = self.get_env()
template = env.get_template('template.%s' % ext, globals=dict(stem=stem))
template = env.get_template('template.%s' %
ext, globals=dict(stem=stem))
output = template.render(year=make_year(), author=make_author())
fn = template.module.fn()
return BoilerplateOutput(fn=fn, data=output)
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('stem', metavar='stem', nargs='?',
help='Specify generated filename stem (.cpp and .h will be added)')
parser.add_argument('--noh', action='store_true', default=False,
help='Skip generating the .h file')
parser.add_argument('--nocpp', action='store_true', default=False,
help='Skip generating the .cpp file')
parser.add_argument('-f', '--force', action='store_true', default=False,
help='Write file(s) even if already existing')
args = parser.parse_args()
success = True
run = BoilerplateRun()
if not args.noh:
success = run.render(stem=args.stem,
ext="h").write(force=args.force) and success
if not args.nocpp:
success = run.render(ext='cpp',
stem=args.stem).write(force=args.force) and success
if success:
exit()
exit(-1)
\ No newline at end of file
#!/usr/bin/python3
# -*- coding: utf-8 -*-
#
# Copyright (c) 2018 Collabora, Ltd.
#
# SPDX-License-Identifier: BSL-1.0
#
# Author(s): Ryan Pavlik <ryan.pavlik@collabora.com>
#
# Purpose: Generates a .cpp and .h file with the given stem,
# containing the expected default/boilerplate contents
import argparse
from file_boilerplate import BoilerplateRun
from sys import exit
def main():
parser = argparse.ArgumentParser()
parser.add_argument('stem', metavar='stem', nargs='?',
help='Specify generated filename stem (.cpp and .h will be added)')
parser.add_argument('--noh', action='store_true', default=False,
help='Skip generating the .h file')
parser.add_argument('--nocpp', action='store_true', default=False,
help='Skip generating the .cpp file')
parser.add_argument('-f', '--force', action='store_true', default=False,
help='Write file(s) even if already existing')
args = parser.parse_args()
success = True
run = BoilerplateRun()
if not args.noh:
success = run.render(stem=args.stem,
ext="h").write(force=args.force) and success
if not args.nocpp:
success = run.render(ext='cpp',
stem=args.stem).write(force=args.force) and success
if success:
exit()
exit(-1)
......@@ -9,6 +9,7 @@
#
# Purpose: Filters useful in generating source code boilerplate
def do_prefix_block(s, line_prefix, block_begin=None, block_end=None, blank_line_prefix=None):
"""Prefix each line of a block of text with a string, as well as applying a begin and end block string.
......@@ -21,7 +22,8 @@ def do_prefix_block(s, line_prefix, block_begin=None, block_end=None, blank_line
# Nothing passed for blank line prefix
blank_line_prefix = line_prefix.strip()
newline = u'\n'
s += newline # this quirk is necessary for splitlines method
s += newline # this quirk is necessary for splitlines method
def filter_line(l):
if l:
return line_prefix + l
......@@ -51,11 +53,13 @@ def do_prefix_block(s, line_prefix, block_begin=None, block_end=None, blank_line
lines[0] = block_end
return newline.join(lines)
def do_make_identifier(s, replacement='_'):
"""Transform characters that aren't valid in identifiers to the given alternate character."""
from re import sub
return sub(r"[-/. \n]", replacement, s)
def do_c_block_comment(s, begin_chars='/*', line_prefix=' * ', end_chars=' */'):
"""Makes things like this: (with begin_chars='/*', line_prefix=' * ', end_chars=' */')
......@@ -66,7 +70,8 @@ def do_c_block_comment(s, begin_chars='/*', line_prefix=' * ', end_chars=' */'):
*/
"""
return do_prefix_block(s, line_prefix=line_prefix, blank_line_prefix=line_prefix.rstrip(),
block_begin=(begin_chars + '\n'), block_end=('\n' + end_chars))
block_begin=(begin_chars + '\n'), block_end=('\n' + end_chars))
def do_cpp_line_comment(s, line_prefix='// '):
"""Makes things like this: (with line_prefix='// ')
......@@ -76,4 +81,4 @@ def do_cpp_line_comment(s, line_prefix='// '):
// bar
"""
return do_prefix_block(s, line_prefix=line_prefix, blank_line_prefix=line_prefix.rstrip(),
block_begin=None, block_end=None)
\ No newline at end of file
block_begin=None, block_end=None)
#!/usr/bin/python3
#!/usr/bin/python3 -i
# -*- coding: utf-8 -*-
#
# Copyright (c) 2018 Collabora, Ltd.
......@@ -10,6 +10,8 @@
# Purpose: Create a list of 'search paths' for templates
from pathlib import Path
def get_parents(dir=None):
if dir is None:
dir = Path.cwd()
......@@ -19,8 +21,10 @@ def get_parents(dir=None):
ret.reverse()
return ret
def get_potential_boilerplate_dirs(dir=None):
return [ d/'.boilerplate' for d in get_parents(dir)]
return [d/'.boilerplate' for d in get_parents(dir)]
def find_paths():
return [ str(d) for d in get_potential_boilerplate_dirs() if d.exists() and d.is_dir()]
def find_paths(dir=None):
return [str(d) for d in get_potential_boilerplate_dirs(dir) if d.exists() and d.is_dir()]
from setuptools import setup
setup(name='file_boilerplate',
version='0.1',
description='Tool for generating boilerplate for source code files (license header, include guard, etc.)',
url='https://gitlab.collabora.com/rpavlik/file-boilerplate',
author='Ryan Pavlik',
author_email='ryan.pavlik@collabora.com',
license='BSL-1.0',
packages=['file_boilerplate'],
entry_points={
'console_scripts': ['genfile=file_boilerplate.command_line:main'],
},
install_requires=[
'jinja2',
],
zip_safe=True,
test_suite='nose.collector',
tests_require=['nose'],
)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment