diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..9a2cede --- /dev/null +++ b/.env.example @@ -0,0 +1,4 @@ +SOURCE_FOLDER= +TARGET_BUCKET= + +GOOGLE_APPLICATION_CREDENTIALS= \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5d9c0c8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,50 @@ +# Bootstrapping # +################# +/node_modules +/public/hot +/public/storage +/storage/*.key +/vendor +.env +.env.backup +.phpunit.result.cache +Homestead.json +Homestead.yaml +npm-debug.log +yarn-error.log +public/robots.txt + + +# OS generated files # +###################### +.DS_Store +.DS_Store? +._* +.Spotlight-V100 +.Trashes +Icon? +ehthumbs.db +Thumbs.db +.directory + +# Tool specific files # +####################### +# vim +*~ +*.swp +*.swo +# sublime text & textmate +*.sublime-* +*.stTheme.cache +*.tmlanguage.cache +*.tmPreferences.cache +# Eclipse +.settings/* +# JetBrains, aka PHPStorm, IntelliJ IDEA +.idea/* +# NetBeans +nbproject/* +# Visual Studio Code +.vscode +# Sass preprocessor +.sass-cache/ \ No newline at end of file diff --git a/.theia/launch.json b/.theia/launch.json new file mode 100644 index 0000000..6077c7f --- /dev/null +++ b/.theia/launch.json @@ -0,0 +1,14 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + "version": "0.2.0", + "configurations": [ + { + "name": "Python: Current File", + "type": "python", + "request": "launch", + "program": "${file}", + "console": "integratedTerminal" + } + ] +} diff --git a/backup.py b/backup.py new file mode 100644 index 0000000..dbbf772 --- /dev/null +++ b/backup.py @@ -0,0 +1,4 @@ +from src import SQLite, StorageClient + +client = SQLite() +print("OK") \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..dd9601f --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +python-dotenv +google-cloud-storage \ No newline at end of file diff --git a/src/__init__.py b/src/__init__.py new file mode 100644 index 0000000..f76f657 --- /dev/null +++ b/src/__init__.py @@ -0,0 +1,10 @@ +from dotenv import load_dotenv + +from .glob import file_exists +from .db import SQLite +from .gcs import StorageClient + +if not file_exists(".env"): + raise FileNotFoundError("Environment variable file does not exist. Copy '.env.example' to '.env'") + +load_dotenv() \ No newline at end of file diff --git a/src/__pycache__/__init__.cpython-39.pyc b/src/__pycache__/__init__.cpython-39.pyc new file mode 100644 index 0000000..70a95df Binary files /dev/null and b/src/__pycache__/__init__.cpython-39.pyc differ diff --git a/src/__pycache__/glob.cpython-39.pyc b/src/__pycache__/glob.cpython-39.pyc new file mode 100644 index 0000000..e670f8d Binary files /dev/null and b/src/__pycache__/glob.cpython-39.pyc differ diff --git a/src/db/__init__.py b/src/db/__init__.py new file mode 100644 index 0000000..cff90f1 --- /dev/null +++ b/src/db/__init__.py @@ -0,0 +1 @@ +from .sqlite import SQLite \ No newline at end of file diff --git a/src/db/__pycache__/__init__.cpython-39.pyc b/src/db/__pycache__/__init__.cpython-39.pyc new file mode 100644 index 0000000..d6a8f13 Binary files /dev/null and b/src/db/__pycache__/__init__.cpython-39.pyc differ diff --git a/src/db/__pycache__/sqlite.cpython-39.pyc b/src/db/__pycache__/sqlite.cpython-39.pyc new file mode 100644 index 0000000..1f14c77 Binary files /dev/null and b/src/db/__pycache__/sqlite.cpython-39.pyc differ diff --git a/src/db/sqlite.py b/src/db/sqlite.py new file mode 100644 index 0000000..7669091 --- /dev/null +++ b/src/db/sqlite.py @@ -0,0 +1,43 @@ +import os +import sqlite3 as sqlite + +from ..glob import file_exists + +class SQLite(): + def __init__(self): + self.db = sqlite.connect(self.get_db_path()) + self.cursor = self.db.cursor() + + self.init() + + def query(self, sql: str): + result = self.cursor.execute(sql) + + if result.rowcount < 1: + return False + + return result + + def get_db_path(self) -> str: + name = ".gcsarchive.db" + path = os.getenv("SOURCE_FOLDER") + + # Append db file name if absent + if not path.endswith(name): + # Append tailing slash if absent + if path[-1] != "/": + path += "/" + path += name + return path + + def configure_db(self): + metadata_sql = "CREATE TABLE metadata (key text, value text)" + metadata = self.query(metadata_sql) + + def init(self): + # Set up db if it's fresh + hasmeta_sql = "SELECT name FROM sqlite_master WHERE type='table' AND name='metadata'" + if not self.query(hasmeta_sql): + self.configure_db() + + return True \ No newline at end of file diff --git a/src/gcs/__init__.py b/src/gcs/__init__.py new file mode 100644 index 0000000..94841ed --- /dev/null +++ b/src/gcs/__init__.py @@ -0,0 +1 @@ +from .client import StorageClient \ No newline at end of file diff --git a/src/gcs/__pycache__/__init__.cpython-39.pyc b/src/gcs/__pycache__/__init__.cpython-39.pyc new file mode 100644 index 0000000..51fe10b Binary files /dev/null and b/src/gcs/__pycache__/__init__.cpython-39.pyc differ diff --git a/src/gcs/__pycache__/client.cpython-39.pyc b/src/gcs/__pycache__/client.cpython-39.pyc new file mode 100644 index 0000000..fd7a831 Binary files /dev/null and b/src/gcs/__pycache__/client.cpython-39.pyc differ diff --git a/src/gcs/client.py b/src/gcs/client.py new file mode 100644 index 0000000..2a29b9b --- /dev/null +++ b/src/gcs/client.py @@ -0,0 +1,21 @@ +import os +from os.path import exists +from google.cloud import storage + +class StorageClient(storage.Client): + def __init__(self, bucket: str = None): + if not bucket: + bucket = os.getenv("TARGET_BUCKET") + + if not self.gcloud_key_exists(): + raise Exception("GOOGLE_APPLICATION_CREDENTIALS has to point to a key file") + + super().__init__() + + # Check if env var is set to a key file + def gcloud_key_exists(self) -> bool: + keyfile = os.getenv("GOOGLE_APPLICATION_CREDENTIALS") + + if not keyfile or not exists(keyfile): + return False + return True \ No newline at end of file diff --git a/src/glob.py b/src/glob.py new file mode 100644 index 0000000..28d3b19 --- /dev/null +++ b/src/glob.py @@ -0,0 +1,4 @@ +import os.path + +def file_exists(file: str) -> bool: + return os.path.isfile(file) \ No newline at end of file