Skip to content

Commit f3e4272

Browse files
authored
Add --status flag to bin/swap-deps (#52)
Adds a new --status flag that displays the current state of swapped dependencies across all demos (or a specific demo if --demo is used). The status output shows: - Swapped gems in Gemfile (path-based or GitHub-based) - Swapped npm packages in package.json (file: protocol) - Backup file presence This helps users quickly see what dependencies are currently swapped without inspecting individual Gemfile and package.json files.
1 parent 135ae13 commit f3e4272

File tree

3 files changed

+337
-3
lines changed

3 files changed

+337
-3
lines changed

lib/demo_scripts/gem_swapper.rb

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,15 @@ def kill_watch_processes
133133
end
134134
# rubocop:enable Metrics/MethodLength
135135

136+
# CLI entry point: Display current swapped dependencies status
137+
def show_status
138+
puts '📊 Swapped dependencies status:'
139+
140+
each_demo do |demo_path|
141+
show_demo_status(demo_path)
142+
end
143+
end
144+
136145
# CLI entry point: Display cache information including location, size, and cached repositories
137146
def show_cache_info
138147
unless File.directory?(CACHE_DIR)
@@ -201,8 +210,106 @@ def load_config(config_file)
201210
raise Error, "Invalid YAML in #{config_file}: #{e.message}"
202211
end
203212

213+
# Regex patterns for detecting swapped gems in Gemfile
214+
# These patterns match the format used by swap_gem_in_gemfile and swap_gem_to_github
215+
GEM_PATH_PATTERN = ->(gem_name) { /^\s*gem\s+["']#{Regexp.escape(gem_name)}["'],\s*path:\s*["']([^"']+)["']/ }
216+
GEM_GITHUB_PATTERN = lambda { |gem_name|
217+
github_pattern = /^\s*gem\s+["']#{Regexp.escape(gem_name)}["'],\s*github:\s*["']([^"']+)["']/
218+
github_ref_pattern = /(?:,\s*(?:branch|tag):\s*["']([^"']+)["'])?/
219+
/#{github_pattern}#{github_ref_pattern}/
220+
}
221+
204222
private
205223

224+
def show_demo_status(demo_path)
225+
puts "\n📦 #{demo_name(demo_path)}:"
226+
227+
gemfile_path = File.join(demo_path, 'Gemfile')
228+
package_json_path = File.join(demo_path, 'package.json')
229+
230+
swapped_gems = detect_swapped_gems(gemfile_path)
231+
swapped_packages = detect_swapped_packages(package_json_path)
232+
backups = detect_backup_files(gemfile_path, package_json_path)
233+
234+
display_swapped_gems(swapped_gems) if swapped_gems.any?
235+
display_swapped_packages(swapped_packages) if swapped_packages.any?
236+
237+
puts " Backups: #{backups.join(', ')}" if backups.any?
238+
239+
return unless swapped_gems.empty? && swapped_packages.empty?
240+
241+
if backups.any?
242+
puts ' ℹ️ No currently swapped dependencies (backups available)'
243+
else
244+
puts ' ℹ️ No swapped dependencies'
245+
end
246+
end
247+
248+
def detect_swapped_gems(gemfile_path)
249+
return [] unless File.exist?(gemfile_path)
250+
251+
gemfile_content = File.read(gemfile_path)
252+
swapped_gems = []
253+
254+
SUPPORTED_GEMS.each do |gem_name|
255+
path_match = gemfile_content.match(GEM_PATH_PATTERN.call(gem_name))
256+
github_match = gemfile_content.match(GEM_GITHUB_PATTERN.call(gem_name))
257+
258+
if path_match
259+
swapped_gems << { name: gem_name, type: 'local', path: path_match[1] }
260+
elsif github_match
261+
ref = github_match[2] || 'main'
262+
swapped_gems << { name: gem_name, type: 'github', path: "#{github_match[1]}@#{ref}" }
263+
end
264+
end
265+
266+
swapped_gems
267+
end
268+
269+
def detect_swapped_packages(package_json_path)
270+
return [] unless File.exist?(package_json_path)
271+
272+
package_data = JSON.parse(File.read(package_json_path))
273+
swapped_packages = []
274+
dependency_types = %w[dependencies devDependencies]
275+
276+
SUPPORTED_GEMS.each do |gem_name|
277+
npm_name = gem_name.tr('_', '-')
278+
dependency_types.each do |dep_type|
279+
next unless package_data[dep_type]&.key?(npm_name)
280+
281+
version = package_data[dep_type][npm_name]
282+
swapped_packages << { name: npm_name, path: version.sub('file:', '') } if version.start_with?('file:')
283+
end
284+
end
285+
286+
swapped_packages
287+
rescue JSON::ParserError
288+
puts ' ⚠️ Could not parse package.json'
289+
[]
290+
end
291+
292+
def detect_backup_files(gemfile_path, package_json_path)
293+
backups = []
294+
backups << 'Gemfile' if File.exist?(gemfile_path + BACKUP_SUFFIX)
295+
backups << 'package.json' if File.exist?(package_json_path + BACKUP_SUFFIX)
296+
backups
297+
end
298+
299+
def display_swapped_gems(swapped_gems)
300+
puts ' Gemfile:'
301+
swapped_gems.each do |gem|
302+
puts " ✓ #{gem[:name]}#{gem[:path]}"
303+
end
304+
end
305+
306+
def display_swapped_packages(swapped_packages)
307+
puts ' package.json:'
308+
swapped_packages.each do |pkg|
309+
puts " ✓ #{pkg[:name]}#{pkg[:path]}"
310+
end
311+
end
312+
206313
def cache_repo_dirs
207314
return [] unless File.directory?(CACHE_DIR)
208315

lib/demo_scripts/swap_deps_cli.rb

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,13 @@
44

55
module DemoScripts
66
# CLI for swapping dependencies between production and local/GitHub versions
7+
# rubocop:disable Metrics/ClassLength
78
class SwapDepsCLI
89
CONFIG_FILE = '.swap-deps.yml'
910

1011
attr_reader :gem_paths, :github_repos, :dry_run, :verbose, :restore, :apply_config,
1112
:skip_build, :watch_mode, :demo_filter, :demos_dir, :list_watch, :kill_watch,
12-
:show_cache, :clean_cache, :clean_cache_gem
13+
:show_cache, :clean_cache, :clean_cache_gem, :show_status
1314

1415
def initialize
1516
@gem_paths = {}
@@ -30,6 +31,7 @@ def initialize
3031
@show_cache = false
3132
@clean_cache = false
3233
@clean_cache_gem = nil
34+
@show_status = false
3335
end
3436

3537
# rubocop:disable Metrics/AbcSize, Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
@@ -40,7 +42,9 @@ def run!
4042
# Require bundler/setup only when actually running commands (not for --help)
4143
require 'bundler/setup'
4244

43-
if @show_cache
45+
if @show_status
46+
show_status_info
47+
elsif @show_cache
4448
show_cache_info
4549
elsif @clean_cache || @clean_cache_gem
4650
clean_cache_handler
@@ -184,7 +188,11 @@ def parse_options!
184188
end
185189

186190
opts.separator ''
187-
opts.separator 'Cache management:'
191+
opts.separator 'Status and cache management:'
192+
193+
opts.on('--status', 'Show current swapped dependencies status') do
194+
@show_status = true
195+
end
188196

189197
opts.on('--show-cache', 'Show cache location, size, and cached repositories') do
190198
@show_cache = true
@@ -258,6 +266,9 @@ def parse_options!
258266
puts ' # Stop all watch processes'
259267
puts ' bin/swap-deps --kill-watch'
260268
puts ''
269+
puts ' # Show current swapped dependencies status'
270+
puts ' bin/swap-deps --status'
271+
puts ''
261272
puts ' # Show cache information'
262273
puts ' bin/swap-deps --show-cache'
263274
puts ''
@@ -308,6 +319,11 @@ def clean_cache_handler
308319
swapper.clean_cache(gem_name: @clean_cache_gem)
309320
end
310321

322+
def show_status_info
323+
swapper = create_swapper
324+
swapper.show_status
325+
end
326+
311327
def apply_from_config
312328
# Use root config if in demo directory, otherwise look for local config
313329
config_file = @root_config_file || CONFIG_FILE
@@ -381,4 +397,5 @@ def each_demo(&)
381397
demos.each(&)
382398
end
383399
end
400+
# rubocop:enable Metrics/ClassLength
384401
end

0 commit comments

Comments
 (0)