BigW Consortium Gitlab

gemojione.rake 4.97 KB
namespace :gemojione do
  desc 'Generates Emoji SHA256 digests'
  task digests: :environment do
    require 'digest/sha2'
    require 'json'

    dir = Gemojione.images_path
    digests = []
    aliases = Hash.new { |hash, key| hash[key] = [] }
    aliases_path = File.join(Rails.root, 'fixtures', 'emojis', 'aliases.json')

    JSON.parse(File.read(aliases_path)).each do |alias_name, real_name|
      aliases[real_name] << alias_name
    end

    Gitlab::AwardEmoji.emojis.map do |name, emoji_hash|
      fpath = File.join(dir, "#{emoji_hash['unicode']}.png")
      digest = Digest::SHA256.file(fpath).hexdigest

      digests << { name: name, unicode: emoji_hash['unicode'], digest: digest }

      aliases[name].each do |alias_name|
        digests << { name: alias_name, unicode: emoji_hash['unicode'], digest: digest }
      end
    end

    out = File.join(Rails.root, 'fixtures', 'emojis', 'digests.json')

    File.open(out, 'w') do |handle|
      handle.write(JSON.pretty_generate(digests))
    end
  end

  # This task will generate a standard and Retina sprite of all of the current
  # Gemojione Emojis, with the accompanying SCSS map.
  #
  # It will not appear in `rake -T` output, and the dependent gems are not
  # included in the Gemfile by default, because this task will only be needed
  # occasionally, such as when new Emojis are added to Gemojione.
  task sprite: :environment do
    begin
      require 'sprite_factory'
      require 'rmagick'
    rescue LoadError
      # noop
    end

    check_requirements!

    SIZE   = 20
    RETINA = SIZE * 2

    # Update these values to the width and height of the spritesheet when
    # new emoji are added.
    SPRITESHEET_WIDTH = 860
    SPRITESHEET_HEIGHT = 840

    Dir.mktmpdir do |tmpdir|
      # Copy the Gemojione assets to the temporary folder for resizing
      FileUtils.cp_r(Gemojione.images_path, tmpdir)

      Dir.chdir(tmpdir) do
        Dir["**/*.png"].each do |png|
          resize!(File.join(tmpdir, png), SIZE)
        end
      end

      style_path = Rails.root.join(*%w(app assets stylesheets pages emojis.scss))

      # Combine the resized assets into a packed sprite and re-generate the SCSS
      SpriteFactory.cssurl = "image-url('$IMAGE')"
      SpriteFactory.run!(File.join(tmpdir, 'png'), {
        output_style: style_path,
        output_image: "app/assets/images/emoji.png",
        selector:     '.emoji-',
        style:        :scss,
        nocomments:   true,
        pngcrush:     true,
        layout:       :packed
      })

      # SpriteFactory's SCSS is a bit too verbose for our purposes here, so
      # let's simplify it
      system(%Q(sed -i '' "s/width: #{SIZE}px; height: #{SIZE}px; background: image-url('emoji.png')/background-position:/" #{style_path}))
      system(%Q(sed -i '' "s/ no-repeat//" #{style_path}))
      system(%Q(sed -i '' "s/ 0px/ 0/" #{style_path}))

      # Append a generic rule that applies to all Emojis
      File.open(style_path, 'a') do |f|
        f.puts
        f.puts <<-CSS.strip_heredoc
        .emoji-icon {
          background-image: image-url('emoji.png');
          background-repeat: no-repeat;
          height: #{SIZE}px;
          width: #{SIZE}px;

          @media only screen and (-webkit-min-device-pixel-ratio: 2),
                 only screen and (min--moz-device-pixel-ratio: 2),
                 only screen and (-o-min-device-pixel-ratio: 2/1),
                 only screen and (min-device-pixel-ratio: 2),
                 only screen and (min-resolution: 192dpi),
                 only screen and (min-resolution: 2dppx) {
            background-image: image-url('emoji@2x.png');
            background-size: #{SPRITESHEET_WIDTH}px #{SPRITESHEET_HEIGHT}px;
          }
        }
        CSS
      end
    end

    # Now do it again but for Retina
    Dir.mktmpdir do |tmpdir|
      # Copy the Gemojione assets to the temporary folder for resizing
      FileUtils.cp_r(Gemojione.images_path, tmpdir)

      Dir.chdir(tmpdir) do
        Dir["**/*.png"].each do |png|
          resize!(File.join(tmpdir, png), RETINA)
        end
      end

      # Combine the resized assets into a packed sprite and re-generate the SCSS
      SpriteFactory.run!(File.join(tmpdir), {
        output_image: "app/assets/images/emoji@2x.png",
        style:        false,
        nocomments:   true,
        pngcrush:     true,
        layout:       :packed
      })
    end
  end

  def check_requirements!
    return if defined?(SpriteFactory) && defined?(Magick)

    puts <<-MSG.strip_heredoc
      This task is disabled by default and should only be run when the Gemojione
      gem is updated with new Emojis.

      To enable this task, *temporarily* add the following lines to Gemfile and
      re-bundle:

      gem 'sprite-factory'
      gem 'rmagick'
    MSG

    exit 1
  end

  def resize!(image_path, size)
    # Resize the image in-place, save it, and free the object
    image = Magick::Image.read(image_path).first
    image.resize!(size, size)
    image.write(image_path) { self.quality = 100 }
    image.destroy!
  end
end