From 8601c5e075ecd35d4c9f155e8477ad719b41fe3a Mon Sep 17 00:00:00 2001 From: rubenwardy Date: Tue, 5 Jun 2018 23:13:39 +0100 Subject: [PATCH] Add support for importing generic git releases --- app/models.py | 10 --- app/tasks/importtasks.py | 86 ++++++++++++++++--------- app/templates/packages/release_new.html | 2 +- app/views/packages/releases.py | 4 +- 4 files changed, 58 insertions(+), 44 deletions(-) diff --git a/app/models.py b/app/models.py index f045d75..a50c4d0 100644 --- a/app/models.py +++ b/app/models.py @@ -434,16 +434,6 @@ class Package(db.Model): return None - def canMakeReleaseFromVCS(self): - if self.repo is None: - return False - - url = urlparse(self.repo) - if url.netloc == "github.com": - return True - - return False - def checkPerm(self, user, perm): if not user.is_authenticated: return False diff --git a/app/tasks/importtasks.py b/app/tasks/importtasks.py index ae689e1..d2c26ea 100644 --- a/app/tasks/importtasks.py +++ b/app/tasks/importtasks.py @@ -137,9 +137,9 @@ class PackageTreeNode: print("Scanning " + baseDir) self.baseDir = baseDir self.author = author - self.name = name - self.repo = repo - self.meta = None + self.name = name + self.repo = repo + self.meta = None self.children = [] # Detect type @@ -275,26 +275,30 @@ class PackageTreeNode: return self.meta.get(key) -def cloneRepo(urlstr): +# Clones a repo from an unvalidated URL. +# Returns a tuple of path and repo on sucess. +# Throws `TaskError` on failure. +# Caller is responsible for deleting returned directory. +def cloneRepo(urlstr, ref=None, recursive=False): gitDir = tempfile.gettempdir() + "/" + randomString(10) err = None try: - git.Repo.clone_from(urlstr, gitDir, progress=None, env=None, depth=1) + repo = git.Repo.clone_from(urlstr, gitDir, progress=None, env=None, depth=1, recursive=recursive) + if ref is not None: + repo.create_head("myhead", ref).checkout() + return gitDir, repo except GitCommandError as e: # This is needed to stop the backtrace being weird err = e.stderr - if err is not None: - raise TaskError(err.replace("stderr: ", "") \ - .replace("Cloning into '" + gitDir + "'...", "") \ - .strip()) - - return gitDir + raise TaskError(err.replace("stderr: ", "") \ + .replace("Cloning into '" + gitDir + "'...", "") \ + .strip()) @celery.task() def getMeta(urlstr, author): - gitDir = cloneRepo(urlstr) + gitDir, _ = cloneRepo(urlstr, recursive=True) tree = PackageTreeNode(gitDir, author=author, repo=urlstr) shutil.rmtree(gitDir) @@ -320,24 +324,8 @@ def getMeta(urlstr, author): return result -@celery.task() -def makeVCSRelease(id, branch): - release = PackageRelease.query.get(id) - - if release is None: - raise TaskError("No such release!") - - if release.package is None: - raise TaskError("No package attached to release") - - url = urlparse(release.package.repo) - - urlmaker = None - if url.netloc == "github.com": - urlmaker = GithubURLMaker(url) - else: - raise TaskError("Unsupported repo") - +def makeVCSReleaseFromGithub(id, branch, release, url): + urlmaker = GithubURLMaker(url) if not urlmaker.isValid(): raise TaskError("Invalid github repo URL") @@ -356,6 +344,37 @@ def makeVCSRelease(id, branch): return release.url + +@celery.task() +def makeVCSRelease(id, branch): + release = PackageRelease.query.get(id) + if release is None: + raise TaskError("No such release!") + elif release.package is None: + raise TaskError("No package attached to release") + + urlmaker = None + url = urlparse(release.package.repo) + if url.netloc == "github.com": + return makeVCSReleaseFromGithub(id, branch, release, url) + else: + gitDir, repo = cloneRepo(release.package.repo, ref=branch, recursive=True) + + try: + filename = randomString(10) + ".zip" + destPath = os.path.join("app/public/uploads", filename) + with open(destPath, "wb") as fp: + repo.archive(fp) + + release.url = "/uploads/" + filename + print(release.url) + release.task_id = None + db.session.commit() + + return release.url + finally: + shutil.rmtree(gitDir) + @celery.task() def importRepoScreenshot(id): package = Package.query.get(id) @@ -363,7 +382,12 @@ def importRepoScreenshot(id): raise Exception("Unexpected none package") # Get URL Maker - gitDir = cloneRepo(package.repo) + try: + gitDir, _ = cloneRepo(package.repo) + except TaskError as e: + # ignore download errors + print(e) + return None # Find and import screenshot try: diff --git a/app/templates/packages/release_new.html b/app/templates/packages/release_new.html index eea9a5a..3578466 100644 --- a/app/templates/packages/release_new.html +++ b/app/templates/packages/release_new.html @@ -11,7 +11,7 @@ {{ render_field(form.title, placeholder="Human readable. Eg: 1.0.0 or 2018-05-28") }} {{ render_field(form.uploadOpt) }} - {% if package.canMakeReleaseFromVCS() %} + {% if package.repo %} {{ render_field(form.vcsLabel) }} {% endif %} {{ render_field(form.fileUpload) }} diff --git a/app/views/packages/releases.py b/app/views/packages/releases.py index 6d8691b..b6f5b20 100644 --- a/app/views/packages/releases.py +++ b/app/views/packages/releases.py @@ -52,8 +52,8 @@ def create_release_page(package): # Initial form class from post data and default data form = CreatePackageReleaseForm() - if package.canMakeReleaseFromVCS(): - form["uploadOpt"].choices = [("vcs", "From VCS Commit or Branch"), ("upload", "File Upload")] + if package.repo is not None: + form["uploadOpt"].choices = [("vcs", "From Git Commit or Branch"), ("upload", "File Upload")] if request.method != "POST": form["uploadOpt"].data = "vcs"