various improvements and license update
This commit is contained in:
parent
5a9b4d9bb1
commit
50a889c9b0
66
LICENSE
66
LICENSE
|
@ -1,10 +1,24 @@
|
|||
pyReload
|
||||
Copyright Zoey Mae 2019
|
||||
PyReloader
|
||||
Copyright Zoey Mae 2021
|
||||
|
||||
NON-VIOLENT PUBLIC LICENSE v1
|
||||
NON-VIOLENT PUBLIC LICENSE v5
|
||||
|
||||
Preamble
|
||||
|
||||
The Non-Violent Public license is a freedom-respecting sharealike license
|
||||
for both the author of a work as well as those subject to a work. It aims
|
||||
to protect the basic rights of human beings from exploitation and the earth
|
||||
from plunder. It aims to ensure a copyrighted work is forever available
|
||||
for public use, modification, and redistribution under the same terms so
|
||||
long as the work is not used for harm. For more information about the NPL
|
||||
refer to the official webpage
|
||||
|
||||
Official Webpage: https://thufie.lain.haus/NPL.html
|
||||
|
||||
Terms and Conditions
|
||||
|
||||
THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS
|
||||
NON-VIOLENT PUBLIC LICENSE v1 ("LICENSE"). THE WORK IS PROTECTED BY
|
||||
NON-VIOLENT PUBLIC LICENSE v5 ("LICENSE"). THE WORK IS PROTECTED BY
|
||||
COPYRIGHT AND ALL OTHER APPLICABLE LAWS. ANY USE OF THE WORK OTHER THAN
|
||||
AS AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED. BY
|
||||
EXERCISING ANY RIGHTS TO THE WORK PROVIDED IN THIS LICENSE, YOU AGREE
|
||||
|
@ -38,8 +52,9 @@ AND CONDITIONS OF THIS LICENSE.
|
|||
timed-relation with a moving image ("synching") will be
|
||||
considered an Adaptation for the purpose of this License.
|
||||
|
||||
c. "Bodily Harm" means any action of one person towards another
|
||||
in an intentional manner.
|
||||
c. "Bodily Harm" means any physical hurt or injury to a person that
|
||||
interferes with the health or comfort of the person and that is more
|
||||
more than merely transient or trifling in nature.
|
||||
|
||||
d. "Collection" means a collection of literary or artistic
|
||||
works, such as encyclopedias and anthologies, or performances,
|
||||
|
@ -61,8 +76,7 @@ AND CONDITIONS OF THIS LICENSE.
|
|||
|
||||
f. "Incarceration" means confinement in a jail, prison, or any
|
||||
other place where individuals of any kind are held against
|
||||
either their will or the will of their legal guardians by physical
|
||||
means.
|
||||
either their will or the will of their legal guardians.
|
||||
|
||||
g. "Licensor" means the individual, individuals, entity or
|
||||
entities that offer(s) the Work under the terms of this License.
|
||||
|
@ -134,13 +148,28 @@ AND CONDITIONS OF THIS LICENSE.
|
|||
through which the Original Author and/or Distributor originally
|
||||
created, derived, and/or modified it.
|
||||
|
||||
o. "Surveilling" means the use of the Work to
|
||||
overtly or covertly observe persons or their activities.
|
||||
o. "Surveilling" means the use of the Work to either
|
||||
overtly or covertly observe and record persons and or their
|
||||
activities.
|
||||
|
||||
p. "Web Service" means the use of a piece of Software to
|
||||
interpret or modify information that is subsequently and directly
|
||||
served to users over the Internet.
|
||||
|
||||
q. "Discriminate" means the use of a work to differentiate between
|
||||
humans in a such a way which prioritizes some above others on the
|
||||
basis of percieved membership within certain groups.
|
||||
|
||||
r. "Hate Speech" means communication or any form
|
||||
of expression which is solely for the purpose of expressing hatred
|
||||
for some group or advocating a form of Discrimination
|
||||
(to Discriminate per definition in (q)) between humans.
|
||||
|
||||
s. "Coercion" means leveraging of the threat of force or use of force
|
||||
to intimidate a person in order to gain compliance, or to offer
|
||||
large incentives which aim to entice a person to act against their
|
||||
will.
|
||||
|
||||
2. FAIR DEALING RIGHTS
|
||||
|
||||
Nothing in this License is intended to reduce, limit, or restrict any
|
||||
|
@ -177,7 +206,6 @@ AND CONDITIONS OF THIS LICENSE.
|
|||
exercise the rights in other media and formats. Subject to
|
||||
Section 8(g), all rights not expressly granted by Licensor are
|
||||
hereby reserved.
|
||||
|
||||
|
||||
4. RESTRICTIONS
|
||||
|
||||
|
@ -227,20 +255,24 @@ AND CONDITIONS OF THIS LICENSE.
|
|||
|
||||
i. You do not use the Work for the purpose of inflicting
|
||||
Bodily Harm on human beings (subject to criminal
|
||||
prosecution or otherwise) outside of providing medical aid.
|
||||
prosecution or otherwise) outside of providing medical aid
|
||||
or undergoing a voluntary procedure under no form of
|
||||
Coercion.
|
||||
ii.You do not use the Work for the purpose of Surveilling
|
||||
or tracking individuals for financial gain.
|
||||
iii. You do not use the Work in an Act of War.
|
||||
iv. You do not use the Work for the purpose of supporting
|
||||
an Act of War.
|
||||
or profiting from an Act of War.
|
||||
v. You do not use the Work for the purpose of Incarceration.
|
||||
vi. You do not use the Work for the purpose of extracting
|
||||
oil, gas, or coal.
|
||||
vi. You do not use the Work for the purpose of extracting,
|
||||
processing, or refining, oil, gas, or coal. Or to in any other
|
||||
way to deliberately pollute the environment as a byproduct
|
||||
of manufacturing or irresponsible disposal of hazardous materials.
|
||||
vii. You do not use the Work for the purpose of
|
||||
expediting, coordinating, or facilitating paid work
|
||||
undertaken by individuals under the age of 12 years.
|
||||
viii. You do not use the Work to either discriminate or
|
||||
spread hate speech on the basis of sex, sexual orientation,
|
||||
viii. You do not use the Work to either Discriminate or
|
||||
spread Hate Speech on the basis of sex, sexual orientation,
|
||||
gender identity, race, age, disability, color, national origin,
|
||||
religion, or lower economic status.
|
||||
|
||||
|
|
|
@ -1,9 +1,109 @@
|
|||
'''
|
||||
PyReloader
|
||||
Copyright (C) 2019 Zoey Mae
|
||||
Licensed under the NPLv4+
|
||||
https://git.pixie.town/thufie/NPL/raw/branch/master/NPL.txt
|
||||
'''
|
||||
__script__ = 'PyReloader'
|
||||
__version__ = (0, 3, 0)
|
||||
__year__ = 2021
|
||||
__author__ = 'Zoey Mae'
|
||||
__url__ = 'htts://git.barkshark.xyz/izaliamae/reloader'
|
||||
__license__ = 'Non-Violent Public License v5'
|
||||
__license_url__ = 'https://git.pixie.town/thufie/NPL/src/tag/5/NPL.txt'
|
||||
|
||||
__version__ = (0, 2, 1)
|
||||
__all__ = ['script']
|
||||
|
||||
class DotDict(dict):
|
||||
def __init__(self, value=None, **kwargs):
|
||||
super().__init__()
|
||||
|
||||
if type(value) in [str, bytes]:
|
||||
self.fromJson(value)
|
||||
|
||||
elif type(value) in [dict, DotDict]:
|
||||
self.update(value)
|
||||
|
||||
elif value:
|
||||
raise TypeError('The value must be a JSON string, dict, or another DotDict object, not', value.__class__)
|
||||
|
||||
if kwargs:
|
||||
self.update(kwargs)
|
||||
|
||||
|
||||
def __getattr__(self, key):
|
||||
try:
|
||||
val = super().__getattribute__(key)
|
||||
|
||||
except AttributeError:
|
||||
val = self.get(key, KeyError)
|
||||
|
||||
if val == KeyError:
|
||||
raise KeyError(f'Invalid key: {key}')
|
||||
|
||||
return DotDict(val) if type(val) == dict else val
|
||||
|
||||
|
||||
def __delattr__(self, key):
|
||||
if self.get(key):
|
||||
del self[key]
|
||||
|
||||
super().__delattr__(key)
|
||||
|
||||
|
||||
def __setattr__(self, key, value):
|
||||
if key.startswith('_'):
|
||||
super().__setattr__(key, value)
|
||||
|
||||
else:
|
||||
super().__setitem__(key, value)
|
||||
|
||||
|
||||
def __parse_item__(self, k, v):
|
||||
if type(v) == dict:
|
||||
v = DotDict(v)
|
||||
|
||||
if not k.startswith('_'):
|
||||
return (k, v)
|
||||
|
||||
|
||||
def get(self, key, default=None):
|
||||
value = super().get(key, default)
|
||||
return DotDict(value) if type(value) == dict else value
|
||||
|
||||
|
||||
def items(self):
|
||||
data = []
|
||||
|
||||
for k, v in super().items():
|
||||
new = self.__parse_item__(k, v)
|
||||
|
||||
if new:
|
||||
data.append(new)
|
||||
|
||||
return data
|
||||
|
||||
|
||||
def values(self):
|
||||
return list(super().values())
|
||||
|
||||
|
||||
def keys(self):
|
||||
return list(super().keys())
|
||||
|
||||
|
||||
def asDict(self):
|
||||
return dict(self)
|
||||
|
||||
|
||||
def toJson(self, indent=None, **kwargs):
|
||||
data = {}
|
||||
|
||||
for k,v in self.items():
|
||||
if type(k) in [DotDict, Path, Pathlib]:
|
||||
k = str(k)
|
||||
|
||||
if type(v) in [DotDict, Path, Pathlib]:
|
||||
v = str(v)
|
||||
|
||||
data[k] = v
|
||||
|
||||
return json.dumps(data, indent=indent, **kwargs)
|
||||
|
||||
|
||||
def fromJson(self, string):
|
||||
data = json.loads(string)
|
||||
self.update(data)
|
||||
|
|
|
@ -1,36 +1,47 @@
|
|||
import os, sys, logging as logger
|
||||
import os, shlex, sys, logging as logger
|
||||
|
||||
from configobj import ConfigObj
|
||||
from pathlib import Path
|
||||
|
||||
from . import DotDict
|
||||
|
||||
|
||||
path = os.getcwd()
|
||||
config_file = f'{path}/reload.cfg'
|
||||
config = ConfigObj(indent_type='\t')
|
||||
config.filename = config_file
|
||||
defaults = {
|
||||
'exec': 'insert command here',
|
||||
'path': None,
|
||||
'watch_ext': ['py', 'env'],
|
||||
'ignore_dirs': ['build', 'config', 'data'],
|
||||
'ignore_files': ['reload.py', 'test.py'],
|
||||
'log_level': 'INFO'
|
||||
}
|
||||
|
||||
|
||||
if os.path.isfile(config_file) == False:
|
||||
configpath = Path.cwd().joinpath('reload.cfg')
|
||||
configfile = ConfigObj(indent_type='\t')
|
||||
configfile.filename = str(configpath)
|
||||
|
||||
if not configpath.exists():
|
||||
print('Cannot find "reload.cfg" in working directory. Creating template and exiting...')
|
||||
|
||||
cfg = {
|
||||
'exec': 'insert command here',
|
||||
'watch_ext': ['py', 'env'],
|
||||
'ignore_dirs': ['build', 'config', 'data'],
|
||||
'ignore_files': ['reload.py', 'test.py'],
|
||||
'log_level': 'INFO'
|
||||
}
|
||||
for setting in defaults:
|
||||
configfile[setting] = cfg[setting]
|
||||
|
||||
for setting in cfg:
|
||||
config[setting] = cfg[setting]
|
||||
try:
|
||||
configfile.write()
|
||||
except PermissionError:
|
||||
print('Failed to write config file because of permission error:', configpath)
|
||||
|
||||
config.write()
|
||||
sys.exit()
|
||||
|
||||
config.reload()
|
||||
configfile.reload()
|
||||
|
||||
config = DotDict()
|
||||
|
||||
for key in config:
|
||||
if config.get(key) == None:
|
||||
for k,v in defaults.items():
|
||||
value = configfile.get(k)
|
||||
key = k
|
||||
|
||||
if value == None:
|
||||
if key == 'exec':
|
||||
print('You forgot to specify a command')
|
||||
sys.exit()
|
||||
|
@ -39,25 +50,33 @@ for key in config:
|
|||
print('You forgot to specify a file extension to watch')
|
||||
sys.exit()
|
||||
|
||||
config[key] = None
|
||||
if key == 'path':
|
||||
value = os.getcwd()
|
||||
|
||||
elif type(config[key]) != list and key != 'log_level':
|
||||
config[key] = [s for s in config[key].split(' ')]
|
||||
if key == 'exec':
|
||||
value = shlex.split(value)
|
||||
|
||||
elif k == 'path':
|
||||
value = Path(value).resolve()
|
||||
|
||||
elif type(v) != list and key != 'log_level':
|
||||
value = [s.strip() for s in value.split(',')]
|
||||
|
||||
config[key] = value
|
||||
|
||||
|
||||
command = config['exec']
|
||||
extensions = config['watch_ext']
|
||||
dirs = config['ignore_dirs']
|
||||
files = config['ignore_files']
|
||||
loglevel = config['log_level'].upper()
|
||||
if not config.path.exists():
|
||||
print('Watch path doesn\'t exist:', config.path)
|
||||
sys.exit()
|
||||
|
||||
|
||||
if len(sys.argv) > 1:
|
||||
command += sys.argv[1:]
|
||||
|
||||
logging = logger.getLogger()
|
||||
logging = logger.getLogger('reloader')
|
||||
logging.setLevel(logger.DEBUG)
|
||||
console = logger.StreamHandler()
|
||||
console.name = 'Console Log'
|
||||
console.level = eval(f'logger.{loglevel}')
|
||||
console.level = eval(f'logger.{config.log_level}')
|
||||
console.formatter = logger.Formatter('%(asctime)s WATCHER: %(message)s', '%H:%M:%S')
|
||||
logging.addHandler(console)
|
||||
|
|
|
@ -1,17 +1,12 @@
|
|||
import time
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import signal
|
||||
import sys
|
||||
import random
|
||||
import logging
|
||||
import os, random, re, signal, subprocess, sys, time
|
||||
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
from watchdog.observers import Observer
|
||||
from watchdog.events import FileSystemEventHandler
|
||||
from datetime import datetime
|
||||
|
||||
from . import config
|
||||
from .config import config, logging
|
||||
|
||||
|
||||
proc = None
|
||||
last_restart = None
|
||||
|
@ -29,8 +24,8 @@ def killProc(proc):
|
|||
time.sleep(1)
|
||||
sec += 1
|
||||
|
||||
if sec > 5:
|
||||
logging.error('Failed to terminate process. Killing process')
|
||||
if sec >= 5:
|
||||
logging.error('Failed to terminate. Killing process...')
|
||||
proc.kill()
|
||||
break
|
||||
|
||||
|
@ -52,9 +47,9 @@ def run(restart=False):
|
|||
killProc(proc)
|
||||
|
||||
try:
|
||||
proc = subprocess.Popen(config.command, preexec_fn=os.setpgrp)
|
||||
proc = subprocess.Popen(config.exec, preexec_fn=os.setpgrp)
|
||||
except FileNotFoundError:
|
||||
logging.error(f'Cannot find executable:', config.command)
|
||||
logging.error(f'Cannot find executable:', config.exec.join(' '))
|
||||
sys.exit()
|
||||
|
||||
last_restart = timestamp
|
||||
|
@ -63,43 +58,41 @@ def run(restart=False):
|
|||
|
||||
class MyHandler(FileSystemEventHandler):
|
||||
def on_any_event(self, event):
|
||||
path, ext = os.path.splitext(os.path.relpath(event.src_path))
|
||||
path = Path(event.src_path)
|
||||
name = path.name
|
||||
directory = str(path.parent).replace(str(config.path) + '/', '')
|
||||
ext = path.suffix.strip('.')
|
||||
|
||||
try:
|
||||
filepath, filename = path.rsplit('/', 1)
|
||||
except ValueError:
|
||||
filepath, filename = ('', path)
|
||||
logging.debug(f'{event.event_type}, {path}, {name}, {ext}')
|
||||
|
||||
# not sure why this doesn't work tbh
|
||||
#logging.debug(event.event_type, filepath, filename, ext)
|
||||
|
||||
logging.debug(f'{event.event_type}, {filepath}, {filename}, {ext}')
|
||||
|
||||
if event.event_type in ['modified', 'created'] and ext[1:] in config.extensions:
|
||||
if config.dirs:
|
||||
if any(path in filepath for path in config.dirs):
|
||||
if event.event_type in ['modified', 'created'] and ext in config.watch_ext:
|
||||
for direc in config.ignore_dirs:
|
||||
if direc in directory:
|
||||
logging.debug('Ignored directory:', directory)
|
||||
return
|
||||
|
||||
if config.files:
|
||||
if filename+ext in config.files:
|
||||
for filename in config.ignore_files:
|
||||
if name == filename:
|
||||
logging.debug('Ignored file name:', filename)
|
||||
return
|
||||
|
||||
run(restart=True)
|
||||
|
||||
|
||||
def main():
|
||||
logging.info('Starting process watcher')
|
||||
logging.debug(f'Watch dir: {config.path}')
|
||||
|
||||
run()
|
||||
|
||||
observer = Observer()
|
||||
observer.schedule(MyHandler(), config.path, recursive=True)
|
||||
logging.info('Starting process watcher')
|
||||
logging.debug(f'Watch dir: {config.path}')
|
||||
observer.schedule(MyHandler(), str(config.path), recursive=True)
|
||||
observer.start()
|
||||
|
||||
try:
|
||||
while True:
|
||||
time.sleep(random.randint(60 * 30, 60 * 60))
|
||||
logging.info('OwO what\'s this?')
|
||||
logging.info('*notices your running process* OwO what\'s this?')
|
||||
|
||||
except KeyboardInterrupt:
|
||||
pass
|
||||
|
|
Loading…
Reference in a new issue