diff --git a/build.ps1 b/build.ps1 index 2b894cd2..8a81fbdd 100644 --- a/build.ps1 +++ b/build.ps1 @@ -377,7 +377,12 @@ if (!$SkipBuild) { } } - Copy-Item "*.dsc.resource.json" $target -Force -ErrorAction Ignore + if ($IsWindows) { + Copy-Item "*.dsc.resource.json" $target -Force -ErrorAction Ignore + } + else { # don't copy WindowsPowerShell resource manifest + Copy-Item "*.dsc.resource.json" $target -Exclude 'windowspowershell.dsc.resource.json' -Force -ErrorAction Ignore + } # be sure that the files that should be executable are executable if ($IsLinux -or $IsMacOS) { diff --git a/dsc/Cargo.lock b/dsc/Cargo.lock index f6801505..bc687973 100644 --- a/dsc/Cargo.lock +++ b/dsc/Cargo.lock @@ -562,6 +562,7 @@ dependencies = [ "tree-sitter-dscexpression", "tree-sitter-rust", "uuid", + "which", ] [[package]] @@ -591,6 +592,12 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" +[[package]] +name = "env_home" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7f84e12ccf0a7ddc17a6c41c93326024c42920d7ee630d04950e6926645c0fe" + [[package]] name = "equivalent" version = "1.0.2" @@ -2347,6 +2354,18 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "which" +version = "7.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2774c861e1f072b3aadc02f8ba886c26ad6321567ecc294c935434cad06f1283" +dependencies = [ + "either", + "env_home", + "rustix", + "winsafe", +] + [[package]] name = "winapi" version = "0.3.9" @@ -2537,6 +2556,12 @@ dependencies = [ "memchr", ] +[[package]] +name = "winsafe" +version = "0.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904" + [[package]] name = "wit-bindgen-rt" version = "0.33.0" diff --git a/dsc/tests/dsc_discovery.tests.ps1 b/dsc/tests/dsc_discovery.tests.ps1 index 058b70c8..6dce5562 100644 --- a/dsc/tests/dsc_discovery.tests.ps1 +++ b/dsc/tests/dsc_discovery.tests.ps1 @@ -183,4 +183,41 @@ Describe 'tests for resource discovery' { $out = dsc resource schema -r abc/def $LASTEXITCODE | Should -Be 7 } + + It 'Verify warning message when executable not found for: ' -TestCases @( + @{ operation = 'get' } + @{ operation = 'set' } + @{ operation = 'test' } + @{ operation = 'delete' } + @{ operation = 'export' } + @{ operation = 'resolve' } + @{ operation = 'whatIf' } + ) { + param($operation) + + $manifest = @" + { + "`$schema": "https://aka.ms/dsc/schemas/v3/bundled/resource/manifest.json", + "type": "Test/ExecutableNotFound", + "version": "0.1.0", + "$operation": { + "executable": "doesNotExist" + } + } +"@ + $oldPath = $env:DSC_RESOURCE_PATH + try { + $env:DSC_RESOURCE_PATH = $testdrive + Set-Content -Path "$testdrive/test.dsc.resource.json" -Value $manifest + $out = dsc resource list 'Test/ExecutableNotFound' 2> "$testdrive/error.txt" | ConvertFrom-Json + $LASTEXITCODE | Should -Be 0 + $out.Count | Should -Be 1 + $out.Type | Should -BeExactly 'Test/ExecutableNotFound' + $out.Kind | Should -BeExactly 'resource' + Get-Content -Path "$testdrive/error.txt" | Should -Match "WARN.*?Executable 'doesNotExist' not found" + } + finally { + $env:DSC_RESOURCE_PATH = $oldPath + } + } } diff --git a/dsc_lib/Cargo.lock b/dsc_lib/Cargo.lock index 79de952b..c6a64eae 100644 --- a/dsc_lib/Cargo.lock +++ b/dsc_lib/Cargo.lock @@ -451,6 +451,7 @@ dependencies = [ "tree-sitter-dscexpression", "tree-sitter-rust", "uuid", + "which", ] [[package]] @@ -480,12 +481,28 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" +[[package]] +name = "env_home" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7f84e12ccf0a7ddc17a6c41c93326024c42920d7ee630d04950e6926645c0fe" + [[package]] name = "equivalent" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" +[[package]] +name = "errno" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" +dependencies = [ + "libc", + "windows-sys 0.59.0", +] + [[package]] name = "fancy-regex" version = "0.14.0" @@ -912,6 +929,12 @@ version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" +[[package]] +name = "linux-raw-sys" +version = "0.4.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" + [[package]] name = "litemap" version = "0.7.5" @@ -1294,6 +1317,19 @@ version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" +[[package]] +name = "rustix" +version = "0.38.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" +dependencies = [ + "bitflags 2.9.0", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.59.0", +] + [[package]] name = "rustversion" version = "1.0.20" @@ -1956,6 +1992,18 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "which" +version = "7.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2774c861e1f072b3aadc02f8ba886c26ad6321567ecc294c935434cad06f1283" +dependencies = [ + "either", + "env_home", + "rustix", + "winsafe", +] + [[package]] name = "winapi" version = "0.3.9" @@ -2093,6 +2141,12 @@ dependencies = [ "memchr", ] +[[package]] +name = "winsafe" +version = "0.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904" + [[package]] name = "wit-bindgen-rt" version = "0.33.0" diff --git a/dsc_lib/Cargo.toml b/dsc_lib/Cargo.toml index df454a65..ce05d2d4 100644 --- a/dsc_lib/Cargo.toml +++ b/dsc_lib/Cargo.toml @@ -36,6 +36,7 @@ tree-sitter = "0.25" tree-sitter-rust = "0.23" tree-sitter-dscexpression = { path = "../tree-sitter-dscexpression" } uuid = { version = "1.15", features = ["v4"] } +which = "7.0" [dev-dependencies] serde_yaml = "0.9" diff --git a/dsc_lib/locales/en-us.toml b/dsc_lib/locales/en-us.toml index 6393e0fd..5aca0d8d 100644 --- a/dsc_lib/locales/en-us.toml +++ b/dsc_lib/locales/en-us.toml @@ -82,6 +82,7 @@ progressSearching = "Searching for resources" foundResourceManifest = "Found resource manifest: %{path}" adapterFound = "Resource adapter '%{adapter}' found" resourceFound = "Resource '%{resource}' found" +executableNotFound = "Executable '%{executable}' not found for operation '%{operation}' for resource '%{resource}'" [dscresources.commandResource] invokeGet = "Invoking get for '%{resource}'" diff --git a/dsc_lib/src/discovery/command_discovery.rs b/dsc_lib/src/discovery/command_discovery.rs index 989e6e8c..95d1bf56 100644 --- a/dsc_lib/src/discovery/command_discovery.rs +++ b/dsc_lib/src/discovery/command_discovery.rs @@ -4,7 +4,7 @@ use crate::discovery::discovery_trait::ResourceDiscovery; use crate::discovery::convert_wildcard_to_regex; use crate::dscresources::dscresource::{Capability, DscResource, ImplementedAs}; -use crate::dscresources::resource_manifest::{import_manifest, validate_semver, Kind, ResourceManifest}; +use crate::dscresources::resource_manifest::{import_manifest, validate_semver, Kind, ResourceManifest, SchemaKind}; use crate::dscresources::command_resource::invoke_command; use crate::dscerror::DscError; use crate::progress::{ProgressBar, ProgressFormat}; @@ -22,6 +22,7 @@ use std::io::BufReader; use std::path::{Path, PathBuf}; use std::str::FromStr; use tracing::{debug, info, trace, warn}; +use which::which; use crate::util::get_setting; use crate::util::get_exe_path; @@ -531,33 +532,41 @@ fn load_manifest(path: &Path) -> Result { Kind::Resource }; - // all command based resources are required to support `get` - let mut capabilities = if manifest.get.is_some() { - vec![Capability::Get] - } else { - vec![] - }; + let mut capabilities: Vec = vec![]; + if let Some(get) = &manifest.get { + verify_executable(&manifest.resource_type, "get", &get.executable); + capabilities.push(Capability::Get); + } if let Some(set) = &manifest.set { + verify_executable(&manifest.resource_type, "set", &set.executable); capabilities.push(Capability::Set); if set.handles_exist == Some(true) { capabilities.push(Capability::SetHandlesExist); } } - if manifest.what_if.is_some() { + if let Some(what_if) = &manifest.what_if { + verify_executable(&manifest.resource_type, "what_if", &what_if.executable); capabilities.push(Capability::WhatIf); } - if manifest.test.is_some() { + if let Some(test) = &manifest.test { + verify_executable(&manifest.resource_type, "test", &test.executable); capabilities.push(Capability::Test); } - if manifest.delete.is_some() { + if let Some(delete) = &manifest.delete { + verify_executable(&manifest.resource_type, "delete", &delete.executable); capabilities.push(Capability::Delete); } - if manifest.export.is_some() { + if let Some(export) = &manifest.export { + verify_executable(&manifest.resource_type, "export", &export.executable); capabilities.push(Capability::Export); } - if manifest.resolve.is_some() { + if let Some(resolve) = &manifest.resolve { + verify_executable(&manifest.resource_type, "resolve", &resolve.executable); capabilities.push(Capability::Resolve); } + if let Some(SchemaKind::Command(command)) = &manifest.schema { + verify_executable(&manifest.resource_type, "schema", &command.executable); + } let resource = DscResource { type_name: manifest.resource_type.clone(), @@ -575,6 +584,12 @@ fn load_manifest(path: &Path) -> Result { Ok(resource) } +fn verify_executable(resource: &str, operation: &str, executable: &str) { + if which(executable).is_err() { + warn!("{}", t!("discovery.commandDiscovery.executableNotFound", resource = resource, operation = operation, executable = executable)); + } +} + fn sort_adapters_based_on_lookup_table(unsorted_adapters: &BTreeMap>, needed_resource_types: &Vec) -> LinkedHashMap> { let mut result = LinkedHashMap::>::new(); diff --git a/tools/test_group_resource/Cargo.lock b/tools/test_group_resource/Cargo.lock index a573ecb3..8c0ba8dc 100644 --- a/tools/test_group_resource/Cargo.lock +++ b/tools/test_group_resource/Cargo.lock @@ -451,6 +451,7 @@ dependencies = [ "tree-sitter-dscexpression", "tree-sitter-rust", "uuid", + "which", ] [[package]] @@ -480,12 +481,28 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" +[[package]] +name = "env_home" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7f84e12ccf0a7ddc17a6c41c93326024c42920d7ee630d04950e6926645c0fe" + [[package]] name = "equivalent" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" +[[package]] +name = "errno" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" +dependencies = [ + "libc", + "windows-sys 0.59.0", +] + [[package]] name = "fancy-regex" version = "0.14.0" @@ -912,6 +929,12 @@ version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" +[[package]] +name = "linux-raw-sys" +version = "0.4.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" + [[package]] name = "litemap" version = "0.7.5" @@ -1294,6 +1317,19 @@ version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" +[[package]] +name = "rustix" +version = "0.38.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" +dependencies = [ + "bitflags 2.9.0", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.59.0", +] + [[package]] name = "rustversion" version = "1.0.20" @@ -1967,6 +2003,18 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "which" +version = "7.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2774c861e1f072b3aadc02f8ba886c26ad6321567ecc294c935434cad06f1283" +dependencies = [ + "either", + "env_home", + "rustix", + "winsafe", +] + [[package]] name = "winapi" version = "0.3.9" @@ -2104,6 +2152,12 @@ dependencies = [ "memchr", ] +[[package]] +name = "winsafe" +version = "0.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904" + [[package]] name = "wit-bindgen-rt" version = "0.33.0"