chili_videos 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. data.tar.gz.sig +1 -0
  2. data/.autotest +5 -0
  3. data/Gemfile +13 -0
  4. data/Gemfile.lock +33 -0
  5. data/History.txt +4 -0
  6. data/LICENSE +20 -0
  7. data/Manifest.txt +63 -0
  8. data/README.md +169 -0
  9. data/Rakefile +45 -0
  10. data/app/controllers/videos_controller.rb +72 -0
  11. data/app/helpers/videos_helper.rb +34 -0
  12. data/app/models/assembly.rb +62 -0
  13. data/app/models/assembly_observer.rb +6 -0
  14. data/app/models/assembly_processor.rb +16 -0
  15. data/app/models/video.rb +24 -0
  16. data/app/views/settings/_settings.html.erb +13 -0
  17. data/app/views/videos/edit.html.erb +32 -0
  18. data/app/views/videos/index.html.erb +37 -0
  19. data/app/views/videos/new.html.erb +41 -0
  20. data/app/views/videos/plugin_not_configured.html.erb +6 -0
  21. data/app/views/videos/show.html.erb +40 -0
  22. data/app/views/videos/upload_complete.html.erb +7 -0
  23. data/assets/player.swf +0 -0
  24. data/assets/readme.html +84 -0
  25. data/assets/stylesheets/forms.css +7 -0
  26. data/assets/stylesheets/videos.css +76 -0
  27. data/assets/swfobject.js +8 -0
  28. data/assets/yt.swf +0 -0
  29. data/autotest/discover.rb +4 -0
  30. data/bin/delayed_job +23 -0
  31. data/config/locales/en.yml +15 -0
  32. data/config/routes.rb +3 -0
  33. data/db/migrate/20110301025054_create_videos.rb +15 -0
  34. data/db/migrate/20110309060901_create_assemblies.rb +14 -0
  35. data/db/migrate/20110314022354_create_delayed_jobs.rb +21 -0
  36. data/db/migrate/20110402043115_create_slugs.rb +18 -0
  37. data/db/migrate/20110402053931_add_slug_cache_to_videos.rb +11 -0
  38. data/init.rb +63 -0
  39. data/lang/en.yml +16 -0
  40. data/lib/chili_videos.rb +18 -0
  41. data/lib/chili_videos/config.rb +40 -0
  42. data/lib/chili_videos/error.rb +5 -0
  43. data/lib/tasks/chili_videos_tasks.rb +112 -0
  44. data/lib/tasks/contributor_tasks.rb +64 -0
  45. data/lib/tasks/delayed_job.rake +6 -0
  46. data/lib/tasks/friendly_id.rake +19 -0
  47. data/lib/video_project_patch.rb +10 -0
  48. data/lib/video_user_patch.rb +10 -0
  49. data/lib/video_version_patch.rb +9 -0
  50. data/rails/delayed_job +25 -0
  51. data/rails/init.rb +1 -0
  52. data/test/fixtures/incomplete_assembly.json +9 -0
  53. data/test/fixtures/single_video_processed_assembly.json +9 -0
  54. data/test/fixtures/standard_transloadit_response.json +6 -0
  55. data/test/functional/videos_controller_test.rb +232 -0
  56. data/test/integration/project_video_list_test.rb +104 -0
  57. data/test/integration/project_video_uploading_test.rb +56 -0
  58. data/test/integration/viewing_project_video_test.rb +74 -0
  59. data/test/test_helper.rb +77 -0
  60. data/test/unit/assembly_processor_test.rb +57 -0
  61. data/test/unit/assembly_test.rb +95 -0
  62. data/test/unit/chili_video_plugin/config_test.rb +49 -0
  63. data/test/unit/chili_video_plugin_test.rb +30 -0
  64. data/test/unit/video_test.rb +26 -0
  65. metadata +279 -0
  66. metadata.gz.sig +0 -0
@@ -0,0 +1,8 @@
1
+ /**
2
+ * SWFObject v1.5: Flash Player detection and embed - http://blog.deconcept.com/swfobject/
3
+ *
4
+ * SWFObject is (c) 2007 Geoff Stearns and is released under the MIT License:
5
+ * http://www.opensource.org/licenses/mit-license.php
6
+ *
7
+ */
8
+ if(typeof deconcept=="undefined"){var deconcept=new Object();}if(typeof deconcept.util=="undefined"){deconcept.util=new Object();}if(typeof deconcept.SWFObjectUtil=="undefined"){deconcept.SWFObjectUtil=new Object();}deconcept.SWFObject=function(_1,id,w,h,_5,c,_7,_8,_9,_a){if(!document.getElementById){return;}this.DETECT_KEY=_a?_a:"detectflash";this.skipDetect=deconcept.util.getRequestParameter(this.DETECT_KEY);this.params=new Object();this.variables=new Object();this.attributes=new Array();if(_1){this.setAttribute("swf",_1);}if(id){this.setAttribute("id",id);}if(w){this.setAttribute("width",w);}if(h){this.setAttribute("height",h);}if(_5){this.setAttribute("version",new deconcept.PlayerVersion(_5.toString().split(".")));}this.installedVer=deconcept.SWFObjectUtil.getPlayerVersion();if(!window.opera&&document.all&&this.installedVer.major>7){deconcept.SWFObject.doPrepUnload=true;}if(c){this.addParam("bgcolor",c);}var q=_7?_7:"high";this.addParam("quality",q);this.setAttribute("useExpressInstall",false);this.setAttribute("doExpressInstall",false);var _c=(_8)?_8:window.location;this.setAttribute("xiRedirectUrl",_c);this.setAttribute("redirectUrl","");if(_9){this.setAttribute("redirectUrl",_9);}};deconcept.SWFObject.prototype={useExpressInstall:function(_d){this.xiSWFPath=!_d?"expressinstall.swf":_d;this.setAttribute("useExpressInstall",true);},setAttribute:function(_e,_f){this.attributes[_e]=_f;},getAttribute:function(_10){return this.attributes[_10];},addParam:function(_11,_12){this.params[_11]=_12;},getParams:function(){return this.params;},addVariable:function(_13,_14){this.variables[_13]=_14;},getVariable:function(_15){return this.variables[_15];},getVariables:function(){return this.variables;},getVariablePairs:function(){var _16=new Array();var key;var _18=this.getVariables();for(key in _18){_16[_16.length]=key+"="+_18[key];}return _16;},getSWFHTML:function(){var _19="";if(navigator.plugins&&navigator.mimeTypes&&navigator.mimeTypes.length){if(this.getAttribute("doExpressInstall")){this.addVariable("MMplayerType","PlugIn");this.setAttribute("swf",this.xiSWFPath);}_19="<embed type=\"application/x-shockwave-flash\" src=\""+this.getAttribute("swf")+"\" width=\""+this.getAttribute("width")+"\" height=\""+this.getAttribute("height")+"\" style=\""+this.getAttribute("style")+"\"";_19+=" id=\""+this.getAttribute("id")+"\" name=\""+this.getAttribute("id")+"\" ";var _1a=this.getParams();for(var key in _1a){_19+=[key]+"=\""+_1a[key]+"\" ";}var _1c=this.getVariablePairs().join("&");if(_1c.length>0){_19+="flashvars=\""+_1c+"\"";}_19+="/>";}else{if(this.getAttribute("doExpressInstall")){this.addVariable("MMplayerType","ActiveX");this.setAttribute("swf",this.xiSWFPath);}_19="<object id=\""+this.getAttribute("id")+"\" classid=\"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000\" width=\""+this.getAttribute("width")+"\" height=\""+this.getAttribute("height")+"\" style=\""+this.getAttribute("style")+"\">";_19+="<param name=\"movie\" value=\""+this.getAttribute("swf")+"\" />";var _1d=this.getParams();for(var key in _1d){_19+="<param name=\""+key+"\" value=\""+_1d[key]+"\" />";}var _1f=this.getVariablePairs().join("&");if(_1f.length>0){_19+="<param name=\"flashvars\" value=\""+_1f+"\" />";}_19+="</object>";}return _19;},write:function(_20){if(this.getAttribute("useExpressInstall")){var _21=new deconcept.PlayerVersion([6,0,65]);if(this.installedVer.versionIsValid(_21)&&!this.installedVer.versionIsValid(this.getAttribute("version"))){this.setAttribute("doExpressInstall",true);this.addVariable("MMredirectURL",escape(this.getAttribute("xiRedirectUrl")));document.title=document.title.slice(0,47)+" - Flash Player Installation";this.addVariable("MMdoctitle",document.title);}}if(this.skipDetect||this.getAttribute("doExpressInstall")||this.installedVer.versionIsValid(this.getAttribute("version"))){var n=(typeof _20=="string")?document.getElementById(_20):_20;n.innerHTML=this.getSWFHTML();return true;}else{if(this.getAttribute("redirectUrl")!=""){document.location.replace(this.getAttribute("redirectUrl"));}}return false;}};deconcept.SWFObjectUtil.getPlayerVersion=function(){var _23=new deconcept.PlayerVersion([0,0,0]);if(navigator.plugins&&navigator.mimeTypes.length){var x=navigator.plugins["Shockwave Flash"];if(x&&x.description){_23=new deconcept.PlayerVersion(x.description.replace(/([a-zA-Z]|\s)+/,"").replace(/(\s+r|\s+b[0-9]+)/,".").split("."));}}else{if(navigator.userAgent&&navigator.userAgent.indexOf("Windows CE")>=0){var axo=1;var _26=3;while(axo){try{_26++;axo=new ActiveXObject("ShockwaveFlash.ShockwaveFlash."+_26);_23=new deconcept.PlayerVersion([_26,0,0]);}catch(e){axo=null;}}}else{try{var axo=new ActiveXObject("ShockwaveFlash.ShockwaveFlash.7");}catch(e){try{var axo=new ActiveXObject("ShockwaveFlash.ShockwaveFlash.6");_23=new deconcept.PlayerVersion([6,0,21]);axo.AllowScriptAccess="always";}catch(e){if(_23.major==6){return _23;}}try{axo=new ActiveXObject("ShockwaveFlash.ShockwaveFlash");}catch(e){}}if(axo!=null){_23=new deconcept.PlayerVersion(axo.GetVariable("$version").split(" ")[1].split(","));}}}return _23;};deconcept.PlayerVersion=function(_29){this.major=_29[0]!=null?parseInt(_29[0]):0;this.minor=_29[1]!=null?parseInt(_29[1]):0;this.rev=_29[2]!=null?parseInt(_29[2]):0;};deconcept.PlayerVersion.prototype.versionIsValid=function(fv){if(this.major<fv.major){return false;}if(this.major>fv.major){return true;}if(this.minor<fv.minor){return false;}if(this.minor>fv.minor){return true;}if(this.rev<fv.rev){return false;}return true;};deconcept.util={getRequestParameter:function(_2b){var q=document.location.search||document.location.hash;if(_2b==null){return q;}if(q){var _2d=q.substring(1).split("&");for(var i=0;i<_2d.length;i++){if(_2d[i].substring(0,_2d[i].indexOf("="))==_2b){return _2d[i].substring((_2d[i].indexOf("=")+1));}}}return "";}};deconcept.SWFObjectUtil.cleanupSWFs=function(){var _2f=document.getElementsByTagName("OBJECT");for(var i=_2f.length-1;i>=0;i--){_2f[i].style.display="none";for(var x in _2f[i]){if(typeof _2f[i][x]=="function"){_2f[i][x]=function(){};}}}};if(deconcept.SWFObject.doPrepUnload){if(!deconcept.unloadSet){deconcept.SWFObjectUtil.prepUnload=function(){__flash_unloadHandler=function(){};__flash_savedUnloadHandler=function(){};window.attachEvent("onunload",deconcept.SWFObjectUtil.cleanupSWFs);};window.attachEvent("onbeforeunload",deconcept.SWFObjectUtil.prepUnload);deconcept.unloadSet=true;}}if(!document.getElementById&&document.all){document.getElementById=function(id){return document.all[id];};}var getQueryParamValue=deconcept.util.getRequestParameter;var FlashObject=deconcept.SWFObject;var SWFObject=deconcept.SWFObject;
Binary file
@@ -0,0 +1,4 @@
1
+ Autotest.add_discovery do
2
+ "rails"
3
+ end
4
+
@@ -0,0 +1,23 @@
1
+ #!/usr/bin/env ruby
2
+ # -*- ruby -*-
3
+ require 'rubygems'
4
+ require 'daemon_spawn'
5
+
6
+ class DelayedJobWorker < DaemonSpawn::Base
7
+ def start(args)
8
+ ENV['RAILS_ENV'] ||= args.first || 'development'
9
+ Dir.chdir ENV['RAILS_ROOT']
10
+ require File.join('config', 'environment')
11
+
12
+ Delayed::Worker.new.start
13
+ end
14
+
15
+ def stop
16
+ system("kill `cat #{ENV['RAILS_ROOT']}/tmp/pids/delayed_job.pid`")
17
+ end
18
+ end
19
+
20
+ DelayedJobWorker.spawn!(:log_file => File.join(ENV['RAILS_ROOT'], "log", "delayed_job.log"),
21
+ :pid_file => File.join(ENV['RAILS_ROOT'], 'tmp', 'pids', 'delayed_job.pid'),
22
+ :sync_log => true,
23
+ :working_dir => ENV['RAILS_ROOT'])
@@ -0,0 +1,15 @@
1
+ # English strings go here for Rails i18n
2
+ en:
3
+ permission_view_video_list: View video list
4
+ permission_view_specific_video: View specific video
5
+ permission_modify_videos: Modify videos
6
+ permission_delete_video: Delete videos
7
+ permission_add_video: Add videos
8
+ transloadit_video_directions: Enter the Transload.it API key and the workflow you would like to use below.
9
+ transloadit_api_key_label: Transload.it API key
10
+ transloadit_workflow_label: Workflow
11
+ new_video_label: Add video
12
+ delete_video_label: Delete this video
13
+ edit_video_label: Edit this video
14
+ confirm_video_deletion: Are you sure you want to delete this video?
15
+ video_deleted_message: "Booyah! The requested video has been deleted."
@@ -0,0 +1,3 @@
1
+ ActionController::Routing::Routes.draw do |map|
2
+ map.resources :videos, :name_prefix => 'project_', :path_prefix => '/projects/:project_id', :collection => {:upload_complete => :get}
3
+ end
@@ -0,0 +1,15 @@
1
+ class CreateVideos < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :videos do |t|
4
+ t.column :title, :string
5
+ t.column :description, :text
6
+ t.column :url, :text
7
+ t.integer :project_id, :user_id, :version_id, :duration, :height, :width
8
+ t.timestamps
9
+ end
10
+ end
11
+
12
+ def self.down
13
+ drop_table :videos
14
+ end
15
+ end
@@ -0,0 +1,14 @@
1
+ class CreateAssemblies < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :assemblies do |t|
4
+ t.integer :project_id, :unsigned => true
5
+ t.integer :user_id, :unsigned => true
6
+ t.string :assembly_id, :assembly_url
7
+ t.boolean :processed
8
+ end
9
+ end
10
+
11
+ def self.down
12
+ drop_table :assemblies
13
+ end
14
+ end
@@ -0,0 +1,21 @@
1
+ class CreateDelayedJobs < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :delayed_jobs, :force => true do |table|
4
+ table.integer :priority, :default => 0 # Allows some jobs to jump to the front of the queue
5
+ table.integer :attempts, :default => 0 # Provides for retries, but still fail eventually.
6
+ table.text :handler # YAML-encoded string of the object that will do work
7
+ table.text :last_error # reason for last failure (See Note below)
8
+ table.datetime :run_at # When to run. Could be Time.zone.now for immediately, or sometime in the future.
9
+ table.datetime :locked_at # Set when a client is working on this object
10
+ table.datetime :failed_at # Set when all retries have failed (actually, by default, the record is deleted instead)
11
+ table.string :locked_by # Who is working on this object (if locked)
12
+ table.timestamps
13
+ end
14
+
15
+ add_index :delayed_jobs, [:priority, :run_at], :name => 'delayed_jobs_priority'
16
+ end
17
+
18
+ def self.down
19
+ drop_table :delayed_jobs
20
+ end
21
+ end
@@ -0,0 +1,18 @@
1
+ class CreateSlugs < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :slugs do |t|
4
+ t.string :name
5
+ t.integer :sluggable_id
6
+ t.integer :sequence, :null => false, :default => 1
7
+ t.string :sluggable_type, :limit => 40
8
+ t.string :scope
9
+ t.datetime :created_at
10
+ end
11
+ add_index :slugs, :sluggable_id
12
+ add_index :slugs, [:name, :sluggable_type, :sequence, :scope], :name => "index_slugs_on_n_s_s_and_s", :unique => true
13
+ end
14
+
15
+ def self.down
16
+ drop_table :slugs
17
+ end
18
+ end
@@ -0,0 +1,11 @@
1
+ class AddSlugCacheToVideos < ActiveRecord::Migration
2
+ def self.up
3
+ add_column :videos, :cached_slug, :string
4
+ add_index :videos, :cached_slug, :unique => true
5
+ end
6
+
7
+ def self.down
8
+ remove_index :videos, :column => :cached_slug
9
+ remove_column :videos, :cached_slug
10
+ end
11
+ end
data/init.rb ADDED
@@ -0,0 +1,63 @@
1
+ require 'redmine'
2
+ require 'chili_videos'
3
+
4
+ # Patches to the Redmine core.
5
+ require 'dispatcher'
6
+ require 'videos_helper'
7
+
8
+ Dispatcher.to_prepare :question_plugin do
9
+ require_dependency 'project'
10
+ Project.send(:include, VideoProjectPatch) unless Project.included_modules.include? VideoProjectPatch
11
+
12
+ require_dependency 'user'
13
+ User.send(:include, VideoUserPatch) unless User.included_modules.include? VideoUserPatch
14
+
15
+ require_dependency 'version'
16
+ Version.send(:include, VideoVersionPatch) unless Version.included_modules.include? VideoVersionPatch
17
+ end
18
+
19
+
20
+ Redmine::Plugin.register :chili_videos do
21
+ name 'Chili Videos plugin'
22
+ author 'Tom Kersten'
23
+ description 'Adds support for using the Transload.it service to transcode videos and associate them with projects.'
24
+ version ChiliVideos::VERSION
25
+ url 'http://example.com/path/to/plugin'
26
+ author_url 'http://tomkersten.com/'
27
+
28
+ project_module :videos do
29
+ permission :view_video_list, :videos => :index
30
+ permission :view_specific_video, :videos => :show
31
+ permission :modify_videos, :videos => [:edit,:update]
32
+ permission :delete_video, :videos => :destroy
33
+ permission :add_video, :videos => [:new, :create, :upload_complete]
34
+ end
35
+
36
+ settings :default => {:transloadit_api_key => '', :transloadit_workflow => ''}, :partial => 'settings/settings'
37
+
38
+ menu :project_menu, :videos, { :controller => 'videos', :action => 'index' }, :caption => 'Videos', :param => :project_id
39
+
40
+ ActiveRecord::Base.observers << :assembly_observer
41
+ end
42
+
43
+ Redmine::WikiFormatting::Macros.register do
44
+ desc "Embeds a flv file into flash video player.\n" +
45
+ "Usage examples:\n\n" +
46
+ " !{{video(id)}}\n"
47
+ macro :video do |o, args|
48
+ video_id = args[0]
49
+ size = args[1] || :standard
50
+
51
+ video = Video.find(video_id)
52
+ if video
53
+ file_url = video.url
54
+ else
55
+ file_url = "im_not_a_video"
56
+ end
57
+
58
+ <<END
59
+ <div class="video-cell large" id="video_#{video.to_param}"></div>
60
+ #{VideosHelper.video_embed_code(video, size)}
61
+ END
62
+ end
63
+ end
@@ -0,0 +1,16 @@
1
+
2
+
3
+ permission_view_video_list: View video list
4
+ permission_view_specific_video: View specific video
5
+ permission_modify_videos: Modify videos
6
+ permission_delete_video: Delete videos
7
+ permission_add_video: Add videos
8
+ transloadit_video_directions: Enter the Transload.it API key and the workflow you would like to use below.
9
+ transloadit_api_key_label: Transload.it API key
10
+ transloadit_workflow_label: Workflow
11
+ default_video_title: (none provided)
12
+ new_video_label: Add video
13
+ delete_video_label: Delete this video
14
+ edit_video_label: Edit this video
15
+ confirm_video_deletion: Are you sure you want to delete this video?
16
+ video_deleted_message: "Booyah! The requested video has been deleted."
@@ -0,0 +1,18 @@
1
+ require 'httparty'
2
+ require 'hashie'
3
+ require 'friendly_id'
4
+
5
+ require 'delayed_job'
6
+ Delayed::Worker.backend = :active_record
7
+
8
+ require 'chili_videos/config'
9
+
10
+ module ChiliVideos
11
+ extend self
12
+
13
+ VERSION = '0.1.0' unless defined?(ChiliVideos::VERSION)
14
+
15
+ def configured?
16
+ !Config.api_key.blank? && !Config.workflow.blank?
17
+ end
18
+ end
@@ -0,0 +1,40 @@
1
+ module ChiliVideos
2
+ module Config
3
+ extend self
4
+
5
+ PLUGIN_KEYNAME = 'plugin_chili_videos'
6
+ API_KEY_KEYNAME = 'transloadit_api_key'
7
+ WORKFLOW_KEYNAME = 'transloadit_workflow'
8
+
9
+ def api_key
10
+ plugin_settings[API_KEY_KEYNAME]
11
+ end
12
+
13
+ def workflow
14
+ plugin_settings[WORKFLOW_KEYNAME]
15
+ end
16
+
17
+ # Accepts anything which responds to '[]' and '.has_key?' # (Hash-like objects)
18
+ #
19
+ # Requires & utilizes the following keys
20
+ # - :api_key
21
+ # - :workflow
22
+ def update(options)
23
+ unless options.has_key?(:api_key) && options.has_key?(:workflow)
24
+ raise ArgumentError, "Missing key(s) in: #{options.inspect}"
25
+ end
26
+ Setting[PLUGIN_KEYNAME] = formatted_hash(options[:api_key], options[:workflow])
27
+ true
28
+ end
29
+
30
+ private
31
+ def plugin_settings
32
+ Setting[PLUGIN_KEYNAME]
33
+ end
34
+
35
+ def formatted_hash(api_key, workflow)
36
+ HashWithIndifferentAccess.new({API_KEY_KEYNAME => api_key,
37
+ WORKFLOW_KEYNAME => workflow})
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,5 @@
1
+ module ChiliVideos
2
+ module Error
3
+ class IncompleteAssembly < RuntimeError; end
4
+ end
5
+ end
@@ -0,0 +1,112 @@
1
+ require 'rake'
2
+ require 'rake/tasklib'
3
+
4
+ class ChiliVideosTasks < Rake::TaskLib
5
+ VALID_DJ_ACTIONS = %w(start restart stop status)
6
+
7
+ def initialize
8
+ define
9
+ end
10
+
11
+ def define
12
+ namespace :chili_videos do
13
+ desc "Install ChiliVideos plugin (migrate database, include assets, etc)"
14
+ task :install => [:migrate_db, :symlink_assets]
15
+
16
+ desc "Uninstalls ChiliVideos plugin (removes database modifications, removes assets, etc)"
17
+ task :uninstall => [:environment] do
18
+ puts "Removing ChiliVideos database modifications..."
19
+ migrate_db(:to_version => 0)
20
+
21
+ puts "Removing link to ChiliVideo assets (stylesheets, js, etc)..."
22
+ remove_symlink asset_destination_dir
23
+
24
+ puts post_uninstall_steps
25
+ end
26
+
27
+ desc "Manage delayed_job...requires argument [ACTION=(#{VALID_DJ_ACTIONS.join('|')})]"
28
+ task :delayed_job, :action, :needs => [:environment] do |task, args|
29
+ unless(args[:action] && VALID_DJ_ACTIONS.include?(args[:action]))
30
+ puts "'ACTION' is a required parameter. Valid values are: #{VALID_DJ_ACTIONS.join(', ')}"
31
+ exit(1)
32
+ end
33
+
34
+ shell_command = "RAILS_ROOT='#{application_root}' RAILS_ENV=#{RAILS_ENV} #{File.expand_path(delayed_job_path)} #{args[:action]}"
35
+ puts "Issuing '#{args[:action]}' command to delayed_job executable (bundled with ChiliVideos)"
36
+ sh shell_command do |ok, status|
37
+ ok || fail("Command failed (status: #{status}) (command: '#{shell_command}')")
38
+ end
39
+ end
40
+
41
+ task :migrate_db => [:environment] do
42
+ puts "Migrating chili_videos-#{ChiliVideos::VERSION}..."
43
+ ActiveRecord::Migration.verbose = ENV["VERBOSE"] ? ENV["VERBOSE"] == "true" : true
44
+ ActiveRecord::Migrator.migrate(gem_db_migrate_dir, ENV["VERSION"] ? ENV["VERSION"].to_i : nil)
45
+ Rake::Task["db:schema:dump"].invoke if ActiveRecord::Base.schema_format == :ruby
46
+ end
47
+
48
+ task :symlink_assets => [:environment] do
49
+ # HACK: Symlinks the files from plugindir/assets to the appropriate place in
50
+ # the rails application
51
+ puts "Symlinking assets (stylesheets, etc)..."
52
+ add_symlink asset_source_dir, asset_destination_dir
53
+ end
54
+ end
55
+ end
56
+
57
+ private
58
+ def application_root
59
+ File.expand_path(RAILS_ROOT)
60
+ end
61
+
62
+ def gem_root
63
+ @gem_root ||= File.expand_path(File.dirname(__FILE__) + "/../..")
64
+ end
65
+
66
+ def asset_destination_dir
67
+ @destination_dir ||= File.expand_path("#{application_root}/public/plugin_assets/chili_videos")
68
+ end
69
+
70
+ def asset_source_dir
71
+ @source_dir ||= File.expand_path(gem_root + "/assets")
72
+ end
73
+
74
+ def gem_db_migrate_dir
75
+ @gem_db_migrate_dir ||= File.expand_path(gem_root + "/db/migrate")
76
+ end
77
+
78
+ def delayed_job_path
79
+ @delayed_job_path ||= File.expand_path(gem_root + "/bin/delayed_job")
80
+ end
81
+
82
+ def remove_symlink(symlink_file)
83
+ system("unlink #{symlink_file}") if File.exists?(symlink_file)
84
+ end
85
+
86
+ def add_symlink(source, destination)
87
+ remove_symlink destination
88
+ system("ln -s #{source} #{destination}")
89
+ end
90
+
91
+ def migrate_db(options = {})
92
+ ActiveRecord::Migration.verbose = ENV["VERBOSE"] ? ENV["VERBOSE"] == "true" : true
93
+ ActiveRecord::Migrator.migrate(gem_db_migrate_dir, options[:to_version])
94
+ Rake::Task["db:schema:dump"].invoke if ActiveRecord::Base.schema_format == :ruby
95
+ end
96
+
97
+ def post_uninstall_steps
98
+ [
99
+ "!!!!! MANUAL STEPS !!!!!",
100
+ "\t1. In your 'config/environment.rb', remove:",
101
+ "\t\tconfig.gem 'chili_videos'",
102
+ "",
103
+ "\t2. In your 'Rakefile', remove:",
104
+ "\t\trequire 'chili_videos'",
105
+ "\t\trequire 'tasks/chili_videos_tasks'",
106
+ "\t\tChiliVideosTasks.new",
107
+ "",
108
+ "\t3. Cycle your application server (mongrel, unicorn, etc)",
109
+ "\n",
110
+ ].join("\n")
111
+ end
112
+ end
@@ -0,0 +1,64 @@
1
+ require 'rake'
2
+ require 'rake/tasklib'
3
+
4
+ class ContributorTasks < Rake::TaskLib
5
+ def initialize
6
+ define
7
+ end
8
+
9
+ def define
10
+ desc "Update contributors list in README"
11
+ task :update_contributors do
12
+ if new_contributors?
13
+ puts "New contributors!"
14
+ new_contributors.each {|name| puts "- #{name}"}
15
+ puts ""
16
+
17
+ print "Updating the 'Contributors' section of README..."
18
+
19
+ File.open("README.md", "w+") do |file|
20
+ file.puts readme_without_contributors_section
21
+ file.puts "## Contributors (sorted alphabetically)"
22
+ file.puts ""
23
+ committers.each {|name| file.puts "* #{name}"}
24
+ end
25
+ puts "done!"
26
+ else
27
+ puts "No new contributors."
28
+ end
29
+ end
30
+ end
31
+
32
+ private
33
+ def all_committers
34
+ all_names = `git shortlog -s |cut -s -f2`
35
+ all_names.gsub!(/\sand\s/, "\n").split("\n").uniq!.sort!
36
+ end
37
+
38
+ def committers
39
+ excluded_committers = ["Tom Kersten"]
40
+ @committers ||= all_committers - excluded_committers
41
+ end
42
+
43
+ def readme_file_contents
44
+ @readme_contents ||= `cat README.md`
45
+ end
46
+
47
+ def existing_contributors
48
+ existing_contributors = readme_file_contents[/## Contributors(.|\n)*/].strip.split("\n* ")
49
+ existing_contributors.shift # remove "Contributors..." line
50
+ existing_contributors
51
+ end
52
+
53
+ def new_contributors
54
+ @new_contributors ||= committers - existing_contributors
55
+ end
56
+
57
+ def new_contributors?
58
+ !new_contributors.empty?
59
+ end
60
+
61
+ def readme_without_contributors_section
62
+ readme_file_contents.sub(/## Contributors(.|\n)*/, '')
63
+ end
64
+ end