poikilos
3 years ago
1 changed files with 216 additions and 0 deletions
@ -0,0 +1,216 @@ |
|||||
|
#!/usr/bin/env python3 |
||||
|
''' |
||||
|
Title: pyissuesyncd |
||||
|
(c) 2021 Jake "Poikilos" Gustafson |
||||
|
|
||||
|
|
||||
|
Purpose: |
||||
|
This python-based daemon synchronizes issues (one-way) from one |
||||
|
repository to another. |
||||
|
|
||||
|
|
||||
|
License: |
||||
|
See the license file in the included EnlivenMinetest directory or at |
||||
|
[EnlivenMinetest](https://github.com/poikilos/EnlivenMinetest) |
||||
|
|
||||
|
|
||||
|
Outputs: |
||||
|
data_directory: The data directory for this service daemon is |
||||
|
os.path.join(profile, ".cache", "pyissuesyncd"). |
||||
|
|
||||
|
|
||||
|
required arguments: |
||||
|
--dst-repo (or set the DST_REPO environment variable) |
||||
|
Issues and dependent data will be overwritten at this API URL. |
||||
|
|
||||
|
|
||||
|
optional arguments: |
||||
|
Environment variables get be set, but a CLI argument will override the |
||||
|
corresponding variable noted below in all caps. |
||||
|
|
||||
|
The two _CACHE directories below are used as the single_cache option |
||||
|
for the Repo (see enissue.py's Repo class for documentation). |
||||
|
|
||||
|
--src-cache: Set the directory to store a cached version of the source repo's data. |
||||
|
* defaults to SRC_CACHE or os.path.join(data_directory, "source") |
||||
|
|
||||
|
--dst-cache: Set the directory to store a cached version of the destination repo's data. |
||||
|
* defaults to DST_CACHE or os.path.join(data_directory, "destination") |
||||
|
|
||||
|
|
||||
|
Examples: |
||||
|
DST_REPO=https://example.com/git/repo pyissuesyncd |
||||
|
pyissuesyncd --dst-repo https://example.com/git/repo |
||||
|
|
||||
|
''' |
||||
|
import os |
||||
|
import sys |
||||
|
import json |
||||
|
# see <https://stackoverflow.com/questions/5574702/how-to-print-to-stderr-in-python> |
||||
|
def error(*args, **kwargs): |
||||
|
print(*args, file=sys.stderr, **kwargs) |
||||
|
|
||||
|
|
||||
|
myFilePath = os.path.realpath(__file__) |
||||
|
me = os.path.basename(__file__) |
||||
|
myDir = os.path.dirname(myFilePath) |
||||
|
|
||||
|
try: |
||||
|
import enissue |
||||
|
except ModuleNotFoundError as ex: |
||||
|
PATH = os.environ.get("PATH") |
||||
|
found_d = None |
||||
|
if PATH is not None: |
||||
|
more_paths = PATH.split(os.pathsep) |
||||
|
# ^ pathsep such as ':' (NOT dirsep such as '/'!) |
||||
|
more_paths |
||||
|
for this_d in more_paths: |
||||
|
tryF = os.path.join(this_d, "enissue.py") |
||||
|
if os.path.isfile(tryF): |
||||
|
found_d = this_d |
||||
|
break |
||||
|
if found_d is not None: |
||||
|
sys.path.append(found_d) |
||||
|
print("* detected enissue.py in {}".format(found_d)) |
||||
|
# print("path: {}".format(sys.path)) |
||||
|
|
||||
|
try: |
||||
|
import eni |
||||
|
except ModuleNotFoundError as ex2: |
||||
|
error(ex2) |
||||
|
print("{} must be in the same directory as enissue.py or in" |
||||
|
" PATH".format(me)) |
||||
|
sys.exit(1) |
||||
|
else: |
||||
|
print("{} must be in the same directory as enissue.py or in" |
||||
|
" PATH".format(me)) |
||||
|
raise ex |
||||
|
|
||||
|
from enissue import Repo |
||||
|
|
||||
|
data_directory = os.path.join(Repo.profile, ".cache", "pyissuesyncd") |
||||
|
|
||||
|
def get_issue(repo, options, issue_no): |
||||
|
results, err = repo.load_issues( |
||||
|
options, |
||||
|
issue_no=issue_no, |
||||
|
) |
||||
|
if results is None: |
||||
|
if err is not None: |
||||
|
if repo.ERROR_410 in err: |
||||
|
# The issue was deleted |
||||
|
pass |
||||
|
error(err) |
||||
|
return None, err |
||||
|
else: |
||||
|
msg = ("Unknown error: Results should not be None unless" |
||||
|
" there is an error (issue_no={})." |
||||
|
"".format(issue_no)) |
||||
|
return None, msg |
||||
|
elif not isinstance(results, list): |
||||
|
raise RuntimeError("Results must be a list even if there is" |
||||
|
" only one result.") |
||||
|
elif len(results) > 1: |
||||
|
raise RuntimeError("Results should have" |
||||
|
" only one result.") |
||||
|
issue = results[0] |
||||
|
''' |
||||
|
match = repo.get_match( |
||||
|
mode, |
||||
|
issue_no=issue_no, |
||||
|
match_all_labels_lower=match_all_labels_lower, |
||||
|
) |
||||
|
matching_issue = match['issue'] |
||||
|
if matching_issue is not None: |
||||
|
repo.show_issue( |
||||
|
matching_issue, |
||||
|
refresh=False, |
||||
|
never_expire=options.get('never_expire') is True, |
||||
|
) |
||||
|
''' |
||||
|
return issue, None |
||||
|
|
||||
|
|
||||
|
def start_issuesyncd(src_options, dst_options): |
||||
|
# src_never_expire = src_options.get('never_expire') is True |
||||
|
issue_no = 1 |
||||
|
# while True: |
||||
|
src_repo = Repo(src_options) |
||||
|
src_issue, err = get_issue(src_repo, src_options, issue_no) |
||||
|
print("src_issue:") |
||||
|
print(json.dumps(src_issue, indent=2)) |
||||
|
|
||||
|
enissue.set_verbose(True) |
||||
|
dst_repo = Repo(dst_options) |
||||
|
dst_issue, err = get_issue(dst_repo, dst_options, issue_no) |
||||
|
print("dst_issue:") |
||||
|
print(json.dumps(dst_issue, indent=2)) |
||||
|
|
||||
|
issue_no += 1 |
||||
|
|
||||
|
def usage(): |
||||
|
print(__doc__) |
||||
|
|
||||
|
if __name__ == "__main__": |
||||
|
src_options = { |
||||
|
'repo_url': "https://github.com/poikilos/EnlivenMinetest", |
||||
|
'never_expire': True, |
||||
|
'quiet': True, |
||||
|
} |
||||
|
dst_options = { |
||||
|
'never_expire': True, |
||||
|
'quiet': True, |
||||
|
} |
||||
|
DST_REPO = os.environ.get("DST_REPO") |
||||
|
if DST_REPO is not None: |
||||
|
dst_options['repo_url'] = DST_REPO |
||||
|
del DST_REPO |
||||
|
SRC_REPO = os.environ.get("SRC_REPO") |
||||
|
if DST_REPO is not None: |
||||
|
src_options['repo_url'] = SRC_REPO |
||||
|
del SRC_REPO |
||||
|
|
||||
|
SRC_CACHE = os.environ.get("SRC_CACHE") |
||||
|
if SRC_CACHE is None: |
||||
|
SRC_CACHE = os.path.join(data_directory, "source") |
||||
|
|
||||
|
DST_CACHE = os.environ.get("DST_CACHE") |
||||
|
if DST_CACHE is None: |
||||
|
DST_CACHE = os.path.join(data_directory, "destination") |
||||
|
|
||||
|
prev_arg = None |
||||
|
|
||||
|
manual_args = ['--dst-repo', '--src-repo', '--src-cache', '--dst-cache'] |
||||
|
|
||||
|
for arg in sys.argv[1:]: |
||||
|
if prev_arg == "--dst-repo": |
||||
|
dst_options['repo_url'] = arg |
||||
|
elif prev_arg == "--src-repo": |
||||
|
src_options['repo_url'] = arg |
||||
|
elif prev_arg == "--src_cache": |
||||
|
SRC_CACHE = arg |
||||
|
elif prev_arg == "--dst_cache": |
||||
|
DST_CACHE = arg |
||||
|
elif arg in manual_args: |
||||
|
pass |
||||
|
else: |
||||
|
usage() |
||||
|
error("Error: The argument is not valid: {}".format(arg)) |
||||
|
sys.exit(1) |
||||
|
prev_arg = arg |
||||
|
|
||||
|
src_options['single_cache'] = SRC_CACHE |
||||
|
dst_options['single_cache'] = DST_CACHE |
||||
|
|
||||
|
|
||||
|
error("SRC_REPO (--src-repo) is {}" |
||||
|
"".format(src_options.get('repo_url'))) |
||||
|
error("DST_REPO (--dst-repo) is {}" |
||||
|
"".format(dst_options.get('repo_url'))) |
||||
|
if dst_options.get('repo_url') is None: |
||||
|
error("Error: You must set DST_REPO in the environment or specify a url after --dst-repo") |
||||
|
sys.exit(1) |
||||
|
|
||||
|
start_issuesyncd(src_options, dst_options) |
||||
|
|
||||
|
|
Loading…
Reference in new issue