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
143
144
145
146
147
148
149
#![allow(missing_copy_implementations)]
//! Common types

use bytes::Bytes;
use rand_core::{OsRng, RngCore};
use serde::{Deserialize, Serialize};
use ssh_key::Fingerprint;
use std::collections::{BTreeMap, BTreeSet};
use url::Url;
use uuid::Uuid;

/// Request a job from server.
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct JobRequest {}

/// Handshake message
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct ClientHello {
    /// Builder key fingerping
    pub fingerprint: Fingerprint,
}

/// Request a job from server.
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
pub struct Challenge {
    /// Challenge payload
    pub payload: Bytes,
}

impl Challenge {
    /// Generate random challenge
    pub fn random() -> Self {
        let mut data = [0u8; 16];
        OsRng.fill_bytes(&mut data);
        Challenge {
            payload: data.to_vec().into(),
        }
    }
}

/// Request a job from server.
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct JobList {
    /// Active jobs for builder.
    pub jobs: Vec<Job>,
}

/// Job information.
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct Job {
    /// UUID of job.
    pub uuid: Uuid,
    /// Name of crate
    pub name: String,
    /// Version of crate
    pub version: String,
    /// URL to download crate from.
    pub source: Url,
    /// Kind of job
    pub kind: JobKind,
}

/// Named variants
#[derive(
    Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Debug, Default,
)]
#[serde(rename_all = "snake_case")]
pub enum NamedVariant {
    /// Default variant
    #[default]
    Default,
}

/// Variant of build.
#[derive(Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Debug)]
#[serde(untagged)]
pub enum Variant {
    /// Named variants
    Named(NamedVariant),
    /// Custom variant
    Custom(String),
}

impl Default for Variant {
    fn default() -> Self {
        Variant::Named(NamedVariant::default())
    }
}

/// Build environment
///
/// This struct contains all inputs needed for the build.
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct BuildEnv {
    /// Name of this variant
    pub variant: Variant,
    /// Target triple to build for
    pub target: String,
    /// Crate features to activate
    pub features: BTreeSet<String>,
    /// Enable default features
    pub default_features: bool,
    /// Environment variables to set
    pub environment: BTreeMap<String, String>,
    /// Additional dependencies to install
    pub dependencies: BTreeMap<String, String>,
}

/// Kind of job to build.
///
/// Each variant of this enumeration corresponds to one Cargo command.
#[derive(Serialize, Deserialize, Clone, Debug)]
pub enum JobKind {
    /// Build metadata
    Metadata,
    /// Build binaries
    Binary(BuildEnv),
    /// Build debian package
    Debian(BuildEnv),
    /// Build coverage
    Coverage(BuildEnv),
}

#[cfg(test)]
mod tests {
    use super::*;
    use serde_test::{assert_tokens, Token};

    #[test]
    fn default_variant() {
        assert_eq!(Variant::default(), Variant::Named(NamedVariant::Default));
    }

    #[test]
    fn variant_serialize_default() {
        assert_tokens(
            &Variant::Named(NamedVariant::Default),
            &[Token::UnitVariant {
                name: "NamedVariant",
                variant: "default",
            }],
        );
    }

    #[test]
    fn variant_serialize_custom() {
        assert_tokens(&Variant::Custom("custom".into()), &[Token::Str("custom")]);
    }
}