snapshot 0.0.1.1 → 0.0.2
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.
- checksums.yaml +4 -4
- data/LICENSE +21 -0
- data/README.md +148 -0
- data/bin/snapshot +34 -0
- data/lib/snapshot.rb +17 -0
- data/lib/snapshot/builder.rb +68 -0
- data/lib/snapshot/dependency_checker.rb +45 -0
- data/lib/snapshot/helper.rb +51 -0
- data/lib/snapshot/languages.rb +6 -0
- data/lib/snapshot/runner.rb +109 -0
- data/lib/snapshot/snapshot_config.rb +113 -0
- data/lib/snapshot/snapshot_file.rb +82 -0
- data/lib/snapshot/update_checker.rb +45 -0
- data/lib/snapshot/version.rb +3 -0
- metadata +176 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2062cd7ffe2f73085accb032e996a17a6bae3366
|
4
|
+
data.tar.gz: 28cece95de94cbcd1ce1b01af91cd49686440799
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 54f045eba2b950217cb20b701166d3301909217d45f5f13fe7e7379ff6da1c32bffa1fb956148674726a3b6ee73af9dae831d371db4374c904c9d53f817f3e85
|
7
|
+
data.tar.gz: 82935ebf00ecdbab062e4353b69debb8fd6744eccf5fe3364993784f40b2051d2ee8fa39150ec304eeecbab8a730a806786d4174df3827679790f207aed6527f
|
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2014 Felix Krause
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,148 @@
|
|
1
|
+
<p align="center">
|
2
|
+
<img src="assets/snapshot.png">
|
3
|
+
</p>
|
4
|
+
|
5
|
+
Snapshot - Create hundreds of iOS app screenshots
|
6
|
+
============
|
7
|
+
|
8
|
+
[](https://twitter.com/KrauseFx)
|
9
|
+
<!-- [](https://github.com/KrauseFx/deliver/blob/develop/LICENSE)
|
10
|
+
[](http://rubygems.org/gems/deliver)
|
11
|
+
[](https://travis-ci.org/KrauseFx/deliver) -->
|
12
|
+
|
13
|
+
Taking perfect iOS screenshots is difficult. You usually want them to look the same in **all languages** on **all devices**.
|
14
|
+
|
15
|
+
This easily results in over **300 screenshots** you have to create.
|
16
|
+
|
17
|
+
Uploading them is really easy, using [```deliver```](https://github.com/KrauseFx/deliver).
|
18
|
+
|
19
|
+
Follow the developer on Twitter: [@KrauseFx](https://twitter.com/KrauseFx)
|
20
|
+
|
21
|
+
|
22
|
+
-------
|
23
|
+
[Features](#features) •
|
24
|
+
[Installation](#installation) •
|
25
|
+
[Quick Start](#quick-start) •
|
26
|
+
[Usage](#usage) •
|
27
|
+
[Tips](#tips) •
|
28
|
+
[Need help?](#need-help)
|
29
|
+
|
30
|
+
-------
|
31
|
+
|
32
|
+
|
33
|
+
# Features
|
34
|
+
- Create hundreds of screenshots in multiple languages on all simulators
|
35
|
+
- Configure it once, store the configuration in git
|
36
|
+
- Do something else, while the computer takes the screenshots for you
|
37
|
+
- Very easy to integrate with ```deliver```
|
38
|
+
|
39
|
+
# Installation
|
40
|
+
|
41
|
+
Install the gem
|
42
|
+
|
43
|
+
sudo gem install snapshot
|
44
|
+
|
45
|
+
Make sure, you have the latest version of the Xcode command line tools installed:
|
46
|
+
|
47
|
+
xcode-select --install
|
48
|
+
|
49
|
+
# Quick Start
|
50
|
+
|
51
|
+
|
52
|
+
The guide will create all the necessary files for you, using the existing app metadata from iTunes Connect.
|
53
|
+
|
54
|
+
- ```cd [your_project_folder]```
|
55
|
+
- ```snapshot```
|
56
|
+
|
57
|
+
Your screenshots will be stored in ```./screenshots/``` by default.
|
58
|
+
|
59
|
+
From now on, you can run ```snapshot``` to create new screenshots of your app.
|
60
|
+
|
61
|
+
|
62
|
+
# Usage
|
63
|
+
|
64
|
+
Why should you have to remember complicated commands and parameters?
|
65
|
+
|
66
|
+
Store your configuration in a text file to easily take screenshots from any computer.
|
67
|
+
|
68
|
+
## Snapfile
|
69
|
+
|
70
|
+
Create a file called ```Snapfile``` in your project directory.
|
71
|
+
Once you created your configuration, just run ```snapshot```.
|
72
|
+
|
73
|
+
The ```Snapfile``` may contain the following information (all are optional):
|
74
|
+
|
75
|
+
### Simulator Types
|
76
|
+
```ruby
|
77
|
+
devices([
|
78
|
+
"iPhone 6",
|
79
|
+
"iPhone 6 Plus",
|
80
|
+
"iPhone 5",
|
81
|
+
"iPhone 4s"
|
82
|
+
])
|
83
|
+
```
|
84
|
+
|
85
|
+
### Languages
|
86
|
+
|
87
|
+
```ruby
|
88
|
+
languages([
|
89
|
+
"en-US",
|
90
|
+
"de-DE",
|
91
|
+
"es-ES"
|
92
|
+
])
|
93
|
+
```
|
94
|
+
|
95
|
+
### Javascript file
|
96
|
+
Usually ```snapshot``` automatically finds your JavaScript file. If that's not the case, you can pass the path
|
97
|
+
to your test file.
|
98
|
+
```ruby
|
99
|
+
js_file './path/file.js'
|
100
|
+
```
|
101
|
+
|
102
|
+
### Scheme
|
103
|
+
To not be asked which scheme to use, just set it like this:
|
104
|
+
```ruby
|
105
|
+
scheme "Name"
|
106
|
+
```
|
107
|
+
|
108
|
+
### Project Path
|
109
|
+
By default, ```snapshot``` will look for your project in the current directory. If it is located somewhere else, pass your custom path:
|
110
|
+
```ruby
|
111
|
+
project_path "./my_project/Project.xcworkspace"
|
112
|
+
```
|
113
|
+
|
114
|
+
### iOS Version
|
115
|
+
I'll try to keep the script up to date. If you need to change the iOS version, you can do it like this:
|
116
|
+
|
117
|
+
```ruby
|
118
|
+
ios_version "9.0"
|
119
|
+
```
|
120
|
+
|
121
|
+
|
122
|
+
# Tips
|
123
|
+
## Available language codes
|
124
|
+
```ruby
|
125
|
+
["da-DK", "de-DE", "el-GR", "en-AU", "en-CA", "en-GB", "en-US", "es-ES", "es-MX", "fi-FI", "fr-CA", "fr-FR", "id-ID", "it-IT", "ja-JP", "ko-KR", "ms-MY", "nl-NL", "no-NO", "pt-BR", "pt-PT", "ru-RU", "sv-SE", "th-TH", "tr-TR", "vi-VI", "cmn-Hans", "zh_CN", "cmn-Hant"]
|
126
|
+
```
|
127
|
+
|
128
|
+
## Use a clean status bar
|
129
|
+
You can use [SimulatorStatusMagic](https://github.com/shinydevelopment/SimulatorStatusMagic) to clean up the status bar.
|
130
|
+
|
131
|
+
## Editing the ```Deliverfile```
|
132
|
+
Change syntax highlighting to *Ruby*.
|
133
|
+
|
134
|
+
# Need help?
|
135
|
+
- If there is a technical problem with ```Snapshot```, submit an issue. Run ```snapshot --trace``` to get the stacktrace.
|
136
|
+
- I'm available for contract work - drop me an email: snapshot@felixkrause.at
|
137
|
+
|
138
|
+
# License
|
139
|
+
This project is licensed under the terms of the MIT license. See the LICENSE file.
|
140
|
+
|
141
|
+
# Contributing
|
142
|
+
|
143
|
+
1. Create an issue to discuss about your idea
|
144
|
+
2. Fork it (https://github.com/KrauseFx/snapshot/fork)
|
145
|
+
3. Create your feature branch (`git checkout -b my-new-feature`)
|
146
|
+
4. Commit your changes (`git commit -am 'Add some feature'`)
|
147
|
+
5. Push to the branch (`git push origin my-new-feature`)
|
148
|
+
6. Create a new Pull Request
|
data/bin/snapshot
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$:.push File.expand_path("../../lib", __FILE__)
|
4
|
+
|
5
|
+
require 'snapshot'
|
6
|
+
require 'commander/import'
|
7
|
+
require 'snapshot/update_checker'
|
8
|
+
require 'snapshot/dependency_checker'
|
9
|
+
|
10
|
+
HighLine.track_eof = false
|
11
|
+
|
12
|
+
|
13
|
+
# Commander
|
14
|
+
program :version, Snapshot::VERSION
|
15
|
+
program :description, 'CLI for \'Snapshot\' - Automatic taking of screenshots on all simulator types in all languages.'
|
16
|
+
program :help, 'Author', 'Felix Krause <krausefx@gmail.com>'
|
17
|
+
program :help, 'Website', 'http://felixkrause.at'
|
18
|
+
program :help, 'GitHub', 'https://github.com/krausefx/snapshot'
|
19
|
+
program :help_formatter, :compact
|
20
|
+
|
21
|
+
global_option('--verbose') { $verbose = true }
|
22
|
+
|
23
|
+
|
24
|
+
Snapshot::UpdateChecker.verify_latest_version
|
25
|
+
|
26
|
+
default_command :run
|
27
|
+
|
28
|
+
command :run do |c|
|
29
|
+
c.syntax = 'snapshot'
|
30
|
+
c.description = 'Run the script, to take all the screenshots.'
|
31
|
+
c.action do |args, options|
|
32
|
+
Snapshot::Runner.new.work
|
33
|
+
end
|
34
|
+
end
|
data/lib/snapshot.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'snapshot/version'
|
3
|
+
require 'snapshot/helper'
|
4
|
+
require 'snapshot/snapshot_config'
|
5
|
+
require 'snapshot/runner'
|
6
|
+
require 'snapshot/builder'
|
7
|
+
require 'snapshot/snapshot_file'
|
8
|
+
require 'snapshot/languages'
|
9
|
+
|
10
|
+
require 'pry' # TODO: Remove
|
11
|
+
|
12
|
+
# Third Party code
|
13
|
+
require 'colored'
|
14
|
+
|
15
|
+
module Snapshot
|
16
|
+
# Your code goes here...
|
17
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'snapshot/dependency_checker'
|
2
|
+
|
3
|
+
module Snapshot
|
4
|
+
class Builder
|
5
|
+
BUILD_DIR = '/tmp/snapshot'
|
6
|
+
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
|
10
|
+
end
|
11
|
+
|
12
|
+
def build_app
|
13
|
+
raise "Could not find project. Please pass the path to your project using 'project_path'.".red unless SnapshotConfig.shared_instance.project_name
|
14
|
+
command = generate_build_command
|
15
|
+
|
16
|
+
Helper.log.info "Building project '#{SnapshotConfig.shared_instance.project_name}'... this might take some time...".green
|
17
|
+
Helper.log.debug command.yellow
|
18
|
+
|
19
|
+
all_lines = []
|
20
|
+
|
21
|
+
PTY.spawn(command) do |stdin, stdout, pid|
|
22
|
+
stdin.each do |line|
|
23
|
+
all_lines << line
|
24
|
+
begin
|
25
|
+
parse_build_line(line) if line.length > 2
|
26
|
+
rescue Exception => ex
|
27
|
+
Helper.log.fatal all_lines.join("\n")
|
28
|
+
raise ex
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
if all_lines.join('\n').include?'** BUILD SUCCEEDED **'
|
34
|
+
Helper.log.info "BUILD SUCCEEDED".green
|
35
|
+
return true
|
36
|
+
else
|
37
|
+
Helper.log.info(all_lines.join(' '))
|
38
|
+
raise "Looks like the build was not successfull."
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
def parse_build_line(line)
|
44
|
+
if line.include?"** BUILD FAILED **"
|
45
|
+
raise line
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def generate_build_command
|
50
|
+
scheme = SnapshotConfig.shared_instance.scheme
|
51
|
+
|
52
|
+
build_command = (DependencyChecker.xctool_installed? ? 'xctool' : 'xcodebuild')
|
53
|
+
[
|
54
|
+
build_command,
|
55
|
+
"-sdk iphonesimulator#{SnapshotConfig.shared_instance.ios_version}",
|
56
|
+
"CONFIGURATION_BUILD_DIR='#{BUILD_DIR}/build'",
|
57
|
+
"-workspace '#{SnapshotConfig.shared_instance.project_path}'",
|
58
|
+
"-scheme '#{scheme}'",
|
59
|
+
"-configuration Debug",
|
60
|
+
"DSTROOT='#{BUILD_DIR}'",
|
61
|
+
"OBJROOT='#{BUILD_DIR}'",
|
62
|
+
"SYMROOT='#{BUILD_DIR}'",
|
63
|
+
"ONLY_ACTIVE_ARCH=NO",
|
64
|
+
"clean build"
|
65
|
+
].join(' ')
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Snapshot
|
2
|
+
class DependencyChecker
|
3
|
+
def self.check_dependencies
|
4
|
+
self.check_xcode_select
|
5
|
+
self.check_simulators
|
6
|
+
self.check_xctool
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.check_xcode_select
|
10
|
+
unless `xcode-select -v`.include?"xcode-select version "
|
11
|
+
Helper.log.fatal '#############################################################'
|
12
|
+
Helper.log.fatal "# You have to install the Xcode commdand line tools to use deliver"
|
13
|
+
Helper.log.fatal "# Install the latest version of Xcode from the AppStore"
|
14
|
+
Helper.log.fatal "# Run xcode-select --install to install the developer tools"
|
15
|
+
Helper.log.fatal '#############################################################'
|
16
|
+
raise "Run 'xcode-select --install' and start deliver again"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.check_simulators
|
21
|
+
Helper.log.debug "Found #{SnapshotFile.available_devices.count} simulators."
|
22
|
+
if SnapshotFile.available_devices.count < 1
|
23
|
+
Helper.log.fatal '#############################################################'
|
24
|
+
Helper.log.fatal "# You have to add new simulators using Xcode"
|
25
|
+
Helper.log.fatal "# Xcode => Window => Devices"
|
26
|
+
Helper.log.fatal '#############################################################'
|
27
|
+
raise "Create the new simulators and run this script again"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.xctool_installed?
|
32
|
+
return `which xctool`.length > 1
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.check_xctool
|
36
|
+
if not self.xctool_installed?
|
37
|
+
Helper.log.error '#############################################################'
|
38
|
+
Helper.log.error "# xctool is recommended to build the apps"
|
39
|
+
Helper.log.error "# Install it using 'brew install xctool'"
|
40
|
+
Helper.log.error "# Falling back to xcode build instead "
|
41
|
+
Helper.log.error '#############################################################'
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'logger'
|
2
|
+
|
3
|
+
module Snapshot
|
4
|
+
class Helper
|
5
|
+
|
6
|
+
|
7
|
+
# Logging happens using this method
|
8
|
+
def self.log
|
9
|
+
if is_test?
|
10
|
+
@@log ||= Logger.new(STDOUT) # don't show any logs when running tests
|
11
|
+
else
|
12
|
+
@@log ||= Logger.new(STDOUT)
|
13
|
+
end
|
14
|
+
|
15
|
+
@@log.formatter = proc do |severity, datetime, progname, msg|
|
16
|
+
string = "#{severity} [#{datetime.strftime('%Y-%m-%d %H:%M:%S.%2N')}]: "
|
17
|
+
second = "#{msg}\n"
|
18
|
+
|
19
|
+
if severity == "DEBUG"
|
20
|
+
string = string.magenta
|
21
|
+
elsif severity == "INFO"
|
22
|
+
string = string.white
|
23
|
+
elsif severity == "WARN"
|
24
|
+
string = string.yellow
|
25
|
+
elsif severity == "ERROR"
|
26
|
+
string = string.red
|
27
|
+
elsif severity == "FATAL"
|
28
|
+
string = string.red.bold
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
[string, second].join("")
|
33
|
+
end
|
34
|
+
|
35
|
+
@@log
|
36
|
+
end
|
37
|
+
|
38
|
+
# @return true if the currently running program is a unit test
|
39
|
+
def self.is_test?
|
40
|
+
defined?SpecHelper
|
41
|
+
end
|
42
|
+
|
43
|
+
# @return the full path to the Xcode developer tools of the currently
|
44
|
+
# running system
|
45
|
+
def self.xcode_path
|
46
|
+
return "" if self.is_test? and not OS.mac?
|
47
|
+
`xcode-select -p`.gsub("\n", '') + "/"
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,6 @@
|
|
1
|
+
module Snapshot
|
2
|
+
module Languages
|
3
|
+
# These are all the languages which are available to choose for the simulator
|
4
|
+
ALL_LANGUAGES = ["da-DK", "de-DE", "el-GR", "en-AU", "en-CA", "en-GB", "en-US", "es-ES", "es-MX", "fi-FI", "fr-CA", "fr-FR", "id-ID", "it-IT", "ja-JP", "ko-KR", "ms-MY", "nl-NL", "no-NO", "pt-BR", "pt-PT", "ru-RU", "sv-SE", "th-TH", "tr-TR", "vi-VI", "cmn-Hans", "zh_CN", "cmn-Hant"]
|
5
|
+
end
|
6
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
require 'pty'
|
2
|
+
|
3
|
+
module Snapshot
|
4
|
+
class Runner
|
5
|
+
TRACE_DIR = '/tmp/snapshot_traces'
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
Snapshot::DependencyChecker.check_dependencies
|
9
|
+
end
|
10
|
+
|
11
|
+
def work
|
12
|
+
@screenshots_path = './screenshots'
|
13
|
+
|
14
|
+
SnapshotConfig.shared_instance.js_file # to verify the file can be found
|
15
|
+
|
16
|
+
Builder.new.build_app
|
17
|
+
|
18
|
+
SnapshotConfig.shared_instance.devices.each do |device|
|
19
|
+
SnapshotConfig.shared_instance.languages.each do |language|
|
20
|
+
|
21
|
+
begin
|
22
|
+
run_tests(device, language)
|
23
|
+
copy_screenshots(language)
|
24
|
+
rescue Exception => ex
|
25
|
+
Helper.log.error(ex)
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def clean_old_traces
|
33
|
+
FileUtils.rm_rf(TRACE_DIR)
|
34
|
+
FileUtils.mkdir_p(TRACE_DIR)
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
def run_tests(device, language)
|
39
|
+
Helper.log.info "Running tests on #{device} in language #{language}".green
|
40
|
+
app_path = Dir.glob("/tmp/snapshot/build/*.app").first
|
41
|
+
|
42
|
+
clean_old_traces
|
43
|
+
|
44
|
+
ENV['SNAPSHOT_LANGUAGE'] = language
|
45
|
+
command = generate_test_command(device, language, app_path)
|
46
|
+
|
47
|
+
retry_run = false
|
48
|
+
|
49
|
+
lines = []
|
50
|
+
PTY.spawn(command) do |stdin, stdout, pid|
|
51
|
+
stdin.each do |line|
|
52
|
+
lines << line
|
53
|
+
result = parse_test_line(line)
|
54
|
+
|
55
|
+
case result
|
56
|
+
when :retry
|
57
|
+
retry_run = true
|
58
|
+
when :screenshot
|
59
|
+
Helper.log.info "Successfully took screenshot 📱"
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
if retry_run
|
65
|
+
Helper.log.error "Instruments tool failed again. Re-trying..."
|
66
|
+
sleep 2 # We need enough sleep... that's an instruments bug
|
67
|
+
run_tests(device, language)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def parse_test_line(line)
|
72
|
+
if line =~ /.*Target failed to run.*/
|
73
|
+
return :retry
|
74
|
+
elsif line.include?"Screenshot captured"
|
75
|
+
return :screenshot
|
76
|
+
elsif line =~ /.*Error: (.*)/
|
77
|
+
raise "UIAutomation Error: #{$1}"
|
78
|
+
elsif line =~ /Instruments Usage Error :(.*)/
|
79
|
+
raise "Instruments Usage Error: #{$1}"
|
80
|
+
elsif line.include?"__NSPlaceholderDictionary initWithObjects:forKeys:count:]: attempt to insert nil object"
|
81
|
+
raise "Looks like something is wrong with the used app. Make sure the build was successful."
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def copy_screenshots(language)
|
86
|
+
resulting_path = [@screenshots_path, language].join('/')
|
87
|
+
FileUtils.mkdir_p resulting_path
|
88
|
+
Dir.glob("#{TRACE_DIR}/**/*.png") do |file|
|
89
|
+
FileUtils.cp_r(file, resulting_path + '/')
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def generate_test_command(device, language, app_path)
|
94
|
+
script_path = SnapshotConfig.shared_instance.js_file
|
95
|
+
|
96
|
+
[
|
97
|
+
"instruments",
|
98
|
+
"-w '#{device}'",
|
99
|
+
"-D '#{TRACE_DIR}/trace'",
|
100
|
+
"-t 'Automation'",
|
101
|
+
"'#{app_path}'",
|
102
|
+
"-e UIARESULTSPATH '#{TRACE_DIR}'",
|
103
|
+
"-e UIASCRIPT '#{script_path}'",
|
104
|
+
"-AppleLanguages '(#{language})'",
|
105
|
+
"-AppleLocale '#{language}'"
|
106
|
+
].join(' ')
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
module Snapshot
|
2
|
+
class SnapshotConfig
|
3
|
+
|
4
|
+
# @return (SnapshotFile)
|
5
|
+
attr_accessor :snapshot_file
|
6
|
+
|
7
|
+
# @return (Array) List of simulators to use
|
8
|
+
attr_accessor :devices
|
9
|
+
|
10
|
+
# @return (Array) A list of languages which should be used
|
11
|
+
attr_accessor :languages
|
12
|
+
|
13
|
+
# @return (String) The iOS version (e.g. 8.1)
|
14
|
+
attr_accessor :ios_version
|
15
|
+
|
16
|
+
# @return (String) The path to the project/workspace
|
17
|
+
attr_accessor :project_path
|
18
|
+
|
19
|
+
# @return (String) The name of a scheme, manually set by the user using the config file
|
20
|
+
attr_accessor :manual_scheme
|
21
|
+
|
22
|
+
# @return (String) The path to the JavaScript file to use
|
23
|
+
attr_accessor :manual_js_file
|
24
|
+
|
25
|
+
|
26
|
+
# A shared singleton
|
27
|
+
def self.shared_instance
|
28
|
+
@@instance ||= SnapshotConfig.new
|
29
|
+
end
|
30
|
+
|
31
|
+
# @param path (String) the path to the config file to use (including the file name)
|
32
|
+
def initialize(path = './Snapfile')
|
33
|
+
set_defaults
|
34
|
+
|
35
|
+
if path and File.exists?path
|
36
|
+
self.snapshot_file = SnapshotFile.new(path, self)
|
37
|
+
else
|
38
|
+
Helper.log.error "Could not find './Snapfile'. It is recommended to create a file into the current directory. Using the defaults now."
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def set_defaults
|
43
|
+
self.ios_version = '8.1'
|
44
|
+
|
45
|
+
self.devices = [
|
46
|
+
"iPhone 6 (#{self.ios_version} Simulator)",
|
47
|
+
"iPhone 6 Plus (#{self.ios_version} Simulator)",
|
48
|
+
"iPhone 5 (#{self.ios_version} Simulator)",
|
49
|
+
"iPhone 4S (#{self.ios_version} Simulator)"
|
50
|
+
]
|
51
|
+
|
52
|
+
self.languages = [
|
53
|
+
'de-DE',
|
54
|
+
'en-US'
|
55
|
+
]
|
56
|
+
|
57
|
+
self.project_path = (Dir.glob("./*.xcworkspace").first rescue nil)
|
58
|
+
self.project_path ||= (Dir.glob("./*.xcodeproj").first rescue nil)
|
59
|
+
end
|
60
|
+
|
61
|
+
# Getters
|
62
|
+
|
63
|
+
# Returns the file name of the project
|
64
|
+
def project_name
|
65
|
+
(self.project_path.split('/').last.split('.').first rescue nil)
|
66
|
+
end
|
67
|
+
|
68
|
+
# The JavaScript UIAutomation file
|
69
|
+
def js_file
|
70
|
+
files = Dir.glob("./*.js").delete_if { |path| path.include?"SnapshotHelper.js" }
|
71
|
+
if files.count == 1
|
72
|
+
return files.first
|
73
|
+
else
|
74
|
+
raise "Could not determine which UIAutomation file to use. Please pass a path to your Javascript file using 'js_path'.".red
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
# The scheme to use (either it's set, or there is only one, or user has to enter it)
|
79
|
+
def scheme
|
80
|
+
begin
|
81
|
+
command = "cd '#{project_path.split('/')[0..-2].join('/')}'; xcodebuild -list"
|
82
|
+
schemes = `#{command}`.split("Schemes:").last.split("\n").each { |a| a.strip! }.delete_if { |a| a == '' }
|
83
|
+
Helper.log.debug "Found available schemes: #{schemes}"
|
84
|
+
|
85
|
+
|
86
|
+
if self.manual_scheme
|
87
|
+
if not schemes.include?manual_scheme
|
88
|
+
raise "Could not find requested scheme '#{self.manual_scheme}' in Xcode's schemes #{schemes}"
|
89
|
+
else
|
90
|
+
return self.manual_scheme
|
91
|
+
end
|
92
|
+
else
|
93
|
+
# We have to ask the user first
|
94
|
+
puts "Found the following schemes in your project:".green
|
95
|
+
puts "You can use 'scheme \"Name\"' in your Snapfile".green
|
96
|
+
puts "--------------------------------------------".green
|
97
|
+
while not schemes.include?self.manual_scheme
|
98
|
+
schemes.each_with_index do |current, index|
|
99
|
+
puts "#{index + 1}) #{current}"
|
100
|
+
end
|
101
|
+
val = gets.strip.to_i
|
102
|
+
if val > 0
|
103
|
+
self.manual_scheme = (schemes[val - 1] rescue nil)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
return self.manual_scheme
|
107
|
+
end
|
108
|
+
rescue Exception => ex
|
109
|
+
raise "Could not fetch available schemes: #{ex}".red
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
module Snapshot
|
2
|
+
class SnapshotFile
|
3
|
+
|
4
|
+
# @return (String) The path to the used Deliverfile.
|
5
|
+
attr_accessor :path
|
6
|
+
|
7
|
+
# @param path (String) the path to the config file to use (including the file name)
|
8
|
+
def initialize(path, config)
|
9
|
+
raise "Config file not found at path '#{path}'".red unless File.exists?(path.to_s)
|
10
|
+
|
11
|
+
self.path = path
|
12
|
+
|
13
|
+
@config = config
|
14
|
+
|
15
|
+
eval(File.read(self.path))
|
16
|
+
end
|
17
|
+
|
18
|
+
def method_missing(method_sym, *arguments, &block)
|
19
|
+
value = arguments.first || (block.call if block_given?)
|
20
|
+
|
21
|
+
case method_sym
|
22
|
+
when :devices
|
23
|
+
self.verify_devices(value)
|
24
|
+
when :languages
|
25
|
+
self.verify_languages(value)
|
26
|
+
when :ios_version
|
27
|
+
raise "ios_version has to be an String".red unless value.kind_of?String
|
28
|
+
@config.ios_version = value
|
29
|
+
when :scheme
|
30
|
+
raise "scheme has to be an String".red unless value.kind_of?String
|
31
|
+
@config.manual_scheme = value
|
32
|
+
when :js_file
|
33
|
+
raise "js_file has to be an String".red unless value.kind_of?String
|
34
|
+
raise "js_file at path '#{value}' not found".red unless File.exists?value
|
35
|
+
@config.manual_js_file = value
|
36
|
+
when :project_path
|
37
|
+
raise "project_path has to be an String".red unless value.kind_of?String
|
38
|
+
|
39
|
+
if File.exists?value and (value.end_with?".xcworkspace" or value.end_with?".xcodeproj")
|
40
|
+
@config.project_path = value
|
41
|
+
else
|
42
|
+
raise "The given project_path '#{value}' could not be found. Make sure to include the extension as well.".red
|
43
|
+
end
|
44
|
+
else
|
45
|
+
Helper.log.error "Unknown method #{method_sym}"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def verify_devices(value)
|
50
|
+
raise "Devices has to be an array".red unless value.kind_of?Array
|
51
|
+
value.each do |current|
|
52
|
+
current += " (#{@config.ios_version} Simulator)" unless current.include?"Simulator"
|
53
|
+
|
54
|
+
unless SnapshotFile.available_devices.include?current
|
55
|
+
raise "Device '#{current}' not found. Available device types: #{SnapshotFile.available_devices}".red
|
56
|
+
end
|
57
|
+
end
|
58
|
+
@config.devices = value
|
59
|
+
end
|
60
|
+
|
61
|
+
def verify_languages(value)
|
62
|
+
raise "Languages has to be an array".red unless value.kind_of?Array
|
63
|
+
value.each do |current|
|
64
|
+
unless Languages::ALL_LANGUAGES.include?current
|
65
|
+
raise "Language '#{current}' not found. Available languages: #{Languages::ALL_LANGUAGES}".red
|
66
|
+
end
|
67
|
+
end
|
68
|
+
@config.languages = value
|
69
|
+
end
|
70
|
+
|
71
|
+
def self.available_devices
|
72
|
+
if not @result
|
73
|
+
@result = []
|
74
|
+
`instruments -s`.split("\n").each do |current|
|
75
|
+
# Example: "iPhone 5 (8.1 Simulator) [C49ECC4A-5A3D-44B6-B9BF-4E25BC326400]"
|
76
|
+
@result << current.split(' [').first if current.include?"Simulator"
|
77
|
+
end
|
78
|
+
end
|
79
|
+
return @result
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'open-uri'
|
2
|
+
|
3
|
+
module Snapshot
|
4
|
+
# Verifies, the user runs the latest version of this gem
|
5
|
+
class UpdateChecker
|
6
|
+
# This method will check if the latest version is installed and show a warning if that's not the case
|
7
|
+
def self.verify_latest_version
|
8
|
+
if self.update_available?
|
9
|
+
v = fetch_latest
|
10
|
+
puts '#######################################################################'.green
|
11
|
+
puts "# Snapshot #{v} is available.".green
|
12
|
+
puts "# It is recommended to use the latest version.".green
|
13
|
+
puts "# Update using '(sudo) gem update snapshot'.".green
|
14
|
+
puts "# To see what's new, open https://github.com/KrauseFx/snapshot/releases.".green
|
15
|
+
puts '#######################################################################'.green
|
16
|
+
return true
|
17
|
+
end
|
18
|
+
false
|
19
|
+
end
|
20
|
+
|
21
|
+
# Is a new official release available (this does not include pre-releases)
|
22
|
+
def self.update_available?
|
23
|
+
begin
|
24
|
+
latest = fetch_latest
|
25
|
+
if latest and Gem::Version.new(latest) > Gem::Version.new(current_version)
|
26
|
+
return true
|
27
|
+
end
|
28
|
+
rescue Exception => ex
|
29
|
+
Helper.log.debug(ex)
|
30
|
+
Helper.log.error("Could not check if 'snapshot' is up to date.")
|
31
|
+
end
|
32
|
+
return false
|
33
|
+
end
|
34
|
+
|
35
|
+
# The currently used version of this gem
|
36
|
+
def self.current_version
|
37
|
+
Snapshot::VERSION
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
def self.fetch_latest
|
42
|
+
JSON.parse(open("http://rubygems.org/api/v1/gems/snapshot.json").read)["version"]
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
metadata
CHANGED
@@ -1,23 +1,191 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: snapshot
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Felix Krause
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-11-
|
12
|
-
dependencies:
|
13
|
-
|
11
|
+
date: 2014-11-10 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: json
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: highline
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 1.6.21
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 1.6.21
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: plist
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 3.1.0
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 3.1.0
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: colored
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: commander
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 4.2.0
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 4.2.0
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: bundler
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: rake
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: rspec
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - "~>"
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: 3.1.0
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - "~>"
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: 3.1.0
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: pry
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ">="
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ">="
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: yard
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - "~>"
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: 0.8.7.4
|
146
|
+
type: :development
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - "~>"
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: 0.8.7.4
|
153
|
+
- !ruby/object:Gem::Dependency
|
154
|
+
name: codeclimate-test-reporter
|
155
|
+
requirement: !ruby/object:Gem::Requirement
|
156
|
+
requirements:
|
157
|
+
- - ">="
|
158
|
+
- !ruby/object:Gem::Version
|
159
|
+
version: '0'
|
160
|
+
type: :development
|
161
|
+
prerelease: false
|
162
|
+
version_requirements: !ruby/object:Gem::Requirement
|
163
|
+
requirements:
|
164
|
+
- - ">="
|
165
|
+
- !ruby/object:Gem::Version
|
166
|
+
version: '0'
|
167
|
+
description: Take the pain out of taking iOS app screenshots.
|
14
168
|
email:
|
15
169
|
- krausefx@gmail.com
|
16
|
-
executables:
|
170
|
+
executables:
|
171
|
+
- snapshot
|
17
172
|
extensions: []
|
18
173
|
extra_rdoc_files: []
|
19
|
-
files:
|
20
|
-
|
174
|
+
files:
|
175
|
+
- LICENSE
|
176
|
+
- README.md
|
177
|
+
- bin/snapshot
|
178
|
+
- lib/snapshot.rb
|
179
|
+
- lib/snapshot/builder.rb
|
180
|
+
- lib/snapshot/dependency_checker.rb
|
181
|
+
- lib/snapshot/helper.rb
|
182
|
+
- lib/snapshot/languages.rb
|
183
|
+
- lib/snapshot/runner.rb
|
184
|
+
- lib/snapshot/snapshot_config.rb
|
185
|
+
- lib/snapshot/snapshot_file.rb
|
186
|
+
- lib/snapshot/update_checker.rb
|
187
|
+
- lib/snapshot/version.rb
|
188
|
+
homepage: http://felixkrause.at
|
21
189
|
licenses:
|
22
190
|
- MIT
|
23
191
|
metadata: {}
|
@@ -41,6 +209,6 @@ rubyforge_project:
|
|
41
209
|
rubygems_version: 2.2.2
|
42
210
|
signing_key:
|
43
211
|
specification_version: 4
|
44
|
-
summary:
|
212
|
+
summary: Snapshot - Create hundreds of iOS app screenshots automatically
|
45
213
|
test_files: []
|
46
214
|
has_rdoc:
|