csscom.py 4.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. #!/usr/bin/env python
  2. from argparse import ArgumentParser
  3. from parse import parse_groups
  4. from generate import generate_group
  5. def compress_css(css, combine_blocks=True, compress_whitespace=True,
  6. compress_color=True, compress_font=True,
  7. compress_dimension=True, sort_properties=True, tab='\t'):
  8. groups = parse_groups(css)
  9. options = dict(combine_blocks=combine_blocks,
  10. compress_whitespace=compress_whitespace,
  11. compress_color=compress_color,
  12. compress_font=compress_font,
  13. compress_dimension=compress_dimension,
  14. sort_properties=sort_properties,
  15. tab=tab)
  16. compressed_groups = [generate_group(selectors, blocks, **options)
  17. for selectors, blocks in groups]
  18. newlines = '' if compress_whitespace else '\n\n'
  19. return newlines.join(compressed_groups)
  20. def parse_options():
  21. parser = ArgumentParser(description='Just another CSS compressor. '
  22. 'If none of the compression options below (those starting with '
  23. '"-c") are specified, all are enabled by default. If any are '
  24. 'specified, the others are not enabled.')
  25. parser.add_argument('files', metavar='FILE', nargs='+',
  26. help='CSS files to compress')
  27. parser.add_argument('-cw', '--compress-whitespace', action='store_true',
  28. help='omit unnecessary whitespaces and semicolons')
  29. parser.add_argument('-cc', '--compress-color', action='store_true',
  30. help='replace color codes/names with shorter synonyms')
  31. parser.add_argument('-cf', '--compress-font', action='store_true',
  32. help='replace separate font statements with shortcut '
  33. 'font statement where possible')
  34. parser.add_argument('-cd', '--compress-dimension', action='store_true',
  35. help='replace separate margin/padding statements with '
  36. 'shortcut statements where possible')
  37. parser.add_argument('-cb', '--combine-blocks', action='store_true',
  38. help='combine or split blocks into blocks with '
  39. 'comma-separated selectors if it results in less '
  40. 'css code')
  41. parser.add_argument('-nc', '--no-compression', action='store_true',
  42. help='don\'t apply any compression, just generate CSS')
  43. parser.add_argument('-ns', '--no-sort', action='store_false',
  44. dest='sort_properties', help='sort property names')
  45. parser.add_argument('-s', '--spaces', type=int, metavar='NUMBER=4',
  46. nargs='?', const=4,
  47. help='number of spaces to use for indenting (indent '
  48. 'defaults to a single tab [\\t])')
  49. parser.add_argument('-o', '--output', metavar='FILE',
  50. help='filename for compressed output (default is '
  51. 'stdout)')
  52. args = parser.parse_args()
  53. # Enable all compression options if none are explicitely enabled
  54. if not any([args.compress_whitespace, args.compress_color,
  55. args.compress_font, args.compress_dimension,
  56. args.combine_blocks]) and not args.no_compression:
  57. args.compress_whitespace = args.compress_color = args.compress_font \
  58. = args.compress_dimension = args.combine_blocks = True
  59. return args
  60. def _content(filename):
  61. handle = open(filename, 'r')
  62. content = handle.read()
  63. handle.close()
  64. return content
  65. if __name__ == '__main__':
  66. args = parse_options()
  67. options = dict(args._get_kwargs())
  68. files = options.pop('files')
  69. spaces = options.pop('spaces')
  70. options['tab'] = '\t' if spaces is None else spaces * ' '
  71. output_file = options.pop('output')
  72. del options['no_compression']
  73. try:
  74. css = '\n'.join(_content(filename) for filename in files)
  75. compressed = compress_css(css, **options)
  76. if output_file:
  77. open(output_file, 'w').write(compressed)
  78. else:
  79. print compressed,
  80. except IOError as e:
  81. print e