From 9bf59bf7e304018f4590b3c54232d2a82038caa8 Mon Sep 17 00:00:00 2001 From: linrongbin16 Date: Sun, 7 Jan 2024 13:07:15 +0800 Subject: [PATCH 1/7] chore(ci): update (#24) --- .github/workflows/ci.yml | 2 +- README.md | 18 ++++++++++++------ ...3-1.rockspec => giturlparser-scm-1.rockspec | 2 +- 3 files changed, 14 insertions(+), 8 deletions(-) rename giturlparser-1.0.3-1.rockspec => giturlparser-scm-1.rockspec (95%) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 042b986..335caea 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -110,7 +110,7 @@ jobs: if: ${{ steps.release.outputs.release_created }} run: | luarocks install dkjson - luarocks write_rockspec --lua-versions="5.1,5.2,5.3,5.4" --tag=${{ steps.release.outputs.tag_name }} --detailed="Pure Lua implemented git URL parsing library" --summary="Pure Lua implemented git URL parsing library" --license=MIT + luarocks write_rockspec --lua-versions="5.1,5.2,5.3,5.4" --tag=${{ steps.release.outputs.tag_name }} --detailed="Pure Lua implemented git URL parsing library" --summary="Pure Lua implemented git URL parsing library" --license=MIT --homepage="https://github.com/linrongbin16/giturlparser.lua" echo 'ls-1' ls -lh mv giturlparser.lua-${{steps.release.outputs.major}}.${{steps.release.outputs.minor}}.${{steps.release.outputs.patch}}-1.rockspec giturlparser-${{steps.release.outputs.major}}.${{steps.release.outputs.minor}}.${{steps.release.outputs.patch}}-1.rockspec diff --git a/README.md b/README.md index 8184022..4ff22c2 100644 --- a/README.md +++ b/README.md @@ -10,11 +10,14 @@ Pure Lua implemented git URL parsing library, e.g. the output of git remote get-url origin.

+# Requirements + +- Lua >= 5.1, luajit >= 2.0.0. + ## Features - [x] Single file & zero dependency. -- [x] Support lua >= 5.1, luajit >= 2.0.0. -- [x] Compatible with RFC 3689. +- [x] Full [Git Protocols](https://git-scm.com/book/en/v2/Git-on-the-Server-The-Protocols) support. ## Install @@ -22,7 +25,9 @@ Pure Lua implemented git URL parsing library, e.g. the output of git remot ## API -### `giturlparser.GitUrlPos` +### Types + +#### `giturlparser.GitUrlPos` The string index of a component. @@ -35,7 +40,7 @@ It contains below fields: - `start_pos`: Start string index. - `end_pos`: End string index. -### `giturlparser.GitUrlInfo` +#### `giturlparser.GitUrlInfo` Parsed information. @@ -68,7 +73,9 @@ It contains below fields: > > If there's only 1 slash, the `org` component is omitted. -### `parse` +### Functions + +#### `parse` Parse `url` and returns the parsed info (lua table). @@ -90,7 +97,6 @@ Returns: ## References 1. [What are the supported git url formats?](https://stackoverflow.com/questions/31801271/what-are-the-supported-git-url-formats) -2. [4.1 Git on the Server - The Protocols](https://git-scm.com/book/en/v2/Git-on-the-Server-The-Protocols) ## Development diff --git a/giturlparser-1.0.3-1.rockspec b/giturlparser-scm-1.rockspec similarity index 95% rename from giturlparser-1.0.3-1.rockspec rename to giturlparser-scm-1.rockspec index bcc65c3..18b1e1a 100644 --- a/giturlparser-1.0.3-1.rockspec +++ b/giturlparser-scm-1.rockspec @@ -1,5 +1,5 @@ package = "giturlparser" -version = "1.0.3-1" +version = "scm-1" source = { url = "git+https://github.com/linrongbin16/giturlparser.lua.git", } From c86279f008639ee127d531c3b1f4b3b3f584beb8 Mon Sep 17 00:00:00 2001 From: linrongbin16 Date: Sun, 7 Jan 2024 16:57:14 +0800 Subject: [PATCH 2/7] chore(docs): wording (#25) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4ff22c2..fc80c29 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ Pure Lua implemented git URL parsing library, e.g. the output of git remot #### `giturlparser.GitUrlPos` -The string index of a component. +The string position of a component. ```lua --- @alias giturlparser.GitUrlPos {start_pos:integer?,end_pos:integer?} From 2b6f1dad3c7f3cd8de156c2028038aa9ae9e393e Mon Sep 17 00:00:00 2001 From: linrongbin16 Date: Sun, 7 Jan 2024 17:07:18 +0800 Subject: [PATCH 3/7] chore(docs): wording (#26) --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index fc80c29..5896132 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ Pure Lua implemented git URL parsing library, e.g. the output of git remote get-url origin.

-# Requirements +## Requirements - Lua >= 5.1, luajit >= 2.0.0. @@ -23,7 +23,7 @@ Pure Lua implemented git URL parsing library, e.g. the output of git remot `luarocks install giturlparser` -## API +## Documents ### Types From 29c0994a31fb9b4ca392f21bb84f102f92706076 Mon Sep 17 00:00:00 2001 From: linrongbin16 Date: Sun, 7 Jan 2024 17:09:56 +0800 Subject: [PATCH 4/7] chore(make): update (#27) --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 5f60bee..4a2cd3e 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -install_dev: +install_deps: luarocks install --local luacov luarocks install --local busted From 454d7c3094669641c5e5dcc3060947f2364e7634 Mon Sep 17 00:00:00 2001 From: linrongbin16 Date: Mon, 8 Jan 2024 15:05:00 +0800 Subject: [PATCH 5/7] fix(parse): fix parse (#28) --- .luacheckrc | 1 + Makefile | 6 - README.md | 90 ++- giturlparser-scm-1.rockspec | 3 + spec/giturlparser_spec.lua | 1432 ++++++++++++++++++++++++++++++++++- src/giturlparser.lua | 643 ++++++++-------- 6 files changed, 1835 insertions(+), 340 deletions(-) delete mode 100644 Makefile diff --git a/.luacheckrc b/.luacheckrc index 56f2305..810574b 100644 --- a/.luacheckrc +++ b/.luacheckrc @@ -3,3 +3,4 @@ max_line_length = 500 unused = false unused_args = false exclude_files = {} +ignore = { "542" } diff --git a/Makefile b/Makefile deleted file mode 100644 index 4a2cd3e..0000000 --- a/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -install_deps: - luarocks install --local luacov - luarocks install --local busted - -test: - busted --coverage diff --git a/README.md b/README.md index 5896132..11b3837 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ + + # giturlparser.lua

@@ -10,20 +12,69 @@ Pure Lua implemented git URL parsing library, e.g. the output of git remote get-url origin.

+## Table of Contents + +- [Requirements](#requirements) +- [Features](#features) +- [Install](#install) +- [API](#api) + - [Types](#types) + - [`giturlparser.GitUrlPos`](#giturlparsergiturlpos) + - [`giturlparser.GitUrlInfo`](#giturlparsergiturlinfo) + - [Functions](#functions) + - [`parse`](#parse) +- [References](#references) +- [Development](#development) +- [Contribute](#contribute) + ## Requirements - Lua >= 5.1, luajit >= 2.0.0. ## Features -- [x] Single file & zero dependency. -- [x] Full [Git Protocols](https://git-scm.com/book/en/v2/Git-on-the-Server-The-Protocols) support. +Single file & zero dependency. + +Full [Git Protocols](https://git-scm.com/book/en/v2/Git-on-the-Server-The-Protocols) support: + +> [!NOTE] +> +> Below pattern are (just easier to help explain the parsing algorithm) written in a regex-like syntax: +> +> 1. The `{}` contains parsed components returned from [`giturlparser.GitUrlInfo`](#giturlparsergiturlinfo). +> 2. The `[]` contains optional (0 or 1) component. +> 3. The `[]*` contains zero or more (≥ 0) component. +> 4. The `[]+` contains 1 or more (≥ 1) component. +> 5. The `|` inside `[]` is **_or_** operator. + +1. `{protocol}://[[{user}[:{password}]@]{host}[:{port}]]/[{org}/]*{repo}`, for example: + - `http://host.xyz/repo.git` + - `https://git@127.0.0.1:12345/repo.git` + - `ssh://username:password@host.xyz:port/path/to/the/repo.git` + - `ssh://host.xyz:port/path/to/the/repo.git` + - `file:///repo.git` + - `file://user:passwd@host.xyz:port/path/to/the/repo.git` + - `file://~/home/to/the/repo.git` +2. `[{user}[:{password}]@]{host}:[{org}/]*{repo}`, for example: + - `git@host.xyz:repo.git` + - `user:passwd@host.xyz:path/to/the/repo.git` +3. `[.|..|~][/{org}]*/{repo}`, for example: + - `repo.git` + - `./repo.git` + - `../path/to/the/repo.git` + - `~/home/to/the/repo.git` + - `/usr/home/to/the/repo.git` + +All of above can be written by: + +1. `[{protocol}://][[{user}[:{password}]@]host[:{port}]]/[{org}/]*{repo}` +2. `[.|..|~][/{org}]*/{repo}` ## Install `luarocks install giturlparser` -## Documents +## API ### Types @@ -50,28 +101,23 @@ Parsed information. It contains below fields: -- `protocol`: Protocol, e.g. `http` (`http://`), `https` (`https://`), `ssh` (`ssh://`), `file` (`file://`). -- `protocol_pos`: Protocol position. -- `user`: User name, e.g. `username` in `ssh://username@githost.com`. -- `user_pos`: User name position. -- `password`: Password, e.g. `password` in `ssh://username:password@githost.com`. -- `password_pos`: Password position. -- `host`: Host name, e.g. `githost.com` in `ssh://githost.com`. -- `host_pos`: Host name position. -- `path`: All the left parts after `host/`, e.g. `linrongbin16/giturlparser.lua.git` in `https://github.com/linrongbin16/giturlparser.lua.git`. -- `path_pos`: Path position. -- `repo`: Repository (the left parts after the last slash `/`, if exists), e.g. `giturlparser.lua.git` in `https://github.com/linrongbin16/giturlparser.lua.git`. -- `repo_pos`: Repository position. -- `org`: , Organization (the parts after `host/` and before the last slash `/`, if exists), e.g. `linrongbin16` in `https://github.com/linrongbin16/giturlparser.lua.git`. -- `org_pos`: Organization position. +- `protocol`/`protocol_pos`: Protocol, e.g. `http` in `http://github.com`, and its position. +- `user`/`user_pos`: User name, e.g. `username` in `ssh://username@githost.com`, and its position. +- `password`/`password_pos`: Password, e.g. `password` in `ssh://username:password@githost.com`, and its position. +- `host`/`host_pos`: Host name, e.g. `githost.com` in `ssh://githost.com`, and its position. +- `port`/`port_pos`: Port, e.g. `12345` in `ssh://127.0.0.1:12345/org/repo.git`, and its position. +- `path`/`path_pos`: All the left parts after host name (and optional port), e.g. `/linrongbin16/giturlparser.lua.git` in `https://github.com/linrongbin16/giturlparser.lua.git`, and its position. -> [!NOTE] -> -> The `{path}` component is equivalent to `{org}/{repo}`. +There're 2 more sugar fields: -> [!IMPORTANT] +- `repo`/`repo_pos`: Repository (the last part after the last slash `/`), e.g. `giturlparser.lua.git` in `https://github.com/linrongbin16/giturlparser.lua.git`, and its position. +- `org`/`org_pos`: , Organization (the parts after host name (and optional port), before the last slash `/`), e.g. `linrongbin16` in `https://github.com/linrongbin16/giturlparser.lua.git`, and its position. + +> [!NOTE] > -> If there's only 1 slash, the `org` component is omitted. +> - The `{path}` component is (almost) equivalent to `/{org}/{repo}`. +> - The `{org}` and `{repo}` component are trimmed from around slashes if there's any. +> - If there's only 1 slash, the `org` component is omitted. ### Functions diff --git a/giturlparser-scm-1.rockspec b/giturlparser-scm-1.rockspec index 18b1e1a..a9b930a 100644 --- a/giturlparser-scm-1.rockspec +++ b/giturlparser-scm-1.rockspec @@ -11,6 +11,9 @@ description = { dependencies = { "lua >= 5.1, luajit >= 2.0.0", } +test_dependencies = { + "inspect", +} build = { type = "builtin", modules = { diff --git a/spec/giturlparser_spec.lua b/spec/giturlparser_spec.lua index 3d49659..d096cee 100644 --- a/spec/giturlparser_spec.lua +++ b/spec/giturlparser_spec.lua @@ -5,8 +5,857 @@ describe("giturlparser", function() before_each(function() end) + -- local inspect = require("inspect") local giturlparser = require("giturlparser") - describe("[http(s)]", function() + describe("[_make_path]", function() + it("repo.git", function() + local actual = giturlparser._make_path("repo.git", 1) + assert_eq(actual.org, nil) + assert_eq(actual.org_pos, nil) + assert_eq(actual.repo, "repo.git") + assert_eq(actual.repo_pos.start_pos, 1) + assert_eq(actual.repo_pos.end_pos, 8) + assert_eq(actual.path, "repo.git") + assert_eq(actual.path_pos.start_pos, 1) + assert_eq(actual.path_pos.end_pos, 8) + end) + it("repo.git/", function() + local actual = giturlparser._make_path("repo.git/", 1) + assert_eq(actual.org, nil) + assert_eq(actual.org_pos, nil) + assert_eq(actual.repo, "repo.git") + assert_eq(actual.repo_pos.start_pos, 1) + assert_eq(actual.repo_pos.end_pos, 8) + assert_eq(actual.path, "repo.git/") + assert_eq(actual.path_pos.start_pos, 1) + assert_eq(actual.path_pos.end_pos, 9) + end) + it("/repo.git/", function() + local actual = giturlparser._make_path("/repo.git/", 1) + assert_eq(actual.org, nil) + assert_eq(actual.org_pos, nil) + assert_eq(actual.repo, "repo.git") + assert_eq(actual.repo_pos.start_pos, 2) + assert_eq(actual.repo_pos.end_pos, 9) + assert_eq(actual.path, "/repo.git/") + assert_eq(actual.path_pos.start_pos, 1) + assert_eq(actual.path_pos.end_pos, 10) + end) + it("/repo.git", function() + local actual = giturlparser._make_path("/repo.git", 1) + assert_eq(actual.org, nil) + assert_eq(actual.org_pos, nil) + assert_eq(actual.repo, "repo.git") + assert_eq(actual.repo_pos.start_pos, 2) + assert_eq(actual.repo_pos.end_pos, 9) + assert_eq(actual.path, "/repo.git") + assert_eq(actual.path_pos.start_pos, 1) + assert_eq(actual.path_pos.end_pos, 9) + end) + it("path/to/the/repo.git", function() + local actual = giturlparser._make_path("path/to/the/repo.git", 1) + assert_eq(actual.org, "path/to/the") + assert_eq(actual.org_pos.start_pos, 1) + assert_eq(actual.org_pos.end_pos, 11) + assert_eq(actual.repo, "repo.git") + assert_eq(actual.repo_pos.start_pos, 13) + assert_eq(actual.repo_pos.end_pos, 20) + assert_eq(actual.path, "path/to/the/repo.git") + assert_eq(actual.path_pos.start_pos, 1) + assert_eq(actual.path_pos.end_pos, 20) + end) + it("path/to/the/repo.git/", function() + local actual = giturlparser._make_path("path/to/the/repo.git/", 1) + assert_eq(actual.org, "path/to/the") + assert_eq(actual.org_pos.start_pos, 1) + assert_eq(actual.org_pos.end_pos, 11) + assert_eq(actual.repo, "repo.git") + assert_eq(actual.repo_pos.start_pos, 13) + assert_eq(actual.repo_pos.end_pos, 20) + assert_eq(actual.path, "path/to/the/repo.git/") + assert_eq(actual.path_pos.start_pos, 1) + assert_eq(actual.path_pos.end_pos, 21) + end) + it("/abspath/to/the/repo.git", function() + local actual = giturlparser._make_path("/abspath/to/the/repo.git", 1) + assert_eq(actual.org, "abspath/to/the") + assert_eq(actual.org_pos.start_pos, 2) + assert_eq(actual.org_pos.end_pos, 15) + assert_eq(actual.repo, "repo.git") + assert_eq(actual.repo_pos.start_pos, 17) + assert_eq(actual.repo_pos.end_pos, 24) + assert_eq(actual.path, "/abspath/to/the/repo.git") + assert_eq(actual.path_pos.start_pos, 1) + assert_eq(actual.path_pos.end_pos, 24) + end) + it("/abspath/to/the/repo.git/", function() + local actual = giturlparser._make_path("/abspath/to/the/repo.git/", 1) + assert_eq(actual.org, "abspath/to/the") + assert_eq(actual.org_pos.start_pos, 2) + assert_eq(actual.org_pos.end_pos, 15) + assert_eq(actual.repo, "repo.git") + assert_eq(actual.repo_pos.start_pos, 17) + assert_eq(actual.repo_pos.end_pos, 24) + assert_eq(actual.path, "/abspath/to/the/repo.git/") + assert_eq(actual.path_pos.start_pos, 1) + assert_eq(actual.path_pos.end_pos, 25) + end) + it("~/path/to/the/repo.git", function() + local actual = giturlparser._make_path("~/path/to/the/repo.git", 1) + assert_eq(actual.org, "~/path/to/the") + assert_eq(actual.org_pos.start_pos, 1) + assert_eq(actual.org_pos.end_pos, 13) + assert_eq(actual.repo, "repo.git") + assert_eq(actual.repo_pos.start_pos, 15) + assert_eq(actual.repo_pos.end_pos, 22) + assert_eq(actual.path, "~/path/to/the/repo.git") + assert_eq(actual.path_pos.start_pos, 1) + assert_eq(actual.path_pos.end_pos, 22) + end) + it("~/path/to/the/repo.git/", function() + local actual = giturlparser._make_path("~/path/to/the/repo.git/", 1) + assert_eq(actual.org, "~/path/to/the") + assert_eq(actual.org_pos.start_pos, 1) + assert_eq(actual.org_pos.end_pos, 13) + assert_eq(actual.repo, "repo.git") + assert_eq(actual.repo_pos.start_pos, 15) + assert_eq(actual.repo_pos.end_pos, 22) + assert_eq(actual.path, "~/path/to/the/repo.git/") + assert_eq(actual.path_pos.start_pos, 1) + assert_eq(actual.path_pos.end_pos, 23) + end) + it("./path/to/the/repo.git", function() + local actual = giturlparser._make_path("./path/to/the/repo.git", 1) + assert_eq(actual.org, "./path/to/the") + assert_eq(actual.org_pos.start_pos, 1) + assert_eq(actual.org_pos.end_pos, 13) + assert_eq(actual.repo, "repo.git") + assert_eq(actual.repo_pos.start_pos, 15) + assert_eq(actual.repo_pos.end_pos, 22) + assert_eq(actual.path, "./path/to/the/repo.git") + assert_eq(actual.path_pos.start_pos, 1) + assert_eq(actual.path_pos.end_pos, 22) + end) + it("../path/to/the/repo.git/", function() + local actual = giturlparser._make_path("../path/to/the/repo.git/", 1) + assert_eq(actual.org, "../path/to/the") + assert_eq(actual.org_pos.start_pos, 1) + assert_eq(actual.org_pos.end_pos, 14) + assert_eq(actual.repo, "repo.git") + assert_eq(actual.repo_pos.start_pos, 16) + assert_eq(actual.repo_pos.end_pos, 23) + assert_eq(actual.path, "../path/to/the/repo.git/") + assert_eq(actual.path_pos.start_pos, 1) + assert_eq(actual.path_pos.end_pos, 24) + end) + end) + + describe("[_make_host]", function() + it("github.com/org/repo.git", function() + local actual = giturlparser._make_host("github.com/org/repo.git", 1) + -- print(string.format("_make_host-1:%s\n", inspect(actual))) + assert_eq(actual.host, "github.com") + assert_eq(actual.host_pos.start_pos, 1) + assert_eq(actual.host_pos.end_pos, 10) + assert_eq(actual.port, nil) + assert_eq(actual.port_pos, nil) + local path_obj = actual.path_obj + assert_eq(path_obj.org, "org") + assert_eq(path_obj.org_pos.start_pos, 12) + assert_eq(path_obj.org_pos.end_pos, 14) + assert_eq(path_obj.repo, "repo.git") + assert_eq(path_obj.repo_pos.start_pos, 16) + assert_eq(path_obj.repo_pos.end_pos, 23) + assert_eq(path_obj.path, "/org/repo.git") + assert_eq(path_obj.path_pos.start_pos, 11) + assert_eq(path_obj.path_pos.end_pos, 23) + end) + it("github.com/org/repo.git/", function() + local actual = giturlparser._make_host("github.com/org/repo.git/", 1) + -- print(string.format("_make_host-2:%s\n", inspect(actual))) + assert_eq(actual.host, "github.com") + assert_eq(actual.host_pos.start_pos, 1) + assert_eq(actual.host_pos.end_pos, 10) + assert_eq(actual.port, nil) + assert_eq(actual.port_pos, nil) + local path_obj = actual.path_obj + assert_eq(path_obj.org, "org") + assert_eq(path_obj.org_pos.start_pos, 12) + assert_eq(path_obj.org_pos.end_pos, 14) + assert_eq(path_obj.repo, "repo.git") + assert_eq(path_obj.repo_pos.start_pos, 16) + assert_eq(path_obj.repo_pos.end_pos, 23) + assert_eq(path_obj.path, "/org/repo.git/") + assert_eq(path_obj.path_pos.start_pos, 11) + assert_eq(path_obj.path_pos.end_pos, 24) + end) + it("github.com:port/org/repo.git", function() + local actual = giturlparser._make_host("github.com:port/org/repo.git", 1) + -- print(string.format("_make_host-3:%s\n", inspect(actual))) + assert_eq(actual.host, "github.com") + assert_eq(actual.host_pos.start_pos, 1) + assert_eq(actual.host_pos.end_pos, 10) + assert_eq(actual.port, "port") + assert_eq(actual.port_pos.start_pos, 12) + assert_eq(actual.port_pos.end_pos, 15) + local path_obj = actual.path_obj + assert_eq(path_obj.org, "org") + assert_eq(path_obj.org_pos.start_pos, 17) + assert_eq(path_obj.org_pos.end_pos, 19) + assert_eq(path_obj.repo, "repo.git") + assert_eq(path_obj.repo_pos.start_pos, 21) + assert_eq(path_obj.repo_pos.end_pos, 28) + assert_eq(path_obj.path, "/org/repo.git") + assert_eq(path_obj.path_pos.start_pos, 16) + assert_eq(path_obj.path_pos.end_pos, 28) + end) + it("127.0.0.1:12345/org/repo.git/", function() + local actual = giturlparser._make_host("127.0.0.1:12345/org/repo.git/", 1) + -- print(string.format("_make_host-4:%s\n", inspect(actual))) + assert_eq(actual.host, "127.0.0.1") + assert_eq(actual.host_pos.start_pos, 1) + assert_eq(actual.host_pos.end_pos, 9) + assert_eq(actual.port, "12345") + assert_eq(actual.port_pos.start_pos, 11) + assert_eq(actual.port_pos.end_pos, 15) + local path_obj = actual.path_obj + assert_eq(path_obj.org, "org") + assert_eq(path_obj.org_pos.start_pos, 17) + assert_eq(path_obj.org_pos.end_pos, 19) + assert_eq(path_obj.repo, "repo.git") + assert_eq(path_obj.repo_pos.start_pos, 21) + assert_eq(path_obj.repo_pos.end_pos, 28) + assert_eq(path_obj.path, "/org/repo.git/") + assert_eq(path_obj.path_pos.start_pos, 16) + assert_eq(path_obj.path_pos.end_pos, 29) + end) + it("github.com/repo.git", function() + local actual = giturlparser._make_host("github.com/repo.git", 1) + -- print(string.format("_make_host-3:%s\n", inspect(actual))) + assert_eq(actual.host, "github.com") + assert_eq(actual.host_pos.start_pos, 1) + assert_eq(actual.host_pos.end_pos, 10) + assert_eq(actual.port, nil) + assert_eq(actual.port_pos, nil) + local path_obj = actual.path_obj + assert_eq(path_obj.org, nil) + assert_eq(path_obj.org_pos, nil) + assert_eq(path_obj.repo, "repo.git") + assert_eq(path_obj.repo_pos.start_pos, 12) + assert_eq(path_obj.repo_pos.end_pos, 19) + assert_eq(path_obj.path, "/repo.git") + assert_eq(path_obj.path_pos.start_pos, 11) + assert_eq(path_obj.path_pos.end_pos, 19) + end) + it("127.0.0.1:12345/repo.git/", function() + local actual = giturlparser._make_host("127.0.0.1:12345/repo.git/", 1) + -- print(string.format("_make_host-4:%s\n", inspect(actual))) + assert_eq(actual.host, "127.0.0.1") + assert_eq(actual.host_pos.start_pos, 1) + assert_eq(actual.host_pos.end_pos, 9) + assert_eq(actual.port, "12345") + assert_eq(actual.port_pos.start_pos, 11) + assert_eq(actual.port_pos.end_pos, 15) + local path_obj = actual.path_obj + assert_eq(path_obj.org, nil) + assert_eq(path_obj.org_pos, nil) + assert_eq(path_obj.repo, "repo.git") + assert_eq(path_obj.repo_pos.start_pos, 17) + assert_eq(path_obj.repo_pos.end_pos, 24) + assert_eq(path_obj.path, "/repo.git/") + assert_eq(path_obj.path_pos.start_pos, 16) + assert_eq(path_obj.path_pos.end_pos, 25) + end) + end) + + describe("[_make_host_with_omit_ssh]", function() + it("github.com:org/repo.git", function() + local actual = + giturlparser._make_host_with_omit_ssh("github.com:org/repo.git", 1) + -- print(string.format("_make_host_with_omit_ssh-1:%s\n", inspect(actual))) + assert_eq(actual.host, "github.com") + assert_eq(actual.host_pos.start_pos, 1) + assert_eq(actual.host_pos.end_pos, 10) + assert_eq(actual.port, nil) + assert_eq(actual.port_pos, nil) + local path_obj = actual.path_obj + assert_eq(path_obj.org, "org") + assert_eq(path_obj.org_pos.start_pos, 12) + assert_eq(path_obj.org_pos.end_pos, 14) + assert_eq(path_obj.repo, "repo.git") + assert_eq(path_obj.repo_pos.start_pos, 16) + assert_eq(path_obj.repo_pos.end_pos, 23) + assert_eq(path_obj.path, "org/repo.git") + assert_eq(path_obj.path_pos.start_pos, 12) + assert_eq(path_obj.path_pos.end_pos, 23) + end) + it("github.com:org/repo.git/", function() + local actual = + giturlparser._make_host_with_omit_ssh("github.com:org/repo.git/", 1) + -- print(string.format("_make_host_with_omit_ssh-2:%s\n", inspect(actual))) + assert_eq(actual.host, "github.com") + assert_eq(actual.host_pos.start_pos, 1) + assert_eq(actual.host_pos.end_pos, 10) + assert_eq(actual.port, nil) + assert_eq(actual.port_pos, nil) + local path_obj = actual.path_obj + assert_eq(path_obj.org, "org") + assert_eq(path_obj.org_pos.start_pos, 12) + assert_eq(path_obj.org_pos.end_pos, 14) + assert_eq(path_obj.repo, "repo.git") + assert_eq(path_obj.repo_pos.start_pos, 16) + assert_eq(path_obj.repo_pos.end_pos, 23) + assert_eq(path_obj.path, "org/repo.git/") + assert_eq(path_obj.path_pos.start_pos, 12) + assert_eq(path_obj.path_pos.end_pos, 24) + end) + it("github.com:repo.git", function() + local actual = + giturlparser._make_host_with_omit_ssh("github.com:repo.git", 1) + -- print(string.format("_make_host_with_omit_ssh-3:%s\n", inspect(actual))) + assert_eq(actual.host, "github.com") + assert_eq(actual.host_pos.start_pos, 1) + assert_eq(actual.host_pos.end_pos, 10) + assert_eq(actual.port, nil) + assert_eq(actual.port_pos, nil) + local path_obj = actual.path_obj + assert_eq(path_obj.org, nil) + assert_eq(path_obj.org_pos, nil) + assert_eq(path_obj.repo, "repo.git") + assert_eq(path_obj.repo_pos.start_pos, 12) + assert_eq(path_obj.repo_pos.end_pos, 19) + assert_eq(path_obj.path, "repo.git") + assert_eq(path_obj.path_pos.start_pos, 12) + assert_eq(path_obj.path_pos.end_pos, 19) + end) + it("127.0.0.1:repo.git/", function() + local actual = + giturlparser._make_host_with_omit_ssh("127.0.0.1:repo.git/", 1) + -- print(string.format("_make_host_with_omit_ssh-4:%s\n", inspect(actual))) + assert_eq(actual.host, "127.0.0.1") + assert_eq(actual.host_pos.start_pos, 1) + assert_eq(actual.host_pos.end_pos, 9) + assert_eq(actual.port, nil) + assert_eq(actual.port_pos, nil) + local path_obj = actual.path_obj + assert_eq(path_obj.org, nil) + assert_eq(path_obj.org_pos, nil) + assert_eq(path_obj.repo, "repo.git") + assert_eq(path_obj.repo_pos.start_pos, 11) + assert_eq(path_obj.repo_pos.end_pos, 18) + assert_eq(path_obj.path, "repo.git/") + assert_eq(path_obj.path_pos.start_pos, 11) + assert_eq(path_obj.path_pos.end_pos, 19) + end) + end) + + describe("[_make_user]", function() + it("github.com/org/repo.git", function() + local actual = giturlparser._make_user("github.com/org/repo.git", 1) + -- print(string.format("_make_user-1:%s\n", inspect(actual))) + assert_eq(actual.user, nil) + assert_eq(actual.user_pos, nil) + assert_eq(actual.password, nil) + assert_eq(actual.password_pos, nil) + local host_obj = actual.host_obj + assert_eq(host_obj.host, "github.com") + assert_eq(host_obj.host_pos.start_pos, 1) + assert_eq(host_obj.host_pos.end_pos, 10) + assert_eq(host_obj.port, nil) + assert_eq(host_obj.port_pos, nil) + local path_obj = host_obj.path_obj + assert_eq(path_obj.org, "org") + assert_eq(path_obj.org_pos.start_pos, 12) + assert_eq(path_obj.org_pos.end_pos, 14) + assert_eq(path_obj.repo, "repo.git") + assert_eq(path_obj.repo_pos.start_pos, 16) + assert_eq(path_obj.repo_pos.end_pos, 23) + assert_eq(path_obj.path, "/org/repo.git") + assert_eq(path_obj.path_pos.start_pos, 11) + assert_eq(path_obj.path_pos.end_pos, 23) + end) + it("github.com/org/repo.git/", function() + local actual = giturlparser._make_user("github.com/org/repo.git/", 1) + -- print(string.format("_make_user-2:%s\n", inspect(actual))) + assert_eq(actual.user, nil) + assert_eq(actual.user_pos, nil) + assert_eq(actual.password, nil) + assert_eq(actual.password_pos, nil) + local host_obj = actual.host_obj + assert_eq(host_obj.host, "github.com") + assert_eq(host_obj.host_pos.start_pos, 1) + assert_eq(host_obj.host_pos.end_pos, 10) + assert_eq(host_obj.port, nil) + assert_eq(host_obj.port_pos, nil) + local path_obj = host_obj.path_obj + assert_eq(path_obj.org, "org") + assert_eq(path_obj.org_pos.start_pos, 12) + assert_eq(path_obj.org_pos.end_pos, 14) + assert_eq(path_obj.repo, "repo.git") + assert_eq(path_obj.repo_pos.start_pos, 16) + assert_eq(path_obj.repo_pos.end_pos, 23) + assert_eq(path_obj.path, "/org/repo.git/") + assert_eq(path_obj.path_pos.start_pos, 11) + assert_eq(path_obj.path_pos.end_pos, 24) + end) + it("user@github.com/org/repo.git", function() + local actual = giturlparser._make_user("user@github.com/org/repo.git", 1) + -- print(string.format("_make_user-3:%s\n", inspect(actual))) + assert_eq(actual.user, "user") + assert_eq(actual.user_pos.start_pos, 1) + assert_eq(actual.user_pos.end_pos, 4) + assert_eq(actual.password, nil) + assert_eq(actual.password_pos, nil) + local host_obj = actual.host_obj + assert_eq(host_obj.host, "github.com") + assert_eq(host_obj.host_pos.start_pos, 6) + assert_eq(host_obj.host_pos.end_pos, 15) + assert_eq(host_obj.port, nil) + assert_eq(host_obj.port_pos, nil) + local path_obj = host_obj.path_obj + assert_eq(path_obj.org, "org") + assert_eq(path_obj.org_pos.start_pos, 17) + assert_eq(path_obj.org_pos.end_pos, 19) + assert_eq(path_obj.repo, "repo.git") + assert_eq(path_obj.repo_pos.start_pos, 21) + assert_eq(path_obj.repo_pos.end_pos, 28) + assert_eq(path_obj.path, "/org/repo.git") + assert_eq(path_obj.path_pos.start_pos, 16) + assert_eq(path_obj.path_pos.end_pos, 28) + end) + it("user:passwd@github.com/org/repo.git/", function() + local actual = + giturlparser._make_user("user:passwd@github.com/org/repo.git/", 1) + -- print(string.format("_make_user-4:%s\n", inspect(actual))) + assert_eq(actual.user, "user") + assert_eq(actual.user_pos.start_pos, 1) + assert_eq(actual.user_pos.end_pos, 4) + assert_eq(actual.password, "passwd") + assert_eq(actual.password_pos.start_pos, 6) + assert_eq(actual.password_pos.end_pos, 11) + local host_obj = actual.host_obj + assert_eq(host_obj.host, "github.com") + assert_eq(host_obj.host_pos.start_pos, 13) + assert_eq(host_obj.host_pos.end_pos, 22) + assert_eq(host_obj.port, nil) + assert_eq(host_obj.port_pos, nil) + local path_obj = host_obj.path_obj + assert_eq(path_obj.org, "org") + assert_eq(path_obj.org_pos.start_pos, 24) + assert_eq(path_obj.org_pos.end_pos, 26) + assert_eq(path_obj.repo, "repo.git") + assert_eq(path_obj.repo_pos.start_pos, 28) + assert_eq(path_obj.repo_pos.end_pos, 35) + assert_eq(path_obj.path, "/org/repo.git/") + assert_eq(path_obj.path_pos.start_pos, 23) + assert_eq(path_obj.path_pos.end_pos, 36) + end) + it("github.com:port/org/repo.git", function() + local actual = giturlparser._make_user("github.com:port/org/repo.git", 1) + -- print(string.format("_make_user-5:%s\n", inspect(actual))) + assert_eq(actual.user, nil) + assert_eq(actual.user_pos, nil) + assert_eq(actual.password, nil) + assert_eq(actual.password_pos, nil) + local host_obj = actual.host_obj + assert_eq(host_obj.host, "github.com") + assert_eq(host_obj.host_pos.start_pos, 1) + assert_eq(host_obj.host_pos.end_pos, 10) + assert_eq(host_obj.port, "port") + assert_eq(host_obj.port_pos.start_pos, 12) + assert_eq(host_obj.port_pos.end_pos, 15) + local path_obj = host_obj.path_obj + assert_eq(path_obj.org, "org") + assert_eq(path_obj.org_pos.start_pos, 17) + assert_eq(path_obj.org_pos.end_pos, 19) + assert_eq(path_obj.repo, "repo.git") + assert_eq(path_obj.repo_pos.start_pos, 21) + assert_eq(path_obj.repo_pos.end_pos, 28) + assert_eq(path_obj.path, "/org/repo.git") + assert_eq(path_obj.path_pos.start_pos, 16) + assert_eq(path_obj.path_pos.end_pos, 28) + end) + it("127.0.0.1:12345/org/repo.git/", function() + local actual = giturlparser._make_user("127.0.0.1:12345/org/repo.git/", 1) + -- print(string.format("_make_user-6:%s\n", inspect(actual))) + assert_eq(actual.user, nil) + assert_eq(actual.user_pos, nil) + assert_eq(actual.password, nil) + assert_eq(actual.password_pos, nil) + local host_obj = actual.host_obj + assert_eq(host_obj.host, "127.0.0.1") + assert_eq(host_obj.host_pos.start_pos, 1) + assert_eq(host_obj.host_pos.end_pos, 9) + assert_eq(host_obj.port, "12345") + assert_eq(host_obj.port_pos.start_pos, 11) + assert_eq(host_obj.port_pos.end_pos, 15) + local path_obj = host_obj.path_obj + assert_eq(path_obj.org, "org") + assert_eq(path_obj.org_pos.start_pos, 17) + assert_eq(path_obj.org_pos.end_pos, 19) + assert_eq(path_obj.repo, "repo.git") + assert_eq(path_obj.repo_pos.start_pos, 21) + assert_eq(path_obj.repo_pos.end_pos, 28) + assert_eq(path_obj.path, "/org/repo.git/") + assert_eq(path_obj.path_pos.start_pos, 16) + assert_eq(path_obj.path_pos.end_pos, 29) + end) + it("user2:passwd2@github.com:port/org/repo.git", function() + local actual = + giturlparser._make_user("user2:passwd2@github.com:port/org/repo.git", 1) + -- print(string.format("_make_user-7:%s\n", inspect(actual))) + assert_eq(actual.user, "user2") + assert_eq(actual.user_pos.start_pos, 1) + assert_eq(actual.user_pos.end_pos, 5) + assert_eq(actual.password, "passwd2") + assert_eq(actual.password_pos.start_pos, 7) + assert_eq(actual.password_pos.end_pos, 13) + local host_obj = actual.host_obj + assert_eq(host_obj.host, "github.com") + assert_eq(host_obj.host_pos.start_pos, 15) + assert_eq(host_obj.host_pos.end_pos, 24) + assert_eq(host_obj.port, "port") + assert_eq(host_obj.port_pos.start_pos, 26) + assert_eq(host_obj.port_pos.end_pos, 29) + local path_obj = host_obj.path_obj + assert_eq(path_obj.org, "org") + assert_eq(path_obj.org_pos.start_pos, 31) + assert_eq(path_obj.org_pos.end_pos, 33) + assert_eq(path_obj.repo, "repo.git") + assert_eq(path_obj.repo_pos.start_pos, 35) + assert_eq(path_obj.repo_pos.end_pos, 42) + assert_eq(path_obj.path, "/org/repo.git") + assert_eq(path_obj.path_pos.start_pos, 30) + assert_eq(path_obj.path_pos.end_pos, 42) + end) + it("git@127.0.0.1:12345/org/repo.git/", function() + local actual = + giturlparser._make_user("git@127.0.0.1:12345/org/repo.git/", 1) + -- print(string.format("_make_user-6:%s\n", inspect(actual))) + assert_eq(actual.user, "git") + assert_eq(actual.user_pos.start_pos, 1) + assert_eq(actual.user_pos.end_pos, 3) + assert_eq(actual.password, nil) + assert_eq(actual.password_pos, nil) + local host_obj = actual.host_obj + assert_eq(host_obj.host, "127.0.0.1") + assert_eq(host_obj.host_pos.start_pos, 5) + assert_eq(host_obj.host_pos.end_pos, 13) + assert_eq(host_obj.port, "12345") + assert_eq(host_obj.port_pos.start_pos, 15) + assert_eq(host_obj.port_pos.end_pos, 19) + local path_obj = host_obj.path_obj + assert_eq(path_obj.org, "org") + assert_eq(path_obj.org_pos.start_pos, 21) + assert_eq(path_obj.org_pos.end_pos, 23) + assert_eq(path_obj.repo, "repo.git") + assert_eq(path_obj.repo_pos.start_pos, 25) + assert_eq(path_obj.repo_pos.end_pos, 32) + assert_eq(path_obj.path, "/org/repo.git/") + assert_eq(path_obj.path_pos.start_pos, 20) + assert_eq(path_obj.path_pos.end_pos, 33) + end) + it("github.com/repo.git", function() + local actual = giturlparser._make_user("github.com/repo.git", 1) + -- print(string.format("_make_user-7:%s\n", inspect(actual))) + assert_eq(actual.user, nil) + assert_eq(actual.user_pos, nil) + assert_eq(actual.password, nil) + assert_eq(actual.password_pos, nil) + local host_obj = actual.host_obj + assert_eq(host_obj.host, "github.com") + assert_eq(host_obj.host_pos.start_pos, 1) + assert_eq(host_obj.host_pos.end_pos, 10) + assert_eq(host_obj.port, nil) + assert_eq(host_obj.port_pos, nil) + local path_obj = host_obj.path_obj + assert_eq(path_obj.org, nil) + assert_eq(path_obj.org_pos, nil) + assert_eq(path_obj.repo, "repo.git") + assert_eq(path_obj.repo_pos.start_pos, 12) + assert_eq(path_obj.repo_pos.end_pos, 19) + assert_eq(path_obj.path, "/repo.git") + assert_eq(path_obj.path_pos.start_pos, 11) + assert_eq(path_obj.path_pos.end_pos, 19) + end) + it("127.0.0.1:12345/repo.git/", function() + local actual = giturlparser._make_user("127.0.0.1:12345/repo.git/", 1) + -- print(string.format("_make_user-8:%s\n", inspect(actual))) + assert_eq(actual.user, nil) + assert_eq(actual.user_pos, nil) + assert_eq(actual.password, nil) + assert_eq(actual.password_pos, nil) + local host_obj = actual.host_obj + assert_eq(host_obj.host, "127.0.0.1") + assert_eq(host_obj.host_pos.start_pos, 1) + assert_eq(host_obj.host_pos.end_pos, 9) + assert_eq(host_obj.port, "12345") + assert_eq(host_obj.port_pos.start_pos, 11) + assert_eq(host_obj.port_pos.end_pos, 15) + local path_obj = host_obj.path_obj + assert_eq(path_obj.org, nil) + assert_eq(path_obj.org_pos, nil) + assert_eq(path_obj.repo, "repo.git") + assert_eq(path_obj.repo_pos.start_pos, 17) + assert_eq(path_obj.repo_pos.end_pos, 24) + assert_eq(path_obj.path, "/repo.git/") + assert_eq(path_obj.path_pos.start_pos, 16) + assert_eq(path_obj.path_pos.end_pos, 25) + end) + it("git@github.com/repo.git", function() + local actual = giturlparser._make_user("git@github.com/repo.git", 1) + -- print(string.format("_make_user-9:%s\n", inspect(actual))) + assert_eq(actual.user, "git") + assert_eq(actual.user_pos.start_pos, 1) + assert_eq(actual.user_pos.end_pos, 3) + assert_eq(actual.password, nil) + assert_eq(actual.password_pos, nil) + local host_obj = actual.host_obj + assert_eq(host_obj.host, "github.com") + assert_eq(host_obj.host_pos.start_pos, 5) + assert_eq(host_obj.host_pos.end_pos, 14) + assert_eq(host_obj.port, nil) + assert_eq(host_obj.port_pos, nil) + local path_obj = host_obj.path_obj + assert_eq(path_obj.org, nil) + assert_eq(path_obj.org_pos, nil) + assert_eq(path_obj.repo, "repo.git") + assert_eq(path_obj.repo_pos.start_pos, 16) + assert_eq(path_obj.repo_pos.end_pos, 23) + assert_eq(path_obj.path, "/repo.git") + assert_eq(path_obj.path_pos.start_pos, 15) + assert_eq(path_obj.path_pos.end_pos, 23) + end) + it("linrongbin:123456@127.0.0.1:12345/repo.git/", function() + local actual = + giturlparser._make_user("linrongbin:123@127.0.0.1:12345/repo.git/", 1) + -- print(string.format("_make_user-8:%s\n", inspect(actual))) + assert_eq(actual.user, "linrongbin") + assert_eq(actual.user_pos.start_pos, 1) + assert_eq(actual.user_pos.end_pos, 10) + assert_eq(actual.password, "123") + assert_eq(actual.password_pos.start_pos, 12) + assert_eq(actual.password_pos.end_pos, 14) + local host_obj = actual.host_obj + assert_eq(host_obj.host, "127.0.0.1") + assert_eq(host_obj.host_pos.start_pos, 16) + assert_eq(host_obj.host_pos.end_pos, 24) + assert_eq(host_obj.port, "12345") + assert_eq(host_obj.port_pos.start_pos, 26) + assert_eq(host_obj.port_pos.end_pos, 30) + local path_obj = host_obj.path_obj + assert_eq(path_obj.org, nil) + assert_eq(path_obj.org_pos, nil) + assert_eq(path_obj.repo, "repo.git") + assert_eq(path_obj.repo_pos.start_pos, 32) + assert_eq(path_obj.repo_pos.end_pos, 39) + assert_eq(path_obj.path, "/repo.git/") + assert_eq(path_obj.path_pos.start_pos, 31) + assert_eq(path_obj.path_pos.end_pos, 40) + end) + end) + + describe("[_make_user with omitted ssh]", function() + it("github.com:org/repo.git", function() + local actual = giturlparser._make_user("github.com:org/repo.git", 1, true) + -- print(string.format("_make_user_omit-1:%s\n", inspect(actual))) + assert_eq(actual.user, nil) + assert_eq(actual.user_pos, nil) + assert_eq(actual.password, nil) + assert_eq(actual.password_pos, nil) + local host_obj = actual.host_obj + assert_eq(host_obj.host, "github.com") + assert_eq(host_obj.host_pos.start_pos, 1) + assert_eq(host_obj.host_pos.end_pos, 10) + assert_eq(host_obj.port, nil) + assert_eq(host_obj.port_pos, nil) + local path_obj = host_obj.path_obj + assert_eq(path_obj.org, "org") + assert_eq(path_obj.org_pos.start_pos, 12) + assert_eq(path_obj.org_pos.end_pos, 14) + assert_eq(path_obj.repo, "repo.git") + assert_eq(path_obj.repo_pos.start_pos, 16) + assert_eq(path_obj.repo_pos.end_pos, 23) + assert_eq(path_obj.path, "org/repo.git") + assert_eq(path_obj.path_pos.start_pos, 12) + assert_eq(path_obj.path_pos.end_pos, 23) + end) + it("github.com:org/repo.git/", function() + local actual = + giturlparser._make_user("github.com:org/repo.git/", 1, true) + -- print(string.format("_make_user_omit-2:%s\n", inspect(actual))) + assert_eq(actual.user, nil) + assert_eq(actual.user_pos, nil) + assert_eq(actual.password, nil) + assert_eq(actual.password_pos, nil) + local host_obj = actual.host_obj + assert_eq(host_obj.host, "github.com") + assert_eq(host_obj.host_pos.start_pos, 1) + assert_eq(host_obj.host_pos.end_pos, 10) + assert_eq(host_obj.port, nil) + assert_eq(host_obj.port_pos, nil) + local path_obj = host_obj.path_obj + assert_eq(path_obj.org, "org") + assert_eq(path_obj.org_pos.start_pos, 12) + assert_eq(path_obj.org_pos.end_pos, 14) + assert_eq(path_obj.repo, "repo.git") + assert_eq(path_obj.repo_pos.start_pos, 16) + assert_eq(path_obj.repo_pos.end_pos, 23) + assert_eq(path_obj.path, "org/repo.git/") + assert_eq(path_obj.path_pos.start_pos, 12) + assert_eq(path_obj.path_pos.end_pos, 24) + end) + it("user@github.com:repo.git", function() + local actual = + giturlparser._make_user("user@github.com:repo.git", 1, true) + -- print(string.format("_make_user_omit-3:%s\n", inspect(actual))) + assert_eq(actual.user, "user") + assert_eq(actual.user_pos.start_pos, 1) + assert_eq(actual.user_pos.end_pos, 4) + assert_eq(actual.password, nil) + assert_eq(actual.password_pos, nil) + local host_obj = actual.host_obj + assert_eq(host_obj.host, "github.com") + assert_eq(host_obj.host_pos.start_pos, 6) + assert_eq(host_obj.host_pos.end_pos, 15) + assert_eq(host_obj.port, nil) + assert_eq(host_obj.port_pos, nil) + local path_obj = host_obj.path_obj + assert_eq(path_obj.org, nil) + assert_eq(path_obj.org_pos, nil) + assert_eq(path_obj.repo, "repo.git") + assert_eq(path_obj.repo_pos.start_pos, 17) + assert_eq(path_obj.repo_pos.end_pos, 24) + assert_eq(path_obj.path, "repo.git") + assert_eq(path_obj.path_pos.start_pos, 17) + assert_eq(path_obj.path_pos.end_pos, 24) + end) + it("user:passwd@127.0.0.1:repo.git/", function() + local actual = + giturlparser._make_user("user:passwd@127.0.0.1:repo.git/", 1, true) + -- print(string.format("_make_user_omit-4:%s\n", inspect(actual))) + assert_eq(actual.user, "user") + assert_eq(actual.user_pos.start_pos, 1) + assert_eq(actual.user_pos.end_pos, 4) + assert_eq(actual.password, "passwd") + assert_eq(actual.password_pos.start_pos, 6) + assert_eq(actual.password_pos.end_pos, 11) + local host_obj = actual.host_obj + assert_eq(host_obj.host, "127.0.0.1") + assert_eq(host_obj.host_pos.start_pos, 13) + assert_eq(host_obj.host_pos.end_pos, 21) + assert_eq(host_obj.port, nil) + assert_eq(host_obj.port_pos, nil) + local path_obj = host_obj.path_obj + assert_eq(path_obj.org, nil) + assert_eq(path_obj.org_pos, nil) + assert_eq(path_obj.repo, "repo.git") + assert_eq(path_obj.repo_pos.start_pos, 23) + assert_eq(path_obj.repo_pos.end_pos, 30) + assert_eq(path_obj.path, "repo.git/") + assert_eq(path_obj.path_pos.start_pos, 23) + assert_eq(path_obj.path_pos.end_pos, 31) + end) + it("github.com:repo.git", function() + local actual = giturlparser._make_user("github.com:repo.git", 1, true) + -- print(string.format("_make_user_omit-5:%s\n", inspect(actual))) + assert_eq(actual.user, nil) + assert_eq(actual.user_pos, nil) + assert_eq(actual.password, nil) + assert_eq(actual.password_pos, nil) + local host_obj = actual.host_obj + assert_eq(host_obj.host, "github.com") + assert_eq(host_obj.host_pos.start_pos, 1) + assert_eq(host_obj.host_pos.end_pos, 10) + assert_eq(host_obj.port, nil) + assert_eq(host_obj.port_pos, nil) + local path_obj = host_obj.path_obj + assert_eq(path_obj.org, nil) + assert_eq(path_obj.org_pos, nil) + assert_eq(path_obj.repo, "repo.git") + assert_eq(path_obj.repo_pos.start_pos, 12) + assert_eq(path_obj.repo_pos.end_pos, 19) + assert_eq(path_obj.path, "repo.git") + assert_eq(path_obj.path_pos.start_pos, 12) + assert_eq(path_obj.path_pos.end_pos, 19) + end) + it("127.0.0.1:repo.git/", function() + local actual = giturlparser._make_user("127.0.0.1:repo.git/", 1, true) + -- print(string.format("_make_user_omit-6:%s\n", inspect(actual))) + assert_eq(actual.user, nil) + assert_eq(actual.user_pos, nil) + assert_eq(actual.password, nil) + assert_eq(actual.password_pos, nil) + local host_obj = actual.host_obj + assert_eq(host_obj.host, "127.0.0.1") + assert_eq(host_obj.host_pos.start_pos, 1) + assert_eq(host_obj.host_pos.end_pos, 9) + assert_eq(host_obj.port, nil) + assert_eq(host_obj.port_pos, nil) + local path_obj = host_obj.path_obj + assert_eq(path_obj.org, nil) + assert_eq(path_obj.org_pos, nil) + assert_eq(path_obj.repo, "repo.git") + assert_eq(path_obj.repo_pos.start_pos, 11) + assert_eq(path_obj.repo_pos.end_pos, 18) + assert_eq(path_obj.path, "repo.git/") + assert_eq(path_obj.path_pos.start_pos, 11) + assert_eq(path_obj.path_pos.end_pos, 19) + end) + it("user@github.com:repo.git", function() + local actual = + giturlparser._make_user("user@github.com:repo.git", 1, true) + -- print(string.format("_make_user_omit-7:%s\n", inspect(actual))) + assert_eq(actual.user, "user") + assert_eq(actual.user_pos.start_pos, 1) + assert_eq(actual.user_pos.end_pos, 4) + assert_eq(actual.password, nil) + assert_eq(actual.password_pos, nil) + local host_obj = actual.host_obj + assert_eq(host_obj.host, "github.com") + assert_eq(host_obj.host_pos.start_pos, 6) + assert_eq(host_obj.host_pos.end_pos, 15) + assert_eq(host_obj.port, nil) + assert_eq(host_obj.port_pos, nil) + local path_obj = host_obj.path_obj + assert_eq(path_obj.org, nil) + assert_eq(path_obj.org_pos, nil) + assert_eq(path_obj.repo, "repo.git") + assert_eq(path_obj.repo_pos.start_pos, 17) + assert_eq(path_obj.repo_pos.end_pos, 24) + assert_eq(path_obj.path, "repo.git") + assert_eq(path_obj.path_pos.start_pos, 17) + assert_eq(path_obj.path_pos.end_pos, 24) + end) + it("git:pass@127.0.0.1:repo.git/", function() + local actual = + giturlparser._make_user("git:pass@127.0.0.1:repo.git/", 1, true) + -- print(string.format("_make_user_omit-9:%s\n", inspect(actual))) + assert_eq(actual.user, "git") + assert_eq(actual.user_pos.start_pos, 1) + assert_eq(actual.user_pos.end_pos, 3) + assert_eq(actual.password, "pass") + assert_eq(actual.password_pos.start_pos, 5) + assert_eq(actual.password_pos.end_pos, 8) + local host_obj = actual.host_obj + assert_eq(host_obj.host, "127.0.0.1") + assert_eq(host_obj.host_pos.start_pos, 10) + assert_eq(host_obj.host_pos.end_pos, 18) + assert_eq(host_obj.port, nil) + assert_eq(host_obj.port_pos, nil) + local path_obj = host_obj.path_obj + assert_eq(path_obj.org, nil) + assert_eq(path_obj.org_pos, nil) + assert_eq(path_obj.repo, "repo.git") + assert_eq(path_obj.repo_pos.start_pos, 20) + assert_eq(path_obj.repo_pos.end_pos, 27) + assert_eq(path_obj.path, "repo.git/") + assert_eq(path_obj.path_pos.start_pos, 20) + assert_eq(path_obj.path_pos.end_pos, 28) + end) + end) + + describe("[parse http(s)]", function() it("http://host.xz/path/to/repo.git/", function() local actual = giturlparser.parse("http://host.xz/path/to/repo.git/") assert_eq(type(actual), "table") @@ -26,6 +875,9 @@ describe("giturlparser", function() assert_eq(actual.repo, "repo.git") assert_eq(actual.repo_pos.start_pos, 24) assert_eq(actual.repo_pos.end_pos, 31) + assert_eq(actual.path, "/path/to/repo.git/") + assert_eq(actual.path_pos.start_pos, 15) + assert_eq(actual.path_pos.end_pos, 32) end) it("http://host.xz/path/to/repo.git", function() local actual = giturlparser.parse("http://host.xz/path/to/repo.git") @@ -46,6 +898,9 @@ describe("giturlparser", function() assert_eq(actual.repo, "repo.git") assert_eq(actual.repo_pos.start_pos, 24) assert_eq(actual.repo_pos.end_pos, 31) + assert_eq(actual.path, "/path/to/repo.git") + assert_eq(actual.path_pos.start_pos, 15) + assert_eq(actual.path_pos.end_pos, 31) end) it("https://host.xz/path/to/repo.git/", function() local actual = giturlparser.parse("https://host.xz/path/to/repo.git/") @@ -167,6 +1022,581 @@ describe("giturlparser", function() assert_eq(actual.repo, "samba.git") assert_eq(actual.repo_pos.start_pos, 41) assert_eq(actual.repo_pos.end_pos, 49) + assert_eq(actual.path, "/samba.git") + assert_eq(actual.path_pos.start_pos, 40) + assert_eq(actual.path_pos.end_pos, 49) + end) + end) + describe("[parse ssh]", function() + it("ssh://user@host.xz/repo.git", function() + local actual = giturlparser.parse("ssh://user@host.xz/repo.git") + assert_eq(type(actual), "table") + assert_eq(actual.protocol, "ssh") + assert_eq(actual.protocol_pos.start_pos, 1) + assert_eq(actual.protocol_pos.end_pos, 3) + assert_eq(actual.user, "user") + assert_eq(actual.user_pos.start_pos, 7) + assert_eq(actual.user_pos.end_pos, 10) + assert_eq(actual.password, nil) + assert_eq(actual.password_pos, nil) + assert_eq(actual.host, "host.xz") + assert_eq(actual.host_pos.start_pos, 12) + assert_eq(actual.host_pos.end_pos, 18) + assert_eq(actual.org, nil) + assert_eq(actual.org_pos, nil) + assert_eq(actual.repo, "repo.git") + assert_eq(actual.repo_pos.start_pos, 20) + assert_eq(actual.repo_pos.end_pos, 27) + assert_eq(actual.path, "/repo.git") + assert_eq(actual.path_pos.start_pos, 19) + assert_eq(actual.path_pos.end_pos, 27) + end) + it("ssh://git@github.com/linrongbin16/giturlparser.lua.git", function() + local actual = giturlparser.parse( + "ssh://git@github.com/linrongbin16/giturlparser.lua.git" + ) + assert_eq(type(actual), "table") + assert_eq(actual.protocol, "ssh") + assert_eq(actual.protocol_pos.start_pos, 1) + assert_eq(actual.protocol_pos.end_pos, 3) + assert_eq(actual.user, "git") + assert_eq(actual.user_pos.start_pos, 7) + assert_eq(actual.user_pos.end_pos, 9) + assert_eq(actual.password, nil) + assert_eq(actual.password_pos, nil) + assert_eq(actual.host, "github.com") + assert_eq(actual.host_pos.start_pos, 11) + assert_eq(actual.host_pos.end_pos, 20) + assert_eq(actual.org, "linrongbin16") + assert_eq(actual.org_pos.start_pos, 22) + assert_eq(actual.org_pos.end_pos, 33) + assert_eq(actual.repo, "giturlparser.lua.git") + assert_eq(actual.repo_pos.start_pos, 35) + assert_eq(actual.repo_pos.end_pos, 54) + assert_eq(actual.path, "/linrongbin16/giturlparser.lua.git") + assert_eq(actual.path_pos.start_pos, 21) + assert_eq(actual.path_pos.end_pos, 54) + end) + end) + describe("[parse ssh omit]", function() + it("git:pass@host.xz:repo.git", function() + local actual = giturlparser.parse("git:pass@host.xz:repo.git") + assert_eq(type(actual), "table") + assert_eq(actual.protocol, nil) + assert_eq(actual.protocol_pos, nil) + assert_eq(actual.user, "git") + assert_eq(actual.user_pos.start_pos, 1) + assert_eq(actual.user_pos.end_pos, 3) + assert_eq(actual.password, "pass") + assert_eq(actual.password_pos.start_pos, 5) + assert_eq(actual.password_pos.end_pos, 8) + assert_eq(actual.host, "host.xz") + assert_eq(actual.host_pos.start_pos, 10) + assert_eq(actual.host_pos.end_pos, 16) + assert_eq(actual.org, nil) + assert_eq(actual.org_pos, nil) + assert_eq(actual.repo, "repo.git") + assert_eq(actual.repo_pos.start_pos, 18) + assert_eq(actual.repo_pos.end_pos, 25) + assert_eq(actual.path, "repo.git") + assert_eq(actual.path_pos.start_pos, 18) + assert_eq(actual.path_pos.end_pos, 25) + end) + it("git@github.com:linrongbin16/giturlparser.lua.git", function() + local actual = + giturlparser.parse("git@github.com:linrongbin16/giturlparser.lua.git") + assert_eq(type(actual), "table") + assert_eq(actual.protocol, nil) + assert_eq(actual.protocol_pos, nil) + assert_eq(actual.user, "git") + assert_eq(actual.user_pos.start_pos, 1) + assert_eq(actual.user_pos.end_pos, 3) + assert_eq(actual.password, nil) + assert_eq(actual.password_pos, nil) + assert_eq(actual.host, "github.com") + assert_eq(actual.host_pos.start_pos, 5) + assert_eq(actual.host_pos.end_pos, 14) + assert_eq(actual.org, "linrongbin16") + assert_eq(actual.org_pos.start_pos, 16) + assert_eq(actual.org_pos.end_pos, 27) + assert_eq(actual.repo, "giturlparser.lua.git") + assert_eq(actual.repo_pos.start_pos, 29) + assert_eq(actual.repo_pos.end_pos, 48) + assert_eq(actual.path, "linrongbin16/giturlparser.lua.git") + assert_eq(actual.path_pos.start_pos, 16) + assert_eq(actual.path_pos.end_pos, 48) + end) + end) + describe("[parse git]", function() + it("git://user@host.xz/repo.git", function() + local actual = giturlparser.parse("git://user@host.xz/repo.git") + assert_eq(type(actual), "table") + assert_eq(actual.protocol, "git") + assert_eq(actual.protocol_pos.start_pos, 1) + assert_eq(actual.protocol_pos.end_pos, 3) + assert_eq(actual.user, "user") + assert_eq(actual.user_pos.start_pos, 7) + assert_eq(actual.user_pos.end_pos, 10) + assert_eq(actual.password, nil) + assert_eq(actual.password_pos, nil) + assert_eq(actual.host, "host.xz") + assert_eq(actual.host_pos.start_pos, 12) + assert_eq(actual.host_pos.end_pos, 18) + assert_eq(actual.org, nil) + assert_eq(actual.org_pos, nil) + assert_eq(actual.repo, "repo.git") + assert_eq(actual.repo_pos.start_pos, 20) + assert_eq(actual.repo_pos.end_pos, 27) + assert_eq(actual.path, "/repo.git") + assert_eq(actual.path_pos.start_pos, 19) + assert_eq(actual.path_pos.end_pos, 27) + end) + it("git://git@github.com/linrongbin16/giturlparser.lua.git", function() + local actual = giturlparser.parse( + "git://git@github.com/linrongbin16/giturlparser.lua.git" + ) + assert_eq(type(actual), "table") + assert_eq(actual.protocol, "git") + assert_eq(actual.protocol_pos.start_pos, 1) + assert_eq(actual.protocol_pos.end_pos, 3) + assert_eq(actual.user, "git") + assert_eq(actual.user_pos.start_pos, 7) + assert_eq(actual.user_pos.end_pos, 9) + assert_eq(actual.password, nil) + assert_eq(actual.password_pos, nil) + assert_eq(actual.host, "github.com") + assert_eq(actual.host_pos.start_pos, 11) + assert_eq(actual.host_pos.end_pos, 20) + assert_eq(actual.org, "linrongbin16") + assert_eq(actual.org_pos.start_pos, 22) + assert_eq(actual.org_pos.end_pos, 33) + assert_eq(actual.repo, "giturlparser.lua.git") + assert_eq(actual.repo_pos.start_pos, 35) + assert_eq(actual.repo_pos.end_pos, 54) + assert_eq(actual.path, "/linrongbin16/giturlparser.lua.git") + assert_eq(actual.path_pos.start_pos, 21) + assert_eq(actual.path_pos.end_pos, 54) + end) + it("git://host.xz/repo.git", function() + local actual = giturlparser.parse("git://host.xz/repo.git") + assert_eq(type(actual), "table") + assert_eq(actual.protocol, "git") + assert_eq(actual.protocol_pos.start_pos, 1) + assert_eq(actual.protocol_pos.end_pos, 3) + assert_eq(actual.user, nil) + assert_eq(actual.user_pos, nil) + assert_eq(actual.password, nil) + assert_eq(actual.password_pos, nil) + assert_eq(actual.host, "host.xz") + assert_eq(actual.host_pos.start_pos, 7) + assert_eq(actual.host_pos.end_pos, 13) + assert_eq(actual.org, nil) + assert_eq(actual.org_pos, nil) + assert_eq(actual.repo, "repo.git") + assert_eq(actual.repo_pos.start_pos, 15) + assert_eq(actual.repo_pos.end_pos, 22) + assert_eq(actual.path, "/repo.git") + assert_eq(actual.path_pos.start_pos, 14) + assert_eq(actual.path_pos.end_pos, 22) + end) + it("git://github.com/linrongbin16/giturlparser.lua.git", function() + local actual = + giturlparser.parse("git://github.com/linrongbin16/giturlparser.lua.git") + assert_eq(type(actual), "table") + assert_eq(actual.protocol, "git") + assert_eq(actual.protocol_pos.start_pos, 1) + assert_eq(actual.protocol_pos.end_pos, 3) + assert_eq(actual.user, nil) + assert_eq(actual.user_pos, nil) + assert_eq(actual.password, nil) + assert_eq(actual.password_pos, nil) + assert_eq(actual.host, "github.com") + assert_eq(actual.host_pos.start_pos, 7) + assert_eq(actual.host_pos.end_pos, 16) + assert_eq(actual.org, "linrongbin16") + assert_eq(actual.org_pos.start_pos, 18) + assert_eq(actual.org_pos.end_pos, 29) + assert_eq(actual.repo, "giturlparser.lua.git") + assert_eq(actual.repo_pos.start_pos, 31) + assert_eq(actual.repo_pos.end_pos, 50) + assert_eq(actual.path, "/linrongbin16/giturlparser.lua.git") + assert_eq(actual.path_pos.start_pos, 17) + assert_eq(actual.path_pos.end_pos, 50) + end) + end) + describe("[parse file remote]", function() + it("file://user@host.xz/repo.git", function() + local actual = giturlparser.parse("file://user@host.xz/repo.git") + assert_eq(type(actual), "table") + assert_eq(actual.protocol, "file") + assert_eq(actual.protocol_pos.start_pos, 1) + assert_eq(actual.protocol_pos.end_pos, 4) + assert_eq(actual.user, "user") + assert_eq(actual.user_pos.start_pos, 8) + assert_eq(actual.user_pos.end_pos, 11) + assert_eq(actual.password, nil) + assert_eq(actual.password_pos, nil) + assert_eq(actual.host, "host.xz") + assert_eq(actual.host_pos.start_pos, 13) + assert_eq(actual.host_pos.end_pos, 19) + assert_eq(actual.org, nil) + assert_eq(actual.org_pos, nil) + assert_eq(actual.repo, "repo.git") + assert_eq(actual.repo_pos.start_pos, 21) + assert_eq(actual.repo_pos.end_pos, 28) + assert_eq(actual.path, "/repo.git") + assert_eq(actual.path_pos.start_pos, 20) + assert_eq(actual.path_pos.end_pos, 28) + end) + it("file://git@github.com/linrongbin16/giturlparser.lua.git", function() + local actual = giturlparser.parse( + "file://git@github.com/linrongbin16/giturlparser.lua.git" + ) + assert_eq(type(actual), "table") + assert_eq(actual.protocol, "file") + assert_eq(actual.protocol_pos.start_pos, 1) + assert_eq(actual.protocol_pos.end_pos, 4) + assert_eq(actual.user, "git") + assert_eq(actual.user_pos.start_pos, 8) + assert_eq(actual.user_pos.end_pos, 10) + assert_eq(actual.password, nil) + assert_eq(actual.password_pos, nil) + assert_eq(actual.host, "github.com") + assert_eq(actual.host_pos.start_pos, 12) + assert_eq(actual.host_pos.end_pos, 21) + assert_eq(actual.org, "linrongbin16") + assert_eq(actual.org_pos.start_pos, 23) + assert_eq(actual.org_pos.end_pos, 34) + assert_eq(actual.repo, "giturlparser.lua.git") + assert_eq(actual.repo_pos.start_pos, 36) + assert_eq(actual.repo_pos.end_pos, 55) + assert_eq(actual.path, "/linrongbin16/giturlparser.lua.git") + assert_eq(actual.path_pos.start_pos, 22) + assert_eq(actual.path_pos.end_pos, 55) + end) + it("file://host.xz/repo.git", function() + local actual = giturlparser.parse("file://host.xz/repo.git") + assert_eq(type(actual), "table") + assert_eq(actual.protocol, "file") + assert_eq(actual.protocol_pos.start_pos, 1) + assert_eq(actual.protocol_pos.end_pos, 4) + assert_eq(actual.user, nil) + assert_eq(actual.user_pos, nil) + assert_eq(actual.password, nil) + assert_eq(actual.password_pos, nil) + assert_eq(actual.host, "host.xz") + assert_eq(actual.host_pos.start_pos, 8) + assert_eq(actual.host_pos.end_pos, 14) + assert_eq(actual.org, nil) + assert_eq(actual.org_pos, nil) + assert_eq(actual.repo, "repo.git") + assert_eq(actual.repo_pos.start_pos, 16) + assert_eq(actual.repo_pos.end_pos, 23) + assert_eq(actual.path, "/repo.git") + assert_eq(actual.path_pos.start_pos, 15) + assert_eq(actual.path_pos.end_pos, 23) + end) + it("file://github.com/linrongbin16/giturlparser.lua.git", function() + local actual = giturlparser.parse( + "file://github.com/linrongbin16/giturlparser.lua.git" + ) + assert_eq(type(actual), "table") + assert_eq(actual.protocol, "file") + assert_eq(actual.protocol_pos.start_pos, 1) + assert_eq(actual.protocol_pos.end_pos, 4) + assert_eq(actual.user, nil) + assert_eq(actual.user_pos, nil) + assert_eq(actual.password, nil) + assert_eq(actual.password_pos, nil) + assert_eq(actual.host, "github.com") + assert_eq(actual.host_pos.start_pos, 8) + assert_eq(actual.host_pos.end_pos, 17) + assert_eq(actual.org, "linrongbin16") + assert_eq(actual.org_pos.start_pos, 19) + assert_eq(actual.org_pos.end_pos, 30) + assert_eq(actual.repo, "giturlparser.lua.git") + assert_eq(actual.repo_pos.start_pos, 32) + assert_eq(actual.repo_pos.end_pos, 51) + assert_eq(actual.path, "/linrongbin16/giturlparser.lua.git") + assert_eq(actual.path_pos.start_pos, 18) + assert_eq(actual.path_pos.end_pos, 51) + end) + end) + describe("[parse file local]", function() + it("file:///path/to/repo.git", function() + local actual = giturlparser.parse("file:///path/to/repo.git") + assert_eq(type(actual), "table") + assert_eq(actual.protocol, "file") + assert_eq(actual.protocol_pos.start_pos, 1) + assert_eq(actual.protocol_pos.end_pos, 4) + assert_eq(actual.user, nil) + assert_eq(actual.user_pos, nil) + assert_eq(actual.password, nil) + assert_eq(actual.password_pos, nil) + assert_eq(actual.host, nil) + assert_eq(actual.host_pos, nil) + assert_eq(actual.port, nil) + assert_eq(actual.port_pos, nil) + assert_eq(actual.org, "path/to") + assert_eq(actual.org_pos.start_pos, 9) + assert_eq(actual.org_pos.end_pos, 15) + assert_eq(actual.repo, "repo.git") + assert_eq(actual.repo_pos.start_pos, 17) + assert_eq(actual.repo_pos.end_pos, 24) + assert_eq(actual.path, "/path/to/repo.git") + assert_eq(actual.path_pos.start_pos, 8) + assert_eq(actual.path_pos.end_pos, 24) + end) + it("file:///repo.git", function() + local actual = giturlparser.parse("file:///repo.git") + assert_eq(type(actual), "table") + assert_eq(actual.protocol, "file") + assert_eq(actual.protocol_pos.start_pos, 1) + assert_eq(actual.protocol_pos.end_pos, 4) + assert_eq(actual.user, nil) + assert_eq(actual.user_pos, nil) + assert_eq(actual.password, nil) + assert_eq(actual.password_pos, nil) + assert_eq(actual.host, nil) + assert_eq(actual.host_pos, nil) + assert_eq(actual.port, nil) + assert_eq(actual.port_pos, nil) + assert_eq(actual.org, nil) + assert_eq(actual.org_pos, nil) + assert_eq(actual.repo, "repo.git") + assert_eq(actual.repo_pos.start_pos, 9) + assert_eq(actual.repo_pos.end_pos, 16) + assert_eq(actual.path, "/repo.git") + assert_eq(actual.path_pos.start_pos, 8) + assert_eq(actual.path_pos.end_pos, 16) + end) + end) + describe("[parse local path]", function() + it("repo.git", function() + local actual = giturlparser.parse("repo.git") + assert_eq(type(actual), "table") + assert_eq(actual.protocol, nil) + assert_eq(actual.protocol_pos, nil) + assert_eq(actual.user, nil) + assert_eq(actual.user_pos, nil) + assert_eq(actual.password, nil) + assert_eq(actual.password_pos, nil) + assert_eq(actual.host, nil) + assert_eq(actual.host_pos, nil) + assert_eq(actual.port, nil) + assert_eq(actual.port_pos, nil) + assert_eq(actual.org, nil) + assert_eq(actual.org_pos, nil) + assert_eq(actual.repo, "repo.git") + assert_eq(actual.repo_pos.start_pos, 1) + assert_eq(actual.repo_pos.end_pos, 8) + assert_eq(actual.path, "repo.git") + assert_eq(actual.path_pos.start_pos, 1) + assert_eq(actual.path_pos.end_pos, 8) + end) + it("repo.git/", function() + local actual = giturlparser.parse("repo.git/") + assert_eq(type(actual), "table") + assert_eq(actual.protocol, nil) + assert_eq(actual.protocol_pos, nil) + assert_eq(actual.user, nil) + assert_eq(actual.user_pos, nil) + assert_eq(actual.password, nil) + assert_eq(actual.password_pos, nil) + assert_eq(actual.host, nil) + assert_eq(actual.host_pos, nil) + assert_eq(actual.port, nil) + assert_eq(actual.port_pos, nil) + assert_eq(actual.org, nil) + assert_eq(actual.org_pos, nil) + assert_eq(actual.repo, "repo.git") + assert_eq(actual.repo_pos.start_pos, 1) + assert_eq(actual.repo_pos.end_pos, 8) + assert_eq(actual.path, "repo.git/") + assert_eq(actual.path_pos.start_pos, 1) + assert_eq(actual.path_pos.end_pos, 9) + end) + it("/repo.git", function() + local actual = giturlparser.parse("/repo.git") + assert_eq(type(actual), "table") + assert_eq(actual.protocol, nil) + assert_eq(actual.protocol_pos, nil) + assert_eq(actual.user, nil) + assert_eq(actual.user_pos, nil) + assert_eq(actual.password, nil) + assert_eq(actual.password_pos, nil) + assert_eq(actual.host, nil) + assert_eq(actual.host_pos, nil) + assert_eq(actual.port, nil) + assert_eq(actual.port_pos, nil) + assert_eq(actual.org, nil) + assert_eq(actual.org_pos, nil) + assert_eq(actual.repo, "repo.git") + assert_eq(actual.repo_pos.start_pos, 2) + assert_eq(actual.repo_pos.end_pos, 9) + assert_eq(actual.path, "/repo.git") + assert_eq(actual.path_pos.start_pos, 1) + assert_eq(actual.path_pos.end_pos, 9) + end) + it("/repo.git/", function() + local actual = giturlparser.parse("/repo.git/") + assert_eq(type(actual), "table") + assert_eq(actual.protocol, nil) + assert_eq(actual.protocol_pos, nil) + assert_eq(actual.user, nil) + assert_eq(actual.user_pos, nil) + assert_eq(actual.password, nil) + assert_eq(actual.password_pos, nil) + assert_eq(actual.host, nil) + assert_eq(actual.host_pos, nil) + assert_eq(actual.port, nil) + assert_eq(actual.port_pos, nil) + assert_eq(actual.org, nil) + assert_eq(actual.org_pos, nil) + assert_eq(actual.repo, "repo.git") + assert_eq(actual.repo_pos.start_pos, 2) + assert_eq(actual.repo_pos.end_pos, 9) + assert_eq(actual.path, "/repo.git/") + assert_eq(actual.path_pos.start_pos, 1) + assert_eq(actual.path_pos.end_pos, 10) + end) + it("./repo.git", function() + local actual = giturlparser.parse("./repo.git") + assert_eq(type(actual), "table") + assert_eq(actual.protocol, nil) + assert_eq(actual.protocol_pos, nil) + assert_eq(actual.user, nil) + assert_eq(actual.user_pos, nil) + assert_eq(actual.password, nil) + assert_eq(actual.password_pos, nil) + assert_eq(actual.host, nil) + assert_eq(actual.host_pos, nil) + assert_eq(actual.port, nil) + assert_eq(actual.port_pos, nil) + assert_eq(actual.org, ".") + assert_eq(actual.org_pos.start_pos, 1) + assert_eq(actual.org_pos.end_pos, 1) + assert_eq(actual.repo, "repo.git") + assert_eq(actual.repo_pos.start_pos, 3) + assert_eq(actual.repo_pos.end_pos, 10) + assert_eq(actual.path, "./repo.git") + assert_eq(actual.path_pos.start_pos, 1) + assert_eq(actual.path_pos.end_pos, 10) + end) + it("../repo.git/", function() + local actual = giturlparser.parse("../repo.git/") + assert_eq(type(actual), "table") + assert_eq(actual.protocol, nil) + assert_eq(actual.protocol_pos, nil) + assert_eq(actual.user, nil) + assert_eq(actual.user_pos, nil) + assert_eq(actual.password, nil) + assert_eq(actual.password_pos, nil) + assert_eq(actual.host, nil) + assert_eq(actual.host_pos, nil) + assert_eq(actual.port, nil) + assert_eq(actual.port_pos, nil) + assert_eq(actual.org, "..") + assert_eq(actual.org_pos.start_pos, 1) + assert_eq(actual.org_pos.end_pos, 2) + assert_eq(actual.repo, "repo.git") + assert_eq(actual.repo_pos.start_pos, 4) + assert_eq(actual.repo_pos.end_pos, 11) + assert_eq(actual.path, "../repo.git/") + assert_eq(actual.path_pos.start_pos, 1) + assert_eq(actual.path_pos.end_pos, 12) + end) + it("~/path/to/repo.git", function() + local actual = giturlparser.parse("~/path/to/repo.git") + assert_eq(type(actual), "table") + assert_eq(actual.protocol, nil) + assert_eq(actual.protocol_pos, nil) + assert_eq(actual.user, nil) + assert_eq(actual.user_pos, nil) + assert_eq(actual.password, nil) + assert_eq(actual.password_pos, nil) + assert_eq(actual.host, nil) + assert_eq(actual.host_pos, nil) + assert_eq(actual.port, nil) + assert_eq(actual.port_pos, nil) + assert_eq(actual.org, "~/path/to") + assert_eq(actual.org_pos.start_pos, 1) + assert_eq(actual.org_pos.end_pos, 9) + assert_eq(actual.repo, "repo.git") + assert_eq(actual.repo_pos.start_pos, 11) + assert_eq(actual.repo_pos.end_pos, 18) + assert_eq(actual.path, "~/path/to/repo.git") + assert_eq(actual.path_pos.start_pos, 1) + assert_eq(actual.path_pos.end_pos, 18) + end) + it("~/path/to/repo.git/", function() + local actual = giturlparser.parse("~/path/to/repo.git/") + assert_eq(type(actual), "table") + assert_eq(actual.protocol, nil) + assert_eq(actual.protocol_pos, nil) + assert_eq(actual.user, nil) + assert_eq(actual.user_pos, nil) + assert_eq(actual.password, nil) + assert_eq(actual.password_pos, nil) + assert_eq(actual.host, nil) + assert_eq(actual.host_pos, nil) + assert_eq(actual.port, nil) + assert_eq(actual.port_pos, nil) + assert_eq(actual.org, "~/path/to") + assert_eq(actual.org_pos.start_pos, 1) + assert_eq(actual.org_pos.end_pos, 9) + assert_eq(actual.repo, "repo.git") + assert_eq(actual.repo_pos.start_pos, 11) + assert_eq(actual.repo_pos.end_pos, 18) + assert_eq(actual.path, "~/path/to/repo.git/") + assert_eq(actual.path_pos.start_pos, 1) + assert_eq(actual.path_pos.end_pos, 19) + end) + it("/absolute/path/to/repo.git", function() + local actual = giturlparser.parse("/absolute/path/to/repo.git") + assert_eq(type(actual), "table") + assert_eq(actual.protocol, nil) + assert_eq(actual.protocol_pos, nil) + assert_eq(actual.user, nil) + assert_eq(actual.user_pos, nil) + assert_eq(actual.password, nil) + assert_eq(actual.password_pos, nil) + assert_eq(actual.host, nil) + assert_eq(actual.host_pos, nil) + assert_eq(actual.port, nil) + assert_eq(actual.port_pos, nil) + assert_eq(actual.org, "absolute/path/to") + assert_eq(actual.org_pos.start_pos, 2) + assert_eq(actual.org_pos.end_pos, 17) + assert_eq(actual.repo, "repo.git") + assert_eq(actual.repo_pos.start_pos, 19) + assert_eq(actual.repo_pos.end_pos, 26) + assert_eq(actual.path, "/absolute/path/to/repo.git") + assert_eq(actual.path_pos.start_pos, 1) + assert_eq(actual.path_pos.end_pos, 26) + end) + it("/absolute/path/to/repo.git/", function() + local actual = giturlparser.parse("/absolute/path/to/repo.git/") + assert_eq(type(actual), "table") + assert_eq(actual.protocol, nil) + assert_eq(actual.protocol_pos, nil) + assert_eq(actual.user, nil) + assert_eq(actual.user_pos, nil) + assert_eq(actual.password, nil) + assert_eq(actual.password_pos, nil) + assert_eq(actual.host, nil) + assert_eq(actual.host_pos, nil) + assert_eq(actual.port, nil) + assert_eq(actual.port_pos, nil) + assert_eq(actual.org, "absolute/path/to") + assert_eq(actual.org_pos.start_pos, 2) + assert_eq(actual.org_pos.end_pos, 17) + assert_eq(actual.repo, "repo.git") + assert_eq(actual.repo_pos.start_pos, 19) + assert_eq(actual.repo_pos.end_pos, 26) + assert_eq(actual.path, "/absolute/path/to/repo.git/") + assert_eq(actual.path_pos.start_pos, 1) + assert_eq(actual.path_pos.end_pos, 27) end) end) end) diff --git a/src/giturlparser.lua b/src/giturlparser.lua index 3d0e6e6..639dd81 100644 --- a/src/giturlparser.lua +++ b/src/giturlparser.lua @@ -106,9 +106,8 @@ end -- 'path' is all payload after 'host', e.g. 'org/repo'. -- --- @alias giturlparser.GitUrlPos {start_pos:integer?,end_pos:integer?} ---- @alias giturlparser.GitUrlInfo {protocol:string?,protocol_pos:giturlparser.GitUrlPos?,user:string?,user_pos:giturlparser.GitUrlPos?,password:string?,password_pos:giturlparser.GitUrlPos?,host:string?,host_pos:giturlparser.GitUrlPos?,org:string?,org_pos:giturlparser.GitUrlPos?,repo:string,repo_pos:giturlparser.GitUrlPos,path:string,path_pos:giturlparser.GitUrlPos} -local GitUrlInfo = {} - +--- @alias giturlparser.GitUrlInfo {protocol:string?,protocol_pos:giturlparser.GitUrlPos?,user:string?,user_pos:giturlparser.GitUrlPos?,password:string?,password_pos:giturlparser.GitUrlPos?,host:string?,host_pos:giturlparser.GitUrlPos?,port:string?,port_pos:giturlparser.GitUrlPos?,org:string?,org_pos:giturlparser.GitUrlPos?,repo:string?,repo_pos:giturlparser.GitUrlPos?,path:string?,path_pos:giturlparser.GitUrlPos?} +-- --- @param url string --- @param start_pos integer --- @param end_pos integer @@ -123,341 +122,363 @@ M._make = function(url, start_pos, end_pos) return component, pos end ---- @param url string ---- @return giturlparser.GitUrlInfo?, string? -M.parse = function(url) - if type(url) ~= "string" or string.len(url) == 0 then - return nil, "empty string" +--- @param val string +--- @param pos giturlparser.GitUrlPos +--- @return string, giturlparser.GitUrlPos +M._trim_slash = function(val, pos) + assert(type(val) == "string") + if val and M._startswith(val, "/") then + val = string.sub(val, 2) + pos.start_pos = pos.start_pos + 1 end - - if M._endswith(url, "/") then - url = string.sub(url, 1, #url - 1) + if val and M._endswith(val, "/") then + val = string.sub(val, 1, string.len(val) - 1) + pos.end_pos = pos.end_pos - 1 end - local protocol = nil - local protocol_pos = nil - local user = nil - local user_pos = nil - local password = nil - local password_pos = nil - local host = nil - local host_pos = nil + return val, pos +end + +--- @alias giturlparser._GitUrlPath {org:string?,org_pos:giturlparser.GitUrlPos?,repo:string?,repo_pos:giturlparser.GitUrlPos?,path:string?,path_pos:giturlparser.GitUrlPos?} +-- +--- @param p string +--- @param start integer +--- @return giturlparser._GitUrlPath +M._make_path = function(p, start) + assert(type(start) == "number") + + -- local inspect = require("inspect") + + local endswith_slash = M._endswith(p, "/") + local org = nil local org_pos = nil local repo = nil local repo_pos = nil local path = nil local path_pos = nil + local plen = string.len(p) - local protocol_delimiter_pos = M._find(url, "://") + local last_slash_pos = M._rfind(p, "/", endswith_slash and plen - 1 or plen) if - type(protocol_delimiter_pos) == "number" and protocol_delimiter_pos > 1 + type(last_slash_pos) == "number" + and last_slash_pos > start + and last_slash_pos < plen then - -- https, ssh, file, sftp, etc - protocol, protocol_pos = M._make(url, 1, protocol_delimiter_pos - 1) - local first_colon_pos = M._find(url, ":", protocol_delimiter_pos + 3) + org, org_pos = M._make(p, start, last_slash_pos - 1) + repo, repo_pos = M._make(p, last_slash_pos, plen) + else + -- no slash found, only 1 path component + repo, repo_pos = M._make(p, start, plen) + end + + -- print( + -- string.format( + -- "|_make_path| p:%s, start:%s, plen:%s\n", + -- inspect(p), + -- inspect(start), + -- inspect(plen) + -- ) + -- ) + path, path_pos = M._make(p, start, plen) + + if repo and repo_pos then + repo, repo_pos = M._trim_slash(repo, repo_pos) + end + if org and org_pos then + org, org_pos = M._trim_slash(org, org_pos) + end + + return { + org = org, + org_pos = org_pos, + repo = repo, + repo_pos = repo_pos, + path = path, + path_pos = path_pos, + } +end + +-- without omitted ssh protocol, host (and port end with ':') end with '/' +-- +--- @alias giturlparser._GitUrlHost {host:string?,host_pos:giturlparser.GitUrlPos?,port:string?,port_pos:giturlparser.GitUrlPos?,path_obj:giturlparser._GitUrlPath} +-- +--- @param p string +--- @param start integer +--- @return giturlparser._GitUrlHost +M._make_host = function(p, start) + assert(type(start) == "number") + assert(not M._startswith(p, "/")) + + local host = nil + local host_pos = nil + local port = nil + local port_pos = nil + --- @type giturlparser._GitUrlPath + local path_obj = {} + + local plen = string.len(p) + + -- find ':', the end position of host, start position of port + local first_colon_pos = M._find(p, ":", start) + if type(first_colon_pos) == "number" and first_colon_pos > start then + -- host end with ':', port start with ':' + host, host_pos = M._make(p, start, first_colon_pos - 1) + + -- find first slash '/' (after second ':'), the end position of port, start position of path + local first_slash_pos = M._find(p, "/", first_colon_pos + 1) if - type(first_colon_pos) == "number" - and first_colon_pos > protocol_delimiter_pos + 3 + type(first_slash_pos) == "number" + and first_slash_pos > first_colon_pos + 1 then - -- host end with ':', or user end with ':' - local first_at_pos = M._find(url, "@", first_colon_pos + 1) - if - type(first_at_pos) == "number" and first_at_pos > first_colon_pos + 1 - then - -- ssh password end pos - local second_colon_pos = M._find(url, ":", first_at_pos + 1) - if - type(second_colon_pos) == "number" - and second_colon_pos > first_at_pos + 1 - then - -- host end with ':' - host, host_pos = M._make(url, first_at_pos + 1, second_colon_pos - 1) - password, password_pos = - M._make(url, first_colon_pos + 1, first_at_pos - 1) - user, user_pos = - M._make(url, protocol_delimiter_pos + 3, first_colon_pos - 1) - - local last_slash_pos = M._rfind(url, "/") - if - type(last_slash_pos) == "number" - and last_slash_pos > second_colon_pos + 1 - then - repo, repo_pos = M._make(url, last_slash_pos + 1, string.len(url)) - org, org_pos = - M._make(url, second_colon_pos + 1, last_slash_pos - 1) - path, path_pos = M._make(url, second_colon_pos + 1, string.len(url)) - else - repo, repo_pos = M._make(url, second_colon_pos + 1, string.len(url)) - path, path_pos = M._make(url, second_colon_pos + 1, string.len(url)) - -- missing org, org_pos - end - else - local first_slash_pos = M._find(url, "/", first_at_pos + 1) - if - type(first_slash_pos) == "number" - and first_slash_pos > first_at_pos + 1 - then - -- host end with '/' - host, host_pos = M._make(url, first_at_pos + 1, first_slash_pos - 1) - password, password_pos = - M._make(url, first_colon_pos + 1, first_at_pos - 1) - user, user_pos = - M._make(url, protocol_delimiter_pos + 3, first_colon_pos - 1) - - local last_slash_pos = M._rfind(url, "/") - if - type(last_slash_pos) == "number" - and last_slash_pos > first_slash_pos + 1 - then - repo, repo_pos = M._make(url, last_slash_pos + 1, string.len(url)) - org, org_pos = - M._make(url, first_slash_pos + 1, last_slash_pos - 1) - path, path_pos = - M._make(url, first_slash_pos + 1, string.len(url)) - else - repo, repo_pos = - M._make(url, first_slash_pos + 1, string.len(url)) - path, path_pos = - M._make(url, first_slash_pos + 1, string.len(url)) - -- missing org, org_pos - end - else - return nil, "invalid url" - end - end - else - -- host end with ':' - host, host_pos = - M._make(url, protocol_delimiter_pos + 3, first_colon_pos - 1) - -- missing user, password - - local last_slash_pos = M._rfind(url, "/") - if - type(last_slash_pos) == "number" - and last_slash_pos > first_colon_pos + 1 - then - repo, repo_pos = M._make(url, last_slash_pos + 1, string.len(url)) - org, org_pos = M._make(url, first_colon_pos + 1, last_slash_pos - 1) - path, path_pos = M._make(url, first_colon_pos + 1, string.len(url)) - else - repo, repo_pos = M._make(url, first_colon_pos + 1, string.len(url)) - path, path_pos = M._make(url, first_colon_pos + 1, string.len(url)) - -- missing org, org_pos - end - end + -- port end with '/' + port, port_pos = M._make(p, first_colon_pos + 1, first_slash_pos - 1) + path_obj = M._make_path(p, first_slash_pos) else - local first_slash_pos = M._find(url, "/", protocol_delimiter_pos + 3) - if - type(first_slash_pos) == "number" - and first_slash_pos > protocol_delimiter_pos + 3 - then - -- host end with '/' - host, host_pos = - M._make(url, protocol_delimiter_pos + 3, first_slash_pos - 1) - local last_slash_pos = M._rfind(url, "/") - if - type(last_slash_pos) == "number" - and last_slash_pos > first_slash_pos + 1 - then - repo, repo_pos = M._make(url, last_slash_pos + 1, string.len(url)) - org, org_pos = M._make(url, first_slash_pos + 1, last_slash_pos - 1) - path, path_pos = M._make(url, first_slash_pos + 1, string.len(url)) - else - repo, repo_pos = M._make(url, first_slash_pos + 1, string.len(url)) - path, path_pos = M._make(url, first_slash_pos + 1, string.len(url)) - -- missing org - end - else - return nil, "invalid url" - end + -- path not found, port end until url end + port, port_pos = M._make(p, first_colon_pos + 1, plen) end else - -- missing protocol, either ssh/local file path - local first_at_pos = M._find(url, "@") - if type(first_at_pos) == "number" and first_at_pos > 1 then - local first_colon_pos = M._find(url, ":") - if - type(first_colon_pos) == "number" - and first_colon_pos > 1 - and first_colon_pos < first_at_pos - then - -- user end with ':', password end with '@' - user, user_pos = M._make(url, 1, first_colon_pos - 1) - password, password_pos = - M._make(url, first_colon_pos + 1, first_at_pos - 1) - - local second_colon_pos = M._find(url, ":", first_at_pos + 1) - if - type(second_colon_pos) == "number" - and second_colon_pos > first_at_pos + 1 - then - -- host end with ':' - host, host_pos = M._make(url, first_at_pos + 1, second_colon_pos - 1) - - local last_slash_pos = M._rfind(url, "/") - if - type(last_slash_pos) == "number" - and last_slash_pos > second_colon_pos + 1 - then - repo, repo_pos = M._make(url, last_slash_pos + 1, string.len(url)) - org, org_pos = - M._make(url, second_colon_pos + 1, last_slash_pos - 1) - path, path_pos = M._make(url, second_colon_pos + 1, string.len(url)) - else - repo, repo_pos = M._make(url, second_colon_pos + 1, string.len(url)) - path, path_pos = M._make(url, second_colon_pos + 1, string.len(url)) - -- missing org - end - else - local first_slash_pos = M._find(url, "/", first_at_pos + 1) - if - type(first_slash_pos) == "number" - and first_slash_pos > first_at_pos + 1 - then - -- host end with '/' - host, host_pos = M._make(url, first_at_pos + 1, first_slash_pos - 1) - - local last_slash_pos = M._rfind(url, "/") - if - type(last_slash_pos) == "number" - and last_slash_pos > first_slash_pos + 1 - then - repo, repo_pos = M._make(url, last_slash_pos + 1, string.len(url)) - org, org_pos = - M._make(url, first_slash_pos + 1, last_slash_pos - 1) - path, path_pos = - M._make(url, first_slash_pos + 1, string.len(url)) - else - repo, repo_pos = - M._make(url, first_slash_pos + 1, string.len(url)) - path, path_pos = - M._make(url, first_slash_pos + 1, string.len(url)) - -- missing org - end - else - return nil, "invalid url" - end - end - else - -- user end with '@' - user, user_pos = M._make(url, 1, first_at_pos - 1) - -- missing password - - local second_colon_pos = M._find(url, ":", first_at_pos + 1) - if - type(second_colon_pos) == "number" - and second_colon_pos > first_at_pos + 1 - then - -- host end with ':' - host, host_pos = M._make(url, first_at_pos + 1, second_colon_pos - 1) - - local last_slash_pos = M._rfind(url, "/") - if - type(last_slash_pos) == "number" - and last_slash_pos > second_colon_pos + 1 - then - repo, repo_pos = M._make(url, last_slash_pos + 1, string.len(url)) - org, org_pos = - M._make(url, second_colon_pos + 1, last_slash_pos - 1) - path, path_pos = M._make(url, second_colon_pos + 1, string.len(url)) - else - repo, repo_pos = M._make(url, second_colon_pos + 1, string.len(url)) - path, path_pos = M._make(url, second_colon_pos + 1, string.len(url)) - -- missing org - end - else - local first_slash_pos = M._find(url, "/", first_at_pos + 1) - if - type(first_slash_pos) == "number" - and first_slash_pos > first_at_pos + 1 - then - -- host end with '/' - host, host_pos = M._make(url, first_at_pos + 1, first_slash_pos - 1) - - local last_slash_pos = M._rfind(url, "/") - if - type(last_slash_pos) == "number" - and last_slash_pos > first_slash_pos + 1 - then - repo, repo_pos = M._make(url, last_slash_pos + 1, string.len(url)) - org, org_pos = - M._make(url, first_slash_pos + 1, last_slash_pos - 1) - path, path_pos = - M._make(url, first_slash_pos + 1, string.len(url)) - else - repo, repo_pos = - M._make(url, first_slash_pos + 1, string.len(url)) - path, path_pos = - M._make(url, first_slash_pos + 1, string.len(url)) - -- missing org - end - else - return nil, "invalid url" - end - end - end + -- port not found, host (highly possibly) end with '/' + + -- find first slash '/', the end position of host, start position of path + local first_slash_pos = M._find(p, "/", start) + if type(first_slash_pos) == "number" and first_slash_pos > start then + -- host end with '/' + host, host_pos = M._make(p, start, first_slash_pos - 1) + path_obj = M._make_path(p, first_slash_pos) else - local first_colon_pos = M._find(url, ":") - if type(first_colon_pos) == "number" and first_colon_pos > 1 then - -- host end with ':' - host, host_pos = M._make(url, 1, first_colon_pos - 1) - - local last_slash_pos = M._rfind(url, "/") - if - type(last_slash_pos) == "number" - and last_slash_pos > first_colon_pos + 1 - then - repo, repo_pos = M._make(url, last_slash_pos + 1, string.len(url)) - org, org_pos = M._make(url, first_colon_pos + 1, last_slash_pos - 1) - path, path_pos = M._make(url, first_colon_pos + 1, string.len(url)) - else - repo, repo_pos = M._make(url, first_colon_pos + 1, string.len(url)) - path, path_pos = M._make(url, first_colon_pos + 1, string.len(url)) - -- missing org - end - else - local first_slash_pos = M._find(url, "/") - if type(first_slash_pos) == "number" and first_slash_pos > 1 then - -- host end with '/' - host, host_pos = M._make(url, 1, first_slash_pos - 1) - - local last_slash_pos = M._rfind(url, "/") - if - type(last_slash_pos) == "number" - and last_slash_pos > first_colon_pos + 1 - then - repo, repo_pos = M._make(url, last_slash_pos + 1, string.len(url)) - org, org_pos = M._make(url, first_colon_pos + 1, last_slash_pos - 1) - path, path_pos = M._make(url, first_colon_pos + 1, string.len(url)) - else - repo, repo_pos = M._make(url, first_colon_pos + 1, string.len(url)) - path, path_pos = M._make(url, first_colon_pos + 1, string.len(url)) - -- missing org - end - else - return nil, "invalid url" - end - end + -- first slash not found, host is omitted, path end until url end + path_obj = M._make_path(p, start) + end + end + + return { + host = host, + host_pos = host_pos, + port = port, + port_pos = port_pos, + path_obj = path_obj, + } +end + +-- with omitted ssh protocol, host end with ':' +-- +--- @param p string +--- @param start integer +--- @return giturlparser._GitUrlHost +M._make_host_with_omit_ssh = function(p, start) + assert(type(start) == "number") + assert(not M._startswith(p, "/")) + + local host = nil + local host_pos = nil + local port = nil + local port_pos = nil + --- @type giturlparser._GitUrlPath + local path_obj = {} + + local plen = string.len(p) + + -- find ':', the end position of host, start position of path + local first_colon_pos = M._find(p, ":", start) + if type(first_colon_pos) == "number" and first_colon_pos > start then + -- host end with ':', path start with ':' + host, host_pos = M._make(p, start, first_colon_pos - 1) + path_obj = M._make_path(p, first_colon_pos + 1) + else + -- host not found, path start from beginning + path_obj = M._make_path(p, start) + end + + return { + host = host, + host_pos = host_pos, + port = port, + port_pos = port_pos, + path_obj = path_obj, + } +end + +--- @alias giturlparser._GitUrlUser {user:string?,user_pos:giturlparser.GitUrlPos?,password:string?,password_pos:giturlparser.GitUrlPos?,host_obj:giturlparser._GitUrlHost} +-- +--- @param p string +--- @param start integer +--- @param ssh_protocol_omitted boolean? +--- @return giturlparser._GitUrlUser +M._make_user = function(p, start, ssh_protocol_omitted) + assert(type(start) == "number") + assert(not M._startswith(p, "/")) + + -- local inspect = require("inspect") + + ssh_protocol_omitted = ssh_protocol_omitted or false + + local user = nil + local user_pos = nil + local password = nil + local password_pos = nil + --- @type giturlparser._GitUrlHost + local host_obj = {} + + local plen = string.len(p) + + local host_start_pos = start + + -- find first '@', the end position of user and password + local first_at_pos = M._find(p, "@", start) + -- print( + -- string.format( + -- "|_make_user-1| p:%s, start:%s, ssh_protocol_omitted:%s, first_at_pos:%s, host_start_pos:%s\n", + -- inspect(p), + -- inspect(start), + -- inspect(ssh_protocol_omitted), + -- inspect(first_at_pos), + -- inspect(host_start_pos) + -- ) + -- ) + if type(first_at_pos) == "number" and first_at_pos > start then + -- user (and password) end with '@' + + -- find first ':' (before '@'), the end position of password + local first_colon_pos = M._find(p, ":", start) + if + type(first_colon_pos) == "number" + and first_colon_pos > start + and first_colon_pos < first_at_pos + then + -- password end with ':' + user, user_pos = M._make(p, start, first_colon_pos - 1) + password, password_pos = M._make(p, first_colon_pos + 1, first_at_pos - 1) + else + -- password not found, user end with '@' + user, user_pos = M._make(p, start, first_at_pos - 1) end + + -- host start from '@', user (and password) end position + host_start_pos = first_at_pos + 1 + else + -- user (and password) not found + -- host start from beginning end + -- print( + -- string.format( + -- "|_make_user-2| ssh_protocol_omitted:%s, host_start_pos:%s, first_at_pos:%s\n", + -- inspect(ssh_protocol_omitted), + -- inspect(host_start_pos), + -- inspect(first_at_pos) + -- ) + -- ) + host_obj = ssh_protocol_omitted + and M._make_host_with_omit_ssh(p, host_start_pos) + or M._make_host(p, host_start_pos) + return { - protocol = protocol, - protocol_pos = protocol_pos, user = user, user_pos = user_pos, password = password, password_pos = password_pos, - host = host, - host_pos = host_pos, - org = org, - org_pos = org_pos, - repo = repo, - repo_pos = repo_pos, - path = path, - path_pos = path_pos, + host_obj = host_obj, } end +--- @param url string +--- @return giturlparser.GitUrlInfo?, string? +M.parse = function(url) + if type(url) ~= "string" or string.len(url) == 0 then + return nil, "empty string" + end + + -- find first '://', the end position of protocol + local protocol_delimiter_pos = M._find(url, "://") + if + type(protocol_delimiter_pos) == "number" and protocol_delimiter_pos > 1 + then + -- protocol end with '://' + local protocol, protocol_pos = M._make(url, 1, protocol_delimiter_pos - 1) + + local user_obj = M._make_user(url, protocol_delimiter_pos + 3) + local host_obj = user_obj.host_obj + local path_obj = host_obj.path_obj + + return { + protocol = protocol, + protocol_pos = protocol_pos, + + -- user + user = user_obj.user, + user_pos = user_obj.user_pos, + password = user_obj.password, + password_pos = user_obj.password_pos, + + -- host + host = host_obj.host, + host_pos = host_obj.host_pos, + port = host_obj.port, + port_pos = host_obj.port_pos, + + -- path + org = path_obj.org, + org_pos = path_obj.org_pos, + repo = path_obj.repo, + repo_pos = path_obj.repo_pos, + path = path_obj.path, + path_pos = path_obj.path_pos, + } + else + -- protocol not found, either ssh/local file path + + -- find first ':', host end position on omitted ssh protocol + local first_colon_pos = M._find(url, ":") + if type(first_colon_pos) == "number" and first_colon_pos > 1 then + local user_obj = M._make_user(url, 1, true) + local host_obj = user_obj.host_obj + local path_obj = host_obj.path_obj + + return { + -- no protocol + + -- user + user = user_obj.user, + user_pos = user_obj.user_pos, + password = user_obj.password, + password_pos = user_obj.password_pos, + + -- host + host = host_obj.host, + host_pos = host_obj.host_pos, + port = host_obj.port, + port_pos = host_obj.port_pos, + + -- path + org = path_obj.org, + org_pos = path_obj.org_pos, + repo = path_obj.repo, + repo_pos = path_obj.repo_pos, + path = path_obj.path, + path_pos = path_obj.path_pos, + } + else + -- host not found + + -- treat as local file path, either absolute/relative + local path_obj = M._make_path(url, 1) + return { + -- no protocol + -- no user + -- no host + + -- path + org = path_obj.org, + org_pos = path_obj.org_pos, + repo = path_obj.repo, + repo_pos = path_obj.repo_pos, + path = path_obj.path, + path_pos = path_obj.path_pos, + } + end + end +end + return M From 4838ccf14a0ff43c04a8448650b853944c42a1db Mon Sep 17 00:00:00 2001 From: linrongbin16 Date: Mon, 8 Jan 2024 15:10:20 +0800 Subject: [PATCH 6/7] chore(docs): writing (#30) --- README.md | 58 +++++++++++++++++++++++++++++++++---------------------- 1 file changed, 35 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index 11b3837..2b985c6 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ Pure Lua implemented git URL parsing library, e.g. the output of git remot Single file & zero dependency. -Full [Git Protocols](https://git-scm.com/book/en/v2/Git-on-the-Server-The-Protocols) support: +Full [Git Protocols](https://git-scm.com/book/en/v2/Git-on-the-Server-The-Protocols) support (see below). > [!NOTE] > @@ -47,28 +47,40 @@ Full [Git Protocols](https://git-scm.com/book/en/v2/Git-on-the-Server-The-Protoc > 4. The `[]+` contains 1 or more (≥ 1) component. > 5. The `|` inside `[]` is **_or_** operator. -1. `{protocol}://[[{user}[:{password}]@]{host}[:{port}]]/[{org}/]*{repo}`, for example: - - `http://host.xyz/repo.git` - - `https://git@127.0.0.1:12345/repo.git` - - `ssh://username:password@host.xyz:port/path/to/the/repo.git` - - `ssh://host.xyz:port/path/to/the/repo.git` - - `file:///repo.git` - - `file://user:passwd@host.xyz:port/path/to/the/repo.git` - - `file://~/home/to/the/repo.git` -2. `[{user}[:{password}]@]{host}:[{org}/]*{repo}`, for example: - - `git@host.xyz:repo.git` - - `user:passwd@host.xyz:path/to/the/repo.git` -3. `[.|..|~][/{org}]*/{repo}`, for example: - - `repo.git` - - `./repo.git` - - `../path/to/the/repo.git` - - `~/home/to/the/repo.git` - - `/usr/home/to/the/repo.git` - -All of above can be written by: - -1. `[{protocol}://][[{user}[:{password}]@]host[:{port}]]/[{org}/]*{repo}` -2. `[.|..|~][/{org}]*/{repo}` +### Full Pattern + +`{protocol}://[[{user}[:{password}]@]{host}[:{port}]]/[{org}/]*{repo}` + +For example: + +- `http://host.xyz/repo.git` +- `https://git@127.0.0.1:12345/repo.git` +- `ssh://username:password@host.xyz:port/path/to/the/repo.git` +- `ssh://host.xyz:port/path/to/the/repo.git` +- `file:///repo.git` +- `file://user:passwd@host.xyz:port/path/to/the/repo.git` +- `file://~/home/to/the/repo.git` + +### Protocol Omitted Pattern + +`[{user}[:{password}]@]{host}:[{org}/]*{repo}` + +For example: + +- `git@host.xyz:repo.git` +- `user:passwd@host.xyz:path/to/the/repo.git` + +### Local Pattern + +`[.|..|~][/{org}]*/{repo}` + +For example: + +- `repo.git` +- `./repo.git` +- `../path/to/the/repo.git` +- `~/home/to/the/repo.git` +- `/usr/home/to/the/repo.git` ## Install From 77e2a62c041fc905724101086fa36bf2dcc10b6e Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 8 Jan 2024 15:12:12 +0800 Subject: [PATCH 7/7] chore(main): release 1.0.7 (#29) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- CHANGELOG.md | 7 +++++++ version.txt | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 235cf61..a94e826 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [1.0.7](https://github.com/linrongbin16/giturlparser.lua/compare/v1.0.6...v1.0.7) (2024-01-08) + + +### Bug Fixes + +* **parse:** fix parse ([#28](https://github.com/linrongbin16/giturlparser.lua/issues/28)) ([454d7c3](https://github.com/linrongbin16/giturlparser.lua/commit/454d7c3094669641c5e5dcc3060947f2364e7634)) + ## [1.0.6](https://github.com/linrongbin16/giturlparser.lua/compare/v1.0.5...v1.0.6) (2024-01-07) diff --git a/version.txt b/version.txt index af0b7dd..238d6e8 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.0.6 +1.0.7