snapshot 0.0.1.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
[![Twitter: @KauseFx](https://img.shields.io/badge/contact-@KrauseFx-blue.svg?style=flat)](https://twitter.com/KrauseFx)
|
9
|
+
<!-- [![License](http://img.shields.io/badge/license-MIT-green.svg?style=flat)](https://github.com/KrauseFx/deliver/blob/develop/LICENSE)
|
10
|
+
[![Gem](https://img.shields.io/gem/v/deliver.svg?style=flat)](http://rubygems.org/gems/deliver)
|
11
|
+
[![Build Status](https://img.shields.io/travis/KrauseFx/deliver/master.svg?style=flat)](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:
|