diff --git a/source/.configmaps b/source/.configmaps index e1f63e8..db0677e 100644 --- a/source/.configmaps +++ b/source/.configmaps @@ -1,7 +1,7 @@ [ { #conditions : [ ], - #ts : 3867308070, + #ts : 3910171340, #comment : '', #formatVersion : '1.1', #applications : OrderedCollection [ @@ -22,13 +22,13 @@ }, { #name : 'TonelLoaderModel', - #versionName : '1.6.3', - #ts : 3867307944 + #versionName : 'b0a807a-master + 134, 135, 137, 138', + #ts : 3910072203 }, { #name : 'TonelReaderModel', - #versionName : '1.6.2', - #ts : 3867235271 + #versionName : 'b0a807a-master + 134, 135, 137, 138', + #ts : 3910170532 }, { #name : 'TonelTools', @@ -37,12 +37,12 @@ }, { #name : 'TonelWriterModel', - #versionName : '1.6.0', - #ts : 3847459439 + #versionName : 'b0a807a-master + 134, 135, 137, 138', + #ts : 3910168633 } ], #name : 'ENVY/Image Tonel', - #versionName : '1.6.3' + #versionName : 'b0a8807a-master + 134, 135, 137, 138' }, { #conditions : [ ], diff --git a/source/TonelLoaderModel/TonelLoader.class.st b/source/TonelLoaderModel/TonelLoader.class.st index b5f6bce..7bc75ed 100644 --- a/source/TonelLoaderModel/TonelLoader.class.st +++ b/source/TonelLoaderModel/TonelLoader.class.st @@ -144,12 +144,13 @@ TonelLoader >> baseEditionStrategy: aTonelLoaderBaseEditionStrategy [ #vaVisibility : 'private' } TonelLoader >> basicLoadApplication: aTonelApplication [ - aTonelApplication prerequisites do: - [:prereq | - (self shouldLoadPrerequisiteApplication: prereq) - ifTrue: [self basicLoadApplication: (self applicationNamed: prereq name)]]. - (self loadedApplications includes: aTonelApplication) - ifFalse: [(TonelApplicationLoader on: aTonelApplication in: self) load] + (self loadedApplications includes: aTonelApplication) + ifFalse: [ + aTonelApplication prerequisites do: [:prereq | + (self shouldLoadPrerequisiteApplication: prereq) + ifTrue: [self basicLoadApplication: (self applicationNamed: prereq name)]]. + self addLoadedApplication: aTonelApplication. + (TonelApplicationLoader on: aTonelApplication in: self) load] ] { #category : 'strategies-convenience' } diff --git a/source/TonelLoaderModel/TonelLoaderApplication.class.st b/source/TonelLoaderModel/TonelLoaderApplication.class.st index 95fd834..efb821e 100644 --- a/source/TonelLoaderModel/TonelLoaderApplication.class.st +++ b/source/TonelLoaderModel/TonelLoaderApplication.class.st @@ -181,13 +181,24 @@ TonelLoaderApplication >> createEdition [ TonelLoaderApplication >> createTonelPackageNameMethodFor: anApp [ "Enter the new method definition below and click 'Resume'." - | source | + | source existingEdition | + (anApp respondsTo: self tonelPackageNameSelector) ifTrue: [| tonelPackageName | tonelPackageName := anApp perform: self tonelPackageNameSelector. self packageName = tonelPackageName ifTrue: [^self]]. self packageName = self name ifTrue: [^self]. source := self tonelPackageNameMethodSource. + + self loader alwaysCreateEditions + ifFalse: [ + existingEdition := + (anApp class shadowEditionsOf: self tonelPackageNameSelector) + detect: [:one | one sourceString = source] + ifNone: []. + existingEdition notNil ifTrue: [existingEdition load ifTrue: [^self]]]. + + (anApp class basicCompile: source notifying: Transcript ifFail: []) ifNotNil: [:compiledMethod | anApp class install: compiledMethod diff --git a/source/TonelLoaderModel/TonelLoaderGitVersionStrategy.class.st b/source/TonelLoaderModel/TonelLoaderGitVersionStrategy.class.st index 80e78cf..4469c0b 100644 --- a/source/TonelLoaderModel/TonelLoaderGitVersionStrategy.class.st +++ b/source/TonelLoaderModel/TonelLoaderGitVersionStrategy.class.st @@ -2,17 +2,104 @@ Class { #name : 'TonelLoaderGitVersionStrategy', #superclass : 'TonelLoaderVersionStrategy', #instVars : [ - 'versionNamePattern' + 'versionNamePattern', + 'hashToVersionPart', + 'pathToVersionPart', + 'dateToVersionPart' + ], + #classVars : [ + 'DefaultBranchPathVersionPart', + 'DefaultCommitHashVersionPart', + 'DefaultCommitDateVersionPart', + 'DefaultVersionNamePattern' ], #category : 'TonelLoaderModel' } -{ #category : 'Not categorized' } +{ #category : 'Defaults - Version parts' } +TonelLoaderGitVersionStrategy class >> defaultBranchPathToVersionPart: aBlock [ + DefaultBranchPathVersionPart := aBlock +] + +{ #category : 'Defaults - Version parts' } +TonelLoaderGitVersionStrategy class >> defaultCommitDateToVersionPart: aBlock [ + DefaultCommitDateVersionPart := aBlock +] + +{ #category : 'Defaults - Version parts' } +TonelLoaderGitVersionStrategy class >> defaultCommitHashToVersionPart: aBlock [ + DefaultCommitHashVersionPart := aBlock +] + +{ #category : 'Defaults - Version parts' } +TonelLoaderGitVersionStrategy class >> defaultVersionNamePattern: aPattern [ + "The version name pattern will be expanded with 3 arguments: + 1. The commit hash representation + 2. The branch path representation + 3. The commit date representation" + DefaultVersionNamePattern := aPattern +] + +{ #category : 'Documentation' } TonelLoaderGitVersionStrategy class >> description [ ^'Use git repository commit hash and branch name' ] +{ #category : 'Defaults - Version parts', + #vaVisibility : 'private' } +TonelLoaderGitVersionStrategy class >> githubShortHash [ + "A block which will return the GitHub short version of a full commit hash - 7 characters long" + + ^[:hexHashString | hexHashString first: 7] +] + +{ #category : 'Defaults - Version parts', + #vaVisibility : 'private' } +TonelLoaderGitVersionStrategy class >> gitlabShortHash [ + "A block which will return the Gitlab short version of a full commit hash - 8 characters long" + ^[:hexHashString | hexHashString first: 8] +] + +{ #category : 'Defaults - Version parts', + #vaVisibility : 'private' } +TonelLoaderGitVersionStrategy class >> hashAndBranchPattern [ + "Use a version name consisting of git hash and branch. + + The version name pattern will be expanded with 3 arguments: + 1. The commit hash representation + 2. The branch path representation + 3. The commit date representation" + + ^'<1s>-<2s>' +] + +{ #category : 'initialization', + #vaVisibility : 'private' } +TonelLoaderGitVersionStrategy class >> initializeAfterLoad [ + + DefaultVersionNamePattern :=self hashAndBranchPattern. + DefaultCommitHashVersionPart := self githubShortHash. + DefaultBranchPathVersionPart := self onlyBranchName. + DefaultCommitDateVersionPart := self iso8601Date. +] + +{ #category : 'Defaults - Version parts', + #vaVisibility : 'private' } +TonelLoaderGitVersionStrategy class >> iso8601Date [ + "A block which will return the date in UTC tz in ISO8601 format" + ^[:aDateTime | aDateTime asUTC printString] + +] + +{ #category : 'Defaults - Version parts', + #vaVisibility : 'private' } +TonelLoaderGitVersionStrategy class >> onlyBranchName [ + "A block which will return only the branch name of the full path to the branch" + ^[:fullGitBranchPath | fullGitBranchPath parts last] + +] + { #category : 'versioning', #vaVisibility : 'private' } TonelLoaderGitVersionStrategy >> attemptVersionFromGit [ @@ -35,31 +122,64 @@ TonelLoaderGitVersionStrategy >> attemptVersionFromGit [ gitBranchCommitFile := CfsReadFileStream open: gitBranchPath asString. [ - commitHash := gitBranchCommitFile nextLine first: 7. + commitHash := gitBranchCommitFile nextLine. stat := gitBranchPath cfsStat. commitDate := DateAndTime date: stat stMtime first time: stat stMtime last] ensure: [gitBranchCommitFile close]. commitHash isEmptyOrNil ifTrue: [ - TonelLoaderError signal: ('Could not retrieve commit hash from the repository') - ] + TonelLoaderError signal: + ('Could not retrieve commit hash from the repository')] ifFalse: [ - ^ - (self versionNamePattern expandMacrosWith: commitHash with: gitBranchPath parts last with: commitDate)]]] + ^(self versionNamePattern + expandMacrosWith: (hashToVersionPart value: commitHash) + with: (pathToVersionPart value: gitBranchPath) + with: (dateToVersionPart value: commitDate))]]] ifFalse: [ TonelLoaderError signal: ( 'There is no git repository at <1p>' expandMacrosWith: self loader reader repositoryPath)] ]. - ^nil + ^nil ] -{ #category : 'versioning', - #vaVisibility : 'private' } -TonelLoaderGitVersionStrategy >> defaultVersionNamePattern [ - ^'<1s>-<2s>' +{ #category : 'accessing' } +TonelLoaderGitVersionStrategy >> branchPathToVersionPart: aBlock [ + "Answer a block used to convert the git branch path to a string that can be included in the Tonel version name + + Argument + 1 argument, the full path of the git branch" + pathToVersionPart := aBlock +] + +{ #category : 'accessing' } +TonelLoaderGitVersionStrategy >> commitDateToVersionPart: aBlock [ + "Set the block used to convert the commit date into a string that can be included in the Tonel version name + + Argument + 1 argument, the commit date of the git branch" + dateToVersionPart := aBlock +] + +{ #category : 'accessing' } +TonelLoaderGitVersionStrategy >> commitHashToVersionPart: aBlock [ + "Set the block used to convert the commit hash into a string that can be included in the Tonel version name + + Arguments: + 1 argument, the the git commit hashas a hex string + " + hashToVersionPart := aBlock +] + +{ #category : 'initialization' } +TonelLoaderGitVersionStrategy >> initialize [ + super initialize. + versionNamePattern := DefaultVersionNamePattern. + dateToVersionPart := DefaultCommitDateVersionPart. + pathToVersionPart := DefaultBranchPathVersionPart. + hashToVersionPart := DefaultCommitHashVersionPart. ] { #category : 'versioning' } @@ -72,11 +192,25 @@ TonelLoaderGitVersionStrategy >> versionFor: aTonelApplication [ { #category : 'accessing' } TonelLoaderGitVersionStrategy >> versionNamePattern [ + "The version name pattern will be expanded with 3 arguments: + 1. The commit hash representation + 2. The branch path representation + 3. The commit date representation + + Answers: + Pattern to be expanded into a version name" ^versionNamePattern - ifNil: [versionNamePattern := self defaultVersionNamePattern] + ifNil: [versionNamePattern := DefaultVersionNamePattern] ] { #category : 'accessing' } TonelLoaderGitVersionStrategy >> versionNamePattern: aString [ + "The version name pattern will be expanded with 3 arguments: + 1. The commit hash representation + 2. The branch path representation + 3. The commit date representation + + Answers: + Pattern to be expanded into a version name" versionNamePattern := aString ] diff --git a/source/TonelReaderModel/TonelParser.class.st b/source/TonelReaderModel/TonelParser.class.st index 04aff9f..053f550 100644 --- a/source/TonelReaderModel/TonelParser.class.st +++ b/source/TonelReaderModel/TonelParser.class.st @@ -234,21 +234,15 @@ TonelParser >> newClassDefinitionFrom: anArray [ ifFalse: [TonelReaderClassDefinition]) name: (metadata at: #name) superclass: (metadata at: #superclass) - variable: nil + variable: ((metadata at: #type ifAbsent: ['']) = 'variable') fieldType: typeName - instanceVariables: - ((metadata at: #instVars ifAbsent: [#()]) collect: [:each | each asString]) - classVariables: - ((metadata at: #classVars ifAbsent: [#()]) collect: [:each | each asString]) - poolDictionaries: - ((metadata at: #pools ifAbsent: [#()]) collect: [:each | each asString]) - ) - category: (metadata at: #category); - classInstanceVariables: (metadata at: #classInstVars ifAbsent: [#()]); - classComment: classComment; - yourself) - - + instanceVariables: (metadata at: #instVars ifAbsent: [#()]) + classVariables: (metadata at: #classVars ifAbsent: [#()]) + poolDictionaries: (metadata at: #pools ifAbsent: [#()])) + category: (metadata at: #category); + classInstanceVariables: (metadata at: #classInstVars ifAbsent: [#()]); + classComment: classComment; + yourself) ] { #category : 'private factory', diff --git a/source/TonelWriterModel/TonelWriter.class.st b/source/TonelWriterModel/TonelWriter.class.st index 96a79ff..e739dc9 100644 --- a/source/TonelWriterModel/TonelWriter.class.st +++ b/source/TonelWriterModel/TonelWriter.class.st @@ -317,13 +317,32 @@ TonelWriter >> ensureDirectory: aString inside: aPath recreate: aBoolean [ directory exists." | path | - path := aPath append: aString. - (aBoolean and: [path exists]) ifTrue: [path deleteAll]. + (aBoolean and: [path exists]) ifTrue: [self ensureDirectoryIsClear: path]. path realize. ^path ] +{ #category : 'utility', + #vaVisibility : 'private' } +TonelWriter >> ensureDirectoryIsClear: path [ + "Private - We ensure the directory is clean. + + NOTE: Since the delete operation might return before the file is actually deleted from disk + we perform up to three retries waiting, with an exponential backoff of the delay. + This avoids file access errors when attempting to write files with the same names. + After that, if the files weren't deleted, we continue as if they were." + + | retries | + path deleteAll. + retries := 0. + [path allFilesAndDirectories notEmpty and: [retries < 3]] whileTrue: [ + (Delay forSeconds: (2 raisedTo: retries)) wait. + retries := retries + 1. + ]. + +] + { #category : 'accessing' } TonelWriter >> flattenSubApplications [ ^flattenSubApplications