<commit_before>/*
 *
 * migrations
 * ledger-core
 *
 * Created by Pierre Pollastri on 25/04/2017.
 *
 * The MIT License (MIT)
 *
 * Copyright (c) 2016 Ledger
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 */
#include "migrations.hpp"

namespace ledger {
    namespace core {
        int getDatabaseMigrationVersion(soci::session& sql) {
            int version = -1;

            try {
                soci::statement st = (sql.prepare << "SELECT version FROM __database_meta__ WHERE id == 0", soci::into(version));
                st.execute();
                st.fetch();
            } catch (...) {
                // if we cannot find the version, it stays set to -1
            }

            return version;
        }

        template <> bool migrate<-1>(soci::session& sql, int currentVersion) {
            return false;
        }

        template <> void rollback<-1>(soci::session& sql, int currentVersion) {
        }

        template <> void migrate<0>(soci::session& sql) {
            sql << "CREATE TABLE __database_meta__("
                "id INT PRIMARY KEY NOT NULL,"
                "version INT NOT NULL"
            ")";

            sql << "INSERT INTO __database_meta__(id, version) VALUES(0, 0)";
        }

        template <> void rollback<0>(soci::session& sql) {
            sql << "DROP TABLE __database_meta__";
        }

        template <> void migrate<1>(soci::session& sql) {
            // Pool table
            sql << "CREATE TABLE pools("
                "name VARCHAR(255) PRIMARY KEY NOT NULL,"
                "created_at VARCHAR(255) NOT NULL"
            ")";

            // Abstract currency table
            sql << "CREATE TABLE currencies("
                "name VARCHAR(255) PRIMARY KEY NOT NULL,"
                "type VARCHAR(255) NOT NULL,"
                "bip44_coin_type INTEGER NOT NULL,"
                "payment_uri_scheme VARCHAR(255)"
            ")";

            // Abstract units table
            sql << "CREATE TABLE units("
                "name VARCHAR(255) NOT NULL,"
                "magnitude INTEGER NOT NULL,"
                "symbol VARCHAR(255) NOT NULL,"
                "code VARCHAR(255) NOT NULL,"
                "currency_name VARCHAR(255) REFERENCES currencies(name) ON DELETE CASCADE ON UPDATE CASCADE"
            ")";

            // Abstract wallet table
            sql << "CREATE TABLE wallets("
                "uid VARCHAR(255) PRIMARY KEY NOT NULL,"
                "name VARCHAR(255),"
                "currency_name VARCHAR(255) NOT NULL REFERENCES currencies(name) ON DELETE CASCADE ON UPDATE CASCADE,"
                "pool_name VARCHAR(255) NOT NULL REFERENCES pools(name) ON DELETE CASCADE ON UPDATE CASCADE,"
                "configuration TEXT NOT NULL, "
                "created_at TEXT NOT NULL"
            ")";

            // Abstract account table
            sql << "CREATE TABLE accounts("
                "uid VARCHAR(255) PRIMARY KEY NOT NULL,"
                "idx INTEGER NOT NULL,"
                "wallet_uid VARCHAR(255) NOT NULL REFERENCES wallets(uid) ON DELETE CASCADE ON UPDATE CASCADE, "
                "created_at TEXT NOT NULL"
            ")";

            // Abstract block table
            sql << "CREATE TABLE blocks("
                    "uid VARCHAR(255) PRIMARY KEY NOT NULL,"
                    "hash VARCHAR(255) NOT NULL,"
                    "height BIGINT NOT NULL,"
                    "time VARCHAR(255) NOT NULL,"
                    "currency_name VARCHAR(255)"
            ")";

            // Abstract operation table
            sql << "CREATE TABLE operations("
                "uid VARCHAR(255) PRIMARY KEY NOT NULL,"
                "account_uid VARCHAR(255) NOT NULL REFERENCES accounts(uid) ON DELETE CASCADE,"
                "wallet_uid VARCHAR(255) NOT NULL REFERENCES wallets(uid) ON DELETE CASCADE,"
                "type VARCHAR(255) NOT NULL,"
                "date VARCHAR(255) NOT NULL,"
                "senders TEXT NOT NULL,"
                "recipients TEXT NOT NULL,"
                "amount VARCHAR(255) NOT NULL,"
                "fees VARCHAR(255),"
                "block_uid VARCHAR(255) REFERENCES blocks(uid) ON DELETE CASCADE,"
                "currency_name VARCHAR(255) NOT NULL REFERENCES currencies(name) ON DELETE CASCADE,"
                "trust TEXT"
            ")";

            // Bitcoin currency table
            sql << "CREATE TABLE bitcoin_currencies("
                "name VARCHAR(255) PRIMARY KEY NOT NULL REFERENCES currencies(name) ON DELETE CASCADE ON UPDATE CASCADE,"
                "identifier VARCHAR(255) NOT NULL,"
                "p2pkh_version VARCHAR(255) NOT NULL,"
                "p2sh_version VARCHAR(255) NOT NULL,"
                "xpub_version VARACHAR(255) NOT NULL,"
                "dust_amount BIGINT NOT NULL,"
                "fee_policy VARCHAR(20) NOT NULL,"
                "message_prefix VARCHAR(255) NOT NULL,"
                "has_timestamped_transaction INTEGER NOT NULL"
            ")";

            // Bitcoin transaction table
            sql << "CREATE TABLE bitcoin_transactions("
                "transaction_uid VARCHAR(255) PRIMARY KEY NOT NULL,"
                "hash VARCHAR(255) NOT NULL,"
                "version INTEGER,"
                "block_uid VARCHAR(255) REFERENCES blocks(uid) ON DELETE CASCADE,"
                "time VARCHAR(255),"
                "locktime INTEGER"
            ")";

            // Bitcoin input table
            sql << "CREATE TABLE bitcoin_inputs("
                "uid VARCHAR(255) PRIMARY KEY NOT NULL," // accountId_idx_previoustxhash_coinbase
                "previous_output_idx INTEGER,"
                "previous_tx_hash VARCHAR(255),"
                "previous_tx_uid VARCHAR(255),"
                "amount  BIGINT,"
                "address VARCHAR(255),"
                "coinbase VARCHAR(255),"
                "sequence BIGINT NOT NULL"
            ")";

            // Bitcoin output table
            sql << "CREATE TABLE bitcoin_outputs("
                "idx INTEGER NOT NULL,"
                "transaction_uid VARCHAR(255) NOT NULL REFERENCES bitcoin_transactions(transaction_uid) ON DELETE CASCADE,"
                "transaction_hash VARCHAR(255) NOT NULL,"
                "amount BIGINT NOT NULL,"
                "script TEXT NOT NULL,"
                "address VARCHAR(255),"
                "account_uid VARCHAR(255),"
                "PRIMARY KEY (idx, transaction_uid)"
                ")";

            // Bitcoin transaction <-> input table
            sql << "CREATE TABLE bitcoin_transaction_inputs("
                "transaction_uid VARCHAR(255) NOT NULL REFERENCES bitcoin_transactions(transaction_uid) ON DELETE CASCADE,"
                "transaction_hash VARCHAR(255) NOT NULL,"
                "input_uid VARCHAR(255) NOT NULL REFERENCES bitcoin_inputs(uid) ON DELETE CASCADE,"
                "input_idx INTEGER NOT NULL,"
                "PRIMARY KEY (transaction_uid, input_uid)"
                ")";

            // Bitcoin account
            sql << "CREATE TABLE bitcoin_accounts("
                "uid VARCHAR(255) NOT NULL PRIMARY KEY REFERENCES accounts(uid) ON DELETE CASCADE ON UPDATE CASCADE,"
                "wallet_uid VARCHAR(255) NOT NULL REFERENCES wallets(uid) ON DELETE CASCADE ON UPDATE CASCADE,"
                "idx INTEGER NOT NULL,"
                "xpub VARCHAR(255) NOT NULL"
            ")";

            // Bitcoin operation table
            sql << "CREATE TABLE bitcoin_operations("
                "uid VARCHAR(255) PRIMARY KEY NOT NULL REFERENCES operations(uid) ON DELETE CASCADE,"
                "transaction_uid VARCHAR(255) NOT NULL REFERENCES bitcoin_transactions(transaction_uid),"
                "transaction_hash VARCHAR(255) NOT NULL"
                ")";
        }

        template <> void rollback<1>(soci::session& sql) {
            // Bitcoin operation table
            sql << "DROP TABLE bitcoin_operations";

            // Bitcoin account
            sql << "DROP TABLE bitcoin_accounts";

            // Bitcoin transaction <-> input table
            sql << "DROP TABLE bitcoin_transaction_inputs";

            // Bitcoin output table
            sql << "DROP TABLE bitcoin_outputs";

            // Bitcoin input table
            sql << "DROP TABLE bitcoin_inputs";

            // Bitcoin transaction table
            sql << "DROP TABLE bitcoin_transactions";

            // Bitcoin currency table
            sql << "DROP TABLE bitcoin_currencies";

            // Abstract operation table
            sql << "DROP TABLE operations";

            // Abstract block table
            sql << "DROP TABLE blocks";

            // Abstract account table
            sql << "DROP TABLE accounts";

            // Abstract wallet table
            sql << "DROP TABLE wallets";

            // Abstract units table
            sql << "DROP TABLE units";

            // Abstract currency table
            sql << "DROP TABLE currencies";

            // Pool table
            sql << "DROP TABLE pools";
        }

        template <> void migrate<2>(soci::session& sql) {
            sql << "ALTER TABLE bitcoin_currencies ADD COLUMN timestamp_delay BIGINT DEFAULT 0";
            sql << "ALTER TABLE bitcoin_currencies ADD COLUMN sighash_type VARCHAR(255) DEFAULT 01";
        }

        template <> void rollback<2>(soci::session& sql) {
            // not supported in standard ways by SQLite :(
        }

        template <> void migrate<3>(soci::session& sql) {
            sql << "ALTER TABLE bitcoin_currencies ADD COLUMN additional_BIPs TEXT DEFAULT ''";
        }

        template <> void rollback<3>(soci::session& sql) {
            // not supported in standard ways by SQLite :(
        }

        template <> void migrate<4>(soci::session& sql) {
            auto count = 0;
            sql << "SELECT COUNT(*) FROM bitcoin_currencies WHERE identifier = 'dgb'", soci::into(count);
            if (count > 0) {
                sql << "UPDATE bitcoin_currencies SET p2sh_version = '3f' WHERE identifier = 'dgb' ";
            }
        }

        template <> void rollback<4>(soci::session& sql) {
            // cannot rollback
        }

        template <> void migrate<5>(soci::session& sql) {
            // ETH currencies
            sql << "CREATE TABLE ethereum_currencies("
                    "name VARCHAR(255) PRIMARY KEY NOT NULL REFERENCES currencies(name) ON DELETE CASCADE ON UPDATE CASCADE,"
                    "identifier VARCHAR(255) NOT NULL,"
                    "chain_id VARACHAR(255) NOT NULL,"
                    "xpub_version VARACHAR(255) NOT NULL,"
                    "message_prefix VARCHAR(255) NOT NULL,"
                    "additional_EIPs TEXT"
                    ")";

            // ETH accounts
            sql << "CREATE TABLE ethereum_accounts("
                    "uid VARCHAR(255) NOT NULL PRIMARY KEY REFERENCES accounts(uid) ON DELETE CASCADE ON UPDATE CASCADE,"
                    "wallet_uid VARCHAR(255) NOT NULL REFERENCES wallets(uid) ON DELETE CASCADE ON UPDATE CASCADE,"
                    "idx INTEGER NOT NULL,"
                    "address VARCHAR(255) NOT NULL"
                    ")";

            // ETH transactions
            sql << "CREATE TABLE ethereum_transactions("
                    "transaction_uid VARCHAR(255) PRIMARY KEY NOT NULL,"
                    "hash VARCHAR(255) NOT NULL,"
                    "nonce VARCHAR(255) NOT NULL,"
                    "value VARCHAR(255) NOT NULL,"
                    "block_uid VARCHAR(255) REFERENCES blocks(uid) ON DELETE CASCADE,"
                    "time VARCHAR(255) NOT NULL,"
                    "sender VARCHAR(255) NOT NULL,"
                    "receiver VARCHAR(255) NOT NULL,"
                    "input_data VARCHAR(255),"
                    "gas_price VARCHAR(255) NOT NULL,"
                    "gas_limit VARCHAR(255) NOT NULL,"
                    "gas_used VARCHAR(255) NOT NULL,"
                    "confirmations BIGINT NOT NULL,"
                    "status BIGINT NOT NULL"
                    ")";

            // ETH operations
            sql << "CREATE TABLE ethereum_operations("
                    "uid VARCHAR(255) PRIMARY KEY NOT NULL REFERENCES operations(uid) ON DELETE CASCADE,"
                    "transaction_uid VARCHAR(255) NOT NULL REFERENCES ethereum_transactions(transaction_uid),"
                    "transaction_hash VARCHAR(255) NOT NULL"
                    ")";

            // ERC20 accounts
            sql << "CREATE TABLE erc20_accounts("
                    "uid VARCHAR(255) PRIMARY KEY NOT NULL ,"
                    "ethereum_account_uid VARCHAR(255) NOT NULL REFERENCES ethereum_accounts(uid) ON DELETE CASCADE,"
                    "contract_address VARCHAR(255) NOT NULL"
                    ")";

            // ERC20 operations
            sql << "CREATE TABLE erc20_operations("
                    "uid VARCHAR(255) PRIMARY KEY NOT NULL ,"
                    "ethereum_operation_uid VARCHAR(255) NOT NULL REFERENCES operations(uid) ON DELETE CASCADE,"
                    "account_uid VARCHAR(255) NOT NULL REFERENCES erc20_accounts(uid) ON DELETE CASCADE,"
                    "type VARCHAR(255) NOT NULL,"
                    "hash VARCHAR(255) NOT NULL,"
                    "nonce VARCHAR(255) NOT NULL,"
                    "value VARCHAR(255) NOT NULL,"
                    "date VARCHAR(255) NOT NULL,"
                    "sender VARCHAR(255) NOT NULL,"
                    "receiver VARCHAR(255) NOT NULL,"
                    "input_data VARCHAR(255),"
                    "gas_price VARCHAR(255) NOT NULL,"
                    "gas_limit VARCHAR(255) NOT NULL,"
                    "gas_used VARCHAR(255) NOT NULL,"
                    "status INTEGER NOT NULL"
                    ")";

            // ERC20 tokens
            sql << "CREATE TABLE erc20_tokens("
                    "contract_address VARCHAR(255) PRIMARY KEY NOT NULL,"
                    "name VARCHAR(255) NOT NULL,"
                    "symbol VARCHAR(255) NOT NULL,"
                    "number_of_decimal INTEGER NOT NULL"
                    ")";

        }

        template <> void rollback<5>(soci::session& sql) {
            // ERC20 tokens
            sql << "DROP TABLE erc20_tokens";

            // ERC20 operations
            sql << "DROP TABLE erc20_operations";

            // ERC20 accounts
            sql << "DROP TABLE erc20_accounts";

            // ETH operations
            sql << "DROP TABLE ethereum_operations";

            // ETH transactions
            sql << "DROP TABLE ethereum_operations";

            // ETH accounts
            sql << "DROP TABLE ethereum_accounts";

            // ETH currencies
            sql << "DROP TABLE ethereum_currencies";
        }
    }
}
<commit_msg>Fix SQL equality test in migrations code.<commit_after>/*
 *
 * migrations
 * ledger-core
 *
 * Created by Pierre Pollastri on 25/04/2017.
 *
 * The MIT License (MIT)
 *
 * Copyright (c) 2016 Ledger
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 */

#include "migrations.hpp"

namespace ledger {
    namespace core {
        int getDatabaseMigrationVersion(soci::session& sql) {
            int version = -1;

            try {
                soci::statement st = (sql.prepare << "SELECT version FROM __database_meta__ WHERE id = 0", soci::into(version));
                st.execute();
                st.fetch();
            } catch (...) {
                // if we cannot find the version, it stays set to -1
            }

            return version;
        }

        template <> bool migrate<-1>(soci::session& sql, int currentVersion) {
            return false;
        }

        template <> void rollback<-1>(soci::session& sql, int currentVersion) {
        }

        template <> void migrate<0>(soci::session& sql) {
            sql << "CREATE TABLE __database_meta__("
                "id INT PRIMARY KEY NOT NULL,"
                "version INT NOT NULL"
            ")";

            sql << "INSERT INTO __database_meta__(id, version) VALUES(0, 0)";
        }

        template <> void rollback<0>(soci::session& sql) {
            sql << "DROP TABLE __database_meta__";
        }

        template <> void migrate<1>(soci::session& sql) {
            // Pool table
            sql << "CREATE TABLE pools("
                "name VARCHAR(255) PRIMARY KEY NOT NULL,"
                "created_at VARCHAR(255) NOT NULL"
            ")";

            // Abstract currency table
            sql << "CREATE TABLE currencies("
                "name VARCHAR(255) PRIMARY KEY NOT NULL,"
                "type VARCHAR(255) NOT NULL,"
                "bip44_coin_type INTEGER NOT NULL,"
                "payment_uri_scheme VARCHAR(255)"
            ")";

            // Abstract units table
            sql << "CREATE TABLE units("
                "name VARCHAR(255) NOT NULL,"
                "magnitude INTEGER NOT NULL,"
                "symbol VARCHAR(255) NOT NULL,"
                "code VARCHAR(255) NOT NULL,"
                "currency_name VARCHAR(255) REFERENCES currencies(name) ON DELETE CASCADE ON UPDATE CASCADE"
            ")";

            // Abstract wallet table
            sql << "CREATE TABLE wallets("
                "uid VARCHAR(255) PRIMARY KEY NOT NULL,"
                "name VARCHAR(255),"
                "currency_name VARCHAR(255) NOT NULL REFERENCES currencies(name) ON DELETE CASCADE ON UPDATE CASCADE,"
                "pool_name VARCHAR(255) NOT NULL REFERENCES pools(name) ON DELETE CASCADE ON UPDATE CASCADE,"
                "configuration TEXT NOT NULL, "
                "created_at TEXT NOT NULL"
            ")";

            // Abstract account table
            sql << "CREATE TABLE accounts("
                "uid VARCHAR(255) PRIMARY KEY NOT NULL,"
                "idx INTEGER NOT NULL,"
                "wallet_uid VARCHAR(255) NOT NULL REFERENCES wallets(uid) ON DELETE CASCADE ON UPDATE CASCADE, "
                "created_at TEXT NOT NULL"
            ")";

            // Abstract block table
            sql << "CREATE TABLE blocks("
                    "uid VARCHAR(255) PRIMARY KEY NOT NULL,"
                    "hash VARCHAR(255) NOT NULL,"
                    "height BIGINT NOT NULL,"
                    "time VARCHAR(255) NOT NULL,"
                    "currency_name VARCHAR(255)"
            ")";

            // Abstract operation table
            sql << "CREATE TABLE operations("
                "uid VARCHAR(255) PRIMARY KEY NOT NULL,"
                "account_uid VARCHAR(255) NOT NULL REFERENCES accounts(uid) ON DELETE CASCADE,"
                "wallet_uid VARCHAR(255) NOT NULL REFERENCES wallets(uid) ON DELETE CASCADE,"
                "type VARCHAR(255) NOT NULL,"
                "date VARCHAR(255) NOT NULL,"
                "senders TEXT NOT NULL,"
                "recipients TEXT NOT NULL,"
                "amount VARCHAR(255) NOT NULL,"
                "fees VARCHAR(255),"
                "block_uid VARCHAR(255) REFERENCES blocks(uid) ON DELETE CASCADE,"
                "currency_name VARCHAR(255) NOT NULL REFERENCES currencies(name) ON DELETE CASCADE,"
                "trust TEXT"
            ")";

            // Bitcoin currency table
            sql << "CREATE TABLE bitcoin_currencies("
                "name VARCHAR(255) PRIMARY KEY NOT NULL REFERENCES currencies(name) ON DELETE CASCADE ON UPDATE CASCADE,"
                "identifier VARCHAR(255) NOT NULL,"
                "p2pkh_version VARCHAR(255) NOT NULL,"
                "p2sh_version VARCHAR(255) NOT NULL,"
                "xpub_version VARACHAR(255) NOT NULL,"
                "dust_amount BIGINT NOT NULL,"
                "fee_policy VARCHAR(20) NOT NULL,"
                "message_prefix VARCHAR(255) NOT NULL,"
                "has_timestamped_transaction INTEGER NOT NULL"
            ")";

            // Bitcoin transaction table
            sql << "CREATE TABLE bitcoin_transactions("
                "transaction_uid VARCHAR(255) PRIMARY KEY NOT NULL,"
                "hash VARCHAR(255) NOT NULL,"
                "version INTEGER,"
                "block_uid VARCHAR(255) REFERENCES blocks(uid) ON DELETE CASCADE,"
                "time VARCHAR(255),"
                "locktime INTEGER"
            ")";

            // Bitcoin input table
            sql << "CREATE TABLE bitcoin_inputs("
                "uid VARCHAR(255) PRIMARY KEY NOT NULL," // accountId_idx_previoustxhash_coinbase
                "previous_output_idx INTEGER,"
                "previous_tx_hash VARCHAR(255),"
                "previous_tx_uid VARCHAR(255),"
                "amount  BIGINT,"
                "address VARCHAR(255),"
                "coinbase VARCHAR(255),"
                "sequence BIGINT NOT NULL"
            ")";

            // Bitcoin output table
            sql << "CREATE TABLE bitcoin_outputs("
                "idx INTEGER NOT NULL,"
                "transaction_uid VARCHAR(255) NOT NULL REFERENCES bitcoin_transactions(transaction_uid) ON DELETE CASCADE,"
                "transaction_hash VARCHAR(255) NOT NULL,"
                "amount BIGINT NOT NULL,"
                "script TEXT NOT NULL,"
                "address VARCHAR(255),"
                "account_uid VARCHAR(255),"
                "PRIMARY KEY (idx, transaction_uid)"
                ")";

            // Bitcoin transaction <-> input table
            sql << "CREATE TABLE bitcoin_transaction_inputs("
                "transaction_uid VARCHAR(255) NOT NULL REFERENCES bitcoin_transactions(transaction_uid) ON DELETE CASCADE,"
                "transaction_hash VARCHAR(255) NOT NULL,"
                "input_uid VARCHAR(255) NOT NULL REFERENCES bitcoin_inputs(uid) ON DELETE CASCADE,"
                "input_idx INTEGER NOT NULL,"
                "PRIMARY KEY (transaction_uid, input_uid)"
                ")";

            // Bitcoin account
            sql << "CREATE TABLE bitcoin_accounts("
                "uid VARCHAR(255) NOT NULL PRIMARY KEY REFERENCES accounts(uid) ON DELETE CASCADE ON UPDATE CASCADE,"
                "wallet_uid VARCHAR(255) NOT NULL REFERENCES wallets(uid) ON DELETE CASCADE ON UPDATE CASCADE,"
                "idx INTEGER NOT NULL,"
                "xpub VARCHAR(255) NOT NULL"
            ")";

            // Bitcoin operation table
            sql << "CREATE TABLE bitcoin_operations("
                "uid VARCHAR(255) PRIMARY KEY NOT NULL REFERENCES operations(uid) ON DELETE CASCADE,"
                "transaction_uid VARCHAR(255) NOT NULL REFERENCES bitcoin_transactions(transaction_uid),"
                "transaction_hash VARCHAR(255) NOT NULL"
                ")";
        }

        template <> void rollback<1>(soci::session& sql) {
            // Bitcoin operation table
            sql << "DROP TABLE bitcoin_operations";

            // Bitcoin account
            sql << "DROP TABLE bitcoin_accounts";

            // Bitcoin transaction <-> input table
            sql << "DROP TABLE bitcoin_transaction_inputs";

            // Bitcoin output table
            sql << "DROP TABLE bitcoin_outputs";

            // Bitcoin input table
            sql << "DROP TABLE bitcoin_inputs";

            // Bitcoin transaction table
            sql << "DROP TABLE bitcoin_transactions";

            // Bitcoin currency table
            sql << "DROP TABLE bitcoin_currencies";

            // Abstract operation table
            sql << "DROP TABLE operations";

            // Abstract block table
            sql << "DROP TABLE blocks";

            // Abstract account table
            sql << "DROP TABLE accounts";

            // Abstract wallet table
            sql << "DROP TABLE wallets";

            // Abstract units table
            sql << "DROP TABLE units";

            // Abstract currency table
            sql << "DROP TABLE currencies";

            // Pool table
            sql << "DROP TABLE pools";
        }

        template <> void migrate<2>(soci::session& sql) {
            sql << "ALTER TABLE bitcoin_currencies ADD COLUMN timestamp_delay BIGINT DEFAULT 0";
            sql << "ALTER TABLE bitcoin_currencies ADD COLUMN sighash_type VARCHAR(255) DEFAULT 01";
        }

        template <> void rollback<2>(soci::session& sql) {
            // not supported in standard ways by SQLite :(
        }

        template <> void migrate<3>(soci::session& sql) {
            sql << "ALTER TABLE bitcoin_currencies ADD COLUMN additional_BIPs TEXT DEFAULT ''";
        }

        template <> void rollback<3>(soci::session& sql) {
            // not supported in standard ways by SQLite :(
        }

        template <> void migrate<4>(soci::session& sql) {
            auto count = 0;
            sql << "SELECT COUNT(*) FROM bitcoin_currencies WHERE identifier = 'dgb'", soci::into(count);
            if (count > 0) {
                sql << "UPDATE bitcoin_currencies SET p2sh_version = '3f' WHERE identifier = 'dgb' ";
            }
        }

        template <> void rollback<4>(soci::session& sql) {
            // cannot rollback
        }

        template <> void migrate<5>(soci::session& sql) {
            // ETH currencies
            sql << "CREATE TABLE ethereum_currencies("
                    "name VARCHAR(255) PRIMARY KEY NOT NULL REFERENCES currencies(name) ON DELETE CASCADE ON UPDATE CASCADE,"
                    "identifier VARCHAR(255) NOT NULL,"
                    "chain_id VARACHAR(255) NOT NULL,"
                    "xpub_version VARACHAR(255) NOT NULL,"
                    "message_prefix VARCHAR(255) NOT NULL,"
                    "additional_EIPs TEXT"
                    ")";

            // ETH accounts
            sql << "CREATE TABLE ethereum_accounts("
                    "uid VARCHAR(255) NOT NULL PRIMARY KEY REFERENCES accounts(uid) ON DELETE CASCADE ON UPDATE CASCADE,"
                    "wallet_uid VARCHAR(255) NOT NULL REFERENCES wallets(uid) ON DELETE CASCADE ON UPDATE CASCADE,"
                    "idx INTEGER NOT NULL,"
                    "address VARCHAR(255) NOT NULL"
                    ")";

            // ETH transactions
            sql << "CREATE TABLE ethereum_transactions("
                    "transaction_uid VARCHAR(255) PRIMARY KEY NOT NULL,"
                    "hash VARCHAR(255) NOT NULL,"
                    "nonce VARCHAR(255) NOT NULL,"
                    "value VARCHAR(255) NOT NULL,"
                    "block_uid VARCHAR(255) REFERENCES blocks(uid) ON DELETE CASCADE,"
                    "time VARCHAR(255) NOT NULL,"
                    "sender VARCHAR(255) NOT NULL,"
                    "receiver VARCHAR(255) NOT NULL,"
                    "input_data VARCHAR(255),"
                    "gas_price VARCHAR(255) NOT NULL,"
                    "gas_limit VARCHAR(255) NOT NULL,"
                    "gas_used VARCHAR(255) NOT NULL,"
                    "confirmations BIGINT NOT NULL,"
                    "status BIGINT NOT NULL"
                    ")";

            // ETH operations
            sql << "CREATE TABLE ethereum_operations("
                    "uid VARCHAR(255) PRIMARY KEY NOT NULL REFERENCES operations(uid) ON DELETE CASCADE,"
                    "transaction_uid VARCHAR(255) NOT NULL REFERENCES ethereum_transactions(transaction_uid),"
                    "transaction_hash VARCHAR(255) NOT NULL"
                    ")";

            // ERC20 accounts
            sql << "CREATE TABLE erc20_accounts("
                    "uid VARCHAR(255) PRIMARY KEY NOT NULL ,"
                    "ethereum_account_uid VARCHAR(255) NOT NULL REFERENCES ethereum_accounts(uid) ON DELETE CASCADE,"
                    "contract_address VARCHAR(255) NOT NULL"
                    ")";

            // ERC20 operations
            sql << "CREATE TABLE erc20_operations("
                    "uid VARCHAR(255) PRIMARY KEY NOT NULL ,"
                    "ethereum_operation_uid VARCHAR(255) NOT NULL REFERENCES operations(uid) ON DELETE CASCADE,"
                    "account_uid VARCHAR(255) NOT NULL REFERENCES erc20_accounts(uid) ON DELETE CASCADE,"
                    "type VARCHAR(255) NOT NULL,"
                    "hash VARCHAR(255) NOT NULL,"
                    "nonce VARCHAR(255) NOT NULL,"
                    "value VARCHAR(255) NOT NULL,"
                    "date VARCHAR(255) NOT NULL,"
                    "sender VARCHAR(255) NOT NULL,"
                    "receiver VARCHAR(255) NOT NULL,"
                    "input_data VARCHAR(255),"
                    "gas_price VARCHAR(255) NOT NULL,"
                    "gas_limit VARCHAR(255) NOT NULL,"
                    "gas_used VARCHAR(255) NOT NULL,"
                    "status INTEGER NOT NULL"
                    ")";

            // ERC20 tokens
            sql << "CREATE TABLE erc20_tokens("
                    "contract_address VARCHAR(255) PRIMARY KEY NOT NULL,"
                    "name VARCHAR(255) NOT NULL,"
                    "symbol VARCHAR(255) NOT NULL,"
                    "number_of_decimal INTEGER NOT NULL"
                    ")";

        }

        template <> void rollback<5>(soci::session& sql) {
            // ERC20 tokens
            sql << "DROP TABLE erc20_tokens";

            // ERC20 operations
            sql << "DROP TABLE erc20_operations";

            // ERC20 accounts
            sql << "DROP TABLE erc20_accounts";

            // ETH operations
            sql << "DROP TABLE ethereum_operations";

            // ETH transactions
            sql << "DROP TABLE ethereum_operations";

            // ETH accounts
            sql << "DROP TABLE ethereum_accounts";

            // ETH currencies
            sql << "DROP TABLE ethereum_currencies";
        }
    }
}
<|endoftext|>


<commit_before>/*
 * CompilationDatabase.cpp
 *
 * Copyright (C) 2009-12 by RStudio, Inc.
 *
 * Unless you have received this program directly from RStudio pursuant
 * to the terms of a commercial license agreement with RStudio, then
 * this program is licensed to you under the terms of version 3 of the
 * GNU Affero General Public License. This program is distributed WITHOUT
 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
 *
 */

#include "CompilationDatabase.hpp"

#include <algorithm>

#include <boost/regex.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/trim_all.hpp>

#include <core/Error.hpp>
#include <core/PerformanceTimer.hpp>
#include <core/FileSerializer.hpp>

#include <core/r_util/RToolsInfo.hpp>

#include <core/system/Process.hpp>
#include <core/system/Environment.hpp>

#include <core/r_util/RPackageInfo.hpp>

#include <r/RExec.hpp>

#include <session/projects/SessionProjects.hpp>
#include <session/SessionModuleContext.hpp>

#include "LibClang.hpp"
#include "SourceIndex.hpp"

using namespace core ;

namespace session {
namespace modules {
namespace clang {
namespace libclang {

namespace {

std::string readDependencyAttributes(const core::FilePath& cppPath)
{
   // read file
   std::string contents;
   Error error = core::readStringFromFile(cppPath, &contents);
   if (error)
   {
      LOG_ERROR(error);
      return std::string();
   }

   // find dependency attributes
   std::string attributes;
   boost::regex re(
     "^\\s*//\\s*\\[\\[Rcpp::(\\w+)(\\(.*?\\))?\\]\\]\\s*$");
   boost::sregex_token_iterator it(contents.begin(), contents.end(), re, 0);
   boost::sregex_token_iterator end;
   for ( ; it != end; ++it)
   {
      std::string attrib = *it;
      boost::algorithm::trim_all(attrib);
      attributes.append(attrib);
   }

   // return them
   return attributes;
}

std::vector<std::string> extractCompileArgs(const std::string& line)
{
   std::vector<std::string> compileArgs;

   // find arguments libclang might care about
   boost::regex re("-[I|D|i|f|s](?:\\\"[^\\\"]+\\\"|[^ ]+)");
   boost::sregex_token_iterator it(line.begin(), line.end(), re, 0);
   boost::sregex_token_iterator end;
   for ( ; it != end; ++it)
   {
      // remove quotes and add it to the compile args
      std::string arg = *it;
      boost::algorithm::replace_all(arg, "\"", "");
      compileArgs.push_back(arg);
   }

   return compileArgs;
}

std::vector<std::string> argsForSourceCpp(const core::FilePath& cppPath)
{
   // baseline args
   std::vector<std::string> compileArgs;
   std::string builtinHeaders = "-I" + clang().builtinHeaders();
   compileArgs.push_back(builtinHeaders);
#if defined(_WIN32)
   std::vector<std::string> rtoolsArgs = rToolsArgs();
   std::copy(rtoolsArgs.begin(),
             rtoolsArgs.end(),
             std::back_inserter(compileArgs));
#elif defined(__APPLE__)
   compileArgs.push_back("-stdlib=libstdc++");
#endif

   // get path to R script
   FilePath rScriptPath;
   Error error = module_context::rScriptPath(&rScriptPath);
   if (error)
   {
      LOG_ERROR(error);
      return std::vector<std::string>();
   }

   // setup env and options
   core::system::Options env;
   core::system::ProcessOptions options;

   // always run as a slave
   std::vector<std::string> args;
   args.push_back("--slave");

   // for packrat projects we execute the profile and set the working
   // directory to the project directory; for other contexts we just
   // propagate the R_LIBS
   if (module_context::packratContext().modeOn)
   {
      options.workingDir = projects::projectContext().directory();
      args.push_back("--no-save");
      args.push_back("--no-restore");
   }
   else
   {
      args.push_back("--vanilla");
      std::string libPaths = module_context::libPathsString();
      if (!libPaths.empty())
         core::system::setenv(&env, "R_LIBS", libPaths);
   }

   // add rtools to path if we need to
   std::string warning;
   module_context::addRtoolsToPathIfNecessary(&env, &warning);

   // set environment into options
   options.environment = env;

   // add command to arguments
   args.push_back("-e");
   boost::format fmt("Rcpp::sourceCpp('%1%', showOutput = TRUE, dryRun = TRUE)");
   args.push_back(boost::str(fmt % cppPath.absolutePath()));

   // execute and capture output
   core::system::ProcessResult result;
   error = core::system::runProgram(
            core::string_utils::utf8ToSystem(rScriptPath.absolutePath()),
            args,
            "",
            options,
            &result);
   if (error)
   {
      LOG_ERROR(error);
      return std::vector<std::string>();
   }

   // break into lines
   std::vector<std::string> lines;
   boost::algorithm::split(lines, result.stdOut,
                           boost::algorithm::is_any_of("\r\n"));

   // find the line with the compilation and add it's args
   std::string compile = "-c " + cppPath.filename() + " -o " + cppPath.stem();
   BOOST_FOREACH(const std::string& line, lines)
   {
      if (line.find(compile) != std::string::npos)
      {
         std::vector<std::string> args = extractCompileArgs(line);
         std::copy(args.begin(), args.end(), std::back_inserter(compileArgs));
      }
   }

   // return the args
   return compileArgs;
}

std::string buildFileHash(const FilePath& filePath)
{
   if (filePath.exists())
   {
      std::ostringstream ostr;
      ostr << filePath.lastWriteTime();
      return ostr.str();
   }
   else
   {
      return std::string();
   }
}

std::string packageBuildFileHash()
{
   std::ostringstream ostr;
   FilePath buildPath = projects::projectContext().buildTargetPath();
   ostr << buildFileHash(buildPath.childPath("DESCRIPTION"));
   FilePath srcPath = buildPath.childPath("src");
   if (srcPath.exists())
   {
      ostr << buildFileHash(srcPath.childPath("Makevars"));
      ostr << buildFileHash(srcPath.childPath("Makevars.win"));
   }
   return ostr.str();
}

} // anonymous namespace

CompilationDatabase::~CompilationDatabase()
{
   try
   {

   }
   catch(...)
   {
   }
}

void CompilationDatabase::updateForCurrentPackage()
{
   // check hash to see if we can avoid this computation
   std::string buildFileHash = packageBuildFileHash();
   if (buildFileHash == packageBuildFileHash_)
      return;
   packageBuildFileHash_ = buildFileHash;

   TIME_FUNCTION

   // to approximate the compiler flags for files in the package src
   // directory we will build a temporary sourceCpp file
   std::ostringstream ostr;
   ostr << "#include <Rcpp.h>" << std::endl;
   ostr << "// [[Rcpp::export]]" << std::endl;
   ostr << "void foo() {}" << std::endl;

   // read the package description file
   using namespace projects;
   FilePath pkgPath = projectContext().buildTargetPath();
   core::r_util::RPackageInfo pkgInfo;
   Error error = pkgInfo.read(pkgPath);
   if (error)
   {
      LOG_ERROR(error);
      return;
   }

   // Discover all of the LinkingTo relationships
   if (!pkgInfo.linkingTo().empty())
   {
      std::vector<std::string> linkingTo;
      r::exec::RFunction parseLinkingTo(".rs.parseLinkingTo");
      parseLinkingTo.addParam(pkgInfo.linkingTo());
      Error error = parseLinkingTo.call(&linkingTo);
      if (error)
         LOG_ERROR(error);

      // emit Rcpp::depends for linking to
      BOOST_FOREACH(const std::string& pkg, linkingTo)
      {
         ostr << "// [[Rcpp::depends(" << pkg << ")]]" << std::endl;
      }
   }

   // write a temp file with all of the depends
   FilePath tempCpp = module_context::tempFile("clangdb", "cpp");
   error = core::writeStringToFile(tempCpp, ostr.str());
   if (error)
   {
      LOG_ERROR(error);
      return;
   }

   // Do a sourceCpp dryRun to capture the baseline config (bail on error)
   std::vector<std::string> args = argsForSourceCpp(tempCpp);
   if (args.empty())
      return;

   // Read Makevars to get PKG_CXXFLAGS and add that
   FilePath srcPath = pkgPath.childPath("src");
   if (srcPath.exists())
   {
      std::string makevars = "Makevars";
#ifdef _WIN32
      if (srcPath.childPath("Makevars.win").exists())
         makevars = "Makevars.win";
#endif
      FilePath makevarsPath = srcPath.childPath(makevars);
      if (makevarsPath.exists())
      {
         // read makevars into lines
         std::vector<std::string> lines;
         Error error = core::readStringVectorFromFile(makevarsPath, &lines);
         if (error)
            LOG_ERROR(error);

         BOOST_FOREACH(const std::string& line, lines)
         {
            if (line.find("PKG_CFLAGS") != std::string::npos ||
                line.find("PKG_CXXFLAGS") != std::string::npos ||
                line.find("PKG_CPPFLAGS") != std::string::npos)
            {
               std::vector<std::string> mArgs = extractCompileArgs(line);
               BOOST_FOREACH(std::string arg, mArgs)
               {
                  // do path substitutions
                  boost::algorithm::replace_first(
                           arg,
                           "-I..",
                           "-I" + srcPath.parent().absolutePath());
                  boost::algorithm::replace_first(
                           arg,
                           "-I.",
                           "-I" + srcPath.absolutePath());

                  args.push_back(arg);
               }
            }
         }
      }
   }

   // set the args
   packageSrcArgs_ = args;

   // wipe out any exising translation units that map to this package
   FilePath pkgSrcDir = projectContext().buildTargetPath().childPath("src");
   std::vector<FilePath> pkgSrcFiles;
   error = pkgSrcDir.children(&pkgSrcFiles);
   if (error)
   {
      LOG_ERROR(error);
      return;
   }
   BOOST_FOREACH(const FilePath& srcPath, pkgSrcFiles)
   {
      sourceIndex().removeTranslationUnit(srcPath.absolutePath());
   }
}

void CompilationDatabase::updateForStandaloneCpp(const core::FilePath& cppPath)
{
   TIME_FUNCTION

   // read the dependency attributes within the cpp file to compare to
   // previous sets of attributes we've used to generate compilation args.
   // bail if we've already generated based on these attributes
   std::string attributes = readDependencyAttributes(cppPath);
   AttribsMap::const_iterator it = attribsMap_.find(cppPath.absolutePath());
   if (it != attribsMap_.end() && it->second == attributes)
      return;

   // arguments for this translation unit
   std::vector<std::string> args = argsForSourceCpp(cppPath);

   // if we got args then update
   if (!args.empty())
   {
      // update if necessary
      updateIfNecessary(cppPath.absolutePath(), args);

      // save attributes to prevent recomputation
      attribsMap_[cppPath.absolutePath()] = attributes;
   }
}

std::vector<std::string> CompilationDatabase::argsForFile(
                                       const std::string& cppPath) const
{
   // if this is a package source file then return the package args
   using namespace projects;
   FilePath filePath(cppPath);
   if (projectContext().config().buildType == r_util::kBuildTypePackage &&
       filePath.parent() == projectContext().buildTargetPath().childPath("src"))
   {
      return packageSrcArgs_;
   }
   // otherwise lookup in the global dictionary
   else
   {
      ArgsMap::const_iterator it = argsMap_.find(cppPath);
      if (it != argsMap_.end())
         return it->second;
      else
         return std::vector<std::string>();
   }
}

std::vector<std::string> CompilationDatabase::rToolsArgs() const
{

#ifdef _WIN32
   if (rToolsArgs_.empty())
   {
      // scan for Rtools
      std::vector<core::r_util::RToolsInfo> rTools;
      Error error = core::r_util::scanRegistryForRTools(&rTools);
      if (error)
         LOG_ERROR(error);

      // enumerate them to see if we have a compatible version
      // (go in reverse order for most recent first)
      std::vector<r_util::RToolsInfo>::const_reverse_iterator it = rTools.rbegin();
      for ( ; it != rTools.rend(); ++it)
      {
         if (module_context::isRtoolsCompatible(*it))
         {
            FilePath rtoolsPath = it->installPath();

            rToolsArgs_.push_back("-I" + rtoolsPath.childPath(
               "gcc-4.6.3/i686-w64-mingw32/include").absolutePath());

            rToolsArgs_.push_back("-I" + rtoolsPath.childPath(
               "gcc-4.6.3/include/c++/4.6.3").absolutePath());

            std::string bits = "-I" + rtoolsPath.childPath(
               "gcc-4.6.3/include/c++/4.6.3/i686-w64-mingw32").absolutePath();
#ifdef _WIN64
            bits += "/64";
#endif
            rToolsArgs_.push_back(bits);

            break;
         }
      }
   }
#endif

   return rToolsArgs_;
}

void CompilationDatabase::updateIfNecessary(
                                    const std::string& cppPath,
                                    const std::vector<std::string>& args)
{
   // get existing args
   std::vector<std::string> existingArgs = argsForFile(cppPath);
   if (args != existingArgs)
   {
      // invalidate the source index
      sourceIndex().removeTranslationUnit(cppPath);

      // update
      argsMap_[cppPath] = args;
   }
}

CompilationDatabase& compilationDatabase()
{
   static CompilationDatabase instance;
   return instance;
}

} // namespace libclang
} // namespace clang
} // namespace modules
} // namesapce session

<commit_msg>handle continuation lines when parsing Makevars<commit_after>/*
 * CompilationDatabase.cpp
 *
 * Copyright (C) 2009-12 by RStudio, Inc.
 *
 * Unless you have received this program directly from RStudio pursuant
 * to the terms of a commercial license agreement with RStudio, then
 * this program is licensed to you under the terms of version 3 of the
 * GNU Affero General Public License. This program is distributed WITHOUT
 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
 *
 */

#include "CompilationDatabase.hpp"

#include <algorithm>

#include <boost/regex.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/trim_all.hpp>

#include <core/Error.hpp>
#include <core/PerformanceTimer.hpp>
#include <core/FileSerializer.hpp>

#include <core/r_util/RToolsInfo.hpp>

#include <core/system/Process.hpp>
#include <core/system/Environment.hpp>

#include <core/r_util/RPackageInfo.hpp>

#include <r/RExec.hpp>

#include <session/projects/SessionProjects.hpp>
#include <session/SessionModuleContext.hpp>

#include "LibClang.hpp"
#include "SourceIndex.hpp"

using namespace core ;

namespace session {
namespace modules {
namespace clang {
namespace libclang {

namespace {

std::string readDependencyAttributes(const core::FilePath& cppPath)
{
   // read file
   std::string contents;
   Error error = core::readStringFromFile(cppPath, &contents);
   if (error)
   {
      LOG_ERROR(error);
      return std::string();
   }

   // find dependency attributes
   std::string attributes;
   boost::regex re(
     "^\\s*//\\s*\\[\\[Rcpp::(\\w+)(\\(.*?\\))?\\]\\]\\s*$");
   boost::sregex_token_iterator it(contents.begin(), contents.end(), re, 0);
   boost::sregex_token_iterator end;
   for ( ; it != end; ++it)
   {
      std::string attrib = *it;
      boost::algorithm::trim_all(attrib);
      attributes.append(attrib);
   }

   // return them
   return attributes;
}

std::vector<std::string> extractCompileArgs(const std::string& line)
{
   std::vector<std::string> compileArgs;

   // find arguments libclang might care about
   boost::regex re("-[I|D|i|f|s](?:\\\"[^\\\"]+\\\"|[^ ]+)");
   boost::sregex_token_iterator it(line.begin(), line.end(), re, 0);
   boost::sregex_token_iterator end;
   for ( ; it != end; ++it)
   {
      // remove quotes and add it to the compile args
      std::string arg = *it;
      boost::algorithm::replace_all(arg, "\"", "");
      compileArgs.push_back(arg);
   }

   return compileArgs;
}

std::vector<std::string> argsForSourceCpp(const core::FilePath& cppPath)
{
   // baseline args
   std::vector<std::string> compileArgs;
   std::string builtinHeaders = "-I" + clang().builtinHeaders();
   compileArgs.push_back(builtinHeaders);
#if defined(_WIN32)
   std::vector<std::string> rtoolsArgs = rToolsArgs();
   std::copy(rtoolsArgs.begin(),
             rtoolsArgs.end(),
             std::back_inserter(compileArgs));
#elif defined(__APPLE__)
   compileArgs.push_back("-stdlib=libstdc++");
#endif

   // get path to R script
   FilePath rScriptPath;
   Error error = module_context::rScriptPath(&rScriptPath);
   if (error)
   {
      LOG_ERROR(error);
      return std::vector<std::string>();
   }

   // setup env and options
   core::system::Options env;
   core::system::ProcessOptions options;

   // always run as a slave
   std::vector<std::string> args;
   args.push_back("--slave");

   // for packrat projects we execute the profile and set the working
   // directory to the project directory; for other contexts we just
   // propagate the R_LIBS
   if (module_context::packratContext().modeOn)
   {
      options.workingDir = projects::projectContext().directory();
      args.push_back("--no-save");
      args.push_back("--no-restore");
   }
   else
   {
      args.push_back("--vanilla");
      std::string libPaths = module_context::libPathsString();
      if (!libPaths.empty())
         core::system::setenv(&env, "R_LIBS", libPaths);
   }

   // add rtools to path if we need to
   std::string warning;
   module_context::addRtoolsToPathIfNecessary(&env, &warning);

   // set environment into options
   options.environment = env;

   // add command to arguments
   args.push_back("-e");
   boost::format fmt("Rcpp::sourceCpp('%1%', showOutput = TRUE, dryRun = TRUE)");
   args.push_back(boost::str(fmt % cppPath.absolutePath()));

   // execute and capture output
   core::system::ProcessResult result;
   error = core::system::runProgram(
            core::string_utils::utf8ToSystem(rScriptPath.absolutePath()),
            args,
            "",
            options,
            &result);
   if (error)
   {
      LOG_ERROR(error);
      return std::vector<std::string>();
   }

   // break into lines
   std::vector<std::string> lines;
   boost::algorithm::split(lines, result.stdOut,
                           boost::algorithm::is_any_of("\r\n"));

   // find the line with the compilation and add it's args
   std::string compile = "-c " + cppPath.filename() + " -o " + cppPath.stem();
   BOOST_FOREACH(const std::string& line, lines)
   {
      if (line.find(compile) != std::string::npos)
      {
         std::vector<std::string> args = extractCompileArgs(line);
         std::copy(args.begin(), args.end(), std::back_inserter(compileArgs));
      }
   }

   // return the args
   return compileArgs;
}

std::string buildFileHash(const FilePath& filePath)
{
   if (filePath.exists())
   {
      std::ostringstream ostr;
      ostr << filePath.lastWriteTime();
      return ostr.str();
   }
   else
   {
      return std::string();
   }
}

std::string packageBuildFileHash()
{
   std::ostringstream ostr;
   FilePath buildPath = projects::projectContext().buildTargetPath();
   ostr << buildFileHash(buildPath.childPath("DESCRIPTION"));
   FilePath srcPath = buildPath.childPath("src");
   if (srcPath.exists())
   {
      ostr << buildFileHash(srcPath.childPath("Makevars"));
      ostr << buildFileHash(srcPath.childPath("Makevars.win"));
   }
   return ostr.str();
}

} // anonymous namespace

CompilationDatabase::~CompilationDatabase()
{
   try
   {

   }
   catch(...)
   {
   }
}

void CompilationDatabase::updateForCurrentPackage()
{
   // check hash to see if we can avoid this computation
   std::string buildFileHash = packageBuildFileHash();
   if (buildFileHash == packageBuildFileHash_)
      return;
   packageBuildFileHash_ = buildFileHash;

   TIME_FUNCTION

   // to approximate the compiler flags for files in the package src
   // directory we will build a temporary sourceCpp file
   std::ostringstream ostr;
   ostr << "#include <Rcpp.h>" << std::endl;
   ostr << "// [[Rcpp::export]]" << std::endl;
   ostr << "void foo() {}" << std::endl;

   // read the package description file
   using namespace projects;
   FilePath pkgPath = projectContext().buildTargetPath();
   core::r_util::RPackageInfo pkgInfo;
   Error error = pkgInfo.read(pkgPath);
   if (error)
   {
      LOG_ERROR(error);
      return;
   }

   // Discover all of the LinkingTo relationships
   if (!pkgInfo.linkingTo().empty())
   {
      std::vector<std::string> linkingTo;
      r::exec::RFunction parseLinkingTo(".rs.parseLinkingTo");
      parseLinkingTo.addParam(pkgInfo.linkingTo());
      Error error = parseLinkingTo.call(&linkingTo);
      if (error)
         LOG_ERROR(error);

      // emit Rcpp::depends for linking to
      BOOST_FOREACH(const std::string& pkg, linkingTo)
      {
         ostr << "// [[Rcpp::depends(" << pkg << ")]]" << std::endl;
      }
   }

   // write a temp file with all of the depends
   FilePath tempCpp = module_context::tempFile("clangdb", "cpp");
   error = core::writeStringToFile(tempCpp, ostr.str());
   if (error)
   {
      LOG_ERROR(error);
      return;
   }

   // Do a sourceCpp dryRun to capture the baseline config (bail on error)
   std::vector<std::string> args = argsForSourceCpp(tempCpp);
   if (args.empty())
      return;

   // Read Makevars to get PKG_CXXFLAGS and add that
   FilePath srcPath = pkgPath.childPath("src");
   if (srcPath.exists())
   {
      std::string makevars = "Makevars";
#ifdef _WIN32
      if (srcPath.childPath("Makevars.win").exists())
         makevars = "Makevars.win";
#endif
      FilePath makevarsPath = srcPath.childPath(makevars);
      if (makevarsPath.exists())
      {
         // read makevars into lines
         std::vector<std::string> lines;
         Error error = core::readStringVectorFromFile(makevarsPath, &lines);
         if (error)
            LOG_ERROR(error);

         bool continuationLine = false;
         BOOST_FOREACH(std::string line, lines)
         {
            boost::algorithm::trim_all(line);

            if (line.find("PKG_CFLAGS") != std::string::npos ||
                line.find("PKG_CXXFLAGS") != std::string::npos ||
                line.find("PKG_CPPFLAGS") != std::string::npos ||
                continuationLine)
            {
               std::vector<std::string> mArgs = extractCompileArgs(line);
               BOOST_FOREACH(std::string arg, mArgs)
               {
                  // do path substitutions
                  boost::algorithm::replace_first(
                           arg,
                           "-I..",
                           "-I" + srcPath.parent().absolutePath());
                  boost::algorithm::replace_first(
                           arg,
                           "-I.",
                           "-I" + srcPath.absolutePath());

                  args.push_back(arg);
               }

               continuationLine = boost::algorithm::ends_with(line, "\\");
            }
         }
      }
   }

   // set the args
   packageSrcArgs_ = args;

   // wipe out any exising translation units that map to this package
   FilePath pkgSrcDir = projectContext().buildTargetPath().childPath("src");
   std::vector<FilePath> pkgSrcFiles;
   error = pkgSrcDir.children(&pkgSrcFiles);
   if (error)
   {
      LOG_ERROR(error);
      return;
   }
   BOOST_FOREACH(const FilePath& srcPath, pkgSrcFiles)
   {
      sourceIndex().removeTranslationUnit(srcPath.absolutePath());
   }
}

void CompilationDatabase::updateForStandaloneCpp(const core::FilePath& cppPath)
{
   TIME_FUNCTION

   // read the dependency attributes within the cpp file to compare to
   // previous sets of attributes we've used to generate compilation args.
   // bail if we've already generated based on these attributes
   std::string attributes = readDependencyAttributes(cppPath);
   AttribsMap::const_iterator it = attribsMap_.find(cppPath.absolutePath());
   if (it != attribsMap_.end() && it->second == attributes)
      return;

   // arguments for this translation unit
   std::vector<std::string> args = argsForSourceCpp(cppPath);

   // if we got args then update
   if (!args.empty())
   {
      // update if necessary
      updateIfNecessary(cppPath.absolutePath(), args);

      // save attributes to prevent recomputation
      attribsMap_[cppPath.absolutePath()] = attributes;
   }
}

std::vector<std::string> CompilationDatabase::argsForFile(
                                       const std::string& cppPath) const
{
   // if this is a package source file then return the package args
   using namespace projects;
   FilePath filePath(cppPath);
   if (projectContext().config().buildType == r_util::kBuildTypePackage &&
       filePath.parent() == projectContext().buildTargetPath().childPath("src"))
   {
      return packageSrcArgs_;
   }
   // otherwise lookup in the global dictionary
   else
   {
      ArgsMap::const_iterator it = argsMap_.find(cppPath);
      if (it != argsMap_.end())
         return it->second;
      else
         return std::vector<std::string>();
   }
}

std::vector<std::string> CompilationDatabase::rToolsArgs() const
{

#ifdef _WIN32
   if (rToolsArgs_.empty())
   {
      // scan for Rtools
      std::vector<core::r_util::RToolsInfo> rTools;
      Error error = core::r_util::scanRegistryForRTools(&rTools);
      if (error)
         LOG_ERROR(error);

      // enumerate them to see if we have a compatible version
      // (go in reverse order for most recent first)
      std::vector<r_util::RToolsInfo>::const_reverse_iterator it = rTools.rbegin();
      for ( ; it != rTools.rend(); ++it)
      {
         if (module_context::isRtoolsCompatible(*it))
         {
            FilePath rtoolsPath = it->installPath();

            rToolsArgs_.push_back("-I" + rtoolsPath.childPath(
               "gcc-4.6.3/i686-w64-mingw32/include").absolutePath());

            rToolsArgs_.push_back("-I" + rtoolsPath.childPath(
               "gcc-4.6.3/include/c++/4.6.3").absolutePath());

            std::string bits = "-I" + rtoolsPath.childPath(
               "gcc-4.6.3/include/c++/4.6.3/i686-w64-mingw32").absolutePath();
#ifdef _WIN64
            bits += "/64";
#endif
            rToolsArgs_.push_back(bits);

            break;
         }
      }
   }
#endif

   return rToolsArgs_;
}

void CompilationDatabase::updateIfNecessary(
                                    const std::string& cppPath,
                                    const std::vector<std::string>& args)
{
   // get existing args
   std::vector<std::string> existingArgs = argsForFile(cppPath);
   if (args != existingArgs)
   {
      // invalidate the source index
      sourceIndex().removeTranslationUnit(cppPath);

      // update
      argsMap_[cppPath] = args;
   }
}

CompilationDatabase& compilationDatabase()
{
   static CompilationDatabase instance;
   return instance;
}

} // namespace libclang
} // namespace clang
} // namespace modules
} // namesapce session

<|endoftext|>


<commit_before>#include <iostream>
#include <vector>
#include <string>

#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/variant/recursive_variant.hpp>
#include <boost/variant/apply_visitor.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/phoenix_function.hpp>

#include "detail/ast.hpp"
#include "compiler.h"
#include "equality_expression.h"
#include "filter.h"
#include "string_operator.h"

namespace filter {

namespace client
{
    namespace qi = boost::spirit::qi;
    namespace ascii = boost::spirit::ascii;

    ///////////////////////////////////////////////////////////////////////////
    //  Walk the tree
    ///////////////////////////////////////////////////////////////////////////
    struct ast_print
    {
        typedef void result_type;

        void operator()(qi::info::nil) const {}
        void operator()(int n) const { std::cout << n; }
        void operator()(bool b) const { std::cout << (b ? "true" : "false"); }
        void operator()(const std::string &s) const { std::cout << s; }
        void operator()(const equality_expression &s) const {
            std::cout << s.identifier << (s.op == s.EQ ? "==" : "!=");
            this->operator()(s.constant);
        }

        void operator()(const nil &) const { std::cout << "/nil/"; }

        void operator()(detail::expression_ast const& ast) const
        {
            boost::apply_visitor(*this, ast.expr);
        }

        void operator()(detail::binary_op const& expr) const
        {
            std::cout << "op:" << expr.op << "(";
            boost::apply_visitor(*this, expr.left.expr);
            std::cout << ", ";
            boost::apply_visitor(*this, expr.right.expr);
            std::cout << ')';
        }
    };

/*

creative_id == 123 or (request.uri == "/bad" and r.lua_data =~ nil) or is_local == true

*/
    ///////////////////////////////////////////////////////////////////////////
    //  Our calculator grammar
    ///////////////////////////////////////////////////////////////////////////

    template <typename Iterator>
    struct calculator : qi::grammar<Iterator, detail::expression_ast(), ascii::space_type>
    {
        calculator() : calculator::base_type(condition)
        {
            using qi::_val;
            using qi::_1;
            using qi::int_;
            using qi::bool_;
            using qi::double_;
            using qi::string;
            using qi::lexeme;
            using qi::lit;
            using ascii::char_;

            quoted_string =
                  lexeme['"' >> +(char_ - '"') >> '"']
                | lexeme['\'' >> +(char_ - '\'') >> '\'']
                ;

            constant =
                  double_           [_val = _1 ]
                | bool_             [_val = _1 ]
                | int_              [_val = _1 ]
                | quoted_string     [_val = _1 ]
                | lit("nil")        [_val = filter::nil()];

            identifier =
                lexeme[+char_("0-9a-zA-Z._")]
                ;

            equality_expr =
                identifier                  [_val =  _1]
                    >>  ( ("==" >> constant [_val == _1])
                        | ("~=" >> constant [_val != _1])
                        | ("<"  >> constant [_val <  _1])
                        | (">"  >> constant [_val >  _1])
                        | ("<=" >> constant [_val <= _1])
                        | ("=>" >> constant [_val >= _1])
                        )
                    |

                identifier                       [_val = _1]
                    >> (
                            (
                                lit(":contains(")      [_val |= string_operator(string_operator::CONTAINS)]
                                | lit(":starts_with(") [_val |= string_operator(string_operator::STARTS_WITH)]
                                | lit(":ends_with(")   [_val |= string_operator(string_operator::ENDS_WITH)]
                            )
                         >> quoted_string        [_val |= _1]
                         >> ')'
                       )
                ;

            braces_expr =
                  '(' >> logical_expression [_val = _1] >> ')'
                | equality_expr             [_val = _1];

            logical_expression =
                    braces_expr                 [_val = _1]
                    >> *( ("and" >> braces_expr [_val &= _1])
                        | ("or"  >> braces_expr [_val |= _1])
                        )
                ;

            condition =
                  logical_expression                [_val = _1]
                ;
        }

        qi::rule<Iterator, detail::expression_ast(), ascii::space_type>
        logical_expression, condition, braces_expr;

        qi::rule<Iterator, equality_expression::type(), ascii::space_type> constant;
        qi::rule<Iterator, equality_expression(), ascii::space_type> equality_expr;
        qi::rule<Iterator, std::string(), ascii::space_type> quoted_string;
        qi::rule<Iterator, std::string(), ascii::space_type> identifier;
    };

}

Compiler::CompileError::CompileError(const std::string &rest)
    : rest(rest) {
}

std::string Compiler::CompileError::what() const {
    return "stopped at: \": " + rest + "\"\n";
}

std::shared_ptr<Filter> Compiler::compile(const std::string &str) {
    using boost::spirit::ascii::space;
    using detail::expression_ast;
    typedef std::string::const_iterator iterator_type;
    typedef client::calculator<iterator_type> calculator;

    std::string::const_iterator iter = str.begin();
    std::string::const_iterator end = str.end();
    detail::expression_ast ast; // = std::make_shared<detail::expression_ast>();
    // ast_print printer;
    calculator calc; // Our grammar
    bool r = phrase_parse(iter, end, calc, space, ast);

    if (r && iter == end)
    {
        // std::cout << "-------------------------\n";
        // std::cout << "Parsing succeeded\n";
        // printer(ast);
        // std::cout << "\n-------------------------\n";
    }
    else
    {
        std::string rest(iter, end);
        throw CompileError(rest);
    }
    return std::make_shared<Filter>(ast);
}

}
<commit_msg>Used wrong operator in filtering expression<commit_after>#include <iostream>
#include <vector>
#include <string>

#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/variant/recursive_variant.hpp>
#include <boost/variant/apply_visitor.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/phoenix_function.hpp>

#include "detail/ast.hpp"
#include "compiler.h"
#include "equality_expression.h"
#include "filter.h"
#include "string_operator.h"

namespace filter {

namespace client
{
    namespace qi = boost::spirit::qi;
    namespace ascii = boost::spirit::ascii;

    ///////////////////////////////////////////////////////////////////////////
    //  Walk the tree
    ///////////////////////////////////////////////////////////////////////////
    struct ast_print
    {
        typedef void result_type;

        void operator()(qi::info::nil) const {}
        void operator()(int n) const { std::cout << n; }
        void operator()(bool b) const { std::cout << (b ? "true" : "false"); }
        void operator()(const std::string &s) const { std::cout << s; }
        void operator()(const equality_expression &s) const {
            std::cout << s.identifier << (s.op == s.EQ ? "==" : "!=");
            this->operator()(s.constant);
        }

        void operator()(const nil &) const { std::cout << "/nil/"; }

        void operator()(detail::expression_ast const& ast) const
        {
            boost::apply_visitor(*this, ast.expr);
        }

        void operator()(detail::binary_op const& expr) const
        {
            std::cout << "op:" << expr.op << "(";
            boost::apply_visitor(*this, expr.left.expr);
            std::cout << ", ";
            boost::apply_visitor(*this, expr.right.expr);
            std::cout << ')';
        }
    };

/*

creative_id == 123 or (request.uri == "/bad" and r.lua_data =~ nil) or is_local == true

*/
    ///////////////////////////////////////////////////////////////////////////
    //  Our calculator grammar
    ///////////////////////////////////////////////////////////////////////////

    template <typename Iterator>
    struct calculator : qi::grammar<Iterator, detail::expression_ast(), ascii::space_type>
    {
        calculator() : calculator::base_type(condition)
        {
            using qi::_val;
            using qi::_1;
            using qi::int_;
            using qi::bool_;
            using qi::double_;
            using qi::string;
            using qi::lexeme;
            using qi::lit;
            using ascii::char_;

            quoted_string =
                  lexeme['"' >> +(char_ - '"') >> '"']
                | lexeme['\'' >> +(char_ - '\'') >> '\'']
                ;

            constant =
                  double_           [_val = _1 ]
                | bool_             [_val = _1 ]
                | int_              [_val = _1 ]
                | quoted_string     [_val = _1 ]
                | lit("nil")        [_val = filter::nil()];

            identifier =
                lexeme[+char_("0-9a-zA-Z._")]
                ;

            equality_expr =
                identifier                  [_val =  _1]
                    >>  ( ("==" >> constant [_val == _1])
                        | ("~=" >> constant [_val != _1])
                        | ("<"  >> constant [_val <  _1])
                        | (">"  >> constant [_val >  _1])
                        | ("<=" >> constant [_val <= _1])
                        | (">=" >> constant [_val >= _1])
                        )
                    |

                identifier                       [_val = _1]
                    >> (
                            (
                                lit(":contains(")      [_val |= string_operator(string_operator::CONTAINS)]
                                | lit(":starts_with(") [_val |= string_operator(string_operator::STARTS_WITH)]
                                | lit(":ends_with(")   [_val |= string_operator(string_operator::ENDS_WITH)]
                            )
                         >> quoted_string        [_val |= _1]
                         >> ')'
                       )
                ;

            braces_expr =
                  '(' >> logical_expression [_val = _1] >> ')'
                | equality_expr             [_val = _1];

            logical_expression =
                    braces_expr                 [_val = _1]
                    >> *( ("and" >> braces_expr [_val &= _1])
                        | ("or"  >> braces_expr [_val |= _1])
                        )
                ;

            condition =
                  logical_expression                [_val = _1]
                ;
        }

        qi::rule<Iterator, detail::expression_ast(), ascii::space_type>
        logical_expression, condition, braces_expr;

        qi::rule<Iterator, equality_expression::type(), ascii::space_type> constant;
        qi::rule<Iterator, equality_expression(), ascii::space_type> equality_expr;
        qi::rule<Iterator, std::string(), ascii::space_type> quoted_string;
        qi::rule<Iterator, std::string(), ascii::space_type> identifier;
    };

}

Compiler::CompileError::CompileError(const std::string &rest)
    : rest(rest) {
}

std::string Compiler::CompileError::what() const {
    return "stopped at: \": " + rest + "\"\n";
}

std::shared_ptr<Filter> Compiler::compile(const std::string &str) {
    using boost::spirit::ascii::space;
    using detail::expression_ast;
    typedef std::string::const_iterator iterator_type;
    typedef client::calculator<iterator_type> calculator;

    std::string::const_iterator iter = str.begin();
    std::string::const_iterator end = str.end();
    detail::expression_ast ast; // = std::make_shared<detail::expression_ast>();
    // ast_print printer;
    calculator calc; // Our grammar
    bool r = phrase_parse(iter, end, calc, space, ast);

    if (r && iter == end)
    {
        // std::cout << "-------------------------\n";
        // std::cout << "Parsing succeeded\n";
        // printer(ast);
        // std::cout << "\n-------------------------\n";
    }
    else
    {
        std::string rest(iter, end);
        throw CompileError(rest);
    }
    return std::make_shared<Filter>(ast);
}

}
<|endoftext|>


<commit_before>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ash/shell_context_menu.h"

#include "ash/desktop_background/desktop_background_controller.h"
#include "ash/shell.h"
#include "grit/ash_strings.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/views/controls/menu/menu_model_adapter.h"
#include "ui/views/controls/menu/menu_runner.h"

namespace ash {
namespace internal {

ShellContextMenu::ShellContextMenu() {
}

ShellContextMenu::~ShellContextMenu() {
}

void ShellContextMenu::ShowMenu(views::Widget* widget,
                                const gfx::Point& location) {
  ui::SimpleMenuModel menu_model(this);
  menu_model.AddItem(MENU_CHANGE_WALLPAPER,
      l10n_util::GetStringUTF16(IDS_AURA_SET_DESKTOP_WALLPAPER));
  views::MenuModelAdapter menu_model_adapter(&menu_model);
  menu_runner_.reset(new views::MenuRunner(menu_model_adapter.CreateMenu()));
  if (menu_runner_->RunMenuAt(
          widget, NULL, gfx::Rect(location, gfx::Size()),
          views::MenuItemView::TOPLEFT, views::MenuRunner::HAS_MNEMONICS) ==
      views::MenuRunner::MENU_DELETED)
    return;
}

bool ShellContextMenu::IsCommandIdChecked(int command_id) const {
  return false;
}

bool ShellContextMenu::IsCommandIdEnabled(int command_id) const {
  switch (static_cast<MenuItem>(command_id)) {
    case MENU_CHANGE_WALLPAPER: {
      return Shell::GetInstance()->user_wallpaper_delegate()->
          CanOpenSetWallpaperPage();
    }
    default:
      return true;
  }
}

void ShellContextMenu::ExecuteCommand(int command_id) {
  switch (static_cast<MenuItem>(command_id)) {
    case MENU_CHANGE_WALLPAPER: {
      Shell::GetInstance()->user_wallpaper_delegate()->
          OpenSetWallpaperPage();
      break;
    }
  }
}

bool ShellContextMenu::GetAcceleratorForCommandId(
      int command_id,
      ui::Accelerator* accelerator) {
  return false;
}

}  // namespace internal
}  // namespace ash
<commit_msg>Activate RootWindow when opening background ContextMenu  This causes the active root window != the root window of active window. I'm still vague about what this really means, but this was causing a menu widget being created on other display (which leads to crash) and I'd like to check this in to proceed.<commit_after>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ash/shell_context_menu.h"

#include "ash/desktop_background/desktop_background_controller.h"
#include "ash/shell.h"
#include "grit/ash_strings.h"
#include "ui/aura/window.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/views/controls/menu/menu_model_adapter.h"
#include "ui/views/controls/menu/menu_runner.h"
#include "ui/views/widget/widget.h"

namespace ash {
namespace internal {

ShellContextMenu::ShellContextMenu() {
}

ShellContextMenu::~ShellContextMenu() {
}

void ShellContextMenu::ShowMenu(views::Widget* widget,
                                const gfx::Point& location) {
  // TODO(oshima): Figure out the exact semantics of
  // just switching the active root window without changing the
  // active window.
  Shell::GetInstance()->set_active_root_window(
      widget->GetNativeView()->GetRootWindow());

  ui::SimpleMenuModel menu_model(this);
  menu_model.AddItem(MENU_CHANGE_WALLPAPER,
      l10n_util::GetStringUTF16(IDS_AURA_SET_DESKTOP_WALLPAPER));
  views::MenuModelAdapter menu_model_adapter(&menu_model);
  menu_runner_.reset(new views::MenuRunner(menu_model_adapter.CreateMenu()));
  if (menu_runner_->RunMenuAt(
          widget, NULL, gfx::Rect(location, gfx::Size()),
          views::MenuItemView::TOPLEFT, views::MenuRunner::HAS_MNEMONICS) ==
      views::MenuRunner::MENU_DELETED)
    return;
}

bool ShellContextMenu::IsCommandIdChecked(int command_id) const {
  return false;
}

bool ShellContextMenu::IsCommandIdEnabled(int command_id) const {
  switch (static_cast<MenuItem>(command_id)) {
    case MENU_CHANGE_WALLPAPER: {
      return Shell::GetInstance()->user_wallpaper_delegate()->
          CanOpenSetWallpaperPage();
    }
    default:
      return true;
  }
}

void ShellContextMenu::ExecuteCommand(int command_id) {
  switch (static_cast<MenuItem>(command_id)) {
    case MENU_CHANGE_WALLPAPER: {
      Shell::GetInstance()->user_wallpaper_delegate()->
          OpenSetWallpaperPage();
      break;
    }
  }
}

bool ShellContextMenu::GetAcceleratorForCommandId(
      int command_id,
      ui::Accelerator* accelerator) {
  return false;
}

}  // namespace internal
}  // namespace ash
<|endoftext|>