/* common/KMOstreeRepoCommitModifier.h
 *
 * Copyright (C) 2023 OpenKylin, Inc
 */

#ifndef __KMOSTREEREPO_H__
#define __KMOSTREEREPO_H__


#include <ostree.h>

#include <map>
#include <memory>
#include <string>
#include <vector>

#include "KMCommonTypePrivate.h"
#include "KMFile.h"
#include "KMInputStream.h"
#include "KMOstreeMutableTree.h"
#include "KMOstreeRepoFile.h"
#include "KMVariantDict.h"

/**
 * @brief ostree repo commit modifier
 */
class KMOstreeRepoCommitModifier
{
public:
    KMOstreeRepoCommitModifier(OstreeRepoCommitModifierFlags flags, OstreeRepoCommitFilter commitFilter, gpointer userData, GDestroyNotify destroyNotify);
    KMOstreeRepoCommitModifier(const KMOstreeRepoCommitModifier &other);
    ~KMOstreeRepoCommitModifier();

    KMOstreeRepoCommitModifier &operator=(const KMOstreeRepoCommitModifier &other);

    OstreeRepoCommitModifier *get();

private:
private:
    class Private;
    std::shared_ptr<Private> d = nullptr;
};

class KMOstreeRepo
{
public:
    KMOstreeRepo(const std::string &path);
    ~KMOstreeRepo();

    OstreeRepo *get();

    // 在磁盘上为存储库创建底层结构，并对结果调用ostree_repo_open()，为使用做准备。
    bool create(OstreeRepoMode mode);

    // 打开仓库
    bool open();

    // 获取此存储库repo的集合ID
    std::string getCollectionId() const;
    bool setCollectionId(const std::string &collectionId);

    // 查找给定集合ref的校验和，并在out_rev中返回
    bool resolveCollectionRef(const OstreeCollectionRef *ref, bool allowNoent, OstreeRepoResolveRevExtFlags flags, std::string &tmpOutRev);

    /**
     * 查找给定的refspec，在参数out_rev中返回其引用的校验和。如果在本地找不到给定的refspec，将回退到远程目录
     * 如果要只检查本地引用，而不检查远程引用或镜像引用，请使用标志OSTREE_REPO_RESOLVE_REV_EXT_LOCAL_ONLY
     */
    bool resolveRev(const std::string &refspec, bool allowNoent, std::string &tmpOutRev);
    bool resolveRevExt(const std::string &refspec, bool allowNoent, OstreeRepoResolveRevExtFlags flags, std::string &tmpOutRev);

    /**
     * 在提交期间禁用对稳定存储的fsync（）请求。此选项只能由创建一次性虚拟机的构建系统工具使用，或者具有更高级别的机制来确保数据一致性。
     */
    void setDisableFsync(bool disable);
    bool getDisableFsync();

    // 启动或恢复事务。为了写入repo，需要启动一个事务。可以使用commitTransaction()完成事务，也可以使用ostee_repo_abort_transaction（）中止事务。
    bool prepareTransaction(bool *outTransactionResume);
    // 完成事务
    bool commitTransaction(OstreeRepoTransactionStats *outStats);
    // 中止活动事务
    bool abortTransaction();

    // 在硬链接签出文件之间建立精确的映射,此函数将构建设备编号和索引节点与其校验和的映射
    bool scanHardlinks();

    // 存储元数据对象对象。将校验和返回为out_csum
    bool writeMetadata(OstreeObjectType objtype, const char *expectedChecksum, KMVariant object, unsigned char **outCsum);

    // 将dir和所有子级的对象存储到存储库中，将生成的文件系统层次结构覆盖到mtree中。
    bool writeDirectoryToMtree(const std::string &dir, KMOstreeMutableTree &mtree, KMOstreeRepoCommitModifier &modifier);

    // 存储流式传输的内容对象object_input，总长度为length。实际校验和将作为out_csum返回。
    bool writeContent(const char *expectedChecksum, KMInputStream &object_input, std::uint64_t length, unsigned char **outCSum);

    // 将mtree的所有元数据对象写入repo；结果outFile指向mtree表示的OSTREE_OBECT_TYPE_DIR_TREE对象。
    bool writeMtree(KMOstreeMutableTree &mtree, KMFile &outFile);

    // 在应用任何压缩后，返回带有校验和sha256的对象的大小（以字节为单位）。
    bool queryObjectStorageSize(OstreeObjectType objtype, const char *sha256, std::uint64_t &outSize);

    // 加载内容对象，将其分解为三部分：实际内容（对于常规文件）、元数据和扩展属性。
    bool loadFile(const char *checksum, KMInputStream &outInput, KMFileInfo &outFileInfo, KMVariant &outXattrs);

    // 写一个提交元数据对象
    bool writeCommitWithTime(const std::string &parent, const char *subject, const char *body, KMVariant metadata, KMFile root, std::uint64_t time, std::string &tmpOutCommit);
    bool writeCommit(const std::string &parent, const char *subject, const char *body, KMVariant metadata, KMFile root, std::string &tmpOutCommit);

    // 将GPG签名添加到提交中。
    bool signCommit(const char *tmpCommitChecksum, const char *keyId, const char *homedir);

    // 如果校验和不为NULL，则将其记录为名为ref的本地ref的目标。否则，如果校验和为NULL，则记录应删除引用。
    void transactionSetCollectionRef(const OstreeCollectionRef *ref, const char *checksum);
    // 如果校验和不为NULL，则将其记录为名为ref的ref的目标；如果提供了remote，则ref将显示为源自该remote。否则，如果校验和为NULL，则记录应删除引用。
    void transactionSetRef(const char *remote, const char *ref, const char *checksum);

    // 存储库配置；不要修改。
    GKeyFile *getConfig();

    // 如果refspec_prefix为NULL，则列出所有本地和远程refspec，并在outRefs中列出它们的当前值。否则，只列出前缀为refspec_prefix的refspec。
    bool listRefsExt(const char *refspecPrefix, OstreeRepoListRefsExtFlags flags, std::map<std::string, std::string> &outRefs);

    // 返回存储库根的文件描述符。
    int getDfd();

    // 此函数同步枚举存储库中的所有静态增量，并以deltaNames形式返回结果。
    bool listStaticDeltaNames(std::vector<std::string> &deltaNamesVector);

    // 将rev的内容加载到root中
    bool readCommit(const char *ref, KMFile &root, std::string &commit);

    // ostree_repo_load_variant的一个版本，专门用于提交，能够返回扩展的状态信息。目前唯一的扩展状态是OSTREE_REPO_COMMIT_STATE_PARTIAL，这意味着只有提交的子路径可用。
    bool loadCommit(const char *checksum, KMVariant &outCommit, OstreeRepoCommitState *outState);
    //  加载objtype类型的元数据对象sha256，将结果存储在outVariant中。
    bool loadVariant(OstreeObjectType objtype, const char *sha256, KMVariant &outMetadata);

    // 此操作为特定提交（如果optToCommit为非空）或现有增量可访问的所有提交（如果optToCommit为空）重新生成这些索引
    bool staticDeltaReindex(OstreeStaticDeltaIndexFlags flags, const char *optToCommit);

    // 使用key_id中指定的密钥对给定数据进行签名
    bool gpgSignData(GBytes *data, GBytes *oldSignatures, const std::vector<std::string> &gpgKeyIds, const std::string &gpgHomeDir, GBytes **outSignatures);

    bool addGpgSignatureSummary(const std::vector<std::string> &gpgKeyIds, const std::string &gpgHomeDir);

    // 获取最后一次错误信息
    std::string errorMessage() const;
    int errorCode() const;

private:
    class Private;
    std::shared_ptr<Private> d = nullptr;
};

#endif // !__KMOSTREEREPO_H__
