enrich-pod-patcher 1.2.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: 310dd4c977748c88b926f757e3a345d7894359b7857021f20c0784496acc9dc5
4
+ data.tar.gz: 994ad2bdc661218e7bfe7ffc53a3d59a4c1878d61d1eb9ba0d0e71c7f98c7830
5
+ SHA512:
6
+ metadata.gz: 8c9842268a7af22c4e60f073efbf1bbfd4650f6d6633f560fef351b811b165207920915c4ac7341a59a726c8d0810b2ba91bef3dff43f70c785912a37ad6e7c4
7
+ data.tar.gz: 3477da36f4bf3a89a1ed48e48e6004b79c86817ed64d06ebd998a9a209d18b785ef6fbddf11ee99584195aeb10b1ed54513bd585f571e03c66f4be151189bfea
data/README.md ADDED
@@ -0,0 +1,48 @@
1
+
2
+ # cocoapods-patch
3
+
4
+ cocoapods-patch is a Cocoapods plugin that solves the problem of forking and maintaining a separate version of a Pod when only a small (often a one-liner), long-lived change in the original Pod is needed.
5
+
6
+ The idea behind the plugin is that patches should live inside the repo (in the `patches` directory) and be distributed together with the rest of your source code. This way, you can more easily code review and test the changes to a Pod and keep it synced across your team.
7
+
8
+ ## Installation
9
+
10
+ First, install the plugin
11
+
12
+ $ gem install cocoapods-patch
13
+
14
+ Next, add a `plugin 'cocoapods-patch'` line to your Podfile to use the plugin. This will enable [automatic apply](#automatically-applying-all-patches-on-install) so you don't have to worry about it again.
15
+
16
+ That's it, you're done.
17
+
18
+ **NOTE:**
19
+ `cocoapods-patch` version 1.0.0 and above require you to use Cocoapods 1.11.0 or greater.
20
+ For anything below that please use version 0.0.9.
21
+
22
+ ## Migrating to v1.0.1+
23
+
24
+ In v1.0.1 of the plugin we've changed the naming scheme of the generated patch files to also include the version of the pods used to generate the patches. This will allow us to do more automation safety and make sure patches are applied successfully.
25
+
26
+ We've added a new command to help with the migration. After updating before doing a `pod install` please first run `pod patch migrate` which will translate any existing patches into their new format. This will use the current version of the pods stated in your lockfile.
27
+
28
+ ## Usage
29
+
30
+ ### Creating a patch
31
+
32
+ To create a patch, first, you need to modify the source code of the installed Pod. Do the desired changes to the Pod source code (under the `Pods/` directory). Once you're satisfied with the result, run:
33
+
34
+ pod patch create POD_NAME
35
+
36
+ This will create a `patches/POD_NAME.diff` file in your repository. The patch is a diff between the Pod version you have specified in your Podfile and your local changes to the Pod. You can now add and commit this patch.
37
+
38
+ ### Automatically applying all patches on install
39
+
40
+ cocoapod-patch can be seamlessly integrated into the normal iOS development workflow. If you follow the installation instructions and add `plugin 'cocoapods-patch'` to your Podfile, every time you do a `pod install`, the plugin will go throught all the available patches and try to apply them. It will only warn you when the patch cannot be applied.
41
+
42
+ ### Applying a patch manually
43
+
44
+ When you want to apply a patch to a pod, run
45
+
46
+ pod patch apply POD_NAME
47
+
48
+ This command will look for the appropriate patch in the `patches` directory and, if possibly, apply it to your local Pod. A patch can be applied only once.
@@ -0,0 +1,3 @@
1
+ module EnrichPodPatcher
2
+ VERSION = "1.2.0"
3
+ end
@@ -0,0 +1,2 @@
1
+ require 'pod/command'
2
+ require 'pod/hook'
@@ -0,0 +1,53 @@
1
+ require 'cocoapods'
2
+
3
+ module Pod
4
+ class Command
5
+ class Patch < Command
6
+ class Apply < Patch
7
+ self.summary = 'Applies a patch to an installed Pod'
8
+
9
+ self.arguments = [
10
+ CLAide::Argument.new('NAME', true)
11
+ ]
12
+
13
+ def initialize(argv)
14
+ @name = argv.shift_argument
15
+ super
16
+ end
17
+
18
+ def validate!
19
+ super
20
+ help! 'A Pod name is required.' unless @name
21
+ end
22
+
23
+ def run
24
+ apply_patch patch_file
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
30
+
31
+ # also used from the post-install hook
32
+ def apply_patch(patch_file)
33
+ working_dir = Dir.pwd
34
+ repo_root = `git rev-parse --show-toplevel`.strip
35
+ ios_project_path = Pathname.new(working_dir).relative_path_from(Pathname.new(repo_root))
36
+
37
+ directory_arg = (ios_project_path.to_s.eql? ".") ? "Pods" : File.join(ios_project_path, 'Pods')
38
+
39
+ Dir.chdir(repo_root) {
40
+ check_cmd = "git apply --check '#{patch_file}' --directory='#{directory_arg}' -p2 2> /dev/null"
41
+
42
+ can_apply = system(check_cmd)
43
+ if can_apply
44
+ apply_cmd = check_cmd.gsub('--check ', '')
45
+ did_apply = system(apply_cmd)
46
+ if did_apply
47
+ Pod::UI.puts "Successfully applied #{patch_file} 🎉"
48
+ else
49
+ Pod::UI.warn "Error: failed to apply #{patch_file}"
50
+ end
51
+ end
52
+ }
53
+ end
@@ -0,0 +1,80 @@
1
+ require 'pathname'
2
+
3
+ module Pod
4
+ class Command
5
+ class Patch < Command
6
+ class Create < Patch
7
+ self.description = <<-DESC
8
+ Creates a patch file comparing your local Pod changes to the upstream
9
+ version specified in your Podfile. The patch is saved into the `patches`
10
+ directory.
11
+ DESC
12
+
13
+ self.arguments = [
14
+ CLAide::Argument.new('NAME', true)
15
+ ]
16
+
17
+ def initialize(argv)
18
+ @name = argv.shift_argument
19
+ super
20
+ end
21
+
22
+ def validate!
23
+ super
24
+ help! 'A Pod name is required.' unless @name
25
+ end
26
+
27
+ def clear_patches_folder_if_empty
28
+ if Dir.empty?(patches_path)
29
+ FileUtils.remove_dir(patches_path)
30
+ end
31
+ end
32
+
33
+ def run
34
+ # create patches folder if it doesn't exist
35
+ FileUtils.mkdir_p(patches_path)
36
+
37
+ Dir.mktmpdir('cocoapods-patch-', config.project_root) do |work_dir|
38
+ sandbox = Pod::Sandbox.new(work_dir)
39
+ installer = Pod::Installer.new(sandbox, config.podfile, config.lockfile)
40
+ installer.clean_install = true
41
+
42
+ installer.prepare
43
+ installer.resolve_dependencies
44
+
45
+ UI.puts "Checking if pod exists in project..."
46
+ specs_by_platform = installer.send :specs_for_pod, @name
47
+
48
+ if specs_by_platform.empty?
49
+ clear_patches_folder_if_empty
50
+ help! "Given pod does not exist in project. Did you use incorrect pod name?"
51
+
52
+ return
53
+ end
54
+
55
+ pod_installer = installer.send :create_pod_installer, @name
56
+ pod_installer.install!
57
+
58
+ UI.puts "Creating patch"
59
+ theirs = Pathname.new(work_dir).join(@name).relative_path_from(config.project_root)
60
+ ours = config.project_pods_root.join(@name).relative_path_from(config.project_root)
61
+ gen_diff_cmd = "git diff --no-index '#{theirs}' '#{ours}' > '#{patch_file}'"
62
+
63
+ did_succeed = system(gen_diff_cmd)
64
+ if not did_succeed.nil?
65
+ if File.empty?(patch_file)
66
+ File.delete(patch_file)
67
+ clear_patches_folder_if_empty
68
+ UI.warn "Error: no changes detected between current pod and original"
69
+ else
70
+ UI.puts "Created patch #{patch_file} 🎉"
71
+ end
72
+ else
73
+ UI.warn "Error: failed to create patch for #{@name}"
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,44 @@
1
+ require 'pathname'
2
+
3
+ module Pod
4
+ class Command
5
+ class Patch < Command
6
+ class Migrate < Patch
7
+ self.description = <<-DESC
8
+ Migrates previous patch files to the new format.
9
+ DESC
10
+
11
+ def clear_patches_folder_if_empty
12
+ if Dir.empty?(patches_path)
13
+ FileUtils.remove_dir(patches_path)
14
+ end
15
+ end
16
+
17
+ def run
18
+ UI.puts 'Migrating patches...'
19
+ patches_dir = Pathname.new(Dir.pwd) + 'patches'
20
+ if patches_dir.directory?
21
+ patches = patches_dir.each_child.select { |c| c.to_s.end_with?('.diff') }
22
+ patches.each do |p|
23
+ # check if patch file has new format
24
+ if p.to_s.include?('+')
25
+ # do nothing
26
+ else
27
+ # rename patch file
28
+ pod_name = p.basename('.diff').to_s
29
+ UI.puts "Renaming #{pod_name}"
30
+
31
+ pod_version = config.lockfile.version(pod_name)
32
+ new_patch_name = p.to_s.gsub('.diff', "+#{pod_version}.diff")
33
+
34
+ File.rename(p, new_patch_name)
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+
44
+
@@ -0,0 +1,20 @@
1
+ require_relative 'patch/apply'
2
+ require_relative 'patch/create'
3
+
4
+ module Pod
5
+ class Command
6
+ class Patch < Command
7
+ self.abstract_command = true
8
+ self.summary = 'Create & apply patches to Pods.'
9
+
10
+ def patch_file
11
+ version = config.lockfile.version(@name)
12
+ return config.project_root + 'patches' + "#{@name}+#{version}.diff"
13
+ end
14
+
15
+ def patches_path
16
+ config.project_root + 'patches'
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,4 @@
1
+ require_relative 'command/patch'
2
+ require_relative 'command/patch/apply'
3
+ require_relative 'command/patch/create'
4
+ require_relative 'command/patch/migrate'
data/lib/pod/hook.rb ADDED
@@ -0,0 +1,54 @@
1
+ require 'cocoapods'
2
+ require 'pathname'
3
+ require_relative 'command/patch/apply'
4
+
5
+ module EnrichPodPatcher
6
+ module Hooks
7
+ Pod::HooksManager.register('enrich-pod-patcher', :pre_install) do |context|
8
+ Pod::UI.puts 'Preparing patchable pods for clean patching'
9
+ patches_dir = Pathname.new(Dir.pwd) + 'patches'
10
+ if patches_dir.directory?
11
+ patches = patches_dir.each_child.select { |c| c.to_s.end_with?('.diff') }
12
+ patches.each do |p|
13
+ pod_name = File.basename(p, ".diff")
14
+ pod_dir = context.sandbox.pod_dir(pod_name)
15
+ context.sandbox.clean_pod(pod_name, pod_dir)
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+
22
+ class Pod::Installer
23
+ # Because our patches may also delete files, we need to apply them before the pod project is generated
24
+ # The project is generated in the `integrate` method, so we override it
25
+ # We first run our patch action and then the original implementation of the method
26
+ # Reference: https://github.com/CocoaPods/CocoaPods/blob/760828a07f8fcfbff03bce13f56a1789b6f5a95d/lib/cocoapods/installer.rb#L178
27
+ alias_method :integrate_old, :integrate
28
+
29
+ def integrate
30
+ # apply our patches
31
+ apply_patches
32
+ # run the original implementation
33
+ integrate_old
34
+ end
35
+
36
+ def apply_patches
37
+ Pod::UI.puts 'Applying patches if necessary'
38
+ patches_dir = Pathname.new(Dir.pwd) + 'patches'
39
+ if patches_dir.directory?
40
+ patches = patches_dir.each_child.select { |c| c.to_s.end_with?('.diff') }
41
+ patches.each do |p|
42
+ pod_name = File.basename(p, ".diff")
43
+ # check if patch is in new format otherwise warn user
44
+ unless p.to_s.include?('+')
45
+ Pod::UI.puts "WARNING: #{pod_name}.diff has an old naming format. Please run pod patch migration first before pod install. See the README for more information.".yellow
46
+ end
47
+
48
+ apply_patch(p)
49
+ end
50
+ end
51
+ end
52
+ end
53
+
54
+
metadata ADDED
@@ -0,0 +1,108 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: enrich-pod-patcher
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.2.0
5
+ platform: ruby
6
+ authors:
7
+ - Enrich Software Corp
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2023-07-18 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: cocoapods
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 1.12.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 1.12.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '2.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '2.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '13.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '13.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '3.9'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '3.9'
69
+ description: Create & apply patches to Pods
70
+ email:
71
+ - doug.yuen@enrichsoftware.com
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - README.md
77
+ - lib/cocoapods_patch.rb
78
+ - lib/cocoapods_plugin.rb
79
+ - lib/pod/command.rb
80
+ - lib/pod/command/patch.rb
81
+ - lib/pod/command/patch/apply.rb
82
+ - lib/pod/command/patch/create.rb
83
+ - lib/pod/command/patch/migrate.rb
84
+ - lib/pod/hook.rb
85
+ homepage:
86
+ licenses:
87
+ - MIT
88
+ metadata: {}
89
+ post_install_message:
90
+ rdoc_options: []
91
+ require_paths:
92
+ - lib
93
+ required_ruby_version: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ version: '0'
98
+ required_rubygems_version: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - ">="
101
+ - !ruby/object:Gem::Version
102
+ version: '0'
103
+ requirements: []
104
+ rubygems_version: 3.0.9
105
+ signing_key:
106
+ specification_version: 4
107
+ summary: Create & apply patches to Pods
108
+ test_files: []