pantograph 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (202) hide show
  1. checksums.yaml +7 -0
  2. data/.yardopts +1 -0
  3. data/LICENSE +21 -0
  4. data/README.md +197 -0
  5. data/bin/bin-proxy +19 -0
  6. data/bin/pantograph +23 -0
  7. data/pantograph/README.md +11 -0
  8. data/pantograph/lib/assets/ActionDetails.md.erb +106 -0
  9. data/pantograph/lib/assets/Actions.md.erb +43 -0
  10. data/pantograph/lib/assets/DefaultPantfileTemplate +20 -0
  11. data/pantograph/lib/assets/completions/completion.bash +23 -0
  12. data/pantograph/lib/assets/completions/completion.fish +39 -0
  13. data/pantograph/lib/assets/completions/completion.sh +12 -0
  14. data/pantograph/lib/assets/completions/completion.zsh +23 -0
  15. data/pantograph/lib/assets/custom_action_template.rb +80 -0
  16. data/pantograph/lib/assets/report_template.xml.erb +15 -0
  17. data/pantograph/lib/pantograph/action.rb +194 -0
  18. data/pantograph/lib/pantograph/action_collector.rb +35 -0
  19. data/pantograph/lib/pantograph/actions/README.md +3 -0
  20. data/pantograph/lib/pantograph/actions/actions_helper.rb +166 -0
  21. data/pantograph/lib/pantograph/actions/add_extra_platforms.rb +45 -0
  22. data/pantograph/lib/pantograph/actions/artifactory.rb +157 -0
  23. data/pantograph/lib/pantograph/actions/bundle_install.rb +156 -0
  24. data/pantograph/lib/pantograph/actions/changelog_from_git_commits.rb +197 -0
  25. data/pantograph/lib/pantograph/actions/clipboard.rb +52 -0
  26. data/pantograph/lib/pantograph/actions/cloc.rb +89 -0
  27. data/pantograph/lib/pantograph/actions/create_pull_request.rb +190 -0
  28. data/pantograph/lib/pantograph/actions/danger.rb +131 -0
  29. data/pantograph/lib/pantograph/actions/debug.rb +32 -0
  30. data/pantograph/lib/pantograph/actions/default_platform.rb +47 -0
  31. data/pantograph/lib/pantograph/actions/download.rb +76 -0
  32. data/pantograph/lib/pantograph/actions/echo.rb +14 -0
  33. data/pantograph/lib/pantograph/actions/ensure_bundle_exec.rb +59 -0
  34. data/pantograph/lib/pantograph/actions/ensure_env_vars.rb +58 -0
  35. data/pantograph/lib/pantograph/actions/ensure_git_branch.rb +69 -0
  36. data/pantograph/lib/pantograph/actions/ensure_git_status_clean.rb +81 -0
  37. data/pantograph/lib/pantograph/actions/erb.rb +88 -0
  38. data/pantograph/lib/pantograph/actions/get_build_number_repository.rb +120 -0
  39. data/pantograph/lib/pantograph/actions/get_github_release.rb +163 -0
  40. data/pantograph/lib/pantograph/actions/git_add.rb +93 -0
  41. data/pantograph/lib/pantograph/actions/git_branch.rb +58 -0
  42. data/pantograph/lib/pantograph/actions/git_commit.rb +80 -0
  43. data/pantograph/lib/pantograph/actions/git_pull.rb +53 -0
  44. data/pantograph/lib/pantograph/actions/git_submodule_update.rb +52 -0
  45. data/pantograph/lib/pantograph/actions/git_tag_exists.rb +74 -0
  46. data/pantograph/lib/pantograph/actions/github_api.rb +262 -0
  47. data/pantograph/lib/pantograph/actions/gradle.rb +278 -0
  48. data/pantograph/lib/pantograph/actions/import.rb +49 -0
  49. data/pantograph/lib/pantograph/actions/import_from_git.rb +71 -0
  50. data/pantograph/lib/pantograph/actions/is_ci.rb +51 -0
  51. data/pantograph/lib/pantograph/actions/jira.rb +115 -0
  52. data/pantograph/lib/pantograph/actions/lane_context.rb +60 -0
  53. data/pantograph/lib/pantograph/actions/last_git_commit.rb +58 -0
  54. data/pantograph/lib/pantograph/actions/last_git_tag.rb +51 -0
  55. data/pantograph/lib/pantograph/actions/make_changelog_from_jenkins.rb +81 -0
  56. data/pantograph/lib/pantograph/actions/min_pantograph_version.rb +57 -0
  57. data/pantograph/lib/pantograph/actions/nexus_upload.rb +230 -0
  58. data/pantograph/lib/pantograph/actions/notification.rb +75 -0
  59. data/pantograph/lib/pantograph/actions/number_of_commits.rb +75 -0
  60. data/pantograph/lib/pantograph/actions/opt_out_usage.rb +40 -0
  61. data/pantograph/lib/pantograph/actions/pantograph_version.rb +15 -0
  62. data/pantograph/lib/pantograph/actions/println.rb +14 -0
  63. data/pantograph/lib/pantograph/actions/prompt.rb +119 -0
  64. data/pantograph/lib/pantograph/actions/push_git_tags.rb +76 -0
  65. data/pantograph/lib/pantograph/actions/push_to_git_remote.rb +127 -0
  66. data/pantograph/lib/pantograph/actions/puts.rb +68 -0
  67. data/pantograph/lib/pantograph/actions/reset_git_repo.rb +121 -0
  68. data/pantograph/lib/pantograph/actions/rocket.rb +83 -0
  69. data/pantograph/lib/pantograph/actions/rsync.rb +74 -0
  70. data/pantograph/lib/pantograph/actions/ruby_version.rb +56 -0
  71. data/pantograph/lib/pantograph/actions/say.rb +56 -0
  72. data/pantograph/lib/pantograph/actions/scp.rb +114 -0
  73. data/pantograph/lib/pantograph/actions/set_github_release.rb +274 -0
  74. data/pantograph/lib/pantograph/actions/sh.rb +71 -0
  75. data/pantograph/lib/pantograph/actions/skip_docs.rb +52 -0
  76. data/pantograph/lib/pantograph/actions/slack.rb +288 -0
  77. data/pantograph/lib/pantograph/actions/sonar.rb +156 -0
  78. data/pantograph/lib/pantograph/actions/ssh.rb +162 -0
  79. data/pantograph/lib/pantograph/actions/twitter.rb +89 -0
  80. data/pantograph/lib/pantograph/actions/update_pantograph.rb +177 -0
  81. data/pantograph/lib/pantograph/actions/zip.rb +120 -0
  82. data/pantograph/lib/pantograph/auto_complete.rb +82 -0
  83. data/pantograph/lib/pantograph/boolean.rb +5 -0
  84. data/pantograph/lib/pantograph/cli_tools_distributor.rb +183 -0
  85. data/pantograph/lib/pantograph/command_line_handler.rb +43 -0
  86. data/pantograph/lib/pantograph/commands_generator.rb +344 -0
  87. data/pantograph/lib/pantograph/configuration_helper.rb +26 -0
  88. data/pantograph/lib/pantograph/core_ext/bundler_monkey_patch.rb +14 -0
  89. data/pantograph/lib/pantograph/documentation/actions_list.rb +214 -0
  90. data/pantograph/lib/pantograph/documentation/docs_generator.rb +95 -0
  91. data/pantograph/lib/pantograph/documentation/markdown_docs_generator.rb +221 -0
  92. data/pantograph/lib/pantograph/environment_printer.rb +282 -0
  93. data/pantograph/lib/pantograph/erb_template_helper.rb +30 -0
  94. data/pantograph/lib/pantograph/features.rb +4 -0
  95. data/pantograph/lib/pantograph/helper/README.md +29 -0
  96. data/pantograph/lib/pantograph/helper/dotenv_helper.rb +50 -0
  97. data/pantograph/lib/pantograph/helper/gem_helper.rb +26 -0
  98. data/pantograph/lib/pantograph/helper/git_helper.rb +135 -0
  99. data/pantograph/lib/pantograph/helper/gradle_helper.rb +62 -0
  100. data/pantograph/lib/pantograph/helper/sh_helper.rb +134 -0
  101. data/pantograph/lib/pantograph/junit_generator.rb +27 -0
  102. data/pantograph/lib/pantograph/lane.rb +97 -0
  103. data/pantograph/lib/pantograph/lane_list.rb +77 -0
  104. data/pantograph/lib/pantograph/lane_manager.rb +140 -0
  105. data/pantograph/lib/pantograph/lane_manager_base.rb +92 -0
  106. data/pantograph/lib/pantograph/markdown_table_formatter.rb +62 -0
  107. data/pantograph/lib/pantograph/new_action.rb +47 -0
  108. data/pantograph/lib/pantograph/one_off.rb +45 -0
  109. data/pantograph/lib/pantograph/other_action.rb +29 -0
  110. data/pantograph/lib/pantograph/pant_file.rb +377 -0
  111. data/pantograph/lib/pantograph/pantograph_require.rb +75 -0
  112. data/pantograph/lib/pantograph/plugins/plugin_fetcher.rb +55 -0
  113. data/pantograph/lib/pantograph/plugins/plugin_generator.rb +86 -0
  114. data/pantograph/lib/pantograph/plugins/plugin_generator_ui.rb +19 -0
  115. data/pantograph/lib/pantograph/plugins/plugin_info.rb +49 -0
  116. data/pantograph/lib/pantograph/plugins/plugin_info_collector.rb +159 -0
  117. data/pantograph/lib/pantograph/plugins/plugin_manager.rb +387 -0
  118. data/pantograph/lib/pantograph/plugins/plugin_search.rb +46 -0
  119. data/pantograph/lib/pantograph/plugins/plugin_update_manager.rb +70 -0
  120. data/pantograph/lib/pantograph/plugins/plugins.rb +12 -0
  121. data/pantograph/lib/pantograph/plugins/template/%gem_name%.gemspec.erb +35 -0
  122. data/pantograph/lib/pantograph/plugins/template/.circleci/config.yml +43 -0
  123. data/pantograph/lib/pantograph/plugins/template/.gitignore +12 -0
  124. data/pantograph/lib/pantograph/plugins/template/.rspec +5 -0
  125. data/pantograph/lib/pantograph/plugins/template/.rubocop.yml +179 -0
  126. data/pantograph/lib/pantograph/plugins/template/.travis.yml +4 -0
  127. data/pantograph/lib/pantograph/plugins/template/Gemfile +6 -0
  128. data/pantograph/lib/pantograph/plugins/template/LICENSE.erb +21 -0
  129. data/pantograph/lib/pantograph/plugins/template/README.md.erb +52 -0
  130. data/pantograph/lib/pantograph/plugins/template/Rakefile +9 -0
  131. data/pantograph/lib/pantograph/plugins/template/lib/pantograph/plugin/%plugin_name%/actions/%plugin_name%_action.rb.erb +47 -0
  132. data/pantograph/lib/pantograph/plugins/template/lib/pantograph/plugin/%plugin_name%/helper/%plugin_name%_helper.rb.erb +16 -0
  133. data/pantograph/lib/pantograph/plugins/template/lib/pantograph/plugin/%plugin_name%/version.rb.erb +5 -0
  134. data/pantograph/lib/pantograph/plugins/template/lib/pantograph/plugin/%plugin_name%.rb.erb +16 -0
  135. data/pantograph/lib/pantograph/plugins/template/pantograph/Pantfile.erb +3 -0
  136. data/pantograph/lib/pantograph/plugins/template/pantograph/Pluginfile.erb +1 -0
  137. data/pantograph/lib/pantograph/plugins/template/spec/%plugin_name%_action_spec.rb.erb +9 -0
  138. data/pantograph/lib/pantograph/plugins/template/spec/spec_helper.rb.erb +15 -0
  139. data/pantograph/lib/pantograph/runner.rb +371 -0
  140. data/pantograph/lib/pantograph/server/action_command.rb +61 -0
  141. data/pantograph/lib/pantograph/server/action_command_return.rb +14 -0
  142. data/pantograph/lib/pantograph/server/command_executor.rb +7 -0
  143. data/pantograph/lib/pantograph/server/command_parser.rb +36 -0
  144. data/pantograph/lib/pantograph/server/control_command.rb +23 -0
  145. data/pantograph/lib/pantograph/server/json_return_value_processor.rb +72 -0
  146. data/pantograph/lib/pantograph/server/socket_server.rb +232 -0
  147. data/pantograph/lib/pantograph/server/socket_server_action_command_executor.rb +101 -0
  148. data/pantograph/lib/pantograph/setup/setup.rb +290 -0
  149. data/pantograph/lib/pantograph/setup/setup_android.rb +64 -0
  150. data/pantograph/lib/pantograph/setup/setup_ios.rb +412 -0
  151. data/pantograph/lib/pantograph/shells.rb +6 -0
  152. data/pantograph/lib/pantograph/supported_platforms.rb +28 -0
  153. data/pantograph/lib/pantograph/tools.rb +10 -0
  154. data/pantograph/lib/pantograph/version.rb +5 -0
  155. data/pantograph/lib/pantograph.rb +51 -0
  156. data/pantograph_core/README.md +79 -0
  157. data/pantograph_core/lib/assets/XMLTemplate.xml.erb +12 -0
  158. data/pantograph_core/lib/pantograph_core/analytics/action_completion_context.rb +34 -0
  159. data/pantograph_core/lib/pantograph_core/analytics/action_launch_context.rb +38 -0
  160. data/pantograph_core/lib/pantograph_core/analytics/analytics_event_builder.rb +23 -0
  161. data/pantograph_core/lib/pantograph_core/analytics/analytics_ingester_client.rb +54 -0
  162. data/pantograph_core/lib/pantograph_core/analytics/analytics_session.rb +71 -0
  163. data/pantograph_core/lib/pantograph_core/cert_checker.rb +116 -0
  164. data/pantograph_core/lib/pantograph_core/command_executor.rb +99 -0
  165. data/pantograph_core/lib/pantograph_core/configuration/commander_generator.rb +103 -0
  166. data/pantograph_core/lib/pantograph_core/configuration/config_item.rb +314 -0
  167. data/pantograph_core/lib/pantograph_core/configuration/configuration.rb +332 -0
  168. data/pantograph_core/lib/pantograph_core/configuration/configuration_file.rb +182 -0
  169. data/pantograph_core/lib/pantograph_core/core_ext/shellwords.rb +63 -0
  170. data/pantograph_core/lib/pantograph_core/core_ext/string.rb +17 -0
  171. data/pantograph_core/lib/pantograph_core/env.rb +9 -0
  172. data/pantograph_core/lib/pantograph_core/feature/feature.rb +51 -0
  173. data/pantograph_core/lib/pantograph_core/features.rb +4 -0
  174. data/pantograph_core/lib/pantograph_core/globals.rb +27 -0
  175. data/pantograph_core/lib/pantograph_core/helper.rb +409 -0
  176. data/pantograph_core/lib/pantograph_core/keychain_importer.rb +74 -0
  177. data/pantograph_core/lib/pantograph_core/languages.rb +14 -0
  178. data/pantograph_core/lib/pantograph_core/module.rb +29 -0
  179. data/pantograph_core/lib/pantograph_core/pantograph_folder.rb +39 -0
  180. data/pantograph_core/lib/pantograph_core/pantograph_pty.rb +57 -0
  181. data/pantograph_core/lib/pantograph_core/pkg_file_analyser.rb +44 -0
  182. data/pantograph_core/lib/pantograph_core/print_table.rb +131 -0
  183. data/pantograph_core/lib/pantograph_core/string_filters.rb +51 -0
  184. data/pantograph_core/lib/pantograph_core/swag.rb +85 -0
  185. data/pantograph_core/lib/pantograph_core/tag_version.rb +31 -0
  186. data/pantograph_core/lib/pantograph_core/test_parser.rb +107 -0
  187. data/pantograph_core/lib/pantograph_core/ui/disable_colors.rb +17 -0
  188. data/pantograph_core/lib/pantograph_core/ui/errors/pantograph_common_error.rb +19 -0
  189. data/pantograph_core/lib/pantograph_core/ui/errors/pantograph_crash.rb +11 -0
  190. data/pantograph_core/lib/pantograph_core/ui/errors/pantograph_error.rb +25 -0
  191. data/pantograph_core/lib/pantograph_core/ui/errors/pantograph_exception.rb +19 -0
  192. data/pantograph_core/lib/pantograph_core/ui/errors/pantograph_shell_error.rb +11 -0
  193. data/pantograph_core/lib/pantograph_core/ui/errors.rb +1 -0
  194. data/pantograph_core/lib/pantograph_core/ui/github_issue_inspector_reporter.rb +62 -0
  195. data/pantograph_core/lib/pantograph_core/ui/implementations/shell.rb +159 -0
  196. data/pantograph_core/lib/pantograph_core/ui/interface.rb +205 -0
  197. data/pantograph_core/lib/pantograph_core/ui/pantograph_runner.rb +276 -0
  198. data/pantograph_core/lib/pantograph_core/ui/ui.rb +26 -0
  199. data/pantograph_core/lib/pantograph_core/update_checker/changelog.rb +37 -0
  200. data/pantograph_core/lib/pantograph_core/update_checker/update_checker.rb +107 -0
  201. data/pantograph_core/lib/pantograph_core.rb +45 -0
  202. metadata +987 -0
@@ -0,0 +1,409 @@
1
+ require 'logger'
2
+ require 'colored'
3
+ require 'tty-spinner'
4
+ require 'pathname'
5
+
6
+ require_relative 'pantograph_folder'
7
+ require_relative 'ui/ui'
8
+ require_relative 'env'
9
+
10
+ module PantographCore
11
+ module Helper
12
+ # pantograph
13
+ #
14
+
15
+ def self.pantograph_enabled?
16
+ # This is called from the root context on the first start
17
+ @enabled ||= !PantographCore::PantographFolder.path.nil?
18
+ end
19
+
20
+ # Checks if pantograph is enabled for this project and returns the folder where the configuration lives
21
+ def self.pantograph_enabled_folder_path
22
+ pantograph_enabled? ? PantographCore::PantographFolder.path : '.'
23
+ end
24
+
25
+ # pantograph installation method
26
+ #
27
+
28
+ # @return [boolean] true if executing with bundler (like 'bundle exec pantograph [action]')
29
+ def self.bundler?
30
+ # Bundler environment variable
31
+ ['BUNDLE_BIN_PATH', 'BUNDLE_GEMFILE'].each do |current|
32
+ return true if ENV.key?(current)
33
+ end
34
+ return false
35
+ end
36
+
37
+ # Do we run from a bundled pantograph, which contains Ruby and OpenSSL?
38
+ # Usually this means the pantograph directory is ~/.pantograph/bin/
39
+ # We set this value via the environment variable `PANTOGRAPH_SELF_CONTAINED`
40
+ def self.contained_pantograph?
41
+ ENV["PANTOGRAPH_SELF_CONTAINED"].to_s == "true" && !self.homebrew?
42
+ end
43
+
44
+ # returns true if pantograph was installed via Homebrew
45
+ def self.homebrew?
46
+ ENV["PANTOGRAPH_INSTALLED_VIA_HOMEBREW"].to_s == "true"
47
+ end
48
+
49
+ # returns true if pantograph was installed via RubyGems
50
+ def self.rubygems?
51
+ !self.bundler? && !self.contained_pantograph? && !self.homebrew?
52
+ end
53
+
54
+ # environment
55
+ #
56
+
57
+ # @return true if the currently running program is a unit test
58
+ def self.test?
59
+ Object.const_defined?("SpecHelper")
60
+ end
61
+
62
+ # @return true if it is enabled to execute external commands
63
+ def self.sh_enabled?
64
+ !self.test?
65
+ end
66
+
67
+ # @return [boolean] true if building in a known CI environment
68
+ def self.ci?
69
+ # Check for Jenkins, Travis CI, ... environment variables
70
+ ['JENKINS_HOME', 'JENKINS_URL', 'TRAVIS', 'CIRCLECI', 'CI', 'APPCENTER_BUILD_ID', 'TEAMCITY_VERSION', 'GO_PIPELINE_NAME', 'bamboo_buildKey', 'GITLAB_CI', 'XCS', 'TF_BUILD', 'GITHUB_ACTION', 'GITHUB_ACTIONS'].each do |current|
71
+ return true if ENV.key?(current)
72
+ end
73
+ return false
74
+ end
75
+
76
+ def self.operating_system
77
+ return "macOS" if RUBY_PLATFORM.downcase.include?("darwin")
78
+ return "Windows" if RUBY_PLATFORM.downcase.include?("mswin")
79
+ return "Linux" if RUBY_PLATFORM.downcase.include?("linux")
80
+ return "Unknown"
81
+ end
82
+
83
+ def self.windows?
84
+ # taken from: https://stackoverflow.com/a/171011/1945875
85
+ (/cygwin|mswin|mingw|bccwin|wince|emx/ =~ RUBY_PLATFORM) != nil
86
+ end
87
+
88
+ def self.linux?
89
+ (/linux/ =~ RUBY_PLATFORM) != nil
90
+ end
91
+
92
+ # Is the currently running computer a Mac?
93
+ def self.mac?
94
+ (/darwin/ =~ RUBY_PLATFORM) != nil
95
+ end
96
+
97
+ # Do we want to disable the colored output?
98
+ def self.colors_disabled?
99
+ PantographCore::Env.truthy?("PANTOGRAPH_DISABLE_COLORS")
100
+ end
101
+
102
+ # Does the user use the Mac stock terminal
103
+ def self.mac_stock_terminal?
104
+ PantographCore::Env.truthy?("TERM_PROGRAM_VERSION")
105
+ end
106
+
107
+ # Logs base directory
108
+ def self.buildlog_path
109
+ return ENV["FL_BUILDLOG_PATH"] || "~/Library/Logs"
110
+ end
111
+
112
+ # Xcode
113
+ #
114
+
115
+ # @return the full path to the Xcode developer tools of the currently
116
+ # running system
117
+ def self.xcode_path
118
+ return "" unless self.mac?
119
+
120
+ if self.xcode_server?
121
+ # Xcode server always creates a link here
122
+ xcode_server_xcode_path = "/Library/Developer/XcodeServer/CurrentXcodeSymlink/Contents/Developer"
123
+ UI.verbose("We're running as XcodeServer, setting path to #{xcode_server_xcode_path}")
124
+ return xcode_server_xcode_path
125
+ end
126
+
127
+ return `xcode-select -p`.delete("\n") + "/"
128
+ end
129
+
130
+ def self.xcode_server?
131
+ # XCS is set by Xcode Server
132
+ return ENV["XCS"].to_i == 1
133
+ end
134
+
135
+ # @return The version of the currently used Xcode installation (e.g. "7.0")
136
+ def self.xcode_version
137
+ return nil unless self.mac?
138
+ return @xcode_version if @xcode_version && @developer_dir == ENV['DEVELOPER_DIR']
139
+
140
+ xcodebuild_path = "#{xcode_path}/usr/bin/xcodebuild"
141
+
142
+ xcode_build_installed = File.exist?(xcodebuild_path)
143
+ unless xcode_build_installed
144
+ UI.verbose("Couldn't find xcodebuild at #{xcodebuild_path}, check that it exists")
145
+ return nil
146
+ end
147
+
148
+ begin
149
+ output = `DEVELOPER_DIR='' "#{xcodebuild_path}" -version`
150
+ @xcode_version = output.split("\n").first.split(' ')[1]
151
+ @developer_dir = ENV['DEVELOPER_DIR']
152
+ rescue => ex
153
+ UI.error(ex)
154
+ UI.user_error!("Error detecting currently used Xcode installation, please ensure that you have Xcode installed and set it using `sudo xcode-select -s [path]`")
155
+ end
156
+ @xcode_version
157
+ end
158
+
159
+ # @return true if Xcode version is higher than 8.3
160
+ def self.xcode_at_least?(version)
161
+ PantographCore::UI.user_error!("Unable to locate Xcode. Please make sure to have Xcode installed on your machine") if xcode_version.nil?
162
+ v = xcode_version
163
+ Gem::Version.new(v) >= Gem::Version.new(version)
164
+ end
165
+
166
+ # iTMSTransporter
167
+ #
168
+
169
+ def self.transporter_java_executable_path
170
+ return File.join(self.transporter_java_path, 'bin', 'java')
171
+ end
172
+
173
+ def self.transporter_java_ext_dir
174
+ return File.join(self.transporter_java_path, 'lib', 'ext')
175
+ end
176
+
177
+ def self.transporter_java_jar_path
178
+ return File.join(self.itms_path, 'lib', 'itmstransporter-launcher.jar')
179
+ end
180
+
181
+ def self.transporter_user_dir
182
+ return File.join(self.itms_path, 'bin')
183
+ end
184
+
185
+ def self.transporter_java_path
186
+ return File.join(self.itms_path, 'java')
187
+ end
188
+
189
+ # @return the full path to the iTMSTransporter executable
190
+ def self.transporter_path
191
+ return File.join(self.itms_path, 'bin', 'iTMSTransporter') unless Helper.windows?
192
+ return File.join(self.itms_path, 'iTMSTransporter')
193
+ end
194
+
195
+ # @return the full path to the iTMSTransporter executable
196
+ def self.itms_path
197
+ return ENV["PANTOGRAPH_ITUNES_TRANSPORTER_PATH"] if PantographCore::Env.truthy?("PANTOGRAPH_ITUNES_TRANSPORTER_PATH")
198
+
199
+ if self.mac?
200
+ # First check for manually install iTMSTransporter
201
+ user_local_itms_path = "/usr/local/itms"
202
+ return user_local_itms_path if File.exist?(user_local_itms_path)
203
+
204
+ # Then check for iTMSTransporter in the Xcode path
205
+ [
206
+ "../Applications/Application Loader.app/Contents/MacOS/itms",
207
+ "../Applications/Application Loader.app/Contents/itms",
208
+ "../SharedFrameworks/ContentDeliveryServices.framework/Versions/A/itms" # For Xcode 11
209
+ ].each do |path|
210
+ result = File.expand_path(File.join(self.xcode_path, path))
211
+ return result if File.exist?(result)
212
+ end
213
+ UI.user_error!("Could not find transporter at #{self.xcode_path}. Please make sure you set the correct path to your Xcode installation.")
214
+ elsif self.windows?
215
+ [
216
+ "C:/Program Files (x86)/itms"
217
+ ].each do |path|
218
+ return path if File.exist?(path)
219
+ end
220
+ UI.user_error!("Could not find transporter at usual locations. Please use environment variable `PANTOGRAPH_ITUNES_TRANSPORTER_PATH` to specify your installation path.")
221
+ else
222
+ # not Mac or Windows
223
+ return ''
224
+ end
225
+ end
226
+
227
+ # keychain
228
+ #
229
+
230
+ def self.keychain_path(keychain_name)
231
+ # Existing code expects that a keychain name will be expanded into a default path to Library/Keychains
232
+ # in the user's home directory. However, this will not allow the user to pass an absolute path
233
+ # for the keychain value
234
+ #
235
+ # So, if the passed value can't be resolved as a file in Library/Keychains, just use it as-is
236
+ # as the keychain path.
237
+ #
238
+ # We need to expand each path because File.exist? won't handle directories including ~ properly
239
+ #
240
+ # We also try to append `-db` at the end of the file path, as with Sierra the default Keychain name
241
+ # has changed for some users: https://github.com/pantograph/pantograph/issues/5649
242
+
243
+ # Remove the ".keychain" at the end of the keychain name
244
+ name = keychain_name.sub(/\.keychain$/, "")
245
+
246
+ possible_locations = [
247
+ File.join(Dir.home, 'Library', 'Keychains', name),
248
+ name
249
+ ].map { |path| File.expand_path(path) }
250
+
251
+ # Transforms ["thing"] to ["thing-db", "thing.keychain-db", "thing", "thing.keychain"]
252
+ keychain_paths = []
253
+ possible_locations.each do |location|
254
+ keychain_paths << "#{location}-db"
255
+ keychain_paths << "#{location}.keychain-db"
256
+ keychain_paths << location
257
+ keychain_paths << "#{location}.keychain"
258
+ end
259
+
260
+ keychain_path = keychain_paths.find { |path| File.file?(path) }
261
+ UI.user_error!("Could not locate the provided keychain. Tried:\n\t#{keychain_paths.join("\n\t")}") unless keychain_path
262
+ keychain_path
263
+ end
264
+
265
+ # helper methods
266
+ #
267
+
268
+ # Runs a given command using backticks (`)
269
+ # and prints them out using the UI.command method
270
+ def self.backticks(command, print: true)
271
+ UI.command(command) if print
272
+ result = `#{command}`
273
+ UI.command_output(result) if print
274
+ return result
275
+ end
276
+
277
+ # removes ANSI colors from string
278
+ def self.strip_ansi_colors(str)
279
+ str.gsub(/\e\[([;\d]+)?m/, '')
280
+ end
281
+
282
+ # Zips directory
283
+ def self.zip_directory(path, output_path, contents_only: false, overwrite: false, print: true)
284
+ if overwrite
285
+ overwrite_command = " && rm -f '#{output_path}'"
286
+ else
287
+ overwrite_command = ""
288
+ end
289
+
290
+ if contents_only
291
+ command = "cd '#{path}'#{overwrite_command} && zip -r '#{output_path}' *"
292
+ else
293
+ containing_path = File.expand_path("..", path)
294
+ contents_path = File.basename(path)
295
+
296
+ command = "cd '#{containing_path}'#{overwrite_command} && zip -r '#{output_path}' '#{contents_path}'"
297
+ end
298
+
299
+ UI.command(command) unless print
300
+ Helper.backticks(command, print: print)
301
+ end
302
+
303
+ # Executes the provided block after adjusting the ENV to have the
304
+ # provided keys and values set as defined in hash. After the block
305
+ # completes, restores the ENV to its previous state.
306
+ def self.with_env_values(hash, &block)
307
+ old_vals = ENV.select { |k, v| hash.include?(k) }
308
+ hash.each do |k, v|
309
+ ENV[k] = hash[k]
310
+ end
311
+ yield
312
+ ensure
313
+ hash.each do |k, v|
314
+ ENV.delete(k) unless old_vals.include?(k)
315
+ ENV[k] = old_vals[k]
316
+ end
317
+ end
318
+
319
+ # loading indicator
320
+ #
321
+
322
+ def self.should_show_loading_indicator?
323
+ return false if PantographCore::Env.truthy?("PANTOGRAPH_DISABLE_ANIMATION")
324
+ return false if Helper.ci?
325
+ return true
326
+ end
327
+
328
+ # Show/Hide loading indicator
329
+ def self.show_loading_indicator(text = nil)
330
+ if self.should_show_loading_indicator?
331
+ # we set the default here, instead of at the parameters
332
+ # as we don't want to `UI.message` a rocket that's just there for the loading indicator
333
+ text ||= "🚀"
334
+ @require_pantograph_spinner = TTY::Spinner.new("[:spinner] #{text} ", format: :dots)
335
+ @require_pantograph_spinner.auto_spin
336
+ else
337
+ UI.message(text) if text
338
+ end
339
+ end
340
+
341
+ def self.hide_loading_indicator
342
+ if self.should_show_loading_indicator? && @require_pantograph_spinner
343
+ @require_pantograph_spinner.success
344
+ end
345
+ end
346
+
347
+ # files
348
+ #
349
+
350
+ # checks if a given path is an executable file
351
+ def self.executable?(cmd_path)
352
+ # no executable files on Windows, so existing is enough there
353
+ cmd_path && !File.directory?(cmd_path) && (File.executable?(cmd_path) || (self.windows? && File.exist?(cmd_path)))
354
+ end
355
+
356
+ # checks if given file is a valid json file
357
+ # base taken from: http://stackoverflow.com/a/26235831/1945875
358
+ def self.json_file?(filename)
359
+ return false unless File.exist?(filename)
360
+ begin
361
+ JSON.parse(File.read(filename))
362
+ return true
363
+ rescue JSON::ParserError
364
+ return false
365
+ end
366
+ end
367
+
368
+ # deprecated
369
+ #
370
+
371
+ # Use Helper.test?, Helper.ci?, Helper.mac? or Helper.windows? instead (legacy calls)
372
+ def self.is_test?
373
+ self.test?
374
+ end
375
+
376
+ def self.is_ci?
377
+ ci?
378
+ end
379
+
380
+ def self.is_mac?
381
+ self.mac?
382
+ end
383
+
384
+ def self.is_windows?
385
+ self.windows?
386
+ end
387
+
388
+ # <b>DEPRECATED:</b> Use the `ROOT` constant from the appropriate tool module instead
389
+ # e.g. File.join(Sigh::ROOT, 'lib', 'assets', 'resign.sh')
390
+ #
391
+ # Path to the installed gem to load resources (e.g. resign.sh)
392
+ def self.gem_path(gem_name)
393
+ UI.deprecated('`Helper.gem_path` is deprecated. Use the `ROOT` constant from the appropriate tool module instead.')
394
+
395
+ if !Helper.test? && Gem::Specification.find_all_by_name(gem_name).any?
396
+ return Gem::Specification.find_by_name(gem_name).gem_dir
397
+ else
398
+ return './'
399
+ end
400
+ end
401
+
402
+ # This method is deprecated, use the `UI` class
403
+ # https://docs.pantograph.tools/advanced/#user-input-and-output
404
+ def self.log
405
+ UI.deprecated("Helper.log is deprecated. Use `UI` class instead")
406
+ UI.current.log
407
+ end
408
+ end
409
+ end
@@ -0,0 +1,74 @@
1
+ require_relative 'helper'
2
+ require 'open3'
3
+
4
+ module PantographCore
5
+ class KeychainImporter
6
+ def self.import_file(path, keychain_path, keychain_password: "", certificate_password: "", output: PantographCore::Globals.verbose?)
7
+ UI.user_error!("Could not find file '#{path}'") unless File.exist?(path)
8
+
9
+ command = "security import #{path.shellescape} -k '#{keychain_path.shellescape}'"
10
+ command << " -P #{certificate_password.shellescape}"
11
+ command << " -T /usr/bin/codesign" # to not be asked for permission when running a tool like `gym` (before Sierra)
12
+ command << " -T /usr/bin/security"
13
+ command << " 1> /dev/null" unless output
14
+
15
+ UI.command(command) if output
16
+ Open3.popen3(command) do |stdin, stdout, stderr, thrd|
17
+ UI.command_output(stdout.read.to_s) if output
18
+
19
+ # Set partition list only if success since it can be a time consuming process if a lot of keys are installed
20
+ if thrd.value.success?
21
+ set_partition_list(path, keychain_path, keychain_password: keychain_password, output: output)
22
+ else
23
+ # Output verbose if file is already installed since not an error otherwise we will show the whole error
24
+ err = stderr.read.to_s.strip
25
+ if err.include?("SecKeychainItemImport") && err.include?("The specified item already exists in the keychain")
26
+ UI.verbose("'#{File.basename(path)}' is already installed on this machine")
27
+ else
28
+ UI.error(err)
29
+ end
30
+ end
31
+ end
32
+ end
33
+
34
+ def self.set_partition_list(path, keychain_path, keychain_password: "", output: PantographCore::Globals.verbose?)
35
+ # When security supports partition lists, also add the partition IDs
36
+ # See https://openradar.appspot.com/28524119
37
+ if Helper.backticks('security -h | grep set-key-partition-list', print: false).length > 0
38
+ command = "security set-key-partition-list"
39
+ command << " -S apple-tool:,apple:"
40
+ command << " -k #{keychain_password.to_s.shellescape}"
41
+ command << " #{keychain_path.shellescape}"
42
+ command << " 1> /dev/null" # always disable stdout. This can be very verbose, and leak potentially sensitive info
43
+
44
+ # Showing loading indicator as this can take some time if a lot of keys installed
45
+ Helper.show_loading_indicator("Setting key partition list... (this can take a minute if there are a lot of keys installed)")
46
+
47
+ UI.command(command) if output
48
+ Open3.popen3(command) do |stdin, stdout, stderr, thrd|
49
+ unless thrd.value.success?
50
+ err = stderr.read.to_s.strip
51
+
52
+ # Inform user when no/wrong password was used as its needed to prevent UI permission popup from Xcode when signing
53
+ if err.include?("SecKeychainItemSetAccessWithPassword")
54
+ UI.important("")
55
+ UI.important("Could not configure imported keychain item (certificate) to prevent UI permission popup when code signing\n" \
56
+ "Check if you supplied the correct `keychain_password` for keychain: `#{keychain_path}`\n" \
57
+ "#{err}")
58
+ UI.important("")
59
+ UI.important("Please look at the following docs to see how to set a keychain password:")
60
+ UI.important(" - https://docs.pantograph.tools/actions/sync_code_signing")
61
+ UI.important(" - https://docs.pantograph.tools/actions/get_certificates")
62
+ else
63
+ UI.error(err)
64
+ end
65
+ end
66
+ end
67
+
68
+ # Hiding after Open3 finishes
69
+ Helper.hide_loading_indicator
70
+
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,14 @@
1
+ module PantographCore
2
+ module Languages
3
+ # These are all the languages which are available to use to upload app metadata and screenshots
4
+
5
+ # The old format which was used until August 2015 (good old times)
6
+ ALL_LANGUAGES_LEGACY = ["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", "cmn-Hant"]
7
+
8
+ # The new format used from September 2015 on
9
+ # Updates should also be made to:
10
+ # - produce/lib/produce/available_default_languages.rb
11
+ # See pull request for example: https://github.com/pantograph/pantograph/pull/14110
12
+ ALL_LANGUAGES = ["ar-SA", "ca", "cs", "da", "de-DE", "el", "en-AU", "en-CA", "en-GB", "en-US", "es-ES", "es-MX", "fi", "fr-CA", "fr-FR", "he", "hi", "hr", "hu", "id", "it", "ja", "ko", "ms", "nl-NL", "no", "pl", "pt-BR", "pt-PT", "ro", "ru", "sk", "sv", "th", "tr", "uk", "vi", "zh-Hans", "zh-Hant"]
13
+ end
14
+ end
@@ -0,0 +1,29 @@
1
+ require 'pantograph/boolean'
2
+
3
+ require_relative 'analytics/analytics_session'
4
+
5
+ module PantographCore
6
+ ROOT = Pathname.new(File.expand_path('../../..', __FILE__))
7
+ Boolean = Pantograph::Boolean
8
+
9
+ # Session is used to report usage metrics.
10
+ # If you opt out, we will not send anything.
11
+ # You can confirm this by observing how we use the environment variable: PANTOGRAPH_OPT_OUT_USAGE
12
+ # Specifically, in AnalyticsSession.finalize_session
13
+ # Learn more at https://docs.pantograph.tools/#metrics
14
+ def self.session
15
+ @session ||= AnalyticsSession.new
16
+ end
17
+
18
+ def self.reset_session
19
+ @session = nil
20
+ end
21
+
22
+ # A directory that's being used to user-wide pantograph configs
23
+ # This directory is also used for the bundled pantograph
24
+ def self.pantograph_user_dir
25
+ path = File.expand_path(File.join(Dir.home, ".pantograph"))
26
+ FileUtils.mkdir_p(path) unless File.directory?(path)
27
+ return path
28
+ end
29
+ end
@@ -0,0 +1,39 @@
1
+ require_relative 'ui/ui'
2
+
3
+ module PantographCore
4
+ class PantographFolder
5
+ FOLDER_NAME = 'pantograph'
6
+
7
+ # Path to the pantograph folder containing the Pantfile and other configuration files
8
+ def self.path
9
+ value ||= "./#{FOLDER_NAME}/" if File.directory?("./#{FOLDER_NAME}/")
10
+ value ||= "./.#{FOLDER_NAME}/" if File.directory?("./.#{FOLDER_NAME}/") # hidden folder
11
+ value ||= "./" if File.basename(Dir.getwd) == FOLDER_NAME && File.exist?('Pantfile') # inside the folder
12
+ value ||= "./" if File.basename(Dir.getwd) == ".#{FOLDER_NAME}" && File.exist?('Pantfile') # inside the folder and hidden
13
+ return value
14
+ end
15
+
16
+ # Path to the Pantfile inside the pantograph folder. This is nil when none is available
17
+ def self.pantfile_path
18
+ return nil if self.path.nil?
19
+
20
+ path = File.join(self.path, 'Pantfile')
21
+ return path if File.exist?(path)
22
+ return nil
23
+ end
24
+
25
+ # Does a pantograph configuration already exist?
26
+ def self.setup?
27
+ return false unless self.pantfile_path
28
+ File.exist?(self.pantfile_path)
29
+ end
30
+
31
+ def self.create_folder!(path = nil)
32
+ path = File.join(path || '.', FOLDER_NAME)
33
+ return if File.directory?(path) # directory is already there
34
+ UI.user_error!("Found a file called 'pantograph' at path '#{path}', please delete it") if File.exist?(path)
35
+ FileUtils.mkdir_p(path)
36
+ UI.success("Created new folder '#{path}'.")
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,57 @@
1
+ # Source: Mix of https://github.com/pantograph/pantograph/pull/7202/files,
2
+ # https://github.com/pantograph/pantograph/pull/11384#issuecomment-356084518 and
3
+ # https://github.com/DragonBox/u3d/blob/59e471ad78ac00cb629f479dbe386c5ad2dc5075/lib/u3d_core/command_runner.rb#L88-L96
4
+
5
+ class StandardError
6
+ def exit_status
7
+ return -1
8
+ end
9
+ end
10
+
11
+ module PantographCore
12
+ class PantographPtyError < StandardError
13
+ attr_reader :exit_status
14
+ def initialize(e, exit_status)
15
+ super(e)
16
+ set_backtrace(e.backtrace) if e
17
+ @exit_status = exit_status
18
+ end
19
+ end
20
+
21
+ class PantographPty
22
+ def self.spawn(command)
23
+ require 'pty'
24
+ PTY.spawn(command) do |command_stdout, command_stdin, pid|
25
+ begin
26
+ yield(command_stdout, command_stdin, pid)
27
+ rescue Errno::EIO
28
+ # Exception ignored intentionally.
29
+ # https://stackoverflow.com/questions/10238298/ruby-on-linux-pty-goes-away-without-eof-raises-errnoeio
30
+ # This is expected on some linux systems, that indicates that the subcommand finished
31
+ # and we kept trying to read, ignore it
32
+ ensure
33
+ begin
34
+ Process.wait(pid)
35
+ rescue Errno::ECHILD, PTY::ChildExited
36
+ # The process might have exited.
37
+ end
38
+ end
39
+ end
40
+ $?.exitstatus
41
+ rescue LoadError
42
+ require 'open3'
43
+ Open3.popen2e(command) do |command_stdin, command_stdout, p| # note the inversion
44
+ yield(command_stdout, command_stdin, p.value.pid)
45
+
46
+ command_stdin.close
47
+ command_stdout.close
48
+ p.value.exitstatus
49
+ end
50
+ rescue StandardError => e
51
+ # Wrapping any error in PantographPtyError to allow
52
+ # callers to see and use $?.exitstatus that
53
+ # would usually get returned
54
+ raise PantographPtyError.new(e, $?.exitstatus)
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,44 @@
1
+ require 'rexml/document'
2
+
3
+ require_relative 'helper'
4
+
5
+ module PantographCore
6
+ class PkgFileAnalyser
7
+ def self.fetch_app_identifier(path)
8
+ xml = self.fetch_distribution_xml_file(path)
9
+ return xml.elements['installer-gui-script/product'].attributes['id'] if xml
10
+ return nil
11
+ end
12
+
13
+ # Fetches the app version from the given pkg file.
14
+ def self.fetch_app_version(path)
15
+ xml = self.fetch_distribution_xml_file(path)
16
+ return xml.elements['installer-gui-script/product'].attributes['version'] if xml
17
+ return nil
18
+ end
19
+
20
+ def self.fetch_distribution_xml_file(path)
21
+ Dir.mktmpdir do |dir|
22
+ Helper.backticks("xar -C #{dir.shellescape} -xf #{path.shellescape}")
23
+
24
+ Dir.foreach(dir) do |file|
25
+ next unless file.include?('Distribution')
26
+
27
+ begin
28
+ content = File.open(File.join(dir, file))
29
+ xml = REXML::Document.new(content)
30
+
31
+ if xml.elements['installer-gui-script/product']
32
+ return xml
33
+ end
34
+ rescue => ex
35
+ UI.error(ex)
36
+ UI.error("Error parsing *.pkg distribution xml #{File.join(dir, file)}")
37
+ end
38
+ end
39
+
40
+ nil
41
+ end
42
+ end
43
+ end
44
+ end