Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Canonicalize registry resource schema #582

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
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
406 changes: 388 additions & 18 deletions registry/Cargo.lock

Large diffs are not rendered by default.

11 changes: 9 additions & 2 deletions registry/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@ name = "registry"
version = "1.0.0"
edition = "2021"

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

[profile.release]
strip = true
# optimize for size
Expand All @@ -13,9 +18,11 @@ lto = true
[dependencies]
clap = { version = "4.5", features = ["derive"] }
crossterm = "0.28"
regex = "1.11.0"
registry = "1.2"
schemars = "0.8"
serde = "1.0"
rust-i18n = "3"
schemars = "1.0.0-alpha.15"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
thiserror = "1.0"
tracing = { version = "0.1" }
Expand Down
91 changes: 91 additions & 0 deletions registry/locales/cli.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
_version: 2
cli:
about:
en: Manage state of Windows registry
# config command help
config:
about:
en: Manage registry configuration.
args:
input:
help:
en: The registry JSON input.
what_if:
help:
en: Run as a what-if operation instead of applying the registry configuration.
get:
about:
en: Retrieve registry configuration.
set:
about:
en: Apply registry configuration.
delete:
about:
en: Delete registry configuration.
# query command help
query:
about:
en: Query a registry key or value.
args:
key_path:
help:
en: The registry key path to query.
value_name:
help:
en: The name of the value to query.
recurse:
help:
en: Recursively query subkeys.
# set command help
set:
about:
en: Set a registry key or value.
args:
key_path:
help:
en: The registry key path to set.
value:
help:
en: The value to set.
# remove command help
remove:
about:
en: Remove a registry key or value.
args:
key_path:
help:
en: The registry key path to remove.
value_name:
help:
en: The name of the value to remove.
recurse:
help:
en: Recursively remove subkeys.
# find command help
find:
about:
en: Find a registry key or value.
args:
key_path:
help:
en: The registry key path to start find.
find:
help:
en: The string to find.
recurse:
help:
en: Recursively find.
keys_only:
help:
en: Only find keys.
values_only:
help:
en: Only find values.
# schema command help
schema:
about:
en: Retrieve JSON schema.
args:
enhanced:
help:
en: Retrieve JSON schema enhanced for VS Code authoring and review.
169 changes: 169 additions & 0 deletions registry/locales/schemas.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
_version: 2

schema:
title:
en: Microsoft.Windows/Registry instance
description:
en: Manages Windows Registry keys and values.
markdownDescription:
en: |-
Each instance of the `Microsoft.Windows/Registry` resource manages a registry key or value.
You can use it to idempotently ensure that a registry key or value exists and set the data
for registry values.
# Properties
keyPath:
title:
en: Registry key path
description:
en: >-
Defines the path to the registry key to manage. Must be prefixed with a valid
hive identifier. Separate the paths with back slashes only.
markdownDescription:
en: |-
The `keyPath` property defines the path to the registry key an instance
of the resource manages. It must be prefixed with a valid hive identifier:

| Identifier | Hive |
|:-------------------------------:|:----------------------|
| `HKCC` or `HKEY_CURRENT_CONFIG` | Current configuration |
| `HKCU` or `HKEY_CURRENT_USER` | Current user |
| `HKCR` or `HKEY_CLASSES_ROOT` | Classes root |
| `HKLM` or `HKEY_LOCAL_MACHINE` | Local machine |
| `HKU` or `HKEY_USERS` | Users |

Specify the path to the registry key with backslashes (`\`), like
`HKCU\DSC\Properties\keyPath\Example`. If using JSON, ensure the
backlsashes are escaped, like `HKCU\\DSC\\Properties\\keyPath\\Example`.
patternErrorMessage:
en: >-
The value must begin with a valid hive identifier. Valid identifiers are:

HKCC, HKEY_CURRENT_CONFIG,
HKCU, HKEY_CURRENT_USER
HKCR, HKEY_CLASSES_ROOT
HKLM, HKEY_LOCAL_MACHINE
HKU, and HKEY_USERS.

metadata:
title:
en: Resource metadata
description:
en: Defines metadata returned by the resource.
markdownDescription:
en: |-
The `metadata` property defines metadata returned by the resource. The registry resource
doesn't support sending metadata input. It returns messages when invoked in what-if mode.
whatIf:
title:
en: What-if messages
description:
en: A list of messages returned by the resource when invoked in what-if mode.
markdownDescription:
en: >-
Contains a list of messages returned by the resource when invoked in what-if mode, as
with the `dsc config set --what-if` command.
valueName:
title:
en: Registry value name
description:
en: Defines the name of the registry value to manage.
markdownDescription:
en: |-
The `valueName` property defines the name of the registry value to manage. This value is
required when specifying value data.
valueData:
title:
en: Registry value data
description:
en: Defines the data for a registry value.
markdownDescription:
en: |-
Defines the data for a registry value. When you specify this value, you must also specify
the name of the registry value.

Define the data as an object with a single property. The property name determines the data
type and the property value determines the data value. The following table lists the
available data types.

| Property name | Data description |
|:--------------:|:-------------------------------------------------------------------|
| `String` | Defines the registry value as a static string. |
| `ExpandString` | Defines the registry value as a string with expandable references. |
| `MultiString` | Defines the registry value as an array of static strings. |
| `Binary` | Defines the registry value as an array of bytes. |
| `DWord` | Defines the registry value as an unsigned 32-bit integer. |
| `QWord` | Defines the registry value as an unsigned 64-bit integer. |
String:
title:
en: String value data
description:
en: Defines the registry value as a static string.
markdownDescription:
en: |-
When you define `valueData` with the `String` property, the resource sets the data for
the registry value as a static string. If the string contains any unexpanded references
to environment variables, such as `%PATH%`, the references are treated as literal
characters and aren't expandable.`
ExpandString:
title:
en: Expandable string value data
description:
en: Defines the registry value as a string with expandable references.
markdownDescription:
en: |-
When you define `valueData` with the `ExpandString` property, the resource sets the data
for the registry value as a string. If the string contains any unexpanded references to
environment variables, such as `%PATH%`, they're expandable.
MultiString:
title:
en: Multiple string value data
description:
en: Defines the registry value as an array of static strings.
markdownDescription:
en: |-
When you define `valueData` with the `MultiString` property, the resource sets the data
for the registry value as an array of static strings. You can specify the value as an
empty array, or as an array containing one or more strings. If any of the strings in the
array contain any unexpanded references to environment variables, such as `%PATH%`, the
references are treated as literal characters and aren't expandable.
Binary:
title:
en: Binary value data
description:
en: Defines the registry value as an array of bytes.
markdownDescription:
en: |-
When you define `valueData` with the `Binary` property, the resource sets the data for
the registry value as an array of bytes. You can specify the value as an empty array or
as an array containing the integer representation of one or more bytes.
DWord:
title:
en: DWord value data
description:
en: Defines the registry value as an unsigned 32-bit integer.
markdownDescription:
en: |-
When you define `valueData` with the `DWord` property, the resource sets the data for the
registry value as an unsigned 32-bit integer.
QWord:
title:
en: QWord value data
description:
en: Defines the registry value as an unsigned 64-bit integer.
markdownDescription:
en: |-
When you define `valueData` with the `QWord` property, the resource sets the data for the
registry value as an unsigned 64-bit integer.
exist:
title:
en: Exist
description:
en: Defines whether the instance should exist.
markdownDescription:
en: |-
The `_exist` property defines whether a registry key or value should exist. When this
property is `true`, the resource creates the registry key or value if it doesn't exist
during a `set` operation. When this property is `false`, the resource deletes the registry
key or value if it exists during a `set` operation.

The default value is `true`.
59 changes: 31 additions & 28 deletions registry/src/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
use clap::{Parser, Subcommand};

#[derive(Parser)]
#[clap(name = "registry", version = "0.0.1", about = "Manage state of Windows registry", long_about = None)]
#[clap(name = "registry", version = "0.0.1", about = t!("cli.about").to_string(), long_about = None)]
pub struct Arguments {

#[clap(subcommand)]
Expand All @@ -13,70 +13,73 @@ pub struct Arguments {

#[derive(Debug, PartialEq, Eq, Subcommand)]
pub enum ConfigSubCommand {
#[clap(name = "get", about = "Retrieve registry configuration.")]
#[clap(name = "get", about = t!("cli.config.get.about").to_string())]
Get {
#[clap(short, long, required = true, help = "The registry JSON input.")]
#[clap(short, long, required = true, help = t!("cli.config.args.input.help").to_string())]
input: String,
},
#[clap(name = "set", about = "Apply registry configuration.")]
#[clap(name = "set", about = t!("cli.config.set.about").to_string())]
Set {
#[clap(short, long, required = true, help = "The registry JSON input.")]
#[clap(short, long, required = true, help = t!("cli.config.args.input.help").to_string())]
input: String,
#[clap(short = 'w', long, help = "Run as a what-if operation instead of applying the registry configuration")]
#[clap(short = 'w', long, help = t!("cli.config.args.what_if.help").to_string())]
what_if: bool,
},
#[clap(name = "delete", about = "Delete registry configuration.")]
#[clap(name = "delete", about = t!("cli.config.delete.about").to_string())]
Delete {
#[clap(short, long, required = true, help = "The registry JSON input.")]
#[clap(short, long, required = true, help = t!("cli.config.args.input.help").to_string())]
input: String,
},
}

#[derive(Debug, PartialEq, Eq, Subcommand)]
pub enum SubCommand {
#[clap(name = "query", about = "Query a registry key or value.", arg_required_else_help = true)]
#[clap(name = "query", about = t!("cli.query.about").to_string(), arg_required_else_help = true)]
Query {
#[clap(short, long, required = true, help = "The registry key path to query.")]
#[clap(short, long, required = true, help = t!("cli.query.args.key_path.help").to_string())]
key_path: String,
#[clap(short, long, help = "The name of the value to query.")]
#[clap(short, long, help = t!("cli.query.args.value_name.help").to_string())]
value_name: Option<String>,
#[clap(short, long, help = "Recursively query subkeys.")]
#[clap(short, long, help = t!("cli.query.args.recurse.help").to_string())]
recurse: bool,
},
#[clap(name = "set", about = "Set a registry key or value.")]
#[clap(name = "set", about = t!("cli.set.about").to_string())]
Set {
#[clap(short, long, required = true, help = "The registry key path to set.")]
#[clap(short, long, required = true, help = t!("cli.set.args.key_path.help").to_string())]
key_path: String,
#[clap(short, long, help = "The value to set.")]
#[clap(short, long, help = t!("cli.set.args.value.help").to_string())]
value: String,
},
#[clap(name = "remove", about = "Remove a registry key or value.", arg_required_else_help = true)]
#[clap(name = "remove", about = t!("cli.remove.about").to_string(), arg_required_else_help = true)]
Remove {
#[clap(short, long, required = true, help = "The registry key path to remove.")]
#[clap(short, long, required = true, help = t!("cli.remove.args.key_path.help").to_string())]
key_path: String,
#[clap(short, long, help = "The name of the value to remove.")]
#[clap(short, long, help = t!("cli.remove.args.value_name.help").to_string())]
value_name: Option<String>,
#[clap(short, long, help = "Recursively remove subkeys.")]
#[clap(short, long, help = t!("cli.remove.args.recurse.help").to_string())]
recurse: bool,
},
#[clap(name = "find", about = "Find a registry key or value.", arg_required_else_help = true)]
#[clap(name = "find", about = t!("cli.find.about").to_string(), arg_required_else_help = true)]
Find {
#[clap(short, long, required = true, help = "The registry key path to start find.")]
#[clap(short, long, required = true, help = t!("cli.find.args.key_path.help").to_string())]
key_path: String,
#[clap(short, long, required = true, help = "The string to find.")]
#[clap(short, long, required = true, help = t!("cli.find.args.find.help").to_string())]
find: String,
#[clap(short, long, help = "Recursively find.")]
#[clap(short, long, help = t!("cli.find.args.recurse.help").to_string())]
recurse: bool,
#[clap(long, help = "Only find keys.")]
#[clap(long, help = t!("cli.find.args.keys_only.help").to_string())]
keys_only: bool,
#[clap(long, help = "Only find values.")]
#[clap(long, help = t!("cli.find.args.values_only.help").to_string())]
values_only: bool,
},
#[clap(name = "config", about = "Manage registry configuration.", arg_required_else_help = true)]
#[clap(name = "config", about = t!("cli.config.about").to_string(), arg_required_else_help = true)]
Config {
#[clap(subcommand)]
subcommand: ConfigSubCommand,
},
#[clap(name = "schema", about = "Retrieve JSON schema.")]
Schema,
#[clap(name = "schema", about = t!("cli.schema.about").to_string())]
Schema {
#[clap(short, long, help = t!("cli.schema.args.values_only.help").to_string())]
enhanced: bool,
},
}
Loading
Loading