~aleteoryx/muditaos

ref: dc9ad45a04a4b592ee020debea06fe51a2560f8c muditaos/module-db/Database/DatabaseInitializer.cpp -rw-r--r-- 4.2 KiB
dc9ad45a — Adam Dobrowolski [MOS-53] Not enough stack for audio worker 3 years ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "DatabaseInitializer.hpp"

#include <algorithm>
#include <cstdio>
#include <memory>
#include <set>
#include <string>
#include <sstream>
#include <array>
#include <log/log.hpp>

DatabaseInitializer::DatabaseInitializer(Database *db) : db(db)
{}

bool DatabaseInitializer::run(std::filesystem::path path, std::string ext)
{
    // Database name is database file path, need to strip off all filesystem related stuff(path, extension)
    std::filesystem::path dbpath = db->getName();
    std::string dbname           = dbpath.filename().replace_extension();

    for (int i = 1;; i++) {
        auto fname = std::make_unique<std::stringstream>();
        (*fname) << dbname << "_" << std::setfill('0') << std::setw(3) << i << '.' << ext;
        auto file = path / fname->str();
        LOG_DEBUG("Running db script: %s", file.c_str());
        auto commands = readCommands(file);
        if (commands.empty())
            break;
        if (!executeOnDb(commands)) {
            LOG_ERROR("Can't initialize database [%s] with [%s]", db->getName().c_str(), file.c_str());
            return false;
        }
    }
    return true;
}

std::string DatabaseInitializer::readContent(const char *filename) const noexcept
{
    std::unique_ptr<char[]> fcontent;
    long fsize = 0;

    auto fp = std::fopen(filename, "r");
    if (fp) {
        std::fseek(fp, 0, SEEK_END);
        fsize = std::ftell(fp);
        std::rewind(fp);

        fcontent = std::make_unique<char[]>(fsize + 1);

        std::fread(fcontent.get(), 1, fsize, fp);

        std::fclose(fp);
    }
    else
        return {};

    return std::string(fcontent.get());
}

std::vector<std::string> DatabaseInitializer::readCommands(std::filesystem::path filePath)
{
    auto fileContent = readContent(filePath.c_str());
    if (fileContent.empty())
        return {};

    std::string currentStatement{};
    std::vector<std::string> statements{};

    std::string line{};
    for (auto &c : fileContent) {
        if (c != '\n') {
            line += c;
        }
        else {
            if (line.empty() || starts_with(line, std::string("--"))) {
                line.clear();
                continue;
            }
            if (ends_with(line, std::string(";"))) {
                statements.push_back(currentStatement + line);
                currentStatement.clear();
                line.clear();
                continue;
            }
            currentStatement += line;

            line.clear();
        }
    }
    return statements;
}

std::array<std::string, 3> DatabaseInitializer::splitFilename(std::string filename)
{
    auto name    = filename.substr(0, filename.find("."));
    auto prefix  = name.substr(0, name.find_last_of("_"));
    auto postfix = name.substr(name.find_last_of("_") + 1, std::string::npos);

    return {name, prefix, postfix};
}

std::vector<std::filesystem::path> DatabaseInitializer::listFiles(std::filesystem::path path,
                                                                  std::string prefix,
                                                                  std::string ext)
{
    std::set<std::pair<int, std::filesystem::path>> orderedFiles;
    for (const auto &entry : std::filesystem::directory_iterator(path)) {
        if (!entry.is_directory() && entry.path().has_filename()) {
            try {
                auto parts      = splitFilename(entry.path().filename().string());
                auto filePrefix = parts[1];
                if (filePrefix == prefix) {
                    auto num = std::stoi(parts[2]);
                    orderedFiles.insert({num, entry.path()});
                }
            }
            catch (std::invalid_argument &e) {
                LOG_INFO("Ignoring file: %s", entry.path().c_str());
            }
        }
    }

    std::vector<std::filesystem::path> files;
    std::for_each(orderedFiles.begin(), orderedFiles.end(), [&](auto item) { files.push_back(item.second); });
    return files;
}

bool DatabaseInitializer::executeOnDb(const std::vector<std::string> statements)
{
    for (auto st : statements) {
        if (!db->execute(st.c_str())) {
            return false;
        }
    }
    return true;
}