various improvements and license update

This commit is contained in:
Izalia Mae 2021-02-06 15:32:12 -05:00
parent 5a9b4d9bb1
commit 50a889c9b0
4 changed files with 231 additions and 87 deletions

66
LICENSE
View file

@ -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.

View file

@ -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)

View file

@ -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)

View file

@ -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