Skip to content

Commit b46fb04

Browse files
committed
githubplugin: rework path and naming schemes, add error handling
1 parent 0fac7fa commit b46fb04

File tree

4 files changed

+86
-28
lines changed

4 files changed

+86
-28
lines changed

githubplugin/__init__.py

Lines changed: 59 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@
3939
from git import Repo
4040

4141

42+
#
43+
# this is NOT the plugin class...
44+
#
45+
4246
class GitHubHelper(object):
4347
""" Helper class for handling the GitHub API """
4448

@@ -268,14 +272,19 @@ def get_plugins_from(self, fork=None, owner='', branch='', fetch=False) -> list:
268272
return sorted(plugins)
269273

270274

275+
#
276+
# this IS the plugin class :)
277+
#
278+
279+
271280
class GithubPlugin(SmartPlugin):
272281
"""
273282
This class supports testing foreign plugins by letting the user select a
274283
shng plugins fork and branch, and then setting up a local repo containing
275284
that fork. Additionally, the specified plugin will be soft-linked into the
276285
"live" plugins repo worktree as a private plugin.
277286
"""
278-
PLUGIN_VERSION = '1.0.0'
287+
PLUGIN_VERSION = '1.0.1'
279288
REPO_DIR = 'priv_repos'
280289

281290
def loggerr(self, msg):
@@ -321,6 +330,9 @@ def __init__(self, sh):
321330
os.mkdir(self.repo_path)
322331

323332
self.gh_apikey = self.get_parameter_value('app_token')
333+
self.supermode = self.get_parameter_value('supermode') == "'I KNOW WHAT I'M DOING!'"
334+
if self.supermode:
335+
self.logger.warning('supermode active, be very careful...')
324336
self.gh = GitHubHelper(self._sh.shtime, apikey=self.gh_apikey, logger=self.logger)
325337

326338
self.init_webinterface(WebInterface)
@@ -338,10 +350,10 @@ def read_repos_from_dir(self, exc=False):
338350
return
339351

340352
self.logger.debug('checking plugin links')
341-
pathlist = Path(self.plg_path).glob('priv_*')
353+
pathlist = Path(self.plg_path).glob('*')
342354
for item in pathlist:
343355
if not item.is_symlink():
344-
self.logger.debug(f'ignoring {item}, is not symlink')
356+
# self.logger.debug(f'ignoring {item}, is not symlink')
345357
continue
346358
target = os.path.join(self.plg_path, os.readlink(str(item)))
347359
if not os.path.isdir(target):
@@ -373,8 +385,7 @@ def read_repos_from_dir(self, exc=False):
373385
repo_path = os.path.join(self.repo_path, owner)
374386
wt_path = os.path.join(self.repo_path, f'{owner}_wt_{branch}')
375387

376-
# use part of link name after ".../plugins/priv_"
377-
name = str(item)[len(self.plg_path) + 6:]
388+
name = str(item)[len(self.plg_path) + 1:]
378389

379390
self.repos[name] = {
380391
'plugin': plugin,
@@ -391,6 +402,7 @@ def read_repos_from_dir(self, exc=False):
391402
'repo': repo,
392403
}
393404
self.repos[name]['clean'] = self.is_repo_clean(name, exc)
405+
self.logger.info(f'added plugin {plugin} with name {name} in {item}')
394406

395407
def check_for_repo_name(self, name) -> bool:
396408
""" check if name exists in repos or link exists """
@@ -403,13 +415,22 @@ def check_for_repo_name(self, name) -> bool:
403415
def create_repo(self, name, owner, plugin, branch=None, rename=False) -> bool:
404416
""" create repo from given parameters """
405417

406-
if not rename:
407-
try:
408-
self.check_for_repo_name(name)
409-
except Exception as e:
410-
self.loggerr(e)
418+
if any(x in name for x in ['/', '..']) or name == self.REPO_DIR:
419+
self.loggerr(f'Invalid characters in name {name} (no dirs, not "{self.REPO_DIR}")')
420+
return False
421+
422+
if not self.supermode:
423+
if not name.startswith('priv_'):
424+
self.loggerr(f'Invalid name, must start with "priv_"')
411425
return False
412426

427+
if not rename:
428+
try:
429+
self.check_for_repo_name(name)
430+
except Exception as e:
431+
self.loggerr(e)
432+
return False
433+
413434
if not owner or not plugin:
414435
self.loggerr(f'Insufficient parameters, github user {owner} or plugin {plugin} empty, unable to fetch repo, aborting.')
415436
return False
@@ -439,7 +460,7 @@ def create_repo(self, name, owner, plugin, branch=None, rename=False) -> bool:
439460
repo['rel_wt_path'] = os.path.join('..', f'{owner}_wt_{branch}')
440461

441462
# set link location from plugin name
442-
repo['link'] = os.path.join(self.plg_path, f'priv_{name}')
463+
repo['link'] = os.path.join(self.plg_path, name)
443464
repo['rel_link_path'] = os.path.join(self.REPO_DIR, f'{owner}_wt_{branch}', plugin)
444465

445466
# make plugins/priv_repos if not present
@@ -472,6 +493,7 @@ def create_repo(self, name, owner, plugin, branch=None, rename=False) -> bool:
472493
repo['repo'] = Repo.clone_from(repo['url'], repo['repo_path'])
473494
except Exception as e:
474495
self.loggerr(f'error while cloning: {e}')
496+
return False
475497

476498
# fetch repo data
477499
self.logger.debug('fetching from origin...')
@@ -515,24 +537,44 @@ def create_repo(self, name, owner, plugin, branch=None, rename=False) -> bool:
515537

516538
repo['clean'] = True
517539

518-
if rename:
519-
self.logger.debug(f'renaming old link priv_{name}')
520-
if not self._move_old_link(name):
521-
self.loggerr(f'unable to move old link priv_{name}, installation needs to be repaired manually')
540+
# try to rename if requested or in supermode
541+
if rename or self.supermode:
542+
self.logger.debug(f'renaming old link {repo["link"]}')
543+
if not self._move_old_link(repo['link']):
544+
# moving not possible...
545+
if not self.supermode:
546+
# quit in normal mode
547+
self.loggerr(f'unable to move old link {repo["link"]}, installation needs to be repaired manually')
548+
return False
549+
else:
550+
# delete in supermode
551+
self.logger.warning(f'unable to move old link {repo["link"]}, deleting it')
552+
if os.path.isdir(repo['link']):
553+
self._rmtree(repo['link'])
554+
else:
555+
os.path.delete(repo['link'])
556+
if os.path.exists(repo['link']):
557+
self.loggerr(f'error removing old link/dir {repo["link"]}')
558+
return False
522559

523560
self.logger.debug(f'creating link {repo["link"]} to {repo["rel_link_path"]}...')
524561
try:
525562
os.symlink(repo['rel_link_path'], repo['link'])
526563
except FileExistsError:
527564
self.loggerr(f'plugin link {repo["link"]} was created by someone else while we were setting up repo. Not overwriting, check link file manually')
565+
return False
528566

529567
self.repos[name] = repo
530568

531569
return True
532570

533571
def _move_old_link(self, name) -> bool:
572+
if not self.supermode and not os.path.basename(name).startswith('priv_'):
573+
self.loggerr(f'unable to move plugin with illegal name {name}')
574+
return False
575+
534576
""" rename old plugin link or folder and repo entry """
535-
link = os.path.join(self.plg_path, f'priv_{name}')
577+
link = os.path.join(self.plg_path, name)
536578
if not os.path.exists(link):
537579
self.logger.debug(f'old link/folder not found: {link}')
538580
return True
@@ -553,7 +595,7 @@ def _move_old_link(self, name) -> bool:
553595
os.rename(link, newlink)
554596
self.logger.debug(f'renamed {link} to {newlink}')
555597
try:
556-
# try to move repo entry to new name
598+
# try to move repo entry to new name (if repo exists)
557599
# ignore if repo name is not existent
558600
name_new = f'{name}_{ver}'
559601
self.repos[name_new] = self.repos[name]

githubplugin/plugin.yaml

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ plugin:
1212
# documentation: '' # An url to optional plugin doc - NOT the url to user_doc!!!
1313
# support: https://knx-user-forum.de/forum/supportforen/smarthome-py
1414

15-
version: 1.0.0 # Plugin version (must match the version specified in __init__.py)
15+
version: 1.0.1 # Plugin version (must match the version specified in __init__.py)
1616

1717
# these min/max-versions MUST be given in quotes, or e.g. 3.10 will be interpreted as 3.1 (3.1 < 3.9 < 3.10)
1818
sh_minversion: '1.10' # minimum shNG version to use this plugin
@@ -34,6 +34,14 @@ parameters:
3434
de: 'App-Token zum Zugriff auf GitHub (optional)'
3535
en: 'App token for accessing GitHub (optional)'
3636

37+
# allow arbitrary targets to be set and overwritten. Do not use this.
38+
supermode:
39+
type: str
40+
default: ''
41+
description:
42+
de: 'Nur zu Entwicklungszwecken. Nicht verwenden.'
43+
en: 'Only for development, do not use.'
44+
3745

3846
item_attributes: NONE
3947

githubplugin/webif/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,9 @@ def getNameSuggestion(self):
216216
json = cherrypy.request.json
217217
plugin = json.get('plugin')
218218

219+
if self.plugin.supermode:
220+
return {"operation": "request", "result": "success", "name": plugin}
221+
219222
count = ''
220223
while os.path.exists(os.path.join(self.plugin.plg_path, f'priv_{plugin}{count}')) and int('0' + count) < 20:
221224
count = str(int('0' + count) + 1)

githubplugin/webif/templates/index.html

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -145,8 +145,8 @@
145145
</select>
146146
<button id='btn-ref-plugin' type="button" class="btn btn-shng btn-sm" onclick="javascript:refetch('plugin');">&#8635;</i></button>
147147
</td>
148-
<td style='padding-left: 15px;'>Pluginname: priv_</td>
149-
<td><input id='name' disabled /></td>
148+
<td style='padding-left: 15px;'>Pluginname: </td>
149+
<td><input id='name' disabled/></td>
150150
<td style='padding-left: 15px;'>
151151
<button id='btn-plugin' disabled type="button" class="btn btn-shng btn-sm" onclick="javascript:selectPlugin(this);">Auswählen</button>
152152
</td>
@@ -168,6 +168,9 @@
168168
{{ super() }}
169169
<script type="text/javascript">
170170

171+
var supermode = {% if p.supermode %}true{% else %}false{% endif %};
172+
var plg_prefix = "{% if not p.supermode %}priv_{% endif %}";
173+
171174
var rateInterval = null;
172175

173176
function handleUpdatedData(response, dataSet='overview') {
@@ -456,15 +459,17 @@
456459
var plugin = document.getElementById('plugin').value;
457460

458461
if (plugin != '') {
459-
document.getElementById('name').value = plugin;
460-
sendData("getNameSuggestion", {"plugin": plugin},
461-
function(response) {},
462-
function(response) {
463-
if (response["name"] != undefined && response["name"] != "") {
464-
document.getElementById('name').value = response["name"];;
462+
document.getElementById('name').value = plg_prefix + plugin;
463+
if (!supermode) {
464+
sendData("getNameSuggestion", {"plugin": plugin},
465+
function(response) {},
466+
function(response) {
467+
if (response["name"] != undefined && response["name"] != "") {
468+
document.getElementById('name').value = plg_prefix + response["name"];
469+
}
465470
}
466-
}
467-
);
471+
);
472+
};
468473
document.getElementById('name').disabled = false;
469474
document.getElementById('btn-plugin').disabled = false;
470475
}

0 commit comments

Comments
 (0)