diff --git a/graccesscli/src/ZB.MOM.WW.GRAccess.Cli/Commands/GRAccessSurfaceCommands.cs b/graccesscli/src/ZB.MOM.WW.GRAccess.Cli/Commands/GRAccessSurfaceCommands.cs index e94317a..ebf3e26 100644 --- a/graccesscli/src/ZB.MOM.WW.GRAccess.Cli/Commands/GRAccessSurfaceCommands.cs +++ b/graccesscli/src/ZB.MOM.WW.GRAccess.Cli/Commands/GRAccessSurfaceCommands.cs @@ -434,7 +434,16 @@ namespace ZB.MOM.WW.GRAccess.Cli.Commands [CommandOption("file", Description = "Script source file", IsRequired = true)] public string File { get; init; } - public override Dictionary Args() { var args = base.Args(); args["file"] = File; return args; } + [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.")] + public string Field { get; init; } = ""; + + public override Dictionary Args() { var args = base.Args(); args["file"] = File; args["field"] = Field; return args; } + } + + [Command("object scripts delete", Description = "Delete a ScriptExtension primitive from an object")] + public sealed class ObjectScriptsDeleteCommand : ObjectScriptsGetCommand + { + public override string Subcommand => "scripts-delete"; } public abstract class ObjectScriptSettingsCommandBase : ObjectScriptsGetCommand @@ -451,6 +460,9 @@ namespace ZB.MOM.WW.GRAccess.Cli.Commands [CommandOption("lock-trigger-period", Description = "Lock TriggerPeriod in this object after setting it")] public bool LockTriggerPeriod { get; init; } + [CommandOption("lock-trigger-type", Description = "Lock TriggerType in this object after setting it")] + public bool LockTriggerType { get; init; } + public override Dictionary Args() { var args = base.Args(); @@ -458,6 +470,7 @@ namespace ZB.MOM.WW.GRAccess.Cli.Commands args["trigger-type"] = TriggerType; args["expression"] = Expression; args["lock-trigger-period"] = LockTriggerPeriod; + args["lock-trigger-type"] = LockTriggerType; return args; } } diff --git a/graccesscli/src/ZB.MOM.WW.GRAccess.Cli/GRAccess/GRAccessCommandDispatcher.cs b/graccesscli/src/ZB.MOM.WW.GRAccess.Cli/GRAccess/GRAccessCommandDispatcher.cs index ac8bdae..d6056f4 100644 --- a/graccesscli/src/ZB.MOM.WW.GRAccess.Cli/GRAccess/GRAccessCommandDispatcher.cs +++ b/graccesscli/src/ZB.MOM.WW.GRAccess.Cli/GRAccess/GRAccessCommandDispatcher.cs @@ -142,9 +142,18 @@ namespace ZB.MOM.WW.GRAccess.Cli.GRAccess case "scripts-create": RequireConfirm(args, Arg(args, "name")); return AtomicObjectEdit(FindSingleObject(galaxy, Kind(args), Arg(args, "name")), obj => ObjectScriptCreate(galaxy, obj, args)); + case "scripts-delete": + return AtomicObjectEdit(FindSingleObject(galaxy, Kind(args), Arg(args, "name")), obj => + { + var scriptName = Arg(args, "script"); + if (string.IsNullOrWhiteSpace(scriptName)) + throw new ArgumentException("Script name is required."); + obj.DeleteExtensionPrimitive("ScriptExtension", scriptName); + return CommandSummary(obj, $"Delete script {scriptName}"); + }); case "scripts-set": RequireConfirm(args, Arg(args, "name")); - return AtomicObjectEdit(FindSingleObject(galaxy, Kind(args), Arg(args, "name")), obj => ObjectScriptSet(galaxy, obj, Arg(args, "script"), Arg(args, "file"))); + return AtomicObjectEdit(FindSingleObject(galaxy, Kind(args), Arg(args, "name")), obj => ObjectScriptSet(galaxy, obj, Arg(args, "script"), Arg(args, "file"), Arg(args, "field", string.Empty))); case "scripts-settings-set": RequireConfirm(args, Arg(args, "name")); return AtomicObjectEdit(FindSingleObject(galaxy, Kind(args), Arg(args, "name")), obj => ObjectScriptSettingsSet(obj, args)); @@ -1590,14 +1599,28 @@ namespace ZB.MOM.WW.GRAccess.Cli.GRAccess }; } - private static string ObjectScriptSet(IGalaxy galaxy, IgObject obj, string scriptName, string file) + private static string ObjectScriptSet(IGalaxy galaxy, IgObject obj, string scriptName, string file, string field = "") { if (string.IsNullOrWhiteSpace(file)) throw new ArgumentException("Script source --file is required."); if (!File.Exists(file)) throw new FileNotFoundException("Script source file was not found.", file); - var attributeName = ScriptAttributeName(scriptName); + string attributeName; + if (!string.IsNullOrWhiteSpace(field)) + { + // Validate against the canonical script-text suffix list so + // callers get a friendly error before we try to write a + // nonexistent attribute. + if (!ScriptTextSuffixes.Any(s => string.Equals(s, field, StringComparison.OrdinalIgnoreCase))) + throw new ArgumentException($"--field must be one of: {string.Join(", ", ScriptTextSuffixes)}"); + attributeName = scriptName + "." + field; + } + else + { + attributeName = ScriptAttributeName(scriptName); + } + var attr = FindAttributeForMutation(obj, attributeName); var body = File.ReadAllText(file); attr.SetValue(CreateMxValue(body, "string")); @@ -1656,6 +1679,12 @@ namespace ZB.MOM.WW.GRAccess.Cli.GRAccess var attr = FindAttributeForMutation(obj, scriptName + ".TriggerType"); attr.SetValue(CreateMxValue(triggerType, "string")); yield return CommandSummary(attr, $"Set script {scriptName}.TriggerType"); + + if (BoolArg(args, "lock-trigger-type")) + { + attr.SetLocked(MxPropertyLockedEnum.MxLockedInMe); + yield return CommandSummary(attr, $"Lock script {scriptName}.TriggerType"); + } } var expression = OptionalArg(args, "expression"); diff --git a/graccesscli/tests/ZB.MOM.WW.GRAccess.Cli.Tests/Commands/GRAccessSurfaceCommandTests.cs b/graccesscli/tests/ZB.MOM.WW.GRAccess.Cli.Tests/Commands/GRAccessSurfaceCommandTests.cs index c5f8eae..ce1212d 100644 --- a/graccesscli/tests/ZB.MOM.WW.GRAccess.Cli.Tests/Commands/GRAccessSurfaceCommandTests.cs +++ b/graccesscli/tests/ZB.MOM.WW.GRAccess.Cli.Tests/Commands/GRAccessSurfaceCommandTests.cs @@ -20,6 +20,8 @@ namespace ZB.MOM.WW.GRAccess.Cli.Tests.Commands [InlineData(typeof(ObjectQueryNameCommand), "object query-name")] [InlineData(typeof(ObjectScriptsCreateCommand), "object scripts create")] [InlineData(typeof(ObjectScriptsSettingsSetCommand), "object scripts settings set")] + [InlineData(typeof(ObjectScriptsSetCommand), "object scripts set")] + [InlineData(typeof(ObjectScriptsDeleteCommand), "object scripts delete")] [InlineData(typeof(TemplateDeriveCommand), "template derive")] [InlineData(typeof(InstanceDeployCommand), "instance deploy")] [InlineData(typeof(ObjectsExportCommand), "objects export")]