Clarify script mutation limits
This commit is contained in:
@@ -60,7 +60,7 @@ graccess object scripts get --galaxy ZB --name TestMachine --type template --scr
|
||||
|
||||
The CLI tries direct GRAccess reads first. If direct GRAccess does not expose inheritance, attribute values, or script bodies, read commands may export the target object to a temporary `.aaPKG`, parse textual/package entries, recurse into nested package archives, parse binary UTF-16 script extension records, and delete the temp files. SQL Server repository reads are not part of normal CLI behavior and should only be used for development verification/debugging.
|
||||
|
||||
Script body access is adapter-dependent. For `ScriptExtension` objects, a bare script name maps to `.ExecuteText`; `object scripts set` writes the matching script body attribute through GRAccess. Mutating script and attribute commands prefer `ConfigurableAttributes[...]` before `Attributes[...]`, because script extension settings such as `TriggerPeriod`, `TriggerType`, `Expression`, and `ExecuteText` are configuration attributes in common GRAccess builds. If neither direct GRAccess nor the package fallback exposes body text, script read commands return structured unavailable details instead of pretending success.
|
||||
Script body access is adapter-dependent. For `ScriptExtension` objects, a bare script name maps to `.ExecuteText`. Mutating script and attribute commands prefer `ConfigurableAttributes[...]` before `Attributes[...]`. On the local GRAccess build, body fields such as `ExecuteText` and `Expression` are package-only and are not persisted by `IAttribute.SetValue`, so the CLI fails fast for those writes instead of returning a false success. Mutable settings such as `TriggerPeriod` and `TriggerType` remain available through `object scripts settings set`. If neither direct GRAccess nor the package fallback exposes body text, script read commands return structured unavailable details instead of pretending success.
|
||||
|
||||
Use the script settings wrapper for IDE-style script configuration:
|
||||
|
||||
@@ -71,7 +71,7 @@ graccess object scripts settings set --galaxy ZB --name '$TestMachine' --type te
|
||||
Use the create wrapper for new object-level script extensions:
|
||||
|
||||
```powershell
|
||||
graccess object scripts create --galaxy ZB --name '$MyTemplate' --type template --script OnScan --file OnScan.txt --trigger-type Periodic --trigger-period-ms 1000 --confirm --confirm-target '$MyTemplate' --llm-json
|
||||
graccess object scripts create --galaxy ZB --name '$MyTemplate' --type template --script OnScan --trigger-type Periodic --trigger-period-ms 1000 --confirm --confirm-target '$MyTemplate' --llm-json
|
||||
```
|
||||
|
||||
## Inheritance And Embedded Objects
|
||||
|
||||
@@ -17,7 +17,7 @@ For LLM-driven script work, read script metadata and validate guarded edits with
|
||||
```powershell
|
||||
graccess object scripts list --galaxy ZB --name TestMachine --type template --llm-json
|
||||
graccess object scripts get --galaxy ZB --name TestMachine --type template --script UpdateTestChangingInt --llm-json
|
||||
graccess object scripts set --galaxy ZB --name TestMachine --type template --script UpdateTestChangingInt --file .\UpdateTestChangingInt.txt --confirm --confirm-target TestMachine --dry-run --llm-json
|
||||
graccess object scripts settings set --galaxy ZB --name TestMachine --type template --script UpdateTestChangingInt --trigger-period-ms 500 --confirm --confirm-target TestMachine --dry-run --llm-json
|
||||
```
|
||||
|
||||
## What The CLI Can Edit Today
|
||||
@@ -28,7 +28,8 @@ graccess object scripts set --galaxy ZB --name TestMachine --type template --scr
|
||||
| Script library export | `script-library export` |
|
||||
| Script library import/add | `script-library import`, `script-library add`, `galaxy import-script-library` |
|
||||
| Object script metadata | `object scripts list`, `object scripts get` |
|
||||
| Object script body read/write | `object scripts get`, `object scripts set` for script body attributes such as `ExecuteText` |
|
||||
| Object script body read | `object scripts get` package fallback for script body attributes such as `ExecuteText` |
|
||||
| Object script mutable settings | `object scripts settings set --trigger-type`, `--trigger-period-ms` |
|
||||
| Script-like attributes | `object attribute set`, lock, security, buffer |
|
||||
| Extension primitives | `object extension add/delete/rename` |
|
||||
| Full object package script payloads | Use `objects export` and `galaxy import-objects` |
|
||||
@@ -90,13 +91,15 @@ $scripts = (@($attrs) + @($extended)) | Where-Object {
|
||||
$scripts | Select-Object Name, DataType, Category, Locked
|
||||
```
|
||||
|
||||
If the script-like setting is a scalar string attribute, edit it through the normal template edit flow. Script extension fields should be written through `ConfigurableAttributes`; the CLI does this automatically for `object scripts set`, `object scripts settings set`, and mutating `object attribute` commands. `object scripts set` is the convenience wrapper for script body attributes. A bare script name maps to `.ExecuteText`; explicit fields such as `.StartupText`, `.OnScanText`, or `.Expression` are preserved.
|
||||
If the script-like setting is a scalar writable attribute, edit it through the normal template edit flow. Script extension attributes are looked up through `ConfigurableAttributes` first, then `Attributes`.
|
||||
|
||||
For local `ScriptExtension` objects, body fields such as `ExecuteText`, `StartupText`, `OnScanText`, and `Expression` are package-only. GRAccess `IAttribute.SetValue` can return success without persisting package-only fields, so `object scripts set` and `object scripts settings set --expression` fail fast when the attribute category starts with `MxCategoryPackageOnly`. Use the IDE or a future package-rewrite path for those fields.
|
||||
|
||||
```powershell
|
||||
graccess object checkout --galaxy ZB --name TestMachine --type template --confirm --confirm-target TestMachine
|
||||
graccess object scripts set --galaxy ZB --name TestMachine --type template --script UpdateTestChangingInt --file .\UpdateTestChangingInt.txt --confirm --confirm-target TestMachine
|
||||
graccess object attribute value set --galaxy ZB --name TestMachine --type template --attribute SomeWritableScriptSetting --value Updated --data-type string --confirm --confirm-target TestMachine
|
||||
graccess object save --galaxy ZB --name TestMachine --type template --confirm --confirm-target TestMachine
|
||||
graccess object checkin --galaxy ZB --name TestMachine --type template --comment 'Update script text' --confirm --confirm-target TestMachine
|
||||
graccess object checkin --galaxy ZB --name TestMachine --type template --comment 'Update writable script setting' --confirm --confirm-target TestMachine
|
||||
```
|
||||
|
||||
Update periodic script settings and lock the interval for deployment inheritance:
|
||||
@@ -137,16 +140,16 @@ Delete:
|
||||
graccess object extension delete --galaxy ZB --name TestMachine --type template --extension-type ScriptExtension --primitive OnScan2 --object-extension --confirm --confirm-target TestMachine
|
||||
```
|
||||
|
||||
These commands manage primitive structure. The IDE-oriented wrapper below creates the same `ScriptExtension` primitive and can initialize the body and common settings:
|
||||
These commands manage primitive structure. The wrapper below creates the same `ScriptExtension` primitive and can initialize mutable settings:
|
||||
|
||||
```powershell
|
||||
graccess object checkout --galaxy ZB --name '$MyTemplate' --type template --confirm --confirm-target '$MyTemplate'
|
||||
graccess object scripts create --galaxy ZB --name '$MyTemplate' --type template --script OnScan --file .\OnScan.txt --trigger-type Periodic --trigger-period-ms 1000 --confirm --confirm-target '$MyTemplate'
|
||||
graccess object scripts create --galaxy ZB --name '$MyTemplate' --type template --script OnScan --trigger-type Periodic --trigger-period-ms 1000 --confirm --confirm-target '$MyTemplate'
|
||||
graccess object save --galaxy ZB --name '$MyTemplate' --type template --confirm --confirm-target '$MyTemplate'
|
||||
graccess object checkin --galaxy ZB --name '$MyTemplate' --type template --comment 'Add OnScan script' --confirm --confirm-target '$MyTemplate'
|
||||
```
|
||||
|
||||
After adding a `ScriptExtension` primitive, set its body with `object scripts set --script <primitiveName>` or `object scripts set --script <primitiveName>.ExecuteText`.
|
||||
After adding a `ScriptExtension` primitive, body text still needs the IDE/package path when the projected body attributes are package-only.
|
||||
|
||||
## Full-Fidelity Object Script Edits
|
||||
|
||||
@@ -200,7 +203,7 @@ graccess instance deploy --galaxy ZB --name TestMachine_ScriptTest_001 --type in
|
||||
```text
|
||||
graccess object scripts list --galaxy ZB --name TestMachine --type template --json
|
||||
graccess object scripts get --galaxy ZB --name TestMachine --type template --script UpdateTestChangingInt --llm-json
|
||||
graccess object scripts set --galaxy ZB --name TestMachine --type template --script UpdateTestChangingInt --file .\UpdateTestChangingInt.txt --confirm --confirm-target TestMachine --llm-json
|
||||
graccess object scripts settings set --galaxy ZB --name TestMachine --type template --script UpdateTestChangingInt --trigger-period-ms 500 --confirm --confirm-target TestMachine --llm-json
|
||||
```
|
||||
|
||||
The local GRAccess examples sometimes show `Template.Scripts[index].ScriptString`. This repository's installed interop exposes the same practical content through script extension attributes such as `UpdateTestChangingInt.ExecuteText`; the CLI writes those attributes directly via `IAttribute.SetValue`.
|
||||
The local GRAccess examples sometimes show `Template.Scripts[index].ScriptString`, but this repository's installed `ArchestrA.GRAccess.dll` does not expose a public object script collection. It exposes script extension projections as attributes and package records. The CLI can read body text through exported package parsing and can write mutable settings through `IAttribute.SetValue`; package-only body/expression fields are not persisted by that GRAccess setter.
|
||||
|
||||
@@ -242,14 +242,15 @@ Scalar `string`, `bool`, `int`, `float`, and `double` writes are supported first
|
||||
graccess object scripts list --galaxy ZB --name TestMachine --type template --llm-json
|
||||
graccess object scripts get --galaxy ZB --name TestMachine --type template --script UpdateTestChangingInt --llm-json
|
||||
graccess object scripts get --galaxy ZB --name TestMachine --type template --script UpdateTestChangingInt.ExecuteText --llm-json
|
||||
graccess object scripts set --galaxy ZB --name TestMachine --type template --script UpdateTestChangingInt --file UpdateTestChangingInt.txt --confirm --confirm-target TestMachine --llm-json
|
||||
graccess object scripts settings set --galaxy ZB --name '$TestMachine' --type template --script UpdateTestChangingInt --trigger-period-ms 500 --lock-trigger-period --confirm --confirm-target '$TestMachine' --llm-json
|
||||
graccess object scripts create --galaxy ZB --name '$MyTemplate' --type template --script OnScan --file OnScan.txt --trigger-type Periodic --trigger-period-ms 1000 --confirm --confirm-target '$MyTemplate' --llm-json
|
||||
graccess object scripts create --galaxy ZB --name '$MyTemplate' --type template --script OnScan --trigger-type Periodic --trigger-period-ms 1000 --confirm --confirm-target '$MyTemplate' --llm-json
|
||||
```
|
||||
|
||||
Direct object script body access depends on the local GRAccess object model. Reads inspect the exported package fallback for script extension bodies and script text fields such as `ExecuteText`, `DeclarationsText`, `StartupText`, `ShutdownText`, `OnScanText`, `OffScanText`, and `Expression`.
|
||||
|
||||
For writes, the CLI follows the GRAccess pattern used by `ScriptExtension` objects: script body and setting mutations prefer `IgObject.ConfigurableAttributes[...]`, then fall back to `Attributes[...]` only if the configurable collection does not expose the requested field. `object scripts set` writes the matching script body attribute; a bare script name maps to `.ExecuteText`. `object scripts settings set` writes common script settings such as `TriggerPeriod`, `TriggerType`, and `Expression`; `--lock-trigger-period` applies `MxLockedInMe` so derived instances receive the interval on deploy. `object scripts create` calls `AddExtensionPrimitive("ScriptExtension", <script>, true)` and can initialize the body/settings in the same checkout flow.
|
||||
For writes, the CLI uses the public GRAccess path exposed by `IgObject.ConfigurableAttributes[...]` / `Attributes[...]` and `IAttribute.SetValue`. This is valid for mutable settings such as `TriggerPeriod` and `TriggerType`. `MxElapsedTime` values are stored in 100 ns increments, so `--trigger-period-ms 500` writes `5,000,000`.
|
||||
|
||||
Script body fields and `Expression` on the local `ScriptExtension` projection are package-only (`MxCategoryPackageOnly*`). GRAccess `IAttribute.SetValue` can report success for those fields without persisting the value, so the CLI now fails fast when it sees a package-only category. `object scripts create` can add the `ScriptExtension` primitive and initialize mutable settings, but it cannot initialize package-only body text through GRAccess. Use the IDE or a future package-rewrite path for body/expression edits.
|
||||
|
||||
### Area, engine, assignment, and I/O wrappers
|
||||
|
||||
|
||||
@@ -316,5 +316,5 @@ The parent instance shape matches `$TestMachine` by count and script metadata. `
|
||||
- Edit embedded child objects by targeting the child instance tagname, such as `DelmiaReceiver_001`, or its hierarchical name when a command supports hierarchical lookup.
|
||||
- Do not mutate `$TestMachine` until the existing checkout state is understood; the template was `checkedOutToMe` during capture.
|
||||
- Direct scalar value readback for many template attributes is not exposed by the current generic attribute value path.
|
||||
- Direct script body readback is not exposed by the current generic value path; use `object scripts get --llm-json` package fallback for reads and `object scripts set` for script body attribute writes.
|
||||
- Direct script body readback is not exposed by the current generic value path; use `object scripts get --llm-json` package fallback for reads. Package-only script body/expression fields are not persisted by GRAccess `IAttribute.SetValue`; use the IDE/package path for those edits.
|
||||
- Extended attributes failed because the local COM type library was not registered.
|
||||
|
||||
@@ -426,7 +426,7 @@ namespace ZB.MOM.WW.GRAccess.Cli.Commands
|
||||
public override Dictionary<string, object> Args() { var args = base.Args(); args["script"] = Script; return args; }
|
||||
}
|
||||
|
||||
[Command("object scripts set", Description = "Set an object script body when supported by the local adapter")]
|
||||
[Command("object scripts set", Description = "Attempt to set object script text through GRAccess; package-only ScriptExtension text fails fast")]
|
||||
public sealed class ObjectScriptsSetCommand : ObjectScriptsGetCommand
|
||||
{
|
||||
public override string Subcommand => "scripts-set";
|
||||
@@ -434,7 +434,7 @@ namespace ZB.MOM.WW.GRAccess.Cli.Commands
|
||||
[CommandOption("file", Description = "Script source file", IsRequired = true)]
|
||||
public string File { get; init; }
|
||||
|
||||
[CommandOption("field", Description = "Script-text field to write: ExecuteText (default), DeclarationsText, StartupText, ShutdownText, OnScanText, OffScanText, Expression. Pass to target a non-body field; omit to default to ExecuteText.")]
|
||||
[CommandOption("field", Description = "Script-text field to write: ExecuteText (default), DeclarationsText, StartupText, ShutdownText, OnScanText, OffScanText, Expression. Package-only fields fail fast instead of silently no-oping.")]
|
||||
public string Field { get; init; } = "";
|
||||
|
||||
public override Dictionary<string, object> Args() { var args = base.Args(); args["file"] = File; args["field"] = Field; return args; }
|
||||
@@ -454,7 +454,7 @@ namespace ZB.MOM.WW.GRAccess.Cli.Commands
|
||||
[CommandOption("trigger-type", Description = "Script trigger type value")]
|
||||
public string TriggerType { get; init; } = "";
|
||||
|
||||
[CommandOption("expression", Description = "Script expression value")]
|
||||
[CommandOption("expression", Description = "Script expression text. On local ScriptExtension builds this is package-only and fails fast.")]
|
||||
public string Expression { get; init; } = "";
|
||||
|
||||
[CommandOption("lock-trigger-period", Description = "Lock TriggerPeriod in this object after setting it")]
|
||||
@@ -475,7 +475,7 @@ namespace ZB.MOM.WW.GRAccess.Cli.Commands
|
||||
}
|
||||
}
|
||||
|
||||
[Command("object scripts create", Description = "Create a ScriptExtension primitive and optionally initialize its body/settings")]
|
||||
[Command("object scripts create", Description = "Create a ScriptExtension primitive and optionally initialize mutable settings")]
|
||||
public sealed class ObjectScriptsCreateCommand : ObjectScriptSettingsCommandBase
|
||||
{
|
||||
public override string Subcommand => "scripts-create";
|
||||
@@ -486,7 +486,7 @@ namespace ZB.MOM.WW.GRAccess.Cli.Commands
|
||||
public override Dictionary<string, object> Args() { var args = base.Args(); args["file"] = File; return args; }
|
||||
}
|
||||
|
||||
[Command("object scripts settings set", Description = "Set ScriptExtension settings through ConfigurableAttributes")]
|
||||
[Command("object scripts settings set", Description = "Set mutable ScriptExtension settings through ConfigurableAttributes")]
|
||||
public sealed class ObjectScriptsSettingsSetCommand : ObjectScriptSettingsCommandBase
|
||||
{
|
||||
public override string Subcommand => "scripts-settings-set";
|
||||
|
||||
@@ -143,6 +143,7 @@ namespace ZB.MOM.WW.GRAccess.Cli.GRAccess
|
||||
RequireConfirm(args, Arg(args, "name"));
|
||||
return AtomicObjectEdit(FindSingleObject(galaxy, Kind(args), Arg(args, "name")), obj => ObjectScriptCreate(galaxy, obj, args));
|
||||
case "scripts-delete":
|
||||
RequireConfirm(args, Arg(args, "name"));
|
||||
return AtomicObjectEdit(FindSingleObject(galaxy, Kind(args), Arg(args, "name")), obj =>
|
||||
{
|
||||
var scriptName = Arg(args, "script");
|
||||
@@ -1693,6 +1694,7 @@ namespace ZB.MOM.WW.GRAccess.Cli.GRAccess
|
||||
if (!string.IsNullOrWhiteSpace(triggerPeriodMs))
|
||||
{
|
||||
var attr = FindAttributeForMutation(obj, scriptName + ".TriggerPeriod");
|
||||
EnsureMutableViaSetValue(attr, scriptName + ".TriggerPeriod");
|
||||
attr.SetValue(CreateMxValue(triggerPeriodMs, "elapsed-ms"));
|
||||
yield return CommandSummary(attr, $"Set script {scriptName}.TriggerPeriod");
|
||||
|
||||
@@ -1707,6 +1709,7 @@ namespace ZB.MOM.WW.GRAccess.Cli.GRAccess
|
||||
if (!string.IsNullOrWhiteSpace(triggerType))
|
||||
{
|
||||
var attr = FindAttributeForMutation(obj, scriptName + ".TriggerType");
|
||||
EnsureMutableViaSetValue(attr, scriptName + ".TriggerType");
|
||||
attr.SetValue(CreateMxValue(triggerType, "string"));
|
||||
yield return CommandSummary(attr, $"Set script {scriptName}.TriggerType");
|
||||
|
||||
|
||||
+48
@@ -164,6 +164,54 @@ namespace ZB.MOM.WW.GRAccess.Cli.Tests.Commands
|
||||
source.ShouldContain("return AtomicObjectEdit(FindSingleObject(galaxy, Kind(args), Arg(args, \"name\")), obj => ObjectScriptSettingsSet");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DispatcherScriptDeleteMutation_RequiresConfirmation()
|
||||
{
|
||||
var source = DispatcherSource();
|
||||
var branch = source.Substring(
|
||||
source.IndexOf("case \"scripts-delete\":", StringComparison.Ordinal),
|
||||
source.IndexOf("case \"scripts-set\":", StringComparison.Ordinal) - source.IndexOf("case \"scripts-delete\":", StringComparison.Ordinal));
|
||||
|
||||
branch.ShouldContain("RequireConfirm(args, Arg(args, \"name\"));");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DispatcherScriptSettings_GuardsPackageOnlyNoOpsBeforeSetValue()
|
||||
{
|
||||
var source = DispatcherSource();
|
||||
|
||||
source.ShouldContain("EnsureMutableViaSetValue(attr, scriptName + \".TriggerPeriod\");");
|
||||
source.ShouldContain("EnsureMutableViaSetValue(attr, scriptName + \".TriggerType\");");
|
||||
source.ShouldContain("EnsureMutableViaSetValue(attr, scriptName + \".Expression\");");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DispatcherElapsedMilliseconds_UseDocumentedHundredNanosecondUnits()
|
||||
{
|
||||
var source = DispatcherSource();
|
||||
|
||||
source.ShouldContain("var elapsedMs = Int64ToElapsedTime(Convert.ToInt64(milliseconds * 10000d));");
|
||||
source.ShouldContain("mxValue.PutElapsedTime(ref elapsedMs);");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ScriptCommandDescriptions_CallOutPackageOnlyLimit()
|
||||
{
|
||||
var set = (CommandAttribute)Attribute.GetCustomAttribute(
|
||||
typeof(ObjectScriptsSetCommand),
|
||||
typeof(CommandAttribute));
|
||||
var settings = (CommandAttribute)Attribute.GetCustomAttribute(
|
||||
typeof(ObjectScriptsSettingsSetCommand),
|
||||
typeof(CommandAttribute));
|
||||
|
||||
set.ShouldNotBeNull();
|
||||
settings.ShouldNotBeNull();
|
||||
set.Description.ShouldNotBeNull();
|
||||
settings.Description.ShouldNotBeNull();
|
||||
set.Description!.ShouldContain("package-only");
|
||||
settings.Description!.ShouldContain("mutable");
|
||||
}
|
||||
|
||||
private static string DispatcherSource()
|
||||
{
|
||||
var directory = new DirectoryInfo(Directory.GetCurrentDirectory());
|
||||
|
||||
Reference in New Issue
Block a user