# frozen_string_literal: true # Copyright 2022 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. require 'cocoapods' require 'digest' require 'optparse' require 'plist' require 'tmpdir' require 'xcodeproj' DEFAULT_TESTAPP_TARGET = "testApp" # Default sources of min iOS version SOURCES=["https://cdn.cocoapods.org/"] MIN_IOS_VERSION="12.0" NOTICES_OUTPUT_PATH="./CoreOnly/NOTICES" SEARCH_LOCAL_POD_VERSION=false @options = { sources: SOURCES, min_ios_version: MIN_IOS_VERSION, output_path: NOTICES_OUTPUT_PATH, search_local_pod_version: false } begin OptionParser.new do |opts| opts.banner = "Usage: app.rb [options]" opts.on('-p', '--pods PODS', 'Pods seperated by space or comma.') { |v| @options[:pods] = v.split(/[ ,]/) } opts.on('-s', '--sources SOURCES', 'Sources of Pods') { |v| @options[:sources] = v.split(/[ ,]/) } opts.on('-m', '--min_ios_version MIN_IOS_VERSION', 'Minimum iOS version') { |v| @options[:min_ios_version] = v } opts.on('-n', '--notices_path OUTPUT_PATH', 'The output path of NOTICES') { |v| @options[:output_path] = v } opts.on('-v', '--search_local_pod_version', 'Attach the latest pod version to a pod in Podfile') { |v| @options[:search_local_pod_version] = true } end.parse! raise OptionParser::MissingArgument if @options[:pods].nil? rescue OptionParser::MissingArgument puts "Argument `--pods` should not be empty." raise end PODS = @options[:pods] SOURCES = @options[:sources] MIN_IOS_VERSION = @options[:min_ios_version] NOTICES_OUTPUT_PATH = @options[:output_path] SEARCH_LOCAL_POD_VERSION = @options[:search_local_pod_version] def create_podfile(path: , sources: , target: , pods: [], min_ios_version: , search_local_pod_version: ) output = "" for source in sources do output += "source \'#{source}\'\n" end if search_local_pod_version for source in sources do if source == "https://cdn.cocoapods.org/" next end `pod repo add #{Digest::MD5.hexdigest source} #{source}` end end output += "use_frameworks! :linkage => :static\n" output += "platform :ios, #{min_ios_version}\n" output += "target \'#{target}\' do\n" for pod in pods do if search_local_pod_version # `pod search` will search a pod locally and generate a corresonding pod # config in a Podfile with `grep`, e.g. # pod search Firebase | grep "pod.*" -m 1 # will generate # pod 'Firebase', '~> 9.0.0' output += `pod search "#{pod}" | grep "pod.*" -m 1` else output += "pod \'#{pod}\'\n" end end output += "end\n" # Remove default footers and headers generated by CocoaPods. output += " class ::Pod::Generator::Acknowledgements def header_text '' end def header_title '' end def footnote_text '' end end " puts "------Podfile------\n#{output}\n-------------------\n" podfile = File.new("#{path}/Podfile", "w") podfile.puts(output) podfile.close end def generate_notices_content(sources: SOURCES, pods: PODS, min_ios_version: MIN_IOS_VERSION) content = "" Dir.mktmpdir do |temp_dir| Dir.chdir(temp_dir) do project_path = "#{temp_dir}/barebone_app.xcodeproj" project_path = "barebone_app.xcodeproj" project = Xcodeproj::Project.new(project_path) project.new_target(:application, DEFAULT_TESTAPP_TARGET, :ios) project.save() create_podfile(path: temp_dir, sources: sources, target: DEFAULT_TESTAPP_TARGET,pods: pods, min_ios_version: min_ios_version, search_local_pod_version: SEARCH_LOCAL_POD_VERSION) pod_install_result = `pod install --allow-root` puts pod_install_result licenses = Plist.parse_xml("Pods/Target Support Files/Pods-testApp/Pods-testApp-acknowledgements.plist") existing_licenses={} for license in licenses["PreferenceSpecifiers"] do if existing_licenses.include?(license["FooterText"]) existing_licenses.store(license["FooterText"], existing_licenses.fetch(license["FooterText"])+"\n"+license["Title"]) next end existing_licenses.store(license["FooterText"], license["Title"]) end existing_licenses.each{ |license, title| # The NOTICES format is like: # ``` # ${title} # ${license} # # ${title} # ${license} # ... # ``` content += "#{title}\n#{license}\n\n" } end end return content.strip end def main() content = generate_notices_content(sources: SOURCES, pods: PODS, min_ios_version: MIN_IOS_VERSION) notices = File.new(NOTICES_OUTPUT_PATH, "w") notices.puts(content) notices.close end main()