Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ members = [
"lib/dsc-lib",
"resources/dism_dsc",
"resources/dscecho",
"resources/filecontent",
"resources/osinfo",
"resources/process",
"resources/registry",
Expand Down Expand Up @@ -49,6 +50,7 @@ default-members = [
"lib/dsc-lib",
"resources/dism_dsc",
"resources/dscecho",
"resources/filecontent",
"resources/osinfo",
"resources/process",
"resources/registry",
Expand Down Expand Up @@ -82,6 +84,7 @@ Windows = [
"lib/dsc-lib",
"resources/dism_dsc",
"resources/dscecho",
"resources/filecontent",
"resources/osinfo",
"resources/process",
"resources/registry",
Expand All @@ -107,6 +110,7 @@ macOS = [
"lib/dsc-lib-telemetry",
"lib/dsc-lib",
"resources/dscecho",
"resources/filecontent",
"resources/osinfo",
"resources/process",
"resources/runcommandonset",
Expand All @@ -128,6 +132,7 @@ Linux = [
"lib/dsc-lib-telemetry",
"lib/dsc-lib",
"resources/dscecho",
"resources/filecontent",
"resources/osinfo",
"resources/process",
"resources/runcommandonset",
Expand Down Expand Up @@ -223,6 +228,8 @@ semver = { version = "1.0.28" }
serde = { version = "1.0.229", features = ["derive"] }
# dsc, dsc-lib, dscecho, dsc-lib-osinfo, osinfo, process, registry, dsc-lib-registry, runcommandonset, sshdconfig, dsctest, test_group_resource, y2j
serde_json = { version = "1.0.151", features = ["preserve_order"] }
# filecontent
sha2 = { version = "0.10.9" }
# dsc, dsc-lib, y2j
serde_yaml = { version = "0.9" }
# dsc-lib-jsonschema-macros
Expand Down
20 changes: 20 additions & 0 deletions data.build.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
"dsc-bicep-ext",
"dscecho",
"echo.dsc.resource.json",
"filecontent",
"filecontent.dsc.resource.json",
"assertion.dsc.resource.json",
"apt.dsc.resource.json",
"apt.dsc.resource.sh",
Expand Down Expand Up @@ -41,6 +43,8 @@
"dsc-bicep-ext",
"dscecho",
"echo.dsc.resource.json",
"filecontent",
"filecontent.dsc.resource.json",
"assertion.dsc.resource.json",
"brew.dsc.resource.json",
"brew.dsc.resource.sh",
Expand Down Expand Up @@ -74,6 +78,8 @@
"dsc-bicep-ext.exe",
"dscecho.exe",
"echo.dsc.resource.json",
"filecontent.exe",
"filecontent.dsc.resource.json",
"assertion.dsc.resource.json",
"featureondemand.dsc.resource.json",
"group.dsc.resource.json",
Expand Down Expand Up @@ -335,6 +341,20 @@
]
}
},
{
"Name": "filecontent",
"Kind": "Resource",
"RelativePath": "resources/filecontent",
"IsRust": true,
"Binaries": [
"filecontent"
],
"CopyFiles": {
"All": [
"filecontent.dsc.resource.json"
]
}
},
{
"Name": "osinfo",
"Kind": "Resource",
Expand Down
4 changes: 2 additions & 2 deletions dsc/tests/dsc_resource_list.tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@ Describe 'Tests for listing resources' {

It 'dsc resource list --tags "<tags>" and --description "<description> work' -TestCases @(
if ($IsLinux) {
@{ tags = 'linux'; description = $null; expectedCount = 2; expectedType = @('DSC.PackageManagement/Apt', 'Microsoft/OSInfo') }
@{ tags = 'linux'; description = $null; expectedCount = 3; expectedType = @('DSC.PackageManagement/Apt', 'Microsoft/FileContent', 'Microsoft/OSInfo') }
}
else {
@{ tags = 'linux'; description = $null; expectedCount = 1; expectedType = 'Microsoft/OSInfo' }
@{ tags = 'linux'; description = $null; expectedCount = 2; expectedType = @('Microsoft/FileContent', 'Microsoft/OSInfo') }
}
@{ tags = $null; description = 'operating system'; expectedCount = 1; expectedType = 'Microsoft/OSInfo' }
@{ tags = 'linux'; description = 'operating system'; expectedCount = 1; expectedType = 'Microsoft/OSInfo' }
Expand Down
13 changes: 13 additions & 0 deletions resources/filecontent/.project.data.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"Name": "filecontent",
"Kind": "Resource",
"IsRust": true,
"Binaries": [
"filecontent"
],
"CopyFiles": {
"All": [
"filecontent.dsc.resource.json"
]
}
}
19 changes: 19 additions & 0 deletions resources/filecontent/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
[package]
name = "filecontent"
version = "0.1.0"
edition = "2024"

[[bin]]
name = "filecontent"
path = "src/main.rs"

[package.metadata.i18n]
available-locales = ["en-us"]
default-locale = "en-us"
load-path = "locales"

[dependencies]
rust-i18n = { workspace = true }
serde = { workspace = true }
serde_json = { workspace = true }
sha2 = { workspace = true }
111 changes: 111 additions & 0 deletions resources/filecontent/filecontent.dsc.resource.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
{
"$schema": "https://aka.ms/dsc/schemas/v3/bundled/resource/manifest.json",
"type": "Microsoft/FileContent",
"description": "Manage the UTF-8 content of a local file.",
"tags": [
"file",
"linux",
"macos",
"windows"
],
"version": "0.1.0",
"get": {
"executable": "filecontent",
"args": [
"get",
{
"jsonInputArg": "--input",
"mandatory": true
}
]
},
"set": {
"executable": "filecontent",
"args": [
"set",
{
"jsonInputArg": "--input",
"mandatory": true
}
],
"implementsPretest": false,
"return": "state"
},
"test": {
"executable": "filecontent",
"args": [
"test",
{
"jsonInputArg": "--input",
"mandatory": true
}
],
"return": "state"
},
"export": {
"executable": "filecontent",
"args": [
"export",
{
"jsonInputArg": "--input",
"mandatory": true
}
],
"supportsFiltering": true
},
"exitCodes": {
"0": "Success",
"1": "Invalid arguments",
"2": "Invalid input",
"3": "File operation error"
},
"schema": {
"embedded": {
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "File Content",
"description": "Manage the UTF-8 content of a local file.",
"type": "object",
"required": [
"path"
],
"properties": {
"content": {
"type": "string",
"title": "Content",
"description": "The UTF-8 content of the file.",
"writeOnly": true
Comment on lines +75 to +76

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should remove the writeOnly keyword since this property is returnable by the resource.

Suggested change
"description": "The UTF-8 content of the file.",
"writeOnly": true
"description": "The UTF-8 content of the file."

},
"sha256": {
"type": "string",
"title": "SHA-256",
"description": "The SHA-256 hash of the file content.",
"pattern": "^[A-Fa-f0-9]{64}$"
},
"sha512": {
"type": "string",
"title": "SHA-512",
"description": "The SHA-512 hash of the file content.",
"pattern": "^[A-Fa-f0-9]{128}$"
},
Comment on lines +78 to +89

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think both of these properties should be marked as read-only, per our guidance for resource properties:

Resources can define read-only properties to describe information about an instance that the resource can retrieve but not directly set. For example, file APIs don't generally allow a user to set the property describing the last time the file was modified.

Generally, you shouldn't include read-only properties when defining the desired state for an instance. Assertion resources that don't support the Set operation can include read-only properties you can use for validating system state for conditional behavior.

Suggested change
"sha256": {
"type": "string",
"title": "SHA-256",
"description": "The SHA-256 hash of the file content.",
"pattern": "^[A-Fa-f0-9]{64}$"
},
"sha512": {
"type": "string",
"title": "SHA-512",
"description": "The SHA-512 hash of the file content.",
"pattern": "^[A-Fa-f0-9]{128}$"
},
"sha256": {
"type": "string",
"title": "SHA-256",
"description": "The SHA-256 hash of the file content.",
"pattern": "^[A-Fa-f0-9]{64}$",
"readOnly": true,
},
"sha512": {
"type": "string",
"title": "SHA-512",
"description": "The SHA-512 hash of the file content.",
"pattern": "^[A-Fa-f0-9]{128}$",
"readOnly": true
},

"path": {
"type": "string",
"title": "Path",
"description": "The path to the local file.",
"minLength": 1
},
"_exist": {
"type": "boolean",
"title": "Exists",
"description": "Indicates whether the file should exist. Set to false to remove the file."
},
"_inDesiredState": {
"type": "boolean",
"title": "In desired state",
"description": "Indicates whether the file is in the desired state. Only returned by test.",
"readOnly": true
}
},
Comment on lines +96 to +107

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Per our documentation on canonical resources, both of these property definitions should reference the canonical property schema and bundle it into $defs:

Suggested change
"_exist": {
"type": "boolean",
"title": "Exists",
"description": "Indicates whether the file should exist. Set to false to remove the file."
},
"_inDesiredState": {
"type": "boolean",
"title": "In desired state",
"description": "Indicates whether the file is in the desired state. Only returned by test.",
"readOnly": true
}
},
"_exist": {
"$ref": "https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/v3/resource/properties/exist.json",
},
"_inDesiredState": {
"$ref": "https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/v3/resource/properties/inDesiredState.json"
}
},
"$defs": {
"https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/v3/resource/properties/exist.json": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/v3/resource/properties/exist.json",
"title": "Instance should exist",
"description": "Indicates whether the DSC resource instance should exist.",
"type": "boolean",
"default": true,
"enum": [
false,
true
]
},
"https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/v3/resource/properties/inDesiredState.json": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/v3/resource/properties/inDesiredState.json",
"title": "Instance is in the Desired State",
"description": "Indicates whether the instance is in the desired state. This property is only returned by the `test` method.",
"type": [
"boolean",
"null"
],
"readOnly": true
}
}

Note

We have to bundle the canonical property schemas for now because we don't yet use a schema registry with an in-memory retriever to be able to lookup the property references. Eventually resource authors will be able to just define the property with the $ref keyword and DSC will correctly validate the instance.

"additionalProperties": false
}
}
}
26 changes: 26 additions & 0 deletions resources/filecontent/locales/en-us.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
_version = 1

[main]
missingOperation = "Missing operation. Usage: filecontent <get|set|test|export> --input <json>"
unknownOperation = "Unknown operation: '%{operation}'. Expected: get, set, test, or export"
missingInput = "Missing --input argument"
missingInputValue = "Missing value for --input argument"
invalidJson = "Invalid JSON input: %{error}"
serializeError = "Failed to serialize output: %{error}"
Comment thread
SteveL-MSFT marked this conversation as resolved.

[input]
emptyPath = "The path must not be empty"
invalidHash = "%{name} must contain exactly %{length} hexadecimal characters"

[get]
readError = "Failed to read file '%{path}': %{error}"

[set]
contentRequired = "The content property is required when setting a file"
writeError = "Failed to write file '%{path}': %{error}"
removeError = "Failed to remove file '%{path}': %{error}"
sha256Mismatch = "The sha256 value does not match the content property"
sha512Mismatch = "The sha512 value does not match the content property"

[export]
readError = "Failed to export file '%{path}' as UTF-8 content: %{error}"
Loading
Loading