From c53e6d822de15d414301ee00a10b13af8f840c4a Mon Sep 17 00:00:00 2001 From: saxenabhishek Date: Fri, 18 Feb 2022 21:39:00 +0530 Subject: [PATCH] feat: parse app name from tags and urls --- frappe/exceptions.py | 3 +++ frappe/installer.py | 53 +++++++++++++++++++++++++++++++++++++--- frappe/utils/__init__.py | 5 ++++ 3 files changed, 58 insertions(+), 3 deletions(-) diff --git a/frappe/exceptions.py b/frappe/exceptions.py index 6ee72b5f81..fcac349708 100644 --- a/frappe/exceptions.py +++ b/frappe/exceptions.py @@ -110,3 +110,6 @@ class InvalidAuthorizationPrefix(CSRFTokenError): pass class InvalidAuthorizationToken(CSRFTokenError): pass class InvalidDatabaseFile(ValidationError): pass class ExecutableNotFound(FileNotFoundError): pass + +class InvalidRemoteException(Exception): + pass diff --git a/frappe/installer.py b/frappe/installer.py index d10dc78286..9bb2d9993f 100644 --- a/frappe/installer.py +++ b/frappe/installer.py @@ -5,10 +5,11 @@ import json import os import sys from collections import OrderedDict -from typing import List, Dict +from typing import List, Dict, Tuple import frappe from frappe.defaults import _clear_cache +from frappe.utils import is_git_url def _new_site( @@ -34,7 +35,6 @@ def _new_site( from frappe.commands.scheduler import _is_scheduler_enabled from frappe.utils import get_site_path, scheduler, touch_file - if not force and os.path.exists(site): print("Site {0} already exists".format(site)) sys.exit(1) @@ -124,6 +124,52 @@ def install_db(root_login=None, root_password=None, db_name=None, source_sql=Non frappe.flags.in_install_db = False +def find_org(org_repo: str) -> Tuple[str, str]: + from frappe.exceptions import InvalidRemoteException + import requests + + org_repo = org_repo[0] + + for org in ["frappe", "erpnext"]: + res = requests.head(f"https://api.github.com/repos/{org}/{org_repo}") + if res.ok: + return org, org_repo + + raise InvalidRemoteException + + +def fetch_details_from_tag(_tag: str) -> Tuple[str, str, str]: + app_tag = _tag.split("@") + org_repo = app_tag[0].split("/") + + try: + repo, tag = app_tag + except ValueError: + repo, tag = app_tag + [None] + + try: + org, repo = org_repo + except Exception: + org, repo = find_org(org_repo) + + return org, repo, tag + + +def parse_app_name(name: str): + name = name.rstrip("/") + if os.path.exists(name): + repo = os.path.split(name)[-1] + elif is_git_url(name): + if name.startswith("git@") or name.startswith("ssh://"): + _repo = name.split(":")[1].rsplit("/", 1)[1] + else: + _repo = name.rsplit("/", 2)[2] + repo = _repo.split(".")[0] + else: + _, repo, _ = fetch_details_from_tag(name) + return repo + + def install_app(name, verbose=False, set_as_patched=True): from frappe.core.doctype.scheduled_job_type.scheduled_job_type import sync_jobs from frappe.model.sync import sync_for @@ -140,7 +186,8 @@ def install_app(name, verbose=False, set_as_patched=True): # install pre-requisites if app_hooks.required_apps: for app in app_hooks.required_apps: - install_app(app, verbose=verbose) + name = parse_app_name(name) + install_app(name, verbose=verbose) frappe.flags.in_install = name frappe.clear_cache() diff --git a/frappe/utils/__init__.py b/frappe/utils/__init__.py index c361b5b430..4a6d578a9c 100644 --- a/frappe/utils/__init__.py +++ b/frappe/utils/__init__.py @@ -918,3 +918,8 @@ def add_user_info(user, user_info): email = info.email, time_zone = info.time_zone ) + +def is_git_url(url: str) -> bool: + # modified to allow without the tailing .git from https://github.com/jonschlinkert/is-git-url.git + pattern = r"(?:git|ssh|https?|\w*@[-\w.]+):(\/\/)?(.*?)(\.git)?(\/?|\#[-\d\w._]+?)$" + return bool(re.match(pattern, url))