aboutsummaryrefslogtreecommitdiff
path: root/src/libstore/build-result.hh
blob: 9634fb944aef91725445b66e235f1015c8e6d950 (plain)
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
140
141
142
#pragma once
///@file

#include "realisation.hh"
#include "derived-path.hh"
#include "comparator.hh"

#include <string>
#include <chrono>
#include <optional>

namespace nix {

struct KeyedBuildResult;

struct BuildResult
{
    /**
     * @note This is directly used in the nix-store --serve protocol.
     * That means we need to worry about compatability across versions.
     * Therefore, don't remove status codes, and only add new status
     * codes at the end of the list.
     */
    enum Status {
        Built = 0,
        Substituted,
        AlreadyValid,
        PermanentFailure,
        InputRejected,
        OutputRejected,
        /// possibly transient
        TransientFailure,
        /// no longer used
        CachedFailure,
        TimedOut,
        MiscFailure,
        DependencyFailed,
        LogLimitExceeded,
        NotDeterministic,
        ResolvesToAlreadyValid,
        NoSubstituters,
    } status = MiscFailure;

    /**
     * Information about the error if the build failed.
     *
     * @todo This should be an entire ErrorInfo object, not just a
     * string, for richer information.
     */
    std::string errorMsg;

    std::string toString() const {
        auto strStatus = [&]() {
            switch (status) {
                case Built: return "Built";
                case Substituted: return "Substituted";
                case AlreadyValid: return "AlreadyValid";
                case PermanentFailure: return "PermanentFailure";
                case InputRejected: return "InputRejected";
                case OutputRejected: return "OutputRejected";
                case TransientFailure: return "TransientFailure";
                case CachedFailure: return "CachedFailure";
                case TimedOut: return "TimedOut";
                case MiscFailure: return "MiscFailure";
                case DependencyFailed: return "DependencyFailed";
                case LogLimitExceeded: return "LogLimitExceeded";
                case NotDeterministic: return "NotDeterministic";
                case ResolvesToAlreadyValid: return "ResolvesToAlreadyValid";
                case NoSubstituters: return "NoSubstituters";
                default: return "Unknown";
            };
        }();
        return strStatus + ((errorMsg == "") ? "" : " : " + errorMsg);
    }

    /**
     * How many times this build was performed.
     */
    unsigned int timesBuilt = 0;

    /**
     * If timesBuilt > 1, whether some builds did not produce the same
     * result. (Note that 'isNonDeterministic = false' does not mean
     * the build is deterministic, just that we don't have evidence of
     * non-determinism.)
     */
    bool isNonDeterministic = false;

    /**
     * For derivations, a mapping from the names of the wanted outputs
     * to actual paths.
     */
    SingleDrvOutputs builtOutputs;

    /**
     * The start/stop times of the build (or one of the rounds, if it
     * was repeated).
     */
    time_t startTime = 0, stopTime = 0;

    /**
     * User and system CPU time the build took.
     */
    std::optional<std::chrono::microseconds> cpuUser, cpuSystem;

    DECLARE_CMP(BuildResult);

    bool success()
    {
        return status == Built || status == Substituted || status == AlreadyValid || status == ResolvesToAlreadyValid;
    }

    void rethrow()
    {
        throw Error("%s", errorMsg);
    }

    /**
     * Project a BuildResult with just the information that pertains to
     * the given path.
     *
     * A `BuildResult` may hold information for multiple derived paths;
     * this function discards information about outputs not relevant in
     * `path`. Build `Goal`s in particular may contain more outputs for
     * a single build result than asked for directly, it's necessary to
     * remove any such additional result to not leak other build infos.
     */
    KeyedBuildResult restrictTo(DerivedPath path) const;
};

/**
 * A `BuildResult` together with its "primary key".
 */
struct KeyedBuildResult : BuildResult
{
    /**
     * The derivation we built or the store path we substituted.
     */
    DerivedPath path;
};

}