fix(create_project): try update() first to preserve user code, fall back to remove+add (#11)
Karstein's review of PR #10: the swap path was destructive -- it nuked the device subtree (Application/PLC_PRG/MAIN task) and rebuilt empty. Even at template-creation time the template's PLC_PRG was lost; only the libraries and an empty Application object survived. Root cause of the original update() crash: it was popping a 'storage format conversion' modal that the script can't see. With the ScriptPromptHandling.NoFlag forced at script top (already in tree), update() now succeeds non-destructively. Verified live on SP22 P1: 1. create_project WinV3Test deviceName='CODESYS Control Win V3 x64' -> succeeds, PLC_PRG preserved (was empty before, still empty after). 2. delete <project>_project.precompilecache -> needed because the cache holds the stale PLCWinNT IoStandard 3.1.3.1 ref. Compile shows 1 error before this step, 0 after. 3. create_pou Application/FB_Counter + set_pou_code with real ST -> succeeds; PLC_PRG references FB_Counter. 4. compile_project -> 0 errors, 1 license warning. The destructive remove() + project.add() path is kept as a fallback for SPs where update() genuinely can't bridge the device kinds, but update() is now the default (and works on SP22 P1). Co-authored-by: Karstein Phobic Nyvold Kvistad <karstein.kvistad@maritimerobotics.com>
This commit is contained in:
parent
07bb66c0f2
commit
a0574b2201
1 changed files with 45 additions and 27 deletions
|
|
@ -179,36 +179,54 @@ try:
|
|||
new_dev_id.type,
|
||||
new_dev_id.id,
|
||||
new_dev_id.version))
|
||||
# NOTE: ScriptDeviceObject.update(device) crashes CODESYS on SP22 P1
|
||||
# (CODESYS exits with code 1 mid-call) when used to swap to a
|
||||
# different *kind* of device -- the API appears intended only for
|
||||
# version-bumping the same device family. ScriptDeviceObject.unplug()
|
||||
# is also the wrong call for top-level devices: it raises
|
||||
# "The argument guidSlot is not a slot device" because unplug only
|
||||
# applies to devices plugged into a slot of a parent device.
|
||||
# The right call for top-level devices is ScriptObject.remove().
|
||||
# The template's PLC_PRG body is empty so we don't lose any user
|
||||
# code by re-creating the device subtree.
|
||||
# Try update() FIRST -- it's the documented in-place device-kind
|
||||
# change that preserves the Application/POU/library subtree
|
||||
# underneath. The earlier "CODESYS exits with code 1" crash was
|
||||
# almost certainly a UI dialog hanging the script worker; with
|
||||
# script_prompt_handling forced to NoFlag at the top of this
|
||||
# script the dialog auto-suppresses. If update() still raises
|
||||
# (e.g. older SP, different device family that genuinely can't
|
||||
# be swapped in-place), fall back to remove() + project.add()
|
||||
# which IS destructive: it nukes the entire device subtree
|
||||
# (Application, POUs, libraries, tasks) and rebuilds an empty
|
||||
# one. The fallback is safe ONLY at template-creation time
|
||||
# because the template's PLC_PRG body is empty -- but anyone
|
||||
# lifting this swap into a standalone change_device tool MUST
|
||||
# NOT use the fallback path on an existing project with code.
|
||||
update_ok = False
|
||||
try:
|
||||
existing_device.remove()
|
||||
print("DEBUG: existing device removed.")
|
||||
existing_device.update(new_dev_id)
|
||||
update_ok = True
|
||||
print("DEBUG: existing_device.update(new_dev_id) succeeded "
|
||||
"-- device kind swapped in-place, subtree preserved.")
|
||||
except Exception as e:
|
||||
detailed = traceback.format_exc()
|
||||
msg = ("Device swap failed at remove step: %s\n%s" % (e, detailed))
|
||||
print("ERROR: %s" % msg)
|
||||
print("SCRIPT_ERROR: %s" % msg)
|
||||
sys.exit(1)
|
||||
try:
|
||||
project.add(existing_name, new_dev_id)
|
||||
print("DEBUG: project.add(name, new_dev_id) succeeded.")
|
||||
except Exception as e:
|
||||
detailed = traceback.format_exc()
|
||||
msg = ("Device swap failed at project.add step "
|
||||
"(remove already happened, project may be in a partial state): "
|
||||
"%s\n%s" % (e, detailed))
|
||||
print("ERROR: %s" % msg)
|
||||
print("SCRIPT_ERROR: %s" % msg)
|
||||
sys.exit(1)
|
||||
print("DEBUG: update(new_dev_id) failed; falling back to "
|
||||
"destructive remove+add. Reason: %s\n%s" % (e, detailed))
|
||||
|
||||
if not update_ok:
|
||||
try:
|
||||
existing_device.remove()
|
||||
print("DEBUG: existing device removed (destructive fallback).")
|
||||
except Exception as e:
|
||||
detailed = traceback.format_exc()
|
||||
msg = ("Device swap failed at remove step (after update() "
|
||||
"fallback): %s\n%s" % (e, detailed))
|
||||
print("ERROR: %s" % msg)
|
||||
print("SCRIPT_ERROR: %s" % msg)
|
||||
sys.exit(1)
|
||||
try:
|
||||
project.add(existing_name, new_dev_id)
|
||||
print("DEBUG: project.add(name, new_dev_id) succeeded "
|
||||
"(destructive fallback path).")
|
||||
except Exception as e:
|
||||
detailed = traceback.format_exc()
|
||||
msg = ("Device swap failed at project.add step "
|
||||
"(remove already happened, project may be in a "
|
||||
"partial state): %s\n%s" % (e, detailed))
|
||||
print("ERROR: %s" % msg)
|
||||
print("SCRIPT_ERROR: %s" % msg)
|
||||
sys.exit(1)
|
||||
device_swapped = True
|
||||
print("DEBUG: Device swap succeeded.")
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue