From 7e0f0d0fd8a2ad1d621e342e19155ab578539234 Mon Sep 17 00:00:00 2001 From: dgtlmoon Date: Tue, 22 Mar 2022 23:08:08 +0100 Subject: [PATCH] Microsoft Windows installation fixes (#492) --- .gitignore | 1 + MANIFEST.in | 2 +- README.md | 4 +- changedetection.py | 111 ++------------------------ changedetectionio/__init__.py | 7 +- changedetectionio/changedetection.py | 114 +++++++++++++++++++++++++++ changedetectionio/store.py | 2 +- setup.py | 6 +- 8 files changed, 131 insertions(+), 116 deletions(-) create mode 100755 changedetectionio/changedetection.py diff --git a/.gitignore b/.gitignore index fe896785..b0df9756 100644 --- a/.gitignore +++ b/.gitignore @@ -8,4 +8,5 @@ __pycache__ build dist venv +*.egg-info* .vscode/settings.json diff --git a/MANIFEST.in b/MANIFEST.in index 16459b79..aa5e9025 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -2,5 +2,5 @@ recursive-include changedetectionio/templates * recursive-include changedetectionio/static * include changedetection.py global-exclude *.pyc -global-exclude *node_modules* +global-exclude node_modules global-exclude venv \ No newline at end of file diff --git a/README.md b/README.md index 8eae318c..91e67b63 100644 --- a/README.md +++ b/README.md @@ -163,9 +163,9 @@ See the wiki https://github.com/dgtlmoon/changedetection.io/wiki/Proxy-configura Raspberry Pi and linux/arm/v6 linux/arm/v7 arm64 devices are supported! See the wiki for [details](https://github.com/dgtlmoon/changedetection.io/wiki/Fetching-pages-with-WebDriver) -## Windows native support? +## Windows support? -Sorry not yet :( https://github.com/dgtlmoon/changedetection.io/labels/windows +YES! See the wiki https://github.com/dgtlmoon/changedetection.io/wiki/Microsoft-Windows ## Support us diff --git a/changedetection.py b/changedetection.py index 90946089..9e76cc8c 100755 --- a/changedetection.py +++ b/changedetection.py @@ -1,110 +1,11 @@ #!/usr/bin/python3 -# Launch as a eventlet.wsgi server instance. - -import getopt -import os -import sys - -import eventlet -import eventlet.wsgi -import changedetectionio - -from changedetectionio import store - -def main(): - ssl_mode = False - host = '' - port = os.environ.get('PORT') or 5000 - do_cleanup = False - - # Must be absolute so that send_from_directory doesnt try to make it relative to backend/ - datastore_path = os.path.join(os.getcwd(), "datastore") - - try: - opts, args = getopt.getopt(sys.argv[1:], "Ccsd:h:p:", "port") - except getopt.GetoptError: - print('backend.py -s SSL enable -h [host] -p [port] -d [datastore path]') - sys.exit(2) - - create_datastore_dir = False - - for opt, arg in opts: - # if opt == '--purge': - # Remove history, the actual files you need to delete manually. - # for uuid, watch in datastore.data['watching'].items(): - # watch.update({'history': {}, 'last_checked': 0, 'last_changed': 0, 'previous_md5': None}) - - if opt == '-s': - ssl_mode = True - - if opt == '-h': - host = arg - - if opt == '-p': - port = int(arg) - - if opt == '-d': - datastore_path = arg - - # Cleanup (remove text files that arent in the index) - if opt == '-c': - do_cleanup = True - - # Create the datadir if it doesnt exist - if opt == '-C': - create_datastore_dir = True - - # isnt there some @thingy to attach to each route to tell it, that this route needs a datastore - app_config = {'datastore_path': datastore_path} - - if not os.path.isdir(app_config['datastore_path']): - if create_datastore_dir: - os.mkdir(app_config['datastore_path']) - else: - print ("ERROR: Directory path for the datastore '{}' does not exist, cannot start, please make sure the directory exists.\n" - "Alternatively, use the -C parameter.".format(app_config['datastore_path']),file=sys.stderr) - sys.exit(2) - - datastore = store.ChangeDetectionStore(datastore_path=app_config['datastore_path'], version_tag=changedetectionio.__version__) - app = changedetectionio.changedetection_app(app_config, datastore) - - # Go into cleanup mode - if do_cleanup: - datastore.remove_unused_snapshots() - - app.config['datastore_path'] = datastore_path - - - @app.context_processor - def inject_version(): - return dict(right_sticky="v{}".format(datastore.data['version_tag']), - new_version_available=app.config['NEW_VERSION_AVAILABLE'], - has_password=datastore.data['settings']['application']['password'] != False - ) - - # Proxy sub-directory support - # Set environment var USE_X_SETTINGS=1 on this script - # And then in your proxy_pass settings - # - # proxy_set_header Host "localhost"; - # proxy_set_header X-Forwarded-Prefix /app; - - if os.getenv('USE_X_SETTINGS'): - print ("USE_X_SETTINGS is ENABLED\n") - from werkzeug.middleware.proxy_fix import ProxyFix - app.wsgi_app = ProxyFix(app.wsgi_app, x_prefix=1, x_host=1) - - if ssl_mode: - # @todo finalise SSL config, but this should get you in the right direction if you need it. - eventlet.wsgi.server(eventlet.wrap_ssl(eventlet.listen((host, port)), - certfile='cert.pem', - keyfile='privkey.pem', - server_side=True), app) - - else: - eventlet.wsgi.server(eventlet.listen((host, int(port))), app) +# Entry-point for running from the CLI when not installed via Pip, Pip will handle the console_scripts entry_points's from setup.py +# It's recommended to use `pip3 install changedetection.io` and start with `changedetection.py` instead, it will be linkd to your global path. +# or Docker. +# Read more https://github.com/dgtlmoon/changedetection.io/wiki +from changedetectionio import changedetection if __name__ == '__main__': - main() + changedetection.main() diff --git a/changedetectionio/__init__.py b/changedetectionio/__init__.py index d4af9d0d..875a0dec 100644 --- a/changedetectionio/__init__.py +++ b/changedetectionio/__init__.py @@ -53,11 +53,10 @@ update_q = queue.Queue() notification_q = queue.Queue() -# Needs to be set this way because we also build and publish via pip -base_path = os.path.dirname(os.path.realpath(__file__)) app = Flask(__name__, - static_url_path="{}/static".format(base_path), - template_folder="{}/templates".format(base_path)) + static_url_path="", + static_folder="static", + template_folder="templates") # Stop browser caching of assets app.config['SEND_FILE_MAX_AGE_DEFAULT'] = 0 diff --git a/changedetectionio/changedetection.py b/changedetectionio/changedetection.py new file mode 100755 index 00000000..a959bc59 --- /dev/null +++ b/changedetectionio/changedetection.py @@ -0,0 +1,114 @@ +#!/usr/bin/python3 + +# Launch as a eventlet.wsgi server instance. + +import getopt +import os +import sys + +import eventlet +import eventlet.wsgi +from . import store, changedetection_app +from . import __version__ + +def main(): + ssl_mode = False + host = '' + port = os.environ.get('PORT') or 5000 + do_cleanup = False + datastore_path = None + + # On Windows, create and use a default path. + if os.name == 'nt': + datastore_path = os.path.expandvars(r'%APPDATA%\changedetection.io') + os.makedirs(datastore_path, exist_ok=True) + else: + # Must be absolute so that send_from_directory doesnt try to make it relative to backend/ + datastore_path = os.path.join(os.getcwd(), "../datastore") + + try: + opts, args = getopt.getopt(sys.argv[1:], "Ccsd:h:p:", "port") + except getopt.GetoptError: + print('backend.py -s SSL enable -h [host] -p [port] -d [datastore path]') + sys.exit(2) + + create_datastore_dir = False + + for opt, arg in opts: + # if opt == '--purge': + # Remove history, the actual files you need to delete manually. + # for uuid, watch in datastore.data['watching'].items(): + # watch.update({'history': {}, 'last_checked': 0, 'last_changed': 0, 'previous_md5': None}) + + if opt == '-s': + ssl_mode = True + + if opt == '-h': + host = arg + + if opt == '-p': + port = int(arg) + + if opt == '-d': + datastore_path = arg + + # Cleanup (remove text files that arent in the index) + if opt == '-c': + do_cleanup = True + + # Create the datadir if it doesnt exist + if opt == '-C': + create_datastore_dir = True + + # isnt there some @thingy to attach to each route to tell it, that this route needs a datastore + app_config = {'datastore_path': datastore_path} + + if not os.path.isdir(app_config['datastore_path']): + if create_datastore_dir: + os.mkdir(app_config['datastore_path']) + else: + print( + "ERROR: Directory path for the datastore '{}' does not exist, cannot start, please make sure the directory exists or specify a directory with the -d option.\n" + "Or use the -C parameter to create the directory.".format(app_config['datastore_path']), file=sys.stderr) + sys.exit(2) + + datastore = store.ChangeDetectionStore(datastore_path=app_config['datastore_path'], version_tag=__version__) + app = changedetection_app(app_config, datastore) + + # Go into cleanup mode + if do_cleanup: + datastore.remove_unused_snapshots() + + app.config['datastore_path'] = datastore_path + + + @app.context_processor + def inject_version(): + return dict(right_sticky="v{}".format(datastore.data['version_tag']), + new_version_available=app.config['NEW_VERSION_AVAILABLE'], + has_password=datastore.data['settings']['application']['password'] != False + ) + + # Proxy sub-directory support + # Set environment var USE_X_SETTINGS=1 on this script + # And then in your proxy_pass settings + # + # proxy_set_header Host "localhost"; + # proxy_set_header X-Forwarded-Prefix /app; + + if os.getenv('USE_X_SETTINGS'): + print ("USE_X_SETTINGS is ENABLED\n") + from werkzeug.middleware.proxy_fix import ProxyFix + app.wsgi_app = ProxyFix(app.wsgi_app, x_prefix=1, x_host=1) + + if ssl_mode: + # @todo finalise SSL config, but this should get you in the right direction if you need it. + eventlet.wsgi.server(eventlet.wrap_ssl(eventlet.listen((host, port)), + certfile='cert.pem', + keyfile='privkey.pem', + server_side=True), app) + + else: + eventlet.wsgi.server(eventlet.listen((host, int(port))), app) + + diff --git a/changedetectionio/store.py b/changedetectionio/store.py index 5e3902b8..a3649501 100644 --- a/changedetectionio/store.py +++ b/changedetectionio/store.py @@ -400,7 +400,7 @@ class ChangeDetectionStore: # system was out of memory, out of RAM etc with open(self.json_store_path+".tmp", 'w') as json_file: json.dump(data, json_file, indent=4) - os.rename(self.json_store_path+".tmp", self.json_store_path) + os.replace(self.json_store_path+".tmp", self.json_store_path) except Exception as e: logging.error("Error writing JSON!! (Main JSON file save was skipped) : %s", str(e)) diff --git a/setup.py b/setup.py index 3b73c93d..e6618942 100644 --- a/setup.py +++ b/setup.py @@ -32,11 +32,11 @@ setup( long_description_content_type='text/markdown', keywords='website change monitor for changes notification change detection ' 'alerts tracking website tracker change alert website and monitoring', - zip_safe=False, - entry_points={"console_scripts": ["changedetection.io=changedetection:main"]}, + entry_points={"console_scripts": ["changedetection.io=changedetectionio.changedetection:main"]}, + zip_safe=True, + scripts=["changedetection.py"], author='dgtlmoon', url='https://changedetection.io', - scripts=['changedetection.py'], packages=['changedetectionio'], include_package_data=True, install_requires=install_requires,