diff --git a/Gemfile.lock b/Gemfile.lock index ae45624..604b098 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,7 +1,7 @@ PATH remote: . specs: - locport (1.2.1) + locport (1.3.0) thor (~> 1.3) GEM diff --git a/README.md b/README.md index 946c362..451467b 100644 --- a/README.md +++ b/README.md @@ -67,6 +67,22 @@ locport list If any conflicts are detected, they will be displayed and program exits with error code 1. +### Looking up a port by address + +```sh +locport port ADDRESS +``` + +Examples: + +```sh +locport port alpha.localhost +locport port http://alpha.localhost +``` + +Lookup compares addresses after removing a leading `http://` prefix from both sides. +If no address is found, command exits with code 1 and produces empty output. + ### Adding existing projects to the index ```sh diff --git a/lib/locport.rb b/lib/locport.rb index 67610f8..7a00012 100644 --- a/lib/locport.rb +++ b/lib/locport.rb @@ -45,6 +45,14 @@ def add(host = "#{File.basename(Dir.pwd)}.localhost") say "added ✓", :green end + desc "port ADDRESS", "Print the indexed port for an address" + def port(address) + found_port = indexer.port_for_address(address) + return say(found_port) if found_port + + exit 1 + end + desc "list", "List indexed projects, hosts and ports" def list indexer.projects.each do |dir, addresses| diff --git a/lib/locport/indexer.rb b/lib/locport/indexer.rb index 27a366a..2038b29 100644 --- a/lib/locport/indexer.rb +++ b/lib/locport/indexer.rb @@ -123,6 +123,14 @@ def append_address_to_dotfile(address, dir: Dir.pwd) save end + def port_for_address(value) + normalized_value = normalize_http_address(value) + + addresses.find do |address| + normalize_http_address(address.host) == normalized_value + end&.port + end + def storage_path File.join storage_dir, DATA_FILE end @@ -174,5 +182,9 @@ def find_unused_port return port unless @addresses.any? { |address| address.port == port } || port_listening?(port) end end + + def normalize_http_address(value) + value.to_s.delete_prefix("http://") + end end end diff --git a/locport.gemspec b/locport.gemspec index e7fdde1..29f4a9d 100644 --- a/locport.gemspec +++ b/locport.gemspec @@ -2,7 +2,7 @@ Gem::Specification.new do |spec| spec.name = "locport" - spec.version = "1.2.1" + spec.version = "1.3.0" spec.summary = "localhost port management" spec.description = "Overview of localhost ports used across projects. Prevent conflicts." spec.authors = ["Robert Starsi"] diff --git a/test/locport/indexer_test.rb b/test/locport/indexer_test.rb index e221394..3df1705 100644 --- a/test/locport/indexer_test.rb +++ b/test/locport/indexer_test.rb @@ -99,6 +99,19 @@ def test_port_open refute @indexer.port_listening?(port) end + def test_port_for_address + @indexer.index(@projects_path, recursive: true) + @indexer.load_projects + + assert_equal 30000, @indexer.port_for_address("http://alpha.localhost") + assert_equal 30000, @indexer.port_for_address("alpha.localhost") + assert_equal 30001, @indexer.port_for_address("http://conflict.localhost") + assert_equal 30001, @indexer.port_for_address("conflict.localhost") + assert_nil @indexer.port_for_address("http://alpha.localhost/foo") + assert_nil @indexer.port_for_address("missing.localhost") + assert_nil @indexer.port_for_address(nil) + end + def test_create_address_without_conflicts dir = Dir.mktmpdir diff --git a/test/locport_main_test.rb b/test/locport_main_test.rb index 6f6feb9..59e22b5 100644 --- a/test/locport_main_test.rb +++ b/test/locport_main_test.rb @@ -4,4 +4,42 @@ class LocportMainTest < Minitest::Test def test_default_task_is_list assert_equal "list", Locport::Main.default_task end + + def test_port_prints_port_when_found + indexer = Minitest::Mock.new + indexer.expect :port_for_address, 30000, ["https://alpha.localhost/foo"] + main = build_main(indexer) + + out, err = capture_io do + main.port("https://alpha.localhost/foo") + end + + assert_equal "30000\n", out + assert_empty err + indexer.verify + end + + def test_port_exits_with_non_zero_and_empty_output_when_not_found + indexer = Minitest::Mock.new + indexer.expect :port_for_address, nil, ["https://missing.localhost"] + main = build_main(indexer) + + out, err = capture_io do + error = assert_raises(SystemExit) do + main.port("https://missing.localhost") + end + assert_equal 1, error.status + end + + assert_empty out + assert_empty err + indexer.verify + end + + private + def build_main(indexer) + main = Locport::Main.new + main.define_singleton_method(:indexer) { indexer } + main + end end