From 1f99faf5bc292edc92f5b9b7de5ad6f39405408e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marius=20D=C3=B6rbandt?= Date: Sun, 10 Nov 2024 17:20:50 +0100 Subject: [PATCH 1/5] Add support for remotes with non-HTTP(S) URLs via external git Closes #3. --- .../instance/canHandleUrlInternally..st | 3 +++ .../instance/cloneFrom..st | 4 ++-- .../instance/fetchFrom..st | 2 +- .../instance/fetchInternalFrom..st | 1 + .../handleConnectionClosed.while.ifRetry..st | 7 +++++++ ...eConnectionClosed.whileTryingTo.ifRetry..st | 18 ------------------ .../instance/push.toRemote.force..st | 2 +- ...emote.update.deleteRemoteBranches.force..st | 5 +++++ ...uestToEnableExternalFetchAndPushBecause..st | 17 +++++++++++++++++ .../instance/shouldHandleUrlExternally..st | 9 +++++++++ .../methodProperties.json | 15 +++++++++------ .../class/nameFromURL..st | 6 ++---- .../methodProperties.json | 2 +- .../instance/buildRemoteUrlInput..st | 2 +- .../GSRemoteDialog.class/methodProperties.json | 2 +- 15 files changed, 60 insertions(+), 35 deletions(-) create mode 100644 src/FileSystem-Git.package/FileSystemGitRepository.class/instance/canHandleUrlInternally..st create mode 100644 src/FileSystem-Git.package/FileSystemGitRepository.class/instance/handleConnectionClosed.while.ifRetry..st delete mode 100644 src/FileSystem-Git.package/FileSystemGitRepository.class/instance/handleConnectionClosed.whileTryingTo.ifRetry..st create mode 100644 src/FileSystem-Git.package/FileSystemGitRepository.class/instance/requestToEnableExternalFetchAndPushBecause..st create mode 100644 src/FileSystem-Git.package/FileSystemGitRepository.class/instance/shouldHandleUrlExternally..st diff --git a/src/FileSystem-Git.package/FileSystemGitRepository.class/instance/canHandleUrlInternally..st b/src/FileSystem-Git.package/FileSystemGitRepository.class/instance/canHandleUrlInternally..st new file mode 100644 index 000000000..81966d1ca --- /dev/null +++ b/src/FileSystem-Git.package/FileSystemGitRepository.class/instance/canHandleUrlInternally..st @@ -0,0 +1,3 @@ +git porcelain +canHandleUrlInternally: aString + ^ {'http://'. 'https://'} anySatisfy: [:each | aString beginsWith: each] \ No newline at end of file diff --git a/src/FileSystem-Git.package/FileSystemGitRepository.class/instance/cloneFrom..st b/src/FileSystem-Git.package/FileSystemGitRepository.class/instance/cloneFrom..st index eff8c8b79..2bf766318 100644 --- a/src/FileSystem-Git.package/FileSystemGitRepository.class/instance/cloneFrom..st +++ b/src/FileSystem-Git.package/FileSystemGitRepository.class/instance/cloneFrom..st @@ -1,11 +1,11 @@ git porcelain cloneFrom: aStringOrUrl - GitFeatureFlags externalFetchAndPush + (self shouldHandleUrlExternally: aStringOrUrl) ifTrue: [self cloneExternalFrom: aStringOrUrl] ifFalse: [[self cloneInternalFrom: aStringOrUrl] on: ConnectionClosed do: [:exception | self handleConnectionClosed: exception - whileTryingTo: 'clone' + while: 'cloning' ifRetry: [self cloneFrom: aStringOrUrl]]]. \ No newline at end of file diff --git a/src/FileSystem-Git.package/FileSystemGitRepository.class/instance/fetchFrom..st b/src/FileSystem-Git.package/FileSystemGitRepository.class/instance/fetchFrom..st index 6657228fb..708a2f606 100644 --- a/src/FileSystem-Git.package/FileSystemGitRepository.class/instance/fetchFrom..st +++ b/src/FileSystem-Git.package/FileSystemGitRepository.class/instance/fetchFrom..st @@ -7,5 +7,5 @@ fetchFrom: aRemoteName do: [:exception | self handleConnectionClosed: exception - whileTryingTo: 'fetch' + while: 'fetching' ifRetry: [self fetchFrom: aRemoteName]]]. \ No newline at end of file diff --git a/src/FileSystem-Git.package/FileSystemGitRepository.class/instance/fetchInternalFrom..st b/src/FileSystem-Git.package/FileSystemGitRepository.class/instance/fetchInternalFrom..st index d49c9c45e..b524dfcf5 100644 --- a/src/FileSystem-Git.package/FileSystemGitRepository.class/instance/fetchInternalFrom..st +++ b/src/FileSystem-Git.package/FileSystemGitRepository.class/instance/fetchInternalFrom..st @@ -3,6 +3,7 @@ fetchInternalFrom: aRemoteName | remote url fetchSpec packFile protocol remoteRefs wantRefs wantSignatures packFileData | remote := self unitOfWork remoteNamed: aRemoteName. url := remote url ifNil: [(GitRemoteUndefined remote: remote) signal: 'No URL configured.']. + (self shouldHandleUrlExternally: url) ifTrue: [^ self fetchAllExternalFrom: aRemoteName]. fetchSpec := remote fetchSpecs ifEmpty: [GitFetchSpec fromString: '+refs/heads/*:refs/remotes/', aRemoteName, '/*' diff --git a/src/FileSystem-Git.package/FileSystemGitRepository.class/instance/handleConnectionClosed.while.ifRetry..st b/src/FileSystem-Git.package/FileSystemGitRepository.class/instance/handleConnectionClosed.while.ifRetry..st new file mode 100644 index 000000000..679a3db5d --- /dev/null +++ b/src/FileSystem-Git.package/FileSystemGitRepository.class/instance/handleConnectionClosed.while.ifRetry..st @@ -0,0 +1,7 @@ +git porcelain +handleConnectionClosed: aConnectionClosed while: aString ifRetry: aBlock + (self requestToEnableExternalFetchAndPushBecause: + ('{1} failed with the internal git implementation.' + format: {aString capitalized})) + ifFalse: [aConnectionClosed pass] + ifTrue: [aBlock value]. \ No newline at end of file diff --git a/src/FileSystem-Git.package/FileSystemGitRepository.class/instance/handleConnectionClosed.whileTryingTo.ifRetry..st b/src/FileSystem-Git.package/FileSystemGitRepository.class/instance/handleConnectionClosed.whileTryingTo.ifRetry..st deleted file mode 100644 index 1c4230366..000000000 --- a/src/FileSystem-Git.package/FileSystemGitRepository.class/instance/handleConnectionClosed.whileTryingTo.ifRetry..st +++ /dev/null @@ -1,18 +0,0 @@ -git porcelain -handleConnectionClosed: aConnectionClosed whileTryingTo: aString ifRetry: aBlock - | preference | - preference := Preferences - pragmaPreferenceFor: GitFeatureFlags - getter: #externalFetchAndPush. - (self confirm: - ('{1}ing failed with the internal git implementation. ' asText, - 'Do you want to try to automatically {2} using the git commandline? ', - 'This will enable ', - ('a preference' asText - addAttribute: (PluggableTextAttribute evalBlock: [preference open]); - yourself), - ' to remember your decision.' format: {aString capitalized. aString})) - ifFalse: [aConnectionClosed pass] - ifTrue: [ - preference preferenceValue: true. - aBlock value]. \ No newline at end of file diff --git a/src/FileSystem-Git.package/FileSystemGitRepository.class/instance/push.toRemote.force..st b/src/FileSystem-Git.package/FileSystemGitRepository.class/instance/push.toRemote.force..st index ca4fb3f5d..5b91594f6 100644 --- a/src/FileSystem-Git.package/FileSystemGitRepository.class/instance/push.toRemote.force..st +++ b/src/FileSystem-Git.package/FileSystemGitRepository.class/instance/push.toRemote.force..st @@ -17,7 +17,7 @@ push: aCollectionOfBranchNamesAndAssociations toRemote: remoteName force: forceB do: [:exception | self handleConnectionClosed: exception - whileTryingTo: 'push' + while: 'pushing' ifRetry: [self push: aCollectionOfBranchNamesAndAssociations toRemote: remoteName diff --git a/src/FileSystem-Git.package/FileSystemGitRepository.class/instance/pushToRemote.update.deleteRemoteBranches.force..st b/src/FileSystem-Git.package/FileSystemGitRepository.class/instance/pushToRemote.update.deleteRemoteBranches.force..st index c31e0f6cd..dd813ce64 100644 --- a/src/FileSystem-Git.package/FileSystemGitRepository.class/instance/pushToRemote.update.deleteRemoteBranches.force..st +++ b/src/FileSystem-Git.package/FileSystemGitRepository.class/instance/pushToRemote.update.deleteRemoteBranches.force..st @@ -3,6 +3,11 @@ pushToRemote: remoteName update: aCollectionOfBranchNamesAndAssociations deleteR | remote url protocol updateRefs deleteRefs pushBlock report | remote := self unitOfWork remoteNamed: remoteName. url := remote url. + (self shouldHandleUrlExternally: url) ifTrue: [ + ^ self + externalPush: aCollectionOfBranchNamesAndAssociations + toRemote: remoteName + force: forceBoolean]. updateRefs := aCollectionOfBranchNamesAndAssociations collect: [:each | each value == each ifTrue: [(self unitOfWork expandRef: each) -> (self unitOfWork objectReferenced: each)] diff --git a/src/FileSystem-Git.package/FileSystemGitRepository.class/instance/requestToEnableExternalFetchAndPushBecause..st b/src/FileSystem-Git.package/FileSystemGitRepository.class/instance/requestToEnableExternalFetchAndPushBecause..st new file mode 100644 index 000000000..cc64a086f --- /dev/null +++ b/src/FileSystem-Git.package/FileSystemGitRepository.class/instance/requestToEnableExternalFetchAndPushBecause..st @@ -0,0 +1,17 @@ +git porcelain +requestToEnableExternalFetchAndPushBecause: aString + | preference answer | + preference := Preferences + pragmaPreferenceFor: GitFeatureFlags + getter: #externalFetchAndPush. + answer := (self confirm: + ('{1} Do you want to automatically use the git commandline? + This will enable {2} to remember your decision.' + withoutLineEndings withBlanksCondensed asText + format: { + aString. + ('a preference' asText + addAttribute: (PluggableTextAttribute evalBlock: [preference open]); + yourself)})). + answer ifTrue: [preference preferenceValue: true]. + ^ answer \ No newline at end of file diff --git a/src/FileSystem-Git.package/FileSystemGitRepository.class/instance/shouldHandleUrlExternally..st b/src/FileSystem-Git.package/FileSystemGitRepository.class/instance/shouldHandleUrlExternally..st new file mode 100644 index 000000000..ac252dc97 --- /dev/null +++ b/src/FileSystem-Git.package/FileSystemGitRepository.class/instance/shouldHandleUrlExternally..st @@ -0,0 +1,9 @@ +git porcelain +shouldHandleUrlExternally: aString + | errorMessage | + GitFeatureFlags externalFetchAndPush ifTrue: [^ true]. + (self canHandleUrlInternally: aString) ifTrue: [^ false]. + errorMessage := 'The url {1} cannot be handled by the internal git implementation.' + format: {aString printString}. + (self requestToEnableExternalFetchAndPushBecause: errorMessage) ifTrue: [^ true]. + self error: errorMessage. \ No newline at end of file diff --git a/src/FileSystem-Git.package/FileSystemGitRepository.class/methodProperties.json b/src/FileSystem-Git.package/FileSystemGitRepository.class/methodProperties.json index 46dc1dcaa..d5e8b62c7 100644 --- a/src/FileSystem-Git.package/FileSystemGitRepository.class/methodProperties.json +++ b/src/FileSystem-Git.package/FileSystemGitRepository.class/methodProperties.json @@ -6,8 +6,9 @@ "branchNamed:" : "jr 3/2/2020 22:13", "branchNames" : "jr 3/3/2020 21:45", "branches" : "jr 3/4/2020 00:46", + "canHandleUrlInternally:" : "mad 11/10/2024 15:41", "cloneExternalFrom:" : "mad 5/23/2024 21:12", - "cloneFrom:" : "mad 5/23/2024 18:12", + "cloneFrom:" : "mad 11/10/2024 15:45", "cloneInternalFrom:" : "mad 5/23/2024 18:11", "commandExists:" : "mad 4/3/2024 15:10", "commitNamed:" : "jr 8/13/2020 23:08", @@ -18,13 +19,13 @@ "externalGitDo:" : "mad 5/22/2024 13:29", "externalPush:toRemote:force:" : "mad 5/18/2024 12:26", "fetchAllExternalFrom:" : "mad 5/23/2024 18:46", - "fetchFrom:" : "mad 5/23/2024 18:10", + "fetchFrom:" : "mad 11/10/2024 15:45", "fetchFromAll:" : "mad 4/22/2024 17:25", - "fetchInternalFrom:" : "mad 4/22/2024 17:24", + "fetchInternalFrom:" : "mad 11/10/2024 15:36", "filesystemOn:" : "CamilloBruni 8/30/2012 14:06", "flushCaches" : "jr 7/2/2017 19:12", "gitStoreOn:" : "CamilloBruni 9/2/2012 12:33", - "handleConnectionClosed:whileTryingTo:ifRetry:" : "mad 4/22/2024 17:21", + "handleConnectionClosed:while:ifRetry:" : "mad 11/10/2024 15:48", "handleTerminalCommandTemplateCharacter:from:into:withCommand:" : "mad 10/9/2024 15:07", "head" : "jr 8/13/2020 23:10", "headReference" : "jr 3/4/2020 00:47", @@ -34,10 +35,10 @@ "performTerminalCommandTemplateReplacement:in:" : "mad 10/9/2024 15:07", "pruneRefs:keep:" : "mad 4/7/2024 14:44", "push:toRemote:" : "mad 5/18/2024 11:30", - "push:toRemote:force:" : "mad 5/18/2024 11:30", + "push:toRemote:force:" : "mad 11/10/2024 15:45", "pushToRemote:deleteRemoteBranches:" : "jr 1/2/2017 10:18", "pushToRemote:update:deleteRemoteBranches:" : "mad 5/18/2024 11:28", - "pushToRemote:update:deleteRemoteBranches:force:" : "mad 5/18/2024 11:27", + "pushToRemote:update:deleteRemoteBranches:force:" : "mad 11/10/2024 15:34", "pushToUpstreamBranchOf:ifNone:" : "jr 3/4/2020 00:49", "recursivelyCollectCommits:into:limit:" : "jr 3/2/2017 10:39", "refsChangedExternally" : "mad 5/18/2024 11:48", @@ -47,6 +48,8 @@ "removeRemoteNamed:" : "jr 3/4/2020 00:49", "repository" : "CamilloBruni 6/22/2011 05:08", "requestTerminalCommand" : "mad 10/31/2024 17:50", + "requestToEnableExternalFetchAndPushBecause:" : "mad 11/10/2024 15:51", + "shouldHandleUrlExternally:" : "mad 11/10/2024 15:48", "tagNamed:" : "MCGitRepositoryTest 3/3/2020 23:40", "tagNames" : "MCGitRepositoryTest 3/3/2020 23:42", "tags" : "jr 3/4/2020 00:49", diff --git a/src/GitS-Core.package/GSGitWorkingCopy.class/class/nameFromURL..st b/src/GitS-Core.package/GSGitWorkingCopy.class/class/nameFromURL..st index 15f07396d..4c57fc2ed 100644 --- a/src/GitS-Core.package/GSGitWorkingCopy.class/class/nameFromURL..st +++ b/src/GitS-Core.package/GSGitWorkingCopy.class/class/nameFromURL..st @@ -1,9 +1,7 @@ instance creation nameFromURL: aString - | url path name | - url := Url absoluteFromText: aString. - path := url path. - path ifEmpty: [^ self requestUnregisteredName]. + | path name | + path := aString splitBy: '/'. name := (path reversed collect: [:each | self withoutGitSuffix: each]) diff --git a/src/GitS-Core.package/GSGitWorkingCopy.class/methodProperties.json b/src/GitS-Core.package/GSGitWorkingCopy.class/methodProperties.json index 0e493b48b..1b54c2eb0 100644 --- a/src/GitS-Core.package/GSGitWorkingCopy.class/methodProperties.json +++ b/src/GitS-Core.package/GSGitWorkingCopy.class/methodProperties.json @@ -11,7 +11,7 @@ "initializeLastImageHash" : "mad 11/28/2023 19:18", "lastImageHash" : "mad 11/28/2023 19:20", "lastImageHash:" : "mad 11/28/2023 19:24", - "nameFromURL:" : "mad 4/10/2024 19:40", + "nameFromURL:" : "mad 11/10/2024 15:19", "newFromUserAndRegister" : "mad 10/22/2023 00:12", "onFSGitRepository:named:" : "mad 9/19/2023 11:53", "onFSReference:named:" : "mad 9/19/2023 11:53", diff --git a/src/GitS-Core.package/GSRemoteDialog.class/instance/buildRemoteUrlInput..st b/src/GitS-Core.package/GSRemoteDialog.class/instance/buildRemoteUrlInput..st index f07e3f860..f72430f36 100644 --- a/src/GitS-Core.package/GSRemoteDialog.class/instance/buildRemoteUrlInput..st +++ b/src/GitS-Core.package/GSRemoteDialog.class/instance/buildRemoteUrlInput..st @@ -5,5 +5,5 @@ buildRemoteUrlInput: builder getText: #remoteUrl; editText: #remoteUrl:; setText: #remoteUrl:; - help: 'URL (https)'; + help: 'URL'; yourself \ No newline at end of file diff --git a/src/GitS-Core.package/GSRemoteDialog.class/methodProperties.json b/src/GitS-Core.package/GSRemoteDialog.class/methodProperties.json index c6db5a939..a0a9d152f 100644 --- a/src/GitS-Core.package/GSRemoteDialog.class/methodProperties.json +++ b/src/GitS-Core.package/GSRemoteDialog.class/methodProperties.json @@ -15,7 +15,7 @@ "buildLayout:" : "mad 9/21/2023 18:18", "buildOkButton:" : "mad 9/21/2023 17:47", "buildRemoteNameInput:" : "mad 9/21/2023 18:20", - "buildRemoteUrlInput:" : "mad 10/16/2023 20:16", + "buildRemoteUrlInput:" : "mad 11/10/2024 18:53", "buildWith:" : "mad 9/21/2023 17:48", "checkValidRemoteName" : "mad 10/16/2023 20:20", "close" : "mad 9/21/2023 17:43", From d30f181169cad31cfa026e65c6d7f3ff4a1ef7d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marius=20D=C3=B6rbandt?= Date: Sun, 10 Nov 2024 17:09:50 +0100 Subject: [PATCH 2/5] Add preference to set git executable Closes #42. --- .../instance/cloneExternalFrom..st | 5 ++++- .../instance/externalGitDo..st | 5 ++++- .../instance/gitExecutable.st | 15 +++++++++++++++ .../instance/suggestWSLGitInstallation.st | 4 ++++ .../methodProperties.json | 6 ++++-- .../class/externalGitExecutable..st | 3 +++ .../class/externalGitExecutable.st | 5 +++++ .../GitFeatureFlags.class/methodProperties.json | 2 ++ .../GitFeatureFlags.class/properties.json | 1 + 9 files changed, 42 insertions(+), 4 deletions(-) create mode 100644 src/FileSystem-Git.package/FileSystemGitRepository.class/instance/gitExecutable.st create mode 100644 src/FileSystem-Git.package/FileSystemGitRepository.class/instance/suggestWSLGitInstallation.st create mode 100644 src/FileSystem-Git.package/GitFeatureFlags.class/class/externalGitExecutable..st create mode 100644 src/FileSystem-Git.package/GitFeatureFlags.class/class/externalGitExecutable.st diff --git a/src/FileSystem-Git.package/FileSystemGitRepository.class/instance/cloneExternalFrom..st b/src/FileSystem-Git.package/FileSystemGitRepository.class/instance/cloneExternalFrom..st index 111920d77..c6f411832 100644 --- a/src/FileSystem-Git.package/FileSystemGitRepository.class/instance/cloneExternalFrom..st +++ b/src/FileSystem-Git.package/FileSystemGitRepository.class/instance/cloneExternalFrom..st @@ -6,4 +6,7 @@ cloneExternalFrom: aStringOrUrl (children isEmpty or: [children size = 1 and: [children first basename = '.git']]) ifFalse: [^ self error: 'Target directory is not empty']. directory deleteAll. - self externalCommand: ('git clone "{1}" "{2}"' format: {aStringOrUrl. directory pathName}). \ No newline at end of file + self externalCommand: ('{1} clone "{2}" "{3}"' format: { + self gitExecutable. + aStringOrUrl. + directory pathName}). \ No newline at end of file diff --git a/src/FileSystem-Git.package/FileSystemGitRepository.class/instance/externalGitDo..st b/src/FileSystem-Git.package/FileSystemGitRepository.class/instance/externalGitDo..st index 30609c254..b33e32f89 100644 --- a/src/FileSystem-Git.package/FileSystemGitRepository.class/instance/externalGitDo..st +++ b/src/FileSystem-Git.package/FileSystemGitRepository.class/instance/externalGitDo..st @@ -1,3 +1,6 @@ git porcelain - external externalGitDo: aCommandLineSuffix - self externalCommand: ('git -C "{1}" {2}' format: {repository workingDir pathName. aCommandLineSuffix}). \ No newline at end of file + self externalCommand: ('{1} -C "{2}" {3}' format: { + self gitExecutable. + repository workingDir pathName. + aCommandLineSuffix}). \ No newline at end of file diff --git a/src/FileSystem-Git.package/FileSystemGitRepository.class/instance/gitExecutable.st b/src/FileSystem-Git.package/FileSystemGitRepository.class/instance/gitExecutable.st new file mode 100644 index 000000000..1a94ad753 --- /dev/null +++ b/src/FileSystem-Git.package/FileSystemGitRepository.class/instance/gitExecutable.st @@ -0,0 +1,15 @@ +git porcelain - external +gitExecutable + | exec | + exec := GitFeatureFlags externalGitExecutable. + (self commandExists: exec) ifTrue: [^ exec]. + exec := UIManager default + request: + ('Git could not be found at the path below. + Please install it or provide a path to the git executable. {1}' + withoutLineEndings withBlanksCondensed + format: {self suggestWSLGitInstallation}) + initialAnswer: exec. + exec isEmptyOrNil ifTrue: [^ self error: 'Missing external git installation']. + GitFeatureFlags externalGitExecutable: exec. + ^ self gitExecutable \ No newline at end of file diff --git a/src/FileSystem-Git.package/FileSystemGitRepository.class/instance/suggestWSLGitInstallation.st b/src/FileSystem-Git.package/FileSystemGitRepository.class/instance/suggestWSLGitInstallation.st new file mode 100644 index 000000000..d46dbc99c --- /dev/null +++ b/src/FileSystem-Git.package/FileSystemGitRepository.class/instance/suggestWSLGitInstallation.st @@ -0,0 +1,4 @@ +git porcelain - external +suggestWSLGitInstallation + (OSProcess isWindows and: [self commandExists: 'wsl']) ifFalse: [^ '']. + ^ 'If git is installed in WSL, you can also enter ''wsl git''.' \ No newline at end of file diff --git a/src/FileSystem-Git.package/FileSystemGitRepository.class/methodProperties.json b/src/FileSystem-Git.package/FileSystemGitRepository.class/methodProperties.json index d5e8b62c7..c3f16d373 100644 --- a/src/FileSystem-Git.package/FileSystemGitRepository.class/methodProperties.json +++ b/src/FileSystem-Git.package/FileSystemGitRepository.class/methodProperties.json @@ -7,7 +7,7 @@ "branchNames" : "jr 3/3/2020 21:45", "branches" : "jr 3/4/2020 00:46", "canHandleUrlInternally:" : "mad 11/10/2024 15:41", - "cloneExternalFrom:" : "mad 5/23/2024 21:12", + "cloneExternalFrom:" : "mad 11/10/2024 16:45", "cloneFrom:" : "mad 11/10/2024 15:45", "cloneInternalFrom:" : "mad 5/23/2024 18:11", "commandExists:" : "mad 4/3/2024 15:10", @@ -16,7 +16,7 @@ "detectTerminalCommand" : "mad 10/31/2024 17:49", "expandRemoteRef:" : "pre 6/15/2018 16:04", "externalCommand:" : "mad 11/4/2024 12:53", - "externalGitDo:" : "mad 5/22/2024 13:29", + "externalGitDo:" : "mad 11/10/2024 16:44", "externalPush:toRemote:force:" : "mad 5/18/2024 12:26", "fetchAllExternalFrom:" : "mad 5/23/2024 18:46", "fetchFrom:" : "mad 11/10/2024 15:45", @@ -24,6 +24,7 @@ "fetchInternalFrom:" : "mad 11/10/2024 15:36", "filesystemOn:" : "CamilloBruni 8/30/2012 14:06", "flushCaches" : "jr 7/2/2017 19:12", + "gitExecutable" : "mad 11/10/2024 17:04", "gitStoreOn:" : "CamilloBruni 9/2/2012 12:33", "handleConnectionClosed:while:ifRetry:" : "mad 11/10/2024 15:48", "handleTerminalCommandTemplateCharacter:from:into:withCommand:" : "mad 10/9/2024 15:07", @@ -50,6 +51,7 @@ "requestTerminalCommand" : "mad 10/31/2024 17:50", "requestToEnableExternalFetchAndPushBecause:" : "mad 11/10/2024 15:51", "shouldHandleUrlExternally:" : "mad 11/10/2024 15:48", + "suggestWSLGitInstallation" : "mad 11/10/2024 17:03", "tagNamed:" : "MCGitRepositoryTest 3/3/2020 23:40", "tagNames" : "MCGitRepositoryTest 3/3/2020 23:42", "tags" : "jr 3/4/2020 00:49", diff --git a/src/FileSystem-Git.package/GitFeatureFlags.class/class/externalGitExecutable..st b/src/FileSystem-Git.package/GitFeatureFlags.class/class/externalGitExecutable..st new file mode 100644 index 000000000..d2e574209 --- /dev/null +++ b/src/FileSystem-Git.package/GitFeatureFlags.class/class/externalGitExecutable..st @@ -0,0 +1,3 @@ +accessing +externalGitExecutable: aString + ExternalGitExecutable := aString \ No newline at end of file diff --git a/src/FileSystem-Git.package/GitFeatureFlags.class/class/externalGitExecutable.st b/src/FileSystem-Git.package/GitFeatureFlags.class/class/externalGitExecutable.st new file mode 100644 index 000000000..6464086ca --- /dev/null +++ b/src/FileSystem-Git.package/GitFeatureFlags.class/class/externalGitExecutable.st @@ -0,0 +1,5 @@ +accessing +externalGitExecutable + + + ^ ExternalGitExecutable ifNil: ['git'] \ No newline at end of file diff --git a/src/FileSystem-Git.package/GitFeatureFlags.class/methodProperties.json b/src/FileSystem-Git.package/GitFeatureFlags.class/methodProperties.json index ec8c71830..303841672 100644 --- a/src/FileSystem-Git.package/GitFeatureFlags.class/methodProperties.json +++ b/src/FileSystem-Git.package/GitFeatureFlags.class/methodProperties.json @@ -7,6 +7,8 @@ "evictFromObjectCacheForTests:" : "jr 4/20/2020 23:33", "externalFetchAndPush" : "tobe 10/15/2022 07:17", "externalFetchAndPush:" : "tobe 10/15/2022 07:17", + "externalGitExecutable" : "mad 11/10/2024 16:52", + "externalGitExecutable:" : "mad 11/10/2024 16:52", "pruneWhenFetching" : "mad 4/7/2024 18:31", "pruneWhenFetching:" : "mad 4/7/2024 14:46", "warnAboutUseOfDeprecatedMethods" : "jr 9/21/2020 23:10", diff --git a/src/FileSystem-Git.package/GitFeatureFlags.class/properties.json b/src/FileSystem-Git.package/GitFeatureFlags.class/properties.json index b235d8664..d567223cd 100644 --- a/src/FileSystem-Git.package/GitFeatureFlags.class/properties.json +++ b/src/FileSystem-Git.package/GitFeatureFlags.class/properties.json @@ -6,6 +6,7 @@ "CustomTerminalCommandForExternalCommands", "EvictFromObjectCache", "ExternalFetchAndPush", + "ExternalGitExecutable", "PruneWhenFetching", "UseUnitOfWorkInterface", "WarnAboutUseOfDeprecatedMethods" ], From 593d5325fdca24ca92f7eb480742c4c47a4c00d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marius=20D=C3=B6rbandt?= Date: Sun, 10 Nov 2024 17:31:19 +0100 Subject: [PATCH 3/5] Require OSProcess dependency in FileSystemGitRepository>>commandExists: --- .../instance/commandExists..st | 4 +++- .../instance/externalCommand..st | 6 +----- .../FileSystemGitRepository.class/instance/osProcess.st | 3 +++ .../instance/osProcessClass..st | 8 ++++++++ .../instance/suggestWSLGitInstallation.st | 2 +- .../FileSystemGitRepository.class/methodProperties.json | 8 +++++--- 6 files changed, 21 insertions(+), 10 deletions(-) create mode 100644 src/FileSystem-Git.package/FileSystemGitRepository.class/instance/osProcess.st create mode 100644 src/FileSystem-Git.package/FileSystemGitRepository.class/instance/osProcessClass..st diff --git a/src/FileSystem-Git.package/FileSystemGitRepository.class/instance/commandExists..st b/src/FileSystem-Git.package/FileSystemGitRepository.class/instance/commandExists..st index 86df52b25..0748d652d 100644 --- a/src/FileSystem-Git.package/FileSystemGitRepository.class/instance/commandExists..st +++ b/src/FileSystem-Git.package/FileSystemGitRepository.class/instance/commandExists..st @@ -1,3 +1,5 @@ git porcelain - external commandExists: aString - ^ (ShellSyntax new findExecutablePathFor: (aString copyUpTo: Character space) inDirectoryPath: nil) notNil \ No newline at end of file + ^ ((self osProcessClass: #ShellSyntax) new + findExecutablePathFor: (aString copyUpTo: Character space) + inDirectoryPath: nil) notNil \ No newline at end of file diff --git a/src/FileSystem-Git.package/FileSystemGitRepository.class/instance/externalCommand..st b/src/FileSystem-Git.package/FileSystemGitRepository.class/instance/externalCommand..st index d16181097..47ebe2814 100644 --- a/src/FileSystem-Git.package/FileSystemGitRepository.class/instance/externalCommand..st +++ b/src/FileSystem-Git.package/FileSystemGitRepository.class/instance/externalCommand..st @@ -1,11 +1,7 @@ git porcelain - external externalCommand: aString | osProcess | - osProcess := (Smalltalk classNamed: #OSProcess) ifNil: [ - (self confirm: 'OSProcess is not installed, but is needed to run git externally. Install it?') ifFalse: [^ self]. - Installer ss project: 'OSProcess'; install: 'OSProcess'. - Installer ss project: 'CommandShell'; install: 'CommandShell'. - ^ self externalCommand: aString]. + osProcess := self osProcess. UIManager default informUser: 'Running a git command in a terminal...' during: [ osProcess waitForCommand: (osProcess isWindows diff --git a/src/FileSystem-Git.package/FileSystemGitRepository.class/instance/osProcess.st b/src/FileSystem-Git.package/FileSystemGitRepository.class/instance/osProcess.st new file mode 100644 index 000000000..5fecfd565 --- /dev/null +++ b/src/FileSystem-Git.package/FileSystemGitRepository.class/instance/osProcess.st @@ -0,0 +1,3 @@ +git porcelain - external +osProcess + ^ self osProcessClass: #OSProcess \ No newline at end of file diff --git a/src/FileSystem-Git.package/FileSystemGitRepository.class/instance/osProcessClass..st b/src/FileSystem-Git.package/FileSystemGitRepository.class/instance/osProcessClass..st new file mode 100644 index 000000000..a84a7a16a --- /dev/null +++ b/src/FileSystem-Git.package/FileSystemGitRepository.class/instance/osProcessClass..st @@ -0,0 +1,8 @@ +git porcelain - external +osProcessClass: aSymbol + (Smalltalk classNamed: aSymbol) ifNotNil: [:class | ^ class]. + (self confirm: 'OSProcess is not installed, but is needed to run git externally. Install it?') + ifFalse: [^ self error: 'OSProcess is needed to run git externally.']. + Installer ss project: 'OSProcess'; install: 'OSProcess'. + Installer ss project: 'CommandShell'; install: 'CommandShell'. + ^ Smalltalk classNamed: aSymbol \ No newline at end of file diff --git a/src/FileSystem-Git.package/FileSystemGitRepository.class/instance/suggestWSLGitInstallation.st b/src/FileSystem-Git.package/FileSystemGitRepository.class/instance/suggestWSLGitInstallation.st index d46dbc99c..c290a415f 100644 --- a/src/FileSystem-Git.package/FileSystemGitRepository.class/instance/suggestWSLGitInstallation.st +++ b/src/FileSystem-Git.package/FileSystemGitRepository.class/instance/suggestWSLGitInstallation.st @@ -1,4 +1,4 @@ git porcelain - external suggestWSLGitInstallation - (OSProcess isWindows and: [self commandExists: 'wsl']) ifFalse: [^ '']. + (self osProcess isWindows and: [self commandExists: 'wsl']) ifFalse: [^ '']. ^ 'If git is installed in WSL, you can also enter ''wsl git''.' \ No newline at end of file diff --git a/src/FileSystem-Git.package/FileSystemGitRepository.class/methodProperties.json b/src/FileSystem-Git.package/FileSystemGitRepository.class/methodProperties.json index c3f16d373..ce684a122 100644 --- a/src/FileSystem-Git.package/FileSystemGitRepository.class/methodProperties.json +++ b/src/FileSystem-Git.package/FileSystemGitRepository.class/methodProperties.json @@ -10,12 +10,12 @@ "cloneExternalFrom:" : "mad 11/10/2024 16:45", "cloneFrom:" : "mad 11/10/2024 15:45", "cloneInternalFrom:" : "mad 5/23/2024 18:11", - "commandExists:" : "mad 4/3/2024 15:10", + "commandExists:" : "mad 11/10/2024 17:23", "commitNamed:" : "jr 8/13/2020 23:08", "createBranchNamed:at:" : "jr 3/4/2020 00:47", "detectTerminalCommand" : "mad 10/31/2024 17:49", "expandRemoteRef:" : "pre 6/15/2018 16:04", - "externalCommand:" : "mad 11/4/2024 12:53", + "externalCommand:" : "mad 11/10/2024 17:29", "externalGitDo:" : "mad 11/10/2024 16:44", "externalPush:toRemote:force:" : "mad 5/18/2024 12:26", "fetchAllExternalFrom:" : "mad 5/23/2024 18:46", @@ -33,6 +33,8 @@ "initializeOn:" : "MaxLeske 7/23/2010 09:59", "knownTerminalCommands" : "mad 10/31/2024 17:31", "orphanedHead" : "jr 1/29/2017 22:52", + "osProcess" : "mad 11/10/2024 17:29", + "osProcessClass:" : "mad 11/10/2024 17:24", "performTerminalCommandTemplateReplacement:in:" : "mad 10/9/2024 15:07", "pruneRefs:keep:" : "mad 4/7/2024 14:44", "push:toRemote:" : "mad 5/18/2024 11:30", @@ -51,7 +53,7 @@ "requestTerminalCommand" : "mad 10/31/2024 17:50", "requestToEnableExternalFetchAndPushBecause:" : "mad 11/10/2024 15:51", "shouldHandleUrlExternally:" : "mad 11/10/2024 15:48", - "suggestWSLGitInstallation" : "mad 11/10/2024 17:03", + "suggestWSLGitInstallation" : "mad 11/10/2024 17:29", "tagNamed:" : "MCGitRepositoryTest 3/3/2020 23:40", "tagNames" : "MCGitRepositoryTest 3/3/2020 23:42", "tags" : "jr 3/4/2020 00:49", From 843a4590a4e18986ec99ed10d4e5e86016c13f10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marius=20D=C3=B6rbandt?= Date: Sun, 10 Nov 2024 18:31:30 +0100 Subject: [PATCH 4/5] Handle exit code of external git commands Fixes #38. Fixes #39. --- .../instance/externalCommand..st | 19 ++++++++++++++++--- .../instance/externalCommandExitCodePath.st | 5 +++++ ...emplateCharacter.from.into.withCommand..st | 2 ++ .../instance/knownTerminalCommands.st | 6 +----- .../instance/windowsTerminalCommand..st | 4 ++++ .../methodProperties.json | 8 +++++--- 6 files changed, 33 insertions(+), 11 deletions(-) create mode 100644 src/FileSystem-Git.package/FileSystemGitRepository.class/instance/externalCommandExitCodePath.st create mode 100644 src/FileSystem-Git.package/FileSystemGitRepository.class/instance/windowsTerminalCommand..st diff --git a/src/FileSystem-Git.package/FileSystemGitRepository.class/instance/externalCommand..st b/src/FileSystem-Git.package/FileSystemGitRepository.class/instance/externalCommand..st index 47ebe2814..ac8d88ddf 100644 --- a/src/FileSystem-Git.package/FileSystemGitRepository.class/instance/externalCommand..st +++ b/src/FileSystem-Git.package/FileSystemGitRepository.class/instance/externalCommand..st @@ -1,9 +1,22 @@ git porcelain - external externalCommand: aString - | osProcess | + | osProcess exitCodeReference exitCode errorMessage | osProcess := self osProcess. + exitCodeReference := FileSystem disk referenceTo: self externalCommandExitCodePath. + exitCodeReference ensureDeleted. UIManager default informUser: 'Running a git command in a terminal...' during: [ osProcess waitForCommand: (osProcess isWindows - ifTrue: ['cmd.exe /c "{1} & pause"' format: {aString}] - ifFalse: [self terminalCommand: aString])]. \ No newline at end of file + ifTrue: [self windowsTerminalCommand: aString] + ifFalse: [self terminalCommand: aString]). + [exitCodeReference exists] whileFalse: [0.1 seconds wait]]. + exitCode := exitCodeReference contents asString withBlanksTrimmed asNumber. + exitCode = 0 ifTrue: [^ self]. + errorMessage := 'An external git command failed.'. + (self confirm: + ('{1} Please check its output before closing the terminal. + Do you want to run it again?' + withoutLineEndings withBlanksCondensed + format: {errorMessage})) + ifFalse: [self error: errorMessage] + ifTrue: [self externalCommand: aString]. \ No newline at end of file diff --git a/src/FileSystem-Git.package/FileSystemGitRepository.class/instance/externalCommandExitCodePath.st b/src/FileSystem-Git.package/FileSystemGitRepository.class/instance/externalCommandExitCodePath.st new file mode 100644 index 000000000..7724f13a4 --- /dev/null +++ b/src/FileSystem-Git.package/FileSystemGitRepository.class/instance/externalCommandExitCodePath.st @@ -0,0 +1,5 @@ +git porcelain - external +externalCommandExitCodePath + | tempDirectory | + tempDirectory := self osProcess isWindows ifTrue: ['\Windows\Temp\'] ifFalse: ['/tmp/']. + ^ tempDirectory, 'git-s-external-command-exit-code' \ No newline at end of file diff --git a/src/FileSystem-Git.package/FileSystemGitRepository.class/instance/handleTerminalCommandTemplateCharacter.from.into.withCommand..st b/src/FileSystem-Git.package/FileSystemGitRepository.class/instance/handleTerminalCommandTemplateCharacter.from.into.withCommand..st index 866ad38fd..4f09a8cda 100644 --- a/src/FileSystem-Git.package/FileSystemGitRepository.class/instance/handleTerminalCommandTemplateCharacter.from.into.withCommand..st +++ b/src/FileSystem-Git.package/FileSystemGitRepository.class/instance/handleTerminalCommandTemplateCharacter.from.into.withCommand..st @@ -5,7 +5,9 @@ handleTerminalCommandTemplateCharacter: aCharacter from: aReadStream into: aWrit aReadStream peek = ${ ifTrue: [^ aWriteStream nextPut: aReadStream next]. replacements := (aReadStream upTo: $}) splitBy: ','. command := aString. + command := command, '; code=$?'. (replacements includes: 'no-key') ifFalse: [command := command, '; read -n 1 -p "Press any key to continue..."']. + command := command, '; echo $code > ', self externalCommandExitCodePath. command := 'sh -c ', (GSTextUtilities quote: command). replacements do: [:each | command := self performTerminalCommandTemplateReplacement: each in: command]. diff --git a/src/FileSystem-Git.package/FileSystemGitRepository.class/instance/knownTerminalCommands.st b/src/FileSystem-Git.package/FileSystemGitRepository.class/instance/knownTerminalCommands.st index 36d0bc459..648e2696e 100644 --- a/src/FileSystem-Git.package/FileSystemGitRepository.class/instance/knownTerminalCommands.st +++ b/src/FileSystem-Git.package/FileSystemGitRepository.class/instance/knownTerminalCommands.st @@ -16,11 +16,7 @@ knownTerminalCommands { 'osascript -e ''tell app "Terminal"'. 'activate'. - 'set w to do script "{":\",'':''"''"''}"'. - 'repeat'. - 'delay 0.1'. - 'if not busy of w then exit repeat'. - 'end repeat'. + 'do script "{":\",'':''"''"''}"'. 'end tell'''. } joinSeparatedBy: String crlf. 'st -e {}'. diff --git a/src/FileSystem-Git.package/FileSystemGitRepository.class/instance/windowsTerminalCommand..st b/src/FileSystem-Git.package/FileSystemGitRepository.class/instance/windowsTerminalCommand..st new file mode 100644 index 000000000..5dbdf0a10 --- /dev/null +++ b/src/FileSystem-Git.package/FileSystemGitRepository.class/instance/windowsTerminalCommand..st @@ -0,0 +1,4 @@ +git porcelain - external +windowsTerminalCommand: aString + ^ 'cmd.exe /v:on /c "{1} & set Code=!ErrorLevel!& pause & echo !Code!> {2}"' + format: {aString. self externalCommandExitCodePath} \ No newline at end of file diff --git a/src/FileSystem-Git.package/FileSystemGitRepository.class/methodProperties.json b/src/FileSystem-Git.package/FileSystemGitRepository.class/methodProperties.json index ce684a122..4bb4a53c8 100644 --- a/src/FileSystem-Git.package/FileSystemGitRepository.class/methodProperties.json +++ b/src/FileSystem-Git.package/FileSystemGitRepository.class/methodProperties.json @@ -15,7 +15,8 @@ "createBranchNamed:at:" : "jr 3/4/2020 00:47", "detectTerminalCommand" : "mad 10/31/2024 17:49", "expandRemoteRef:" : "pre 6/15/2018 16:04", - "externalCommand:" : "mad 11/10/2024 17:29", + "externalCommand:" : "mad 11/10/2024 18:58", + "externalCommandExitCodePath" : "mad 11/10/2024 18:14", "externalGitDo:" : "mad 11/10/2024 16:44", "externalPush:toRemote:force:" : "mad 5/18/2024 12:26", "fetchAllExternalFrom:" : "mad 5/23/2024 18:46", @@ -27,11 +28,11 @@ "gitExecutable" : "mad 11/10/2024 17:04", "gitStoreOn:" : "CamilloBruni 9/2/2012 12:33", "handleConnectionClosed:while:ifRetry:" : "mad 11/10/2024 15:48", - "handleTerminalCommandTemplateCharacter:from:into:withCommand:" : "mad 10/9/2024 15:07", + "handleTerminalCommandTemplateCharacter:from:into:withCommand:" : "mad 11/10/2024 17:44", "head" : "jr 8/13/2020 23:10", "headReference" : "jr 3/4/2020 00:47", "initializeOn:" : "MaxLeske 7/23/2010 09:59", - "knownTerminalCommands" : "mad 10/31/2024 17:31", + "knownTerminalCommands" : "mad 11/10/2024 18:30", "orphanedHead" : "jr 1/29/2017 22:52", "osProcess" : "mad 11/10/2024 17:29", "osProcessClass:" : "mad 11/10/2024 17:24", @@ -64,4 +65,5 @@ "validate" : "MCGitRepositoryTest 3/3/2020 23:40", "validateReferenceName:" : "pre 6/15/2018 16:06", "versions" : "jr 3/4/2020 00:50", + "windowsTerminalCommand:" : "mad 11/10/2024 18:15", "withUnitOfWork:" : "jr 2/29/2020 21:43" } } From 7e7c562cb579245370caa134d7ee088a7c357306 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marius=20D=C3=B6rbandt?= Date: Sun, 10 Nov 2024 17:16:57 +0100 Subject: [PATCH 5/5] Encode external commands in UTF-8 Fixes #41. --- .../FileSystemGitRepository.class/instance/externalCommand..st | 3 ++- .../FileSystemGitRepository.class/methodProperties.json | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/FileSystem-Git.package/FileSystemGitRepository.class/instance/externalCommand..st b/src/FileSystem-Git.package/FileSystemGitRepository.class/instance/externalCommand..st index ac8d88ddf..ab488b9be 100644 --- a/src/FileSystem-Git.package/FileSystemGitRepository.class/instance/externalCommand..st +++ b/src/FileSystem-Git.package/FileSystemGitRepository.class/instance/externalCommand..st @@ -8,7 +8,8 @@ externalCommand: aString osProcess waitForCommand: (osProcess isWindows ifTrue: [self windowsTerminalCommand: aString] - ifFalse: [self terminalCommand: aString]). + ifFalse: [self terminalCommand: aString]) + squeakToUtf8. [exitCodeReference exists] whileFalse: [0.1 seconds wait]]. exitCode := exitCodeReference contents asString withBlanksTrimmed asNumber. exitCode = 0 ifTrue: [^ self]. diff --git a/src/FileSystem-Git.package/FileSystemGitRepository.class/methodProperties.json b/src/FileSystem-Git.package/FileSystemGitRepository.class/methodProperties.json index 4bb4a53c8..68a4aeb11 100644 --- a/src/FileSystem-Git.package/FileSystemGitRepository.class/methodProperties.json +++ b/src/FileSystem-Git.package/FileSystemGitRepository.class/methodProperties.json @@ -15,7 +15,7 @@ "createBranchNamed:at:" : "jr 3/4/2020 00:47", "detectTerminalCommand" : "mad 10/31/2024 17:49", "expandRemoteRef:" : "pre 6/15/2018 16:04", - "externalCommand:" : "mad 11/10/2024 18:58", + "externalCommand:" : "mad 11/10/2024 19:06", "externalCommandExitCodePath" : "mad 11/10/2024 18:14", "externalGitDo:" : "mad 11/10/2024 16:44", "externalPush:toRemote:force:" : "mad 5/18/2024 12:26",