message: Add support for private jenkins

diff:
@@ -144,7 +144,23 @@ PhLJenkins2Entity >> shouldComputeChildrenLazily [
^ true
]
+{ #category : #accessing }
+PhLJenkins2Entity >> token [
+ ^ parent token
+]
+
{ #category : #accessing }
PhLJenkins2Entity >> url [
- ^ (properties at: 'url') asUrl
+ "We get the URL from the json sent by Jenkins. In case of a secure Jenkins, we need to set the username and token to the URL we get."
+
+ | url |
+ url := (properties at: 'url') asUrl.
+ self username ifNotNil: [ :username | url username: username ].
+ self token ifNotNil: [ :token | url password: token ].
+ ^ url
+]
+
+{ #category : #accessing }
+PhLJenkins2Entity >> username [
+ ^ parent username
]

diff:
@@ -4,7 +4,7 @@ I'm a job as can be available on a Jenkins platform.
Class {
#name : #PhLJenkins2Job,
#superclass : #PhLJenkins2Entity,
- #category : 'PharoLauncher-Core-Model'
+ #category : #'PharoLauncher-Core-Model'
}
{ #category : #protected }
@@ -26,12 +26,14 @@ PhLJenkins2Job >> builds [
{ #category : #accessing }
PhLJenkins2Job >> lastSuccessfulBuild [
- ^ PhLJenkins2Build
+ ^ (PhLJenkins2Build
newWithProperties:
(Dictionary new
at: 'number' put: self lastSuccessfulBuildNumber;
at: 'url' put: (self url / 'lastSuccessfulBuild') printString;
- yourself)
+ yourself))
+ parent: self;
+ yourself
]
{ #category : #accessing }

diff:
@@ -9,7 +9,7 @@ Class {
'url',
'name'
],
- #category : 'PharoLauncher-Core-Model'
+ #category : #'PharoLauncher-Core-Model'
}
{ #category : #'instance creation' }
@@ -19,6 +19,14 @@ PhLJenkins2Server class >> name: aString url: anUrl [
yourself
]
+{ #category : #'instance creation' }
+PhLJenkins2Server class >> name: aString url: anUrl username: anotherString token: yetAnotherString [
+ ^ (self name: aString url: anUrl)
+ username: anotherString;
+ token: yetAnotherString;
+ yourself
+]
+
{ #category : #accessing }
PhLJenkins2Server >> jobs [
^ self query: PhLJenkins2Job
@@ -40,7 +48,27 @@ PhLJenkins2Server >> templatesAndGroups [
^ self jobs
]
+{ #category : #accessing }
+PhLJenkins2Server >> token [
+ ^ url password
+]
+
+{ #category : #accessing }
+PhLJenkins2Server >> token: aString [
+ url password: aString
+]
+
{ #category : #accessing }
PhLJenkins2Server >> url [
^ url
]
+
+{ #category : #accessing }
+PhLJenkins2Server >> username [
+ ^ url username
+]
+
+{ #category : #accessing }
+PhLJenkins2Server >> username: aString [
+ url username: aString
+]

diff:
@@ -13,7 +13,9 @@ Class {
'url',
'filterPattern',
'templates',
- 'expanded'
+ 'expanded',
+ 'username',
+ 'token'
],
#category : #'PharoLauncher-Core-Model'
}
@@ -274,7 +276,7 @@ PhLTemplateSource >> asBasicTemplateGroup [
url: url asZnUrl
filterPattern: pattern ].
type == self class jenkinsServerType
- ifTrue: [ ^ PhLJenkins2Server name: name url: url asZnUrl ].
+ ifTrue: [ ^ PhLJenkins2Server name: name url: url asZnUrl username: username token: token ].
type == self class urlGroupType
ifTrue: [ ^ PhLFixedURLsTemplateGroup new
setName: name Templates: OrderedCollection new;
@@ -357,6 +359,16 @@ PhLTemplateSource >> templatesDo: aBlockClosure [
templates ifNotNil: [ templates do: aBlockClosure ]
]
+{ #category : #accessing }
+PhLTemplateSource >> token [
+ ^ token
+]
+
+{ #category : #accessing }
+PhLTemplateSource >> token: anObject [
+ token := anObject
+]
+
{ #category : #accessing }
PhLTemplateSource >> type [
^ type
@@ -376,3 +388,13 @@ PhLTemplateSource >> url [
PhLTemplateSource >> url: aString [
url := aString
]
+
+{ #category : #accessing }
+PhLTemplateSource >> username [
+ ^ username
+]
+
+{ #category : #accessing }
+PhLTemplateSource >> username: anObject [
+ username := anObject
+]

diff:
Class {
#name : #PhLJenkins2BuildTest,
#superclass : #PhLJenkins2EntityTest,
- #category : 'PharoLauncher-Tests-Download'
+ #category : #'PharoLauncher-Tests-Download'
}
+{ #category : #'instance creation' }
+PhLJenkins2BuildTest class >> newInstance [
+ | job |
+ job := PhLJenkins2Build
+ newWithProperties: (STONJSON fromString: '{"_class":"hudson.matrix.MatrixBuild","url":"https://ci.inria.fr/moose/job/ClassNamesAnalyzer/223/","number":223}').
+ job parent: PhLJenkins2JobTest newInstance.
+ ^ job
+]
+
+{ #category : #'instance creation' }
+PhLJenkins2BuildTest class >> newSecureJenkinsInstance [
+ | job |
+ job := PhLJenkins2Build
+ newWithProperties: (STONJSON fromString: '{"_class":"hudson.matrix.MatrixBuild","url":"https://ci.inria.fr/moose/job/ClassNamesAnalyzer/223/","number":223}').
+ job parent: PhLJenkins2JobTest newSecureJenkinsInstance.
+ ^ job
+]
+
{ #category : #helpers }
PhLJenkins2BuildTest >> artifactRelativePath [
^ 'foo.zip'
@@ -21,22 +39,22 @@ PhLJenkins2BuildTest >> buildUrlString [
{ #category : #'instance creation' }
PhLJenkins2BuildTest >> emptyBuild [
- ^ PhLJenkins2Build
- newWithProperties:
- (Dictionary new
+ ^ (PhLJenkins2Build newWithProperties: (Dictionary new
at: 'number' put: self buildNumber;
at: 'url' put: self buildUrlString;
- yourself)
+ yourself))
+ parent: PhLJenkins2JobTest newSecureJenkinsInstance;
+ yourself
]
{ #category : #'instance creation' }
PhLJenkins2BuildTest >> emptyLastSuccessfulBuild [
- ^ PhLJenkins2Build
- newWithProperties:
- (Dictionary new
+ ^ (PhLJenkins2Build newWithProperties: (Dictionary new
at: 'number' put: self buildNumber;
at: 'url' put: self lastSuccessfulBuildUrlString;
- yourself)
+ yourself))
+ parent: PhLJenkins2JobTest newSecureJenkinsInstance;
+ yourself
]
{ #category : #helpers }

diff:
Class {
#name : #PhLJenkins2EntityTest,
#superclass : #TestCase,
- #category : 'PharoLauncher-Tests-Download'
+ #category : #'PharoLauncher-Tests-Download'
}
+{ #category : #testing }
+PhLJenkins2EntityTest class >> isAbstract [
+ ^ self = PhLJenkins2EntityTest
+]
+
+{ #category : #'instance creation' }
+PhLJenkins2EntityTest class >> newInstance [
+ ^ self subclassResponsibility
+]
+
+{ #category : #'instance creation' }
+PhLJenkins2EntityTest class >> newSecureJenkinsInstance [
+ ^ self subclassResponsibility
+]
+
+{ #category : #testing }
+PhLJenkins2EntityTest class >> shouldInheritSelectors [
+ ^ true
+]
+
{ #category : #helpers }
PhLJenkins2EntityTest >> downloadManager [
| manager |
@@ -13,6 +33,16 @@ PhLJenkins2EntityTest >> downloadManager [
^ manager
]
+{ #category : #'instance creation' }
+PhLJenkins2EntityTest >> newInstance [
+ ^ self class newInstance
+]
+
+{ #category : #'instance creation' }
+PhLJenkins2EntityTest >> newSecureJenkinsInstance [
+ ^ self class newSecureJenkinsInstance
+]
+
{ #category : #running }
PhLJenkins2EntityTest >> setUp [
super setUp.
@@ -30,3 +60,15 @@ PhLJenkins2EntityTest >> tearDown [
super tearDown.
PhLDownloadManagerMock remove.
]
+
+{ #category : #tests }
+PhLJenkins2EntityTest >> testNonSecureJenkinsDoesNotIncludesIdentifiersInUrl [
+ self deny: self newInstance url hasUsername.
+ self deny: self newInstance url hasPassword
+]
+
+{ #category : #tests }
+PhLJenkins2EntityTest >> testSecureJenkinsIncludesIdentifiersInUrl [
+ self assert: self newSecureJenkinsInstance url hasUsername.
+ self assert: self newSecureJenkinsInstance url hasPassword
+]

diff:
Class {
#name : #PhLJenkins2JobTest,
#superclass : #PhLJenkins2EntityTest,
- #category : 'PharoLauncher-Tests-Download'
+ #category : #'PharoLauncher-Tests-Download'
}
+{ #category : #helpers }
+PhLJenkins2JobTest class >> newInstance [
+ | job |
+ job := PhLJenkins2Job
+ newWithProperties: (STONJSON fromString: '{"_class":"hudson.matrix.MatrixBuild","url":"https://ci.inria.fr/pharo-contribution/job/A4BP/1304/","number":1304}').
+ job parent: PhLJenkins2ServerTest newInstance.
+ ^ job
+]
+
+{ #category : #helpers }
+PhLJenkins2JobTest class >> newSecureJenkinsInstance [
+ | job |
+ job := PhLJenkins2Job
+ newWithProperties: (STONJSON fromString: '{"_class":"hudson.matrix.MatrixBuild","url":"https://ci.inria.fr/pharo-contribution/job/A4BP/1304/","number":1304}').
+ job parent: PhLJenkins2ServerTest newSecureJenkinsInstance.
+ ^ job
+]
+
{ #category : #helpers }
PhLJenkins2JobTest >> lastSuccessfulBuildNumber [
^ 52
@@ -16,41 +34,38 @@ PhLJenkins2JobTest >> lastSuccessfulBuildUrlString [
{ #category : #'instance creation' }
PhLJenkins2JobTest >> newJobWithNoSuccessfulBuild [
- ^ PhLJenkins2Job
- newWithProperties:
- (Dictionary new
+ ^ (PhLJenkins2Job newWithProperties: (Dictionary new
at: 'url' put: 'url' asUrl;
at: 'name' put: 'thejob';
- yourself)
+ yourself))
+ parent: PhLJenkins2ServerTest newInstance;
+ yourself
]
{ #category : #'instance creation' }
PhLJenkins2JobTest >> newJobWithNullSuccessfulBuild [
- ^ PhLJenkins2Job
- newWithProperties:
- (Dictionary new
+ ^ (PhLJenkins2Job newWithProperties: (Dictionary new
at: 'url' put: 'url' asUrl;
at: 'name' put: 'thejob';
at: 'lastSuccessfulBuild' put: nil;
- yourself)
+ yourself))
+ parent: PhLJenkins2ServerTest newInstance;
+ yourself
]
{ #category : #'instance creation' }
PhLJenkins2JobTest >> newJobWithSuccessfulBuild [
- ^ PhLJenkins2Job
- newWithProperties:
- (Dictionary new
+ ^ (PhLJenkins2Job newWithProperties: (Dictionary new
at: 'url' put: 'url' asUrl;
at: 'name' put: 'thejob';
- at: 'lastSuccessfulBuild'
- put:
- (Dictionary
- newFromPairs:
- {'number'.
- (self lastSuccessfulBuildNumber).
+ at: 'lastSuccessfulBuild' put: (Dictionary newFromPairs: {
+ 'number'.
+ self lastSuccessfulBuildNumber.
'url'.
- (self lastSuccessfulBuildUrlString)});
- yourself)
+ self lastSuccessfulBuildUrlString });
+ yourself))
+ parent: PhLJenkins2ServerTest newInstance;
+ yourself
]
{ #category : #responses }

diff:
+Class {
+ #name : #PhLJenkins2RunTest,
+ #superclass : #PhLJenkins2EntityTest,
+ #category : #'PharoLauncher-Tests-Download'
+}
+
+{ #category : #'instance creation' }
+PhLJenkins2RunTest class >> newInstance [
+ | job |
+ job := PhLJenkins2Run
+ newWithProperties: (STONJSON fromString: '{"url":"https://ci.inria.fr/pharo-contribution/job/MaterialDesignLite/PHARO=61,VERSION=development/1140/","number":1140}').
+ job parent: PhLJenkins2BuildTest newInstance.
+ ^ job
+]
+
+{ #category : #'instance creation' }
+PhLJenkins2RunTest class >> newSecureJenkinsInstance [
+ | job |
+ job := PhLJenkins2Run
+ newWithProperties: (STONJSON fromString: '{"url":"https://ci.inria.fr/pharo-contribution/job/MaterialDesignLite/PHARO=61,VERSION=development/1140/","number":1140}').
+ job parent: PhLJenkins2BuildTest newSecureJenkinsInstance.
+ ^ job
+]

diff:
Class {
#name : #PhLJenkins2ServerTest,
#superclass : #PhLJenkins2EntityTest,
- #category : 'PharoLauncher-Tests-Download'
+ #category : #'PharoLauncher-Tests-Download'
}
+{ #category : #'instance creation' }
+PhLJenkins2ServerTest class >> newInstance [
+ ^ PhLJenkins2Server name: 'foo' url: 'bar' asUrl
+]
+
+{ #category : #'instance creation' }
+PhLJenkins2ServerTest class >> newSecureJenkinsInstance [
+ ^ self newInstance
+ username: 'Christophe';
+ token: 'dkewjdcnriuwefjncreiuhf';
+ yourself
+]
+
{ #category : #responses }
PhLJenkins2ServerTest >> defaultJobName [
^ 'theJobName'
@@ -22,7 +35,12 @@ PhLJenkins2ServerTest >> jobsResponse [
{ #category : #'instance creation' }
PhLJenkins2ServerTest >> newInstance [
- ^ PhLJenkins2Server name: 'foo' url: 'bar' asUrl
+ ^ self class newInstance
+]
+
+{ #category : #'instance creation' }
+PhLJenkins2ServerTest >> newSecureJenkinsInstance [
+ ^ self class newSecureJenkinsInstance
]
{ #category : #responses }

original_message: Add support for private jenkins


message: Factorize code

change_type: MODIFY

diff:
@@ -6,20 +6,22 @@ Class {
{ #category : #'instance creation' }
PhLJenkins2BuildTest class >> newInstance [
- | job |
- job := PhLJenkins2Build
- newWithProperties: (STONJSON fromString: '{"_class":"hudson.matrix.MatrixBuild","url":"https://ci.inria.fr/moose/job/ClassNamesAnalyzer/223/","number":223}').
- job parent: PhLJenkins2JobTest newInstance.
- ^ job
+ ^ self newWithoutParent
+ parent: PhLJenkins2JobTest newInstance;
+ yourself
+]
+
+{ #category : #'instance creation' }
+PhLJenkins2BuildTest class >> newSecureInstance [
+ ^ self newWithoutParent
+ parent: PhLJenkins2JobTest newSecureInstance;
+ yourself
]
{ #category : #'instance creation' }
-PhLJenkins2BuildTest class >> newSecureJenkinsInstance [
- | job |
- job := PhLJenkins2Build
- newWithProperties: (STONJSON fromString: '{"_class":"hudson.matrix.MatrixBuild","url":"https://ci.inria.fr/moose/job/ClassNamesAnalyzer/223/","number":223}').
- job parent: PhLJenkins2JobTest newSecureJenkinsInstance.
- ^ job
+PhLJenkins2BuildTest class >> newWithoutParent [
+ ^ PhLJenkins2Build newWithProperties: (STONJSON fromString:
+ '{"_class":"hudson.matrix.MatrixBuild","url":"https://ci.inria.fr/moose/job/ClassNamesAnalyzer/223/","number":223}')
]
{ #category : #helpers }
@@ -43,7 +45,7 @@ PhLJenkins2BuildTest >> emptyBuild [
at: 'number' put: self buildNumber;
at: 'url' put: self buildUrlString;
yourself))
- parent: PhLJenkins2JobTest newSecureJenkinsInstance;
+ parent: PhLJenkins2JobTest newSecureInstance;
yourself
]
@@ -53,7 +55,7 @@ PhLJenkins2BuildTest >> emptyLastSuccessfulBuild [
at: 'number' put: self buildNumber;
at: 'url' put: self lastSuccessfulBuildUrlString;
yourself))
- parent: PhLJenkins2JobTest newSecureJenkinsInstance;
+ parent: PhLJenkins2JobTest newSecureInstance;
yourself
]

diff:
@@ -15,7 +15,7 @@ PhLJenkins2EntityTest class >> newInstance [
]
{ #category : #'instance creation' }
-PhLJenkins2EntityTest class >> newSecureJenkinsInstance [
+PhLJenkins2EntityTest class >> newSecureInstance [
^ self subclassResponsibility
]
@@ -39,8 +39,8 @@ PhLJenkins2EntityTest >> newInstance [
]
{ #category : #'instance creation' }
-PhLJenkins2EntityTest >> newSecureJenkinsInstance [
- ^ self class newSecureJenkinsInstance
+PhLJenkins2EntityTest >> newSecureInstance [
+ ^ self class newSecureInstance
]
{ #category : #running }
@@ -69,6 +69,6 @@ PhLJenkins2EntityTest >> testNonSecureJenkinsDoesNotIncludesIdentifiersInUrl [
{ #category : #tests }
PhLJenkins2EntityTest >> testSecureJenkinsIncludesIdentifiersInUrl [
- self assert: self newSecureJenkinsInstance url hasUsername.
- self assert: self newSecureJenkinsInstance url hasPassword
+ self assert: self newSecureInstance url hasUsername.
+ self assert: self newSecureInstance url hasPassword
]

diff:
@@ -6,20 +6,22 @@ Class {
{ #category : #helpers }
PhLJenkins2JobTest class >> newInstance [
- | job |
- job := PhLJenkins2Job
- newWithProperties: (STONJSON fromString: '{"_class":"hudson.matrix.MatrixBuild","url":"https://ci.inria.fr/pharo-contribution/job/A4BP/1304/","number":1304}').
- job parent: PhLJenkins2ServerTest newInstance.
- ^ job
+ ^ self newWithoutParent
+ parent: PhLJenkins2ServerTest newInstance;
+ yourself
+]
+
+{ #category : #helpers }
+PhLJenkins2JobTest class >> newSecureInstance [
+ ^ self newWithoutParent
+ parent: PhLJenkins2ServerTest newSecureInstance;
+ yourself
]
{ #category : #helpers }
-PhLJenkins2JobTest class >> newSecureJenkinsInstance [
- | job |
- job := PhLJenkins2Job
- newWithProperties: (STONJSON fromString: '{"_class":"hudson.matrix.MatrixBuild","url":"https://ci.inria.fr/pharo-contribution/job/A4BP/1304/","number":1304}').
- job parent: PhLJenkins2ServerTest newSecureJenkinsInstance.
- ^ job
+PhLJenkins2JobTest class >> newWithoutParent [
+ ^ PhLJenkins2Job newWithProperties: (STONJSON fromString:
+ '{"_class":"hudson.matrix.MatrixBuild","url":"https://ci.inria.fr/pharo-contribution/job/A4BP/1304/","number":1304}')
]
{ #category : #helpers }

diff:
@@ -6,18 +6,20 @@ Class {
{ #category : #'instance creation' }
PhLJenkins2RunTest class >> newInstance [
- | job |
- job := PhLJenkins2Run
- newWithProperties: (STONJSON fromString: '{"url":"https://ci.inria.fr/pharo-contribution/job/MaterialDesignLite/PHARO=61,VERSION=development/1140/","number":1140}').
- job parent: PhLJenkins2BuildTest newInstance.
- ^ job
+ ^ self newWithoutParent
+ parent: PhLJenkins2BuildTest newInstance;
+ yourself
]
{ #category : #'instance creation' }
-PhLJenkins2RunTest class >> newSecureJenkinsInstance [
- | job |
- job := PhLJenkins2Run
- newWithProperties: (STONJSON fromString: '{"url":"https://ci.inria.fr/pharo-contribution/job/MaterialDesignLite/PHARO=61,VERSION=development/1140/","number":1140}').
- job parent: PhLJenkins2BuildTest newSecureJenkinsInstance.
- ^ job
+PhLJenkins2RunTest class >> newSecureInstance [
+ ^ self newWithoutParent
+ parent: PhLJenkins2BuildTest newSecureInstance;
+ yourself
+]
+
+{ #category : #'instance creation' }
+PhLJenkins2RunTest class >> newWithoutParent [
+ ^ PhLJenkins2Run newWithProperties: (STONJSON fromString:
+ '{"url":"https://ci.inria.fr/pharo-contribution/job/MaterialDesignLite/PHARO=61,VERSION=development/1140/","number":1140}')
]

diff:
@@ -10,9 +10,9 @@ PhLJenkins2ServerTest class >> newInstance [
]
{ #category : #'instance creation' }
-PhLJenkins2ServerTest class >> newSecureJenkinsInstance [
+PhLJenkins2ServerTest class >> newSecureInstance [
^ self newInstance
- username: 'Christophe';
+ username: 'BadetitouTheUnicorn';
token: 'dkewjdcnriuwefjncreiuhf';
yourself
]
@@ -39,8 +39,8 @@ PhLJenkins2ServerTest >> newInstance [
]
{ #category : #'instance creation' }
-PhLJenkins2ServerTest >> newSecureJenkinsInstance [
- ^ self class newSecureJenkinsInstance
+PhLJenkins2ServerTest >> newSecureInstance [
+ ^ self class newSecureInstance
]
{ #category : #responses }

license: MIT License

repo: pharo-project/pharo-launcher

original_message: Factorize code


message: Rename token into password

diff:
@@ -113,6 +113,11 @@ PhLJenkins2Entity >> parent: aPhLEntity [
parent := aPhLEntity
]
+{ #category : #accessing }
+PhLJenkins2Entity >> password [
+ ^ parent password
+]
+
{ #category : #accessing }
PhLJenkins2Entity >> properties [
^ properties
@@ -144,11 +149,6 @@ PhLJenkins2Entity >> shouldComputeChildrenLazily [
^ true
]
-{ #category : #accessing }
-PhLJenkins2Entity >> token [
- ^ parent token
-]
-
{ #category : #accessing }
PhLJenkins2Entity >> url [
"We get the URL from the json sent by Jenkins. In case of a secure Jenkins, we need to set the username and token to the URL we get."
@@ -156,7 +156,7 @@ PhLJenkins2Entity >> url [
| url |
url := (properties at: 'url') asUrl.
self username ifNotNil: [ :username | url username: username ].
- self token ifNotNil: [ :token | url password: token ].
+ self password ifNotNil: [ :token | url password: token ].
^ url
]

diff:
@@ -20,10 +20,10 @@ PhLJenkins2Server class >> name: aString url: anUrl [
]
{ #category : #'instance creation' }
-PhLJenkins2Server class >> name: aString url: anUrl username: anotherString token: yetAnotherString [
+PhLJenkins2Server class >> name: aString url: anUrl username: anotherString password: yetAnotherString [
^ (self name: aString url: anUrl)
username: anotherString;
- token: yetAnotherString;
+ password: yetAnotherString;
yourself
]
@@ -37,6 +37,16 @@ PhLJenkins2Server >> name [
^ name
]
+{ #category : #accessing }
+PhLJenkins2Server >> password [
+ ^ url password
+]
+
+{ #category : #accessing }
+PhLJenkins2Server >> password: aString [
+ url password: aString
+]
+
{ #category : #initialization }
PhLJenkins2Server >> setName: aString url: aZnUrl [
name := aString.
@@ -48,16 +58,6 @@ PhLJenkins2Server >> templatesAndGroups [
^ self jobs
]
-{ #category : #accessing }
-PhLJenkins2Server >> token [
- ^ url password
-]
-
-{ #category : #accessing }
-PhLJenkins2Server >> token: aString [
- url password: aString
-]
-
{ #category : #accessing }
PhLJenkins2Server >> url [
^ url

diff:
@@ -15,7 +15,7 @@ Class {
'templates',
'expanded',
'username',
- 'token'
+ 'password'
],
#category : #'PharoLauncher-Core-Model'
}
@@ -276,7 +276,7 @@ PhLTemplateSource >> asBasicTemplateGroup [
url: url asZnUrl
filterPattern: pattern ].
type == self class jenkinsServerType
- ifTrue: [ ^ PhLJenkins2Server name: name url: url asZnUrl username: username token: token ].
+ ifTrue: [ ^ PhLJenkins2Server name: name url: url asZnUrl username: username password: password ].
type == self class urlGroupType
ifTrue: [ ^ PhLFixedURLsTemplateGroup new
setName: name Templates: OrderedCollection new;
@@ -335,6 +335,16 @@ PhLTemplateSource >> name: aString [
name := aString
]
+{ #category : #accessing }
+PhLTemplateSource >> password [
+ ^ password
+]
+
+{ #category : #accessing }
+PhLTemplateSource >> password: anObject [
+ password := anObject
+]
+
{ #category : #printing }
PhLTemplateSource >> printOn: aStream [
super printOn: aStream.
@@ -359,16 +369,6 @@ PhLTemplateSource >> templatesDo: aBlockClosure [
templates ifNotNil: [ templates do: aBlockClosure ]
]
-{ #category : #accessing }
-PhLTemplateSource >> token [
- ^ token
-]
-
-{ #category : #accessing }
-PhLTemplateSource >> token: anObject [
- token := anObject
-]
-
{ #category : #accessing }
PhLTemplateSource >> type [
^ type

original_message: Rename token into password


message:
After the support for private jenkins here we add the support for privates urls and http listing.
Fixes

diff:
@@ -11,7 +11,7 @@ Class {
#classVars : [
'RegexCache'
],
- #category : 'PharoLauncher-Core-Model'
+ #category : #'PharoLauncher-Core-Model'
}
{ #category : #defaults }
@@ -34,6 +34,22 @@ PhLHTTPListingTemplateGroup class >> name: aString url: anUrl filterPattern: aPa
yourself
]
+{ #category : #'instance creation' }
+PhLHTTPListingTemplateGroup class >> name: aString url: anUrl filterPattern: aPatternString username: anotherString password: yetAnotherString [
+ ^ (self name: aString url: anUrl filterPattern: aPatternString)
+ username: anotherString;
+ password: yetAnotherString;
+ yourself
+]
+
+{ #category : #'instance creation' }
+PhLHTTPListingTemplateGroup class >> name: aString url: anUrl username: anotherString password: yetAnotherString [
+ ^ (self name: aString url: anUrl)
+ username: anotherString;
+ password: yetAnotherString;
+ yourself
+]
+
{ #category : #accessing }
PhLHTTPListingTemplateGroup class >> regexCache [
"Cache the regex per version so that we don't recompute it all the time"
@@ -63,6 +79,16 @@ PhLHTTPListingTemplateGroup >> name [
^ name
]
+{ #category : #accessing }
+PhLHTTPListingTemplateGroup >> password [
+ ^ url password
+]
+
+{ #category : #accessing }
+PhLHTTPListingTemplateGroup >> password: aString [
+ ^ url password: aString
+]
+
{ #category : #accessing }
PhLHTTPListingTemplateGroup >> regex [
^ self class regexCache at: self name asSymbol
@@ -98,3 +124,13 @@ PhLHTTPListingTemplateGroup >> templatesAndGroups [
^ templates
]
+
+{ #category : #accessing }
+PhLHTTPListingTemplateGroup >> username [
+ ^ url username
+]
+
+{ #category : #accessing }
+PhLHTTPListingTemplateGroup >> username: aString [
+ url username: aString
+]

diff:
@@ -10,7 +10,7 @@ Class {
#category : #'PharoLauncher-Core-Model'
}
-{ #category : #'as yet unclassified' }
+{ #category : #example }
PhLRemoteTemplate class >> example [
^ self name: 'Pharo Mooc' url: 'https://mooc.pharo.org/image/PharoWeb.zip'
]
@@ -22,6 +22,14 @@ PhLRemoteTemplate class >> name: aString url: anUrl [
yourself
]
+{ #category : #'instance creation' }
+PhLRemoteTemplate class >> name: aString url: anUrl username: anotherString password: yetAnotherString [
+ ^ (self name: aString url: anUrl)
+ username: anotherString;
+ password: yetAnotherString;
+ yourself
+]
+
{ #category : #comparing }
PhLRemoteTemplate >> = anObject [
self == anObject ifTrue: [ ^ true ].
@@ -35,6 +43,16 @@ PhLRemoteTemplate >> hash [
^ name hash bitXor: url hash
]
+{ #category : #accessing }
+PhLRemoteTemplate >> password [
+ ^ url password
+]
+
+{ #category : #accessing }
+PhLRemoteTemplate >> password: aString [
+ url password: aString
+]
+
{ #category : #'initialize-release' }
PhLRemoteTemplate >> setName: aName url: anUrl [
name := aName.
@@ -55,6 +73,16 @@ PhLRemoteTemplate >> url [
^ url
]
+{ #category : #accessing }
+PhLRemoteTemplate >> username [
+ ^ url username
+]
+
+{ #category : #accessing }
+PhLRemoteTemplate >> username: aString [
+ url username: aString
+]
+
{ #category : #accessing }
PhLRemoteTemplate >> zipArchive [
"The local template group takes care of cashing downloaded templates."

diff:
@@ -274,7 +274,7 @@ PhLTemplateSource >> asBasicTemplateGroup [
^ PhLHTTPListingTemplateGroup
name: name
url: url asZnUrl
- filterPattern: pattern ].
+ filterPattern: pattern username: username password: password].
type == self class jenkinsServerType
ifTrue: [ ^ PhLJenkins2Server name: name url: url asZnUrl username: username password: password ].
type == self class urlGroupType
@@ -289,12 +289,13 @@ PhLTemplateSource >> asBasicTemplateGroup [
{ #category : #converting }
PhLTemplateSource >> asTemplate [
- type == self class urlType
- ifTrue: [ ^ PhLRemoteTemplate
+ type == self class urlType ifTrue: [
+ ^ PhLRemoteTemplate
name: name
- url: url asUrl ].
+ url: url asUrl
+ username: username
+ password: password ].
self error: 'Template type not supported!'
-
]
{ #category : #converting }

original_message:
After the support for private jenkins (#415), here we add the support for privates urls and http listing.

Fixes #331


message: Open playground instead of workspace.

diff:
@@ -49,7 +49,7 @@ PhLDeploymentScript class >> closeWindowsAndOpenDevelopmentEnvironment [
PanelMorph allInstancesDo: [ :pm | pm delete ].
self closeAllWindows.
TaskbarMorph reset.
- Workspace open contents: 'PharoLauncherApplication open.'.
+ Smalltalk tools workspace openContents: 'PharoLauncherApplication open.'.
"PanelMorph comes from use of #openWorldWithSpec"
]

original_message: Open playground instead of workspace.


message: Do not take extension into account for image names + rename test case to match real class to test.

diff:
@@ -181,7 +181,7 @@ PhLDirectoryBasedImageRepository >> imageNames [
| imageNames |
imageNames := OrderedCollection new.
- self withImagesFilesDo: [ :imageFile | imageNames add: imageFile basename ].
+ self withImagesFilesDo: [ :imageFile | imageNames add: imageFile basenameWithoutExtension ].
^ imageNames
]

change_type: RENAME

diff:
A PhLDirectoryBasedImageGroupTest is a test class for testing the behavior of PhLDirectoryBasedImageGroup
"
Class {
- #name : #PhLDirectoryBasedImageGroupTest,
+ #name : #PhLDirectoryBasedImageRepositoryTest,
#superclass : #ClassTestCase,
- #category : 'PharoLauncher-Tests-Core'
+ #category : #'PharoLauncher-Tests-Core'
}
{ #category : #coverage }
-PhLDirectoryBasedImageGroupTest >> classToBeTested [
+PhLDirectoryBasedImageRepositoryTest >> classToBeTested [
^ PhLDirectoryBasedImageRepository
]
{ #category : #'instance-creation' }
-PhLDirectoryBasedImageGroupTest >> emptyGroup [
+PhLDirectoryBasedImageRepositoryTest >> emptyGroup [
^ self classToBeTested forDirectory: FileSystem memory workingDirectory
]
{ #category : #'instance-creation' }
-PhLDirectoryBasedImageGroupTest >> newGroupWithAnImage [
+PhLDirectoryBasedImageRepositoryTest >> newGroupWithAnImage [
| group baseDirectory |
group := self emptyGroup.
baseDirectory := group baseDirectory.
@@ -29,7 +29,7 @@ PhLDirectoryBasedImageGroupTest >> newGroupWithAnImage [
]
{ #category : #'tests-action' }
-PhLDirectoryBasedImageGroupTest >> testCopyImageNamedTo [
+PhLDirectoryBasedImageRepositoryTest >> testCopyImageNamedTo [
| group |
group := self newGroupWithAnImage.
self assert: group imageNames asSet equals: #('test') asSet.
@@ -39,7 +39,7 @@ PhLDirectoryBasedImageGroupTest >> testCopyImageNamedTo [
]
{ #category : #'tests-action' }
-PhLDirectoryBasedImageGroupTest >> testDeleteImageNamed [
+PhLDirectoryBasedImageRepositoryTest >> testDeleteImageNamed [
| group |
group := self newGroupWithAnImage.
self assert: group imageNames asSet equals: #('test') asSet.
@@ -48,7 +48,7 @@ PhLDirectoryBasedImageGroupTest >> testDeleteImageNamed [
]
{ #category : #'instance-creation' }
-PhLDirectoryBasedImageGroupTest >> testDirectoryForImageNamed [
+PhLDirectoryBasedImageRepositoryTest >> testDirectoryForImageNamed [
| group |
group := self emptyGroup.
self assert: group images isEmpty.
@@ -56,7 +56,7 @@ PhLDirectoryBasedImageGroupTest >> testDirectoryForImageNamed [
]
{ #category : #'instance-creation' }
-PhLDirectoryBasedImageGroupTest >> testEmptyByDefault [
+PhLDirectoryBasedImageRepositoryTest >> testEmptyByDefault [
| group |
group := self emptyGroup.
self assert: group images isEmpty.
@@ -64,7 +64,7 @@ PhLDirectoryBasedImageGroupTest >> testEmptyByDefault [
]
{ #category : #'instance-creation' }
-PhLDirectoryBasedImageGroupTest >> testIgnoreNonConformDirectories [
+PhLDirectoryBasedImageRepositoryTest >> testIgnoreNonConformDirectories [
| group baseDirectory |
group := self emptyGroup.
baseDirectory := group baseDirectory.
@@ -83,14 +83,14 @@ PhLDirectoryBasedImageGroupTest >> testIgnoreNonConformDirectories [
]
{ #category : #'tests-action' }
-PhLDirectoryBasedImageGroupTest >> testImageNames [
+PhLDirectoryBasedImageRepositoryTest >> testImageNames [
| group |
group := self newGroupWithAnImage.
self assert: group imageNames asSet equals: #('test') asSet.
]
{ #category : #'tests-action' }
-PhLDirectoryBasedImageGroupTest >> testImages [
+PhLDirectoryBasedImageRepositoryTest >> testImages [
| group |
group := self newGroupWithAnImage.
self assert: group images size equals: 1.
@@ -98,7 +98,7 @@ PhLDirectoryBasedImageGroupTest >> testImages [
]
{ #category : #'tests-action' }
-PhLDirectoryBasedImageGroupTest >> testMakeUniqueImageName [
+PhLDirectoryBasedImageRepositoryTest >> testMakeUniqueImageName [
{
" { basename . expectedResult . {existingNames} } "
@@ -126,7 +126,7 @@ PhLDirectoryBasedImageGroupTest >> testMakeUniqueImageName [
]
{ #category : #'tests-action' }
-PhLDirectoryBasedImageGroupTest >> testRenameImageNamedTo [
+PhLDirectoryBasedImageRepositoryTest >> testRenameImageNamedTo [
| group |
group := self newGroupWithAnImage.
self assert: group imageNames asSet equals: #('test') asSet.


message:
Speed up opening of new image presenter.
The new image presenter is slow because it change a lot an image presenter in an unwanted way because the content does not really changes.
This commit change that to update the image only when needed.

diff:
@@ -7,6 +7,7 @@ Class {
#traits : 'TPhLInteractionTrait',
#classTraits : 'TPhLInteractionTrait classTrait',
#instVars : [
+ 'isNameOk',
'imageName',
'createButton',
'initScriptText',
@@ -48,6 +49,16 @@ PhLImageCreationPresenter class >> example [
model: {PhLRemoteTemplate example}) openWithSpec
]
+{ #category : #initialization }
+PhLImageCreationPresenter >> checkNewName: name [
+ | isValid |
+ isValid := name isEmpty or: [ self application imageRepository hasImageNamed: name ].
+
+ isNameOk = isValid ifTrue: [ ^ self ].
+
+ (isNameOk := isValid) ifTrue: [ self showNameError ] ifFalse: [ self showNameOk ]
+]
+
{ #category : #closing }
PhLImageCreationPresenter >> close [
self window ifNotNil: [ :window | window close ]
@@ -55,10 +66,7 @@ PhLImageCreationPresenter >> close [
{ #category : #initialization }
PhLImageCreationPresenter >> connectPresenters [
- imageName whenTextChangedDo: [ :name |
- (name isEmpty or: [ self application imageRepository hasImageNamed: name])
- ifTrue: [ self showNameError ]
- ifFalse: [ self showNameOk ] ]
+ imageName whenTextChangedDo: [ :name | self checkNewName: name ]
]
{ #category : #accessing }


message: Update PhLDirectoryBasedImageRepository.class.st

diff:
@@ -323,7 +323,6 @@ PhLDirectoryBasedImageRepository >> withImagesFilesCollect: aBlock [
imageName := aDirectory basename.
imageFiles := aDirectory filesMatching: imageName , '.image'.
(imageFiles size = 1 and: [ (aDirectory filesMatching: imageName , '.changes') size = 1 ])
- ifTrue: [ collection add: (aBlock value: imageFiles first) ]
- ifFalse: [ nil ].
+ ifTrue: [ collection add: (aBlock value: imageFiles first) ].
collection ]
]


message: Entirely remove the execution of command to ensure execution rights when opening the vm manager.

diff:
@@ -110,6 +110,20 @@ PhLVirtualMachine >> downloadUrl [
format: { self pharoVersion . self archPath . self manager downloadPathOSTypeSegment . self flavour . self blessing }
]
+{ #category : #updating }
+PhLVirtualMachine >> ensureExecutionRights [
+ "Unzipping with Pharo does not preserve unix rights and so, the pahro VM executable does not have the execution permission.
+ We have to set it explicitely on Unix and OS X."
+
+ Smalltalk os isWindows ifTrue: [ ^ self ].
+
+ PhLProcessWrapper new
+ shellCommand;
+ addArguments: 'chmod u+x';
+ in: [ :command | self executablesToEnsure do: [ :file | command addArgument: file fullName surroundedByDoubleQuotes ] ];
+ runAndWaitTimeOut: 5 seconds
+]
+
{ #category : #setting }
PhLVirtualMachine >> executable: aPathOrfileReference [
executableRef := aPathOrfileReference asFileReference
@@ -288,7 +302,7 @@ PhLVirtualMachine >> updateFromUrl [
self manager class fetch: self downloadUrl to: self vmStore / (self id , '.zip').
self initializeExecutableRefFrom: self vmStore / self id.
- self manager ensureExecutionRightsOf: {self}
+ self ensureExecutionRights
]
{ #category : #accessing }

diff:
@@ -294,23 +294,6 @@ PhLVirtualMachineManager >> downloadPathOSTypeSegment [
]
-{ #category : #querying }
-PhLVirtualMachineManager >> ensureExecutionRightsOf: aCollectionOfVms [
- "Unzipping with Pharo does not preserve unix rights and so, the pahro VM executable does not have the execution permission.
- We have to set it explicitely on Unix and OS X."
-
- | executables command |
- Smalltalk os isWindows ifTrue: [ ^ self ].
-
- executables := aCollectionOfVms flatCollect: #executablesToEnsure.
- command := PhLProcessWrapper new
- shellCommand;
- addArguments: 'chmod u+x';
- yourself.
- executables do: [ :file | command addArgument: file fullName surroundedByDoubleQuotes ].
- command runAndWaitTimeOut: 5 seconds
-]
-
{ #category : #private }
PhLVirtualMachineManager >> fetchCompatibleVm [
[ self class
@@ -545,12 +528,10 @@ PhLVirtualMachineManager >> virtualMachine [
{ #category : #querying }
PhLVirtualMachineManager >> virtualMachines [
- | vmsInVmStore defaultVms allVms |
+ | vmsInVmStore defaultVms |
defaultVms := self defaultVirtualMachines.
vmsInVmStore := self availableVirtualMachines values reject: [ :vm | defaultVms anySatisfy: [ :diskVM | diskVM id = vm id ] ].
- allVms := vmsInVmStore , defaultVms.
- self ensureExecutionRightsOf: allVms.
- ^ allVms
+ ^ vmsInVmStore , defaultVms
]
{ #category : #querying }


diff:
@@ -12,6 +12,7 @@ Class {
#traits : 'TPhLInteractionTrait',
#classTraits : 'TPhLInteractionTrait classTrait',
#instVars : [
+ 'reservedImagesNamesCache',
'isNameOk',
'imageName',
'createButton',
@@ -61,7 +62,7 @@ PhLImageCreationPresenter >> checkNewName: name [
I use a variable to know the state during the last validation."
| isValid |
- isValid := name isEmpty or: [ self application imageRepository hasImageNamed: name ].
+ isValid := name isEmpty or: [ reservedImagesNamesCache includes: name asLowercase ].
"Image already in the right state. We skip."
isNameOk = isValid ifTrue: [ ^ self ].
@@ -116,6 +117,12 @@ PhLImageCreationPresenter >> initializationScripts [
select: [ :file | file extension = 'st' ]
]
+{ #category : #initialization }
+PhLImageCreationPresenter >> initialize [
+ super initialize.
+ reservedImagesNamesCache := self application imageRepository imageNames collect: #asLowercase
+]
+
{ #category : #initialization }
PhLImageCreationPresenter >> initializePresenters [
imageName := self newTextInput

original_message:
Do not scan the disk at each keystrock.

Fixes #412


diff:
@@ -118,7 +118,7 @@ PhLLaunchConfigurationPresenter >> configurationName [
{ #category : #initialization }
PhLLaunchConfigurationPresenter >> connectPresenters [
- configurationTable selectIndex: 1.
+ configurationTable selectIndex: 1
]
{ #category : #accessing }
@@ -139,8 +139,7 @@ PhLLaunchConfigurationPresenter >> initializePresenters [
items: self image launchConfigurations;
display: [ :each | each name ];
whenSelectionChangedDo: [ :selection |
- selectedConfiguration := selection selectedItem
- ifNil: [ PhLNullLaunchConfiguration new ].
+ selectedConfiguration := selection selectedItem ifNil: [ PhLNullLaunchConfiguration new ].
self selectedConfigurationChanged ];
yourself.
selectedConfigurationNameField := self newTextInput
@@ -149,23 +148,27 @@ PhLLaunchConfigurationPresenter >> initializePresenters [
vmList := self newDropList
sortingBlock: [ :a :b | a model id > b model id ];
display: [ :each | each id ];
- whenSelectedItemChangedDo:
- [ :vm |
- vm ifNotNil:
- [ vm isHeadless
- ifTrue: [ self addInteractiveImageArgument ] ] ];
+ whenSelectedItemChangedDo: [ :vm | vm ifNotNil: [ vm isHeadless ifTrue: [ self addInteractiveImageArgument ] ] ];
yourself.
"Run in a separate process to do not block UI. Can take some seconds."
[ self initializeVmListContent ] fork.
- vmArgumentList := (self instantiate: SpEditableListPresenter)
+ (vmArgumentList := self instantiate: SpEditableListPresenter)
addItemBlock: [ self application newRequest
title: 'New VM argument?';
request ];
+ removeItemBlock: [ :item |
+ item
+ ifNotNil: [ vmArgumentList items remove: item.
+ vmArgumentList refresh ] ];
yourself.
- imageArgumentList := (self instantiate: SpEditableListPresenter)
+ (imageArgumentList := self instantiate: SpEditableListPresenter)
addItemBlock: [ self application newRequest
title: 'New image argument?';
request ];
+ removeItemBlock: [ :item |
+ item
+ ifNotNil: [ imageArgumentList items remove: item.
+ imageArgumentList refresh ] ];
yourself.
applyChangesButton := self newButton
label: 'Apply';
@@ -223,6 +226,16 @@ PhLLaunchConfigurationPresenter >> saveSelectedConfiguration [
self application launchConfigurationEdited: config.
]
+{ #category : #action }
+PhLLaunchConfigurationPresenter >> selectImageArgumentAt: anIndex [
+ imageArgumentList selectIndex: anIndex
+]
+
+{ #category : #action }
+PhLLaunchConfigurationPresenter >> selectVMArgumentAt: anIndex [
+ vmArgumentList selectIndex: anIndex
+]
+
{ #category : #accessing }
PhLLaunchConfigurationPresenter >> selectedConfiguration [
^ selectedConfiguration
@@ -230,11 +243,12 @@ PhLLaunchConfigurationPresenter >> selectedConfiguration [
{ #category : #updating }
PhLLaunchConfigurationPresenter >> selectedConfigurationChanged [
-
selectedConfigurationNameField text: self selectedConfiguration name.
self setVmFromConfiguration.
vmArgumentList items: self selectedConfiguration vmArguments.
- imageArgumentList items: self selectedConfiguration imageArguments
+ imageArgumentList items: self selectedConfiguration imageArguments.
+ self selectImageArgumentAt: 1.
+ self selectVMArgumentAt: 1
]
{ #category : #initialization }

diff:
@@ -15,6 +15,16 @@ PhLLaunchConfigurationPresenter >> clickDeleteConfigurationButton [
configurationTable removeButton click
]
+{ #category : #'*PharoLauncher-Tests-SpecUI' }
+PhLLaunchConfigurationPresenter >> clickDeleteImageArgumentButton [
+ imageArgumentList removeButton click
+]
+
+{ #category : #'*PharoLauncher-Tests-SpecUI' }
+PhLLaunchConfigurationPresenter >> clickDeleteVMArgumentButton [
+ vmArgumentList removeButton click
+]
+
{ #category : #'*PharoLauncher-Tests-SpecUI' }
PhLLaunchConfigurationPresenter >> selectConfiguration: aPhLLaunchConfiguration [
configurationTable selectItem: aPhLLaunchConfiguration

diff:
@@ -172,6 +172,48 @@ PhLLaunchConfigurationPresenterTest >> testImageLaunchConfigurationsUpdatedWhenC
equals: PhLLaunchConfiguration defaultName.
]
+{ #category : #tests }
+PhLLaunchConfigurationPresenterTest >> testRemoveImageArgument [
+ presenter imageArguments add: '--interactive'.
+ self assert: presenter imageArguments size equals: 1.
+
+ presenter selectImageArgumentAt: 1.
+ presenter clickDeleteImageArgumentButton.
+
+ self assertEmpty: presenter imageArguments
+]
+
+{ #category : #tests }
+PhLLaunchConfigurationPresenterTest >> testRemoveImageArgumentWithoutSelectionDoesNotThrowError [
+ presenter imageArguments add: '--interactive'.
+
+ "Unselect"
+ presenter selectImageArgumentAt: 0.
+
+ self shouldnt: [ presenter clickDeleteImageArgumentButton ] raise: NotFound
+]
+
+{ #category : #tests }
+PhLLaunchConfigurationPresenterTest >> testRemoveVMArgument [
+ presenter vmArguments add: '--interactive'.
+ self assert: presenter vmArguments size equals: 1.
+
+ presenter selectVMArgumentAt: 1.
+ presenter clickDeleteVMArgumentButton.
+
+ self assertEmpty: presenter vmArguments
+]
+
+{ #category : #tests }
+PhLLaunchConfigurationPresenterTest >> testRemoveVMArgumentWithoutSelectionDoesNotThrowError [
+ presenter vmArguments add: '--interactive'.
+
+ "Unselect"
+ presenter selectVMArgumentAt: 0.
+
+ self shouldnt: [ presenter clickDeleteVMArgumentButton ] raise: NotFound
+]
+
{ #category : #tests }
PhLLaunchConfigurationPresenterTest >> testSelectingAConfigurationAndClosingWindowSelectsItInImagesPresenterToolbar [
| config imagesPresenter window |

original_message:
Fix deletion of images and vm arguments when none is selected

This also select the first image and vm arguments when we select a configuration.

Fixes #428


message: This alloms one to write .st files with startup actions to customize the launcher at launch.

diff:
@@ -15,9 +15,12 @@ PhLSettingBrowser class >> initialize [
{ #category : #'system startup' }
PhLSettingBrowser class >> launcherStartUp [
- PharoLauncherApplication isDeployed
- ifFalse: [ ^ self ].
- self preferencesFile ifNotNil: [ self new treeHolder updateSettingNodes ]
+ PharoLauncherApplication isDeployed ifFalse: [ ^ self ].
+
+ self preferencesFile ifNotNil: [ self new treeHolder updateSettingNodes ].
+
+ "Allow to have manual settings in the preferences foldor of Pharo Launcher."
+ StartupPreferencesLoader default load: (self preferencesFolder filesMatching: '*.st')
]
{ #category : #'system startup' }


message:
Speed up ston reading.
Building the list of images tool 2.5sec before in my case. It now takes 200ms.

diff:
@@ -26,6 +26,9 @@ Class {
'initializationScript',
'shouldRunInitializationScript'
],
+ #classInstVars : [
+ 'reader'
+ ],
#category : #'PharoLauncher-Core-Model'
}
@@ -59,19 +62,24 @@ PhLImage class >> example32 [
{ #category : #'instance creation' }
PhLImage class >> imageFromMetadata: imageFileReference [
"Will recreate the image object from its STON serialized version if possible"
- (imageFileReference parent / self metadataFileName)
- readStreamDo: [ :stream | | object |
- object := STON fromStream: stream.
- (object isKindOf: PhLImage)
- ifTrue: [ ^ object ].
+
+ imageFileReference parent / self metadataFileName
+ readStreamDo: [ :stream |
+ | object |
+ object := (self stonReader on: stream) next.
+ (object isKindOf: PhLImage) ifTrue: [ ^ object ].
(object isKindOf: Dictionary)
ifTrue: [ "old metadata file format"
^ self new
privOriginTemplate: (object at: #template);
yourself ].
PhLError signal: 'Unrecognized metadata format' ]
- ifAbsent: [ ^ self new ].
+ ifAbsent: [ ^ self new ]
+]
+{ #category : #'class initialization' }
+PhLImage class >> initialize [
+ SessionManager default registerUserClassNamed: self name
]
{ #category : #'instance creation' }
@@ -86,11 +94,23 @@ PhLImage class >> metadataFileName [
^ 'meta-inf.ston'
]
+{ #category : #'system startup' }
+PhLImage class >> startUp: isImageStarting [
+ isImageStarting ifTrue: [ reader := nil ]
+]
+
{ #category : #serialization }
PhLImage class >> stonAllInstVarNames [
^ super stonAllInstVarNames reject: [ :varName | varName = #file ]
]
+{ #category : #accessing }
+PhLImage class >> stonReader [
+ "The ston reader is building caches when reading a file. Since we read *a lot* of files, we cache a reader with all the built caches."
+
+ ^ reader ifNil: [ reader := STONReader new ]
+]
+
{ #category : #accessing }
PhLImage class >> versionFileName [
^ 'pharo.version'


message: Add bug, enhancement and new feature templates

change_type: ADD

diff:
+---
+name: Bug report
+about: Create a report to help us improve the latest dev version of the Pharo Launcher
+title: ''
+labels: Bug
+assignees: ''
+
+---
+
+**Describe the bug**
+A clear and concise description of what the bug is.
+
+**To Reproduce**
+Steps to reproduce the behavior:
+1. Go to '...'
+2. Click on '....'
+3. Scroll down to '....'
+4. See error
+
+**Expected behavior**
+A clear and concise description of what you expected to happen.
+
+**Screenshots**
+If applicable, add screenshots to help explain your problem.
+
+**Version information:**
+ - OS: [e.g. iOS]
+ - Version: [e.g. 1.6.1]
+
+**Additional context**
+Add any other context about the problem here.

diff:
+---
+name: Enhancement request
+about: Create a report to help us improve
+title: Enhance X with Y
+labels: Enhancement
+assignees: ''
+
+---
+
+**Describe the request**
+A clear and concise description of what is missing and how it could be enhanced.
+
+**Expected behavior**
+A clear and concise description of what you expected to happen.
+
+**Screenshots**
+If applicable, add screenshots to help explain your problem.
+
+**Version information:**
+ - OS: [e.g. iOS]
+ - Version: [e.g. 1.6.1]
+
+**Additional context**
+Add any other context about the problem here.

diff:
+---
+name: Feature request
+about: Suggest an idea to discuss
+title: "[Feature Request]"
+labels: New Feature
+assignees: ''
+
+---
+
+**Is your feature request related to a problem? Please describe.**
+A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
+
+**Describe the solution you'd like**
+A clear and concise description of what you want to happen.
+
+**Describe alternatives you've considered**
+A clear and concise description of any alternative solutions or features you've considered.
+
+**Additional context**
+Add any other context or screenshots about the feature request here.


message: Cache jenkins entities children to speedup the new image UI for jenkins templates.

diff:
@@ -6,11 +6,17 @@ Class {
#superclass : #PhLAbstractTemplateGroup,
#instVars : [
'properties',
- 'parent'
+ 'parent',
+ 'childrenCache'
],
#category : #'PharoLauncher-Core-Model'
}
+{ #category : #testing }
+PhLJenkins2Entity class >> isAbstract [
+ ^ self = PhLJenkins2Entity
+]
+
{ #category : #protected }
PhLJenkins2Entity class >> jsonFields [
^ self subclassResponsibility
@@ -33,7 +39,15 @@ PhLJenkins2Entity class >> newWithProperties: json [
yourself
]
-{ #category : #'as yet unclassified' }
+{ #category : #accessing }
+PhLJenkins2Entity >> children [
+ "Since we need to request the network to get children, it is better to cache them.
+ In the current use of the launcher, the jenkins entities are recreated each time we want to create a new image. Thus, we can cache the children, the probability of the jenkins been updated meanwhile."
+
+ ^ childrenCache ifNil: [ childrenCache := super children ]
+]
+
+{ #category : #testing }
PhLJenkins2Entity >> hasChildren [
^ true
]


message: Remove unread temporary

diff:
@@ -231,10 +231,9 @@ PhLVirtualMachineManager >> compatibleVm [
^ self availableVirtualMachinesByImageFormat
at: self imageFormatNumber asString
- ifAbsent: [ | vmPath |
- self fetchCompatibleVm.
+ ifAbsent: [ self fetchCompatibleVm.
self fetchSourcesFileForCompatibleVm.
- vmPath := self availableVirtualMachinesByImageFormat at: self imageFormatNumber asString ]
+ self availableVirtualMachinesByImageFormat at: self imageFormatNumber asString ]
]
{ #category : #private }

original_message: Remove unread temporary


message: Remove methods with equivalent in the superclass.

diff:
@@ -58,11 +58,6 @@ PhLAbstractTemplate >> hasChildren [
^ false
]
-{ #category : #testing }
-PhLAbstractTemplate >> isLocalTemplate [
- ^ false
-]
-
{ #category : #testing }
PhLAbstractTemplate >> isTemplate [
^ true

diff:
@@ -47,11 +47,6 @@ PhLJenkins2Entity >> children [
^ childrenCache ifNil: [ childrenCache := super children ]
]
-{ #category : #testing }
-PhLJenkins2Entity >> hasChildren [
- ^ true
-]
-
{ #category : #accessing }
PhLJenkins2Entity >> icon [
"(Base64MimeConverter mimeEncode: 'jenkins.png' asFileReference binaryReadStream) contents"

diff:
@@ -27,16 +27,6 @@ PhLJenkins2ServerTest >> defaultJobUrlString [
^ 'http://server/segment'
]
-{ #category : #'instance creation' }
-PhLJenkins2ServerTest >> newInstance [
- ^ self class newInstance
-]
-
-{ #category : #'instance creation' }
-PhLJenkins2ServerTest >> newSecureInstance [
- ^ self class newSecureInstance
-]
-
{ #category : #responses }
PhLJenkins2ServerTest >> noJobsResponse [
^ '{"jobs" : []}'

diff:
@@ -11,11 +11,6 @@ Class {
#category : #'PharoLauncher-Tests-Functional'
}
-{ #category : #'as yet unclassified' }
-PhLVirtualMachineManagerFunctionalTest class >> availaibleVirtualMachines [
- Smalltalk vm imageVersionNumber
-]
-
{ #category : #support }
PhLVirtualMachineManagerFunctionalTest >> preSpurHeader [
^ self getImageHeader: 'http://files.pharo.org/image/50-preSpur/latest.zip'


message: Improve some assertions to have better logs in the CI in case of failure.

diff:
@@ -24,18 +24,14 @@ PhLCreateTemplateFromImageCommandTest >> testCanCreateATemplateAndRemoveImageWhe
selectImageAt: 1;
requestAnswer: 'TestTemplate'.
- self assert: presenter templateRepository localTemplates isEmpty.
+ self assertEmpty: presenter templateRepository localTemplates.
self assert: (presenter imageRepository hasImageNamed: 'TestImage').
command execute.
templates := presenter templateRepository localTemplateNames.
- self
- assert: templates size
- equals: 1.
- self
- assertCollection: templates
- hasSameElements: #('TestTemplate').
- self deny: (presenter imageRepository hasImageNamed: 'TestImage').
+ self assert: templates size equals: 1.
+ self assertCollection: templates hasSameElements: #('TestTemplate').
+ self deny: (presenter imageRepository hasImageNamed: 'TestImage')
]
{ #category : #tests }
@@ -47,14 +43,10 @@ PhLCreateTemplateFromImageCommandTest >> testCanCreateATemplateWhenSingleImageSe
selectImageAt: 1;
requestAnswer: 'TestTemplate'.
- self assert: presenter templateRepository localTemplates isEmpty.
+ self assertEmpty: presenter templateRepository localTemplates.
command execute.
templates := presenter templateRepository localTemplateNames.
- self
- assert: templates size
- equals: 1.
- self
- assertCollection: templates
- hasSameElements: #('TestTemplate').
+ self assert: templates size equals: 1.
+ self assertCollection: templates hasSameElements: #('TestTemplate')
]

diff:
@@ -48,6 +48,6 @@ PhLDeleteImageCommandTest >> testImagesPresenterIsRefreshedWhenImageDeleted [
images := command imagesPresenter imageNames.
self
- assert: images isEmpty;
- assert: (presenter imageLabel beginsWith: 'No image selected').
+ assertEmpty: images;
+ assert: (presenter imageLabel beginsWith: 'No image selected')
]

diff:
@@ -34,11 +34,9 @@ PhLRemoveTemplateCommandTest >> testCanRemoveALocalTemplate [
command execute.
- self
- assertCollection: presenter templateNames
- hasSameElements: #().
+ self assertCollection: presenter templateNames hasSameElements: #().
- self assert: presenter templateRoots isEmpty.
+ self assertEmpty: presenter templateRoots
]
{ #category : #tests }

diff:
@@ -44,23 +44,23 @@ PhLDirectoryBasedImageRepositoryTest >> testDeleteImageNamed [
group := self newGroupWithAnImage.
self assert: group imageNames asSet equals: #('test') asSet.
group deleteImageNamed: 'test'.
- self assert: group imageNames isEmpty
+ self assertEmpty: group imageNames
]
{ #category : #'instance-creation' }
PhLDirectoryBasedImageRepositoryTest >> testDirectoryForImageNamed [
| group |
group := self emptyGroup.
- self assert: group images isEmpty.
- self assert: group imageNames isEmpty.
+ self assertEmpty: group images.
+ self assertEmpty: group imageNames
]
{ #category : #'instance-creation' }
PhLDirectoryBasedImageRepositoryTest >> testEmptyByDefault [
| group |
group := self emptyGroup.
- self assert: group images isEmpty.
- self assert: group imageNames isEmpty.
+ self assertEmpty: group images.
+ self assertEmpty: group imageNames
]
{ #category : #'instance-creation' }

diff:
@@ -24,8 +24,7 @@ PhLTemplateSourcesTest >> testAlmostIdenticalTemplateSourcesAreDifferent [
templatesSources2 := (PhLPharoTemplateSources withTemplateList: PhLPharoTemplateSources defaultSources) sources.
templatesSources2 second templates first name: 'changed'.
- self deny: templatesSources1 = templatesSources2
-
+ self deny: templatesSources1 equals: templatesSources2
]
{ #category : #tests }
@@ -57,31 +56,27 @@ PhLTemplateSourcesTest >> testGivenUserSourcesFileAbsentWhenAskingUserSourcesThe
sources := (PhLUserTemplateSources withFile: sourcesFile) sources.
- self assert: sources isEmpty
+ self assertEmpty: sources
]
{ #category : #tests }
PhLTemplateSourcesTest >> testGivenUserSourcesFileWithErrorsWhenAskingUserSourcesThenGetEmptyCollection [
| sources |
- sourcesFile
- writeStreamDo: [ :stream | stream nextPutAll: 'foobar' ].
+ sourcesFile writeStreamDo: [ :stream | stream nextPutAll: 'foobar' ].
sources := (PhLTemplateSources withFile: sourcesFile) sources.
- self assert: sources isEmpty
+ self assertEmpty: sources
]
{ #category : #tests }
PhLTemplateSourcesTest >> testGivenUserSourcesFileWithReferencesToUnknownVariablesWhenAskingUserSourcesThenGetEmptyCollection [
| sources |
- sourcesFile
- writeStreamDo: [ :stream | stream nextPutAll: '[PhLHTTPListingTemplateGroup{#nonexistingiv:''http://foo.org'',#name:''foo''}]' ].
+ sourcesFile writeStreamDo: [ :stream | stream nextPutAll: '[PhLHTTPListingTemplateGroup{#nonexistingiv:''http://foo.org'',#name:''foo''}]' ].
- self
- shouldnt:[ sources := (PhLTemplateSources withFile: sourcesFile) sources ]
- raise: InstanceVariableNotFound.
+ self shouldnt: [ sources := (PhLTemplateSources withFile: sourcesFile) sources ] raise: InstanceVariableNotFound.
- self assert: sources isEmpty
+ self assertEmpty: sources
]
{ #category : #tests }
@@ -99,26 +94,21 @@ PhLTemplateSourcesTest >> testIdenticalTemplateSourcesAreEquals [
{ #category : #tests }
PhLTemplateSourcesTest >> testNoUpdateAnnouncedWhenDownloadedSourcesIsSameAsSources [
| announcements sources |
-
sourcesFile writeStreamDo: [ :stream | stream nextPutAll: (STON toString: true) ].
announcements := OrderedCollection new.
ZnClientTest new
withServerDo: [ :server |
- server onRequestRespond: [ :request |
- ZnResponse ok: (ZnEntity text: (STON toString: true)) ].
+ server onRequestRespond: [ :request | ZnResponse ok: (ZnEntity text: (STON toString: true)) ].
sources := PhLPharoTemplateSources withFile: sourcesFile.
PhLPharoTemplateSources sourcesUrl: server localUrl.
- PhLPharoTemplateSources announcer weak
- when: PhLSourcesFileUpdateAvailable
- send: #add:
- to: announcements.
+ PhLPharoTemplateSources announcer weak when: PhLSourcesFileUpdateAvailable send: #add: to: announcements.
sources checkForUpdates.
- self assert: announcements isEmpty ].
+ self assertEmpty: announcements ]
]
{ #category : #tests }

diff:
@@ -93,7 +93,7 @@ PhLJenkins2BuildTest >> runUrlString [
PhLJenkins2BuildTest >> testBuildWithArtifacts [
| artifact |
self setUpResponse: self oneArtifactResponse.
- self assert: self emptyBuild runs isEmpty.
+ self assertEmpty: self emptyBuild runs.
self assert: self emptyBuild artifacts size equals: 1.
artifact := self emptyBuild artifacts first.
self assert: artifact relativePath equals: self artifactRelativePath.
@@ -104,7 +104,7 @@ PhLJenkins2BuildTest >> testBuildWithArtifacts [
PhLJenkins2BuildTest >> testBuildWithRuns [
| run |
self setUpResponse: self oneRunResponse.
- self assert: self emptyBuild artifacts isEmpty.
+ self assertEmpty: self emptyBuild artifacts.
self assert: self emptyBuild runs size equals: 1.
run := self emptyBuild runs first.
self assert: run number equals: self runNumber
@@ -113,8 +113,8 @@ PhLJenkins2BuildTest >> testBuildWithRuns [
{ #category : #tests }
PhLJenkins2BuildTest >> testEmptyBuild [
self setUpResponse: '{}'.
- self assert: self emptyBuild artifacts isEmpty.
- self assert:self emptyBuild runs isEmpty.
+ self assertEmpty: self emptyBuild artifacts.
+ self assertEmpty: self emptyBuild runs
]
{ #category : #tests }

diff:
@@ -108,7 +108,7 @@ PhLJenkins2JobTest >> pipelineResponse [
{ #category : #tests }
PhLJenkins2JobTest >> testJobWithNoSuccessfulBuild [
self setUpResponse: self noBuildsResponse.
- self assert: self newJobWithNoSuccessfulBuild builds isEmpty
+ self assertEmpty: self newJobWithNoSuccessfulBuild builds
]
{ #category : #tests }

diff:
@@ -55,7 +55,7 @@ PhLJenkins2ServerTest >> oneJobResponse [
{ #category : #tests }
PhLJenkins2ServerTest >> testNoJob [
self setUpResponse: self noJobsResponse.
- self assert: self newInstance jobs isEmpty
+ self assertEmpty: self newInstance jobs
]
{ #category : #tests }

diff:
@@ -44,7 +44,7 @@ PhLVirtualMachineManagerFunctionalTest >> testCanDetectPreSpurImage [
{ #category : #tests }
PhLVirtualMachineManagerFunctionalTest >> testCanDetectSystemUnzip [
- self assert: PhLVirtualMachineManager canUseSytemZip equals: true
+ self assert: PhLVirtualMachineManager canUseSytemZip
]
{ #category : #tests }

diff:
@@ -71,11 +71,9 @@ PhLLaunchConfigurationPresenterTest >> testConfigurationDetailIsCleanedWhenConfi
selectConfiguration: config;
clickDeleteConfigurationButton.
- self assert: presenter imageArguments isEmpty.
- self assert: presenter vmArguments isEmpty.
- self assert: presenter configurationName isEmpty.
-
-
+ self assertEmpty: presenter imageArguments.
+ self assertEmpty: presenter vmArguments.
+ self assertEmpty: presenter configurationName
]
{ #category : #tests }


message:
Launcher `open` - explicitly disable fullscreen mode
Also, "beOpenedInWorld" seems ambiguous and possibly misledaing, so change to "beOpenedAsWorld"

diff:
@@ -12,8 +12,8 @@ Class {
'imageRepository',
'templateRepository',
'imagesPresenter',
- 'openInWorld',
- 'scriptsDirectory'
+ 'scriptsDirectory',
+ 'openAsWorld'
],
#classVars : [
'Default',
@@ -121,14 +121,16 @@ PharoLauncherApplication class >> menuCommandOn: aBuilder [
{ #category : #opening }
PharoLauncherApplication class >> open [
<script>
- ^ self default run
+ ^ self default
+ openAsWorld: false;
+ run
]
{ #category : #opening }
PharoLauncherApplication class >> openFull [
<script>
^ self default
- beOpenedInWorld;
+ beOpenedAsWorld;
run
]
@@ -199,8 +201,8 @@ PharoLauncherApplication class >> templatesClearedOnStartup: aBoolean [
]
{ #category : #configuring }
-PharoLauncherApplication >> beOpenedInWorld [
- openInWorld := true
+PharoLauncherApplication >> beOpenedAsWorld [
+ self openAsWorld: true
]
{ #category : #accessing }
@@ -226,7 +228,7 @@ PharoLauncherApplication >> imageRepositoryChanged: newImage [
{ #category : #initialization }
PharoLauncherApplication >> initialize [
- openInWorld := false.
+ openAsWorld := false.
imageRepository := PhLDirectoryBasedImageRepository default.
self templatesClearedOnStartup
ifTrue: [ self class resetTemplateRepository ].
@@ -249,6 +251,11 @@ PharoLauncherApplication >> launchConfigurationEdited: aLaunchConfiguration [
ifFalse: [ imagesPresenter selectConfiguration: aLaunchConfiguration ].
]
+{ #category : #configuring }
+PharoLauncherApplication >> openAsWorld: aBoolean [
+ openAsWorld := aBoolean
+]
+
{ #category : #initialization }
PharoLauncherApplication >> resetTemplateRepository [
templateRepository := TemplateRepository
@@ -259,7 +266,7 @@ PharoLauncherApplication >> resetTemplateRepository [
PharoLauncherApplication >> run [
| presenterClass |
self initializeImagesPresenter.
- presenterClass := openInWorld
+ presenterClass := openAsWorld
ifTrue: [ SpWorldPresenter ]
ifFalse: [ imagesPresenter defaultWindowPresenterClass ].
self


message:
Update README.md
Access download page securely. (This second PR is because I accidentally did the first one against my fork instead of upstream)
is working on having the pharo.org server to redirect http -> https now that we have SSL

diff:
@@ -7,7 +7,7 @@ The Pharo Launcher is a cross-platform application that
- automatically find and download the appropriate VM to launch your images.
## How to get Pharo Launcher and install it?
-See http://pharo.org/download for detailed download and installation instructions.
+See https://pharo.org/download for detailed download and installation instructions.
## Pharo Launcher documentation
Pharo Launcher documentation is available at https://pharo-project.github.io/pharo-launcher/

original_message:
Update README.md

Access download page securely. (This second PR is because I accidentally did the first one against my fork instead of upstream)

@MarcusDenker is working on having the pharo.org server to redirect http -> https now that we have SSL


message:
Update templates.md
Script to generate `mysources.list`

diff:
@@ -37,10 +37,31 @@ There are different ways:
You can create your own templates from Pharo Launcher. From any image in the image list, right-click and select `Create template` or `Create template and delete image`. It will create a zip file from the selected image and put it in the Templates category under the provided name.
## Create your own list of template categories
-Pharo already provides a wide range of templates but you can provide your own categories. It is useful to add templates that are private (e.g. private jenkins instance) or only of interest for you. It is doable thanks to the `mysources.list` file located in the Pharo folder. If present, this file defines additional template sources to the official list of templates. At this time, there is no UI to add them but you can take inspiration from the following examples.
-Warning: take care to separate each template category by a comma. All categories should be enclosed inside `[]`.
+Pharo already provides a wide range of templates but you can provide your own categories. It is useful to add templates that are private (e.g. private jenkins instance) or only of interest for you. It is doable thanks to the `mysources.list` file located in the `PhLUserTemplateSources sourcesFile` folder. If present, this file defines additional template sources beyond the official list of templates. At this time, there is no UI to add them but you can take inspiration from the following examples.
-Here is an example of a `mysources.list` file:
+Here is a Pharo script to generate an example file:
+```smalltalk
+| sources |
+ sources := {
+ PhLTemplateSource new
+ type: #HttpListing;
+ name: 'User-defined http listing';
+ url: 'http://myserver.org/myimages/'.
+ PhLTemplateSource new
+ type: #JenkinsServer;
+ name: 'My Jenkins server';
+ url: 'https://jenkins.mycompany.org';
+ username: 'john';
+ password: 'doefkwoiekfdoekdw2302ek349039e' }.
+
+ PhLUserTemplateSources sourcesFile writeStreamDo: [ :s |
+ (STON writer on: s)
+ newLine: String lf;
+ prettyPrint: true;
+ nextPut: sources ]
+```
+
+You can also edit the file directly if you are comfortable with JSON. Warning: take care to separate each template category by a comma. All categories should be enclosed inside `[]`. Here is the `mysources.list` file generated by the above script:
```json
[
PhLTemplateSource {


message:
[Enh]: Custom VM/Images - Refactor and Add Squeak
Add Squeak
Extensive Documentation
Rename GToolkit image class due to botched prefix and failure to capitalize "Toolkit"
Refactor hooks now that second example has provided clarity

diff:
"
-I represent a Pharo image. I live in a particular location and have a name. Users can launch me.
+I represent a Pharo (or other) image. I live in a particular location and have a name. Users can launch me.
+
+#VM Matching
+I am matched to the appropriate VM to launch me via my ""version file"", which is in the same folder as me, and whose name is the string returned by #versionFileName. My version file's contents are of the form: `{prefix}{version}`*, where:
+- {prefix} is empty for standard Pharo images. It is made available and used by custom images/VMs e.g. Gtoolkit uses 'gt-'
+- {version} is whatever convention is used by the image/VM type. For standard Pharo, it is the Pharo version with dots removed. Examples:
+ - Pharo 9.0 -> `90`.
+ - Gtoolkit 0.8.83 -> `gt-0.8.83`.
+* This pattern is the same as the matching VM root folder minus the architecture. See PhLVirtualMachine comment, ""Filesystem Location"" section for more info.
+
+#Customized Image Types
+Subclassing me allows you to customize things like:
+- Which VM to use (if not using the standard mapping from Pharo image version to Pharo VM). For example, GToolkit or Squeak VMs. See below for more details.
+- Default image arguments (by overriding #defaultArguments). For example, GToolkit needs this because the image immediately closes after startup unless `'--no-quit'` is supplied.
+
+##Custom VM Mapping
+with contents `{prefix}{version}` e.g. `gt-0.8.83`. This is the same as the VM root folder minus the architecture. See PhLVirtualMachine comment, ""Filesystem Location"" section for more info.
+Let's say you have an image that should be run on a custom VM (i.e. not a standard Pharo one)... subclass me, overriding `#versionPrefix` to match the `#versionPrefix` returned by an appropriate PhLVirtualMachine subclass. N.B. To change the VM of an image that has previously been launched with another VM, you may have to delete the image's metainfo file, which would cache the VM info.
+
+##Installing an existing (on the filesystem) image in Launcher
+Currently, custom images can't be downloaded via Launcher due to differences in URL and other conventions, although this could probably be implemented if someone was interested enough. To create a template from a custom image, you must do the following:
+1. Download the image and changes file.
+2. Create a folder in your Launcher images folder which contains the image and changes file. Both files should have the same basename as the folder. For example, `/path/to/launcher_images/Gtoolkit 0.8.83`, `Gtoolkit 0.8.83.image` and `Gtoolkit 0.8.83.changes`.
+3. Create a ""version file"" as described in ""Custom VM Mapping"" above.
+4. Open or refresh Launcher. The image should appear.
+
+##Template Creation
+To create a template from a custom image, prepare an image as described above in ""Installing..."" and then select the image in Launcher, bring up its context menu, choose ""Create Template"" and go through the dialogs.
+The template should now be available to create new images.
Instance Variables
file: a reference to the .image file
@@ -9,7 +37,7 @@ Instance Variables
pharoVersion: the Pharo version number of the image
originTemplate: template that was used to create this image
-My metadata are serialized when setting description, template or before launching the image (implies to compute formatNumber, architecture and pharo version)
+My metadata are serialized when setting description, template or before launching the image (implies to compute formatNumber, architecture and pharo version).
"
Class {
#name : #PhLImage,
@@ -35,7 +63,7 @@ Class {
{ #category : #accessing }
PhLImage class >> classForLocation: imageFileReference [
^ self allSubclasses
- detect: [ :cls | cls isClassForLocation: imageFileReference ]
+ detect: [ :cls | cls isSubclassForLocation: imageFileReference ]
ifNone: [ self ]
]
@@ -84,8 +112,10 @@ PhLImage class >> initialize [
]
{ #category : #testing }
-PhLImage class >> isClassForLocation: imageFileReference [
- self subclassResponsibility
+PhLImage class >> isSubclassForLocation: imageFileReference [
+ | versionFile |
+ versionFile := imageFileReference parent / self versionFileName.
+ ^ versionFile exists and: [ versionFile contents beginsWith: self versionPrefix ]
]
{ #category : #'instance creation' }
@@ -128,6 +158,13 @@ PhLImage class >> versionFileName [
^ 'pharo.version'
]
+{ #category : #accessing }
+PhLImage class >> versionPrefix [
+ "Used in matching me to a VM. See class comment, 'VM Matching' section"
+
+ ^ ''
+]
+
{ #category : #configuring }
PhLImage >> addLaunchConfiguration: aPhLLaunchConfiguration [
launchConfigurations

diff:
@@ -11,7 +11,7 @@ Class {
}
{ #category : #testing }
-PhLPrivateVirtualMachine class >> isClassForDirectory: aFileReference private: isPrivateVm [
+PhLPrivateVirtualMachine class >> isSubclassForDirectory: aFileReference private: isPrivateVm [
^ isPrivateVm
]

diff:
"
-I represent a Pharo virtual machine that can be used to run image.
+I represent a Pharo (or other) virtual machine that can be used to run an image.
+
+# Filesystem Location
+For standard Pharo VMs, this is handled automatically and users should not have to be concerned about the details. However, the name of my executable's root folder must follow an exact pattern because this is how I am matched to images. My custom subclasses will have to know where and how to install their files. My executable is kept in the Launcher VM folder, in a root folder of the form `{prefix}{version}{architecture}`, where:
+- {prefix} - Standard Pharo VMs have no prefix, which is available and used to distinguish custom images/VMs. For example, Gtoolkit uses 'gt-'.
+- {version} - Standard Pharo VMs use the image version without dots e.g. '90' for Pharo 9.0. Custom classes can use any convention they wish, e.g. Gtoolkit keeps the dots e.g. '0.8.83' for Gtoolkit 0.8.83.
+- {architecture} - one of #('x64', 'x86')
+
+Three folder naming examples:
+- 64-bit: For Pharo 9.0 64-bit, I would be in the `path/to/vms/90-x64` folder
+- 32-bit: For Pharo 8.0 32-bit, I would be in the `path/to/vms/80-x86` folder
+- Custom VM: For GToolkit 0.8.83, I would be in the `path/to/vms/gt-0.8.83-x64` folder
+
+#Customized VM Types
+Subclassing me allows you to use non-standard Pharo VMs, customizing things like the `#executableName`. Also, pick a prefix as described above in 'Filesystem Location'.
+
+##Setup
+Currently, custom VMs can't be downloaded via Launcher due to differences in URL and other conventions, although this could probably be implemented if someone was interested enough. To install VMs within Launcher
+1. Download the VM
+2. Put the VM, including all libraries and other needed resources - like the sources file - into a folder as described above in 'Filesystem Location'
executableRef is a reference to the script/binary to actually use to launch images.
vmBinaryRef is a reference to the vm binary (not a bash file).
@@ -30,7 +49,7 @@ PhLVirtualMachine class >> directory: aFileReference [
{ #category : #'instance creation' }
PhLVirtualMachine class >> directory: aFileReference private: isPrivateVm [
| targetClass |
- targetClass := self allSubclasses detect: [ :cls | cls isClassForDirectory: aFileReference private: isPrivateVm ] ifNone: [ self ].
+ targetClass := self allSubclasses detect: [ :cls | cls isSubclassForDirectory: aFileReference private: isPrivateVm ] ifNone: [ self ].
^ targetClass new
initializeOn: aFileReference;
yourself
@@ -61,8 +80,16 @@ PhLVirtualMachine class >> id: aString [
]
{ #category : #testing }
-PhLVirtualMachine class >> isClassForDirectory: aFileReference private: isPrivateVm [
- self subclassResponsibility
+PhLVirtualMachine class >> isSubclassForDirectory: aFileReference private: isPrivateVm [
+
+ ^ isPrivateVm not and: [ aFileReference basename beginsWith: self versionPrefix ]
+]
+
+{ #category : #accessing }
+PhLVirtualMachine class >> versionPrefix [
+ "See class comment, 'Filesystem Location' section"
+
+ ^ ''
]
{ #category : #comparing }

change_type: DELETE

diff:
-Class {
- #name : #PLhGtoolkitImage,
- #superclass : #PhLImage,
- #category : #'PharoLauncher-GToolkit'
-}
-
-{ #category : #testing }
-PLhGtoolkitImage class >> isClassForLocation: imageFileReference [
- | versionFile |
- versionFile := imageFileReference parent / self versionFileName.
- ^ versionFile exists and: [ versionFile contents beginsWith: 'gt-' ]
-]
-
-{ #category : #accessing }
-PLhGtoolkitImage >> defaultArguments [
- ^ super defaultArguments
- add: '--no-quit';
- add: '--interactive';
- yourself
-]

diff:
+"
+See PhLImage comment for setup details. GToolkit VM/image bundles can be downloaded at https://gtoolkit.com/download/.
+"
+Class {
+ #name : #PhLGToolkitImage,
+ #superclass : #PhLImage,
+ #category : #'PharoLauncher-GToolkit'
+}
+
+{ #category : #testing }
+PhLGToolkitImage class >> versionPrefix [
+ ^ PhLGToolkitVirtualMachine versionPrefix
+]
+
+{ #category : #accessing }
+PhLGToolkitImage >> defaultArguments [
+ ^ super defaultArguments
+ add: '--no-quit';
+ add: '--interactive';
+ yourself
+]

diff:
+"
+See PhLVirtualMachine's comment for general details. GToolkit VM/image bundles can be downloaded at https://gtoolkit.com/download/
+
+#Setup
+Two things unique to GToolkit setup:
+1. Gtoolkit currently puts some libraries in non-standard locations e.g. on Mac, several dylibs are outside the .app bundle in its parent folder. Make sure to include all these libraries and any other needed resources - like the sources file - when placing the VM in the Launcher VM folder.
+2. For the time being, each image must be launched with the VM distributed with that image version, even for minor and patch releases*. No assumptions can be made about compatibility other than that because the VM may change with every image version.
+
+* Per the GToolkit team on 8/28/2020 on the GT Discord Server, general channel
+"
Class {
#name : #PhLGToolkitVirtualMachine,
#superclass : #PhLVirtualMachine,
@@ -9,7 +19,7 @@ PhLGToolkitVirtualMachine class >> executableName [
^ 'GlamorousToolkit'
]
-{ #category : #testing }
-PhLGToolkitVirtualMachine class >> isClassForDirectory: aFileReference private: isPrivateVm [
- ^ aFileReference basename beginsWith: 'gt-'
+{ #category : #accessing }
+PhLGToolkitVirtualMachine class >> versionPrefix [
+ ^ 'gt-'
]

diff:
+"
+See PhLImage comment for setup details. Squeak VM/image bundles can be downloaded at https://squeak.org/downloads/
+"
+Class {
+ #name : #PhLSqueakImage,
+ #superclass : #PhLImage,
+ #category : #'PharoLauncher-Squeak'
+}
+
+{ #category : #testing }
+PhLSqueakImage class >> versionPrefix [
+ ^ PhLSqueakVirtualMachine versionPrefix
+]

diff:
+"
+See PhLVirtualMachine's comment for general details. Squeak VM/image bundles can be downloaded at https://squeak.org/downloads/
+"
+Class {
+ #name : #PhLSqueakVirtualMachine,
+ #superclass : #PhLVirtualMachine,
+ #category : #'PharoLauncher-Squeak'
+}
+
+{ #category : #querying }
+PhLSqueakVirtualMachine class >> executableName [
+ ^ 'Squeak'
+]
+
+{ #category : #testing }
+PhLSqueakVirtualMachine class >> versionPrefix [
+ ^ 'sq-'
+]

diff: +Package { #name : #'PharoLauncher-Squeak' }

diff:
@@ -9,7 +9,7 @@ Class {
}
{ #category : #testing }
-PhLOsXMojaveTestImage class >> isClassForLocation: aFileReference [
+PhLOsXMojaveTestImage class >> isSubclassForLocation: aFileReference [
^ false
]

original_message:
[Enh]: Custom VM/Images - Refactor and Add Squeak
- Add Squeak
- Extensive Documentation
- Rename GToolkit image class due to botched prefix and failure to capitalize "Toolkit"
- Refactor hooks now that second example has provided clarity


message: [MetaC]: Add GToolkit and Squeak Packages to Baseline

diff:
@@ -30,6 +30,10 @@ BaselineOfPharoLauncher >> baseline: spec [
spec requires: #(#'XMLParser' #'OSSubprocess' #'OSWinSubprocess' #'Ston' #'PharoLauncher-80Compatibility' #'PharoLauncher-Pharo9ToRemove-FileLocator'). ];
package: #'PharoLauncher-Spec2' with: [
spec requires: #(#'PharoLauncher-Core' #Spec2). ];
+ package: #'PharoLauncher-GToolkit' with: [
+ spec requires: #(#'PharoLauncher-Core'). ];
+ package: #'PharoLauncher-Squeak' with: [
+ spec requires: #(#'PharoLauncher-Core'). ];
package: #'PharoLauncher-Tests-Core' with: [
spec requires: #(#'PharoLauncher-Core' ). ];


message: [MetaC]: Add GT and Sqeak to Default Group

diff:
@@ -46,5 +46,5 @@ BaselineOfPharoLauncher >> baseline: spec [
package: #'PharoLauncher-Tests-Functional' with: [
spec requires: #(#'PharoLauncher-Core' #'PharoLauncher-Tests-Download'). ].
spec
- group: 'Default' with: #(#'PharoLauncher-Tests-Core' #'PharoLauncher-Tests-Download' #'PharoLauncher-Core' #'PharoLauncher-Spec2' #'PharoLauncher-Tests-SpecUI' #'PharoLauncher-Tests-Functional'). ].
+ group: 'Default' with: #(#'PharoLauncher-Tests-Core' #'PharoLauncher-Tests-Download' #'PharoLauncher-Core' #'PharoLauncher-Spec2' #'PharoLauncher-Tests-SpecUI' #'PharoLauncher-Tests-Functional' #'PharoLauncher-GToolkit' #'PharoLauncher-Squeak'). ].
]


message: adapted, added a configuration

diff:
+Class {
+ #name : #PhLGtkConfiguration,
+ #superclass : #SpGtkConfiguration,
+ #category : #'PharoLauncher-Spec2-Gtk'
+}
+
+{ #category : #configuring }
+PhLGtkConfiguration >> configureGeneral: anApplication [
+
+ self addCSSProviderFromString: '
+toolbar.compact {
+ font-size: 0.6em }
+toolbar.compact toolbutton > button {
+ padding: 2px;
+ margin: 2px }
+'
+]

diff:
+Extension { #name : #PharoLauncherApplication }
+
+{ #category : #'*PharoLauncher-Spec2-Gtk' }
+PharoLauncherApplication class >> openGtk [
+ <script>
+
+ ^ (Default := self new)
+ useBackend: #Gtk with: PhLGtkConfiguration new;
+ openAsWorld: false;
+ run
+]

diff: +Package { #name : #'PharoLauncher-Spec2-Gtk' }

diff:
@@ -14,7 +14,8 @@ Class {
'descriptionPanel',
'launchConfigurationList',
'imageFilter',
- 'rootCommandsGroup'
+ 'rootCommandsGroup',
+ 'toolbar'
],
#category : #'PharoLauncher-Spec2'
}
@@ -58,45 +59,43 @@ PhLImagesPresenter class >> buildContextualMenuGroup [
{ #category : #commands }
PhLImagesPresenter class >> buildToolbarGroup [
+
^ (CmCommandGroup named: 'Toolbar') asSpecGroup
description: 'Pharo Launcher toolbar';
+ register: ((CmCommandGroup named: 'Create') asSpecGroup
+ beDisplayedAsGroup;
register: PhLOpenNewImageWindowCommand forSpec;
+ yourself);
+ register: ((CmCommandGroup named: 'Image') asSpecGroup
+ beDisplayedAsGroup;
register: PhLLaunchImageCommand forSpec;
register: PhLLaunchImageCommand new asSpecLaunchWithoutSettingsCommand;
register: PhLLaunchImageFromDiskCommand forSpec;
register: PhLImportImageCommand forSpec;
register: PhLRefreshImageRepositoryCommand forSpec;
- register:
- (PhLShowImageInFolderCommand forSpec
+ register: (PhLShowImageInFolderCommand forSpec
name: 'Show';
yourself);
register: PhLDeleteImageCommand forSpec;
- register:
- (PhLQuitCommand forSpec
- beDisplayedOnRightSide;
yourself);
- register:
- (PhLAboutCommand forSpec
- beDisplayedOnRightSide;
+ register: ((CmCommandGroup named: 'Settings') asSpecGroup
+ register: (PhLOpenVmManagerCommand forSpec
+ name: 'VMs';
yourself);
- register:
- (PhLOpenSettingsCommand forSpec
+ register: (PhLOpenSettingsCommand forSpec
name: 'Settings';
- beDisplayedOnRightSide;
- yourself);
- register:
- (PhLOpenVmManagerCommand forSpec
- name: 'VMs';
- beDisplayedOnRightSide;
yourself);
- beDisplayedAsGroup;
- yourself
+ register: (PhLAboutCommand forSpec);
+ register: (PhLQuitCommand forSpec);
+ yourself;
+ yourself)
]
{ #category : #specs }
PhLImagesPresenter class >> defaultSpec [
^ SpBoxLayout newVertical
+ add: #toolbar expand: false;
add: #imageFilter expand: false;
add: (SpPanedLayout newVertical
positionOfSlider: 65 percent;
@@ -119,6 +118,25 @@ PhLImagesPresenter >> actionLaunch [
cmd execute
]
+{ #category : #initialization }
+PhLImagesPresenter >> buildToolbar [
+ | toolbarGroup |
+
+ toolbarGroup := self toolbarGroup.
+ ^ self newPresenter
+ layout: (SpBoxLayout newLeftToRight
+ add: (self newLaunchToolbar fillWith: toolbarGroup / 'Create') expand: false;
+ add: (SpBoxLayout newTopToBottom
+ vAlignCenter;
+ add: self newLaunchConfigurationDropList expand: false;
+ yourself);
+ add: (self newLaunchToolbar fillWith: toolbarGroup / 'Image') expand: false;
+ add: self newLabel; "to create an space"
+ addLast: (self newLaunchToolbar fillWith: toolbarGroup / 'Settings') expand: false;
+ yourself);
+ yourself
+]
+
{ #category : #initialization }
PhLImagesPresenter >> connectPresenters [
@@ -177,6 +195,7 @@ PhLImagesPresenter >> imageRepository [
{ #category : #initialization }
PhLImagesPresenter >> initializePresenters [
+ toolbar := self buildToolbar.
imageFilter := self newTextInput
placeholder: 'Enter image name filter ...';
whenTextChangedDo: [ :filterString | self filter: filterString asLowercase ];
@@ -223,12 +242,9 @@ PhLImagesPresenter >> initializeWindow: aWindowPresenter [
aWindowPresenter
title: 'Pharo Launcher';
initialExtent: 700 @ 500;
- toolbar: self toolbarGroup asToolbarPresenter;
centered;
whenClosedDo: [ self imageRepository unsubscribe: self ].
self rootCommandsGroup installShortcutsIn: aWindowPresenter.
- aWindowPresenter toolbar
- addItem: self newLaunchConfigurationDropList.
aWindowPresenter
bindKeyCombination: $f meta
toAction: [ self actionFilter ]
@@ -256,27 +272,34 @@ PhLImagesPresenter >> refresh [
{ #category : #updating }
PhLImagesPresenter >> refreshLaunchConfigurationList [
| image items |
+
[ image := self singleImage ]
on: PhLCommandError
- do: [ self resetLaunchConfigurationList.
+ do: [
+ self resetLaunchConfigurationList.
^ self ].
- items := image launchConfigurations collect: [ :each |
+ items := image launchConfigurations
+ collect: [ :each |
SpDropListItem new
model: each;
display: [ :config | config name ];
- icon: (self iconNamed: #configuration);
+ icon: (self application iconNamed: #configuration);
yourself ].
+
items addFirst: (SpDropListItem new
model: 'Edit configurations ...';
- action: [ self
+ action: [
+ self
editLaunchConfigurations;
refreshLaunchConfigurationList ];
- icon: (self iconNamed: #edit);
+ icon: (self application iconNamed: #edit);
yourself ).
+
launchConfigurationList
resetSelection;
dropListItems: items.
+
[ launchConfigurationList selectItem: image defaultLaunchConfiguration ]
on: NotFound "Default configuration has been deleted but there are still other configurations"
do: [ launchConfigurationList selectIndex: 2 ]
@@ -284,6 +307,7 @@ PhLImagesPresenter >> refreshLaunchConfigurationList [
{ #category : #updating }
PhLImagesPresenter >> resetLaunchConfigurationList [
+
launchConfigurationList
resetSelection;
items: #() "no image selected".
@@ -296,7 +320,8 @@ PhLImagesPresenter >> rootCommandsGroup [
{ #category : #'api - selection' }
PhLImagesPresenter >> selectConfiguration: aPhLLaunchConfiguration [
- launchConfigurationList selectItem: aPhLLaunchConfiguration.
+
+ launchConfigurationList selectItem: aPhLLaunchConfiguration
]
{ #category : #'api - selection' }
@@ -318,6 +343,7 @@ PhLImagesPresenter >> selectedImages [
{ #category : #'api - accessing' }
PhLImagesPresenter >> selectedLaunchConfiguration [
+
^ launchConfigurationList selectedItem
]

diff:
@@ -105,12 +105,15 @@ PhLVMPresenter >> initializePresenters [
{ #category : #initialization }
PhLVMPresenter >> initializeWindow: aWindowPresenter [
+
aWindowPresenter
title: 'Locally available Virtual Machines';
initialExtent: 720 @ 300;
- toolbar: (self rootCommandsGroup / 'Toolbar') asToolbarPresenter;
+ toolbar: (self newLaunchToolbar fillWith: (self rootCommandsGroup / 'Toolbar'));
centered.
+
self rootCommandsGroup installShortcutsIn: aWindowPresenter.
+
self privateVmsTogglePresenter
whenUnselectedDo: [ self privateVmsTogglePresenter
label: 'public';

diff:
@@ -27,6 +27,12 @@ Class {
#category : #'PharoLauncher-Spec2'
}
+{ #category : #accessing }
+PharoLauncherApplication class >> applicationName [
+
+ ^ 'pharo-launcher'
+]
+
{ #category : #testing }
PharoLauncherApplication class >> beDeployed [
IsDeployed := true
@@ -130,7 +136,8 @@ PharoLauncherApplication class >> open [
{ #category : #opening }
PharoLauncherApplication class >> openFull [
<script>
- ^ self default
+
+ ^ (Default := self new)
beOpenedAsWorld;
run
]
@@ -235,8 +242,7 @@ PharoLauncherApplication >> initialize [
imageRepository := PhLDirectoryBasedImageRepository default.
self templatesClearedOnStartup
ifTrue: [ self class resetTemplateRepository ].
- self resetTemplateRepository.
- self useBackend: #Gtk.
+ self resetTemplateRepository
]
{ #category : #private }

diff:
+Extension { #name : #SpPresenter }
+
+{ #category : #'*PharoLauncher-Spec2' }
+SpPresenter >> newLaunchToolbar [
+
+ ^ self newToolbar
+ addStyle: 'compact';
+ yourself
+]

original_message: adapted, added a configuration


message: fix builds and start

diff:
@@ -24,39 +24,23 @@ Class {
{ #category : #specs }
PhLImageDetailPresenter class >> defaultSpec [
- ^ SpBoxLayout newVertical
- add: #imageLabel
- withConstraints: [ :constraints | constraints height: self labelHeight * 1.5 ];
- add:
- (SpBoxLayout newHorizontal
- add: 'description:' withConstraints: self labelConstraintsBlock;
- add: #description;
- yourself);
- add:
- (SpBoxLayout newHorizontal
- add: 'Origin template:' withConstraints: self labelConstraintsBlock;
- add: #template;
- yourself)
- height: self labelHeight;
- add:
- (SpBoxLayout newHorizontal
- add: '' withConstraints: self labelConstraintsBlock;
- add: #templateUrl;
- yourself)
- height: self labelHeight;
- add:
- (SpBoxLayout newHorizontal
- add: 'Initialization script:' withConstraints: self labelConstraintsBlock;
+
+ ^ SpBoxLayout newTopToBottom
+ add: #imageLabel expand: false;
+ add: (SpGridLayout new
+ beRowNotHomogeneous;
+ beColumnNotHomogeneous;
+ column: 1 withConstraints: [ :c | c beNotExpand; vAlignStart ];
+ column: 2 withConstraints: [ :c | c beExpand ];
+ add: 'Description' at: 1@1; add: #description at: 2@1;
+ add: 'Origin template' at: 1@2; add: #template at: 2@2;
+ add: #templateUrl at: 2@3;
+ add: 'Initialization script' at: 1@4; add: (SpBoxLayout newLeftToRight
add: #initializationScript expand: false;
add: #shouldRunInitializationScript expand: false;
- yourself)
- height: self labelHeight;
- add:
- (SpBoxLayout newHorizontal
- add: 'Location:' withConstraints: self labelConstraintsBlock;
- add: #location;
- yourself)
- height: self labelHeight;
+ yourself) at: 2@4;
+ add: 'Location' at: 1@5; add: #location at: 2@5;
+ yourself);
yourself
]

diff:
@@ -94,15 +94,7 @@ PhLImagesPresenter class >> buildToolbarGroup [
{ #category : #specs }
PhLImagesPresenter class >> defaultSpec [
- ^ SpBoxLayout newVertical
- add: #toolbar expand: false;
- add: #imageFilter expand: false;
- add: (SpPanedLayout newVertical
- positionOfSlider: 65 percent;
- add: #imageTable;
- add: #descriptionPanel;
- yourself);
- yourself
+ ^ nil
]
{ #category : #'api - actions' }
@@ -118,6 +110,52 @@ PhLImagesPresenter >> actionLaunch [
cmd execute
]
+{ #category : #initialization }
+PhLImagesPresenter >> buildDescriptionPanel [
+
+ ^ self
+ instantiate: PhLImageDetailPresenter
+ on: PhLNullImage new
+]
+
+{ #category : #initialization }
+PhLImagesPresenter >> buildImageFilter [
+
+ ^ self newTextInput
+ placeholder: 'Enter image name filter ...';
+ whenTextChangedDo: [ :filterString | self filter: filterString asLowercase ];
+ yourself
+]
+
+{ #category : #initialization }
+PhLImagesPresenter >> buildImageTable [
+
+ ^ self newTable
+ items: self imageRepository images;
+ sortingBlock: #lastModification descending;
+ whenActivatedDo: [ self actionLaunch ];
+ bindKeyCombination: Character cr asShortcut toAction: [ self actionLaunch ];
+ "whenBuiltDo: [ :tree | tree widget alternateRowsColor ];"
+ addColumn: ((SpStringTableColumn title: 'Name' evaluated: #name)
+ width: 350;
+ yourself);
+ addColumn: ((SpStringTableColumn title: 'Architecture' evaluated: #architecture)
+ width: 80;
+ yourself);
+ addColumn: ((SpStringTableColumn title: 'Pharo Version' evaluated: #pharoVersion)
+ width: 80;
+ yourself);
+ addColumn: ((SpStringTableColumn
+ title: 'Last modified'
+ evaluated: [ :image | self readableDateFor: image lastModification ])
+ sortFunction: #lastModification descending;
+ yourself);
+ contextMenuFromCommandsGroup: [ self rootCommandsGroup / 'Context Menu' ];
+ beResizable;
+ beMultipleSelection;
+ yourself
+]
+
{ #category : #initialization }
PhLImagesPresenter >> buildToolbar [
| toolbarGroup |
@@ -140,9 +178,7 @@ PhLImagesPresenter >> buildToolbar [
{ #category : #initialization }
PhLImagesPresenter >> connectPresenters [
- super connectPresenters.
-
- imageTable whenSelectionChangedDo: [ :selection |
+ imageTable transmitDo: [ :image |
self
refreshLaunchConfigurationList;
updateToolbarCommandsAvailability ].
@@ -196,52 +232,28 @@ PhLImagesPresenter >> imageRepository [
PhLImagesPresenter >> initializePresenters [
toolbar := self buildToolbar.
- imageFilter := self newTextInput
- placeholder: 'Enter image name filter ...';
- whenTextChangedDo: [ :filterString | self filter: filterString asLowercase ];
- yourself.
- imageTable := self newTable
- items: self imageRepository images;
- sortingBlock: #lastModification descending;
- whenActivatedDo: [ self actionLaunch ];
- bindKeyCombination: Character cr asShortcut toAction: [ self actionLaunch ];
- "whenBuiltDo: [ :tree | tree widget alternateRowsColor ];"
- addColumn:
- ((SpStringTableColumn title: 'Name' evaluated: #name)
- width: 350;
- yourself);
- addColumn:
- ((SpStringTableColumn title: 'Architecture' evaluated: #architecture)
- width: 80;
- yourself);
- addColumn:
- ((SpStringTableColumn title: 'Pharo Version' evaluated: #pharoVersion)
- width: 80;
+ imageFilter := self buildImageFilter.
+ imageTable := self buildImageTable.
+ descriptionPanel := self buildDescriptionPanel.
+
+ self layout: (SpBoxLayout newTopToBottom
+ add: toolbar expand: false;
+ add: imageFilter expand: false;
+ add: (SpPanedLayout newTopToBottom
+ positionOfSlider: 60 percent;
+ add: imageTable;
+ add: descriptionPanel;
yourself);
- addColumn:
- ((SpStringTableColumn
- title: 'Last modified'
- evaluated: [ :image | self readableDateFor: image lastModification ])
- sortFunction: #lastModification descending;
- yourself);
- contextMenuFromCommandsGroup: [ self rootCommandsGroup / 'Context Menu' ];
- beResizable;
- beMultipleSelection;
- yourself.
- descriptionPanel := self
- instantiate: PhLImageDetailPresenter
- on: PhLNullImage new.
- self imageRepository whenChangedSend: #refresh to: self.
- self whenDisplayDo:
- [ self imageRepository hasImages
- ifTrue: [ self selectImageAt: 1 ] ].
+ yourself).
+
+ self imageRepository whenChangedSend: #refresh to: self
]
{ #category : #initialization }
PhLImagesPresenter >> initializeWindow: aWindowPresenter [
aWindowPresenter
title: 'Pharo Launcher';
- initialExtent: 700 @ 500;
+ initialExtent: 700 @ 550;
centered;
whenClosedDo: [ self imageRepository unsubscribe: self ].
self rootCommandsGroup installShortcutsIn: aWindowPresenter.
@@ -265,6 +277,7 @@ PhLImagesPresenter >> readableDateFor: aDateAndTime [
{ #category : #updating }
PhLImagesPresenter >> refresh [
+
imageTable items: self imageRepository images.
self refreshLaunchConfigurationList
]
@@ -368,6 +381,14 @@ PhLImagesPresenter >> toolbarGroup [
^ self rootCommandsGroup / 'Toolbar'
]
+{ #category : #initialization }
+PhLImagesPresenter >> updatePresenter [
+
+ self imageRepository hasImages
+ ifTrue: [ imageTable selectFirst ]
+
+]
+
{ #category : #updating }
PhLImagesPresenter >> updateToolbarCommandsAvailability [
self withToolbarDo: [ :toolbar |

diff:
@@ -286,16 +286,23 @@ PharoLauncherApplication >> scriptsDirectory: aFileReference [
{ #category : #running }
PharoLauncherApplication >> start [
- | presenterClass |
self initializeImagesPresenter.
- presenterClass := openAsWorld
- ifTrue: [ SpWorldPresenter ]
- ifFalse: [ imagesPresenter defaultWindowPresenterClass ].
+
+ openAsWorld ifTrue: [
+ self startFull.
+ ^ self ].
+
+ imagesPresenter openWithSpec
+]
+
+{ #category : #running }
+PharoLauncherApplication >> startFull [
+
self
open: imagesPresenter
withSpecLayout: imagesPresenter defaultSpec
- using: presenterClass
+ using: SpWorldPresenter
]
{ #category : #accessing }

diff:
@@ -93,6 +93,7 @@ PhLTestImagesPresenter >> newRequest [
{ #category : #updating }
PhLTestImagesPresenter >> refreshLaunchConfigurationList [
+
launchConfigurationList ifNotNil: [ super refreshLaunchConfigurationList ]
]

original_message: fix builds and start