File: lib/radiant/extension/script.rb

Overview
Module Structure
Class Hierarchy
Code

Overview

Module Structure

  module: <Toplevel Module>
  module: Radiant#254
  class: Extension#255
includes
  Annotatable   
  Simpleton   
inherits from
  Object ( Builtin-Module )
  module: Script#256
has properties
module method: execute / 1 #258
  module: Util#269
has properties
attribute: extension_name [RW] #270
attribute: extension [RW] #270
method: to_extension_name / 1 #272
method: installed? #276
method: registered? #281
method: extension_paths #285
method: load_extensions #291
method: find_extension #295
  class: Install#300
includes
  Util ( Radiant::Extension::Script )
inherits from
  Object ( Builtin-Module )
has properties
method: initialize / 1 #303
  class: Uninstall#319
includes
  Util ( Radiant::Extension::Script )
inherits from
  Object ( Builtin-Module )
has properties
method: initialize / 1 #322
  class: Info#333
includes
  Util ( Radiant::Extension::Script )
inherits from
  Object ( Builtin-Module )
has properties
method: initialize / 1 #336
  class: Help#343
inherits from
  Object ( Builtin-Module )
has properties
method: initialize / 1 #344
method: help #350
method: install #367
method: uninstall #374
method: info #381
method: command_names #389
  module: Registry#6
  class: Extension#7
inherits from
  Base ( ActiveResource )
has properties
method: install #10
method: uninstall #14
method: inspect #18
  class: Action#32
inherits from
  Object ( Builtin-Module )
has properties
method: rake / 1 #33
method: tasks_include? / 1 #38
method: file_utils #52
  class: Installer#59
inherits from
  Action ( Registry )
has properties
attribute: url [RW] #60
attribute: path [RW] #60
attribute: name [RW] #60
method: initialize / 2 #61
method: install #65
method: copy_to_vendor_extensions #71
method: migrate #76
method: update #80
  class: Uninstaller#85
inherits from
  Action ( Registry )
has properties
attribute: name [RW] #86
method: initialize / 1 #87
method: uninstall #91
method: migrate_down #96
method: remove_extension_directory #100
  class: Checkout#105
inherits from
  Installer ( Registry )
has properties
method: initialize / 1 #106
method: checkout_command #110
method: install #114
method: checkout #119
  class: Download#125
inherits from
  Installer ( Registry )
has properties
method: initialize / 1 #126
method: install #130
method: unpack #136
method: filename #140
method: download #144
  class: Git#150
inherits from
  Checkout ( Registry )
has properties
method: project_in_git? #151
method: checkout_command #155
method: checkout #159
method: copy_to_vendor_extensions #173
  class: Subversion#178
inherits from
  Checkout ( Registry )
has properties
method: checkout_command #179
  class: Gem#184
inherits from
  Download ( Registry )
has properties
method: gem_name / 1 #185
method: download #189
method: unpack #200
  class: Tarball#209
inherits from
  Download ( Registry )
has properties
method: filename #210
method: unpack #214
  class: Gzip#221
inherits from
  Tarball ( Registry )
has properties
method: filename #222
method: unpack #226
  class: Bzip2#233
inherits from
  Tarball ( Registry )
has properties
method: filename #234
method: unpack #238
  class: Zip#245
inherits from
  Download ( Registry )
has properties
method: unpack #246

Class Hierarchy

Object ( Builtin-Module )
Base ( ActiveResource )
  Extension ( Registry ) #7
Action ( Registry ) — #32
Installer ( Registry ) — #59
Checkout ( Registry ) — #105
  Git    #150
  Subversion    #178
Download ( Registry ) — #125
Gem ( Registry ) — #184
Tarball ( Registry ) — #209
  Gzip    #221
  Bzip2    #233
Zip ( Registry ) — #245
Uninstaller ( Registry ) — #85
Extension ( Radiant ) — #255
Install ( Radiant::Extension::Script ) — #300
Uninstall ( Radiant::Extension::Script ) — #319
Info ( Radiant::Extension::Script ) — #333
Help ( Radiant::Extension::Script ) — #343

Code

   1  require 'active_resource'
   2  require 'tmpdir'
   3  require 'fileutils'
   4  require 'rake'
   5 
   6  module Registry
   7    class Extension < ActiveResource::Base
   8      self.site = ENV['REGISTRY_URL'] || "http://ext.radiantcms.org/"
   9 
  10      def install
  11        Registry.const_get(install_type).new(self).install
  12      end
  13 
  14      def uninstall
  15        Uninstaller.new(self).uninstall
  16      end
  17 
  18      def inspect
  19  %{
  20  Name:           #{name}
  21  Description:
  22    #{description}
  23  Author:         #{author.name} <#{author.email}>
  24  Source code:    #{repository_url}
  25  Download:       #{download_url}
  26  Install type:   #{install_type}
  27  Supports:       Radiant #{supports_radiant_version}
  28  }.strip
  29      end
  30    end
  31 
  32    class Action
  33      def rake(command)
  34        puts "rake #{command}"
  35        puts `rake #{command} RAILS_ENV=#{RAILS_ENV}` if tasks_include? command
  36      end
  37 
  38      def tasks_include?(command)
  39        command = command.split(':')
  40        if command.length > 1 && command[0..1] == ['radiant','extensions']
  41          extension = command[2]
  42          task = "radiant:extensions:#{extension}:#{command[3].split[0]}"
  43        else
  44          extension = task = command[0]
  45        end
  46        rake_file = File.join(RAILS_ROOT, 'vendor', 'extensions', extension) + '/lib/tasks/' + extension + '_extension_tasks.rake'
  47        load rake_file if File.exist? rake_file
  48        tasks = Rake.application.tasks.map(&:name)
  49        tasks.include? task
  50      end
  51      
  52      def file_utils
  53        FileUtils
  54      end
  55      
  56      delegate :cd, :cp_r, :rm_r, :to => :file_utils
  57    end
  58 
  59    class Installer < Action
  60      attr_accessor :url, :path, :name
  61      def initialize(url, name)
  62        self.url, self.name = url, name
  63      end
  64 
  65      def install
  66        copy_to_vendor_extensions
  67        migrate
  68        update
  69      end
  70 
  71      def copy_to_vendor_extensions
  72        cp_r(self.path, File.expand_path(File.join(RAILS_ROOT, 'vendor', 'extensions', name)))
  73        rm_r(self.path)
  74      end
  75 
  76      def migrate
  77        rake "radiant:extensions:#{name}:migrate"
  78      end
  79 
  80      def update
  81        rake "radiant:extensions:#{name}:update"
  82      end
  83    end
  84 
  85    class Uninstaller < Action
  86      attr_accessor :name
  87      def initialize(extension)
  88        self.name = extension.name
  89      end
  90 
  91      def uninstall
  92        migrate_down
  93        remove_extension_directory
  94      end
  95 
  96      def migrate_down
  97        rake "radiant:extensions:#{name}:migrate VERSION=0"
  98      end
  99 
 100      def remove_extension_directory
 101        rm_r(File.join(RAILS_ROOT, 'vendor', 'extensions', name))
 102      end
 103    end
 104 
 105    class Checkout < Installer
 106      def initialize(extension)
 107        super(extension.repository_url, extension.name)
 108      end
 109 
 110      def checkout_command
 111        raise "Not Implemented!"
 112      end
 113 
 114      def install
 115        checkout
 116        super
 117      end
 118 
 119      def checkout
 120        self.path = File.join(Dir.tmpdir, name)
 121        cd(Dir.tmpdir) { system "#{checkout_command}" }
 122      end
 123    end
 124 
 125    class Download < Installer
 126      def initialize(extension)
 127        super(extension.download_url, extension.name)
 128      end
 129 
 130      def install
 131        download
 132        unpack
 133        super
 134      end
 135 
 136      def unpack
 137        raise "Not Implemented!"
 138      end
 139 
 140      def filename
 141        File.basename(self.url)
 142      end
 143 
 144      def download
 145        require 'open-uri'
 146        File.open(File.join(Dir.tmpdir, self.filename), 'w') {|f| f.write open(self.url).read }
 147      end
 148    end
 149 
 150    class Git < Checkout
 151      def project_in_git?
 152        @in_git ||= File.directory?(".git")
 153      end
 154      
 155      def checkout_command
 156        "git clone #{url} #{name}"
 157      end
 158      
 159      def checkout
 160        if project_in_git?
 161          system "git submodule add #{url} vendor/extensions/#{name}"
 162          cd(File.join('vendor', 'extensions', name)) do
 163            system "git submodule init && git submodule update"
 164          end
 165        else
 166          super
 167          cd(path) do
 168            system "git submodule init && git submodule update"
 169          end
 170        end
 171      end
 172      
 173      def copy_to_vendor_extensions
 174        super unless project_in_git?
 175      end
 176    end
 177 
 178    class Subversion < Checkout
 179      def checkout_command
 180        "svn checkout #{url} #{name}"
 181      end
 182    end
 183 
 184    class Gem < Download
 185      def gem_name(name)
 186        name.gsub(/-\d+\.\d+\.\d+(.+)?\.gem/, '')
 187      end
 188 
 189      def download
 190        # Don't download the gem if it's already installed
 191        extension = gem_name(filename)
 192        begin
 193          gem extension
 194        rescue ::Gem::LoadError
 195          super
 196          `gem install #{extension}`
 197        end
 198      end
 199 
 200      def unpack
 201        output = nil
 202        cd(Dir.tmpdir) do
 203          output = `gem unpack #{gem_name(filename)}`
 204        end
 205        self.path = output.match(/'(.*)'/)[1]
 206      end
 207    end
 208 
 209    class Tarball < Download
 210      def filename
 211        "#{self.name}.tar"
 212      end
 213 
 214      def unpack
 215        output = nil
 216        cd(Dir.tmpdir) { output = `tar xvf #{filename}` }
 217        self.path = File.join(Dir.tmpdir, output.split(/\n/).first.split('/').first)
 218      end
 219    end
 220 
 221    class Gzip < Tarball
 222      def filename
 223        @unpacked ? super : "#{self.name}.tar.gz"
 224      end
 225 
 226      def unpack
 227        cd(Dir.tmpdir) { system "gunzip #{self.filename}" }
 228        @unpacked = true
 229        super
 230      end
 231    end
 232 
 233    class Bzip2 < Tarball
 234      def filename
 235        @unpacked ? super : "#{self.name}.tar.bz2"
 236      end
 237 
 238      def unpack
 239        cd(Dir.tmpdir) { system "bunzip2 #{self.filename}" }
 240        @unpacked = true
 241        super
 242      end
 243    end
 244 
 245    class Zip < Download
 246      def unpack
 247        output = nil
 248        cd(Dir.tmpdir) { output = `unzip #{filename} -d #{name}` }
 249        self.path = File.join(Dir.tmpdir, name)
 250      end
 251    end
 252  end
 253 
 254  module Radiant
 255    class Extension
 256      module Script
 257        class << self
 258          def execute(args)
 259            command = args.shift || 'help'
 260            begin
 261              const_get(command.camelize).new(args)
 262            rescue ArgumentError => e
 263              puts e.message
 264              Help.new [command]
 265            end
 266          end
 267        end
 268 
 269        module Util
 270          attr_accessor :extension_name, :extension
 271 
 272          def to_extension_name(string)
 273            string.to_s.underscore
 274          end
 275 
 276          def installed?
 277            path_match = Regexp.compile("(^|/|\\\\)#{extension_name}$")
 278            extension_paths.any? {|p| p =~ path_match }
 279          end
 280 
 281          def registered?
 282            self.extension
 283          end
 284 
 285          def extension_paths
 286            paths = [RAILS_ROOT, RADIANT_ROOT].uniq.map { |p| Dir["#{p}/vendor/extensions/*"] }
 287            paths.unshift Dir["#{RADIANT_ROOT}/test/fixtures/extensions/*"] if RAILS_ENV == 'test'    #nasty
 288            paths.flatten
 289          end
 290 
 291          def load_extensions
 292            Registry::Extension.find(:all)
 293          end
 294 
 295          def find_extension
 296            self.extension = load_extensions.find{|e| e.name == self.extension_name }
 297          end
 298        end
 299 
 300        class Install
 301          include Util
 302 
 303          def initialize(args=[])
 304            raise ArgumentError, "You must specify an extension to install." if args.blank?
 305            self.extension_name = to_extension_name(args.shift)
 306            if installed?
 307              puts "#{extension_name} is already installed."
 308            else
 309              find_extension
 310              if registered?
 311                extension.install
 312              else
 313                raise ArgumentError, "#{extension_name} is not available in the registry."
 314              end
 315            end
 316          end
 317        end
 318 
 319        class Uninstall
 320          include Util
 321 
 322          def initialize(args=[])
 323            raise ArgumentError, "You must specify an extension to uninstall." if args.blank?
 324            self.extension_name = to_extension_name(args.shift)
 325            if installed?
 326              find_extension && extension.uninstall
 327            else
 328              puts "#{extension_name} is not installed."
 329            end
 330          end
 331        end
 332 
 333        class Info
 334          include Util
 335 
 336          def initialize(args=[])
 337            raise ArgumentError, "You must specify an extension to get info on" if args.blank?
 338            self.extension_name = to_extension_name(args.shift)
 339            find_extension and puts extension.inspect
 340          end
 341        end
 342 
 343        class Help
 344          def initialize(args=[])
 345            command = args.shift
 346            command = 'help' unless self.class.instance_methods(false).collect {|im| im.to_s}.include?(command.to_s)
 347            send(command)
 348          end
 349 
 350          def help
 351            $stdout.puts %{Usage:   script/extension command [arguments]
 352 
 353    Available commands:
 354        #{command_names}
 355 
 356    For help on an individual command:
 357        script/extension help command
 358        
 359    You may install extensions from another registry by setting the REGISTRY_URL
 360    By default the REGISTRY_URL is set to http://ext.radiantcms.org
 361    
 362    Code for the registry application may be found at:
 363    http://github.com/radiant/radiant-extension-registry/
 364              }
 365          end
 366 
 367          def install
 368            $stdout.puts %{Usage:    script/extension install extension_name
 369 
 370    Installs an extension from information in the global registry.
 371            }
 372          end
 373 
 374          def uninstall
 375            $stdout.puts %{Usage:    script/extension uninstall extension_name
 376 
 377    Removes a previously installed extension from the current project.
 378              }
 379          end
 380 
 381          def info
 382            $stdout.puts %{Usage:    script/extension info extension_name
 383 
 384    Displays registry information about the extension.
 385            }
 386          end
 387 
 388          private
 389            def command_names
 390              (Radiant::Extension::Script.constants - ['Util']).sort.map {|n| n.to_s.underscore }.join(", ")
 391            end
 392        end
 393      end
 394    end
 395  end