Skip to content

Commit 8deb1a2

Browse files
authored
Improve swap-deps backup handling for multiple swaps (#48)
When users swap dependencies multiple times without restoring (e.g., swapping from path A to path B), the tool now: - Preserves the original backup (not the intermediate state) - Provides clearer messages about backup status - Detects and warns about inconsistent states This prevents users from losing their original dependency versions when performing multiple swaps in succession.
1 parent 0bfb7be commit 8deb1a2

File tree

1 file changed

+47
-2
lines changed

1 file changed

+47
-2
lines changed

lib/demo_scripts/gem_swapper.rb

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -740,20 +740,65 @@ def restore_demo(demo_path)
740740
restored
741741
end
742742

743+
# rubocop:disable Metrics/MethodLength, Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
743744
def backup_file(file_path)
744745
backup_path = file_path + BACKUP_SUFFIX
745746

747+
# If backup exists, check if the current file is already swapped
746748
if File.exist?(backup_path)
747-
puts " ⚠️ Backup already exists for #{File.basename(file_path)} - skipping new backup"
748-
return
749+
content = File.read(file_path)
750+
is_gemfile = file_path.end_with?('Gemfile')
751+
752+
# Check if file has already been swapped
753+
gem_names = NPM_PACKAGE_PATHS.keys.map { |name| Regexp.escape(name) }.join('|')
754+
gem_pattern = /^\s*gem\s+["'](?:#{gem_names})["'],.*(?:path:|github:)/
755+
already_swapped = if is_gemfile
756+
# Check for path: or github: in Gemfile
757+
content.match?(gem_pattern)
758+
else
759+
# Check for file: protocol on managed packages in package.json
760+
begin
761+
data = JSON.parse(content)
762+
dep_types = %w[dependencies devDependencies peerDependencies]
763+
# Convert gem names to npm package names (snake_case to kebab-case)
764+
npm_package_names = NPM_PACKAGE_PATHS.keys.map { |name| name.tr('_', '-') }
765+
dep_types.any? do |type|
766+
deps = data[type]
767+
next false unless deps.is_a?(Hash)
768+
769+
# Check if any managed package uses file: protocol
770+
npm_package_names.any? do |pkg_name|
771+
deps[pkg_name].is_a?(String) && deps[pkg_name].start_with?('file:')
772+
end
773+
end
774+
rescue JSON::ParserError
775+
false
776+
end
777+
end
778+
779+
if already_swapped
780+
# File is already swapped and backup exists - this is OK for re-swapping to new location
781+
puts ' ℹ️ Using existing backup (preserving original dependencies)'
782+
return
783+
else
784+
# File is not swapped but backup exists - this shouldn't happen normally
785+
puts ' ⚠️ WARNING: Backup exists but file appears unswapped. This is an inconsistent state.'
786+
puts ' The backup file may be corrupted or the file was manually edited.'
787+
puts ' Please either:'
788+
puts ' 1. Run: bin/swap-deps --restore'
789+
puts " 2. Or manually remove: #{File.basename(backup_path)}"
790+
raise Error, 'Inconsistent state: backup exists but file is not swapped. Run --restore first.'
791+
end
749792
end
750793

751794
if dry_run
752795
puts " [DRY-RUN] Would backup #{File.basename(file_path)}"
753796
else
754797
FileUtils.cp(file_path, backup_path)
798+
puts " ✓ Created backup: #{File.basename(backup_path)}"
755799
end
756800
end
801+
# rubocop:enable Metrics/MethodLength, Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
757802

758803
def write_file(file_path, content)
759804
if dry_run

0 commit comments

Comments
 (0)