-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
159 additions
and
92 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
from __future__ import annotations | ||
|
||
from os import path, walk | ||
from subprocess import run | ||
from typing import TYPE_CHECKING | ||
|
||
from django.conf import settings | ||
|
||
from outdated.parser import LockFileParser | ||
|
||
if TYPE_CHECKING: | ||
from .outdated.models import Project | ||
|
||
|
||
class RepoDoesNotExist(FileNotFoundError): | ||
"""Raise when repository is not locally saved.""" | ||
|
||
|
||
class Tracker: | ||
def __init__(self, project: Project): | ||
self.project = project | ||
self.local_path = f"/projects/{self.project.clone_path}" | ||
|
||
def _run(self, command, fail_without_local_copy=False): | ||
if not self.has_local_copy and fail_without_local_copy: | ||
raise RepoDoesNotExist( | ||
f"Can't run {command} without local copy of {self.project.repo}" | ||
) | ||
return run(command, cwd=self.repository_path, capture_output=True, shell=True) | ||
|
||
def clone(self, force=False): | ||
if self.has_local_copy and not force: | ||
return | ||
if force: | ||
self.delete() | ||
self._run( | ||
f"git clone -n --depth 1 --filter=tree:0 {self.project.clone_url} {self.project.clone_path}" | ||
) | ||
self._run( | ||
f"git sparse-checkout set --no-cone {' '.join(settings.SUPPORTED_LOCK_FILES)}" | ||
) | ||
|
||
def checkout(self): | ||
return self._run("git checkout", True) | ||
|
||
def _get_lockfile(self, root, file): | ||
file_path = path.join(root, file) | ||
rel_file_path = path.relpath(file_path, self.local_path) | ||
with open(file_path, "r") as file_content: | ||
return {"name": rel_file_path, "data": file_content.read()} | ||
|
||
@property | ||
def lockfiles(self): | ||
if not self.has_local_copy: | ||
raise RepoDoesNotExist( | ||
f"Unable to retrieve lockfiles for {self.project.repo} because it is not saved locally." | ||
) | ||
|
||
lockfile_list = [] | ||
for root, _, files in walk(self.local_path): | ||
if ".git" in root: | ||
continue | ||
|
||
lockfile_list.extend([self._get_lockfile(root, file) for file in files]) | ||
|
||
return lockfile_list | ||
|
||
@property | ||
def has_local_copy(self): | ||
return path.exists(self.local_path) | ||
|
||
@property | ||
def repository_path(self): | ||
return self.local_path if self.has_local_copy else "/projects/" | ||
|
||
@property | ||
def has_changes(self): | ||
self._run("git fetch", True) | ||
result = self._run("git diff --quiet @{u}..") | ||
return bool(result.returncode) | ||
|
||
def sync(self, only_on_change=False): | ||
if not self.has_changes and only_on_change: | ||
return | ||
dependencies = LockFileParser(self.lockfiles).parse() | ||
self.project.versioned_dependencies.set(dependencies) | ||
|
||
def setup(self): | ||
self.clone() | ||
self.checkout() | ||
self.sync() | ||
|
||
def delete(self): | ||
self._run(f"rm -rf /projects/{self.project.clone_path}") |