[Cuis-dev] Package Installer - initial version

Mariano Montone marianomontone at gmail.com
Thu Nov 25 12:18:26 PST 2021


Hello Juan,

I'm submitting (see attached) an initial version of the Package
Installer for review.

The code needs to be better commented, methods classified, etc. But I
would like to know if there are any major objections first; my plan is
to clean things up once it is on a git repository.

Can you have a look and give me some feedback?

To run select: World Menu -> Open -> Package Installer.

Thanks!

Mariano
-------------- next part --------------
'From Cuis 5.0 [latest update: #4973] on 25 November 2021 at 5:16:00 pm'!
'Description '!
!provides: 'PackageInstaller' 1 25!
SystemOrganization addCategory: 'PackageInstaller'!


!classDefinition: #PackageInstallerWindow category: 'PackageInstaller'!
SystemWindow subclass: #PackageInstallerWindow
	instanceVariableNames: 'filterString filterInput currentIndex'
	classVariableNames: ''
	poolDictionaries: ''
	category: 'PackageInstaller'!
!classDefinition: 'PackageInstallerWindow class' category: 'PackageInstaller'!
PackageInstallerWindow class
	instanceVariableNames: ''!

!classDefinition: #PackageDescription category: 'PackageInstaller'!
Object subclass: #PackageDescription
	instanceVariableNames: 'name homepage description features provides requires tags'
	classVariableNames: ''
	poolDictionaries: ''
	category: 'PackageInstaller'!
!classDefinition: 'PackageDescription class' category: 'PackageInstaller'!
PackageDescription class
	instanceVariableNames: ''!

!classDefinition: #FilePackageDescription category: 'PackageInstaller'!
PackageDescription subclass: #FilePackageDescription
	instanceVariableNames: 'codePackageFile'
	classVariableNames: ''
	poolDictionaries: ''
	category: 'PackageInstaller'!
!classDefinition: 'FilePackageDescription class' category: 'PackageInstaller'!
FilePackageDescription class
	instanceVariableNames: ''!

!classDefinition: #PackageInstaller category: 'PackageInstaller'!
Object subclass: #PackageInstaller
	instanceVariableNames: 'packageList'
	classVariableNames: 'PackageList'
	poolDictionaries: ''
	category: 'PackageInstaller'!
!classDefinition: 'PackageInstaller class' category: 'PackageInstaller'!
PackageInstaller class
	instanceVariableNames: ''!


!FilePackageDescription commentStamp: '<historical>' prior: 0!
PackageSpec of a package that lives on a file on disk.!

!PackageInstallerWindow methodsFor: 'as yet unclassified' stamp: 'MM 11/25/2021 15:21:52'!
buildActionsBar

	| actionsBar | 
	
	actionsBar _ LayoutMorph newRow.
	
	actionsBar addMorph:
		(PluggableButtonMorph 
				model: self 
				action: #installPackage
				label: 'Install package').
	actionsBar addMorph:
		(PluggableButtonMorph
				model: self
				action: #updatePackageList
				label: 'Update package list').
	
	actionsBar addMorph: (LabelMorph contents: 'Search: ').
	
	filterInput _ TextModelMorph textProvider: self textGetter: #filterString textSetter: #filterString:.
	filterInput acceptOnCR: true;
		askBeforeDiscardingEdits: false.
	actionsBar addMorph: filterInput layoutSpec: (LayoutSpec fixedHeight: 30).
	
	^ actionsBar! !

!PackageInstallerWindow methodsFor: 'as yet unclassified' stamp: 'MM 11/25/2021 13:56:23'!
buildDetailPane
	^ TextModelMorph textProvider:  self textGetter: #packageDescription! !

!PackageInstallerWindow methodsFor: 'as yet unclassified' stamp: 'MM 11/25/2021 15:23:37'!
buildMorphicWindow

	|layout|
		
	layout _ LayoutMorph newRow.
	layout addMorph: self buildPackageListMorph layoutSpec: (LayoutSpec proportionalWidth: 0.5).
	layout addAdjusterAndMorph: self buildDetailPane layoutSpec: (LayoutSpec proportionalWidth: 0.5).
	self addMorph: layout layoutSpec: (LayoutSpec proportionalWidth: 1).
	self addMorph: self buildActionsBar layoutSpec: (LayoutSpec new fixedHeight: 30; proportionalWidth: 1; yourself). 
	! !

!PackageInstallerWindow methodsFor: 'as yet unclassified' stamp: 'MM 11/25/2021 15:29:21'!
buildPackageListMorph
	
	^ PluggableListMorph model: self listGetter: #packageListNames indexGetter: #currentIndex indexSetter: #currentIndex:.! !

!PackageInstallerWindow methodsFor: 'as yet unclassified' stamp: 'MM 11/25/2021 15:17:00'!
currentIndex
	^ currentIndex ifNil: [0]! !

!PackageInstallerWindow methodsFor: 'as yet unclassified' stamp: 'MM 11/25/2021 15:17:08'!
currentIndex: index
	currentIndex _ index.
	self changed: #acceptedContents! !

!PackageInstallerWindow methodsFor: 'as yet unclassified' stamp: 'MM 11/25/2021 16:18:21'!
filteredPackageList

	| packageList |
	
	packageList _ model packageList.
	
	^ filterString isEmpty
		ifTrue: [packageList]
		ifFalse: [packageList select: [:package | package packageName includesSubstring: filterString caseSensitive: false]]! !

!PackageInstallerWindow methodsFor: 'as yet unclassified' stamp: 'MM 11/25/2021 14:18:16'!
getFilter
	^ [:str :el | el printString includesSubstring: str caseSensitive: false]! !

!PackageInstallerWindow methodsFor: 'as yet unclassified' stamp: 'MM 11/25/2021 15:18:18'!
initialize
	super initialize.
	filterString _ ''.! !

!PackageInstallerWindow methodsFor: 'as yet unclassified' stamp: 'MM 11/25/2021 15:26:06'!
installPackage
	self selectedPackage ifNotNil: [:package | package install]! !

!PackageInstallerWindow methodsFor: 'as yet unclassified' stamp: 'MM 11/25/2021 14:04:10'!
open
	self buildMorphicWindow.
	labelString _ 'Package Installer'.
	self openInWorld! !

!PackageInstallerWindow methodsFor: 'as yet unclassified' stamp: 'MM 11/25/2021 16:49:17'!
packageDescription

	|package|
	
	package _ self selectedPackage.
	
	package ifNil: [^''].
	
	^ String streamContents: [:s | 
		s nextPutAll: package packageName;
			newLine.
		60 timesRepeat: [	s nextPut: $-].
		s newLine; newLine.
		
		package description ifNotEmpty: [
			s nextPutAll: package description;
				newLine;
				newLine].
		
		s nextPutAll: package codePackageFile description]! !

!PackageInstallerWindow methodsFor: 'as yet unclassified' stamp: 'MM 11/25/2021 16:12:17'!
packageListNames

	^ self filteredPackageList collect: [:package | package packageName].
	
	! !

!PackageInstallerWindow methodsFor: 'as yet unclassified' stamp: 'MM 11/25/2021 16:10:59'!
selectedPackage
	currentIndex ifNil: [^nil].
	currentIndex isZero ifTrue: [^nil].
	^ self filteredPackageList at: currentIndex.! !

!PackageInstallerWindow methodsFor: 'as yet unclassified' stamp: 'MM 11/25/2021 15:30:07'!
updatePackageList

	model updatePackageList.
	self changed: #packageListNames! !

!PackageInstallerWindow methodsFor: 'accessing' stamp: 'MM 11/25/2021 13:43:45'!
filterInput
	"Answer the value of filterInput"

	^ filterInput! !

!PackageInstallerWindow methodsFor: 'accessing' stamp: 'MM 11/25/2021 13:43:45'!
filterInput: anObject
	"Set the value of filterInput"

	filterInput _ anObject! !

!PackageInstallerWindow methodsFor: 'accessing' stamp: 'MM 11/25/2021 13:43:45'!
filterString
	"Answer the value of filterString"

	^ filterString! !

!PackageInstallerWindow methodsFor: 'accessing' stamp: 'MM 11/25/2021 16:53:16'!
filterString: aString
	"Set the value of filterString"

	filterString _ aString.
	filterInput hasUnacceptedEdits: false.
	self currentIndex: nil.
	self changed: #packageListNames! !

!PackageInstallerWindow methodsFor: 'accessing' stamp: 'MM 11/25/2021 13:43:45'!
model
	"Answer the value of model"

	^ model! !

!PackageInstallerWindow methodsFor: 'accessing' stamp: 'MM 11/25/2021 13:43:45'!
model: anObject
	"Set the value of model"

	model _ anObject! !

!PackageInstallerWindow class methodsFor: 'as yet unclassified' stamp: 'MM 11/25/2021 15:11:25'!
open

	^ self open: PackageInstaller new label: 'Package Installer'! !

!PackageInstallerWindow class methodsFor: 'as yet unclassified' stamp: 'MM 11/25/2021 17:15:50'!
worldMenuForOpenGroup
	^ `{{
			#itemGroup 		-> 		20.
			#itemOrder 		-> 		10.
			#label 			->	'Package Installer'.
			#object 			-> 	PackageInstallerWindow.
			#selector 		-> 		#open.
			#icon 			-> 		#packageIcon.
			#balloonText 	-> 		'A tool for installing local Cuis packages.'.
		} asDictionary}`! !

!PackageDescription methodsFor: 'accessing' stamp: 'MM 11/19/2021 12:01:08'!
description
	"Answer the value of description"

	^ description! !

!PackageDescription methodsFor: 'accessing' stamp: 'MM 11/19/2021 12:01:08'!
description: anObject
	"Set the value of description"

	description _ anObject! !

!PackageDescription methodsFor: 'accessing' stamp: 'MM 11/19/2021 12:01:08'!
features
	"Answer the value of features"

	^ features! !

!PackageDescription methodsFor: 'accessing' stamp: 'MM 11/19/2021 12:01:08'!
features: anObject
	"Set the value of features"

	features _ anObject! !

!PackageDescription methodsFor: 'accessing' stamp: 'MM 11/19/2021 12:01:08'!
homepage
	"Answer the value of homepage"

	^ homepage! !

!PackageDescription methodsFor: 'accessing' stamp: 'MM 11/19/2021 12:01:08'!
homepage: anObject
	"Set the value of homepage"

	homepage _ anObject! !

!PackageDescription methodsFor: 'accessing' stamp: 'MM 11/19/2021 12:01:08'!
name: anObject
	"Set the value of name"

	name _ anObject! !

!PackageDescription methodsFor: 'accessing' stamp: 'MM 11/19/2021 13:17:45'!
packageName

	^ name! !

!PackageDescription methodsFor: 'accessing' stamp: 'MM 11/19/2021 12:12:36'!
provides
	"Answer the value of provides"

	^ provides! !

!PackageDescription methodsFor: 'accessing' stamp: 'MM 11/19/2021 12:12:36'!
provides: anObject
	"Set the value of provides"

	provides _ anObject! !

!PackageDescription methodsFor: 'accessing' stamp: 'MM 11/19/2021 12:12:36'!
requires
	"Answer the value of requires"

	^ requires! !

!PackageDescription methodsFor: 'accessing' stamp: 'MM 11/19/2021 12:12:36'!
requires: anObject
	"Set the value of requires"

	requires _ anObject! !

!PackageDescription methodsFor: 'accessing' stamp: 'MM 11/19/2021 12:16:27'!
tags
	"Answer the value of tags"

	^ tags! !

!PackageDescription methodsFor: 'accessing' stamp: 'MM 11/19/2021 12:16:27'!
tags: anObject
	"Set the value of tags"

	tags _ anObject! !

!PackageDescription methodsFor: 'as yet unclassified' stamp: 'MM 11/19/2021 14:09:58'!
install

	provides do: [:feature |
		Feature require: feature]! !

!FilePackageDescription methodsFor: 'accessing' stamp: 'MM 11/19/2021 14:12:03'!
codePackageFile
	"Answer the value of codePackageFile"

	^ codePackageFile! !

!FilePackageDescription methodsFor: 'accessing' stamp: 'MM 11/19/2021 14:12:03'!
codePackageFile: anObject
	"Set the value of codePackageFile"

	codePackageFile _ anObject! !

!FilePackageDescription methodsFor: 'as yet unclassified' stamp: 'MM 11/25/2021 16:30:52'!
install
	
	(FeatureRequirement name: name)
		pathName: codePackageFile fullName;
		satisfyRequirementsAndInstall! !

!PackageInstaller methodsFor: 'accessing' stamp: 'MM 11/25/2021 14:24:04'!
packageList
	"Answer the value of packageList"

	^ packageList! !

!PackageInstaller methodsFor: 'as yet unclassified' stamp: 'MM 11/25/2021 15:12:28'!
addPackage: aPackageSpec

	packageList add: aPackageSpec! !

!PackageInstaller methodsFor: 'as yet unclassified' stamp: 'MM 11/25/2021 17:12:12'!
buildPackageDescription: aCodePackage

	"Create a PackageSpec from aCodePackage."
	
	| packageSpec |
	
	packageSpec _ FilePackageDescription new.
	
	packageSpec name: aCodePackage packageName;
		description: aCodePackage packageDescription;
		requires: aCodePackage requires;
		provides: aCodePackage provides;
		codePackageFile: aCodePackage.
	
	^ packageSpec! !

!PackageInstaller methodsFor: 'as yet unclassified' stamp: 'MM 11/25/2021 17:12:12'!
collectPackagesFromDirectory: aDirectory

	"Create a collection of PackageSpec with package files found in aDirectory."
	
	|packageFiles|
	
	packageFiles _ aDirectory fileNamesMatching: '*.pck.st'.
		
	packageFiles do: [:packageFile | | packageSpec codePackage |
		codePackage _ CodePackageFile onFileEntry: (aDirectory // packageFile).
		packageSpec _ self buildPackageDescription: codePackage.
		self addPackage: packageSpec]! !

!PackageInstaller methodsFor: 'as yet unclassified' stamp: 'MM 11/25/2021 14:39:54'!
collectPackagesFromDisk

	"Collect PackageSpec with package files found in Cuis packages directories."
	
	self placesToLookForPackagesDo: [:aDirectory | 
		self collectPackagesFromDirectory: aDirectory]! !

!PackageInstaller methodsFor: 'as yet unclassified' stamp: 'MM 11/25/2021 16:15:28'!
initialize
	packageList _ PackageList ifNil: [self updatePackageList]! !

!PackageInstaller methodsFor: 'as yet unclassified' stamp: 'MM 11/25/2021 14:40:18'!
placesToLookForPackagesDo: aBlock

	| base packagesDirectory |

	"Look in Cuis image folder and reasonable subfolders"
	base _ DirectoryEntry smalltalkImageDirectory.
	aBlock value: base.
	packagesDirectory _ base / 'Packages'.
	aBlock value: packagesDirectory.
	packagesDirectory allRegularDirectoriesDo: aBlock.
	base regularDirectoriesDo: [ :child |
		child = packagesDirectory ifFalse: [
			aBlock value: child.
			child allRegularDirectoriesDo: aBlock]].
	
	"Look in parent directory and reasonable subfolders. 
	Useful when image is stored in a subdirectory of the main app directory.
	This could be the case when the package comes from a 'main' git repo, and image is copied from gitHub.
	First try directories including the word Cuis in the name. Then try others."
	base parent regularDirectoriesDo: [ :dir |
		dir ~= base ifTrue: [
			('*Cuis*' match: dir name)
				ifTrue: [aBlock value: dir. dir allRegularDirectoriesDo: aBlock]]].
	base parent regularDirectoriesDo: [ :dir |
		dir ~= base ifTrue: [
			('*Cuis*' match: dir name)
				ifFalse: [aBlock value: dir. dir allRegularDirectoriesDo: aBlock]]].

	"Also look in host OS current directory"
	(base ~= DirectoryEntry currentDirectory and: [base parent ~= DirectoryEntry currentDirectory])
		ifTrue: [
			base _ DirectoryEntry currentDirectory.
			base allRegularDirectoriesDo: aBlock ]! !

!PackageInstaller methodsFor: 'as yet unclassified' stamp: 'MM 11/25/2021 16:15:37'!
updatePackageList
	
	packageList _ OrderedCollection new.
	self collectPackagesFromDisk.
	packageList sort: [:p1 :p2 | p1 packageName < p2 packageName].
	PackageList _ packageList.
	self changed: #packageList.
	^ packageList! !

!CodePackageFile methodsFor: '*PackageInstaller' stamp: 'MM 11/19/2021 14:30:09'!
packageDescription
	^ description! !


More information about the Cuis-dev mailing list