cocoapods-embed-flutter 0.5.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 (51) hide show
  1. checksums.yaml +7 -0
  2. data/.github/config/config.js +21 -0
  3. data/.github/config/package-lock.json +223 -0
  4. data/.github/config/package.json +16 -0
  5. data/.github/config/pre_changelog_hook.js +27 -0
  6. data/.github/dependabot.yml +23 -0
  7. data/.github/workflows/main.yml +145 -0
  8. data/.gitignore +178 -0
  9. data/CHANGELOG.md +32 -0
  10. data/CODE_OF_CONDUCT.md +76 -0
  11. data/Gemfile +15 -0
  12. data/Gemfile.lock +170 -0
  13. data/LICENSE +21 -0
  14. data/README.md +35 -0
  15. data/Rakefile +39 -0
  16. data/cocoapods-embed-flutter.gemspec +30 -0
  17. data/example/flutter_module/.gitignore +48 -0
  18. data/example/flutter_module/.metadata +10 -0
  19. data/example/flutter_module/README.md +11 -0
  20. data/example/flutter_module/analysis_options.yaml +4 -0
  21. data/example/flutter_module/flutter_module.iml +18 -0
  22. data/example/flutter_module/flutter_module_android.iml +27 -0
  23. data/example/flutter_module/lib/main.dart +112 -0
  24. data/example/flutter_module/pubspec.lock +174 -0
  25. data/example/flutter_module/pubspec.yaml +87 -0
  26. data/example/flutter_module/test/widget_test.dart +30 -0
  27. data/example/ios_app/Gemfile +4 -0
  28. data/example/ios_app/Gemfile.lock +110 -0
  29. data/example/ios_app/Podfile +11 -0
  30. data/example/ios_app/Podfile.lock +28 -0
  31. data/example/ios_app/ios_app/Assets.xcassets/AccentColor.colorset/Contents.json +11 -0
  32. data/example/ios_app/ios_app/Assets.xcassets/AppIcon.appiconset/Contents.json +98 -0
  33. data/example/ios_app/ios_app/Assets.xcassets/Contents.json +6 -0
  34. data/example/ios_app/ios_app/ContentView.swift +40 -0
  35. data/example/ios_app/ios_app/Preview Content/Preview Assets.xcassets/Contents.json +6 -0
  36. data/example/ios_app/ios_app/ios_appApp.swift +18 -0
  37. data/example/ios_app/ios_app.xcodeproj/project.pbxproj +426 -0
  38. data/lib/cocoapods-embed-flutter/flutter/dependency.rb +93 -0
  39. data/lib/cocoapods-embed-flutter/flutter/downloader.rb +61 -0
  40. data/lib/cocoapods-embed-flutter/flutter/external_sources.rb +201 -0
  41. data/lib/cocoapods-embed-flutter/flutter/pubspec.rb +166 -0
  42. data/lib/cocoapods-embed-flutter/gem_version.rb +3 -0
  43. data/lib/cocoapods-embed-flutter/hooks/post_install.rb +8 -0
  44. data/lib/cocoapods-embed-flutter/hooks.rb +1 -0
  45. data/lib/cocoapods-embed-flutter/source.rb +1 -0
  46. data/lib/cocoapods-embed-flutter/src/pub.rb +114 -0
  47. data/lib/cocoapods-embed-flutter.rb +3 -0
  48. data/lib/cocoapods_plugin.rb +1 -0
  49. data/spec/info_spec.rb +7 -0
  50. data/spec/spec_helper.rb +50 -0
  51. metadata +165 -0
@@ -0,0 +1,201 @@
1
+ # Similar to:
2
+ # https://github.com/CocoaPods/CocoaPods/blob/master/lib/cocoapods/external_sources/abstract_external_source.rb
3
+ require 'cocoapods-embed-flutter/flutter/downloader'
4
+ require 'cocoapods'
5
+
6
+ module Flutter
7
+ module Pub
8
+ module ExternalSources
9
+ SOURCE_KEYS = {
10
+ :git => [:tag, :branch, :commit, :submodules].freeze,
11
+ :svn => [:folder, :tag, :revision].freeze,
12
+ :hg => [:revision].freeze,
13
+ :http => [:flatten, :type, :sha256, :sha1, :headers].freeze,
14
+ }.freeze
15
+
16
+ # Returns the path to `pubspec` with the given name and location to search.
17
+ #
18
+ # @param [String] name
19
+ # the name of the project declared in `pubspec`.
20
+ #
21
+ # @param [Hash] options
22
+ # requirement opttions for the source of project.
23
+ #
24
+ # @note the source of project can either be local or all the remotes
25
+ # supported by `cocoapods-downloader`.
26
+ #
27
+ # @return [Spec] the `pubspec` with the given name satisfying
28
+ # requirement options.
29
+ #
30
+ def self.fetchWithNameAndOptions(name, options)
31
+ raise StandardError, 'A flutter module requires a name.' unless name
32
+
33
+ options = options.last if options.is_a?(Array)
34
+ raise StandardError, "No options specified for flutter module: '#{name}'." unless options.is_a?(Hash)
35
+
36
+ if options.key?(:path)
37
+ path = options[:path]
38
+ elsif SOURCE_KEYS.keys.any? { |key| options.key?(key) }
39
+ source = DownloaderSource.new(name, options, Pod::Config.instance.podfile_path)
40
+ source.fetch(Pod::Config.instance.sandbox)
41
+ path = source.normalized_pupspec_path
42
+ else
43
+ raise StandardError, "Invalid flutter module: '#{name}'."
44
+ end
45
+
46
+ return Spec.find(name, path)
47
+ end
48
+
49
+ # Provides support for fetching a specification file from a source handled
50
+ # by the downloader. Supports all the options of the downloader
51
+ #
52
+ # @note The pubspec must be in the root of the repository
53
+ # or in directory with the name provided
54
+ #
55
+ class DownloaderSource
56
+ # @return [String] the name of the Package described by this external source.
57
+ #
58
+ attr_reader :name
59
+
60
+ # @return [Hash{Symbol => String}] the hash representation of the
61
+ # external source.
62
+ #
63
+ attr_reader :params
64
+
65
+ # @return [String] the path where the podfile is defined to resolve
66
+ # relative paths.
67
+ #
68
+ attr_reader :podfile_path
69
+
70
+ # @return [Boolean] Whether the source is allowed to touch the cache.
71
+ #
72
+ attr_reader :can_cache
73
+ alias_method :can_cache?, :can_cache
74
+
75
+ # Initialize a new instance
76
+ #
77
+ # @param [String] name @see #name
78
+ # @param [Hash] params @see #params
79
+ # @param [String] podfile_path @see #podfile_path
80
+ # @param [Boolean] can_cache @see #can_cache
81
+ #
82
+ def initialize(name, params, podfile_path, can_cache = true)
83
+ @name = name
84
+ @params = params
85
+ @podfile_path = podfile_path
86
+ @can_cache = can_cache
87
+ end
88
+
89
+ # @return [Boolean] whether an external source source is equal to another
90
+ # according to the {#name} and to the {#params}.
91
+ #
92
+ def ==(other)
93
+ return false if other.nil?
94
+ name == other.name && params == other.params
95
+ end
96
+
97
+
98
+ public
99
+
100
+ # @!group Subclasses hooks
101
+
102
+ # Fetches the external source from the remote according to the params.
103
+ #
104
+ # @param [Sandbox] sandbox
105
+ # the sandbox where the specification should be stored.
106
+ #
107
+ # @return [void]
108
+ #
109
+ def fetch(sandbox)
110
+ pre_download(sandbox)
111
+ end
112
+
113
+ # @return [String] a string representation of the source suitable for UI.
114
+ #
115
+ def description
116
+ strategy = Pod::Downloader.strategy_from_options(params)
117
+ options = params.dup
118
+ url = options.delete(strategy)
119
+ result = "from `#{url}`"
120
+ options.each do |key, value|
121
+ result << ", #{key} `#{value}`"
122
+ end
123
+ result
124
+ end
125
+
126
+ # Return the normalized path for a pubspec for a relative declared path.
127
+ #
128
+ # @param [String] declared_path
129
+ # The path declared in the podfile.
130
+ #
131
+ # @return [String] The uri of the pubspec appending the name of the file
132
+ # and expanding it if necessary.
133
+ #
134
+ # @note If the declared path is expanded only if the represents a path
135
+ # relative to the file system.
136
+ #
137
+ def normalized_pupspec_path(declared_path)
138
+ Spec.find_file(name, declared_path)
139
+ end
140
+
141
+ def normalized_pupspec_path
142
+ Spec.find_file(name, target)
143
+ end
144
+
145
+ private
146
+
147
+ # @! Subclasses helpers
148
+
149
+ # Pre-downloads a Pod passing the options to the downloader and informing
150
+ # the sandbox.
151
+ #
152
+ # @param [Sandbox] sandbox
153
+ # The sandbox where the Pod should be downloaded.
154
+ #
155
+ # @note To prevent a double download of the repository the pod is
156
+ # marked as pre-downloaded indicating to the installer that only
157
+ # clean operations are needed.
158
+ #
159
+ # @todo The downloader configuration is the same of the
160
+ # #{PodSourceInstaller} and it needs to be kept in sync.
161
+ #
162
+ # @return [void]
163
+ #
164
+ def pre_download(sandbox)
165
+ title = "Pre-downloading: `#{name}` #{description}"
166
+ Pod::UI.titled_section(title, :verbose_prefix => '-> ') do
167
+ begin
168
+ download_result = Downloader.download(download_request, target, :can_cache => can_cache)
169
+ rescue Pod::DSLError => e
170
+ raise Pod::Informative, "Failed to load '#{name}' pubspec: #{e.message}"
171
+ rescue => e
172
+ raise Pod::Informative, "Failed to download '#{name}': #{e.message}"
173
+ end
174
+
175
+ # spec = download_result.spec
176
+ # raise Pod::Informative, "Unable to find a specification for '#{name}'." unless spec
177
+
178
+ # since the podspec might be cleaned, we want the checksum to refer
179
+ # to the json in the sandbox
180
+ # spec.defined_in_file = nil
181
+
182
+ # store_podspec(sandbox, spec)
183
+ # sandbox.store_pre_downloaded_pod(name)
184
+ # sandbox.store_checkout_source(name, download_result.checkout_options)
185
+ end
186
+ end
187
+
188
+ def download_request
189
+ Pod::Downloader::Request.new(
190
+ :name => name,
191
+ :params => params,
192
+ )
193
+ end
194
+
195
+ def target
196
+ return Pod::Config.instance.sandbox.pod_dir(name)
197
+ end
198
+ end
199
+ end
200
+ end
201
+ end
@@ -0,0 +1,166 @@
1
+ require 'cocoapods-embed-flutter/flutter/dependency'
2
+ require 'yaml'
3
+
4
+ module Flutter
5
+ NAME = 'flutter'.freeze
6
+ DIR_NAME = 'Flutter'.freeze
7
+
8
+ module Pub
9
+ SPEC_FILE = 'pubspec.yaml'.freeze
10
+ TOOL_DIR = '.dart_tool'.freeze
11
+ CACHE_FILE = 'package_config.json'.freeze
12
+
13
+ # The Specification provides a DSL to describe a flutter project.
14
+ # A project is defined as a library originating from a source.
15
+ # A specification can support detailed attributes for modules of code
16
+ # through dependencies.
17
+ #
18
+ # Usually it is stored in `pubspec.yaml` file.
19
+ #
20
+ class Spec
21
+ # @return [String] the path where the specification is defined, if loaded
22
+ # from a file.
23
+ #
24
+ attr_reader :defined_in_file
25
+
26
+ # @param [String] path
27
+ # the path to the specification.
28
+ #
29
+ def initialize(path)
30
+ @data = YAML.load_file path
31
+ @defined_in_file = path
32
+ end
33
+
34
+ # Returns the path to `pubspec` with the given name and location to search.
35
+ #
36
+ # @param [String] name
37
+ # the name of the project declared in `pubspec`.
38
+ #
39
+ # @param [String] path
40
+ # where project or pubspec is located.
41
+ #
42
+ # @note either the flutter module or the `pubspec` of the flutter module
43
+ # can be in the path. Optionally you can provide the `pubspec`
44
+ # file directly.
45
+ #
46
+ # @return [String] path to the `pubspec` with the given name if present.
47
+ #
48
+ def self.find_file(name, path)
49
+ path = File.expand_path(path, Dir.pwd)
50
+
51
+ if File.basename(path) == Pub::SPEC_FILE
52
+ return path
53
+ elsif Dir.exists?(File.expand_path(name, path)) && File.exists?(File.expand_path(Pub::SPEC_FILE, File.expand_path(name, path)))
54
+ return File.expand_path(Pub::SPEC_FILE, File.expand_path(name, path))
55
+ elsif File.exists?(File.expand_path(Pub::SPEC_FILE, path))
56
+ return File.expand_path(Pub::SPEC_FILE, path)
57
+ else
58
+ return nil
59
+ end
60
+ end
61
+
62
+ # Returns the path to `pubspec` with the given name and location to search.
63
+ #
64
+ # @param [String] name
65
+ # the name of the project declared in `pubspec`.
66
+ #
67
+ # @param [String] path
68
+ # where project or pubspec is located.
69
+ #
70
+ # @note either the flutter module or the `pubspec` of the flutter module
71
+ # can be in the path. Optionally you can provide the `pubspec`
72
+ # file directly.
73
+ #
74
+ # @return [Spec] the `pubspec` with the given name if present.
75
+ #
76
+ def self.find(name, path)
77
+ pubspec_path = find_file(name, path)
78
+ raise StandardError, "Invalid path: '#{path}' for flutter module: '#{name}'." unless pubspec_path
79
+ pubspec = Spec.new(pubspec_path)
80
+ raise StandardError, "Invalid path: '#{path}' for flutter module: '#{name}'." unless pubspec.name == name
81
+ return pubspec
82
+ end
83
+
84
+ # @return [Boolean] If this specification is a module specification.
85
+ #
86
+ def module?
87
+ return false unless @data.include?(Flutter::NAME)
88
+ return @data[Flutter::NAME].is_a?(Hash) && @data[Flutter::NAME].include?('module')
89
+ end
90
+
91
+ # @return [String] the path to the flutter project.
92
+ #
93
+ def project_path
94
+ File.dirname(defined_in_file)
95
+ end
96
+
97
+ # @return [String] the path to the flutter project
98
+ # dependencies cache file.
99
+ #
100
+ def package_cache_path
101
+ File.join(project_path, Pub::TOOL_DIR, Pub::CACHE_FILE)
102
+ end
103
+
104
+ # @return [String] the path to the flutter project.
105
+ #
106
+ def pod_helper_path
107
+ File.join(project_path, '.ios', Flutter::DIR_NAME, 'podhelper.rb') if module?
108
+ end
109
+
110
+ # @return [Array<Dependency>] the list of all the projects this
111
+ # specification depends upon and are included in app release.
112
+ #
113
+ def dependencies
114
+ return [] unless @data.include?('dependencies')
115
+ Dependency.create_from_hash(@data['dependencies'], self)
116
+ end
117
+
118
+ # @return [Array<Dependency>] the list of all the projects this
119
+ # specification depends upon only during development.
120
+ #
121
+ def dev_dependencies
122
+ return [] unless @data.include?('dev_dependencies')
123
+ Dependency.create_from_hash(@data['dev_dependencies'], self)
124
+ end
125
+
126
+ # @return [Array<Dependency>] the list of all the projects this
127
+ # specification depends upon.
128
+ #
129
+ def all_dependencies
130
+ dependencies + dev_dependencies
131
+ end
132
+
133
+ # @return [Boolean] If the flutter project for this specification
134
+ # has all its dependencies installed.
135
+ #
136
+ def setup?
137
+ File.exists?(package_cache_path) && (!module? || File.exists?(pod_helper_path))
138
+ end
139
+
140
+ # Sets up the project installing all specified dependencies.
141
+ #
142
+ # @return void
143
+ #
144
+ def setup
145
+ return if setup?
146
+ pup_get
147
+ all_dependencies.each(&:install)
148
+ end
149
+
150
+ # Runs `flutter pub get` on project directory.
151
+ #
152
+ # @return void
153
+ #
154
+ def pup_get
155
+ Dir.chdir(project_path) { |path| system('flutter pub get', exception: true) }
156
+ end
157
+
158
+ def method_missing(m, *args, &block)
159
+ if @data.include?(m.to_s)
160
+ return @data[m.to_s]
161
+ end
162
+ super.method_missing(m, *args, &block)
163
+ end
164
+ end
165
+ end
166
+ end
@@ -0,0 +1,3 @@
1
+ module CocoapodsEmbedFlutter
2
+ VERSION = '0.5.0'.freeze
3
+ end
@@ -0,0 +1,8 @@
1
+ module CocoapodsEmbedFlutter
2
+ # Registers for CocoaPods plugin hooks
3
+ module Hooks
4
+ Pod::HooksManager.register('cocoapods-embed-flutter', :post_install) do |installer, options|
5
+ # Do nothing
6
+ end
7
+ end
8
+ end
@@ -0,0 +1 @@
1
+ require 'cocoapods-embed-flutter/hooks/post_install'
@@ -0,0 +1 @@
1
+ require 'cocoapods-embed-flutter/src/pub'
@@ -0,0 +1,114 @@
1
+ require 'cocoapods-embed-flutter/gem_version'
2
+ require 'cocoapods-embed-flutter/flutter/pubspec'
3
+ require 'cocoapods-embed-flutter/flutter/external_sources'
4
+
5
+ module Pod
6
+ class Podfile
7
+ # The Podfile is a specification that describes the dependencies of the
8
+ # targets of one or more Xcode projects. With Embed Flutter
9
+ # it is possible to declare flutter module as dependency
10
+ #
11
+ # A Podfile can be very simple:
12
+ #
13
+ # target 'MyApp'
14
+ # pub 'flutter_module', :path => '../'
15
+ #
16
+ # An example of a more complex Podfile can be:
17
+ #
18
+ # platform :ios, '9.0'
19
+ # inhibit_all_warnings!
20
+ #
21
+ # target 'MyApp' do
22
+ # pub 'flutter_module', :path => '../'
23
+ # end
24
+ #
25
+ # target 'MyAppTests' do
26
+ # pub 'flutter_module_test', :path => '../'
27
+ # end
28
+ #
29
+ # post_install do |installer|
30
+ # installer.pods_project.targets.each do |target|
31
+ # puts "#{target.name}"
32
+ # end
33
+ # end
34
+ #
35
+ #
36
+ # @note Currently only one flutter module per target is
37
+ # supported.
38
+ #
39
+ module DSL
40
+ # Specifies a flutter module dependency of the project.
41
+ #
42
+ # A dependency requirement is defined by the name of the module and
43
+ # optionally a list of requirements.
44
+ #
45
+ #
46
+ # ### Using the files from a local path.
47
+ #
48
+ # If you would like to use develop a flutter module in tandem with
49
+ # its client project you can use the `path` option.
50
+ #
51
+ # pub 'flutter_module', :path => '../'
52
+ #
53
+ # Using this option Embed Flutter will assume the given folder
54
+ # to be the root of the flutter module or the root of flutter module `pubspec` file
55
+ # or points to the `pubspec` file itself and will link the files directly from there
56
+ # in the Pods project. This means that your edits will persist to
57
+ # CocoaPods installations.
58
+ #
59
+ # The referenced folder can be a checkout of your your favourite SCM or
60
+ # even a git submodule of the current repository.
61
+ #
62
+ # Note that either the flutter module or the `pubspec` of the flutter module
63
+ # can be in the folder. Optionally you can provide the `pubspec` file directly.
64
+ #
65
+ #
66
+ # ### From a flutter module in the root of a library repository.
67
+ #
68
+ # Sometimes you may want to use the bleeding edge version of a module. Or a
69
+ # specific revision. If this is the case, you can specify that with your
70
+ # pub declaration.
71
+ #
72
+ # To use the `master` or `main` branch of the repository:
73
+ #
74
+ # pub 'flutter_module', :git => 'https://github.com/octokit/flutter_module.git'
75
+ #
76
+ #
77
+ # To use a different branch of the repository:
78
+ #
79
+ # pub 'flutter_module', :git => 'https://github.com/octokit/flutter_module.git', :branch => 'dev'
80
+ #
81
+ #
82
+ # To use a tag of the repository:
83
+ #
84
+ # pub 'flutter_module', :git => 'https://github.com/octokit/flutter_module.git', :tag => '0.7.0'
85
+ #
86
+ #
87
+ # Or specify a commit:
88
+ #
89
+ # pub 'flutter_module', :git => 'https://github.com/octokit/flutter_module.git', :commit => '082f8319af'
90
+ #
91
+ # The flutter module or its `pubspec` file is expected to be in the
92
+ # root of the repository.
93
+ #
94
+ #
95
+ # @note This method allow a nil name and the raises to be more
96
+ # informative.
97
+ #
98
+ # @return [void]
99
+ #
100
+ def pub(name = nil, *requirements)
101
+ pubspec = Flutter::Pub::ExternalSources.fetchWithNameAndOptions(name, requirements)
102
+ pubspec.setup
103
+ raise StandardError, "Invalid flutter module: '#{name}'." unless File.exists?(pubspec.pod_helper_path)
104
+ install_flutter_pods_for_pubspec(pubspec)
105
+ end
106
+
107
+ def install_flutter_pods_for_pubspec(pubspec)
108
+ raise ArgumentError, "Invalid `pubspec` argument." unless pubspec.is_a?(Flutter::Pub::Spec)
109
+ load pubspec.pod_helper_path
110
+ install_all_flutter_pods(pubspec.project_path)
111
+ end
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,3 @@
1
+ require 'cocoapods-embed-flutter/gem_version'
2
+ require 'cocoapods-embed-flutter/source'
3
+ require 'cocoapods-embed-flutter/hooks'
@@ -0,0 +1 @@
1
+ require 'cocoapods-embed-flutter'
data/spec/info_spec.rb ADDED
@@ -0,0 +1,7 @@
1
+ require_relative 'spec_helper'
2
+
3
+ describe 'Plugin info test' do
4
+ it 'checks name' do
5
+ ''.should.equal ''
6
+ end
7
+ end
@@ -0,0 +1,50 @@
1
+ require 'pathname'
2
+ ROOT = Pathname.new(File.expand_path('../../', __FILE__))
3
+ $:.unshift((ROOT + 'lib').to_s)
4
+ $:.unshift((ROOT + 'spec').to_s)
5
+
6
+ require 'bundler/setup'
7
+ require 'bacon'
8
+ require 'mocha-on-bacon'
9
+ require 'pretty_bacon'
10
+ require 'pathname'
11
+ require 'cocoapods'
12
+
13
+ Mocha.configure { |c| c.stubbing_non_existent_method = :prevent }
14
+
15
+ require 'cocoapods_plugin'
16
+
17
+ #-----------------------------------------------------------------------------#
18
+
19
+ module Pod
20
+
21
+ # Disable the wrapping so the output is deterministic in the tests.
22
+ #
23
+ UI.disable_wrap = true
24
+
25
+ # Redirects the messages to an internal store.
26
+ #
27
+ module UI
28
+ @output = ''
29
+ @warnings = ''
30
+
31
+ class << self
32
+ attr_accessor :output
33
+ attr_accessor :warnings
34
+
35
+ def puts(message = '')
36
+ @output << "#{message}\n"
37
+ end
38
+
39
+ def warn(message = '', actions = [])
40
+ @warnings << "#{message}\n"
41
+ end
42
+
43
+ def print(message)
44
+ @output << message
45
+ end
46
+ end
47
+ end
48
+ end
49
+
50
+ #-----------------------------------------------------------------------------#