33// SPDX-License-Identifier: MPL-2.0
44
55use log:: { debug, info} ;
6+ use std:: collections:: HashMap ;
67use std:: path:: Path ;
78use std:: process:: Stdio ;
89use thiserror:: Error ;
910use tokio:: process:: Command ;
1011
1112#[ derive( Error , Debug ) ]
1213pub enum PushProfileError {
14+ #[ error( "Failed to run Nix show-derivation command: {0}" ) ]
15+ ShowDerivationError ( std:: io:: Error ) ,
16+ #[ error( "Nix show-derivation command resulted in a bad exit code: {0:?}" ) ]
17+ ShowDerivationExitError ( Option < i32 > ) ,
18+ #[ error( "Nix show-derivation command output contained an invalid UTF-8 sequence: {0}" ) ]
19+ ShowDerivationUtf8Error ( std:: str:: Utf8Error ) ,
20+ #[ error( "Failed to parse the output of nix show-derivation: {0}" ) ]
21+ ShowDerivationParseError ( serde_json:: Error ) ,
22+ #[ error( "Nix show-derivation output is empty" ) ]
23+ ShowDerivationEmpty ,
1324 #[ error( "Failed to run Nix build command: {0}" ) ]
1425 BuildError ( std:: io:: Error ) ,
1526 #[ error( "Nix build command resulted in a bad exit code: {0:?}" ) ]
@@ -44,6 +55,39 @@ pub struct PushProfileData<'a> {
4455}
4556
4657pub async fn push_profile ( data : PushProfileData < ' _ > ) -> Result < ( ) , PushProfileError > {
58+ debug ! (
59+ "Finding the deriver of store path for {}" ,
60+ & data. deploy_data. profile. profile_settings. path
61+ ) ;
62+
63+ // `nix-store --query --deriver` doesn't work on invalid paths, so we parse output of show-derivation :(
64+ let mut show_derivation_command = Command :: new ( "nix" ) ;
65+
66+ show_derivation_command
67+ . arg ( "show-derivation" )
68+ . arg ( & data. deploy_data . profile . profile_settings . path ) ;
69+
70+ let show_derivation_output = show_derivation_command
71+ . output ( )
72+ . await
73+ . map_err ( PushProfileError :: ShowDerivationError ) ?;
74+
75+ match show_derivation_output. status . code ( ) {
76+ Some ( 0 ) => ( ) ,
77+ a => return Err ( PushProfileError :: ShowDerivationExitError ( a) ) ,
78+ } ;
79+
80+ let derivation_info: HashMap < & str , serde_json:: value:: Value > = serde_json:: from_str (
81+ std:: str:: from_utf8 ( & show_derivation_output. stdout )
82+ . map_err ( PushProfileError :: ShowDerivationUtf8Error ) ?,
83+ )
84+ . map_err ( PushProfileError :: ShowDerivationParseError ) ?;
85+
86+ let derivation_name = derivation_info
87+ . keys ( )
88+ . next ( )
89+ . ok_or ( PushProfileError :: ShowDerivationEmpty ) ?;
90+
4791 info ! (
4892 "Building profile `{}` for node `{}`" ,
4993 data. deploy_data. profile_name, data. deploy_data. node_name
@@ -56,15 +100,9 @@ pub async fn push_profile(data: PushProfileData<'_>) -> Result<(), PushProfileEr
56100 } ;
57101
58102 if data. supports_flakes {
59- build_command. arg ( "build" ) . arg ( format ! (
60- "{}#deploy.nodes.\" {}\" .profiles.\" {}\" .path" ,
61- data. repo, data. deploy_data. node_name, data. deploy_data. profile_name
62- ) )
103+ build_command. arg ( "build" ) . arg ( derivation_name)
63104 } else {
64- build_command. arg ( & data. repo ) . arg ( "-A" ) . arg ( format ! (
65- "deploy.nodes.\" {}\" .profiles.\" {}\" .path" ,
66- data. deploy_data. node_name, data. deploy_data. profile_name
67- ) )
105+ build_command. arg ( derivation_name)
68106 } ;
69107
70108 match ( data. keep_result , data. supports_flakes ) {
@@ -142,7 +180,7 @@ pub async fn push_profile(data: PushProfileData<'_>) -> Result<(), PushProfileEr
142180 } ;
143181 }
144182
145- debug ! (
183+ info ! (
146184 "Copying profile `{}` to node `{}`" ,
147185 data. deploy_data. profile_name, data. deploy_data. node_name
148186 ) ;
0 commit comments