#![deny(
warnings,
missing_debug_implementations,
missing_copy_implementations,
trivial_casts,
trivial_numeric_casts,
unsafe_code,
unstable_features,
unused_import_braces,
unused_qualifications,
missing_docs
)]
use serde::{de::DeserializeOwned, Deserialize, Serialize};
use serde_json::{Map, Value};
pub use concourse_resource_derive::*;
pub mod internal;
#[allow(missing_debug_implementations)]
#[derive(Serialize)]
pub struct InOutput<V, M> {
pub version: V,
pub metadata: Option<M>,
}
#[allow(missing_debug_implementations)]
#[derive(Serialize)]
pub struct OutOutput<V, M> {
pub version: V,
pub metadata: Option<M>,
}
pub trait IntoMetadataKV {
fn into_metadata_kv(self) -> Vec<internal::KV>;
}
#[allow(missing_debug_implementations)]
#[derive(Serialize, Deserialize, Copy, Clone, Default)]
pub struct Empty;
impl IntoMetadataKV for Empty {
fn into_metadata_kv(self) -> Vec<internal::KV> {
vec![]
}
}
#[derive(Debug)]
pub struct BuildMetadata {
pub id: String,
pub name: Option<String>,
pub job_name: Option<String>,
pub pipeline_name: Option<String>,
pub pipeline_instance_vars: Option<Map<String, Value>>,
pub team_name: String,
pub atc_external_url: String,
}
pub trait Resource {
type Version: Serialize + DeserializeOwned;
type Source: DeserializeOwned;
type InParams: DeserializeOwned;
type InMetadata: Serialize + IntoMetadataKV;
type OutParams: DeserializeOwned;
type OutMetadata: Serialize + IntoMetadataKV;
fn resource_check(
source: Option<Self::Source>,
version: Option<Self::Version>,
) -> Vec<Self::Version>;
fn resource_in(
source: Option<Self::Source>,
version: Self::Version,
params: Option<Self::InParams>,
output_path: &str,
) -> Result<InOutput<Self::Version, Self::InMetadata>, Box<dyn std::error::Error>>;
fn resource_out(
source: Option<Self::Source>,
params: Option<Self::OutParams>,
input_path: &str,
) -> OutOutput<Self::Version, Self::OutMetadata>;
fn build_metadata() -> BuildMetadata {
BuildMetadata {
id: std::env::var("BUILD_ID").expect("environment variable BUILD_ID should be present"),
name: std::env::var("BUILD_NAME").ok(),
job_name: std::env::var("BUILD_JOB_NAME").ok(),
pipeline_name: std::env::var("BUILD_PIPELINE_NAME").ok(),
pipeline_instance_vars: std::env::var("BUILD_PIPELINE_INSTANCE_VARS")
.ok()
.and_then(|instance_vars| serde_json::from_str(&instance_vars[..]).ok()),
team_name: std::env::var("BUILD_TEAM_NAME")
.expect("environment variable BUILD_TEAM_NAME should be present"),
atc_external_url: std::env::var("ATC_EXTERNAL_URL")
.expect("environment variable ATC_EXTERNAL_URL should be present"),
}
}
}
#[macro_export]
macro_rules! create_resource {
($resource:ty) => {
use std::io::Read;
use concourse_resource::internal::*;
fn main() {
let mut input_buffer = String::new();
let stdin = std::io::stdin();
let mut handle = stdin.lock();
handle.read_to_string(&mut input_buffer).unwrap();
let mut args = std::env::args();
match args.next().expect("should have a bin name").as_ref() {
"/opt/resource/check" => {
let input: CheckInput<
<$resource as Resource>::Source,
<$resource as Resource>::Version,
> = serde_json::from_str(&input_buffer).expect("error deserializing input");
let result =
<$resource as Resource>::resource_check(input.source, input.version);
println!(
"{}",
serde_json::to_string(&result).expect("error serializing output")
);
}
"/opt/resource/in" => {
let input: InInput<
<$resource as Resource>::Source,
<$resource as Resource>::Version,
<$resource as Resource>::InParams,
> = serde_json::from_str(&input_buffer).expect("error deserializing input");
let result = <$resource as Resource>::resource_in(
input.source,
input.version,
input.params,
&args.next().expect("expected path as first parameter"),
);
match result {
Err(error) => {
eprintln!("Error! {}", error);
std::process::exit(1);
}
Ok(InOutput { version, metadata }) => println!(
"{}",
serde_json::to_string(&InOutputKV {
version,
metadata: metadata.map(|md| md.into_metadata_kv())
})
.expect("error serializing output")
),
};
}
"/opt/resource/out" => {
let input: OutInput<
<$resource as Resource>::Source,
<$resource as Resource>::OutParams,
> = serde_json::from_str(&input_buffer).expect("error deserializing input");
let result = <$resource as Resource>::resource_out(
input.source,
input.params,
&args.next().expect("expected path as first parameter"),
);
println!(
"{}",
serde_json::to_string(&OutOutputKV {
version: result.version,
metadata: result.metadata.map(|md| md.into_metadata_kv())
})
.expect("error serializing output")
);
}
v => eprintln!("unexpected being called as '{}'", v),
}
}
};
}