diff options
Diffstat (limited to 'third_party/python/giturlparse')
15 files changed, 786 insertions, 0 deletions
diff --git a/third_party/python/giturlparse/giturlparse-0.10.0.dist-info/LICENSE b/third_party/python/giturlparse/giturlparse-0.10.0.dist-info/LICENSE new file mode 100644 index 0000000000..37ec93a14f --- /dev/null +++ b/third_party/python/giturlparse/giturlparse-0.10.0.dist-info/LICENSE @@ -0,0 +1,191 @@ +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and +distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright +owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities +that control, are controlled by, or are under common control with that entity. +For the purposes of this definition, "control" means (i) the power, direct or +indirect, to cause the direction or management of such entity, whether by +contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the +outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising +permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including +but not limited to software source code, documentation source, and configuration +files. + +"Object" form shall mean any form resulting from mechanical transformation or +translation of a Source form, including but not limited to compiled object code, +generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made +available under the License, as indicated by a copyright notice that is included +in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that +is based on (or derived from) the Work and for which the editorial revisions, +annotations, elaborations, or other modifications represent, as a whole, an +original work of authorship. For the purposes of this License, Derivative Works +shall not include works that remain separable from, or merely link (or bind by +name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version +of the Work and any modifications or additions to that Work or Derivative Works +thereof, that is intentionally submitted to Licensor for inclusion in the Work +by the copyright owner or by an individual or Legal Entity authorized to submit +on behalf of the copyright owner. For the purposes of this definition, +"submitted" means any form of electronic, verbal, or written communication sent +to the Licensor or its representatives, including but not limited to +communication on electronic mailing lists, source code control systems, and +issue tracking systems that are managed by, or on behalf of, the Licensor for +the purpose of discussing and improving the Work, but excluding communication +that is conspicuously marked or otherwise designated in writing by the copyright +owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf +of whom a Contribution has been received by Licensor and subsequently +incorporated within the Work. + +2. Grant of Copyright License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable copyright license to reproduce, prepare Derivative Works of, +publicly display, publicly perform, sublicense, and distribute the Work and such +Derivative Works in Source or Object form. + +3. Grant of Patent License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable (except as stated in this section) patent license to make, have +made, use, offer to sell, sell, import, and otherwise transfer the Work, where +such license applies only to those patent claims licensable by such Contributor +that are necessarily infringed by their Contribution(s) alone or by combination +of their Contribution(s) with the Work to which such Contribution(s) was +submitted. If You institute patent litigation against any entity (including a +cross-claim or counterclaim in a lawsuit) alleging that the Work or a +Contribution incorporated within the Work constitutes direct or contributory +patent infringement, then any patent licenses granted to You under this License +for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. + +You may reproduce and distribute copies of the Work or Derivative Works thereof +in any medium, with or without modifications, and in Source or Object form, +provided that You meet the following conditions: + +You must give any other recipients of the Work or Derivative Works a copy of +this License; and +You must cause any modified files to carry prominent notices stating that You +changed the files; and +You must retain, in the Source form of any Derivative Works that You distribute, +all copyright, patent, trademark, and attribution notices from the Source form +of the Work, excluding those notices that do not pertain to any part of the +Derivative Works; and +If the Work includes a "NOTICE" text file as part of its distribution, then any +Derivative Works that You distribute must include a readable copy of the +attribution notices contained within such NOTICE file, excluding those notices +that do not pertain to any part of the Derivative Works, in at least one of the +following places: within a NOTICE text file distributed as part of the +Derivative Works; within the Source form or documentation, if provided along +with the Derivative Works; or, within a display generated by the Derivative +Works, if and wherever such third-party notices normally appear. The contents of +the NOTICE file are for informational purposes only and do not modify the +License. You may add Your own attribution notices within Derivative Works that +You distribute, alongside or as an addendum to the NOTICE text from the Work, +provided that such additional attribution notices cannot be construed as +modifying the License. +You may add Your own copyright statement to Your modifications and may provide +additional or different license terms and conditions for use, reproduction, or +distribution of Your modifications, or for any such Derivative Works as a whole, +provided Your use, reproduction, and distribution of the Work otherwise complies +with the conditions stated in this License. + +5. Submission of Contributions. + +Unless You explicitly state otherwise, any Contribution intentionally submitted +for inclusion in the Work by You to the Licensor shall be under the terms and +conditions of this License, without any additional terms or conditions. +Notwithstanding the above, nothing herein shall supersede or modify the terms of +any separate license agreement you may have executed with Licensor regarding +such Contributions. + +6. Trademarks. + +This License does not grant permission to use the trade names, trademarks, +service marks, or product names of the Licensor, except as required for +reasonable and customary use in describing the origin of the Work and +reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. + +Unless required by applicable law or agreed to in writing, Licensor provides the +Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, +including, without limitation, any warranties or conditions of TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are +solely responsible for determining the appropriateness of using or +redistributing the Work and assume any risks associated with Your exercise of +permissions under this License. + +8. Limitation of Liability. + +In no event and under no legal theory, whether in tort (including negligence), +contract, or otherwise, unless required by applicable law (such as deliberate +and grossly negligent acts) or agreed to in writing, shall any Contributor be +liable to You for damages, including any direct, indirect, special, incidental, +or consequential damages of any character arising as a result of this License or +out of the use or inability to use the Work (including but not limited to +damages for loss of goodwill, work stoppage, computer failure or malfunction, or +any and all other commercial damages or losses), even if such Contributor has +been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. + +While redistributing the Work or Derivative Works thereof, You may choose to +offer, and charge a fee for, acceptance of support, warranty, indemnity, or +other liability obligations and/or rights consistent with this License. However, +in accepting such obligations, You may act only on Your own behalf and on Your +sole responsibility, not on behalf of any other Contributor, and only if You +agree to indemnify, defend, and hold each Contributor harmless for any liability +incurred by, or claims asserted against, such Contributor by reason of your +accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work + +To apply the Apache License to your work, attach the following boilerplate +notice, with the fields enclosed by brackets "[]" replaced with your own +identifying information. (Don't include the brackets!) The text should be +enclosed in the appropriate comment syntax for the file format. We also +recommend that a file or class name and description of purpose be included on +the same "printed page" as the copyright notice for easier identification within +third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/third_party/python/giturlparse/giturlparse-0.10.0.dist-info/METADATA b/third_party/python/giturlparse/giturlparse-0.10.0.dist-info/METADATA new file mode 100644 index 0000000000..198277d691 --- /dev/null +++ b/third_party/python/giturlparse/giturlparse-0.10.0.dist-info/METADATA @@ -0,0 +1,165 @@ +Metadata-Version: 2.1 +Name: giturlparse +Version: 0.10.0 +Summary: A Git URL parsing module (supports parsing and rewriting) +Home-page: https://github.com/nephila/giturlparse +Author: Aaron O Mullan +Author-email: aaron@friendco.de +Maintainer: Iacopo Spalletti +Maintainer-email: i.spalletti@nephila.it +License: Apache v2 +Keywords: giturlparse +Platform: UNKNOWN +Classifier: Development Status :: 5 - Production/Stable +Classifier: Framework :: Django +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: Apache Software License +Classifier: Natural Language :: English +Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: 3.7 +Requires-Python: >=3.6 +Description-Content-Type: text/x-rst + +=========== +giturlparse +=========== + +Parse & rewrite git urls (supports GitHub, Bitbucket, FriendCode, Assembla, Gitlab ...) + +This is a fork of giturlparse.py with updated parsers. + +Original project can be found at https://github.com/FriendCode/giturlparse.py + +************ +Installing +************ + +:: + + pip install giturlparse + +****************** +Examples +****************** + +Exposed attributes +================== + +* ``platform``: platform codename +* ``host``: server hostname +* ``resource``: same as ``host`` +* ``port``: URL port (only if explicitly defined in URL) +* ``protocol``: URL protocol (git, ssh, http/https) +* ``protocols``: list of protocols explicitly defined in URL +* ``user``: repository user +* ``owner``: repository owner (user or organization) +* ``repo``: repository name +* ``name``: same as ``repo`` +* ``groups``: list of groups - gitlab only +* ``path``: path to file or directory (includes the branch name) - gitlab / github only +* ``path_raw``: raw path starting from the repo name (might include platform keyword) - gitlab / github only +* ``branch``: branch name (when parseable) - gitlab / github only + +Parse +================== + +:: + + from giturlparse import parse + + p = parse('git@bitbucket.org:AaronO/some-repo.git') + + p.host, p.owner, p.repo + + # => ('bitbucket.org', 'AaronO', 'some-repo') + + +Rewrite +================== + +:: + + from giturlparse import parse + + url = 'git@github.com:Org/Private-repo.git' + + p = parse(url) + + p.url2ssh, p.url2https, p.url2git, p.url2http + # => ('git@github.com:Org/Private-repo.git', 'https://github.com/Org/Private-repo.git', 'git://github.com/Org/Private-repo.git', None) + +URLS +================== + +Alternative URLs for same repo:: + + from giturlparse import parse + + url = 'git@github.com:Org/Private-repo.git' + + parse(url).urls + # => { + # 'ssh': 'git@github.com:Org/Private-repo.git', + # 'https': 'https://github.com/Org/Private-repo.git', + # 'git': 'git://github.com/Org/Private-repo.git' + # } + +Validate +================== + +:: + + from giturlparse import parse, validate + + url = 'git@github.com:Org/Private-repo.git' + + parse(url).valid + # => True + + # Or + + validate(url) + # => True + +Tests +================== + +:: + + python setup.py test + +License +================== + +Apache v2 (Check out LICENSE file) + +.. :changelog: + +******* +History +******* + +.. towncrier release notes start + +0.10.0 (2020-12-05) +=================== + +Features +-------- + +- General matching improvements (#18) +- Update tooling, drop python2 (#10213) + +0.9.2 (2018-10-27) +================== + +* Removed "s" from the base platform regex +* Fix license classifier in setup.py +* Update meta files + +0.9.1 (2018-01-20) +================== + +* First fork release + + diff --git a/third_party/python/giturlparse/giturlparse-0.10.0.dist-info/RECORD b/third_party/python/giturlparse/giturlparse-0.10.0.dist-info/RECORD new file mode 100644 index 0000000000..f5d97476fb --- /dev/null +++ b/third_party/python/giturlparse/giturlparse-0.10.0.dist-info/RECORD @@ -0,0 +1,18 @@ +giturlparse/__init__.py,sha256=c5WMm7u1auWiuJrsY0bo1IsT6iRi8b6pGebNQC03_PI,332 +giturlparse/parser.py,sha256=BTaOH--z1-odYdOwEb5iNadYpCvUM4-bKHYXGKxGIZM,1924 +giturlparse/result.py,sha256=wKg1h9vYXkPseRgEAIk8TDPS1UMIU_z3t4IKbT7uD18,2765 +giturlparse/platforms/__init__.py,sha256=y8xzQWxqGHwlvx0pY99Hqott-xK2Q0iBzpQ9dTehTrY,527 +giturlparse/platforms/assembla.py,sha256=iPYpPOu8cNapbniD7sj63aTwPGT4DUH1U8RkvbUkiqE,498 +giturlparse/platforms/base.py,sha256=cZPxEa1u1WNq6IvhUVp3XWJtks9Dy2sifDaJAdeHclI,1566 +giturlparse/platforms/bitbucket.py,sha256=R6dsFBhuMlLe9-gIAP7X8hzJn-FHAjI-bBgnfNom4tc,680 +giturlparse/platforms/friendcode.py,sha256=w__PNSQAkNO2Y45doOw7YMDqwuSyu_FocQTRa305VM0,389 +giturlparse/platforms/github.py,sha256=G_7VRQpm5ZtvOcc1xbVF3CnC4AcCRnyK7EgkoaoqOEo,1446 +giturlparse/platforms/gitlab.py,sha256=2K65zlI8CA5OdXV9eXW3SBFH7oW78lFlkhLviW3Mwyo,1794 +giturlparse/tests/__init__.py,sha256=yBGT6Ycwx1AsTFYemzHoqrJ82seE0gfGti99VyrV3x0,37 +giturlparse/tests/parse.py,sha256=dpFzvo40qdH7Zg6CmgMqBMeZz473GhbZotmVK_nq_pk,14594 +giturlparse/tests/rewrite.py,sha256=scB7YGBUeFo3bEyI0Mvc0hK_ajlBY2RkrEGRtnrtukc,3386 +giturlparse-0.10.0.dist-info/LICENSE,sha256=c7p036pSC0mkAbXSFFmoUjoUbzt1GKgz7qXvqFEwv2g,10273 +giturlparse-0.10.0.dist-info/METADATA,sha256=NDWxArULRXhAAu2KttDMuZu1k35HvJ1eJHEcWfeB8lI,3511 +giturlparse-0.10.0.dist-info/WHEEL,sha256=oh0NKYrTcu1i1-wgrI1cnhkjYIi8WJ-8qd9Jrr5_y4E,110 +giturlparse-0.10.0.dist-info/top_level.txt,sha256=NHfX7iaRAYz-bnROU6Q0tgNInQU-YgIeeii0uznxCLA,12 +giturlparse-0.10.0.dist-info/RECORD,, diff --git a/third_party/python/giturlparse/giturlparse-0.10.0.dist-info/WHEEL b/third_party/python/giturlparse/giturlparse-0.10.0.dist-info/WHEEL new file mode 100644 index 0000000000..1f227afa9f --- /dev/null +++ b/third_party/python/giturlparse/giturlparse-0.10.0.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.36.1) +Root-Is-Purelib: true +Tag: py2-none-any +Tag: py3-none-any + diff --git a/third_party/python/giturlparse/giturlparse-0.10.0.dist-info/top_level.txt b/third_party/python/giturlparse/giturlparse-0.10.0.dist-info/top_level.txt new file mode 100644 index 0000000000..d756422c23 --- /dev/null +++ b/third_party/python/giturlparse/giturlparse-0.10.0.dist-info/top_level.txt @@ -0,0 +1 @@ +giturlparse diff --git a/third_party/python/giturlparse/giturlparse/__init__.py b/third_party/python/giturlparse/giturlparse/__init__.py new file mode 100644 index 0000000000..aee86e3750 --- /dev/null +++ b/third_party/python/giturlparse/giturlparse/__init__.py @@ -0,0 +1,14 @@ +from .parser import parse as _parse +from .result import GitUrlParsed + +__author__ = "Iacopo Spalletti" +__email__ = "i.spalletti@nephila.it" +__version__ = "0.10.0" + + +def parse(url, check_domain=True): + return GitUrlParsed(_parse(url, check_domain)) + + +def validate(url, check_domain=True): + return parse(url, check_domain).valid diff --git a/third_party/python/giturlparse/giturlparse/parser.py b/third_party/python/giturlparse/giturlparse/parser.py new file mode 100644 index 0000000000..c67f03500d --- /dev/null +++ b/third_party/python/giturlparse/giturlparse/parser.py @@ -0,0 +1,69 @@ +from collections import defaultdict + +from .platforms import PLATFORMS + +SUPPORTED_ATTRIBUTES = ( + "domain", + "repo", + "owner", + "path_raw", + "groups_path", + "_user", + "port", + "url", + "platform", + "protocol", +) + + +def parse(url, check_domain=True): + # Values are None by default + parsed_info = defaultdict(lambda: None) + parsed_info["port"] = "" + parsed_info["path_raw"] = "" + parsed_info["groups_path"] = "" + + # Defaults to all attributes + map(parsed_info.setdefault, SUPPORTED_ATTRIBUTES) + + for name, platform in PLATFORMS: + for protocol, regex in platform.COMPILED_PATTERNS.items(): + # print(name, protocol, regex) + # Match current regex against URL + match = regex.match(url) + + # Skip if not matched + if not match: + # print("[%s] URL: %s dit not match %s" % (name, url, regex.pattern)) + continue + + # Skip if domain is bad + domain = match.group("domain") + # print('[%s] DOMAIN = %s' % (url, domain,)) + if check_domain: + if platform.DOMAINS and not (domain in platform.DOMAINS): + continue + if platform.SKIP_DOMAINS and domain in platform.SKIP_DOMAINS: + continue + + # add in platform defaults + parsed_info.update(platform.DEFAULTS) + + # Get matches as dictionary + matches = platform.clean_data(match.groupdict(default="")) + + # Update info with matches + parsed_info.update(matches) + + # Update info with platform info + parsed_info.update( + { + "url": url, + "platform": name, + "protocol": protocol, + } + ) + return parsed_info + + # Empty if none matched + return parsed_info diff --git a/third_party/python/giturlparse/giturlparse/platforms/__init__.py b/third_party/python/giturlparse/giturlparse/platforms/__init__.py new file mode 100644 index 0000000000..8add1b7a78 --- /dev/null +++ b/third_party/python/giturlparse/giturlparse/platforms/__init__.py @@ -0,0 +1,18 @@ +from .assembla import AssemblaPlatform +from .base import BasePlatform +from .bitbucket import BitbucketPlatform +from .friendcode import FriendCodePlatform +from .github import GitHubPlatform +from .gitlab import GitLabPlatform + +# Supported platforms +PLATFORMS = [ + # name -> Platform object + ("github", GitHubPlatform()), + ("bitbucket", BitbucketPlatform()), + ("friendcode", FriendCodePlatform()), + ("assembla", AssemblaPlatform()), + ("gitlab", GitLabPlatform()), + # Match url + ("base", BasePlatform()), +] diff --git a/third_party/python/giturlparse/giturlparse/platforms/assembla.py b/third_party/python/giturlparse/giturlparse/platforms/assembla.py new file mode 100644 index 0000000000..2624e85954 --- /dev/null +++ b/third_party/python/giturlparse/giturlparse/platforms/assembla.py @@ -0,0 +1,14 @@ +from .base import BasePlatform + + +class AssemblaPlatform(BasePlatform): + DOMAINS = ("git.assembla.com",) + PATTERNS = { + "ssh": r"(?P<protocols>(git\+)?(?P<protocol>ssh))?(://)?git@(?P<domain>.+?):(?P<pathname>(?P<repo>.+)).git", + "git": r"(?P<protocols>(?P<protocol>git))://(?P<domain>.+?)/(?P<pathname>(?P<repo>.+)).git", + } + FORMATS = { + "ssh": r"git@%(domain)s:%(repo)s.git", + "git": r"git://%(domain)s/%(repo)s.git", + } + DEFAULTS = {"_user": "git"} diff --git a/third_party/python/giturlparse/giturlparse/platforms/base.py b/third_party/python/giturlparse/giturlparse/platforms/base.py new file mode 100644 index 0000000000..000726381d --- /dev/null +++ b/third_party/python/giturlparse/giturlparse/platforms/base.py @@ -0,0 +1,43 @@ +import itertools +import re + + +class BasePlatform: + FORMATS = { + "ssh": r"(?P<protocols>(git\+)?(?P<protocol>ssh))?(://)?%(_user)s@%(host)s:%(repo)s.git", + "http": r"(?P<protocols>(git\+)?(?P<protocol>http))://%(host)s/%(repo)s.git", + "https": r"(?P<protocols>(git\+)?(?P<protocol>https))://%(host)s/%(repo)s.git", + "git": r"(?P<protocols>(?P<protocol>git))://%(host)s/%(repo)s.git", + } + + PATTERNS = { + "ssh": r"(?P<_user>.+)@(?P<domain>[^/]+?):(?P<repo>.+).git", + "http": r"http://(?P<domain>[^/]+?)/(?P<repo>.+).git", + "https": r"https://(?P<domain>[^/]+?)/(?P<repo>.+).git", + "git": r"git://(?P<domain>[^/]+?)/(?P<repo>.+).git", + } + + # None means it matches all domains + DOMAINS = None + SKIP_DOMAINS = None + DEFAULTS = {} + + def __init__(self): + # Precompile PATTERNS + self.COMPILED_PATTERNS = {proto: re.compile(regex, re.IGNORECASE) for proto, regex in self.PATTERNS.items()} + + # Supported protocols + self.PROTOCOLS = self.PATTERNS.keys() + + if self.__class__ == BasePlatform: + sub = [subclass.SKIP_DOMAINS for subclass in self.__class__.__subclasses__() if subclass.SKIP_DOMAINS] + if sub: + self.SKIP_DOMAINS = list(itertools.chain.from_iterable(sub)) + + @staticmethod + def clean_data(data): + data["path"] = "" + data["branch"] = "" + data["protocols"] = list(filter(lambda x: x, data["protocols"].split("+"))) + data["pathname"] = data["pathname"].strip(":") + return data diff --git a/third_party/python/giturlparse/giturlparse/platforms/bitbucket.py b/third_party/python/giturlparse/giturlparse/platforms/bitbucket.py new file mode 100644 index 0000000000..baab24466b --- /dev/null +++ b/third_party/python/giturlparse/giturlparse/platforms/bitbucket.py @@ -0,0 +1,20 @@ +from .base import BasePlatform + + +class BitbucketPlatform(BasePlatform): + PATTERNS = { + "https": ( + r"(?P<protocols>(git\+)?(?P<protocol>https))://(?P<_user>.+)@(?P<domain>.+?)" + r"(?P<pathname>/(?P<owner>.+)/(?P<repo>.+?)(?:\.git)?)$" + ), + "ssh": ( + r"(?P<protocols>(git\+)?(?P<protocol>ssh))?(://)?git@(?P<domain>.+?):" + r"(?P<pathname>(?P<owner>.+)/(?P<repo>.+?)(?:\.git)?)$" + ), + } + FORMATS = { + "https": r"https://%(owner)s@%(domain)s/%(owner)s/%(repo)s.git", + "ssh": r"git@%(domain)s:%(owner)s/%(repo)s.git", + } + DOMAINS = ("bitbucket.org",) + DEFAULTS = {"_user": "git"} diff --git a/third_party/python/giturlparse/giturlparse/platforms/friendcode.py b/third_party/python/giturlparse/giturlparse/platforms/friendcode.py new file mode 100644 index 0000000000..6de9f17eab --- /dev/null +++ b/third_party/python/giturlparse/giturlparse/platforms/friendcode.py @@ -0,0 +1,14 @@ +from .base import BasePlatform + + +class FriendCodePlatform(BasePlatform): + DOMAINS = ("friendco.de",) + PATTERNS = { + "https": ( + r"(?P<protocols>(git\+)?(?P<protocol>https))://(?P<domain>.+?)/" + r"(?P<pathname>(?P<owner>.+)@user/(?P<repo>.+)).git" + ), + } + FORMATS = { + "https": r"https://%(domain)s/%(owner)s@user/%(repo)s.git", + } diff --git a/third_party/python/giturlparse/giturlparse/platforms/github.py b/third_party/python/giturlparse/giturlparse/platforms/github.py new file mode 100644 index 0000000000..8eb44ef513 --- /dev/null +++ b/third_party/python/giturlparse/giturlparse/platforms/github.py @@ -0,0 +1,39 @@ +from .base import BasePlatform + + +class GitHubPlatform(BasePlatform): + PATTERNS = { + "https": ( + r"(?P<protocols>(git\+)?(?P<protocol>https))://(?P<domain>[^/]+?)" + r"(?P<pathname>/(?P<owner>[^/]+?)/(?P<repo>[^/]+?)(?:\.git)?(?P<path_raw>(/blob/|/tree/).+)?)$" + ), + "ssh": ( + r"(?P<protocols>(git\+)?(?P<protocol>ssh))?(://)?git@(?P<domain>.+?)(?P<pathname>(:|/)" + r"(?P<owner>[^/]+)/(?P<repo>[^/]+?)(?:\.git)" + r"(?P<path_raw>(/blob/|/tree/).+)?)$" + ), + "git": ( + r"(?P<protocols>(?P<protocol>git))://(?P<domain>.+?)" + r"(?P<pathname>/(?P<owner>[^/]+)/(?P<repo>[^/]+?)(?:\.git)?" + r"(?P<path_raw>(/blob/|/tree/).+)?)$" + ), + } + FORMATS = { + "https": r"https://%(domain)s/%(owner)s/%(repo)s.git%(path_raw)s", + "ssh": r"git@%(domain)s:%(owner)s/%(repo)s.git%(path_raw)s", + "git": r"git://%(domain)s/%(owner)s/%(repo)s.git%(path_raw)s", + } + DOMAINS = ( + "github.com", + "gist.github.com", + ) + DEFAULTS = {"_user": "git"} + + @staticmethod + def clean_data(data): + data = BasePlatform.clean_data(data) + if data["path_raw"].startswith("/blob/"): + data["path"] = data["path_raw"].replace("/blob/", "") + if data["path_raw"].startswith("/tree/"): + data["branch"] = data["path_raw"].replace("/tree/", "") + return data diff --git a/third_party/python/giturlparse/giturlparse/platforms/gitlab.py b/third_party/python/giturlparse/giturlparse/platforms/gitlab.py new file mode 100644 index 0000000000..38b37efb23 --- /dev/null +++ b/third_party/python/giturlparse/giturlparse/platforms/gitlab.py @@ -0,0 +1,43 @@ +from .base import BasePlatform + + +class GitLabPlatform(BasePlatform): + PATTERNS = { + "https": ( + r"(?P<protocols>(git\+)?(?P<protocol>https))://(?P<domain>.+?)(?P<port>:[0-9]+)?" + r"(?P<pathname>/(?P<owner>[^/]+?)/" + r"(?P<groups_path>.*?)?(?(groups_path)/)?(?P<repo>[^/]+?)(?:\.git)?" + r"(?P<path_raw>(/blob/|/-/tree/).+)?)$" + ), + "ssh": ( + r"(?P<protocols>(git\+)?(?P<protocol>ssh))?(://)?git@(?P<domain>.+?):(?P<port>[0-9]+)?(?(port))?" + r"(?P<pathname>/?(?P<owner>[^/]+)/" + r"(?P<groups_path>.*?)?(?(groups_path)/)?(?P<repo>[^/]+?)(?:\.git)?" + r"(?P<path_raw>(/blob/|/-/tree/).+)?)$" + ), + "git": ( + r"(?P<protocols>(?P<protocol>git))://(?P<domain>.+?):(?P<port>[0-9]+)?(?(port))?" + r"(?P<pathname>/?(?P<owner>[^/]+)/" + r"(?P<groups_path>.*?)?(?(groups_path)/)?(?P<repo>[^/]+?)(?:\.git)?" + r"(?P<path_raw>(/blob/|/-/tree/).+)?)$" + ), + } + FORMATS = { + "https": r"https://%(domain)s/%(owner)s/%(groups_slash)s%(repo)s.git%(path_raw)s", + "ssh": r"git@%(domain)s:%(port_slash)s%(owner)s/%(groups_slash)s%(repo)s.git%(path_raw)s", + "git": r"git://%(domain)s%(port)s/%(owner)s/%(groups_slash)s%(repo)s.git%(path_raw)s", + } + SKIP_DOMAINS = ( + "github.com", + "gist.github.com", + ) + DEFAULTS = {"_user": "git", "port": ""} + + @staticmethod + def clean_data(data): + data = BasePlatform.clean_data(data) + if data["path_raw"].startswith("/blob/"): + data["path"] = data["path_raw"].replace("/blob/", "") + if data["path_raw"].startswith("/-/tree/"): + data["branch"] = data["path_raw"].replace("/-/tree/", "") + return data diff --git a/third_party/python/giturlparse/giturlparse/result.py b/third_party/python/giturlparse/giturlparse/result.py new file mode 100644 index 0000000000..4a33136c51 --- /dev/null +++ b/third_party/python/giturlparse/giturlparse/result.py @@ -0,0 +1,131 @@ +from copy import copy + +from .platforms import PLATFORMS + +# Possible values to extract from a Git Url +REQUIRED_ATTRIBUTES = ( + "domain", + "repo", +) + + +class GitUrlParsed: + platform = None + + def __init__(self, parsed_info): + self._parsed = parsed_info + + # Set parsed objects as attributes + for k, v in parsed_info.items(): + setattr(self, k, v) + + for name, platform in PLATFORMS: + if name == self.platform: + self._platform_obj = platform + break + + def _valid_attrs(self): + return all([getattr(self, attr, None) for attr in REQUIRED_ATTRIBUTES]) # NOQA + + @property + def valid(self): + return all( + [ + self._valid_attrs(), + ] + ) + + ## + # Alias properties + ## + @property + def host(self): + return self.domain + + @property + def resource(self): + return self.domain + + @property + def name(self): + return self.repo + + @property + def user(self): + if hasattr(self, "_user"): + return self._user + + return self.owner + + @property + def groups(self): + if self.groups_path: + return self.groups_path.split("/") + else: + return [] + + def format(self, protocol): # noqa : A0003 + """Reformat URL to protocol.""" + items = copy(self._parsed) + items["port_slash"] = "%s/" % self.port if self.port else "" + items["groups_slash"] = "%s/" % self.groups_path if self.groups_path else "" + return self._platform_obj.FORMATS[protocol] % items + + @property + def normalized(self): + """Normalize URL.""" + return self.format(self.protocol) + + ## + # Rewriting + ## + @property + def url2ssh(self): + return self.format("ssh") + + @property + def url2http(self): + return self.format("http") + + @property + def url2https(self): + return self.format("https") + + @property + def url2git(self): + return self.format("git") + + # All supported Urls for a repo + @property + def urls(self): + return {protocol: self.format(protocol) for protocol in self._platform_obj.PROTOCOLS} + + ## + # Platforms + ## + @property + def github(self): + return self.platform == "github" + + @property + def bitbucket(self): + return self.platform == "bitbucket" + + @property + def friendcode(self): + return self.platform == "friendcode" + + @property + def assembla(self): + return self.platform == "assembla" + + @property + def gitlab(self): + return self.platform == "gitlab" + + ## + # Get data as dict + ## + @property + def data(self): + return dict(self._parsed) |