1# -*- coding: utf-8 -*-
2import os
3import sys
4import shutil
5
6from django.core.management.base import AppCommand
7from django.core.management.color import color_style
8
9from django_extensions.management.utils import _make_writeable, signalcommand
10
11
12class Command(AppCommand):
13    help = "Creates a Django management command directory structure for the given app name in the app's directory."
14
15    requires_system_checks = False
16    # Can't import settings during this command, because they haven't
17    # necessarily been created.
18    can_import_settings = True
19
20    def add_arguments(self, parser):
21        super().add_arguments(parser)
22        parser.add_argument(
23            '--name', '-n', action='store', dest='command_name',
24            default='sample',
25            help='The name to use for the management command'
26        )
27        parser.add_argument(
28            '--base', '-b', action='store', dest='base_command',
29            default='Base', help='The base class used for implementation of '
30            'this command. Should be one of Base, App, Label, or NoArgs'
31        )
32        parser.add_argument(
33            '--dry-run', action='store_true', default=False,
34            help='Do not actually create any files'
35        )
36
37    @signalcommand
38    def handle_app_config(self, args, **options):
39        app = args
40        copy_template('command_template', app.path, **options)
41
42
43def copy_template(template_name, copy_to, **options):
44    """Copy the specified template directory to the copy_to location"""
45    import django_extensions
46
47    style = color_style()
48    ERROR = getattr(style, 'ERROR', lambda x: x)
49    SUCCESS = getattr(style, 'SUCCESS', lambda x: x)
50
51    command_name, base_command = options['command_name'], '%sCommand' % options['base_command']
52    dry_run = options['dry_run']
53    verbosity = options["verbosity"]
54
55    template_dir = os.path.join(django_extensions.__path__[0], 'conf', template_name)
56
57    # walk the template structure and copies it
58    for d, subdirs, files in os.walk(template_dir):
59        relative_dir = d[len(template_dir) + 1:]
60        if relative_dir and not os.path.exists(os.path.join(copy_to, relative_dir)):
61            if not dry_run:
62                os.mkdir(os.path.join(copy_to, relative_dir))
63        for i, subdir in enumerate(subdirs):
64            if subdir.startswith('.'):
65                del subdirs[i]
66        for f in files:
67            if f.endswith(('.pyc', '.pyo')) or f.startswith(('.DS_Store', '__pycache__')):
68                continue
69            path_old = os.path.join(d, f)
70            path_new = os.path.join(copy_to, relative_dir, f.replace('sample', command_name)).rstrip(".tmpl")
71            if os.path.exists(path_new):
72                path_new = os.path.join(copy_to, relative_dir, f).rstrip(".tmpl")
73                if os.path.exists(path_new):
74                    if verbosity > 1:
75                        print(ERROR("%s already exists" % path_new))
76                    continue
77            if verbosity > 1:
78                print(SUCCESS("%s" % path_new))
79            with open(path_old, 'r') as fp_orig:
80                data = fp_orig.read()
81                data = data.replace('{{ command_name }}', command_name)
82                data = data.replace('{{ base_command }}', base_command)
83                if not dry_run:
84                    with open(path_new, 'w') as fp_new:
85                        fp_new.write(data)
86            if not dry_run:
87                try:
88                    shutil.copymode(path_old, path_new)
89                    _make_writeable(path_new)
90                except OSError:
91                    sys.stderr.write("Notice: Couldn't set permission bits on %s. You're probably using an uncommon filesystem setup. No problem.\n" % path_new)
92