diff options
author | Matthew Somerville <matthew-github@dracos.co.uk> | 2016-05-31 15:37:35 +0100 |
---|---|---|
committer | Matthew Somerville <matthew-github@dracos.co.uk> | 2016-05-31 15:37:35 +0100 |
commit | 7118fe5e033d6af9ac8eae6c69278791d5e8547d (patch) | |
tree | 674ead661eda1363752f628d07c6cadd612be81f /bin/make_css | |
parent | 34fdac8fd6452653762e49981858a843b68cf1a0 (diff) | |
parent | 54988561abba0ffdb44cc0baf0c2042ba9770b18 (diff) |
Merge branch 'move-to-libsass'
Diffstat (limited to 'bin/make_css')
-rwxr-xr-x | bin/make_css | 168 |
1 files changed, 137 insertions, 31 deletions
diff --git a/bin/make_css b/bin/make_css index 87126ef28..29f2e8523 100755 --- a/bin/make_css +++ b/bin/make_css @@ -1,31 +1,137 @@ -#!/bin/bash -# -# make_css: -# Generate CSS files from SCSS files. -# -# Requires sass which you can get from http://sass-lang.com/ -# FixMyStreet cobrand requires compass -# -# Copyright (c) 2012 UK Citizens Online Democracy. All rights reserved. -# Email: matthew@mysociety.org. WWW: http://www.mysociety.org - -COMPASS=compass -SASS=sass -DIR=$(cd "$(dirname "$0")" >/dev/null && pwd -P) -PARENT=$(cd "$DIR"/../.. >/dev/null && pwd) -if [ -f "$PARENT/gem-bin/compass" ]; then - COMPASS=$PARENT/gem-bin/compass - SASS=$PARENT/gem-bin/sass -fi - -DIRECTORY=$(cd "$DIR"/../web >/dev/null && pwd) - -DIRS=${@:-`find -L $DIRECTORY -name "*.scss" -exec dirname {} \; | uniq`} - -for dir in $DIRS; do - if [ -e "$dir/config.rb" ]; then - $COMPASS compile --output-style compressed $dir - else - $SASS --scss --update --style compressed $dir - fi -done +#!/usr/bin/env perl + +use strict; +use warnings; +use feature 'say'; + +BEGIN { + use File::Basename qw(dirname); + use File::Spec; + my $d = dirname(File::Spec->rel2abs($0)); + require "$d/../setenv.pl"; +} + +use CSS::Sass; +use File::ChangeNotify; +use File::Find::Rule; +use File::Slurp; +use Getopt::Long; +use Path::Tiny; +use Pod::Usage; + +# Store ARGV in case we need to restart later. +my @ARGVorig = @ARGV; + +GetOptions( + 'verbose' => \my $verbose, + 'watch' => \my $watch, + 'help|?' => \my $help, +) or pod2usage(2); +pod2usage(1) if $help; + +my $sass = CSS::Sass->new( + output_style => SASS_STYLE_COMPRESSED, + dont_die => 1, +); + +# Get directories from the command line, defaulting to 'web' if none. +# We need absolute paths so that the include files lookup works. +my @dirs = map { m{/} ? $_ : "web/cobrands/$_" } @ARGV; +@dirs = 'web' unless @dirs; +@dirs = map { path($_)->absolute->stringify } @dirs; + +# Initial compilation, to also discover all the included files. +my %includes; +my %include_to_main; +foreach my $file (File::Find::Rule->file->name(qr/^[^_].*\.scss$/)->in(@dirs)) { + my @includes = compile($file, $verbose); + $includes{$file} = \@includes; + map { push @{$include_to_main{$_}}, $file } @includes ? @includes : $file; +} + +# If we're not watching, we're done! +exit unless $watch; + +my $watcher = File::ChangeNotify->instantiate_watcher( + directories => [ @dirs, keys %include_to_main ], + filter => qr/\.scss$/, +); + +say "\033[34mWatching for changes\033[0m"; + +while ( my @events = $watcher->wait_for_events() ) { + for my $file (map { $_->path } @events) { + verbose($file, "%s was updated"); + for my $inc (@{$include_to_main{$file}}) { + my @includes = compile($inc, 1); + # From CSS::Sass::Watchdog test, we see includes are sorted + if (@includes && @{$includes{$inc}} && "@{$includes{$inc}}" ne "@includes") { + say "\033[34mRestarting to update includes\033[0m"; + exec( $^X, $0, @ARGVorig ) or die "Can't re-exec myself($^X,$0): $!\n"; + } + } + } +} + +# Given a SCSS file, compile it and generate a .map file, +# show an error if any, and return the list of includes. +sub compile { + my ($file, $verbose) = @_; + (my $output_file = $file) =~ s/scss$/css/; + my $source_map_file = "$output_file.map"; + + $sass->options->{source_map_file} = $source_map_file; + my ($css, $stats) = $sass->compile_file($file); + unless ($css) { + warn "\033[31m" . $sass->last_error . "\033[0m";; + return; + } + + my $written = write_if_different($output_file, $css); + if ($written) { + verbose($file, " \033[32mupdated\033[0m %s"); + } elsif ($verbose) { + verbose($file, " \033[33munchanged\033[0m %s"); + } + write_if_different($source_map_file, $stats->{source_map_string}); + return @{$stats->{included_files} || []}; +} + +# Write a file, only if it has changed. +sub write_if_different { + my ($fn, $data) = @_; + my $current = File::Slurp::read_file($fn, { binmode => ':utf8', err_mode => 'quiet' }); + if (!$current || $current ne $data) { + File::Slurp::write_file($fn, { binmode => ':utf8' }, $data); + return 1; + } + return 0; +} + +sub verbose { + my ($file, $format) = @_; + # Strip most of file path, keep dir/file + (my $pr = $file) =~ s{.*/(.*/.*)\.scss}{$1}; + say sprintf $format, $pr; +} + +__END__ + +=head1 NAME + +make_css - Generate CSS files from SCSS files, watch for changes. + +=head1 SYNOPSIS + +make_css [options] [dirs ...] + + Options: + --verbose display more information + --watch wait for file updates and compile automatically + --help this help message + +If no directories are specified, any .scss files under web/ that do not begin +with a "_" will be processed. "web/cobrands/" may be omitted from a given +directory. + +=cut |