| #!/usr/bin/python | |
| # Copyright 2018 The Tulsi Authors. All rights reserved. | |
| # | |
| # Licensed under the Apache License, Version 2.0 (the "License"); | |
| # you may not use this file except in compliance with the License. | |
| # You may obtain a copy of the License at | |
| # | |
| # http://www.apache.org/licenses/LICENSE-2.0 | |
| # | |
| # Unless required by applicable law or agreed to in writing, software | |
| # distributed under the License is distributed on an "AS IS" BASIS, | |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| # See the License for the specific language governing permissions and | |
| # limitations under the License. | |
| """Manages our dSYM SQLite database schema.""" | |
| import errno | |
| import os | |
| import sqlite3 | |
| SQLITE_SYMBOL_CACHE_PATH = os.path.expanduser('~/Library/Application Support/' | |
| 'Tulsi/Scripts/symbol_cache.db') | |
| class SymbolCacheSchema(object): | |
| """Defines and updates the SQLite database used for DBGShellCommands.""" | |
| current_version = 1 | |
| def UpdateSchemaV1(self, connection): | |
| """Updates the database to the v1 schema. | |
| Args: | |
| connection: Connection to the database that needs to be updated. | |
| Returns: | |
| True if the database reported that it was updated to v1. | |
| False if not. | |
| """ | |
| # Create the table (schema version 1). | |
| cursor = connection.cursor() | |
| cursor.execute('CREATE TABLE symbol_cache(' | |
| 'uuid TEXT PRIMARY KEY, ' | |
| 'dsym_path TEXT, ' | |
| 'architecture TEXT' | |
| ');') | |
| # NOTE: symbol_cache (uuid) already has an index, as the PRIMARY KEY. | |
| # Create a unique index to keep dSYM paths and architectures unique. | |
| cursor.execute('CREATE UNIQUE INDEX idx_dsym_arch ' | |
| 'ON ' | |
| 'symbol_cache(' | |
| 'dsym_path, ' | |
| 'architecture' | |
| ');') | |
| cursor.execute('PRAGMA user_version = 1;') | |
| # Verify the updated user_version, as confirmation of the update. | |
| cursor.execute('PRAGMA user_version;') | |
| return cursor.fetchone()[0] == 1 | |
| def VerifySchema(self, connection): | |
| """Updates the database to the latest schema. | |
| Args: | |
| connection: Connection to the database that needs to be updated. | |
| Returns: | |
| True if the database reported that it was updated to the latest schema. | |
| False if not. | |
| """ | |
| cursor = connection.cursor() | |
| cursor.execute('PRAGMA user_version;') # Default is 0 | |
| db_version = cursor.fetchone()[0] | |
| # Update to the latest schema in the given database, if necessary. | |
| if db_version < self.current_version: | |
| # Future schema updates will build on this. | |
| if self.UpdateSchemaV1(connection): | |
| db_version = 1 | |
| # Return if the database has been updated to the latest schema. | |
| return db_version == self.current_version | |
| def InitDB(self, db_path): | |
| """Initializes a new connection to a SQLite database. | |
| Args: | |
| db_path: String representing a reference to the SQLite database. | |
| Returns: | |
| A sqlite3.connection object representing an active connection to | |
| the database referenced by db_path. | |
| """ | |
| # If this is not an in-memory SQLite database... | |
| if ':memory:' not in db_path: | |
| # Create all subdirs before we create a new db or connect to existing. | |
| if not os.path.isfile(db_path): | |
| try: | |
| os.makedirs(os.path.dirname(db_path)) | |
| except OSError as e: | |
| if e.errno != errno.EEXIST: | |
| raise | |
| connection = sqlite3.connect(db_path) | |
| # Update to the latest schema and return the db connection. | |
| if self.VerifySchema(connection): | |
| return connection | |
| else: | |
| return None | |
| def __init__(self, db_path=SQLITE_SYMBOL_CACHE_PATH): | |
| self.connection = self.InitDB(db_path) | |
| def __del__(self): | |
| if self.connection: | |
| self.connection.close() |