flick 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e81859ea546a01df31102f29fc4657df27c46fe0
4
- data.tar.gz: 9f1a43b57c5337fe732b01bdabec233a4cf0040c
3
+ metadata.gz: bb64107c4d21b8fc509321fdc0d98763e3e376e6
4
+ data.tar.gz: 154aa4c74efa4fead2f6cdd5880c7b71602607ed
5
5
  SHA512:
6
- metadata.gz: 5da1d5231a633095d3fe7cda6452d007d7c13e78f17ddee6939bc6427f1135909a544649a83285850f71cd06de4a43b7ade43c10bd463e493a9dad4cf7e14f8b
7
- data.tar.gz: 83780db9a51eb5ab0b50a0e812138e95082389ed5ddf197cc22bf000d62ed9575dc869bec50ebfbc11160640395cd68f72f0f25e04b1beca4ac87f5a6470072d
6
+ metadata.gz: 07dba93a03a97b5a725bc98afca7e3cda8c66138aab7ae1f15efaa6f3caf4a43a01599344117130f04f54391ef6c40629178b66e714c5693e0d1dacd7f026c43
7
+ data.tar.gz: 7e400657a20828488546d0229b251fe3bbe7a125c25aee55eb23aba1cc41fdc275b0d2aa6bd4c76c1c04295194e535fdd2bddab91a18486db83214081abd991e
data/README.md CHANGED
@@ -14,6 +14,7 @@ Features
14
14
  * Falls back to screenshot recording if video record is not available.
15
15
  * Video record android emulators and **real** iOS devices.
16
16
  * Takes a screenshot every 0.5 seconds (default), then combines the screenshots into a single mp4 or gif.
17
+ * Android pulls only unique (default) screenshots from devices/emulators. e.g. A 1 minute test run might convert to only 30 seconds of video based on unique images. You can change this by passing `-q false` to pull all images instead.
17
18
  * iOS example [here](https://www.dropbox.com/s/4pjhhmnsx9gj5pi/ios-flick-example.mp4?dl=0)
18
19
  * Android Emulator example [here](https://www.dropbox.com/s/gwunrvgzxkny13z/android-flick-example.mp4?dl=0)
19
20
  * Flick auto selects device when only one device is connected, per platform.
@@ -28,17 +29,24 @@ So I created Flick to work for my needs, and included a couple other tools I use
28
29
 
29
30
  If you're looking for high-quality video, then this wouldn't be the tool for you. Take a look at this great tool [androidtool-mac](https://github.com/mortenjust/androidtool-mac) instead.
30
31
 
31
- Prerequisites
32
+ Prerequisites
32
33
  -------------
33
34
  #### System Tools
34
35
  * Install ffmpeg. [OSX](https://trac.ffmpeg.org/wiki/CompilationGuide/MacOSX)
35
36
  * ```$ brew install ffmpeg```
37
+ * Install ffmpeg. [Windows](https://ffmpeg.zeranoe.com/builds/)
38
+ * Download either the 32-bit or 64-bit static versions.
39
+ * Extract the zip file and move the ffmpeg folder somewhere else.
40
+ * Add the ffmpeg bin location to your PATH user variables. e.g. C:\ffmpeg\bin
36
41
  * Install mp4box. [OSX](http://hunterford.me/compiling-mp4box-on-mac-os-x/)
37
42
  * ```$ brew install mp4box```
43
+ * Install mp4box. [Windows](http://www.videohelp.com/software/MP4Box)
44
+ * Run the gpac-0.6.2-DEV-rev634-gd2332cb-master-x(64 or 32 bit).exe
45
+ * Select to install only the MP4Box component.
38
46
 
39
47
  #### Android
40
48
  * Install [SDK Tools](http://developer.android.com/sdk/installing/index.html?pkg=tools).
41
- * SDK tools are added to your $PATH. [OSX](http://stackoverflow.com/questions/5526470/trying-to-add-adb-to-path-variable-osx)
49
+ * SDK tools are added to your $PATH. [OSX](http://stackoverflow.com/questions/5526470/trying-to-add-adb-to-path-variable-osx)
42
50
  * Enable [USB Debugging](https://www.kingoapp.com/root-tutorials/how-to-enable-usb-debugging-mode-on-android.htm) on your device(s).
43
51
  * Emulator or Devices have approximately 1GB of [sdcard space](http://developer.android.com/tools/help/mksdcard.html).
44
52
 
@@ -60,54 +68,55 @@ Usage:
60
68
  $ flick --help
61
69
 
62
70
  DESCRIPTION:
63
-
71
+
64
72
  A CLI to capture screenshots, video, logs, and device info for Android (Devices & Emulators) and iOS (Devices).
65
-
73
+
66
74
  COMMANDS:
67
-
68
- help Display global or [command] help documentation
69
- info Get device information
70
- log Get device log output
71
- screenshot Take a screenshot
72
- video Record video
73
-
75
+
76
+ help Display global or [command] help documentation
77
+ info Get device information
78
+ log Get device log output
79
+ screenshot Take a screenshot
80
+ video Record video
81
+
74
82
  GLOBAL OPTIONS:
75
-
76
- -h, --help
83
+
84
+ -h, --help
77
85
  Display help documentation
78
-
79
- -v, --version
86
+
87
+ -v, --version
80
88
  Display version information
81
-
82
- -t, --trace
89
+
90
+ -t, --trace
83
91
  Display backtrace when an error occurs
84
92
 
85
- * See usage examples in:
86
-
87
93
  `$ flick info --help`
88
-
94
+
89
95
  $ flick info -p (ios or android)
90
96
  $ flick info -p (ios or android) -s true -o $HOME
91
-
92
-
97
+
98
+
93
99
  `$ flick log --help`
94
-
100
+
95
101
  $ flick log -a start -p (ios or android) -o $HOME -n iosLog
96
102
  $ flick log -a stop -p (ios or android)
97
103
 
98
104
  `$ flick screenshot --help`
99
-
100
- $ flick screenshot -p (ios or android)
101
-
105
+
106
+ $ flick screenshot -p (ios or android) -o $HOME -n myImage
107
+
102
108
  `$ flick video --help`
103
-
109
+
104
110
  $ flick video -a start -p (ios or android)
105
111
  $ flick video -a stop -p (ios or android) -o /output -n myVideo -f gif
106
112
  $ flick video -a start -p android -u emulator-5554 -c 1000
107
113
  $ flick video -a stop -p android -u emulator-5554
108
114
 
109
- Demo
110
- ----
115
+ `$ flick manager --help`
116
+ $ flick manager -a install -p (ios or android) -f ~/myApp/my-awesome-app.apk or .app
117
+ $ flick maanger -a uninstall -p (ios or android) -n com.package.name
118
+
119
+ ##Demo
111
120
  <img src="https://www.dropbox.com/s/9be37gc1c2dlxa6/flick-demo.gif?raw=1" width="600">
112
121
 
113
122
  ## Contributing
@@ -119,7 +128,7 @@ Bug reports and pull requests are welcome on GitHub at https://github.com/isonic
119
128
  * Setup Flick android for cross platform os's (windows & linux)
120
129
  * Add screenshot capture for iOS Simulators.
121
130
  * Multithread the screenshot and pull process.
122
- * Look into capturing video from iOS similar to [this](https://github.com/mortenjust/androidtool-mac/blob/9347cd9aeca9e7370e323d12f862bc5d8beacc25/AndroidTool/IOSDeviceHelper.swift#L56)
131
+ * Look into capturing video for iOS similar to [this](https://github.com/mortenjust/androidtool-mac/blob/9347cd9aeca9e7370e323d12f862bc5d8beacc25/AndroidTool/IOSDeviceHelper.swift#L56)
123
132
 
124
133
  ## License
125
134
 
data/bin/flick CHANGED
@@ -28,7 +28,7 @@ command :video do |c|
28
28
  :unique => true, #defaults to pulling only unique screenshots. Speeds up pulling process from device.
29
29
  :format => "mp4",
30
30
  :outdir => Dir.pwd #defaults to save in current directory.
31
-
31
+
32
32
  Video.new(options.default).run
33
33
  end
34
34
  end
@@ -45,11 +45,11 @@ command :screenshot do |c|
45
45
  c.action do |args, options|
46
46
  options.default \
47
47
  :outdir => Dir.pwd #defaults to save in current directory.
48
-
48
+
49
49
  Screenshot.new(options.default).screenshot
50
50
  end
51
51
  end
52
-
52
+
53
53
  command :log do |c|
54
54
  c.syntax = 'flick log [options]'
55
55
  c.summary = 'Get device log output'
@@ -63,7 +63,7 @@ command :log do |c|
63
63
  c.action do |args, options|
64
64
  options.default \
65
65
  :outdir => Dir.pwd #defaults to save in current directory.
66
-
66
+
67
67
  Log.new(options.default).run
68
68
  end
69
69
  end
@@ -81,7 +81,23 @@ command :info do |c|
81
81
  options.default \
82
82
  :save => false,
83
83
  :outdir => Dir.pwd #defaults to save in current directory.
84
-
84
+
85
85
  Info.new(options.default).info
86
86
  end
87
+ end
88
+
89
+ command :manager do |c|
90
+ c.syntax = 'flick manager [options]'
91
+ c.summary = 'Manage apps on devices'
92
+ c.description = c.summary
93
+ c.example 'description', "flick manager -a install -p android -f ~/my-awesome-app.apk\n flick manager -a uninstall -p ios -n com.viber"
94
+ c.option '-a', '--action ACTION', String, 'Set action: install or uninstall'
95
+ c.option '-p', '--platform PLATFORM', String, 'Set platform: android or ios'
96
+ c.option '-u', '--udid UDID', String, 'Set device UDID.'
97
+ c.option '-f', '--file FILE', String, 'Set the apk or app file location path.'
98
+ c.option '-n', '--name NAME', String, 'Set the package name.'
99
+ c.action do |args, options|
100
+
101
+ Manager.new(options.default).run
102
+ end
87
103
  end
data/flick.gemspec CHANGED
@@ -24,7 +24,7 @@ Gem::Specification.new do |spec|
24
24
  spec.bindir = "bin"
25
25
  spec.executables = ["flick"]
26
26
  spec.require_paths = ["lib"]
27
-
27
+
28
28
  spec.add_development_dependency "bundler", "~> 1.10"
29
29
  spec.add_development_dependency "rake", "~> 10.0"
30
30
  spec.add_development_dependency "rspec", '~> 3.4', '>= 3.4.0'
@@ -34,4 +34,7 @@ Gem::Specification.new do |spec|
34
34
  spec.add_dependency "json", '~> 1.8', '>= 1.8.3'
35
35
  spec.add_dependency "wannabe_bool", "~> 0.5.0"
36
36
  spec.add_dependency "awesome_print", '~> 1.6', '>= 1.6.1'
37
+ spec.add_dependency "os", "~> 0.9.6"
38
+ spec.add_dependency "sys-proctable", '~> 1.1', '>= 1.1.1'
39
+ spec.add_dependency "apktools", '~> 0.7.1', '>= 0.7.1'
37
40
  end
data/lib/flick.rb CHANGED
@@ -3,6 +3,10 @@ require 'json'
3
3
  require 'parallel'
4
4
  require 'wannabe_bool'
5
5
  require 'awesome_print'
6
+ require 'os'
7
+ require 'tempfile'
8
+ require 'sys/proctable'
9
+ require 'apktools/apkxml'
6
10
 
7
11
  require "flick/version"
8
12
  require_relative "./flick/android"
@@ -13,4 +17,5 @@ require_relative "./flick/log"
13
17
  require_relative "./flick/screenshot"
14
18
  require_relative "./flick/simple_daemon"
15
19
  require_relative "./flick/system"
16
- require_relative "./flick/video"
20
+ require_relative "./flick/video"
21
+ require_relative "./flick/manager"
data/lib/flick/android.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  module Flick
2
2
  class Android
3
3
  attr_accessor :flick_dir, :dir_name, :udid, :name, :outdir, :unique, :limit, :specs
4
-
4
+
5
5
  def initialize options
6
6
  Flick::Checker.system_dependency "adb"
7
7
  self.flick_dir = "#{Dir.home}/.flick"
@@ -14,43 +14,43 @@ module Flick
14
14
  self.specs = options.fetch(:specs, false)
15
15
  create_flick_dirs
16
16
  end
17
-
17
+
18
18
  def create_flick_dirs
19
19
  Flick::System.setup_system_dir flick_dir
20
- %x(adb -s #{udid} shell 'mkdir #{dir_name}' >> /dev/null 2>&1)
20
+ %x(adb -s #{udid} shell 'mkdir #{dir_name}')
21
21
  end
22
-
22
+
23
23
  def clear_files
24
- %x(adb -s #{udid} shell rm '#{dir_name}/*' >> /dev/null 2>&1)
25
24
  Flick::System.clean_system_dir flick_dir, udid
25
+ %x(adb -s #{udid} shell rm '#{dir_name}/*')
26
26
  end
27
-
27
+
28
28
  def devices
29
29
  (`adb devices`).scan(/\n(.*)\t/).flatten
30
30
  end
31
-
31
+
32
32
  def devices_connected?
33
- !devices.empty?
33
+ devices.any?
34
34
  end
35
-
35
+
36
36
  def check_for_devices
37
37
  unless devices_connected?
38
- puts "\nNo Devices Connected or Authorized!!!\nMake sure at least one device (emulator/simulator) is started!\n".red
38
+ puts "\nNo Devices Connected or Authorized!!!\nMake sure at least one device (emulator/simulator) is connected!\n".red
39
39
  abort
40
40
  end
41
41
  end
42
-
42
+
43
43
  def get_device_udid opts_hash
44
44
  devices_connected?
45
45
  return unless opts_hash[:udid].nil?
46
46
  if devices.size == 1
47
- devices[0]
47
+ devices.first
48
48
  else
49
49
  puts "\nMultiple android devices '#{devices}' found.\nSpecify a single UDID. e.g. -u #{devices.sample}\n".red
50
50
  abort unless specs
51
51
  end
52
52
  end
53
-
53
+
54
54
  def info
55
55
  specs = { os: "ro.build.version.release", manufacturer: "ro.product.manufacturer", model: "ro.product.model", sdk: "ro.build.version.sdk" }
56
56
  hash = { udid: udid }
@@ -61,54 +61,85 @@ module Flick
61
61
  hash
62
62
  end
63
63
 
64
+ def install app_path
65
+ %x(adb -s #{udid} install -r #{app_path})
66
+ end
67
+
68
+ def uninstall package
69
+ if app_installed? package
70
+ %x(adb -s #{udid} shell pm uninstall #{package})
71
+ else
72
+ puts packages
73
+ puts "\n#{package} was not found on device #{udid}! Please choose one from above. e.g. #{packages.sample}\n".red
74
+ end
75
+ end
76
+
77
+ def app_version app_path
78
+ manifest(app_path).find {|x| x.name == "versionName" }["value"]
79
+ end
80
+
81
+ def package_name app_path
82
+ manifest(app_path).find {|x| x.name == "package" }["value"]
83
+ end
84
+
85
+ def manifest app_path
86
+ data = ApkXml.new app_path
87
+ data.parse_xml("AndroidManifest.xml", false, true)
88
+ data.xml_elements[0].attributes
89
+ end
90
+
91
+ def app_installed? package
92
+ packages.include? "package:#{package}"
93
+ end
94
+
95
+ def packages
96
+ %x(adb -s #{udid} shell pm list packages).split
97
+ end
98
+
64
99
  def os_version
65
- `adb -s #{udid} shell getprop "ro.build.version.release"`.strip.to_f
100
+ %x(adb -s #{udid} shell getprop "ro.build.version.release").strip.to_f
66
101
  end
67
-
102
+
68
103
  def screenshot name
69
104
  %x(adb -s #{udid} shell screencap #{dir_name}/#{name}.png)
70
105
  end
71
-
106
+
72
107
  def log name
73
108
  %x(adb -s #{udid} logcat -v long > #{outdir}/#{name}.log)
74
109
  end
75
-
110
+
76
111
  def recordable?
77
- (`adb -s #{udid} shell 'ls /system/bin/screenrecord'`).strip == "/system/bin/screenrecord"
112
+ %x(adb -s #{udid} shell "ls /system/bin/screenrecord").strip == "/system/bin/screenrecord"
78
113
  end
79
-
114
+
80
115
  def screenrecord name
81
116
  %x(adb -s #{udid} shell screenrecord --time-limit #{limit} --size 720x1280 #{dir_name}/#{name}.mp4)
82
117
  end
83
-
118
+
84
119
  def pull_file file, dir
85
- %x(adb -s #{udid} pull #{file} #{dir} >> /dev/null 2>&1)
120
+ %x(adb -s #{udid} pull #{file} #{dir})
86
121
  end
87
-
88
- def unique_files
122
+
123
+ def unique_files type
89
124
  if os_version < 6.0
90
125
  command = "md5"
91
126
  else
92
127
  command = "md5sum"
93
128
  end
94
- files = `adb -s #{udid} shell "#{command} #{dir_name}/#{udid}*"`
129
+ files = %x(adb -s #{udid} shell "#{command} #{dir_name}/#{type}-#{udid}*")
95
130
  hash = files.split("\r\n").map { |file| { md5: file.match(/(.*) /)[1].strip, file: file.match(/ (.*)/)[1].strip } }
96
131
  hash.uniq! { |e| e[:md5] }
97
132
  hash.map { |file| file[:file] }
98
133
  end
99
-
100
- def pull_files
134
+
135
+ def pull_files type
101
136
  if unique
102
- files = unique_files
137
+ files = unique_files type
103
138
  else
104
- files = (`adb -s #{udid} shell "ls #{dir_name}/#{udid}*"`).split("\r\n")
139
+ files = %x(adb -s #{udid} shell "ls #{dir_name}/#{type}-#{udid}*").split("\r\n")
105
140
  end
106
141
  return if files.empty?
107
142
  Parallel.map(files, in_threads: 10) { |file| pull_file file, flick_dir }
108
143
  end
109
-
110
- def screenshots_exist?
111
- (`adb -s #{udid} shell "ls #{dir_name}/#{udid}-*.png | wc -l"`).to_i > 0
112
- end
113
144
  end
114
145
  end
data/lib/flick/checker.rb CHANGED
@@ -1,13 +1,24 @@
1
1
  module Flick
2
2
  module Checker
3
+ def self.which(cmd)
4
+ exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : ['']
5
+ ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
6
+ exts.each { |ext|
7
+ exe = File.join(path, "#{cmd}#{ext}")
8
+ return exe if File.executable?(exe) && !File.directory?(exe)
9
+ }
10
+ end
11
+ return nil
12
+ end
13
+
3
14
  def self.system_dependency dep
4
- program = `which #{dep}`
15
+ program = self.which dep
5
16
  if program.empty?
6
17
  puts "\n#{dep} was not found. Please ensure you have installed #{dep} and it's in your $PATH\n".red
7
18
  abort
8
19
  end
9
20
  end
10
-
21
+
11
22
  def self.platform platform
12
23
  platforms = ["android","ios"]
13
24
  unless platforms.include? platform
@@ -15,7 +26,7 @@ module Flick
15
26
  abort
16
27
  end
17
28
  end
18
-
29
+
19
30
  def self.action action
20
31
  actions = ["start","stop"]
21
32
  unless actions.include? action
@@ -23,7 +34,22 @@ module Flick
23
34
  abort
24
35
  end
25
36
  end
26
-
37
+
38
+ def self.manager option
39
+ options = ["install","uninstall"]
40
+ unless options.include? option
41
+ puts "\nPlease specify a valid option #{options}. e.g. flick <job> -a #{options.sample} -p ios\n".red
42
+ abort
43
+ end
44
+ end
45
+
46
+ def self.file_exists? file
47
+ unless File.exists? file
48
+ puts "\n#{file} does not exist! Please specify a valid file path.".red
49
+ abort
50
+ end
51
+ end
52
+
27
53
  def self.format format
28
54
  formats = ["mp4","gif"]
29
55
  unless formats.include? format
data/lib/flick/ios.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  module Flick
2
2
  class Ios
3
3
  attr_accessor :flick_dir, :udid, :name, :outdir, :todir, :specs
4
-
4
+
5
5
  def initialize options
6
6
  Flick::Checker.system_dependency "idevice_id"
7
7
  self.flick_dir = "#{Dir.home}/.flick"
@@ -12,26 +12,26 @@ module Flick
12
12
  self.specs = options.fetch(:specs, false)
13
13
  create_flick_dirs
14
14
  end
15
-
15
+
16
16
  def create_flick_dirs
17
17
  Flick::System.setup_system_dir flick_dir
18
18
  end
19
-
19
+
20
20
  def devices
21
21
  (`idevice_id -l`).split.uniq.map { |d| d }
22
22
  end
23
-
23
+
24
24
  def devices_connected?
25
- !devices.empty?
25
+ devices.any?
26
26
  end
27
-
27
+
28
28
  def check_for_devices
29
29
  unless devices_connected?
30
30
  puts "\nNo iPhone or iPad Devices Connected!!!\nMake sure at least one REAL device is connected!\n".red
31
31
  abort
32
- end
32
+ end
33
33
  end
34
-
34
+
35
35
  def get_device_udid opts_hash
36
36
  check_for_devices
37
37
  return unless opts_hash[:udid].nil?
@@ -42,7 +42,7 @@ module Flick
42
42
  abort unless specs
43
43
  end
44
44
  end
45
-
45
+
46
46
  def info
47
47
  specs = { os: "ProductVersion", name: "DeviceName", arc: "CPUArchitecture", type: "DeviceClass", sdk: "ProductType" }
48
48
  hash = { udid: udid }
@@ -52,23 +52,46 @@ module Flick
52
52
  end
53
53
  hash
54
54
  end
55
-
55
+
56
56
  def recordable?
57
57
  false
58
58
  end
59
-
59
+
60
60
  def clear_files
61
61
  Flick::System.clean_system_dir flick_dir, udid
62
62
  end
63
-
63
+
64
64
  def screenshot name
65
65
  Flick::Checker.system_dependency "idevicescreenshot"
66
66
  %x(idevicescreenshot -u #{udid} #{todir}/#{name}.png)
67
67
  end
68
-
68
+
69
69
  def log name
70
70
  Flick::Checker.system_dependency "idevicesyslog"
71
71
  %x(idevicesyslog -u #{udid} > #{outdir}/#{name}.log)
72
72
  end
73
+
74
+ def install app_path
75
+ Flick::Checker.system_dependency "ideviceinstaller"
76
+ %x(ideviceinstaller -u #{udid} -i #{app_path})
77
+ end
78
+
79
+ def uninstall package
80
+ Flick::Checker.system_dependency "ideviceinstaller"
81
+ if app_installed? package
82
+ %x(ideviceinstaller -u #{udid} -U #{package})
83
+ else
84
+ puts packages
85
+ puts "\n#{package} was not found on device #{udid}! Please choose one from above. e.g. #{packages.sample}\n".red
86
+ end
87
+ end
88
+
89
+ def app_installed? package
90
+ packages.include? "#{package}"
91
+ end
92
+
93
+ def packages
94
+ %x(ideviceinstaller -u #{udid} -l -o list_user).split("\n")[1..100000].map { |p| p.match(/(.*) -/)[1] }
95
+ end
73
96
  end
74
97
  end
data/lib/flick/log.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  class Log
2
-
2
+
3
3
  attr_accessor :action, :platform, :driver, :udid
4
-
4
+
5
5
  def initialize options
6
6
  Flick::Checker.action options[:action]
7
7
  Flick::Checker.platform options[:platform]
@@ -16,24 +16,34 @@ class Log
16
16
  end
17
17
  self.udid = self.driver.udid
18
18
  end
19
-
19
+
20
+ def android
21
+ platform == "android"
22
+ end
23
+
24
+ def ios
25
+ platform == "ios"
26
+ end
27
+
20
28
  def run
21
29
  self.send(action)
22
30
  end
23
-
31
+
24
32
  def start
25
33
  puts "Saving to #{driver.outdir}/#{driver.name}.log"
26
34
  log
27
35
  end
28
-
36
+
29
37
  def stop
30
38
  Flick::System.kill_process "log", udid
39
+ Flick::System.kill "idevicesyslog -u #{udid}" if ios
40
+ Flick::System.kill "adb -s #{udid} logcat" if android
31
41
  end
32
-
42
+
33
43
  def log
34
44
  stop
35
45
  $0 = "flick-log-#{udid}"
36
- SimpleDaemon.daemonize! "/tmp/#{udid}-pidfile"
46
+ SimpleDaemon.daemonize!
37
47
  command = -> do
38
48
  driver.log driver.name
39
49
  end
@@ -0,0 +1,41 @@
1
+ class Manager
2
+
3
+ attr_accessor :action, :platform, :driver, :udid, :file, :name
4
+
5
+ def initialize options
6
+ Flick::Checker.manager options[:action]
7
+ Flick::Checker.platform options[:platform]
8
+ self.action = options[:action]
9
+ self.platform = options[:platform]
10
+ case platform
11
+ when "ios"
12
+ self.driver = Flick::Ios.new options
13
+ when "android"
14
+ self.driver = Flick::Android.new options
15
+ end
16
+ self.udid = self.driver.udid
17
+ self.file = options[:file]
18
+ self.name = options[:name]
19
+ end
20
+
21
+ def run
22
+ self.send(action)
23
+ end
24
+
25
+ def install
26
+ if file.nil?
27
+ puts "Specify a file path. e.g. -f #{Dir.home}/myApp/amazing-app.apk or .app".red; abort
28
+ else
29
+ Flick::Checker.file_exists? file
30
+ driver.install file
31
+ end
32
+ end
33
+
34
+ def uninstall
35
+ if name.nil?
36
+ puts "Specify a Package Name or Bundle ID. e.g. -n ".red; abort
37
+ else
38
+ driver.uninstall name
39
+ end
40
+ end
41
+ end
@@ -1,7 +1,7 @@
1
1
  class Screenshot
2
-
2
+
3
3
  attr_accessor :platform, :driver
4
-
4
+
5
5
  def initialize options
6
6
  Flick::Checker.platform options[:platform]
7
7
  self.platform = options[:platform]
@@ -14,15 +14,19 @@ class Screenshot
14
14
  end
15
15
  setup
16
16
  end
17
-
17
+
18
+ def android
19
+ platform == "android"
20
+ end
21
+
18
22
  def screenshot
19
23
  puts "Saving to #{driver.outdir}/#{driver.name}.png"
20
24
  driver.screenshot driver.name
21
- driver.pull_file "#{driver.dir_name}/#{driver.name}.png", driver.outdir if platform == "android"
25
+ driver.pull_file "#{driver.dir_name}/#{driver.name}.png", driver.outdir if android
22
26
  end
23
-
27
+
24
28
  private
25
-
29
+
26
30
  def setup
27
31
  driver.clear_files
28
32
  end
@@ -18,7 +18,7 @@
18
18
  # * The process becomes a session leader of a new session
19
19
  # * The process becomes the process group leader of a new process group
20
20
  # * The process has no controlling terminal
21
- #
21
+ #
22
22
  # Optionally fork again and have the parent exit. This guarantes that
23
23
  # the daemon is not a session leader nor can it acquire a controlling
24
24
  # terminal (under SVR4)
@@ -28,13 +28,13 @@
28
28
  # \_ simple daemon - writes out its pid to file
29
29
  #
30
30
  # Change the current working directory to / to avoid interfering with
31
- # mounting and unmounting. By default don't bother to chdir("/") here
31
+ # mounting and unmounting. By default don't bother to chdir("/") here
32
32
  # because we might to run inside APP_ROOT.
33
33
  #
34
34
  # Set file mode creation mask to 000 to allow creation of files with any
35
- # required permission later. By default umask is whatever was set by the
36
- # parent process at startup and can be set in config.ru and config_file,
37
- # so making it 0000 and potentially exposing sensitive log data can be
35
+ # required permission later. By default umask is whatever was set by the
36
+ # parent process at startup and can be set in config.ru and config_file,
37
+ # so making it 0000 and potentially exposing sensitive log data can be
38
38
  # bad policy.
39
39
  #
40
40
  # Close unneeded file descriptors inherited from the parent (there is no
@@ -46,8 +46,9 @@
46
46
  # value of getpid() after step 3.
47
47
  #
48
48
  class SimpleDaemon
49
+
49
50
  # In the directory where you want your daemon add a git submodule to
50
- # your project and create a daemon launcher script:
51
+ # your project and create a daemon launcher script:
51
52
  #
52
53
  # #!/usr/bin/env ruby
53
54
  #
@@ -74,14 +75,16 @@ class SimpleDaemon
74
75
  # $ ps aux | grep "my daemon"
75
76
  #
76
77
  #
77
- def self.daemonize! pidfile, out = '/dev/null', err = '/dev/null', safe = true
78
+ def self.daemonize! out = '/dev/null', err = '/dev/null', safe = true
78
79
  raise 'First fork failed' if (pid = fork) == -1
79
80
  exit unless pid.nil?
80
81
  Process.setsid
81
82
  raise 'Second fork failed' if (pid = fork) == -1
82
83
  exit unless pid.nil?
83
- kill pidfile
84
- write Process.pid, pidfile
84
+ kill_pid
85
+ @file = Tempfile.new
86
+ @file.write Process.pid
87
+ @file.rewind
85
88
  unless safe
86
89
  Dir.chdir '/'
87
90
  File.umask 0000
@@ -103,9 +106,12 @@ class SimpleDaemon
103
106
 
104
107
  # Try and read the existing pid from the pid file and signal HUP to
105
108
  # process.
106
- def self.kill pidfile
107
- opid = open(pidfile).read.strip.to_i
108
- Process.kill "HUP", opid
109
+ def self.kill_pid
110
+ unless @file.nil?
111
+ opid = @file.read
112
+ Process.kill "HUP", opid
113
+ @file.unlink
114
+ end
109
115
  rescue TypeError
110
116
  $stdout.puts "#{pidfile} was empty: TypeError"
111
117
  rescue Errno::ENOENT
data/lib/flick/system.rb CHANGED
@@ -1,28 +1,48 @@
1
1
  module Flick
2
2
  module System
3
+
4
+ include Sys #load sys-proctable methods
5
+
3
6
  def self.setup_system_dir dir_name
4
- %x(mkdir #{dir_name} >> /dev/null 2>&1)
7
+ Dir.mkdir dir_name unless File.exists? dir_name
5
8
  end
6
-
9
+
7
10
  def self.clean_system_dir dir_name, udid
8
- %x(rm #{dir_name}/#{udid}* >> /dev/null 2>&1)
11
+ Dir.glob("#{dir_name}/*#{udid}*").each do |file|
12
+ File.delete file
13
+ end
9
14
  end
10
-
11
- def self.process_running? type, udid
12
- `pgrep -f #{type}-#{udid}`.to_i > 0
15
+
16
+ def self.find_pid string
17
+ processes = ProcTable.ps.find_all { |x| x.cmdline.include? string }
18
+ processes.map { |p| p.pid } rescue []
13
19
  end
14
-
15
- def self.kill_process type, udid
16
- if self.process_running? type, udid
17
- pid = `pgrep -f flick-#{type}-#{udid}`.to_i
18
- `kill #{pid}` unless pid.zero?
19
- end
20
- if type == "video"
21
- pid = `pgrep -f #{udid}-`.to_i
22
- `kill #{pid}` unless pid.zero?
20
+
21
+ def self.kill_pids pid_array
22
+ return if pid_array.empty?
23
+ pid_array.each { |p| Process.kill 'SIGKILL', p }
24
+ end
25
+
26
+ def self.process_running? string
27
+ pid = self.find_pid string
28
+ unless pid.empty?
29
+ puts "PROCESSING IS RUNNING!!!"
30
+ true
31
+ else
32
+ false
23
33
  end
24
34
  end
25
-
35
+
36
+ def self.kill_process type, udid
37
+ pids = self.find_pid "#{type}-#{udid}"
38
+ self.kill_pids pids
39
+ end
40
+
41
+ def self.kill string
42
+ pids = self.find_pid string
43
+ self.kill_pids pids
44
+ end
45
+
26
46
  def self.video_length file
27
47
  (`ffmpeg -i #{file} 2>&1 | grep Duration | cut -d ' ' -f 4 | sed s/,//`).strip
28
48
  end
data/lib/flick/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Flick
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
data/lib/flick/video.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  class Video
2
2
 
3
3
  attr_accessor :action, :platform, :driver, :image_count, :seconds, :extended, :udid, :format
4
-
4
+
5
5
  def initialize options
6
6
  Flick::Checker.action options[:action]
7
7
  Flick::Checker.platform options[:platform]
@@ -20,19 +20,19 @@ class Video
20
20
  self.udid = self.driver.udid
21
21
  self.format = options[:format]
22
22
  end
23
-
23
+
24
24
  def android
25
25
  platform == "android"
26
26
  end
27
-
27
+
28
28
  def ios
29
29
  platform == "ios"
30
30
  end
31
-
31
+
32
32
  def run
33
33
  self.send(action)
34
34
  end
35
-
35
+
36
36
  def start
37
37
  driver.clear_files
38
38
  puts "\nStarting Recoder!!!"
@@ -49,7 +49,7 @@ class Video
49
49
  start_screenshot_record
50
50
  end
51
51
  end
52
-
52
+
53
53
  def stop
54
54
  puts "\nStopping Recorder!!!"
55
55
  if driver.recordable?
@@ -60,99 +60,94 @@ class Video
60
60
  sleep 1
61
61
  driver.clear_files
62
62
  end
63
-
64
- private
65
-
63
+
64
+ private
65
+
66
66
  def start_record
67
67
  Flick::System.kill_process "video", udid
68
68
  $0 = "flick-video-#{udid}"
69
- SimpleDaemon.daemonize! "/tmp/#{udid}-pidfile"
69
+ SimpleDaemon.daemonize!
70
70
  command = -> do
71
- driver.screenrecord "#{udid}-single"
71
+ driver.screenrecord "video-#{udid}-single"
72
72
  end
73
73
  command.call
74
74
  end
75
-
76
- def is_recording?
77
- !(`pgrep -f #{udid}-`).empty?
78
- end
79
-
75
+
80
76
  def loop_record
81
77
  Flick::System.kill_process "video", udid
82
78
  $0 = "flick-video-#{udid}"
83
- SimpleDaemon.daemonize! "/tmp/#{udid}-pidfile"
79
+ SimpleDaemon.daemonize!
84
80
  command = -> do
85
81
  count = "%03d" % 1
86
82
  loop do
87
- unless is_recording?
88
- driver.screenrecord "#{udid}-#{count}"
83
+ unless Flick::System.process_running? "#{udid}-"
84
+ driver.screenrecord "video-#{udid}-#{count}"
89
85
  count.next!
90
86
  end
91
87
  end
92
88
  end
93
89
  command.call
94
90
  end
95
-
91
+
96
92
  def stop_record
97
93
  Flick::System.kill_process "video", udid
98
94
  sleep 5 #wait for video process to finish
99
- driver.pull_files
100
- files = (`ls #{driver.flick_dir}/#{udid}*.mp4`).split("\n")
95
+ driver.pull_files "video"
96
+ files = Dir.glob("#{driver.flick_dir}/video-#{udid}*.mp4")
101
97
  return if files.empty?
102
98
  files.each { |file| system("mp4box -cat #{file} #{driver.flick_dir}/#{driver.name}.mp4") }
103
99
  puts "Saving to #{driver.outdir}/#{driver.name}.#{format}"
104
100
  if format == "gif"
105
101
  gif
106
102
  else
107
- %x(nohup mv #{driver.flick_dir}/#{driver.name}.mp4 #{driver.outdir}/#{driver.name}.mp4)
103
+ File.rename "#{driver.flick_dir}/#{driver.name}.mp4", "#{driver.outdir}/#{driver.name}.mp4"
108
104
  end
109
105
  end
110
-
106
+
111
107
  def start_screenshot_record
112
108
  Flick::System.kill_process "screenshot", udid
113
109
  puts "Process will stop after #{image_count} screenshots.\n"
114
110
  $0 = "flick-screenshot-#{udid}"
115
- SimpleDaemon.daemonize! "/tmp/#{udid}-pidfile"
111
+ SimpleDaemon.daemonize!
116
112
  command = -> do
117
113
  count = "%03d" % 1
118
114
  loop do
119
- if count.to_i < image_count
120
- driver.screenshot "#{udid}-#{count}"
115
+ if count.to_i <= image_count
116
+ driver.screenshot "screenshot-#{udid}-#{count}"
121
117
  count.next!; sleep seconds
122
118
  else
123
- puts "\nStop count exceeded. Saving to #{driver.outdir}/#{driver.name}.#{format}".red
124
- self.send(format)
119
+ stop_screenshot_recording
125
120
  break
126
121
  end
127
122
  end
128
123
  end
129
124
  command.call
130
125
  end
131
-
132
- def stop_screenshot_recording
133
- Flick::System.kill_process "screenshot", udid
134
- `rm /tmp/#{udid}-pidfile >> /dev/null 2>&1`
135
- driver.pull_files if android
126
+
127
+ def stop_screenshot_recording
128
+ driver.pull_files "screenshot" if android
136
129
  puts "Saving to #{driver.outdir}/#{driver.name}.#{format}"
137
130
  self.send(format)
138
131
  end
139
-
132
+
140
133
  def gif
141
134
  convert_images_to_mp4 unless driver.recordable?
142
- %x(nohup ffmpeg -i #{driver.flick_dir}/#{driver.name}.mp4 -pix_fmt rgb24 #{driver.outdir}/#{driver.name}.gif)
135
+ %x(ffmpeg -loglevel quiet -i #{driver.flick_dir}/#{driver.name}.mp4 -pix_fmt rgb24 #{driver.outdir}/#{driver.name}.gif)
143
136
  end
144
-
137
+
145
138
  def mp4
146
139
  convert_images_to_mp4
147
- %x(nohup mv #{driver.flick_dir}/#{driver.name}.mp4 #{driver.outdir}/#{driver.name}.mp4) unless format == "gif"
140
+ File.rename "#{driver.flick_dir}/#{driver.name}.mp4", "#{driver.outdir}/#{driver.name}.mp4" unless format == "gif"
148
141
  end
149
-
142
+
150
143
  def convert_images_to_mp4
151
144
  remove_zero_byte_images
152
- %x(nohup ffmpeg -framerate 1 -pattern_type glob -i '#{driver.flick_dir}/#{udid}*.png' -c:v libx264 -pix_fmt yuv420p #{driver.flick_dir}/#{driver.name}.mp4)
145
+ %x(ffmpeg -loglevel quiet -framerate 1 -pattern_type glob -i '#{driver.flick_dir}/screenshot-#{udid}*.png' -c:v libx264 -pix_fmt yuv420p #{driver.flick_dir}/#{driver.name}.mp4)
153
146
  end
154
-
147
+
155
148
  def remove_zero_byte_images
156
- %x(nohup find #{driver.flick_dir} -type f -size 0 | xargs rm '#{udid}*.png' -f)
149
+ Dir.glob("#{driver.flick_dir}/screenshot-#{udid}*.png").each do |f|
150
+ File.delete f if File.zero? f
151
+ end
157
152
  end
158
153
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: flick
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Justin
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-03-18 00:00:00.000000000 Z
11
+ date: 2016-07-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -166,6 +166,60 @@ dependencies:
166
166
  - - ">="
167
167
  - !ruby/object:Gem::Version
168
168
  version: 1.6.1
169
+ - !ruby/object:Gem::Dependency
170
+ name: os
171
+ requirement: !ruby/object:Gem::Requirement
172
+ requirements:
173
+ - - "~>"
174
+ - !ruby/object:Gem::Version
175
+ version: 0.9.6
176
+ type: :runtime
177
+ prerelease: false
178
+ version_requirements: !ruby/object:Gem::Requirement
179
+ requirements:
180
+ - - "~>"
181
+ - !ruby/object:Gem::Version
182
+ version: 0.9.6
183
+ - !ruby/object:Gem::Dependency
184
+ name: sys-proctable
185
+ requirement: !ruby/object:Gem::Requirement
186
+ requirements:
187
+ - - "~>"
188
+ - !ruby/object:Gem::Version
189
+ version: '1.1'
190
+ - - ">="
191
+ - !ruby/object:Gem::Version
192
+ version: 1.1.1
193
+ type: :runtime
194
+ prerelease: false
195
+ version_requirements: !ruby/object:Gem::Requirement
196
+ requirements:
197
+ - - "~>"
198
+ - !ruby/object:Gem::Version
199
+ version: '1.1'
200
+ - - ">="
201
+ - !ruby/object:Gem::Version
202
+ version: 1.1.1
203
+ - !ruby/object:Gem::Dependency
204
+ name: apktools
205
+ requirement: !ruby/object:Gem::Requirement
206
+ requirements:
207
+ - - "~>"
208
+ - !ruby/object:Gem::Version
209
+ version: 0.7.1
210
+ - - ">="
211
+ - !ruby/object:Gem::Version
212
+ version: 0.7.1
213
+ type: :runtime
214
+ prerelease: false
215
+ version_requirements: !ruby/object:Gem::Requirement
216
+ requirements:
217
+ - - "~>"
218
+ - !ruby/object:Gem::Version
219
+ version: 0.7.1
220
+ - - ">="
221
+ - !ruby/object:Gem::Version
222
+ version: 0.7.1
169
223
  description: A CLI with helpful QA tools for iOS and Android from the command line
170
224
  email:
171
225
  - justin.ison@gmail.com
@@ -192,6 +246,7 @@ files:
192
246
  - lib/flick/info.rb
193
247
  - lib/flick/ios.rb
194
248
  - lib/flick/log.rb
249
+ - lib/flick/manager.rb
195
250
  - lib/flick/screenshot.rb
196
251
  - lib/flick/simple_daemon.rb
197
252
  - lib/flick/system.rb
@@ -224,4 +279,3 @@ specification_version: 4
224
279
  summary: A CLI to capture screenshots, video, logs, and device information for Android
225
280
  (Devices & Emulators) and iOS (Devices).
226
281
  test_files: []
227
- has_rdoc: