gsdkcp-tool 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 72aa98955b1ce78371d6ec0bc0670bd18d2937f97f7dcd2ee35607b3c3c66aa5
4
+ data.tar.gz: 2f2f36264c62825bb62e5fb712db9010d3108a276b31ea495b3588d8fd22b3fc
5
+ SHA512:
6
+ metadata.gz: ef775eae8641a5e3d0373e9fb492cc3a315daca9a7714c558edef017374300ddc6bce4e0ca5bad927cf67ba3b86899b6320e207443faf549e5ede3fa3eb41ceb
7
+ data.tar.gz: 996f6ec2c294adc53f97b1d358c8fb02112c4452aeda8bf3fa91be26558c90c4af74e83647d3f9bc5438de286569fc98080cdef6ee6d60c995681b5c094fe4f1
data/.gitignore ADDED
@@ -0,0 +1,8 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
data/.travis.yml ADDED
@@ -0,0 +1,6 @@
1
+ ---
2
+ language: ruby
3
+ cache: bundler
4
+ rvm:
5
+ - 2.6.3
6
+ before_install: gem install bundler -v 2.1.4
@@ -0,0 +1,74 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ In the interest of fostering an open and welcoming environment, we as
6
+ contributors and maintainers pledge to making participation in our project and
7
+ our community a harassment-free experience for everyone, regardless of age, body
8
+ size, disability, ethnicity, gender identity and expression, level of experience,
9
+ nationality, personal appearance, race, religion, or sexual identity and
10
+ orientation.
11
+
12
+ ## Our Standards
13
+
14
+ Examples of behavior that contributes to creating a positive environment
15
+ include:
16
+
17
+ * Using welcoming and inclusive language
18
+ * Being respectful of differing viewpoints and experiences
19
+ * Gracefully accepting constructive criticism
20
+ * Focusing on what is best for the community
21
+ * Showing empathy towards other community members
22
+
23
+ Examples of unacceptable behavior by participants include:
24
+
25
+ * The use of sexualized language or imagery and unwelcome sexual attention or
26
+ advances
27
+ * Trolling, insulting/derogatory comments, and personal or political attacks
28
+ * Public or private harassment
29
+ * Publishing others' private information, such as a physical or electronic
30
+ address, without explicit permission
31
+ * Other conduct which could reasonably be considered inappropriate in a
32
+ professional setting
33
+
34
+ ## Our Responsibilities
35
+
36
+ Project maintainers are responsible for clarifying the standards of acceptable
37
+ behavior and are expected to take appropriate and fair corrective action in
38
+ response to any instances of unacceptable behavior.
39
+
40
+ Project maintainers have the right and responsibility to remove, edit, or
41
+ reject comments, commits, code, wiki edits, issues, and other contributions
42
+ that are not aligned to this Code of Conduct, or to ban temporarily or
43
+ permanently any contributor for other behaviors that they deem inappropriate,
44
+ threatening, offensive, or harmful.
45
+
46
+ ## Scope
47
+
48
+ This Code of Conduct applies both within project spaces and in public spaces
49
+ when an individual is representing the project or its community. Examples of
50
+ representing a project or community include using an official project e-mail
51
+ address, posting via an official social media account, or acting as an appointed
52
+ representative at an online or offline event. Representation of a project may be
53
+ further defined and clarified by project maintainers.
54
+
55
+ ## Enforcement
56
+
57
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
58
+ reported by contacting the project team at zhangjinquan@bytedance.com. All
59
+ complaints will be reviewed and investigated and will result in a response that
60
+ is deemed necessary and appropriate to the circumstances. The project team is
61
+ obligated to maintain confidentiality with regard to the reporter of an incident.
62
+ Further details of specific enforcement policies may be posted separately.
63
+
64
+ Project maintainers who do not follow or enforce the Code of Conduct in good
65
+ faith may face temporary or permanent repercussions as determined by other
66
+ members of the project's leadership.
67
+
68
+ ## Attribution
69
+
70
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71
+ available at [https://contributor-covenant.org/version/1/4][version]
72
+
73
+ [homepage]: https://contributor-covenant.org
74
+ [version]: https://contributor-covenant.org/version/1/4/
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ source "https://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in gsdkcp-tool.gemspec
4
+ gemspec
5
+
6
+ gem "rake", "~> 12.0"
7
+ gem "minitest", "~> 5.0"
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2022 zhangjinquan
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
13
+ all 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
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,44 @@
1
+ # Gsdkcp::Tool
2
+
3
+ Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/gsdkcp/tool`. To experiment with that code, run `bin/console` for an interactive prompt.
4
+
5
+ TODO: Delete this and the text above, and describe your gem
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'gsdkcp-tool'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle install
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install gsdkcp-tool
22
+
23
+ ## Usage
24
+
25
+ TODO: Write usage instructions here
26
+
27
+ ## Development
28
+
29
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
30
+
31
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
32
+
33
+ ## Contributing
34
+
35
+ Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/gsdkcp-tool. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/[USERNAME]/gsdkcp-tool/blob/master/CODE_OF_CONDUCT.md).
36
+
37
+
38
+ ## License
39
+
40
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
41
+
42
+ ## Code of Conduct
43
+
44
+ Everyone interacting in the Gsdkcp::Tool project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/gsdkcp-tool/blob/master/CODE_OF_CONDUCT.md).
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.libs << "test"
6
+ t.libs << "lib"
7
+ t.test_files = FileList["test/**/*_test.rb"]
8
+ end
9
+
10
+ task :default => :test
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "gcpt"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
data/exe/gsdkcp-tool ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "gcpt"
5
+
6
+ GCPT::GCPTCommand.run(ARGV)
@@ -0,0 +1,31 @@
1
+ require_relative 'lib/gcpt/version'
2
+
3
+ Gem::Specification.new do |spec|
4
+ spec.name = "gsdkcp-tool"
5
+ spec.version = GCPT::VERSION
6
+ spec.authors = ["zhangjinquan"]
7
+ spec.email = ["zhangjinquan@bytedance.com"]
8
+
9
+ spec.summary = %q{CLI tool for GSDK integration.}
10
+ spec.description = %q{CLI tool for GSDK integration.}
11
+ spec.homepage = "https://gdev.nvsgames.cn/home"
12
+ spec.license = "MIT"
13
+ spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0")
14
+
15
+ spec.metadata["allowed_push_host"] = "https://rubygems.org"
16
+
17
+ spec.metadata["homepage_uri"] = spec.homepage
18
+ spec.metadata["source_code_uri"] = "https://gdev.nvsgames.cn/home"
19
+ spec.metadata["changelog_uri"] = "https://gdev.nvsgames.cn/home"
20
+
21
+ # Specify which files should be added to the gem when it is released.
22
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
23
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
24
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
25
+ end
26
+ spec.add_runtime_dependency "claide", "~> 1.0.3"
27
+ spec.add_runtime_dependency "xcodeproj", "~> 1.21.0"
28
+ spec.bindir = "exe"
29
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
30
+ spec.require_paths = ["lib"]
31
+ end
@@ -0,0 +1,90 @@
1
+ require 'gcpt/utils/json_model'
2
+
3
+ module GCPT
4
+ module BuildReport
5
+ class BaseInfo
6
+ include JSONable
7
+
8
+ attr_accessor :region # string, cn/i18n, unknown
9
+ attr_accessor :app_version # string
10
+ attr_accessor :build_version # string
11
+ attr_accessor :gsdk_version # string
12
+ attr_accessor :project_type # string, application/library
13
+ attr_accessor :app_size # number, TODO:delayed
14
+ attr_accessor :engine_type # string
15
+ attr_accessor :engine_version # string
16
+ attr_accessor :languages ## # string, zh,en
17
+ end
18
+
19
+ class GsdkInfo
20
+ include JSONable
21
+
22
+ attr_accessor :build_info # map
23
+ attr_accessor :checksums # map, TODO:delayed
24
+ end
25
+
26
+ class ENVInfo
27
+ include JSONable
28
+
29
+ attr_accessor :env # string
30
+ attr_accessor :os # string
31
+ attr_accessor :os_version # string
32
+ attr_accessor :machine # string
33
+ attr_accessor :device_id # string
34
+ attr_accessor :build_tool # string, TODO:delayed
35
+ attr_accessor :build_mode # string, TODO:delayed
36
+ attr_accessor :deps_tool # string, cocoapods/unknown/...
37
+ end
38
+
39
+ class ProjectInfo
40
+ include JSONable
41
+
42
+ attr_accessor :build_config # string
43
+ attr_accessor :build_settings # map
44
+ attr_accessor :swift_version # string, TODO:delayed
45
+ attr_accessor :info_plist # string
46
+ attr_accessor :entitlement # string
47
+ attr_accessor :game_config # map
48
+ end
49
+
50
+ class BuildMatric
51
+ include JSONable
52
+
53
+ attr_accessor :name # string
54
+ attr_accessor :duration # number, seconds
55
+ end
56
+
57
+ class ExtraInfo
58
+ include JSONable
59
+
60
+ attr_accessor :error_message # string, TODO:
61
+ end
62
+
63
+ class ReportInfo
64
+ include JSONable
65
+
66
+ # autofill
67
+ attr_accessor :protocol_version # number # 3
68
+ attr_accessor :platform # string # ios
69
+
70
+ attr_accessor :app_id # string
71
+ attr_accessor :application_id # string
72
+ attr_accessor :build_begin # number, seconds, TODO:
73
+ attr_accessor :build_end # number, seconds, TODO:
74
+
75
+ attr_accessor :base_info # object, BaseInfo
76
+ attr_accessor :gsdk_info # object, GsdkInfo
77
+ attr_accessor :env_info # object, ENVInfo
78
+ attr_accessor :project_info # object, ProjectInfo
79
+ attr_accessor :build_log # string, TODO:
80
+ attr_accessor :build_spends # list, [BuildMatric]
81
+ attr_accessor :build_result # string, success/failed
82
+
83
+ def initialize
84
+ super
85
+ self.protocol_version = 3
86
+ self.platform = 'ios'
87
+ end
88
+ end
89
+ end # BuildReport
90
+ end # GCPT
@@ -0,0 +1,35 @@
1
+ require 'net/http'
2
+ require 'json'
3
+
4
+ module GCPT
5
+ module BuildReport
6
+ FAAS_URL_PREFIX = 'https://gsdk-build.bytedance.com/api/build/log/invoke/'
7
+
8
+ class ReportApi
9
+ def self.faas_post(method, data)
10
+ uri = URI(FAAS_URL_PREFIX + method)
11
+ res = Net::HTTP.post(uri, data.to_json, {
12
+ 'Content-Type' => 'application/json',
13
+ 'x-gsdk-access' => ENV['X_GSDK_ACCESS']
14
+ })
15
+ raise "Http error, code: #{res.code}" unless res.code == '200'
16
+
17
+ content = JSON.parse(res.body)
18
+ if content['code'] != 0
19
+ raise "faas request error: #{content['message']}"
20
+ end
21
+ return content['data']
22
+ end
23
+
24
+ def self.report(data)
25
+ begin
26
+ faas_post('v3_collect_build', data)
27
+ rescue => e
28
+ puts "gsdkcp-tool report failed: #{e}"
29
+ else
30
+ puts 'gsdkcp-tool report success'
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,231 @@
1
+ require_relative 'models'
2
+ require 'json'
3
+ require 'Xcodeproj'
4
+ require 'pathname'
5
+ require 'gcpt/utils/executable'
6
+ require 'gcpt/utils/helper'
7
+ require_relative 'report_api'
8
+
9
+ module GCPT
10
+ module BuildReport
11
+ class Reporter
12
+ def initialize()
13
+ super
14
+ # @options = options
15
+ end
16
+
17
+ def prepare()
18
+ @is_app = ENV['MACH_O_TYPE'] == 'mh_execute'
19
+ @product_path = ENV['CODESIGNING_FOLDER_PATH']
20
+ @gsdk_build_info = {}
21
+
22
+ gsdk_framework_path = @is_app && find_gsdk_in_app || find_gsdk_in_search_paths
23
+ if gsdk_framework_path
24
+ plist_path = gsdk_framework_path.join('Info.plist')
25
+ plist = Helper::read_plist_from_path(plist_path)
26
+ for key in %w[build_id dsl version resion source]
27
+ value = plist["gsdk_#{key}"]
28
+ if value
29
+ @gsdk_build_info[key] = value
30
+ end
31
+ end
32
+ end
33
+
34
+ @project = Xcodeproj::Project.open(ENV['PROJECT_FILE_PATH'])
35
+ @host_target = @project.targets.find { |target| target.name == ENV['TARGET_NAME'] }
36
+ end
37
+
38
+ def find_gsdk_in_app()
39
+ framework__path = Pathname.new(@product_path).join('Frameworks/BD_GameSDK_iOS.framework')
40
+ framework__path.exist? && framework__path || nil
41
+ end
42
+
43
+ def find_gsdk_in_search_paths()
44
+ paths = Helper::split_build_setting_array_to_string(ENV['FRAMEWORK_SEARCH_PATHS']) || []
45
+ paths.find { |pa|
46
+ if pa[0] == '"' && pa[-1] == '"'
47
+ pa = pa[1...-1]
48
+ end
49
+ Pathname.new(pa).join('BD_GameSDK_iOS.framework').exist?
50
+ }
51
+ end
52
+
53
+ def run()
54
+ prepare()
55
+ report_info = self._collect_report_info()
56
+ ReportApi::report(report_info)
57
+ end
58
+
59
+ def plist_content()
60
+ plist_path = ENV['PRODUCT_SETTINGS_PATH']
61
+ begin
62
+ File.read(plist_path)
63
+ rescue
64
+ end
65
+ end
66
+
67
+ def product_plist
68
+ @product_plist ||= begin
69
+ plist_path = ENV['PRODUCT_SETTINGS_PATH']
70
+ begin
71
+ Xcodeproj::Plist::read_from_path(plist_path)
72
+ rescue
73
+ return {}
74
+ end
75
+ end
76
+ end
77
+
78
+ def get_product_plist_value(key)
79
+ value = product_plist[key]
80
+ if value && value.include?('$')
81
+ value = `echo #{value}`.strip
82
+ end
83
+ value
84
+ end
85
+
86
+ def game_config()
87
+ product_plist && product_plist['GameConfig'] || {}
88
+ end
89
+
90
+ def app_path()
91
+ ENV['CODESIGNING_FOLDER_PATH']
92
+ end
93
+
94
+ def _collect_base_info()
95
+ base_info = BaseInfo.new
96
+ base_info.app_version = ENV['MARKETING_VERSION'] || get_product_plist_value('CFBundleShortVersionString')
97
+ base_info.build_version = ENV['CURRENT_PROJECT_VERSION'] || get_product_plist_value('CFBundleVersion')
98
+ base_info.project_type = @is_app ? 'application' : 'library'
99
+ base_info.gsdk_version = @gsdk_build_info['version']
100
+
101
+ # parse region
102
+ begin
103
+ base_info.region = 'known'
104
+ if !game_config.empty?
105
+ case game_config['serverRegion']
106
+ when 10, 20
107
+ base_info.region = 'i18n'
108
+ when 0, nil
109
+ base_info.region = 'cn'
110
+ end
111
+ end
112
+ end
113
+
114
+ # parse languages
115
+ Dir.chdir(app_path) do
116
+ base_info.languages = Dir.glob('*.lproj').map { |name|
117
+ File.basename(name, '.lproj')
118
+ }.join(',')
119
+ end
120
+
121
+ _parse_engine(base_info)
122
+
123
+ base_info
124
+ end
125
+
126
+ def _parse_engine(base_info)
127
+ build_settings = @host_target.build_settings(ENV['CONFIGURATION'])
128
+ base_info.engine_type = 'unknown'
129
+ if build_settings['UNITY_RUNTIME_VERSION']
130
+ base_info.engine_type = 'unity'
131
+ base_info.engine_version = build_settings['UNITY_RUNTIME_VERSION']
132
+ end
133
+ end
134
+
135
+ def _collect_gsdk_info()
136
+ sdk_info = GsdkInfo.new
137
+ sdk_info.build_info = @gsdk_build_info
138
+ sdk_info
139
+ end
140
+
141
+ def _parse_regex(regex, text, group_index)
142
+ if text
143
+ result = regex.match(text)[group_index]
144
+ if result
145
+ return result.strip
146
+ end
147
+ end
148
+ nil
149
+ end
150
+
151
+ def _parse_cmd(cmd, args)
152
+ result = Executable.execute_command(cmd, args, false)
153
+ if result && block_given?
154
+ yield result
155
+ end
156
+ end
157
+
158
+ def _collect_env_info()
159
+ env_info = ENVInfo.new
160
+
161
+ env_info.env = ENV.keys.sort().map do |name|
162
+ "#{name}=#{ENV[name]}"
163
+ end.join("\n")
164
+
165
+ _parse_cmd('sw_vers', []) do |result|
166
+ env_info.os = _parse_regex(/ProductName:(.*)/, result, 1)
167
+ env_info.os_version = _parse_regex(/ProductVersion:(.*)/, result, 1)
168
+ end
169
+
170
+ _parse_cmd('system_profiler', ['SPHardwareDataType']) do |result|
171
+ env_info.machine = _parse_regex(/Model Identifier:(.*)/, result, 1)
172
+ env_info.device_id = _parse_regex(/Hardware UUID:(.*)/, result, 1)
173
+ end
174
+
175
+ _parse_deps_tool(env_info)
176
+
177
+ env_info
178
+ end
179
+
180
+ def _parse_deps_tool(env_info)
181
+ env_info.deps_tool = 'unknown'
182
+ if ENV['PODS_ROOT'] && File.exist?(ENV['PODS_ROOT'])
183
+ env_info.deps_tool = 'cocoapods'
184
+ end
185
+ end
186
+
187
+ def _collect_project_info()
188
+ project_info = ProjectInfo.new
189
+ project_info.info_plist = plist_content
190
+ project_info.game_config = game_config
191
+ project_info.build_config = ENV['CONFIGURATION']
192
+ project_info.build_settings = @host_target.build_settings(project_info.build_config)
193
+
194
+ # parse entitlement
195
+ if ENV['CODE_SIGN_ENTITLEMENTS']
196
+ entitlement_path = Pathname.new(ENV['PROJECT_DIR']).join(ENV['CODE_SIGN_ENTITLEMENTS'])
197
+ if entitlement_path.exist?
198
+ project_info.entitlement = File.read(entitlement_path)
199
+ end
200
+ end
201
+
202
+ project_info
203
+ end
204
+
205
+ def _collect_build_log()
206
+ build_log = []
207
+ build_log
208
+ end
209
+
210
+ def _collect_build_spends()
211
+ build_spends = []
212
+ build_spends
213
+ end
214
+
215
+ def _collect_report_info()
216
+ report_info = ReportInfo.new
217
+ report_info.application_id = ENV['PRODUCT_BUNDLE_IDENTIFIER'] || get_product_plist_value('CFBundleIdentifier')
218
+ report_info.app_id = game_config['appId']
219
+
220
+ report_info.base_info = self._collect_base_info()
221
+ report_info.gsdk_info = self._collect_gsdk_info()
222
+ report_info.env_info = self._collect_env_info()
223
+ report_info.project_info = self._collect_project_info()
224
+ report_info.build_log = self._collect_build_log()
225
+ report_info.build_spends = self._collect_build_spends()
226
+ report_info.build_result = 'success'
227
+ report_info
228
+ end
229
+ end
230
+ end
231
+ end
@@ -0,0 +1,53 @@
1
+ require 'claide'
2
+ require 'gcpt/version'
3
+ require 'gcpt/build_report/reporter'
4
+
5
+ module GCPT
6
+ class GCPTCommand < CLAide::Command
7
+ self.abstract_command = true
8
+ self.description = 'GSDK utility tool for game CP.'
9
+ self.command = 'gsdkcp-tool'
10
+ self.version = GCPT::VERSION
11
+
12
+ def self.options
13
+ [
14
+ ].concat(super)
15
+ end
16
+
17
+ def initialize(argv)
18
+ super
19
+ end
20
+
21
+ def validate!
22
+ super
23
+ end
24
+
25
+ def run
26
+ end
27
+
28
+ class BuildReport < self
29
+ self.summary = 'Report build results to G'
30
+ self.description = <<-DESC
31
+ Report build results to G
32
+ DESC
33
+
34
+ def self.options
35
+ [
36
+ ].concat(super)
37
+ end
38
+
39
+ def initialize(argv)
40
+ super
41
+ end
42
+
43
+ def validate!
44
+ super
45
+ end
46
+
47
+ def run
48
+ super
49
+ GCPT::BuildReport::Reporter.new().run()
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,230 @@
1
+ module GCPT
2
+ module Executable
3
+ # Creates the methods for the executable with the given name.
4
+ #
5
+ # @param [Symbol] name
6
+ # the name of the executable.
7
+ #
8
+ # @return [void]
9
+ #
10
+ def executable(name)
11
+ define_method(name) do |*command|
12
+ Executable.execute_command(name, Array(command).flatten, false)
13
+ end
14
+
15
+ define_method(name.to_s + '!') do |*command|
16
+ Executable.execute_command(name, Array(command).flatten, true)
17
+ end
18
+ end
19
+
20
+ # Executes the given command displaying it if in verbose mode.
21
+ #
22
+ # @param [String] executable
23
+ # The binary to use.
24
+ #
25
+ # @param [Array<#to_s>] command
26
+ # The command to send to the binary.
27
+ #
28
+ # @param [Bool] raise_on_failure
29
+ # Whether it should raise if the command fails.
30
+ #
31
+ # @raise If the executable could not be located.
32
+ #
33
+ # @raise If the command fails and the `raise_on_failure` is set to true.
34
+ #
35
+ # @return [String] the output of the command (STDOUT and STDERR).
36
+ #
37
+ def self.execute_command(executable, command, raise_on_failure = true)
38
+ bin = which!(executable)
39
+
40
+ command = command.map(&:to_s)
41
+ if File.basename(bin) == 'tar.exe'
42
+ # Tar on Windows needs --force-local
43
+ command.push('--force-local')
44
+ end
45
+ full_command = "#{bin} #{command.join(' ')}"
46
+
47
+ stdout = Indenter.new([])
48
+ stderr = Indenter.new([])
49
+
50
+ status = popen3(bin, command, stdout, stderr)
51
+ stdout = stdout.join
52
+ stderr = stderr.join
53
+ output = stdout + stderr
54
+ unless status.success?
55
+ if raise_on_failure
56
+ raise Informative, "#{full_command}\n\n#{output}"
57
+ else
58
+ puts("[!] Failed: #{full_command}".red)
59
+ end
60
+ end
61
+
62
+ output
63
+ end
64
+
65
+ # Returns the absolute path to the binary with the given name on the current
66
+ # `PATH`, or `nil` if none is found.
67
+ #
68
+ # @param [String] program
69
+ # The name of the program being searched for.
70
+ #
71
+ # @return [String,Nil] The absolute path to the given program, or `nil` if
72
+ # it wasn't found in the current `PATH`.
73
+ #
74
+ def self.which(program)
75
+ program = program.to_s
76
+ paths = ENV.fetch('PATH') { '' }.split(File::PATH_SEPARATOR)
77
+ paths.unshift('./')
78
+ paths.uniq!
79
+ paths.each do |path|
80
+ bin = File.expand_path(program, path)
81
+ if Gem.win_platform?
82
+ bin += '.exe'
83
+ end
84
+ if File.file?(bin) && File.executable?(bin)
85
+ return bin
86
+ end
87
+ end
88
+ nil
89
+ end
90
+
91
+ # Returns the absolute path to the binary with the given name on the current
92
+ # `PATH`, or raises if none is found.
93
+ #
94
+ # @param [String] program
95
+ # The name of the program being searched for.
96
+ #
97
+ # @return [String] The absolute path to the given program.
98
+ #
99
+ def self.which!(program)
100
+ which(program).tap do |bin|
101
+ raise Informative, "Unable to locate the executable `#{program}`" unless bin
102
+ end
103
+ end
104
+
105
+ # Runs the given command, capturing the desired output.
106
+ #
107
+ # @param [String] executable
108
+ # The binary to use.
109
+ #
110
+ # @param [Array<#to_s>] command
111
+ # The command to send to the binary.
112
+ #
113
+ # @param [Symbol] capture
114
+ # Whether it should raise if the command fails.
115
+ #
116
+ # @param [Hash] env
117
+ # Environment variables to be set for the command.
118
+ #
119
+ # @raise If the executable could not be located.
120
+ #
121
+ # @return [(String, Process::Status)]
122
+ # The desired captured output from the command, and the status from
123
+ # running the command.
124
+ #
125
+ def self.capture_command(executable, command, capture: :merge, env: {}, **kwargs)
126
+ bin = which!(executable)
127
+
128
+ require 'open3'
129
+ command = command.map(&:to_s)
130
+ case capture
131
+ when :merge then Open3.capture2e(env, [bin, bin], *command, **kwargs)
132
+ when :both then Open3.capture3(env, [bin, bin], *command, **kwargs)
133
+ when :out then Open3.capture3(env, [bin, bin], *command, **kwargs).values_at(0, -1)
134
+ when :err then Open3.capture3(env, [bin, bin], *command, **kwargs).drop(1)
135
+ when :none then Open3.capture3(env, [bin, bin], *command, **kwargs).last
136
+ end
137
+ end
138
+
139
+ # (see Executable.capture_command)
140
+ #
141
+ # @raise If running the command fails
142
+ #
143
+ def self.capture_command!(executable, command, **kwargs)
144
+ capture_command(executable, command, **kwargs).tap do |result|
145
+ result = Array(result)
146
+ status = result.last
147
+ unless status.success?
148
+ output = result[0..-2].join
149
+ raise Informative, "#{executable} #{command.join(' ')}\n\n#{output}".strip
150
+ end
151
+ end
152
+ end
153
+
154
+ private
155
+
156
+ def self.popen3(bin, command, stdout, stderr)
157
+ require 'open3'
158
+ Open3.popen3(bin, *command) do |i, o, e, t|
159
+ reader(o, stdout)
160
+ reader(e, stderr)
161
+ i.close
162
+
163
+ status = t.value
164
+
165
+ o.flush
166
+ e.flush
167
+ sleep(0.01)
168
+
169
+ status
170
+ end
171
+ end
172
+
173
+ def self.reader(input, output)
174
+ Thread.new do
175
+ buf = ''
176
+ begin
177
+ loop do
178
+ buf << input.readpartial(4096)
179
+ loop do
180
+ string, separator, buf = buf.partition(/[\r\n]/)
181
+ if separator.empty?
182
+ buf = string
183
+ break
184
+ end
185
+ output << (string << separator)
186
+ end
187
+ end
188
+ rescue EOFError, IOError
189
+ output << (buf << $/) unless buf.empty?
190
+ end
191
+ end
192
+ end
193
+
194
+ #-------------------------------------------------------------------------#
195
+
196
+ # Helper class that allows to write to an {IO} instance taking into account
197
+ # the UI indentation level.
198
+ #
199
+ class Indenter < ::Array
200
+ # @return [Fixnum] The indentation level of the UI.
201
+ #
202
+ attr_reader :indent
203
+
204
+ # @return [IO] the {IO} to which the output should be printed.
205
+ #
206
+ attr_reader :io
207
+
208
+ # Init a new Indenter
209
+ #
210
+ # @param [IO] io @see io
211
+ #
212
+ def initialize(io = nil)
213
+ @io = io
214
+ @indent = ''
215
+ end
216
+
217
+ # Stores a portion of the output and prints it to the {IO} instance.
218
+ #
219
+ # @param [String] value
220
+ # the output to print.
221
+ #
222
+ # @return [void]
223
+ #
224
+ def <<(value)
225
+ super
226
+ io << "#{indent}#{value}" if io
227
+ end
228
+ end
229
+ end
230
+ end
@@ -0,0 +1,16 @@
1
+ autoload :CFPropertyList, 'cfpropertylist'
2
+
3
+ module GCPT
4
+ class Helper
5
+ # from xcodeproj-1.21.0/lib/xcodeproj/project/object/build_configuration.rb
6
+ def self.split_build_setting_array_to_string(string)
7
+ regexp = / *((['"]?).*?[^\\]\2)(?=( |\z))/
8
+ string.scan(regexp).map(&:first)
9
+ end
10
+
11
+ def self.read_plist_from_path(path)
12
+ contents = File.read(path)
13
+ CFPropertyList.native_types(CFPropertyList::List.new(:data => contents).value)
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,29 @@
1
+ module GCPT
2
+ module JSONable
3
+ module ClassMethods
4
+ attr_accessor :attributes
5
+
6
+ def attr_accessor *attrs
7
+ (self.attributes ||= []).concat(attrs)
8
+ super
9
+ end
10
+ end
11
+
12
+ def self.included(base)
13
+ base.extend(ClassMethods)
14
+ end
15
+
16
+ def as_json options = {}
17
+ serialized = Hash.new
18
+ self.class.attributes.each do |attribute|
19
+ value = self.public_send(attribute)
20
+ serialized[attribute] = value if !value.nil?
21
+ end
22
+ serialized
23
+ end
24
+
25
+ def to_json *a
26
+ as_json.to_json *a
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,3 @@
1
+ module GCPT
2
+ VERSION = "0.1.0"
3
+ end
data/lib/gcpt.rb ADDED
@@ -0,0 +1,8 @@
1
+ require "gcpt/version"
2
+ require "gcpt/command"
3
+
4
+ Encoding.default_external = Encoding::UTF_8
5
+
6
+ module GCPT
7
+ class Error < StandardError; end
8
+ end
metadata ADDED
@@ -0,0 +1,96 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: gsdkcp-tool
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - zhangjinquan
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2022-03-01 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: claide
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 1.0.3
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 1.0.3
27
+ - !ruby/object:Gem::Dependency
28
+ name: xcodeproj
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 1.21.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 1.21.0
41
+ description: CLI tool for GSDK integration.
42
+ email:
43
+ - zhangjinquan@bytedance.com
44
+ executables:
45
+ - gsdkcp-tool
46
+ extensions: []
47
+ extra_rdoc_files: []
48
+ files:
49
+ - ".gitignore"
50
+ - ".travis.yml"
51
+ - CODE_OF_CONDUCT.md
52
+ - Gemfile
53
+ - LICENSE.txt
54
+ - README.md
55
+ - Rakefile
56
+ - bin/console
57
+ - bin/setup
58
+ - exe/gsdkcp-tool
59
+ - gsdkcp-tool.gemspec
60
+ - lib/gcpt.rb
61
+ - lib/gcpt/build_report/models.rb
62
+ - lib/gcpt/build_report/report_api.rb
63
+ - lib/gcpt/build_report/reporter.rb
64
+ - lib/gcpt/command.rb
65
+ - lib/gcpt/utils/executable.rb
66
+ - lib/gcpt/utils/helper.rb
67
+ - lib/gcpt/utils/json_model.rb
68
+ - lib/gcpt/version.rb
69
+ homepage: https://gdev.nvsgames.cn/home
70
+ licenses:
71
+ - MIT
72
+ metadata:
73
+ allowed_push_host: https://rubygems.org
74
+ homepage_uri: https://gdev.nvsgames.cn/home
75
+ source_code_uri: https://gdev.nvsgames.cn/home
76
+ changelog_uri: https://gdev.nvsgames.cn/home
77
+ post_install_message:
78
+ rdoc_options: []
79
+ require_paths:
80
+ - lib
81
+ required_ruby_version: !ruby/object:Gem::Requirement
82
+ requirements:
83
+ - - ">="
84
+ - !ruby/object:Gem::Version
85
+ version: 2.3.0
86
+ required_rubygems_version: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ requirements: []
92
+ rubygems_version: 3.0.9
93
+ signing_key:
94
+ specification_version: 4
95
+ summary: CLI tool for GSDK integration.
96
+ test_files: []