Switch to hand-rolled logging
authorJakob <jakob@jcornell.net>
Sun, 1 Dec 2019 22:12:40 +0000 (16:12 -0600)
committerJakob <jakob@jcornell.net>
Sun, 1 Dec 2019 22:12:40 +0000 (16:12 -0600)
api.py
auth.py
common.py
main.py

diff --git a/api.py b/api.py
index 13bc80c1b9964d9f2775d6d7a0d4adddaeafec8c..fdee4c7531202cd85692a7fb1b19d65c2d52497e 100644 (file)
--- a/api.py
+++ b/api.py
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <https://www.gnu.org/licenses/>.
 
-from collections import namedtuple
 import json
 from pathlib import PurePosixPath
-from urllib.parse import urlencode as mk_qs
 import urllib.request
 
-import auth
 import util
 
 def walk_pages(opener, url):
diff --git a/auth.py b/auth.py
index b91b09e7c152d4216b5b8b931ee412d3babff7ba..269991de52803e7523b098bc8141ca9cc3fa2713 100644 (file)
--- a/auth.py
+++ b/auth.py
@@ -22,7 +22,7 @@ from pathlib import PurePosixPath
 import urllib.parse
 import urllib.request
 
-import common
+from common import log
 import util
 
 ADDRESS = 'localhost'
@@ -31,8 +31,6 @@ ENDPOINT = '/redirection_endpoint'
 
 TIMEOUT = timedelta(minutes = 30)
 
-LOGGER = common.LOGGER.getChild('auth')
-
 class OauthCodeRequestHandler(http.server.BaseHTTPRequestHandler):
        LANDING_PATH = '/landing'
 
@@ -124,7 +122,7 @@ class OauthHandler(urllib.request.BaseHandler):
        def _handle(self, request):
                token_doc = self.storage_mgr.get('authInfo')
                if not token_doc:
-                       LOGGER.info("No stored access token. Requesting a new token.")
+                       log('info', "No stored access token. Requesting a new token.")
                        token_doc = get_access_token(self.storage_mgr, self.api_iface)
                        self.storage_mgr['authInfo'] = token_doc
                self._set_auth_header(request, token_doc)
@@ -134,7 +132,7 @@ class OauthHandler(urllib.request.BaseHandler):
        https_request = _handle
 
        def http_error_401(self, request, fp, code, msg, headers):
-               LOGGER.info("Access token expired or revoked. Requesting a new token.")
+               log('info', "Access token expired or revoked. Requesting a new token.")
                token_doc = get_access_token(self.storage_mgr, self.api_iface)
                self.storage_mgr['authInfo'] = token_doc
                self._set_auth_header(request, token_doc)
@@ -177,7 +175,7 @@ def get_access_token(storage_mgr, api_iface):
                if resp.status == 200:
                        token_doc = body
                else:
-                       LOGGER.info("Stored refresh token rejected. Obtaining new authorization code.")
+                       log('info', "Stored refresh token rejected. Obtaining new authorization code.")
                        assert resp.status == 400
 
        if token_doc is None:
@@ -205,10 +203,10 @@ def get_access_token(storage_mgr, api_iface):
                )
                Thread(target = server.serve_forever, daemon = True).start()
 
-               LOGGER.info("Attempting to launch a web browser to authorize the application…")
+               log('info', "Attempting to launch a web browser to authorize the application…")
                if not webbrowser.open(user_url):
-                       LOGGER.info("Failed to launch a browser. Please visit this URL to authorize the application:")
-                       LOGGER.info("    {}".format(user_url))
+                       log('info', "Failed to launch a browser. Please visit this URL to authorize the application:")
+                       log('info', user_url, indent = 1)
 
                try:
                        resp = channel.get(timeout = TIMEOUT.total_seconds())
@@ -315,6 +313,6 @@ class CookieAuthHandler(urllib.request.HTTPCookieProcessor):
                self.cookiejar.save()
 
        def http_error_401(self, request, fp, code, msg, headers):
-               LOGGER.info("Session cookies missing or expired. Logging in…")
+               log('info', "Session cookies missing or expired. Logging in…")
                self.log_in()
                return self.parent.open(request, timeout = request.timeout)
index 3cc3ea7fa7a7d2a1cd099dde500eee15800b3238..b6346a6b8cc3a68ab184561b0a5af0f1bf0c5d48 100644 (file)
--- a/common.py
+++ b/common.py
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <https://www.gnu.org/licenses/>.
 
-from collections import deque, namedtuple
+from collections import namedtuple
 import json
-import logging
 from pathlib import PurePosixPath
-import urllib.request
+
 
 BlackboardRoot = namedtuple('BlackboardRoot', ['host', 'path'])
 BB_ROOT = BlackboardRoot(
@@ -25,25 +24,11 @@ BB_ROOT = BlackboardRoot(
        path = PurePosixPath('/'),
 )
 
-LOGGER = logging.getLogger('bb-sync-api')
-logging.basicConfig()
-LOGGER.setLevel(logging.INFO)
-
-class Adapter(logging.LoggerAdapter):
-       def process(self, msg, kwargs):
-               return ('  ' * kwargs['indent'] + msg, kwargs)
-
-'''
-LOGGER = Adapter(LOGGER, {})
-LOGGER.debug('some message', indent = 1)
 
-class IndentingFormatter(logging.Formatter):
-       def format(self, record):
-               prefix = '  ' * record.indent if hasattr(record, 'indent') else ''
-               return prefix + None
+def log(level, message, indent = 0):
+       import sys
+       print(level.upper().rjust(7) + ': ' + indent * '  ' + message, file = sys.stderr)
 
-LOGGER.setFormatter(logging.Formatter('', style = '{'))
-'''
 
 class StorageManager():
        def __init__(self, path):
diff --git a/main.py b/main.py
index c15e992cb861d90ebc05bb4048df2408098691e8..e35af39c247ee395a755f2b8caa28f83e12cba96 100644 (file)
--- a/main.py
+++ b/main.py
@@ -20,10 +20,8 @@ import json
 from operator import attrgetter
 from pathlib import Path
 import shutil
-import sys
 import tempfile
 import urllib.parse
-import urllib.request
 
 from common import *
 import api
@@ -93,26 +91,26 @@ with StorageManager(Path('auth_cache')) as storage_mgr:
                found_course_id = None
        if found_course_id:
                if found_course_id != course_id:
-                       LOGGER.warning("Using a course root previously used for another course!")
-                       LOGGER.warning("File versioning may misbehave.")
+                       log('warning', "Using a course root previously used for another course!")
+                       log('warning', "File versioning may misbehave.")
        else:
                with meta_path.open('x') as f:
                        json.dump({'course_id': course_id}, f)
 
        content_path = api_iface.get_content_path(course_id, content_id)
-       LOGGER.info("Blackboard content path: {}".format('/'.join(seg['id'] for seg in content_path)))
+       log('info', "Blackboard content path: {}".format('/'.join(seg['id'] for seg in content_path)))
        local_content_root = functools.reduce(fs.join_content_path, content_path, local_course_root)
-       LOGGER.info("Local content path: {}".format(local_content_root))
+       log('info', "Local content path: {}".format(local_content_root))
 
        for child_doc in api_iface.get_children(course_id, content_id):
-               LOGGER.info("Processing content item {id}: \"{title}\"".format(**child_doc))
+               log('info', "Processing content item {id}: \"{title}\"".format(**child_doc))
                local_path = fs.join_content_path(local_content_root, child_doc)
                versions = fs.get_child_versions(local_path)
 
                for attachment_doc in api_iface.get_attachments(course_id, child_doc['id']):
                        att_id = attachment_doc['id']
 
-                       LOGGER.info("  Checking attachment {id}: \"{fileName}\"".format(**attachment_doc))
+                       log('info', "Checking attachment {id}: \"{fileName}\"".format(**attachment_doc), indent = 1)
 
                        class Result:
                                NoVersions = namedtuple('NoVersions', [])
@@ -146,19 +144,29 @@ with StorageManager(Path('auth_cache')) as storage_mgr:
                        if Result.to_update(result):
                                if isinstance(result, Result.SingleLatest):
                                        new_version = result.version.next()
-                                       LOGGER.info("    Found new revision ({})".format(new_version.version))
+                                       log('info', "Found new revision ({})".format(new_version.version), indent = 2)
                                else:
                                        new_version = fs.VersionInfo(att_id, 0)
-                                       LOGGER.info("    Storing initial revision")
+                                       log('info', "Storing initial revision", indent = 2)
                                dest = fs.get_new_path(local_path, attachment_doc['fileName'])
-                               LOGGER.info("    Destination: {}".format(dest))
+                               log('info', "Destination: {}".format(dest), indent = 2)
                                tmp_path.replace(dest)
                                fs.write_metadata(dest, new_version)
                        elif isinstance(result, Result.SingleLatest):
                                # versions match
                                tmp_path.unlink()
                        elif isinstance(result, Result.MultipleLatest):
-                               LOGGER.error("    Identified multiple latest versions for {id}: {fileName}"
-                                       .format(**attachment_doc)
+                               log(
+                                       'error',
+                                       "Identified multiple latest versions for {id}: {fileName}".format(**attachment_doc),
+                                       indent = 2,
                                )
-                               LOGGER.error("    Please delete ")
+                               log(
+                                       'error',
+                                       "To allow the program to check this attachment, delete all or all but one of these files:",
+                                       indent = 2,
+                               )
+                               for path_str in sorted(map(str, result.paths)):
+                                       log('error', path_str, indent = 3)
+                       else:
+                               raise AssertionError()