kintsugi 0.3.1 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cdc0655ad443f7511adec336aef55e40ed0bb5458cf5fd9ae7747294bf40881d
4
- data.tar.gz: 214a8426b955d0c36b2ff51f55b2016ed69861ccc5d99fa2d463567cbc6872fc
3
+ metadata.gz: 0e2593fa95851c928b7ad943430c1db40d4c21831e24bd16f371f24298714c99
4
+ data.tar.gz: dca49c53301790803690ad5aa81dcf59b2f9036402a713b63b9093130994fe51
5
5
  SHA512:
6
- metadata.gz: 79d21fb3b3ddcb977a0b09bb5f80d19d6337574cb5b975a342d261bd689b53ff387a4ef2c7f0fb9a33d6698ce0e739b76824515ecf4b869f5858228635d99047
7
- data.tar.gz: 4a902033e2f4236d82f3db8b1fa832ec78e8201b264a32a11599b3c0df3b048bb82e5abee8cb3d3fac7e74ae4d6ff37029ae9cd809fee5ebbe65723c997862e7
6
+ metadata.gz: aa8c40252da2e56f9753fd143e1b100599c31737badcb5c16906e5883008b6344a5e44c09f2619f90045b0c987971f0248f2400d5f95acd20dac7c810b061a05
7
+ data.tar.gz: 15da61db3bea0d5d3c9528ba93b087ae67956eb58f4d846639936fcf682ac5f7cc5f6d2ec8eb87cc41673b960978e245b3eaf33d21b31c1e5a0ebadf46780d07
data/README.md CHANGED
@@ -40,15 +40,22 @@ And see the magic happen! :sparkles:
40
40
 
41
41
  ### Git merge driver
42
42
 
43
- To use Kintsugi as a Git merge driver, follow these steps:
43
+ You can setup Kintsugi to automatically resolve conflicts that occur in `pbxproj` files when such conflicts occur.
44
44
 
45
- - Add it as driver to Git config file by running the following:
45
+ #### Automatic install
46
+
47
+ Run `kintsugi install-driver`. This will install Kintsugi as a merge driver globally. Note that Kintsugi needs to be in your `PATH`.
48
+
49
+ ❗ Do not install with bundler because the installation might succeed even if Kintsugi is not in `PATH`.
50
+
51
+ #### Manual install
52
+
53
+ - Add Kintsugi as driver to Git config file by running the following:
46
54
  ```sh
47
55
  git config merge.kintsugi.name "Kintsugi driver" # Or any other name you prefer
48
- git config merge.kintsugi.driver "kintsugi driver %O %A %B %P"
56
+ git config merge.kintsugi.driver "<path_to_kintsugi> driver %O %A %B %P"
49
57
  ```
50
58
 
51
- `kintsugi` should be in your `PATH`.
52
59
  Run `git config` with `--global` to add this to the global config file.
53
60
 
54
61
  - Add the following line to the `.gitattributes` file at the root of the repository:
@@ -65,7 +72,11 @@ See our [Contribution guidelines](./CONTRIBUTING.md).
65
72
 
66
73
  ## Alternatives
67
74
 
68
- - [XcodeGen](https://github.com/yonaskolb/XcodeGen): You can commit this JSON file into Git instead of the `.pbxproj` file. Then resolving conflicts is much easier.
75
+ All of the alternatives below allow you to generate your Xcode projects based on a spec or manifest. You commit these files to git, and can even remove the `.xcodeproj` files from git.
76
+
77
+ - [XcodeGen](https://github.com/yonaskolb/XcodeGen)
78
+ - [Tuist](https://github.com/tuist)
79
+ - [Xcake](https://github.com/igor-makarov/xcake)
69
80
 
70
81
  ## Copyright
71
82
 
data/bin/kintsugi CHANGED
@@ -6,6 +6,7 @@
6
6
 
7
7
  require "kintsugi"
8
8
  require_relative "../lib/kintsugi/cli"
9
+ require_relative "../lib/kintsugi/error"
9
10
 
10
11
  def parse_options!(command, argv)
11
12
  options = {}
@@ -28,4 +29,11 @@ command =
28
29
  end
29
30
 
30
31
  options = parse_options!(command, ARGV)
31
- command.action.call(options, ARGV, command.option_parser)
32
+
33
+ begin
34
+ command.action.call(options, ARGV)
35
+ rescue ArgumentError => e
36
+ puts "#{e.class}: #{e}"
37
+ rescue Kintsugi::MergeError => e
38
+ puts e
39
+ end
@@ -190,24 +190,24 @@ module Kintsugi
190
190
  when Hash
191
191
  (old_value || {}).reject do |key, value|
192
192
  if value != removed_change[key] && added_change[key] != value
193
- raise "Trying to remove value '#{removed_change[key]}' of hash with key '#{key}' but " \
194
- "it changed to #{value}. This is considered a conflict that should be resolved " \
195
- "manually."
193
+ raise MergeError, "Trying to remove value '#{removed_change[key]}' of hash with key " \
194
+ "'#{key}' but it changed to #{value}. This is considered a conflict that should be " \
195
+ "resolved manually."
196
196
  end
197
197
 
198
198
  removed_change.key?(key)
199
199
  end
200
200
  when String
201
201
  if old_value != removed_change && !old_value.nil? && added_change != old_value
202
- raise "Trying to remove value '#{removed_change}', but the existing value is " \
203
- "'#{old_value}'. This is considered a conflict that should be resolved manually."
202
+ raise MergeError, "Trying to remove value '#{removed_change}', but the existing value " \
203
+ "is '#{old_value}'. This is considered a conflict that should be resolved manually."
204
204
  end
205
205
 
206
206
  nil
207
207
  when nil
208
208
  nil
209
209
  else
210
- raise "Unsupported change #{removed_change} of type #{removed_change.class}"
210
+ raise MergeError, "Unsupported change #{removed_change} of type #{removed_change.class}"
211
211
  end
212
212
  end
213
213
 
@@ -220,7 +220,8 @@ module Kintsugi
220
220
  new_value = old_value.merge(change)
221
221
 
222
222
  unless (old_value.to_a - new_value.to_a).empty?
223
- raise "New hash #{change} contains values that conflict with old hash #{old_value}"
223
+ raise MergeError, "New hash #{change} contains values that conflict with old hash " \
224
+ "#{old_value}"
224
225
  end
225
226
 
226
227
  new_value
@@ -229,14 +230,15 @@ module Kintsugi
229
230
  when nil
230
231
  nil
231
232
  else
232
- raise "Unsupported change #{change} of type #{change.class}"
233
+ raise MergeError, "Unsupported change #{change} of type #{change.class}"
233
234
  end
234
235
  end
235
236
 
236
237
  def remove_component(component, change)
237
238
  if component.to_tree_hash != change
238
- raise "Trying to remove an object that changed since then. This is considered a conflict " \
239
- "that should be resolved manually. Name of the object is: '#{component.display_name}'"
239
+ raise MergeError, "Trying to remove an object that changed since then. This is " \
240
+ "considered a conflict that should be resolved manually. Name of the object is: " \
241
+ "'#{component.display_name}'"
240
242
  end
241
243
 
242
244
  if change["isa"] == "PBXFileReference"
@@ -302,8 +304,8 @@ module Kintsugi
302
304
  when "PBXReferenceProxy"
303
305
  add_reference_proxy(component, change)
304
306
  else
305
- raise "Trying to add unsupported component type #{change["isa"]}. Full component change " \
306
- "is: #{change}"
307
+ raise MergeError, "Trying to add unsupported component type #{change["isa"]}. Full " \
308
+ "component change is: #{change}"
307
309
  end
308
310
  end
309
311
 
@@ -331,7 +333,7 @@ module Kintsugi
331
333
  containing_component << reference_proxy
332
334
  add_attributes_to_component(reference_proxy, change)
333
335
  else
334
- raise "Trying to add reference proxy to an unsupported component type " \
336
+ raise MergeError, "Trying to add reference proxy to an unsupported component type " \
335
337
  "#{containing_component.isa}. Change is: #{change}"
336
338
  end
337
339
  end
@@ -346,7 +348,7 @@ module Kintsugi
346
348
  containing_component.children << variant_group
347
349
  add_attributes_to_component(variant_group, change)
348
350
  else
349
- raise "Trying to add variant group to an unsupported component type " \
351
+ raise MergeError, "Trying to add variant group to an unsupported component type " \
350
352
  "#{containing_component.isa}. Change is: #{change}"
351
353
  end
352
354
  end
@@ -442,7 +444,7 @@ module Kintsugi
442
444
  when "PBXReferenceProxy"
443
445
  component.remote_ref = container_proxy
444
446
  else
445
- raise "Trying to add container item proxy to an unsupported component type " \
447
+ raise MergeError, "Trying to add container item proxy to an unsupported component type " \
446
448
  "#{containing_component.isa}. Change is: #{change}"
447
449
  end
448
450
  add_attributes_to_component(container_proxy, change, ignore_keys: ["containerPortal"])
@@ -541,7 +543,7 @@ module Kintsugi
541
543
  file_reference.include_in_index = nil
542
544
  add_attributes_to_component(file_reference, change)
543
545
  else
544
- raise "Trying to add file reference to an unsupported component type " \
546
+ raise MergeError, "Trying to add file reference to an unsupported component type " \
545
547
  "#{containing_component.isa}. Change is: #{change}"
546
548
  end
547
549
  end
@@ -556,8 +558,8 @@ module Kintsugi
556
558
  new_group = containing_component.project.new(Xcodeproj::Project::PBXGroup)
557
559
  containing_component.children << new_group
558
560
  else
559
- raise "Trying to add group to an unsupported component type #{containing_component.isa}. " \
560
- "Change is: #{change}"
561
+ raise MergeError, "Trying to add group to an unsupported component type " \
562
+ "#{containing_component.isa}. Change is: #{change}"
561
563
  end
562
564
 
563
565
  add_attributes_to_component(new_group, change)
@@ -581,8 +583,8 @@ module Kintsugi
581
583
  add_child_to_component(component, added_attribute_element)
582
584
  end
583
585
  else
584
- raise "Trying to add attribute of unsupported type '#{change_value.class}' to " \
585
- "object #{component}. Attribute name is '#{change_name}'"
586
+ raise MergeError, "Trying to add attribute of unsupported type '#{change_value.class}' " \
587
+ "to object #{component}. Attribute name is '#{change_name}'"
586
588
  end
587
589
  end
588
590
  end
data/lib/kintsugi/cli.rb CHANGED
@@ -12,12 +12,14 @@ module Kintsugi
12
12
  # Subcommands of Kintsugi CLI.
13
13
  attr_reader :subcommands
14
14
 
15
- # Root command Kintsugi CLI.
15
+ # Root command of Kintsugi CLI.
16
16
  attr_reader :root_command
17
17
 
18
18
  def initialize
19
19
  @subcommands = {
20
- "driver" => create_driver_subcommand
20
+ "driver" => create_driver_subcommand,
21
+ "install-driver" => create_install_driver_subcommand,
22
+ "uninstall-driver" => create_uninstall_driver_subcommand
21
23
  }.freeze
22
24
  @root_command = create_root_command
23
25
  end
@@ -27,7 +29,7 @@ module Kintsugi
27
29
  Command = Struct.new(:option_parser, :action, :description, keyword_init: true)
28
30
 
29
31
  def create_driver_subcommand
30
- driver_option_parser =
32
+ option_parser =
31
33
  OptionParser.new do |opts|
32
34
  opts.banner = "Usage: kintsugi driver BASE OURS THEIRS ORIGINAL_FILE_PATH\n" \
33
35
  "Uses Kintsugi as a Git merge driver. Parameters " \
@@ -40,7 +42,7 @@ module Kintsugi
40
42
  end
41
43
  end
42
44
 
43
- driver_action = lambda { |_, arguments, option_parser|
45
+ driver_action = lambda { |_, arguments|
44
46
  if arguments.count != 4
45
47
  puts "Incorrect number of arguments to 'driver' subcommand\n\n"
46
48
  puts option_parser
@@ -50,14 +52,110 @@ module Kintsugi
50
52
  }
51
53
 
52
54
  Command.new(
53
- option_parser: driver_option_parser,
55
+ option_parser: option_parser,
54
56
  action: driver_action,
55
57
  description: "3-way merge compatible with Git merge driver"
56
58
  )
57
59
  end
58
60
 
61
+ def create_install_driver_subcommand
62
+ option_parser =
63
+ OptionParser.new do |opts|
64
+ opts.banner = "Usage: kintsugi install-driver\n" \
65
+ "Installs Kintsugi as a Git merge driver globally. "
66
+
67
+ opts.on("-h", "--help", "Prints this help") do
68
+ puts opts
69
+ exit
70
+ end
71
+ end
72
+
73
+ action = lambda { |_, arguments|
74
+ if arguments.count != 0
75
+ puts "Incorrect number of arguments to 'install-driver' subcommand\n\n"
76
+ puts option_parser
77
+ exit(1)
78
+ end
79
+
80
+ if `which kintsugi`.chomp.empty?
81
+ puts "Can only install Kintsugi globally if Kintsugi is in your PATH"
82
+ exit(1)
83
+ end
84
+
85
+ install_kintsugi_driver_globally
86
+ puts "Done! 🪄"
87
+ }
88
+
89
+ Command.new(
90
+ option_parser: option_parser,
91
+ action: action,
92
+ description: "Installs Kintsugi as a Git merge driver globally"
93
+ )
94
+ end
95
+
96
+ def install_kintsugi_driver_globally
97
+ `git config --global merge.kintsugi.name "Kintsugi driver"`
98
+ `git config --global merge.kintsugi.driver "kintsugi driver %O %A %B %P"`
99
+
100
+ attributes_file_path = global_attributes_file_path
101
+ merge_using_kintsugi_line = "'*.pbxproj merge=kintsugi'"
102
+ `grep -sqxF #{merge_using_kintsugi_line} "#{attributes_file_path}" \
103
+ || echo #{merge_using_kintsugi_line} >> "#{attributes_file_path}"`
104
+ end
105
+
106
+ def global_attributes_file_path
107
+ # The logic to decide the path to the global attributes file is described at:
108
+ # https://git-scm.com/docs/gitattributes.
109
+ config_attributes_file_path = `git config --global core.attributesfile`
110
+ return config_attributes_file_path unless config_attributes_file_path.empty?
111
+
112
+ if ENV["XDG_CONFIG_HOME"].nil? || ENV["XDG_CONFIG_HOME"].empty?
113
+ File.join(ENV["HOME"], ".config/git/attributes")
114
+ else
115
+ File.join(ENV["XDG_CONFIG_HOME"], "git/attributes")
116
+ end
117
+ end
118
+
119
+ def create_uninstall_driver_subcommand
120
+ option_parser =
121
+ OptionParser.new do |opts|
122
+ opts.banner = "Usage: kintsugi uninstall-driver\n" \
123
+ "Uninstalls Kintsugi as a Git merge driver that was previously installed globally."
124
+
125
+ opts.on("-h", "--help", "Prints this help") do
126
+ puts opts
127
+ exit
128
+ end
129
+ end
130
+
131
+ action = lambda { |_, arguments|
132
+ if arguments.count != 0
133
+ puts "Incorrect number of arguments to 'uninstall-driver' subcommand\n\n"
134
+ puts option_parser
135
+ exit(1)
136
+ end
137
+
138
+ uninstall_kintsugi_driver_globally
139
+ puts "Done!"
140
+ }
141
+
142
+ Command.new(
143
+ option_parser: option_parser,
144
+ action: action,
145
+ description: "Uninstalls Kintsugi as a Git merge driver that was previously installed " \
146
+ "globally."
147
+ )
148
+ end
149
+
150
+ def uninstall_kintsugi_driver_globally
151
+ `git config --global --unset merge.kintsugi.name`
152
+ `git config --global --unset merge.kintsugi.driver`
153
+
154
+ `sed -i '' '/\*.pbxproj\ merge=kintsugi/d' "#{global_attributes_file_path}"`
155
+ end
156
+
59
157
  def create_root_command
60
- root_option_parser = OptionParser.new do |opts|
158
+ option_parser = OptionParser.new do |opts|
61
159
  opts.banner = "Kintsugi, version #{Version::STRING}\n" \
62
160
  "Copyright (c) 2021 Lightricks\n\n" \
63
161
  "Usage: kintsugi <pbxproj_filepath> [options]\n" \
@@ -83,7 +181,7 @@ module Kintsugi
83
181
  opts.on_tail("\nSUBCOMMANDS\n#{subcommands_descriptions}")
84
182
  end
85
183
 
86
- root_action = lambda { |options, arguments, option_parser|
184
+ root_action = lambda { |options, arguments|
87
185
  if arguments.count != 1
88
186
  puts "Incorrect number of arguments\n\n"
89
187
  puts option_parser
@@ -96,7 +194,7 @@ module Kintsugi
96
194
  }
97
195
 
98
196
  Command.new(
99
- option_parser: root_option_parser,
197
+ option_parser: option_parser,
100
198
  action: root_action,
101
199
  description: nil
102
200
  )
@@ -0,0 +1,9 @@
1
+ # Copyright (c) 2021 Lightricks. All rights reserved.
2
+ # Created by Ben Yohay.
3
+ # frozen_string_literal: true
4
+
5
+ module Kintsugi
6
+ # Raised when an error occurred while Kintsugi tried to resolve conflicts.
7
+ class MergeError < RuntimeError
8
+ end
9
+ end
@@ -3,6 +3,6 @@
3
3
  module Kintsugi
4
4
  # This module holds the Kintsugi version information.
5
5
  module Version
6
- STRING = "0.3.1"
6
+ STRING = "0.4.0"
7
7
  end
8
8
  end
data/lib/kintsugi.rb CHANGED
@@ -9,6 +9,7 @@ require "xcodeproj"
9
9
 
10
10
  require_relative "kintsugi/xcodeproj_extensions"
11
11
  require_relative "kintsugi/apply_change_to_project"
12
+ require_relative "kintsugi/error"
12
13
 
13
14
  module Kintsugi
14
15
  class << self
@@ -21,11 +22,11 @@ module Kintsugi
21
22
  # Path to where the changes to apply to the project are written in JSON format.
22
23
  #
23
24
  # @raise [ArgumentError]
24
- # If the file extension is not `pbxproj` or the file doesn't exist
25
+ # If the file extension is not `pbxproj`, or the file doesn't exist, or if no rebase,
26
+ # cherry-pick, or merge is in progress
25
27
  #
26
- # @raise [RuntimeError]
27
- # If no rebase, cherry-pick, or merge is in progress, or the project file couldn't be
28
- # opened, or there was an error applying the change to the project.
28
+ # @raise [MergeError]
29
+ # If there was an error applying the change to the project.
29
30
  #
30
31
  # @return [void]
31
32
  def resolve_conflicts(project_file_path, changes_output_path)
@@ -59,7 +60,7 @@ module Kintsugi
59
60
  # @param [String] original_project_path
60
61
  # Path to the original path of the file.
61
62
  #
62
- # @raise [RuntimeError]
63
+ # @raise [MergeError]
63
64
  # If there was an error applying the change to the project.
64
65
  #
65
66
  # @return [void]
@@ -104,8 +105,8 @@ module Kintsugi
104
105
 
105
106
  Dir.chdir(File.dirname(project_file_path)) do
106
107
  unless file_has_base_ours_and_theirs_versions?(project_file_path)
107
- raise ArgumentError, "File '#{project_file_path}' doesn't have conflicts, or a 3-way " \
108
- "merge is not possible."
108
+ raise ArgumentError, "File '#{project_file_path}' doesn't have conflicts, " \
109
+ "or a 3-way merge is not possible."
109
110
  end
110
111
  end
111
112
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kintsugi
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.1
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ben Yohay
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-11-30 00:00:00.000000000 Z
11
+ date: 2022-01-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: xcodeproj
@@ -123,6 +123,7 @@ files:
123
123
  - lib/kintsugi.rb
124
124
  - lib/kintsugi/apply_change_to_project.rb
125
125
  - lib/kintsugi/cli.rb
126
+ - lib/kintsugi/error.rb
126
127
  - lib/kintsugi/utils.rb
127
128
  - lib/kintsugi/version.rb
128
129
  - lib/kintsugi/xcodeproj_extensions.rb
@@ -150,7 +151,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
150
151
  version: '0'
151
152
  requirements: []
152
153
  rubyforge_project:
153
- rubygems_version: 2.7.3
154
+ rubygems_version: 2.7.6.3
154
155
  signing_key:
155
156
  specification_version: 4
156
157
  summary: pbxproj files git conflicts solver