0
0
Fork 0

fix(git_init): default to sibling _git dir, auto-create, clear empty check

CODESYS Git uses a dual-storage model: the .project file stays where
it is, the git working tree lives in a SEPARATE empty directory. The
prior default ("init in the project's own folder") tripped over the
project file itself and CODESYS would raise the unhelpful
'gitProjectStoragePath: ... is not a valid Git repository location:
DirectoryNotEmpty'. Hit this end-to-end during the first PDE-Demo
smoke test on 2026-04-25 -- the user had to dance around it manually.

git_init now:
- Defaults LocalRepoPath to '<project_basename>_git' as a sibling of
  the project's own dir when not supplied (or when supplied equal to
  the project dir, which has the same trap).
- Auto-creates the target dir if missing.
- Pre-validates emptiness and raises a clear, action-oriented error
  if non-empty, instead of letting CODESYS surface DirectoryNotEmpty.

server.ts tool description updated to call out the dual-storage rule
and the auto-default behaviour up front.

Verified API contract via Stubs/scriptengine/GitScriptProject.pyi
(local SP22 install) and the helpme-codesys.com Git scripting page
(https://content.helpme-codesys.com/en/CODESYS%20Git/_git_using_scripting.html).
This commit is contained in:
Karstein Phobic Nyvold Kvistad 2026-04-25 20:22:10 +02:00
parent 3623c45d31
commit 31e842929e
2 changed files with 35 additions and 5 deletions

View file

@ -19,9 +19,39 @@ try:
"the project does not yet have a git binding. The init() "
"call below should establish one if a repo path is supplied.")
if not LOCAL_REPO_PATH:
# Default: init a repo in the project's own directory
LOCAL_REPO_PATH = os.path.dirname(PROJECT_FILE_PATH)
# CODESYS Git uses a dual-storage model: the .project file stays where it
# is, the git working tree lives in a SEPARATE empty directory. Pointing
# init() at the project's own folder fails with "DirectoryNotEmpty", and
# passing nothing previously dumped the user into that trap. Default to a
# '<project_basename>_git' sibling and auto-create it; verify it is empty
# before handing off to CODESYS so we surface a clear hint instead of
# CODESYS's lower-level error.
project_dir = os.path.dirname(PROJECT_FILE_PATH)
project_stem = os.path.splitext(os.path.basename(PROJECT_FILE_PATH))[0]
if not LOCAL_REPO_PATH or os.path.normcase(os.path.abspath(LOCAL_REPO_PATH)) == os.path.normcase(os.path.abspath(project_dir)):
if LOCAL_REPO_PATH:
print("DEBUG: requested LocalRepoPath equals the project dir; "
"rerouting to a sibling because CODESYS Git requires a separate empty dir.")
# Use a sibling so we don't write into the (likely shared) project folder
LOCAL_REPO_PATH = os.path.join(os.path.dirname(project_dir), project_stem + "_git")
print("DEBUG: defaulted LocalRepoPath to '%s'" % LOCAL_REPO_PATH)
if not os.path.exists(LOCAL_REPO_PATH):
print("DEBUG: creating LocalRepoPath '%s'" % LOCAL_REPO_PATH)
os.makedirs(LOCAL_REPO_PATH)
elif not os.path.isdir(LOCAL_REPO_PATH):
raise RuntimeError(
"LocalRepoPath '%s' exists but is not a directory." % LOCAL_REPO_PATH)
else:
existing = os.listdir(LOCAL_REPO_PATH)
if existing:
raise RuntimeError(
"LocalRepoPath '%s' is not empty (contains %d entries: %s). "
"CODESYS Git's dual-storage model requires a fresh empty "
"directory separate from the project's own folder. Either "
"pass a different localRepoPath or empty this one, then "
"retry git_init." % (
LOCAL_REPO_PATH, len(existing), existing[:5]))
print("DEBUG: calling git.init('%s')" % LOCAL_REPO_PATH)
git.init(LOCAL_REPO_PATH)

View file

@ -1066,10 +1066,10 @@ export async function startMcpServer(config: ServerConfig): Promise<void> {
s.tool(
'git_init',
"Initialises a Git repository for the project's directory (or a custom path) via project.git.init(). One-shot setup; use git_status afterwards to confirm. Requires the CODESYS Git plug-in AND an active CODESYS Professional Developer Edition subscription license -- without the subscription, the tool fails fast with a clear PDE-required message (the runtime 'HasGitLicense' rule gates every project.git.* call).",
"Initialises a Git working tree for the project via project.git.init(). CODESYS Git uses a dual-storage model: the .project file stays where it is, the git repo lives in a SEPARATE empty directory. If localRepoPath is omitted (or equals the project's own folder), the tool auto-defaults to a '<project_basename>_git' sibling and auto-creates it; if it exists and is non-empty, the tool fails with a clear hint. One-shot setup; use git_status afterwards to confirm. Requires the CODESYS Git plug-in AND an active CODESYS Professional Developer Edition subscription license -- without the subscription, the tool fails fast with a clear PDE-required message (the runtime 'HasGitLicense' rule gates every project.git.* call).",
{
projectFilePath: z.string().describe("Path to the project file."),
localRepoPath: z.string().optional().describe("Filesystem path to initialise the repo at. Defaults to the project file's parent directory."),
localRepoPath: z.string().optional().describe("Filesystem path for the git working tree. Must be a separate empty directory, NOT the project's own folder. If omitted, defaults to a '<project_basename>_git' sibling and auto-creates it."),
},
async (args: { projectFilePath: string; localRepoPath?: string }) => {
const escaped = resolvePath(args.projectFilePath, workspaceDir);