# frozen_string_literal: true require 'generators/ember/generator_helpers' require 'net/http' require 'uri' require 'fileutils' module Ember module Generators class InstallGenerator < ::Rails::Generators::Base class InvalidChannel < ::Thor::Error; end class ConflictingOptions < ::Thor::Error; end class InsufficientOptions < ::Thor::Error; end ::InvalidChannel = InvalidChannel ::ConflictingOptions = ConflictingOptions ::InsufficientOptions = InsufficientOptions desc 'Install Ember.js into your vendor folder' class_option :head, type: :boolean, default: false, desc: 'Download Ember.js & Ember data from canary channel. This is deprecated. Use channel instead.' class_option :channel, type: :string, required: false, desc: "Ember release channel Choose between 'release', 'beta' or 'canary'" class_option :ember_only, type: :boolean, required: false, desc: 'Only download Ember.', aliases: '--ember' class_option :ember_data_only, type: :boolean, required: false, desc: 'Only download ember-data', aliases: '--ember-data' class_option :tag, type: :string, required: false, desc: 'Download tagged release use syntax v1.0.0-beta.3/ember-data & v1.0.0-rc.8/ember' def initialize(args = [], options = {}, config = {}) super(args, options, config) check_options process_options end def ember unless options.ember_data_only? get_ember_js_for(:development) get_ember_js_for(:production) end rescue Thor::Error say('WARNING: no ember files on this channel or tag', :yellow) end def ember_data unless options.ember_only? get_ember_data_for(:development) get_ember_data_for(:production) end rescue Thor::Error say('WARNING: no ember-data files on this channel or tag', :yellow) end private def get_ember_data_for(environment) create_file "vendor/assets/ember/#{environment}/ember-data.js" do fetch url_for(channel, 'ember-data', environment), "vendor/assets/ember/#{environment}/ember-data.js" end sourcemap_url = "#{base_url}/#{channel}/ember-data.js.map" if resource_exist?(sourcemap_url) create_file "vendor/assets/ember/#{environment}/ember-data.js.map" do fetch sourcemap_url, "vendor/assets/ember/#{environment}/ember-data.js.map", false end end end def get_ember_js_for(environment) create_file "vendor/assets/ember/#{environment}/ember.js" do fetch url_for(channel, 'ember', environment), "vendor/assets/ember/#{environment}/ember.js" end compiler_url = "#{base_url}/#{channel}/ember-template-compiler.js" if resource_exist?(compiler_url) create_file "vendor/assets/ember/#{environment}/ember-template-compiler.js" do fetch "#{base_url}/#{channel}/ember-template-compiler.js", "vendor/assets/ember/#{environment}/ember-template-compiler.js" end end end def url_for(channel, component, environment) base = "#{base_url}/#{channel}/#{component}" case environment when :production "#{base}.prod.js" when :development if resource_exist?("#{base}.debug.js") "#{base}.debug.js" # Ember.js 1.10.0.beta.1 or later else "#{base}.js" end end end def check_options say('WARNING: --head option is deprecated in favor of --channel=canary', :yellow) if options.head? if options.head? && options.channel? say 'ERROR: conflicting options. --head and --channel. Use either --head or --channel=', :red raise ConflictingOptions end if options.channel? && !%w[release beta canary].include?(options[:channel]) say 'ERROR: channel can either be release, beta or canary', :red raise InvalidChannel end if options.channel? && options.tag? say 'ERROR: conflicting options. --tag and --channel. --tag is incompatible with other options', :red raise ConflictingOptions end if options.head? && options.tag? say 'ERROR: conflicting options. --tag and --head. --tag is incompatible with other options', :red raise ConflictingOptions end if options.tag? && !(options.ember_only? || options.ember_data_only?) say 'ERROR: insufficient options. --tag needs to be combined with eithe --ember or --ember-data', :red raise InsufficientOptions end end def process_options @channel = :canary if options.head? @channel = "tags/#{options.tag}" if options.tag? end def base_url 'http://builds.emberjs.com' end def channel @channel ||= if options.channel options[:channel] else :release end end def fetch(from, to, prepend_verbose = true) message = "#{from} -> #{to}" say_status('downloading:', message, :green) uri = URI(from) output = StringIO.new if prepend_verbose output.puts "// Fetched from channel: #{channel}, with url " + uri.to_s output.puts "// Fetched on: #{Time.now.utc.iso8601}" end response = Net::HTTP.get_response(uri) case response.code when '404' say "ERROR: Error reading the content from the channel with url #{from}. File not found", :red raise Thor::Error when '200' output.puts response.body.force_encoding('UTF-8') else say "ERROR: Unexpected error with status #{response.code} reading the content from the channel with url #{from}.", :red raise Thor::Error end output.rewind output.read end def resource_exist?(target) uri = URI(target) response = Net::HTTP.new(uri.host, uri.port).head(uri.path) response.code == '200' end end end end