snapgit 0.6.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. checksums.yaml +7 -0
  2. data/.coveralls.yml +1 -0
  3. data/.editorconfig +17 -0
  4. data/.gitattributes +1 -0
  5. data/.gitignore +14 -0
  6. data/.rubocop.yml +10 -0
  7. data/.rubocop_todo.yml +57 -0
  8. data/.travis.yml +42 -0
  9. data/Gemfile +4 -0
  10. data/LICENSE +165 -0
  11. data/README.md +28 -0
  12. data/Rakefile +79 -0
  13. data/bin/lolcommits +335 -0
  14. data/bin/snapgit +14 -0
  15. data/config/cucumber.yml +2 -0
  16. data/features/bugs.feature +63 -0
  17. data/features/lolcommits.feature +286 -0
  18. data/features/plugins.feature +20 -0
  19. data/features/step_definitions/lolcommits_steps.rb +142 -0
  20. data/features/support/env.rb +61 -0
  21. data/features/support/path_helpers.rb +39 -0
  22. data/lib/core_ext/class.rb +8 -0
  23. data/lib/core_ext/mini_magick/utilities.rb +15 -0
  24. data/lib/lolcommits.rb +34 -0
  25. data/lib/lolcommits/capturer.rb +24 -0
  26. data/lib/lolcommits/capturer/capture_cygwin.rb +22 -0
  27. data/lib/lolcommits/capturer/capture_fake.rb +9 -0
  28. data/lib/lolcommits/capturer/capture_linux.rb +45 -0
  29. data/lib/lolcommits/capturer/capture_linux_animated.rb +72 -0
  30. data/lib/lolcommits/capturer/capture_mac.rb +23 -0
  31. data/lib/lolcommits/capturer/capture_mac_animated.rb +73 -0
  32. data/lib/lolcommits/capturer/capture_windows.rb +22 -0
  33. data/lib/lolcommits/cli/fatals.rb +77 -0
  34. data/lib/lolcommits/cli/launcher.rb +29 -0
  35. data/lib/lolcommits/cli/process_runner.rb +48 -0
  36. data/lib/lolcommits/cli/timelapse_gif.rb +45 -0
  37. data/lib/lolcommits/configuration.rb +138 -0
  38. data/lib/lolcommits/git_info.rb +82 -0
  39. data/lib/lolcommits/init.rb +121 -0
  40. data/lib/lolcommits/installation.rb +128 -0
  41. data/lib/lolcommits/platform.rb +127 -0
  42. data/lib/lolcommits/plugin.rb +130 -0
  43. data/lib/lolcommits/plugins/dot_com.rb +50 -0
  44. data/lib/lolcommits/plugins/lol_protonet.rb +68 -0
  45. data/lib/lolcommits/plugins/lol_slack.rb +68 -0
  46. data/lib/lolcommits/plugins/lol_tumblr.rb +127 -0
  47. data/lib/lolcommits/plugins/lol_twitter.rb +155 -0
  48. data/lib/lolcommits/plugins/lol_yammer.rb +85 -0
  49. data/lib/lolcommits/plugins/lolsrv.rb +59 -0
  50. data/lib/lolcommits/plugins/loltext.rb +147 -0
  51. data/lib/lolcommits/plugins/snapgit.rb +167 -0
  52. data/lib/lolcommits/plugins/tranzlate.rb +115 -0
  53. data/lib/lolcommits/plugins/uploldz.rb +65 -0
  54. data/lib/lolcommits/runner.rb +134 -0
  55. data/lib/lolcommits/version.rb +5 -0
  56. data/snapgit.gemspec +63 -0
  57. data/test/images/test_image.jpg +0 -0
  58. data/test/lolcommits_test.rb +35 -0
  59. data/test/plugins_test.rb +52 -0
  60. data/vendor/ext/CommandCam/COPYING +674 -0
  61. data/vendor/ext/CommandCam/CommandCam.exe +0 -0
  62. data/vendor/ext/CommandCam/LICENSE +16 -0
  63. data/vendor/ext/imagesnap/ReadMeOrDont.rtf +117 -0
  64. data/vendor/ext/imagesnap/imagesnap +0 -0
  65. data/vendor/ext/videosnap/videosnap +0 -0
  66. data/vendor/fonts/Lato.ttf +0 -0
  67. data/vendor/logos/Snapgit.png +0 -0
  68. metadata +509 -0
@@ -0,0 +1,61 @@
1
+ # -*- encoding : utf-8 -*-
2
+ require 'aruba/cucumber'
3
+ require 'methadone/cucumber'
4
+ require 'open3'
5
+ require 'ffaker'
6
+ require 'fileutils'
7
+
8
+ require File.join(File.expand_path(File.dirname(__FILE__)), 'path_helpers')
9
+ include Lolcommits
10
+
11
+ World(PathHelpers)
12
+
13
+ Before do
14
+ # Using "announce" causes massive warnings on 1.9.2
15
+ @puts = true
16
+ @aruba_timeout_seconds = 20
17
+
18
+ # prevent launchy from opening gifs in tests
19
+ set_env 'LAUNCHY_DRY_RUN', 'true'
20
+ set_env 'LOLCOMMITS_CAPTURER', 'CaptureFake'
21
+
22
+ author_name = 'Testy McTesterson'
23
+ author_email = 'testy@tester.com'
24
+
25
+ set_env 'GIT_AUTHOR_NAME', author_name
26
+ set_env 'GIT_COMMITTER_NAME', author_name
27
+ set_env 'GIT_AUTHOR_EMAIL', author_email
28
+ set_env 'GIT_COMMITTER_EMAIL', author_email
29
+ end
30
+
31
+ # for tasks that may take an insanely long time (e.g. network related)
32
+ # we should strive to not have any of these in our scenarios, naturally.
33
+ Before('@slow_process') do
34
+ @aruba_io_wait_seconds = 5
35
+ @aruba_timeout_seconds = 60
36
+ end
37
+
38
+ # in order to fake an interactive rebase, we replace the editor with a script
39
+ # to simply squash a few random commits. in this case, using lines 3-5.
40
+ Before('@fake-interactive-rebase') do
41
+ set_env 'GIT_EDITOR', "sed -i -e '3,5 s/pick/squash/g'"
42
+ end
43
+
44
+ # adjust the path so tests dont see a global imagemagick install
45
+ Before('@fake-no-imagemagick') do
46
+ reject_paths_with_cmd('mogrify')
47
+ end
48
+
49
+ # adjust the path so tests dont see a global ffmpeg install
50
+ Before('@fake-no-ffmpeg') do
51
+ reject_paths_with_cmd('ffmpeg')
52
+ end
53
+
54
+ # do test in temporary directory so our own git repo-ness doesn't affect it
55
+ Before('@in-tempdir') do
56
+ @dirs = [Dir.mktmpdir]
57
+ end
58
+
59
+ After('@in-tempdir') do
60
+ FileUtils.rm_rf(@dirs.first)
61
+ end
@@ -0,0 +1,39 @@
1
+ # -*- encoding : utf-8 -*-
2
+ require 'fileutils'
3
+ require 'aruba/api'
4
+ require 'lolcommits/platform'
5
+
6
+ module PathHelpers
7
+ def reject_paths_with_cmd(cmd)
8
+ # make a new subdir that still contains cmds
9
+ tmpbindir = File.expand_path(File.join(@dirs, 'bin'))
10
+ FileUtils.mkdir_p tmpbindir
11
+
12
+ preseve_cmds_in_path(%w(git mplayer), tmpbindir)
13
+
14
+ exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : ['']
15
+ newpaths = ENV['PATH'].split(File::PATH_SEPARATOR).reject do |path|
16
+ found_cmd = false
17
+ exts.each do |ext|
18
+ exe = "#{path}/#{cmd}#{ext}"
19
+ found_cmd = true if File.executable? exe
20
+ end
21
+ found_cmd
22
+ end
23
+
24
+ # add the temporary directory with git in it back into the path
25
+ newpaths << tmpbindir
26
+
27
+ # use aruba/api set_env to set PATH, which will be automaticaly restored
28
+ set_env 'PATH', newpaths.join(File::PATH_SEPARATOR)
29
+ end
30
+
31
+ def preseve_cmds_in_path(cmds, tmpbindir)
32
+ cmds.each do |cmd|
33
+ whichcmd = Lolcommits::Platform.command_which(cmd)
34
+ unless whichcmd.nil?
35
+ FileUtils.ln_s whichcmd, File.join(tmpbindir, File.basename(whichcmd))
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,8 @@
1
+ # -*- encoding : utf-8 -*-
2
+ class Class
3
+ def subclasses
4
+ result = []
5
+ ObjectSpace.each_object(Class) { |klass| result << klass if klass < self }
6
+ result
7
+ end
8
+ end
@@ -0,0 +1,15 @@
1
+ # -*- encoding : utf-8 -*-
2
+ # To maintain MiniMagick compatibility on Windows for v3.8.1 we need this patch
3
+ # If/when we upgrade MiniMagick to 4.2+ this patch can be removed
4
+ # We are locked at v3.8.1 since MiniMagick 4+ dropped support for Ruby 1.8.7
5
+ module MiniMagick
6
+ module Utilities
7
+ class << self
8
+ # fixes issue introduced in this commit
9
+ # https://github.com/minimagick/minimagick/commit/65b6427395cbfe6
10
+ def windows_escape(cmdline)
11
+ '"' + cmdline.gsub(/\\(?=\\*\")/, '\\\\\\').gsub(/\"/, '\\"').gsub(/\\$/, '\\\\\\').gsub('%', '%%') + '"'
12
+ end
13
+ end
14
+ end
15
+ end
data/lib/lolcommits.rb ADDED
@@ -0,0 +1,34 @@
1
+ # -*- encoding : utf-8 -*-
2
+ $LOAD_PATH.unshift File.expand_path('.')
3
+
4
+ require 'core_ext/class'
5
+ require 'mini_magick'
6
+ require 'core_ext/mini_magick/utilities'
7
+ require 'fileutils'
8
+ require 'git'
9
+ require 'open3'
10
+ require 'methadone'
11
+ require 'date'
12
+
13
+ require 'lolcommits/version'
14
+ require 'lolcommits/configuration'
15
+ require 'lolcommits/capturer'
16
+ require 'lolcommits/git_info'
17
+ require 'lolcommits/installation'
18
+ require 'lolcommits/plugin'
19
+ require 'lolcommits/platform'
20
+
21
+ require 'lolcommits/plugins/loltext'
22
+ require 'lolcommits/plugins/dot_com'
23
+ require 'lolcommits/plugins/tranzlate'
24
+ require 'lolcommits/plugins/lol_twitter'
25
+ require 'lolcommits/plugins/uploldz'
26
+ require 'lolcommits/plugins/lolsrv'
27
+ require 'lolcommits/plugins/lol_yammer'
28
+ require 'lolcommits/plugins/lol_protonet'
29
+ require 'lolcommits/plugins/lol_tumblr'
30
+ require 'lolcommits/plugins/lol_slack'
31
+ require 'lolcommits/plugins/snapgit'
32
+
33
+ # require runner after all the plugins have been required
34
+ require 'lolcommits/runner'
@@ -0,0 +1,24 @@
1
+ # -*- encoding : utf-8 -*-
2
+ module Lolcommits
3
+ class Capturer
4
+ include Methadone::CLILogging
5
+
6
+ attr_accessor :capture_device, :capture_delay, :snapshot_location,
7
+ :video_location, :frames_location, :animated_duration
8
+
9
+ def initialize(attributes = {})
10
+ attributes.each do |attr, val|
11
+ send("#{attr}=", val)
12
+ end
13
+ debug 'Capturer: initializing new instance ' + to_s
14
+ end
15
+ end
16
+ end
17
+
18
+ require 'lolcommits/capturer/capture_mac'
19
+ require 'lolcommits/capturer/capture_mac_animated'
20
+ require 'lolcommits/capturer/capture_linux'
21
+ require 'lolcommits/capturer/capture_linux_animated'
22
+ require 'lolcommits/capturer/capture_windows'
23
+ require 'lolcommits/capturer/capture_cygwin'
24
+ require 'lolcommits/capturer/capture_fake'
@@ -0,0 +1,22 @@
1
+ # -*- encoding : utf-8 -*-
2
+ module Lolcommits
3
+ class CaptureCygwin < Capturer
4
+ def capture
5
+ # DirectShow takes a while to show... at least for me anyway
6
+ delaycmd = ' /delay 3000'
7
+ if capture_delay > 0
8
+ # CommandCam delay is in milliseconds
9
+ delaycmd = " /delay #{capture_delay * 1000}"
10
+ end
11
+
12
+ _stdin, stdout, _stderr = Open3.popen3("#{executable_path} /filename `cygpath -w #{snapshot_location}`#{delaycmd}")
13
+
14
+ # looks like we still need to read the output for something to happen
15
+ stdout.read
16
+ end
17
+
18
+ def executable_path
19
+ File.join(Configuration::LOLCOMMITS_ROOT, 'vendor', 'ext', 'CommandCam', 'CommandCam.exe')
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,9 @@
1
+ # -*- encoding : utf-8 -*-
2
+ module Lolcommits
3
+ class CaptureFake < Capturer
4
+ def capture
5
+ test_image = File.join Configuration::LOLCOMMITS_ROOT, 'test', 'images', 'test_image.jpg'
6
+ FileUtils.cp test_image, snapshot_location
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,45 @@
1
+ # -*- encoding : utf-8 -*-
2
+ module Lolcommits
3
+ class CaptureLinux < Capturer
4
+ MPLAYER_FPS = 25
5
+
6
+ def capture_device_string
7
+ @capture_device.nil? ? nil : "-tv device=\"#{@capture_device}\""
8
+ end
9
+
10
+ def capture
11
+ debug 'LinuxCapturer: making tmp directory'
12
+ tmpdir = Dir.mktmpdir
13
+
14
+ # Default delay is 1s
15
+ delay = capture_delay != 0 ? capture_delay : 1
16
+
17
+ # There's no way to give a capture delay in mplayer, but a number of frame
18
+ # mplayer's "delay" is actually a number of frames at 25 fps
19
+ # multiply the set value (in seconds) by 25
20
+ frames = delay.to_i * MPLAYER_FPS
21
+
22
+ debug 'LinuxCapturer: calling out to mplayer to capture image'
23
+ # mplayer's output is ugly and useless, let's throw it away
24
+ _stdin, stdout, _stderr = Open3.popen3("mplayer -vo jpeg:outdir=#{tmpdir} #{capture_device_string} -frames #{frames} -fps #{MPLAYER_FPS} tv://")
25
+ # looks like we still need to read the output for something to happen
26
+ stdout.read
27
+
28
+ debug 'LinuxCapturer: calling out to mplayer to capture image'
29
+
30
+ # get last frame from tmpdir (regardless of fps)
31
+ all_frames = Dir.glob("#{tmpdir}/*.jpg").sort_by do |f|
32
+ File.mtime(f)
33
+ end
34
+
35
+ if all_frames.empty?
36
+ debug 'LinuxCapturer: failed to capture any image'
37
+ else
38
+ FileUtils.mv(all_frames.last, snapshot_location)
39
+ debug 'LinuxCapturer: cleaning up'
40
+ end
41
+
42
+ FileUtils.rm_rf(tmpdir)
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,72 @@
1
+ # -*- encoding : utf-8 -*-
2
+ module Lolcommits
3
+ class CaptureLinuxAnimated < Capturer
4
+ def capture
5
+ # make a fresh frames directory
6
+ FileUtils.rm_rf(frames_location)
7
+ FileUtils.mkdir_p(frames_location)
8
+
9
+ # capture the raw video with ffmpeg video4linux2
10
+ system_call "ffmpeg -v quiet -y -f video4linux2 -video_size 320x240 -i #{capture_device_string} -t #{capture_duration} \"#{video_location}\" > /dev/null"
11
+ return unless File.exist?(video_location)
12
+ # convert raw video to png frames with ffmpeg
13
+ system_call "ffmpeg #{capture_delay_string} -v quiet -i \"#{video_location}\" -t #{animated_duration} \"#{frames_location}/%09d.png\" > /dev/null"
14
+
15
+ # use fps to set delay and number of frames to skip (for lower filesized gifs)
16
+ fps = video_fps(video_location)
17
+ skip = frame_skip(fps)
18
+ delay = frame_delay(fps, skip)
19
+ debug "Capturer: anaimated gif choosing every #{skip} frames with a frame delay of #{delay}"
20
+
21
+ # create the looping animated gif from frames (picks nth frame with seq,
22
+ # quotes output and concats to a single line with tr)
23
+ seq_command = "seq -f \"\\\"#{frames_location}/%09g.png\\\"\" 1 #{skip} #{Dir["#{frames_location}/*"].length} | tr '\\n' ' '"
24
+ seq_frame_files = system_call(seq_command, true)
25
+ # convert to animated gif with delay and gif optimisation
26
+ system_call "convert -layers OptimizeTransparency -delay #{delay} -loop 0 #{seq_frame_files} -coalesce \"#{snapshot_location}\""
27
+ end
28
+
29
+ private
30
+
31
+ def system_call(call_str, capture_output = false)
32
+ debug "Capturer: making system call for \n #{call_str}"
33
+ capture_output ? `#{call_str}` : system(call_str)
34
+ end
35
+
36
+ def frame_delay(fps, skip)
37
+ # calculate frame delay
38
+ delay = ((100.0 * skip) / fps.to_f).to_i
39
+ delay < 6 ? 6 : delay # hard limit for IE browsers
40
+ end
41
+
42
+ def video_fps(file)
43
+ # inspect fps of the captured video file (default to 29.97)
44
+ fps = system_call("ffmpeg -i \"#{file}\" 2>&1 | sed -n \"s/.*, \\(.*\\) fp.*/\\1/p\"", true)
45
+ fps.to_i < 1 ? 29.97 : fps.to_f
46
+ end
47
+
48
+ def frame_skip(fps)
49
+ # of frames to skip depends on movie fps
50
+ case fps
51
+ when 0..15
52
+ 2
53
+ when 16..28
54
+ 3
55
+ else
56
+ 4
57
+ end
58
+ end
59
+
60
+ def capture_device_string
61
+ capture_device || '/dev/video0'
62
+ end
63
+
64
+ def capture_delay_string
65
+ " -ss #{capture_delay}" if capture_delay.to_i > 0
66
+ end
67
+
68
+ def capture_duration
69
+ animated_duration.to_i + capture_delay.to_i
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,23 @@
1
+ # -*- encoding : utf-8 -*-
2
+ module Lolcommits
3
+ class CaptureMac < Capturer
4
+ def capture_device_string
5
+ @capture_device.nil? ? nil : "-d \"#{@capture_device}\""
6
+ end
7
+
8
+ def capture
9
+ # TODO: check we have a webcam we can capture from first. See issue #219
10
+ # operating laptop in clamshell (lid closed) from 2nd desktop screen,
11
+ # needs to better handle the capturer (imagesnap, videosnap
12
+ # CommandCam, mplayer) return code or check with an option before
13
+ # attempting capture. Alt solution is puttin in prompt mode option :(
14
+ call_str = "#{executable_path} -q \"#{snapshot_location}\" -w #{capture_delay} #{capture_device_string}"
15
+ debug "Capturer: making system call for #{call_str}"
16
+ system(call_str)
17
+ end
18
+
19
+ def executable_path
20
+ File.join(Configuration::LOLCOMMITS_ROOT, 'vendor', 'ext', 'imagesnap', 'imagesnap')
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,73 @@
1
+ # -*- encoding : utf-8 -*-
2
+ module Lolcommits
3
+ class CaptureMacAnimated < Capturer
4
+ def capture
5
+ # make a fresh frames directory
6
+ FileUtils.rm_rf(frames_location)
7
+ FileUtils.mkdir_p(frames_location)
8
+
9
+ # capture the raw video with videosnap
10
+ system_call "#{executable_path} -s 240 #{capture_device_string}#{capture_delay_string}-t #{animated_duration} --no-audio \"#{video_location}\" > /dev/null"
11
+ return unless File.exist?(video_location)
12
+ # get fps for ffmpeg output stream configuration
13
+ fps = video_fps(video_location)
14
+ # convert raw video to png frames with ffmpeg
15
+ system_call "ffmpeg -v quiet -i \"#{video_location}\" -t #{animated_duration} -r #{fps} \"#{frames_location}/%09d.png\""
16
+
17
+ # use fps to set delay and number of frames to skip (for lower filesized gifs)
18
+ skip = frame_skip(fps)
19
+ delay = frame_delay(fps, skip)
20
+ debug "Capturer: animated gif choosing every #{skip} frames with a frame delay of #{delay}"
21
+
22
+ # create the looping animated gif from frames (picks nth frame with seq,
23
+ # quotes output and concats to a single line with tr)
24
+ seq_command = "seq -f \"\\\"#{frames_location}/%09g.png\\\"\" 1 #{skip} #{Dir["#{frames_location}/*"].length} | tr '\\n' ' '"
25
+ seq_frame_files = system_call(seq_command, true)
26
+ # convert to animated gif with delay and gif optimisation
27
+ system_call "convert -layers OptimizeTransparency -delay #{delay} -loop 0 #{seq_frame_files} -coalesce \"#{snapshot_location}\" > /dev/null"
28
+ end
29
+
30
+ def executable_path
31
+ File.join(Configuration::LOLCOMMITS_ROOT, 'vendor', 'ext', 'videosnap', 'videosnap')
32
+ end
33
+
34
+ private
35
+
36
+ def system_call(call_str, capture_output = false)
37
+ debug "Capturer: making system call for \n #{call_str}"
38
+ capture_output ? `#{call_str}` : system(call_str)
39
+ end
40
+
41
+ def frame_delay(fps, skip)
42
+ # calculate frame delay
43
+ delay = ((100.0 * skip) / fps.to_f).to_i
44
+ delay < 6 ? 6 : delay # hard limit for IE browsers
45
+ end
46
+
47
+ def video_fps(file)
48
+ # inspect fps of the captured video file (default to 29.97)
49
+ fps = system_call("ffmpeg -i \"#{file}\" 2>&1 | sed -n \"s/.*, \\(.*\\) fp.*/\\1/p\"", true)
50
+ fps.to_i < 1 ? 29.97 : fps.to_f
51
+ end
52
+
53
+ def frame_skip(fps)
54
+ # of frames to skip depends on movie fps
55
+ case fps
56
+ when 0..15
57
+ 2
58
+ when 16..28
59
+ 3
60
+ else
61
+ 4
62
+ end
63
+ end
64
+
65
+ def capture_device_string
66
+ "-d \"#{capture_device}\" " if capture_device
67
+ end
68
+
69
+ def capture_delay_string
70
+ "-w \"#{capture_delay}\" " if capture_delay.to_i > 0
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,22 @@
1
+ # -*- encoding : utf-8 -*-
2
+ module Lolcommits
3
+ class CaptureWindows < Capturer
4
+ def capture
5
+ # DirectShow takes a while to show... at least for me anyway
6
+ delaycmd = ' /delay 3000'
7
+ if capture_delay > 0
8
+ # CommandCam delay is in milliseconds
9
+ delaycmd = " /delay #{capture_delay * 1000}"
10
+ end
11
+
12
+ _stdin, stdout, _stderr = Open3.popen3("#{executable_path} /filename #{snapshot_location}#{delaycmd}")
13
+
14
+ # looks like we still need to read the output for something to happen
15
+ stdout.read
16
+ end
17
+
18
+ def executable_path
19
+ File.join(Configuration::LOLCOMMITS_ROOT, 'vendor', 'ext', 'CommandCam', 'CommandCam.exe')
20
+ end
21
+ end
22
+ end