watch.py 3.51 KB
Newer Older
Bach Dániel committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
# Copyright 2014 Budapest University of Technology and Economics (BME IK)
#
# This file is part of CIRCLE Cloud.
#
# CIRCLE is free software: you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation, either version 3 of the License, or (at your option)
# any later version.
#
# CIRCLE is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along
# with CIRCLE.  If not, see <http://www.gnu.org/licenses/>.

18 19 20 21 22 23 24 25
import subprocess
import os
import pyinotify

from django.core.management.base import BaseCommand
from django.conf import settings

STATIC_FILES = u'--include-path={}'.format(':'.join(settings.STATICFILES_DIRS))
26
IGNORED_FOLDERS = ("static_collected", "bower_components", )
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59


class LessUtils(object):
    @staticmethod
    def less_path_to_css_path(pathname):
        return "%s.css" % pathname[:-1 * len(".less")]

    @staticmethod
    def compile_less(less_pathname, css_pathname):
        cmd = ["lessc", STATIC_FILES, less_pathname, css_pathname]

        print("\n%s" % ("=" * 30))
        print("Compiling: %s" % os.path.basename(less_pathname))

        try:
            subprocess.check_output(cmd)
        except subprocess.CalledProcessError as e:
            print(e.output)
        else:
            print("Successfully compiled:\n%s\n->\n%s" % (
                less_pathname, css_pathname))

    @staticmethod
    def initial_compile():
        """ Walks through the project looking for LESS files
        and compiles them into CSS.
        """
        for root, dirs, files in os.walk(settings.SITE_ROOT):
            for f in files:
                if not f.endswith(".less"):
                    continue

                relpath = os.path.relpath(root, settings.SITE_ROOT)
60
                if relpath.startswith(IGNORED_FOLDERS):
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
                    continue

                less_pathname = "%s/%s" % (root, f)
                css_pathname = LessUtils.less_path_to_css_path(less_pathname)
                LessUtils.compile_less(less_pathname, css_pathname)

    @staticmethod
    def start_watch():
        """ Watches for changes in LESS files recursively from the
        project's root and compiles the files
        """
        wm = pyinotify.WatchManager()

        class EventHandler(pyinotify.ProcessEvent):
            def process_IN_MODIFY(self, event):
                if not event.name.endswith(".less"):
                    return

79 80 81 82
                relpath = os.path.relpath(event.pathname, settings.SITE_ROOT)
                if relpath.startswith(IGNORED_FOLDERS):
                    return

83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103
                css_pathname = LessUtils.less_path_to_css_path(event.pathname)
                LessUtils.compile_less(event.pathname, css_pathname)

        handler = EventHandler()
        notifier = pyinotify.Notifier(wm, handler)
        wm.add_watch(settings.SITE_ROOT, pyinotify.IN_MODIFY, rec=True)
        notifier.loop()


class Command(BaseCommand):
    help = "Compiles all LESS files then watches for changes."

    def handle(self, *args, **kwargs):
        # for first run compile everything
        print("Initial LESS compiles")
        LessUtils.initial_compile()
        print("\n%s\n" % ("=" * 30))
        print("End of initial LESS compiles\n")

        # after first run watch less files
        LessUtils.start_watch()